Skip to content

Commit

Permalink
add way to run script with pre-build
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Jul 4, 2022
1 parent 1b986f3 commit 1222225
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 51 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- #910 - `pre-build` can now take a string pointing to a script file to run.
- #905 - added `qemu-runner` for musl images, allowing use of native or emulated runners.
- #905 - added qemu emulation to `i586-unknown-linux-gnu`, `i686-unknown-linux-musl`, and `i586-unknown-linux-gnu`, so they can run on an `x86` CPU, rather than an `x86_64` CPU.
- #900 - add the option to skip copying build artifacts back to host when using remote cross via `CROSS_REMOTE_SKIP_BUILD_ARTIFACTS`.
- #891 - support custom user namespace overrides by setting the `CROSS_CONTAINER_USER_NAMESPACE` environment variable.
- #891 - support custom user namespace overrides by setting the `CROSS_CONTAINER_USER_NAMESPACE` environment variable.
- #890 - support rootless docker via the `CROSS_ROOTLESS_CONTAINER_ENGINE` environment variable.

### Changed
Expand Down
18 changes: 17 additions & 1 deletion docs/cross_toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,26 @@ The `target` key allows you to specify parameters for specific compilation targe
xargo = false
build-std = false
image = "test-image"
pre-build = ["apt-get update"]
pre-build = ["apt-get update"] # can also be the path to a file to run
runner = "custom-runner"
```

# `target.TARGET.pre-build`

The `pre-build` field can also reference a file to copy and run

```toml
[target.aarch64-unknown-linux-gnu]
pre-build = "./scripts/my-script.sh"
```

```sh
$ cat ./scripts/my-script.sh
#!/usr/bin/env bash

apt-get install libssl-dev -y
```

# `target.TARGET.env`

The `target` key allows you to specify environment variables that should be used for a specific compilation target.
Expand Down
21 changes: 15 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::docker::custom::PreBuild;
use crate::shell::{self, MessageInfo};
use crate::{CrossToml, Result, Target, TargetList};

Expand Down Expand Up @@ -77,9 +78,14 @@ impl Environment {
self.get_values_for("DOCKERFILE_CONTEXT", target, |s| s.to_string())
}

fn pre_build(&self, target: &Target) -> (Option<Vec<String>>, Option<Vec<String>>) {
fn pre_build(&self, target: &Target) -> (Option<PreBuild>, Option<PreBuild>) {
self.get_values_for("PRE_BUILD", target, |v| {
v.split('\n').map(String::from).collect()
let v: Vec<_> = v.split('\n').map(String::from).collect();
if v.len() == 1 {
PreBuild::Single(v.into_iter().next().expect("should contain one item"))
} else {
PreBuild::Lines(v)
}
})
}

Expand Down Expand Up @@ -311,7 +317,7 @@ impl Config {
.map_or(Ok(None), |t| Ok(t.dockerfile_build_args(target)))
}

pub fn pre_build(&self, target: &Target) -> Result<Option<Vec<String>>> {
pub fn pre_build(&self, target: &Target) -> Result<Option<PreBuild>> {
self.get_from_ref(target, Environment::pre_build, CrossToml::pre_build)
}

Expand Down Expand Up @@ -477,7 +483,10 @@ mod tests {
assert_eq!(config.build_std(&target()), None);
assert_eq!(
config.pre_build(&target())?,
Some(vec![s!("apt-get update"), s!("apt-get install zlib-dev")])
Some(PreBuild::Lines(vec![
s!("apt-get update"),
s!("apt-get install zlib-dev")
]))
);

Ok(())
Expand Down Expand Up @@ -513,7 +522,7 @@ mod tests {
}

#[test]
pub fn env_target_and_toml_build_pre_build_then_use_toml() -> Result<()> {
pub fn env_target_and_toml_build_pre_build_then_use_env() -> Result<()> {
let mut map = HashMap::new();
map.insert(
"CROSS_TARGET_AARCH64_UNKNOWN_LINUX_GNU_PRE_BUILD",
Expand All @@ -524,7 +533,7 @@ mod tests {
let config = Config::new_with(Some(toml(TOML_BUILD_PRE_BUILD)?), env);
assert_eq!(
config.pre_build(&target())?,
Some(vec![s!("dpkg --add-architecture arm64")])
Some(PreBuild::Single(s!("dpkg --add-architecture arm64")))
);

Ok(())
Expand Down
99 changes: 87 additions & 12 deletions src/cross_toml.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![doc = include_str!("../docs/cross_toml.md")]

use crate::docker::custom::PreBuild;
use crate::shell::{self, MessageInfo};
use crate::{config, errors::*};
use crate::{Target, TargetList};
Expand All @@ -24,7 +25,8 @@ pub struct CrossBuildConfig {
xargo: Option<bool>,
build_std: Option<bool>,
default_target: Option<String>,
pre_build: Option<Vec<String>>,
#[serde(default, deserialize_with = "opt_string_or_string_vec")]
pre_build: Option<PreBuild>,
#[serde(default, deserialize_with = "opt_string_or_struct")]
dockerfile: Option<CrossTargetDockerfileConfig>,
}
Expand All @@ -38,7 +40,8 @@ pub struct CrossTargetConfig {
image: Option<String>,
#[serde(default, deserialize_with = "opt_string_or_struct")]
dockerfile: Option<CrossTargetDockerfileConfig>,
pre_build: Option<Vec<String>>,
#[serde(default, deserialize_with = "opt_string_or_string_vec")]
pre_build: Option<PreBuild>,
runner: Option<String>,
#[serde(default)]
env: CrossEnvConfig,
Expand Down Expand Up @@ -254,12 +257,8 @@ impl CrossToml {
}

/// Returns the `build.dockerfile.pre-build` and `target.{}.dockerfile.pre-build` part of `Cross.toml`
pub fn pre_build(&self, target: &Target) -> (Option<&[String]>, Option<&[String]>) {
self.get_ref(
target,
|b| b.pre_build.as_deref(),
|t| t.pre_build.as_deref(),
)
pub fn pre_build(&self, target: &Target) -> (Option<&PreBuild>, Option<&PreBuild>) {
self.get_ref(target, |b| b.pre_build.as_ref(), |t| t.pre_build.as_ref())
}

/// Returns the `target.{}.runner` part of `Cross.toml`
Expand Down Expand Up @@ -398,6 +397,64 @@ where
deserializer.deserialize_any(StringOrStruct(PhantomData))
}

fn opt_string_or_string_vec<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
where
T: Deserialize<'de> + std::str::FromStr<Err = std::convert::Infallible> + From<Vec<String>>,
D: serde::Deserializer<'de>,
{
use std::{fmt, marker::PhantomData};

use serde::de::{self, SeqAccess, Visitor};

struct StringOrStringVec<T>(PhantomData<fn() -> T>);

impl<'de, T> Visitor<'de> for StringOrStringVec<T>
where
T: Deserialize<'de> + FromStr<Err = std::convert::Infallible> + From<Vec<String>>,
{
type Value = Option<T>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("string or seq")
}

fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(FromStr::from_str(value).ok())
}

fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut vec: Vec<String> = vec![];

while let Some(inner) = seq.next_element::<String>()? {
vec.push(inner)
}
Ok(Some(vec.into()))
}

fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(None)
}

fn visit_unit<E>(self) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(None)
}
}

deserializer.deserialize_any(StringOrStringVec(PhantomData))
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -438,7 +495,7 @@ mod tests {
xargo: Some(true),
build_std: None,
default_target: None,
pre_build: Some(vec!["echo 'Hello World!'".to_string()]),
pre_build: Some(PreBuild::Lines(vec!["echo 'Hello World!'".to_string()])),
dockerfile: None,
},
};
Expand Down Expand Up @@ -477,7 +534,7 @@ mod tests {
image: Some("test-image".to_string()),
runner: None,
dockerfile: None,
pre_build: Some(vec![]),
pre_build: Some(PreBuild::Lines(vec![])),
},
);

Expand Down Expand Up @@ -520,7 +577,7 @@ mod tests {
context: None,
build_args: None,
}),
pre_build: Some(vec!["echo 'Hello'".to_string()]),
pre_build: Some(PreBuild::Lines(vec!["echo 'Hello'".to_string()])),
runner: None,
env: CrossEnvConfig {
passthrough: None,
Expand All @@ -539,7 +596,7 @@ mod tests {
xargo: Some(true),
build_std: None,
default_target: None,
pre_build: Some(vec![]),
pre_build: Some(PreBuild::Lines(vec![])),
dockerfile: None,
},
};
Expand Down Expand Up @@ -771,4 +828,22 @@ mod tests {

Ok(())
}

#[test]
fn pre_build_script() -> Result<()> {
let toml_str = r#"
[target.aarch64-unknown-linux-gnu]
pre-build = "./my-script.sh"
[build]
pre-build = ["echo Hello World"]
"#;
let (toml, unused) = CrossToml::parse_from_cross(toml_str, MSG_INFO)?;
assert!(unused.is_empty());
assert!(matches!(
toml.pre_build(&Target::new_built_in("aarch64-unknown-linux-gnu")),
(Some(&PreBuild::Lines(_)), Some(&PreBuild::Single(_)))
));
Ok(())
}
}
37 changes: 36 additions & 1 deletion src/docker/custom.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::io::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use crate::docker::Engine;
use crate::shell::MessageInfo;
Expand All @@ -22,6 +23,40 @@ pub enum Dockerfile<'a> {
},
}

#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum PreBuild {
/// A path to a file to copy or a single line to `RUN`
Single(String),
/// Lines to execute in a single `RUN`
Lines(Vec<String>),
}

impl FromStr for PreBuild {
type Err = std::convert::Infallible;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(PreBuild::Single(s.to_string()))
}
}

impl From<Vec<String>> for PreBuild {
fn from(vec: Vec<String>) -> Self {
PreBuild::Lines(vec)
}
}

impl PreBuild {
#[must_use]
pub fn is_single(&self) -> bool {
matches!(self, Self::Single(..))
}

#[must_use]
pub fn is_lines(&self) -> bool {
matches!(self, Self::Lines(..))
}
}

impl<'a> Dockerfile<'a> {
#[allow(clippy::too_many_arguments)]
pub fn build(
Expand Down Expand Up @@ -98,7 +133,7 @@ impl<'a> Dockerfile<'a> {
if let Some(context) = self.context() {
docker_build.arg(&context);
} else {
docker_build.arg(".");
docker_build.arg(host_root);
}

docker_build.run(msg_info, true)?;
Expand Down
2 changes: 1 addition & 1 deletion src/docker/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod custom;
pub mod custom;
mod engine;
mod local;
pub mod remote;
Expand Down
Loading

0 comments on commit 1222225

Please sign in to comment.