Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Each environment is defined in a `environment` sub-table, with the name used to
| `dockerfile` | String | The path to a dockerfile, this will be build and passed to `docker create`. This or the `image` field must be present. | `dockerfile = "$HOME/dockerfile"` |
| `entry_cmd` | String| The command that will be run in the container when the environment is started. Passed to `docker exec`. This is a required field. | `entry_cmd = ["/bin/bash"]` |
| `entry_options` | String Array | Options passed to `docker exec` for the `entry_cmd` | `entry_options = ["-it"]`|
| `cp_cmds`| String Array | A list of commands to copy files to or from the container. Use `CONTAINER`as a placeholder for the container name. Passed directly to `docker cp` | `cp_cmds = [" -L /home/my_script.sh CONTAINER:/home/init_script.sh"]`|
| `exec_cmds`| String Array | A list of additional commands that will be run in the container when it is created, useful for adding additional packages. Passed to `docker exec` | `exec_cmds = ["apt update -y", "apt install -y cowsay"]`|
| `exec_options` | String Array | Docker CLI options passed to the `docker exec` for all `exec_cmds` | `exec_options = ["-u", "user"]`|
| `create_options` | String Array | Docker CLI options passed to `docker create` command. Note that `--name` is not allowed as that is provided by `berth`| `create_options = ["--privileged"]`|
Expand Down Expand Up @@ -272,3 +273,9 @@ A difference from the container naming convention is that the third part is a `s
- Add snapshot testing
- Add docker mocking
- Add check if docker is up in test ctor
- Fix cleanup not always working
- Fix docker containers not removing them selves if build fails
- Improves errors when build fails due to docker exec
- Add dependciy system for files outside of berth file for update tracking
- Add docker cp support
- Add build context around dockerfile inputs to allow COPY to work
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
rustToolchain
pkg-config
openssl
bacon
];
};
}
Expand Down
12 changes: 12 additions & 0 deletions src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ pub struct TomlEnvironment {
#[serde(default)]
entry_options: Vec<String>,

#[serde(default)]
cp_cmds: Vec<String>,

#[serde(default)]
exec_cmds: Vec<String>,

Expand Down Expand Up @@ -137,6 +140,9 @@ pub struct TomlPreset {
#[serde(default)]
entry_options: Vec<String>,

#[serde(default)]
cp_cmds: Vec<String>,

#[serde(default)]
exec_cmds: Vec<String>,

Expand Down Expand Up @@ -170,6 +176,7 @@ pub struct Environment {
pub exec_cmds: Vec<String>,
pub exec_options: Vec<String>,
pub create_options: Vec<String>,
pub cp_cmds: Vec<String>,
}

pub struct Configuration {
Expand Down Expand Up @@ -359,16 +366,20 @@ impl Configuration {
if !preset.entry_cmd.is_empty() {
env.entry_cmd = preset.entry_cmd.clone();
}

if !preset.provided_image.is_empty() {
env.provided_image = preset.provided_image.clone();
}

if !preset.dockerfile.is_empty() {
env.dockerfile = preset.dockerfile.clone();
}

env.entry_options.extend_from_slice(&preset.entry_options);
env.exec_cmds.extend_from_slice(&preset.exec_cmds);
env.exec_options.extend_from_slice(&preset.exec_options);
env.create_options.extend_from_slice(&preset.create_options);
env.cp_cmds.extend_from_slice(&preset.cp_cmds);
}
}

Expand Down Expand Up @@ -474,6 +485,7 @@ impl Configuration {
exec_cmds: env.exec_cmds,
exec_options: env.exec_options,
create_options: env.create_options,
cp_cmds: env.cp_cmds,
};

let mut hasher = DefaultHasher::new();
Expand Down
15 changes: 15 additions & 0 deletions src/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl DockerHandler {

self.create_container()?;
self.start_container().await?;
self.copy_commands()?;
self.exec_setup_commands()?;

spinner.finish_and_clear();
Expand Down Expand Up @@ -268,6 +269,20 @@ impl DockerHandler {
Ok(())
}

fn copy_commands(&self) -> Result<()> {
for cmd in &self.env.cp_cmds {
let mut args = vec!["cp"];

let fixed_string = cmd.clone().replace("CONTAINER", &self.env.name);

let split_cmd = shell_words::split(&fixed_string).unwrap();
args.extend(split_cmd.iter().map(|s| s.as_str()));

Self::run_docker_command(args)?;
}
Ok(())
}

pub async fn stop_container_if_running(&self) -> Result<()> {
if self.is_container_running().await? {
self.docker
Expand Down
32 changes: 32 additions & 0 deletions tests/docker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,38 @@ fn mount() -> Result<()> {
Ok(())
}

#[test]
#[serial]
fn copy_cmds() -> Result<()> {
let mut tmp_file = NamedTempFile::new().unwrap();
let tmp_file_path = tmp_file.path().to_str().unwrap().to_string();
let file_text = "Hello World";
writeln!(tmp_file, "{}", file_text).unwrap();

TestHarness::new()
.config(&formatdoc!(
r#"
image = "alpine:edge"
entry_cmd = "/bin/ash"
cp_cmds = ["{} CONTAINER:{}"]
create_options = ["-it"]
entry_options = ["-it"]
"#,
tmp_file_path,
tmp_file_path
))?
.args(vec!["--config-path", "[config_path]", "[name]"])?
.run(DEFAULT_TIMEOUT)?
.send_line(&format!("cat {}", tmp_file_path))?
.expect_string(file_text)?
.send_line("exit")?
.expect_terminate()?
.success()?;

tmp_file.close().unwrap();
Ok(())
}

#[test]
#[serial]
fn exec_cmds() -> Result<()> {
Expand Down
5 changes: 5 additions & 0 deletions tests/test_utils/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ impl TestBase {
if let Some(dir) = &self.working_dir {
command.current_dir(dir);
}

if let Ok(docker_host) = std::env::var("DOCKER_HOST") {
self.envs.push(("DOCKER_HOST".into(), docker_host));
}

command.env_clear();
command.args(self.args.clone());
command.envs(self.envs.clone());
Expand Down