<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using Ductus.FluentDocker.Commands;
using Ductus.FluentDocker.Common;
using Ductus.FluentDocker.Extensions;
using Ductus.FluentDocker.Model.Builders;
using Ductus.FluentDocker.Model.Common;
using Ductus.FluentDocker.Model.Compose;
using Ductus.FluentDocker.Model.Containers;
using Ductus.FluentDocker.Services;
using Ductus.FluentDocker.Services.Extensions;

namespace Ductus.FluentDocker.Builders
{
  public sealed class ContainerBuilder : BaseBuilder<IContainerService>
  {
    private readonly ContainerBuilderConfig _config = new ContainerBuilderConfig();
    private RepositoryBuilder _repositoryBuilder;

    internal ContainerBuilder(IBuilder parent) : base(parent)
    {
    }

    public override IContainerService Build()
    {
      var host = FindHostService();
      if (!host.HasValue)
        throw new FluentDockerException(
          $"Cannot build container {_config.Image} since no host service is defined");

      // Login on private repo if needed.
      _repositoryBuilder?.Build(host.Value);

      if (_config.VerifyExistence && !string.IsNullOrEmpty(_config.CreateParams.Name))
      {
        // Since filter on docker is only prefix filter
        var existing =
          host.Value.GetContainers(true, $"name={_config.CreateParams.Name}")
            .FirstOrDefault(x => IsNameMatch(x.Name, _config.CreateParams.Name));

        if (null != existing)
        {
          existing.RemoveOnDispose = _config.DeleteOnDispose;
          existing.StopOnDispose = _config.StopOnDispose;
          
          // Run hooks will not be run since they have already met the requirements
          // (since container was found running).
          AddHooks(existing);

          return existing;
        }
      }

      // If we have networks, the first is supplied as --network option on docker create
      // TODO: This is a ugly hack that needs to be cleaned up.
      var cfgNw = (IList<INetworkService>)_config.Networks ?? new INetworkService[0];
      
      var firstNw = null != _config.NetworkNames
        ? _config.NetworkNames[0]
        : (0 == cfgNw.Count ? string.Empty : cfgNw[0].Name);

      if (string.Empty != firstNw) _config.CreateParams.Network = firstNw;
      
      var container = host.Value.Create(_config.Image, _config.ImageFocrePull, _config.CreateParams, _config.StopOnDispose,
        _config.DeleteOnDispose,
        _config.DeleteVolumeOnDispose,
        _config.DeleteNamedVolumeOnDispose,
        _config.Command, _config.Arguments);

      AddHooks(container);

      foreach (var network in cfgNw)
      {
        if (network.Name != firstNw)
          network.Attach(container, true /*detachOnDisposeNetwork*/);
      }

      if (null == _config.NetworkNames) return container;

      var nw = host.Value.GetNetworks();
      foreach (var network in (IEnumerable<string>) _config.NetworkNames ?? new string[0])
      {
        if (network == firstNw) continue;
        
        var nets = nw.First(x => x.Name == network);
        nets.Attach(container, true /*detachOnDisposeNetwork*/);
      }

      return container;
    }

    protected override IBuilder InternalCreate()
    {
      return new ContainerBuilder(this);
    }

    public ContainerBuilder RemoveVolumesOnDispose(bool includeNamedVolues = false)
    {
      _config.DeleteVolumeOnDispose = true;
      _config.DeleteNamedVolumeOnDispose = includeNamedVolues;
      return this;
    }

    public ContainerBuilder UseImage(string image, bool force = false)
    {
      _config.Image = image;
      _config.ImageFocrePull = force;
      return this;
    }

    /// <summary>
    ///   Uses credentials to login to a registry.
    /// </summary>
    /// <param name="server">The ip or dns to the server (with optioanl :port)</param>
    /// <param name="user">An optional user to use when logging in.</param>
    /// <param name="password">An optional password to user when logging in.</param>
    /// <returns>Itself for fluent access.</returns>
    public ContainerBuilder WithCredential(string server, string user = null, string password = null)
    {
      _repositoryBuilder = new RepositoryBuilder(server, user, password);
      return this;
    }

    public ContainerBuilder IsWindowsImage()
    {
      _config.IsWindowsImage = true;
      return this;
    }

    public ImageBuilder FromImage(string image)
    {
      UseImage(image);

      var builder = new ImageBuilder(this).AsImageName(image);
      Childs.Add(builder);

      return builder;
    }

    public CompositeBuilder UseCompose()
    {
      var builder = new CompositeBuilder(this);
      Childs.Add(builder);
      return builder;
    }

    public CompositeBuilder FromComposeFile(string composeFile)
    {
      return UseCompose().FromFile(composeFile);
    }

    public ContainerBuilder WithName(string name)
    {
      _config.CreateParams.Name = name;
      return this;
    }

    public ContainerBuilder Command(string command, params string[] arguments)
    {
      _config.Command = command;
      _config.Arguments = arguments;
      return this;
    }

    public ContainerBuilder IsPrivileged()
    {
      _config.CreateParams.Privileged = true;
      return this;
    }

    public ContainerBuilder WithEnvironment(params string[] nameValue)
    {
      _config.CreateParams.Environment = nameValue;
      return this;
    }

    public ContainerBuilder UseEnvironmentFile(params string[] file)
    {
      _config.CreateParams.EnvironmentFiles = _config.CreateParams.EnvironmentFiles.ArrayAdd(file);
      return this;
    }

    public ContainerBuilder WithParentCGroup(int cgroup)
    {<commit_msg>Added WithHostName on cotainerbuilder (Issue #110).<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.RegularExpressions;
using Ductus.FluentDocker.Commands;
using Ductus.FluentDocker.Common;
using Ductus.FluentDocker.Extensions;
using Ductus.FluentDocker.Model.Builders;
using Ductus.FluentDocker.Model.Common;
using Ductus.FluentDocker.Model.Compose;
using Ductus.FluentDocker.Model.Containers;
using Ductus.FluentDocker.Services;
using Ductus.FluentDocker.Services.Extensions;

namespace Ductus.FluentDocker.Builders
{
  public sealed class ContainerBuilder : BaseBuilder<IContainerService>
  {
    private readonly ContainerBuilderConfig _config = new ContainerBuilderConfig();
    private RepositoryBuilder _repositoryBuilder;

    internal ContainerBuilder(IBuilder parent) : base(parent)
    {
    }

    public override IContainerService Build()
    {
      var host = FindHostService();
      if (!host.HasValue)
        throw new FluentDockerException(
          $"Cannot build container {_config.Image} since no host service is defined");

      // Login on private repo if needed.
      _repositoryBuilder?.Build(host.Value);

      if (_config.VerifyExistence && !string.IsNullOrEmpty(_config.CreateParams.Name))
      {
        // Since filter on docker is only prefix filter
        var existing =
          host.Value.GetContainers(true, $"name={_config.CreateParams.Name}")
            .FirstOrDefault(x => IsNameMatch(x.Name, _config.CreateParams.Name));

        if (null != existing)
        {
          existing.RemoveOnDispose = _config.DeleteOnDispose;
          existing.StopOnDispose = _config.StopOnDispose;
          
          // Run hooks will not be run since they have already met the requirements
          // (since container was found running).
          AddHooks(existing);

          return existing;
        }
      }

      // If we have networks, the first is supplied as --network option on docker create
      // TODO: This is a ugly hack that needs to be cleaned up.
      var cfgNw = (IList<INetworkService>)_config.Networks ?? new INetworkService[0];
      
      var firstNw = null != _config.NetworkNames
        ? _config.NetworkNames[0]
        : (0 == cfgNw.Count ? string.Empty : cfgNw[0].Name);

      if (string.Empty != firstNw) _config.CreateParams.Network = firstNw;
      
      var container = host.Value.Create(_config.Image, _config.ImageFocrePull, _config.CreateParams, _config.StopOnDispose,
        _config.DeleteOnDispose,
        _config.DeleteVolumeOnDispose,
        _config.DeleteNamedVolumeOnDispose,
        _config.Command, _config.Arguments);

      AddHooks(container);

      foreach (var network in cfgNw)
      {
        if (network.Name != firstNw)
          network.Attach(container, true /*detachOnDisposeNetwork*/);
      }

      if (null == _config.NetworkNames) return container;

      var nw = host.Value.GetNetworks();
      foreach (var network in (IEnumerable<string>) _config.NetworkNames ?? new string[0])
      {
        if (network == firstNw) continue;
        
        var nets = nw.First(x => x.Name == network);
        nets.Attach(container, true /*detachOnDisposeNetwork*/);
      }

      return container;
    }

    protected override IBuilder InternalCreate()
    {
      return new ContainerBuilder(this);
    }

    public ContainerBuilder RemoveVolumesOnDispose(bool includeNamedVolues = false)
    {
      _config.DeleteVolumeOnDispose = true;
      _config.DeleteNamedVolumeOnDispose = includeNamedVolues;
      return this;
    }

    public ContainerBuilder UseImage(string image, bool force = false)
    {
      _config.Image = image;
      _config.ImageFocrePull = force;
      return this;
    }

    /// <summary>
    ///   Uses credentials to login to a registry.
    /// </summary>
    /// <param name="server">The ip or dns to the server (with optioanl :port)</param>
    /// <param name="user">An optional user to use when logging in.</param>
    /// <param name="password">An optional password to user when logging in.</param>
    /// <returns>Itself for fluent access.</returns>
    public ContainerBuilder WithCredential(string server, string user = null, string password = null)
    {
      _repositoryBuilder = new RepositoryBuilder(server, user, password);
      return this;
    }

    public ContainerBuilder IsWindowsImage()
    {
      _config.IsWindowsImage = true;
      return this;
    }

    public ImageBuilder FromImage(string image)
    {
      UseImage(image);

      var builder = new ImageBuilder(this).AsImageName(image);
      Childs.Add(builder);

      return builder;
    }

    public CompositeBuilder UseCompose()
    {
      var builder = new CompositeBuilder(this);
      Childs.Add(builder);
      return builder;
    }

    public CompositeBuilder FromComposeFile(string composeFile)
    {
      return UseCompose().FromFile(composeFile);
    }

    public ContainerBuilder WithName(string name)
    {
      _config.CreateParams.Name = name;
      return this;
    }

    public ContainerBuilder WithHostName(string name)
    {
      _config.CreateParams.Hostname = name;
      return this;
    }

    public ContainerBuilder Command(string command, params string[] arguments)
    {
      _config.Command = command;
      _config.Arguments = arguments;
      return this;
    }

    public ContainerBuilder IsPrivileged()
    {
      _config.CreateParams.Privileged = true;
      return this;
    }

    public ContainerBuilder WithEnvironment(params string[] nameValue)
    {
      _config.CreateParams.Environment = nameValue;
      return this;
    }

    public ContainerBuilder UseEnvironmentFile(params string[] file)
    {
      _config.CreateParams.EnvironmentFiles = _config.CreateParams.EnvironmentFiles.ArrayAdd(file);
      return this;
    }

    public ContainerBuilder WithParentCGroup(int cgroup)
    {
{'fraction_non_alphanumeric': 0.0913658038147139, 'fraction_numerical': 0.0011069482288828339, 'mean_word_length': 2.867303259795851, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1782438', 'n_tokens_mistral': 3325, 'n_tokens_neox': 3256, 'n_words': 811}