-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
1,169 additions
and
455 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,218 +1,96 @@ | ||
use std::path::Path; | ||
use std::{path::Path, process::Command, str::FromStr}; | ||
|
||
use color_eyre::{ | ||
eyre::{bail, Context, ContextCompat}, | ||
Result, | ||
}; | ||
use log::info; | ||
use tokio::process::Command; | ||
|
||
use crate::data_home::get_data_home; | ||
|
||
pub enum Executor { | ||
Native, | ||
Docker, | ||
} | ||
|
||
pub struct Environment { | ||
pub executor: Executor, | ||
pub version: String, | ||
#[derive(Debug, Clone)] | ||
pub enum Sdk { | ||
Installed { version: String }, | ||
Docker { image: String }, | ||
} | ||
|
||
pub enum Cargo { | ||
pub enum Environment { | ||
Native, | ||
Sdk { environment: Environment }, | ||
Sdk(Sdk), | ||
} | ||
|
||
impl Cargo { | ||
pub fn native() -> Self { | ||
Cargo::Native | ||
} | ||
|
||
pub fn sdk(environment: Environment) -> Self { | ||
Cargo::Sdk { environment } | ||
} | ||
|
||
pub fn command<'a>( | ||
self, | ||
sub_command: &'a str, | ||
repository_root: &'a Path, | ||
) -> Result<CargoCommand<'a>> { | ||
Ok(CargoCommand { | ||
cargo: self, | ||
sub_command, | ||
repository_root, | ||
manifest_path: None, | ||
profile: None, | ||
workspace: false, | ||
all_features: false, | ||
all_targets: false, | ||
features: None, | ||
passthrough_arguments: None, | ||
}) | ||
} | ||
pub enum Host { | ||
Local, | ||
Remote, | ||
} | ||
|
||
pub struct CargoCommand<'a> { | ||
cargo: Cargo, | ||
sub_command: &'a str, | ||
repository_root: &'a Path, | ||
manifest_path: Option<&'a Path>, | ||
profile: Option<&'a str>, | ||
workspace: bool, | ||
all_features: bool, | ||
all_targets: bool, | ||
features: Option<&'a [String]>, | ||
passthrough_arguments: Option<&'a [String]>, | ||
pub struct Cargo { | ||
host: Host, | ||
environment: Environment, | ||
} | ||
|
||
impl<'a> CargoCommand<'a> { | ||
pub fn manifest_path(&mut self, manifest_path: &'a Path) -> Result<()> { | ||
if !manifest_path.is_relative() { | ||
bail!("manifest path must be relative to repository root") | ||
impl Cargo { | ||
pub fn local(environment: Environment) -> Self { | ||
Self { | ||
host: Host::Local, | ||
environment, | ||
} | ||
self.manifest_path = Some(manifest_path); | ||
Ok(()) | ||
} | ||
|
||
pub fn profile(&mut self, profile: &'a str) { | ||
self.profile = Some(profile); | ||
} | ||
|
||
pub fn workspace(&mut self) { | ||
self.workspace = true; | ||
} | ||
|
||
pub fn all_features(&mut self) { | ||
self.all_features = true; | ||
} | ||
|
||
pub fn all_targets(&mut self) { | ||
self.all_targets = true; | ||
} | ||
|
||
pub fn features(&mut self, features: &'a [String]) { | ||
self.features = Some(features); | ||
} | ||
|
||
pub fn passthrough_arguments(&mut self, passthrough_arguments: &'a [String]) { | ||
self.passthrough_arguments = Some(passthrough_arguments); | ||
pub fn remote(environment: Environment) -> Self { | ||
Self { | ||
host: Host::Remote, | ||
environment, | ||
} | ||
} | ||
|
||
pub fn shell_command(self) -> Result<String> { | ||
let mut cargo_arguments = String::new(); | ||
|
||
if let Some(manifest_path) = self.manifest_path { | ||
cargo_arguments.push_str(&format!( | ||
"--manifest-path {path}", | ||
path = manifest_path | ||
.to_str() | ||
.wrap_err("failed to convert manifest path to string")? | ||
)); | ||
} | ||
if let Some(profile) = self.profile { | ||
cargo_arguments.push_str(&format!(" --profile {profile}")); | ||
} | ||
if self.workspace { | ||
cargo_arguments.push_str(" --workspace"); | ||
} | ||
if self.all_features { | ||
cargo_arguments.push_str(" --all-features"); | ||
} | ||
if self.all_targets { | ||
cargo_arguments.push_str(" --all-targets"); | ||
} | ||
if let Some(features) = self.features { | ||
cargo_arguments.push_str(" --features "); | ||
cargo_arguments.push_str(&features.join(",")); | ||
} | ||
if let Some(passthrough_arguments) = self.passthrough_arguments { | ||
cargo_arguments.push_str(" -- "); | ||
cargo_arguments.push_str(&passthrough_arguments.join(" ")); | ||
} | ||
pub fn command(self, repository_root: impl AsRef<Path>) -> Result<Command> { | ||
let repository_root = repository_root.as_ref(); | ||
|
||
let shell_command = match self.cargo { | ||
Cargo::Native => { | ||
format!( | ||
"cd {repository_root} && cargo {command} {cargo_arguments}", | ||
repository_root = self | ||
.repository_root | ||
.to_str() | ||
.wrap_err("failed to convert repository root to string")?, | ||
command = self.sub_command, | ||
) | ||
} | ||
Cargo::Sdk { | ||
environment: | ||
Environment { | ||
executor: Executor::Native, | ||
version, | ||
}, | ||
} => { | ||
// TODO: implement remote | ||
let command = match self.environment { | ||
Environment::Native => Command::new("cargo"), | ||
Environment::Sdk(Sdk::Installed { version }) => { | ||
let data_home = get_data_home().wrap_err("failed to get data home")?; | ||
let environment_file = &data_home.join(format!( | ||
"sdk/{version}/environment-setup-corei7-64-aldebaran-linux" | ||
)); | ||
let sdk_environment_setup = environment_file | ||
.to_str() | ||
.wrap_err("failed to convert sdk environment setup path to string")?; | ||
let cargo_command = format!( | ||
"cargo {command} {cargo_arguments}", | ||
command = self.sub_command, | ||
); | ||
format!( | ||
"cd {repository_root} && . {sdk_environment_setup} && {cargo_command}", | ||
repository_root = self | ||
.repository_root | ||
.to_str() | ||
.wrap_err("failed to convert repository root to string")?, | ||
) | ||
let mut command = Command::new("bash"); | ||
command | ||
.arg("-c") | ||
.arg(format!(". {sdk_environment_setup} && cargo $@")) | ||
.arg("cargo"); | ||
command | ||
} | ||
Cargo::Sdk { | ||
environment: | ||
Environment { | ||
executor: Executor::Docker, | ||
version, | ||
}, | ||
} => { | ||
Environment::Sdk(Sdk::Docker { image }) => { | ||
let data_home = get_data_home().wrap_err("failed to get data home")?; | ||
let cargo_home = data_home.join("container-cargo-home/"); | ||
// TODO: This has to cd into the current pwd first | ||
let mut command = Command::new("bash"); | ||
command.arg("-c"); | ||
command.arg( | ||
format!("\ | ||
mkdir -p {cargo_home} && | ||
mkdir -p {cargo_home} && \ | ||
docker run \ | ||
--volume={repository_root}:/hulk:z \ | ||
--volume={cargo_home}:/naosdk/sysroots/corei7-64-aldebaran-linux/home/cargo:Z \ | ||
--volume={cargo_home}:/naosdk/sysroots/corei7-64-aldebaran-linux/home/cargo:z \ | ||
--rm \ | ||
--interactive \ | ||
--tty ghcr.io/hulks/naosdk:{version} \ | ||
--tty {image} \ | ||
/bin/bash -c \"\ | ||
cd /hulk && \ | ||
. /naosdk/environment-setup-corei7-64-aldebaran-linux && \ | ||
cargo {command} {cargo_arguments}\ | ||
cargo $@\ | ||
\" | ||
", | ||
repository_root=self.repository_root.to_str().wrap_err("failed to convert repository root to string")?, | ||
repository_root=repository_root.to_str().wrap_err("failed to convert repository root to string")?, | ||
cargo_home=cargo_home.to_str().wrap_err("failed to convert cargo home to string")?, | ||
command=self.sub_command, | ||
) | ||
)).arg("cargo"); | ||
command | ||
} | ||
}; | ||
Ok(shell_command) | ||
} | ||
} | ||
|
||
pub async fn run_shell(command: &str) -> Result<()> { | ||
info!("Executing command: `{command}`"); | ||
|
||
let status = Command::new("sh") | ||
.arg("-c") | ||
.arg(command) | ||
.status() | ||
.await | ||
.wrap_err("failed to execute cargo command")?; | ||
|
||
if !status.success() { | ||
bail!("cargo command exited with {status}"); | ||
Ok(command) | ||
} | ||
Ok(()) | ||
} |
Oops, something went wrong.