1 module viva.docker.docker; 2 3 import viva.io; 4 import std.file; 5 import std.conv; 6 import std.array; 7 import std.getopt; 8 import std.process; 9 import std.algorithm; 10 11 /++ 12 + struct holding options for a docker operation 13 +/ 14 public struct DockerOptions 15 { 16 /// the docker image to be run 17 string image = null; 18 /// custom command to be run 19 string command = null; 20 /// container user 21 string user = null; 22 /// container name 23 string name = null; 24 25 /// verbose mode 26 bool verbose = false; 27 /// detach the container 28 bool detach = false; 29 /// remove container 30 bool remove = true; 31 /// enable privileged mode (useful for GDB) 32 bool privileged = false; 33 /// enable GDB (GNU Debugger) 34 bool gdb = false; 35 } 36 37 /++ 38 + struct holding info about a container 39 +/ 40 public struct DockerContainerInfo 41 { 42 /// the id of the container 43 string id; 44 45 /// the name of the container 46 string name; 47 48 /// the image name of the container 49 string image; 50 51 /// the status of the container (`Exited` or `Created`) 52 string status; 53 } 54 55 // TODO: maybe we shouldn't add the sudo? and have the user run the d project with sudo instead? so its not there if not needed? 56 version(Windows) private string[] defaultArgs = ["docker"]; 57 else private string[] defaultArgs = ["sudo", "docker"]; 58 59 private string runCommand(string[] args) @safe 60 { 61 string[] command = defaultArgs ~ args; 62 auto res = execute(command); 63 if (res.status != 0) throw new Exception("cannot run command: '" ~ command.join(" ") ~ "'. command exited with " ~ res.status.to!string); 64 return res.output; 65 } 66 67 /++ 68 + run docker in a shell 69 + Returns: ? 70 +/ 71 public string runDockerShell(DockerOptions options) @safe 72 { 73 string[] dockerArgs = ["run", "-it"]; 74 75 if (options.remove) dockerArgs ~= ["--rm"]; 76 if (options.detach) dockerArgs ~= ["--detach"]; 77 78 if (options.user != null) dockerArgs ~= ["--user", options.user]; 79 if (options.name != null) dockerArgs ~= ["--name", options.name]; 80 81 if (options.privileged) dockerArgs ~= ["--privileged"]; 82 83 if (options.gdb) dockerArgs ~= ["--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"]; 84 85 dockerArgs ~= [options.image]; 86 87 if (options.command != null) dockerArgs ~= options.command.split(" "); 88 89 return runCommand(dockerArgs); 90 } 91 92 /++ 93 + lists all containers 94 + Returns: a list of objects of info of all the containers 95 +/ 96 public DockerContainerInfo[] runDockerContainerList() @safe 97 { 98 import std.uni : isWhite; 99 100 string[] dockerArgs = ["ps", "-a", "--format", "\"table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}\""]; 101 102 string[] containers = runCommand(dockerArgs).split("\n"); 103 DockerContainerInfo[] containerInfos = []; 104 105 foreach (container; containers) 106 { 107 string[] containerParts = container.split!isWhite; 108 109 if (containerParts.length < 5) continue; 110 111 containerInfos ~= DockerContainerInfo(containerParts[1], containerParts[2], containerParts[3], containerParts[4]); 112 } 113 114 return containerInfos; 115 } 116 117 /++ 118 + build a dockerfile 119 + Returns: ? 120 +/ 121 public string runDockerBuild(string imageName, string dockerFile) @safe 122 { 123 string[] dockerArgs = ["build", "-f", dockerFile, "-t", imageName, "."]; 124 return runCommand(dockerArgs); 125 }