contain_rs_core/client/
mod.rs

1//!
2//! This module contains the traits that represent the bare functiionality of a client.
3//!
4//! See [crate::client::podman::Podman] for usage of the podman client implementation.
5//!
6
7use std::{
8    io::{BufRead, BufReader},
9    process::Command,
10};
11
12use os_pipe::PipeReader;
13
14use crate::{
15    container::{Container, IntoContainer},
16    error::ContainerResult,
17    rt::DetailedContainerInfo,
18};
19
20pub mod docker;
21pub mod podman;
22pub mod shared;
23
24///
25/// The client Trait represents a way to access a client.
26///
27/// It's implemented by the [crate::client::podman::Podman] struct for example. And will be for docker as well.
28/// If you do that for any specific Type you get [`handles`](Handle) for free.
29///
30///
31pub trait Client: Clone {
32    type ClientType: Client;
33
34    fn command(&self) -> Command;
35    fn create<C: IntoContainer>(&self, container: C) -> ContainerHandle<Self::ClientType>;
36    fn run(&self, container: &Container) -> ContainerResult<()>;
37    fn stop(&self, container: &Container) -> ContainerResult<()>;
38    fn rm(&self, container: &Container) -> ContainerResult<()>;
39    fn log(&self, container: &Container) -> ContainerResult<Option<Log>>;
40    fn inspect(&self, container: &Container) -> ContainerResult<Option<DetailedContainerInfo>>;
41    fn exists(&self, container: &Container) -> ContainerResult<bool>;
42    fn runs(&self, container: &Container) -> ContainerResult<bool>;
43    fn wait(&self, container: &Container) -> ContainerResult<()>;
44}
45
46///
47/// A handle is a way to interact with a container.
48///
49/// When you create a container using a [Client] it will return one of these.
50/// The handle automatically stops and removes the container, when it goes out of scope.
51///
52pub trait Handle {
53    fn run(&self) -> ContainerResult<()>;
54    fn wait(&self) -> ContainerResult<()>;
55    fn run_and_wait(&self) -> ContainerResult<()>;
56    fn stop(&self) -> ContainerResult<()>;
57    fn rm(&self) -> ContainerResult<()>;
58    fn log(&self) -> ContainerResult<Option<Log>>;
59    fn container(&self) -> &Container;
60    fn is_running(&self) -> ContainerResult<bool>;
61    fn exists(&self) -> ContainerResult<bool>;
62}
63
64pub struct Log {
65    pub reader: PipeReader,
66}
67
68impl Log {
69    fn stream(&mut self) -> impl BufRead {
70        BufReader::new(self.reader.try_clone().unwrap())
71    }
72}
73
74pub struct ContainerHandle<T: Client> {
75    client: T,
76    container: Container,
77}
78
79impl<T: Client> Handle for ContainerHandle<T> {
80    fn run(&self) -> ContainerResult<()> {
81        if !self.is_running()? {
82            self.client.run(&self.container)?;
83        }
84
85        Ok(())
86    }
87
88    fn wait(&self) -> ContainerResult<()> {
89        self.client.wait(&self.container)?;
90
91        Ok(())
92    }
93
94    fn run_and_wait(&self) -> ContainerResult<()> {
95        if !self.is_running()? {
96            self.run()?;
97            self.wait()?;
98        }
99
100        Ok(())
101    }
102
103    fn stop(&self) -> ContainerResult<()> {
104        if self.is_running()? {
105            self.client.stop(&self.container)?
106        }
107
108        Ok(())
109    }
110
111    fn rm(&self) -> ContainerResult<()> {
112        self.stop()?;
113
114        if self.exists()? {
115            self.client.rm(&self.container)?
116        }
117
118        Ok(())
119    }
120
121    fn log(&self) -> ContainerResult<Option<Log>> {
122        if self.is_running()? {
123            Ok(self.client.log(&self.container)?)
124        } else {
125            Ok(None)
126        }
127    }
128
129    fn container(&self) -> &Container {
130        &self.container
131    }
132
133    fn is_running(&self) -> ContainerResult<bool> {
134        Ok(self.exists()? && self.client.runs(&self.container)?)
135    }
136
137    fn exists(&self) -> ContainerResult<bool> {
138        self.client.exists(&self.container)
139    }
140}
141
142impl<T: Client> Drop for ContainerHandle<T> {
143    fn drop(&mut self) {
144        self.rm().unwrap();
145    }
146}