Skip to content

Commit

Permalink
Make image struct and rename Host -> TargetTriple
Browse files Browse the repository at this point in the history
  • Loading branch information
Emilgardis committed Jun 25, 2022
1 parent 48d2b7b commit d303111
Show file tree
Hide file tree
Showing 17 changed files with 938 additions and 251 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- #803 - added `CROSS_CUSTOM_TOOLCHAIN` to disable automatic installation of components for use with tools like `cargo-bisect-rustc`
- #817 - Toolchain images can now be specified as for a certain toolchain via `target.{target}.image.toolchain`
- #803, #817 - added `CROSS_CUSTOM_TOOLCHAIN` to disable automatic installation of components for use with tools like `cargo-bisect-rustc`
- #795 - added images for additional toolchains maintained by cross-rs.
- #792 - added `CROSS_CONTAINER_IN_CONTAINER` environment variable to replace `CROSS_DOCKER_IN_DOCKER`.
- #785 - added support for remote container engines through data volumes through setting the `CROSS_REMOTE` environment variable. also adds in utility commands to create and remove persistent data volumes.
Expand Down Expand Up @@ -54,6 +55,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Fixed

- #836 - write a `CACHEDIR.TAG` when creating the target directory, similar to `cargo`.
- #817 - made `cross +channel` parsing more compliant to parsing a toolchain
- #804 - allow usage of env `CARGO_BUILD_TARGET` as an alias for `CROSS_BUILD_TARGET`
- #792 - fixed container-in-container support when using podman.
- #781 - ensure `target.$(...)` config options override `build` ones.
Expand Down
46 changes: 33 additions & 13 deletions src/bin/commands/containers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use atty::Stream;
use clap::{Args, Subcommand};
use cross::{docker, CommandExt};
use cross::{
docker::{self, ImageArchitecture},
rustc::{QualifiedToolchain, Toolchain},
CommandExt,
};

#[derive(Args, Debug)]
pub struct ListVolumes {
Expand Down Expand Up @@ -76,7 +80,7 @@ pub struct CreateVolume {
}

impl CreateVolume {
pub fn run(self, engine: docker::Engine, channel: Option<&str>) -> cross::Result<()> {
pub fn run(self, engine: docker::Engine, channel: Option<&Toolchain>) -> cross::Result<()> {
create_persistent_volume(self, &engine, channel)
}
}
Expand All @@ -98,7 +102,7 @@ pub struct RemoveVolume {
}

impl RemoveVolume {
pub fn run(self, engine: docker::Engine, channel: Option<&str>) -> cross::Result<()> {
pub fn run(self, engine: docker::Engine, channel: Option<&Toolchain>) -> cross::Result<()> {
remove_persistent_volume(self, &engine, channel)
}
}
Expand All @@ -118,7 +122,7 @@ pub enum Volumes {
}

impl Volumes {
pub fn run(self, engine: docker::Engine, toolchain: Option<&str>) -> cross::Result<()> {
pub fn run(self, engine: docker::Engine, toolchain: Option<&Toolchain>) -> cross::Result<()> {
match self {
Volumes::List(args) => args.run(engine),
Volumes::RemoveAll(args) => args.run(engine),
Expand Down Expand Up @@ -296,12 +300,19 @@ pub fn create_persistent_volume(
..
}: CreateVolume,
engine: &docker::Engine,
channel: Option<&str>,
channel: Option<&Toolchain>,
) -> cross::Result<()> {
// we only need a triple that needs docker: the actual target doesn't matter.
let triple = cross::Host::X86_64UnknownLinuxGnu.triple();
let (target, metadata, dirs) =
docker::get_package_info(engine, triple, channel, docker_in_docker, verbose)?;
let target = cross::Target::BuiltIn {
triple: cross::TargetTriple::X86_64UnknownLinuxGnu,
};
let mut toolchain = QualifiedToolchain::default(verbose)?;
if let Some(channel) = channel {
toolchain = toolchain.with_picked(channel.clone(), verbose)?;
} else {
toolchain.replace_host(&ImageArchitecture::from_target(target.target().clone()));
};
let (metadata, dirs) = docker::get_package_info(engine, &toolchain, docker_in_docker, verbose)?;
let container = docker::remote::unique_container_identifier(&target, &metadata, &dirs)?;
let volume = docker::remote::unique_toolchain_identifier(&dirs.sysroot)?;

Expand Down Expand Up @@ -358,7 +369,7 @@ pub fn create_persistent_volume(
engine,
&container,
&dirs.sysroot,
&target,
target.target(),
mount_prefix.as_ref(),
true,
verbose,
Expand All @@ -372,16 +383,25 @@ pub fn create_persistent_volume(

pub fn remove_persistent_volume(
RemoveVolume {
target,
target: _,
docker_in_docker,
verbose,
..
}: RemoveVolume,
engine: &docker::Engine,
channel: Option<&str>,
channel: Option<&Toolchain>,
) -> cross::Result<()> {
let (_, _, dirs) =
docker::get_package_info(engine, &target, channel, docker_in_docker, verbose)?;
// we only need a triple that needs docker: the actual target doesn't matter.
let target = cross::Target::BuiltIn {
triple: cross::TargetTriple::X86_64UnknownLinuxGnu,
};
let mut toolchain = QualifiedToolchain::default(verbose)?;
if let Some(channel) = channel {
toolchain = toolchain.with_picked(channel.clone(), verbose)?;
} else {
toolchain.replace_host(&ImageArchitecture::from_target(target.target().clone()));
};
let (_, dirs) = docker::get_package_info(engine, &toolchain, docker_in_docker, verbose)?;
let volume = docker::remote::unique_toolchain_identifier(&dirs.sysroot)?;

if !docker::remote::volume_exists(engine, &volume, verbose)? {
Expand Down
6 changes: 3 additions & 3 deletions src/bin/cross-util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![deny(missing_debug_implementations, rust_2018_idioms)]

use clap::{CommandFactory, Parser, Subcommand};
use cross::docker;
use cross::{docker, rustc::Toolchain};

mod commands;

Expand All @@ -10,7 +10,7 @@ mod commands;
struct Cli {
/// Toolchain name/version to use (such as stable or 1.59.0).
#[clap(value_parser = is_toolchain)]
toolchain: Option<String>,
toolchain: Option<Toolchain>,
#[clap(subcommand)]
command: Commands,
}
Expand Down Expand Up @@ -65,7 +65,7 @@ pub fn main() -> cross::Result<()> {
}
Commands::Volumes(args) => {
let engine = get_container_engine(args.engine(), args.verbose())?;
args.run(engine, cli.toolchain.as_deref())?;
args.run(engine, cli.toolchain.as_ref())?;
}
Commands::Containers(args) => {
let engine = get_container_engine(args.engine(), args.verbose())?;
Expand Down
39 changes: 38 additions & 1 deletion src/bin/cross.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,47 @@
#![deny(missing_debug_implementations, rust_2018_idioms)]

use std::{
env,
io::{self, Write},
};

use cross::{cargo, cli, rustc, OutputExt, Subcommand};

pub fn main() -> cross::Result<()> {
cross::install_panic_hook()?;
cross::install_termination_hook()?;

let status = cross::run()?;
let target_list = rustc::target_list(false)?;
let args = cli::parse(&target_list)?;
let subcommand = args.subcommand;
let verbose = args
.all
.iter()
.any(|a| a == "--verbose" || a == "-v" || a == "-vv");
let status = match cross::run(args, target_list, verbose)? {
Some(status) => status,
None => {
// if we fallback to the host cargo, use the same invocation that was made to cross
let argv: Vec<String> = env::args().skip(1).collect();
eprintln!("Warning: Falling back to `cargo` on the host.");
match subcommand {
Some(Subcommand::List) => {
// this won't print in order if we have both stdout and stderr.
let out = cargo::run_and_get_output(&argv, verbose)?;
let stdout = out.stdout()?;
if out.status.success() && cli::is_subcommand_list(&stdout) {
cli::fmt_subcommands(&stdout);
} else {
// Not a list subcommand, which can happen with weird edge-cases.
print!("{}", stdout);
io::stdout().flush().unwrap();
}
out.status
}
_ => cargo::run(&argv, verbose)?,
}
}
};
let code = status
.code()
.ok_or_else(|| eyre::Report::msg("Cargo process terminated by signal"))?;
Expand Down
32 changes: 22 additions & 10 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::docker::{ImageArchitecture, PossibleImage};
use crate::{CrossToml, Result, Target, TargetList};

use std::collections::HashMap;
Expand Down Expand Up @@ -64,8 +65,18 @@ impl Environment {
self.get_values_for("BUILD_STD", target, bool_from_envvar)
}

fn image(&self, target: &Target) -> Option<String> {
fn image(&self, target: &Target) -> Result<Option<PossibleImage>> {
self.get_target_var(target, "IMAGE")
.map(|i| i.parse().expect("infallible"))
.map(|mut i: PossibleImage| {
if let Some(toolchain) = self.get_target_var(target, "IMAGE_TOOLCHAIN") {
i.toolchain = Some(ImageArchitecture::from_target(toolchain.into()));
Ok(i)
} else {
Ok(i)
}
})
.transpose()
}

fn dockerfile(&self, target: &Target) -> Option<String> {
Expand Down Expand Up @@ -178,12 +189,12 @@ impl Config {
None
}

fn string_from_config(
fn get_config<'a, T: 'a>(
&self,
target: &Target,
env: impl Fn(&Environment, &Target) -> Option<String>,
config: impl Fn(&CrossToml, &Target) -> Option<String>,
) -> Result<Option<String>> {
env: impl Fn(&Environment, &Target) -> Option<T>,
config: impl Fn(&CrossToml, &Target) -> Option<T>,
) -> Result<Option<T>> {
let env_value = env(&self.env, target);
if let Some(env_value) = env_value {
return Ok(Some(env_value));
Expand Down Expand Up @@ -239,12 +250,13 @@ impl Config {
self.bool_from_config(target, Environment::build_std, CrossToml::build_std)
}

pub fn image(&self, target: &Target) -> Result<Option<String>> {
self.string_from_config(target, Environment::image, CrossToml::image)
pub fn image(&self, target: &Target) -> Result<Option<PossibleImage>> {
let env = self.env.image(target)?;
self.get_config(target, move |_, _| env.clone(), CrossToml::image)
}

pub fn runner(&self, target: &Target) -> Result<Option<String>> {
self.string_from_config(target, Environment::runner, CrossToml::runner)
self.get_config(target, Environment::runner, CrossToml::runner)
}

pub fn env_passthrough(&self, target: &Target) -> Result<Option<Vec<String>>> {
Expand All @@ -270,11 +282,11 @@ impl Config {
}

pub fn dockerfile(&self, target: &Target) -> Result<Option<String>> {
self.string_from_config(target, Environment::dockerfile, CrossToml::dockerfile)
self.get_config(target, Environment::dockerfile, CrossToml::dockerfile)
}

pub fn dockerfile_context(&self, target: &Target) -> Result<Option<String>> {
self.string_from_config(
self.get_config(
target,
Environment::dockerfile_context,
CrossToml::dockerfile_context,
Expand Down
31 changes: 21 additions & 10 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::PossibleImage;
use crate::{config, errors::*};
use crate::{Target, TargetList};
use serde::de::DeserializeOwned;
Expand Down Expand Up @@ -34,7 +35,8 @@ pub struct CrossBuildConfig {
pub struct CrossTargetConfig {
xargo: Option<bool>,
build_std: Option<bool>,
image: Option<String>,
#[serde(default, deserialize_with = "opt_string_or_struct")]
image: Option<PossibleImage>,
#[serde(default, deserialize_with = "opt_string_or_struct")]
dockerfile: Option<CrossTargetDockerfileConfig>,
pre_build: Option<Vec<String>>,
Expand Down Expand Up @@ -195,7 +197,7 @@ impl CrossToml {
}

/// Returns the `target.{}.image` part of `Cross.toml`
pub fn image(&self, target: &Target) -> Option<String> {
pub fn image(&self, target: &Target) -> Option<PossibleImage> {
self.get_string(target, |_| None, |t| t.image.as_ref())
}

Expand Down Expand Up @@ -284,12 +286,12 @@ impl CrossToml {
self.targets.get(target)
}

fn get_string<'a>(
fn get_string<'a, T: Clone + 'a>(
&'a self,
target: &Target,
get_build: impl Fn(&'a CrossBuildConfig) -> Option<&'a String>,
get_target: impl Fn(&'a CrossTargetConfig) -> Option<&'a String>,
) -> Option<String> {
get_build: impl Fn(&'a CrossBuildConfig) -> Option<&'a T>,
get_target: impl Fn(&'a CrossTargetConfig) -> Option<&'a T>,
) -> Option<T> {
self.get_target(target)
.and_then(get_target)
.or_else(|| get_build(&self.build))
Expand Down Expand Up @@ -380,6 +382,8 @@ where

#[cfg(test)]
mod tests {
use crate::docker::ImageArchitecture;

use super::*;

#[test]
Expand Down Expand Up @@ -435,7 +439,7 @@ mod tests {
let mut target_map = HashMap::new();
target_map.insert(
Target::BuiltIn {
triple: "aarch64-unknown-linux-gnu".to_string(),
triple: "aarch64-unknown-linux-gnu".into(),
},
CrossTargetConfig {
env: CrossEnvConfig {
Expand All @@ -444,7 +448,7 @@ mod tests {
},
xargo: Some(false),
build_std: Some(true),
image: Some("test-image".to_string()),
image: Some("test-image".parse().expect("infallible")),
runner: None,
dockerfile: None,
pre_build: Some(vec![]),
Expand Down Expand Up @@ -479,12 +483,17 @@ mod tests {
let mut target_map = HashMap::new();
target_map.insert(
Target::BuiltIn {
triple: "aarch64-unknown-linux-gnu".to_string(),
triple: "aarch64-unknown-linux-gnu".into(),
},
CrossTargetConfig {
xargo: Some(false),
build_std: None,
image: None,
image: Some(PossibleImage {
name: "test-image".to_string(),
toolchain: Some(ImageArchitecture::from_target(
"aarch64-unknown-linux-musl".into(),
)),
}),
dockerfile: Some(CrossTargetDockerfileConfig {
file: "Dockerfile.test".to_string(),
context: None,
Expand Down Expand Up @@ -526,6 +535,8 @@ mod tests {
xargo = false
dockerfile = "Dockerfile.test"
pre-build = ["echo 'Hello'"]
image.name = "test-image"
image.toolchain = "aarch64-unknown-linux-musl"
[target.aarch64-unknown-linux-gnu.env]
volumes = ["VOL"]
Expand Down
Loading

0 comments on commit d303111

Please sign in to comment.