Skip to content

Commit 1aab4cf

Browse files
committed
Add interactive mode to cross-util run
1 parent be92c3f commit 1aab4cf

File tree

9 files changed

+74
-53
lines changed

9 files changed

+74
-53
lines changed

.changes/1280.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "Allow to run arbitrary commands in containers using `cross-util run ...`",
3+
"issues": [1266],
4+
"type": "added",
5+
"breaking": false
6+
}

CHANGELOG.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ This project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased] - ReleaseDate
99

10-
- #1266 Allow to run arbitrary commands in containers using `cross-util run --target <target> --command <command>`
11-
1210
## [v0.2.5] - 2023-02-04
1311

1412
## Fixed

src/bin/commands/run.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use clap::Args as ClapArgs;
22
use cross::config::Config;
33
use cross::shell::{MessageInfo, Verbosity};
4-
use cross::SafeCommand;
54
use cross::{
6-
cargo_metadata_with_args, cli::Args, docker, rustc, setup, toml, CargoVariant, CrossSetup,
5+
cargo_metadata_with_args, cli::Args, docker, rustc, setup, toml, CommandVariant, CrossSetup,
76
Target,
87
};
98
use eyre::Context;
@@ -22,11 +21,14 @@ pub struct Run {
2221
/// Container engine (such as docker or podman).
2322
#[clap(long)]
2423
pub engine: Option<String>,
25-
24+
/// Target
2625
#[clap(short, long)]
2726
pub target: String,
28-
29-
#[clap(short, long)]
27+
/// Interactive session
28+
#[clap(short, long, default_value = "false")]
29+
pub interactive: bool,
30+
/// Command to run, will be run in a shell
31+
#[clap(last = true)]
3032
pub command: String,
3133
}
3234

@@ -76,14 +78,20 @@ impl Run {
7678
let image = image.to_definite_with(&engine, msg_info);
7779

7880
let paths = docker::DockerPaths::create(&engine, metadata, cwd, toolchain, msg_info)?;
79-
let options =
80-
docker::DockerOptions::new(engine, target, config, image, CargoVariant::None, None);
81+
let options = docker::DockerOptions::new(
82+
engine,
83+
target,
84+
config,
85+
image,
86+
CommandVariant::Shell,
87+
None,
88+
self.interactive,
89+
);
8190

82-
let command = SafeCommand::new("sh");
8391
let mut args = vec![String::from("-c")];
8492
args.push(self.command.clone());
8593

86-
docker::run(options, paths, command, &args, None, msg_info)
94+
docker::run(options, paths, &args, None, msg_info)
8795
.wrap_err("could not run container")?;
8896
}
8997

src/docker/custom.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl<'a> Dockerfile<'a> {
8585
build_args: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
8686
msg_info: &mut MessageInfo,
8787
) -> Result<String> {
88-
let uses_zig = options.cargo_variant.uses_zig();
88+
let uses_zig = options.command_variant.uses_zig();
8989
let mut docker_build = options.engine.command();
9090
docker_build.invoke_build_command();
9191
docker_build.disable_scan_suggest();

src/docker/local.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::sync::atomic::Ordering;
55

66
use super::shared::*;
77
use crate::errors::Result;
8-
use crate::extensions::{CommandExt, SafeCommand};
8+
use crate::extensions::CommandExt;
99
use crate::file::{PathExt, ToUtf8};
1010
use crate::shell::{MessageInfo, Stream};
1111
use eyre::Context;
@@ -29,14 +29,14 @@ fn mount(
2929
pub(crate) fn run(
3030
options: DockerOptions,
3131
paths: DockerPaths,
32-
mut cmd: SafeCommand,
3332
args: &[String],
3433
msg_info: &mut MessageInfo,
3534
) -> Result<ExitStatus> {
3635
let engine = &options.engine;
3736
let toolchain_dirs = paths.directories.toolchain_directories();
3837
let package_dirs = paths.directories.package_directories();
3938

39+
let mut cmd = options.command_variant.safe_command();
4040
cmd.args(args);
4141

4242
let mut docker = engine.subcommand("run");
@@ -134,6 +134,11 @@ pub(crate) fn run(
134134
if io::Stdin::is_atty() && io::Stdout::is_atty() && io::Stderr::is_atty() {
135135
docker.arg("-t");
136136
}
137+
138+
if options.interactive {
139+
docker.arg("-i");
140+
}
141+
137142
let mut image_name = options.image.name.clone();
138143
if options.needs_custom_image() {
139144
image_name = options

src/docker/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ pub use image::{Architecture, Image, ImagePlatform, Os as ContainerOs, PossibleI
1717
use std::process::ExitStatus;
1818

1919
use crate::errors::*;
20-
use crate::extensions::SafeCommand;
2120
use crate::shell::MessageInfo;
2221

2322
#[derive(Debug)]
@@ -45,7 +44,6 @@ pub fn image_name(target: &str, sub: Option<&str>, repository: &str, tag: &str)
4544
pub fn run(
4645
options: DockerOptions,
4746
paths: DockerPaths,
48-
command: SafeCommand,
4947
args: &[String],
5048
subcommand: Option<crate::Subcommand>,
5149
msg_info: &mut MessageInfo,
@@ -57,9 +55,9 @@ pub fn run(
5755
);
5856
}
5957
if options.is_remote() {
60-
remote::run(options, paths, command, args, subcommand, msg_info)
58+
remote::run(options, paths, args, subcommand, msg_info)
6159
.wrap_err("could not complete remote run")
6260
} else {
63-
local::run(options, paths, command, args, msg_info)
61+
local::run(options, paths, args, msg_info)
6462
}
6563
}

src/docker/remote.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ use super::engine::Engine;
1010
use super::shared::*;
1111
use crate::config::bool_from_envvar;
1212
use crate::errors::Result;
13-
use crate::extensions::{CommandExt, SafeCommand};
13+
use crate::extensions::CommandExt;
1414
use crate::file::{self, PathExt, ToUtf8};
1515
use crate::rustc::{self, QualifiedToolchain, VersionMetaExt};
1616
use crate::shell::{MessageInfo, Stream};
17+
use crate::temp;
1718
use crate::TargetTriple;
18-
use crate::{temp, CargoVariant};
1919

2020
// prevent further commands from running if we handled
2121
// a signal earlier, and the volume is exited.
@@ -667,7 +667,6 @@ impl QualifiedToolchain {
667667
pub(crate) fn run(
668668
options: DockerOptions,
669669
paths: DockerPaths,
670-
mut cmd: SafeCommand,
671670
args: &[String],
672671
subcommand: Option<crate::Subcommand>,
673672
msg_info: &mut MessageInfo,
@@ -896,7 +895,9 @@ pub(crate) fn run(
896895
}
897896
}
898897

899-
if options.cargo_variant != CargoVariant::None {
898+
let mut cmd = options.command_variant.safe_command();
899+
900+
if !options.command_variant.is_shell() {
900901
// `clean` doesn't handle symlinks: it will just unlink the target
901902
// directory, so we should just substitute it our target directory
902903
// for it. we'll still have the same end behavior
@@ -976,6 +977,11 @@ symlink_recurse \"${{prefix}}\"
976977
docker.add_cwd(&paths)?;
977978
docker.arg(&container_id);
978979
docker.add_build_command(toolchain_dirs, &cmd);
980+
981+
if options.interactive {
982+
docker.arg("-i");
983+
}
984+
979985
bail_container_exited!();
980986
let status = docker
981987
.run_and_get_status(msg_info, false)

src/docker/shared.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::file::{self, write_file, PathExt, ToUtf8};
1717
use crate::id;
1818
use crate::rustc::QualifiedToolchain;
1919
use crate::shell::{ColorChoice, MessageInfo, Verbosity};
20-
use crate::{CargoVariant, OutputExt, Target, TargetTriple};
20+
use crate::{CommandVariant, OutputExt, Target, TargetTriple};
2121

2222
use rustc_version::Version as RustcVersion;
2323

@@ -33,9 +33,10 @@ pub struct DockerOptions {
3333
pub target: Target,
3434
pub config: Config,
3535
pub image: Image,
36-
pub cargo_variant: CargoVariant,
36+
pub command_variant: CommandVariant,
3737
// not all toolchains will provide this
3838
pub rustc_version: Option<RustcVersion>,
39+
pub interactive: bool,
3940
}
4041

4142
impl DockerOptions {
@@ -44,16 +45,18 @@ impl DockerOptions {
4445
target: Target,
4546
config: Config,
4647
image: Image,
47-
cargo_variant: CargoVariant,
48+
cargo_variant: CommandVariant,
4849
rustc_version: Option<RustcVersion>,
50+
interactive: bool,
4951
) -> DockerOptions {
5052
DockerOptions {
5153
engine,
5254
target,
5355
config,
5456
image,
55-
cargo_variant,
57+
command_variant: cargo_variant,
5658
rustc_version,
59+
interactive,
5760
}
5861
}
5962

@@ -928,8 +931,8 @@ fn validate_env_var<'a>(
928931
Ok((key, value))
929932
}
930933

931-
impl CargoVariant {
932-
pub(crate) fn safe_command(self) -> SafeCommand {
934+
impl CommandVariant {
935+
pub(crate) fn safe_command(&self) -> SafeCommand {
933936
SafeCommand::new(self.to_str())
934937
}
935938
}
@@ -1041,7 +1044,7 @@ impl DockerCommandExt for Command {
10411044
])
10421045
.args(["-e", "CARGO_TARGET_DIR=/target"])
10431046
.args(["-e", &cross_runner]);
1044-
if options.cargo_variant.uses_zig() {
1047+
if options.command_variant.uses_zig() {
10451048
// otherwise, zig has a permission error trying to create the cache
10461049
self.args(["-e", "XDG_CACHE_HOME=/target/.zig-cache"]);
10471050
}

src/lib.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -443,38 +443,42 @@ impl Serialize for Target {
443443
}
444444

445445
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
446-
pub enum CargoVariant {
446+
pub enum CommandVariant {
447447
Cargo,
448448
Xargo,
449449
Zig,
450-
None,
450+
Shell,
451451
}
452452

453-
impl CargoVariant {
454-
pub fn create(uses_zig: bool, uses_xargo: bool) -> Result<CargoVariant> {
453+
impl CommandVariant {
454+
pub fn create(uses_zig: bool, uses_xargo: bool) -> Result<CommandVariant> {
455455
match (uses_zig, uses_xargo) {
456456
(true, true) => eyre::bail!("cannot use both zig and xargo"),
457-
(true, false) => Ok(CargoVariant::Zig),
458-
(false, true) => Ok(CargoVariant::Xargo),
459-
(false, false) => Ok(CargoVariant::Cargo),
457+
(true, false) => Ok(CommandVariant::Zig),
458+
(false, true) => Ok(CommandVariant::Xargo),
459+
(false, false) => Ok(CommandVariant::Cargo),
460460
}
461461
}
462462

463463
pub fn to_str(self) -> &'static str {
464464
match self {
465-
CargoVariant::Cargo => "cargo",
466-
CargoVariant::Xargo => "xargo",
467-
CargoVariant::Zig => "cargo-zigbuild",
468-
CargoVariant::None => "",
465+
CommandVariant::Cargo => "cargo",
466+
CommandVariant::Xargo => "xargo",
467+
CommandVariant::Zig => "cargo-zigbuild",
468+
CommandVariant::Shell => "sh",
469469
}
470470
}
471471

472472
pub fn uses_xargo(self) -> bool {
473-
self == CargoVariant::Xargo
473+
self == CommandVariant::Xargo
474474
}
475475

476476
pub fn uses_zig(self) -> bool {
477-
self == CargoVariant::Zig
477+
self == CommandVariant::Zig
478+
}
479+
480+
pub(crate) fn is_shell(self) -> bool {
481+
self == CommandVariant::Shell
478482
}
479483
}
480484

@@ -606,8 +610,9 @@ pub fn run(
606610
target.clone(),
607611
config,
608612
image,
609-
crate::CargoVariant::create(uses_zig, uses_xargo)?,
613+
crate::CommandVariant::create(uses_zig, uses_xargo)?,
610614
rustc_version,
615+
false,
611616
);
612617

613618
install_interpreter_if_needed(
@@ -617,16 +622,8 @@ pub fn run(
617622
&options,
618623
msg_info,
619624
)?;
620-
let cmd = options.cargo_variant.safe_command();
621-
let status = docker::run(
622-
options,
623-
paths,
624-
cmd,
625-
&filtered_args,
626-
args.subcommand,
627-
msg_info,
628-
)
629-
.wrap_err("could not run container")?;
625+
let status = docker::run(options, paths, &filtered_args, args.subcommand, msg_info)
626+
.wrap_err("could not run container")?;
630627
let needs_host = args.subcommand.map_or(false, |sc| sc.needs_host(is_remote));
631628
if !status.success() {
632629
warn_on_failure(&target, &toolchain, msg_info)?;

0 commit comments

Comments
 (0)