rusty_docker_compose/
lib.rs

1use std::fs::File;
2use std::path::Path;
3use std::process::{Command, Stdio};
4use std::thread;
5
6#[derive(Clone)]
7pub struct DockerComposeCmd {
8    file: String,
9    logs_dir: String,
10}
11
12impl DockerComposeCmd {
13    pub fn new(file: &str, logs_dir: &str) -> DockerComposeCmd {
14        DockerComposeCmd {
15            file: file.to_string(),
16            logs_dir: logs_dir.to_string(),
17        }
18    }
19
20    fn get_docker_compose_command() -> &'static str {
21        if Command::new("docker-compose").output().is_ok() {
22            return "docker-compose";
23        } else {
24            return "docker compose";
25        }
26    }
27
28    pub fn up(&self) {
29        let docker_compose_command = Self::get_docker_compose_command();
30
31        let output = Command::new(docker_compose_command)
32            .arg("-f")
33            .arg(self.file.clone())
34            .arg("up")
35            .arg("-d")
36            .output()
37            .expect("Failed to execute command");
38        println!("Output: {}", String::from_utf8_lossy(&output.stdout));
39        println!("Errors: {}", String::from_utf8_lossy(&output.stderr));
40        println!("Docker Compose started");
41
42        let dir = &self.logs_dir;
43        if Path::new(dir).exists() {
44            std::fs::remove_dir_all(dir).unwrap();
45        }
46        std::fs::create_dir_all(dir).unwrap();
47
48        let output = Command::new(docker_compose_command)
49            .arg("-f")
50            .arg(self.file.clone())
51            .arg("ps")
52            .arg("--services")
53            .output()
54            .unwrap();
55
56        let stdout = String::from_utf8(output.stdout).unwrap();
57        let containers: Vec<String> = stdout.lines().map(String::from).collect();
58
59        let _handles: Vec<_> = containers
60            .into_iter()
61            .map(|container| {
62                let file_name = format!("{}/{}.log", dir, container);
63                let file_path = std::path::PathBuf::from(file_name);
64                let docker_compose_file = self.file.clone();
65                thread::spawn(move || {
66                    let follow_container_log =
67                        |container: String, file_path: std::path::PathBuf| {
68                            let file = File::create(file_path).unwrap();
69                            let _ = Command::new(docker_compose_command)
70                                .arg("-f")
71                                .arg(docker_compose_file)
72                                .arg("logs")
73                                .arg("--follow")
74                                .arg("--no-log-prefix")
75                                .arg(&container)
76                                .stdout(Stdio::from(file))
77                                .spawn()
78                                .unwrap();
79                        };
80
81                    follow_container_log(container, file_path);
82                });
83            })
84            .collect();
85    }
86
87    pub fn down(&self) {
88        println!("Gracefully shutting down...");
89
90        let docker_compose_command = Self::get_docker_compose_command();
91
92        let _output = Command::new(docker_compose_command)
93            .arg("-f")
94            .arg(self.file.clone())
95            .arg("down")
96            .output()
97            .expect("Failed to execute command");
98    }
99}
100
101pub struct DockerCompose {
102    cmd: DockerComposeCmd,
103}
104
105impl DockerCompose {
106    pub fn new(file: &str, logs_dir: &str) -> DockerCompose {
107        let cmd = DockerComposeCmd::new(file, logs_dir);
108        cmd.up();
109        DockerCompose { cmd }
110    }
111}
112
113impl Drop for DockerCompose {
114    fn drop(&mut self) {
115        self.cmd.down();
116    }
117}