This repository was archived by the owner on Jul 18, 2024. It is now read-only.
forked from JetBrains/teamcity-csharp-interactive
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDockerRun.cs
182 lines (170 loc) · 6.9 KB
/
DockerRun.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// ReSharper disable InconsistentNaming
// ReSharper disable CommentTypo
// ReSharper disable IdentifierTypo
// ReSharper disable InvertIf
// ReSharper disable UnusedMember.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedType.Global
namespace HostApi;
using Internal;
using Internal.Cmd;
using Internal.Docker;
/// <summary>
/// Docker runs a command in isolated containers. A container is a process which runs on a host. The host may be local or remote. When an operator executes docker run, the container process that runs is isolated in that it has its own file system, its own networking, and its own isolated process tree separate from the host.
/// </summary>
[Target]
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 = "",
// Keep STDIN open even if not attached
bool Interactive = false,
// Allocate a pseudo-TTY
bool Tty = false
)
{
public DockerRun(string image = "") : this(new CommandLine(string.Empty), image)
{ }
public DockerRun(ICommandLine commandLine, string image)
: this(
commandLine,
image,
[],
[],
[],
[],
[],
[],
[])
{ }
public IStartInfo GetStartInfo(IHost host)
{
if (host == null) throw new ArgumentNullException(nameof(host));
var directoryMap = new Dictionary<string, string>();
var pathResolver = new PathResolver(Platform, directoryMap);
using var pathResolverToken = host.GetService<HostComponents>().PathResolverContext.Register(pathResolver);
var settings = host.GetService<HostComponents>().DockerSettings;
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(
("--interactive", Interactive),
("--tty", Tty),
("--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),
("--pull", Pull?.ToString()?.ToLowerInvariant() ?? 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.Select(i => (pathResolver.ToAbsolutPath(i.Key), i.Value)).ToArray())
.AddValues("-v", ":", Volumes.ToArray())
.AddArgs(Options.ToArray())
.AddArgs(Image)
.AddArgs(startInfo.ExecutablePath)
.AddArgs(startInfo.Args.ToArray())
.WithVars(Vars.ToArray());
}
public override string ToString() =>
string.IsNullOrWhiteSpace(ShortName)
? $"{CommandLine} in the docker container {Image}"
: ShortName;
private class PathResolver(string platform, IDictionary<string, string> directoryMap) : IPathResolver
{
public string Resolve(IHost host, string path, IPathResolver nextResolver)
{
path = Path.GetFullPath(path);
if (!directoryMap.TryGetValue(path, out var toPath))
{
var isWindows = IsWindows();
var rootDirectory = isWindows ? "c:" : string.Empty;
toPath = $"{rootDirectory}/.{Guid.NewGuid().ToString().Substring(0, 8)}";
directoryMap.Add(path, toPath);
}
return toPath;
}
public string ToAbsolutPath(string path)
{
if (IsWindows())
{
return path;
}
path = path.Replace(":", string.Empty).Replace('\\', '/');
if (path.Length > 0 && path[0] != '/')
{
path = "/" + path;
}
return path;
}
private bool IsWindows() => platform.ToLower().Contains("windows");
}
}