public partial record DockerRun()

in TeamCity.CSharpInteractive.HostApi/DockerRun.cs [19:168]


public partial record DockerRun(
    // Command to run in container.
    ICommandLine CommandLine,
    // Docker image.
    string Image,
    // Specifies the set of command line arguments to use when starting the tool.
    IEnumerable<string> Args,
    // Specifies the set of environment variables that apply to this process and its child processes.
    IEnumerable<(string name, string value)> Vars,
    // Additional docker options
    IEnumerable<string> Options,
    // Expose a port or a range of ports
    IEnumerable<string> ExposedPorts,
    // Publish a container's port(s) to the host
    IEnumerable<string> PublishedPorts,
    // Adds bind mounts or volumes using the --mount flag
    IEnumerable<string> Mounts,
    // Bind mount a volume
    IEnumerable<(string from, string to)> Volumes,
    // Overrides the tool executable path.
    string ExecutablePath = "",
    // Specifies the working directory for the tool to be started.
    string WorkingDirectory = "",
    // Number of CPUs
    int? CPUs = default,
    // Overwrite the default ENTRYPOINT of the image
    string EntryPoint = "",
    // Container host name
    string HostName = "",
    // Kernel memory limit
    int? KernelMemory = default,
    // Memory limit
    int? Memory = default,
    // Assign a name to the container
    string? Name = default,
    // Connect a container to a network
    string Network = "",
    // Set platform if server is multi-platform capable
    string Platform = "",
    // Give extended privileges to this container
    bool? Privileged = default,
    // Pull image before running ("always"|"missing"|"never")
    DockerPullType? Pull = default,
    // Mount the container's root filesystem as read only
    bool? ReadOnly = default,
    // Automatically remove the container when it exits
    bool? AutoRemove = default,
    // Username or UID (format: <name|uid>[:<group|gid>])
    string User = "",
    // Working directory inside the container
    string ContainerWorkingDirectory = "",
    // A file with environment variables inside the container
    string EnvFile = "",
    // Specifies a short name for this operation.
    string ShortName = "")
{
    public DockerRun(string image = "") : this(new CommandLine(string.Empty), image)
    { }

    public DockerRun(ICommandLine commandLine, string image)
        : this(
            commandLine,
            image,
            Enumerable.Empty<string>(),
            Enumerable.Empty<(string, string)>(),
            Enumerable.Empty<string>(),
            Enumerable.Empty<string>(),
            Enumerable.Empty<string>(),
            Enumerable.Empty<string>(),
            Enumerable.Empty<(string, string)>())
    { }

    public IStartInfo GetStartInfo(IHost host)
    {
        var directoryMap = new Dictionary<string, string>();
        var pathResolver = new PathResolver(Platform, directoryMap);
        using var pathResolverToken = host.GetService<IPathResolverContext>().Register(pathResolver);
        var settings = host.GetService<IDockerSettings>();

        var startInfo = CommandLine.GetStartInfo(host);
        var cmd = new CommandLine(string.IsNullOrWhiteSpace(ExecutablePath) ? settings.DockerExecutablePath : ExecutablePath)
            .WithShortName(!string.IsNullOrWhiteSpace(ShortName) ? ShortName : $"{startInfo.ShortName} in the docker container {Image}")
            .WithWorkingDirectory(WorkingDirectory)
            .WithArgs("run")
            .AddBooleanArgs(
                ("-it", Name == string.Empty),
                ("--privileged", Privileged),
                ("--read-only", ReadOnly),
                ("--rm", AutoRemove))
            .AddArgs("--expose", ExposedPorts)
            .AddArgs("--publish", PublishedPorts)
            .AddArgs("--mount", Mounts)
            .AddArgs(
                ("--cpus", CPUs?.ToString() ?? ""),
                ("--entrypoint", EntryPoint),
                ("--hostname", HostName),
                ("--kernel-memory", KernelMemory?.ToString() ?? ""),
                ("--memory", Memory?.ToString() ?? ""),
                ("--name", Name ?? string.Empty),
                ("--network", Network),
                ("--platform", Platform),
                ("--platform", Pull?.ToString() ?? string.Empty),
                ("--user", User),
                ("--workdir", ContainerWorkingDirectory),
                ("--env-file", EnvFile))
            .AddArgs(Args.ToArray())
            .AddValues("-e", "=", startInfo.Vars.ToArray());

        var additionalVolums = directoryMap.Select(i => (i.Key, i.Value));
        return cmd
            .AddValues("-v", ":", additionalVolums.ToArray())
            .AddValues("-v", ":", Volumes.ToArray())
            .AddArgs(Options.ToArray())
            .AddArgs(Image)
            .AddArgs(startInfo.ExecutablePath)
            .AddArgs(startInfo.Args.ToArray())
            .WithVars(Vars.ToArray());
    }

    public void PreRun(IHost host) => CommandLine.PreRun(host);

    public IEnumerable<IServiceMessage> GetNonStdStreamsServiceMessages(IHost host) => CommandLine.GetNonStdStreamsServiceMessages(host);
    
    public override string ToString() => !string.IsNullOrWhiteSpace(ShortName) ? ShortName : $"{CommandLine} in the docker container {Image}";
    
    private class PathResolver : IPathResolver
    {
        private readonly string _platform;
        private readonly IDictionary<string, string> _directoryMap;

        public PathResolver(string platform, IDictionary<string, string> directoryMap)
        {
            _platform = platform;
            _directoryMap = directoryMap;
        }

        public string Resolve(IHost host, string path, IPathResolver nextResolver)
        {
            path = Path.GetFullPath(path);
            if (!_directoryMap.TryGetValue(path, out var toPath))
            {
                var rootDirectory = _platform.Contains("windows", StringComparison.OrdinalIgnoreCase) ? "c:" : string.Empty;
                toPath = $"{rootDirectory}/.{Guid.NewGuid().ToString()[..8]}";
                _directoryMap.Add(path, toPath);
            }

            return toPath;
        }
    }
}