Skip to content

Commit

Permalink
Add a cargo-dist-url-override key
Browse files Browse the repository at this point in the history
  • Loading branch information
fasterthanlime committed Nov 1, 2024
1 parent 33316c5 commit d97bb5e
Show file tree
Hide file tree
Showing 9 changed files with 194 additions and 65 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 36 additions & 2 deletions cargo-dist-schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,7 @@ pub struct GithubMatrixEntry {
#[serde(skip_serializing_if = "Option::is_none")]
pub runner: Option<GithubRunner>,
/// Expression to execute to install dist
#[serde(skip_serializing_if = "Option::is_none")]
pub install_dist: Option<String>,
pub install_dist: GhaRunStep,
/// Arguments to pass to dist
#[serde(skip_serializing_if = "Option::is_none")]
pub dist_args: Option<String>,
Expand All @@ -315,6 +314,41 @@ pub struct GithubMatrixEntry {
pub cache_provider: Option<String>,
}

/// A GitHub Actions "run" step, either bash or powershell
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
// this mirrors GHA's structure, see
// * <https://serde.rs/enum-representations.html>
// * <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell>
#[serde(tag = "shell", content = "run")]
pub enum GhaRunStep {
/// see [`DashScript`]
#[serde(rename = "sh")]
Dash(DashScript),
/// see [`PowershellScript`]
#[serde(rename = "pwsh")]
Powershell(PowershellScript),
}

impl From<DashScript> for GhaRunStep {
fn from(bash: DashScript) -> Self {
Self::Dash(bash)
}
}

impl From<PowershellScript> for GhaRunStep {
fn from(powershell: PowershellScript) -> Self {
Self::Powershell(powershell)
}
}

declare_strongly_typed_string! {
/// A bit of shell script (that can run with `/bin/sh`), ran on CI runners. Can be multi-line.
pub struct DashScript => &DashScriptRef;

/// A bit of powershell script, ran on CI runners. Can be multi-line.
pub struct PowershellScript => &PowershellScriptRef;
}

/// Type of job to run on pull request
#[derive(
Debug, Copy, Clone, Serialize, Deserialize, JsonSchema, Default, PartialEq, Eq, PartialOrd, Ord,
Expand Down
1 change: 1 addition & 0 deletions cargo-dist/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ spdx.workspace = true
base64.workspace = true
lazy_static.workspace = true
current_platform.workspace = true
schemars.workspace = true

[dev-dependencies]
insta.workspace = true
Expand Down
51 changes: 31 additions & 20 deletions cargo-dist/src/backend/ci/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use axoasset::{LocalAsset, SourceFile};
use axoprocess::Cmd;
use camino::{Utf8Path, Utf8PathBuf};
use cargo_dist_schema::{
GithubMatrix, GithubMatrixEntry, GithubRunner, GithubRunnerRef, TargetTriple, TargetTripleRef,
GhaRunStep, GithubMatrix, GithubMatrixEntry, GithubRunner, GithubRunnerRef, TargetTriple,
TargetTripleRef,
};
use serde::{Deserialize, Serialize};
use tracing::warn;
Expand All @@ -24,24 +25,30 @@ use crate::{
DistError, DistGraph, SortedMap, SortedSet,
};

use super::{DistInstallSettings, DistInstallStrategy};

#[cfg(not(windows))]
const GITHUB_CI_DIR: &str = ".github/workflows/";
#[cfg(windows)]
const GITHUB_CI_DIR: &str = r".github\workflows\";
const GITHUB_CI_FILE: &str = "release.yml";

/// Info about running dist in Github CI
///
/// THESE FIELDS ARE LOAD-BEARING because they're used in the templates.
#[derive(Debug, Serialize)]
pub struct GithubCiInfo {
/// Cached path to github CI workflows dir
#[serde(skip_serializing)]
pub github_ci_workflow_dir: Utf8PathBuf,
/// Version of rust toolchain to install (deprecated)
pub rust_version: Option<String>,
/// expression to use for installing dist via shell script
pub install_dist_sh: String,
/// expression to use for installing dist via powershell script
pub install_dist_ps1: String,

// TODO: do something so the templates can actually use this to generate
// shell/powershell — or just pregenerate it.
//
/// Our install strategy for dist itself
pub dist_install_strategy: DistInstallStrategy,
/// Whether to fail-fast
pub fail_fast: bool,
/// Whether to cache builds
Expand Down Expand Up @@ -216,8 +223,12 @@ impl GithubCiInfo {
}

// Get the platform-specific installation methods
let install_dist_sh = super::install_dist_sh_for_version(dist_version);
let install_dist_ps1 = super::install_dist_ps1_for_version(dist_version);
let dist_install_strategy = (DistInstallSettings {
version: dist_version,
url_override: dist.config.dist_url_override.as_deref(),
})
.install_strategy();

let hosting_providers = dist
.hosting
.as_ref()
Expand Down Expand Up @@ -245,7 +256,7 @@ impl GithubCiInfo {
cache_provider: cache_provider_for_runner(global_runner),
runner: Some(global_runner.to_owned()),
dist_args: Some("--artifacts=global".into()),
install_dist: Some(install_dist_sh.clone()),
install_dist: dist_install_strategy.bash().into(),
packages_install: None,
};

Expand Down Expand Up @@ -300,8 +311,7 @@ impl GithubCiInfo {
};
for (runner, targets) in local_runs {
use std::fmt::Write;
let install_dist =
install_dist_for_targets(&targets, &install_dist_sh, &install_dist_ps1);
let install_dist = install_dist_for_targets(&targets, &dist_install_strategy);
let mut dist_args = String::from("--artifacts=local");
for target in &targets {
write!(dist_args, " --target={target}").unwrap();
Expand All @@ -311,7 +321,7 @@ impl GithubCiInfo {
cache_provider: cache_provider_for_runner(&runner),
runner: Some(runner),
dist_args: Some(dist_args),
install_dist: Some(install_dist.to_owned()),
install_dist: install_dist.to_owned(),
packages_install: package_install_for_targets(&targets, &dependencies),
});
}
Expand All @@ -334,8 +344,7 @@ impl GithubCiInfo {
github_ci_workflow_dir,
tag_namespace,
rust_version,
install_dist_sh,
install_dist_ps1,
dist_install_strategy,
fail_fast,
cache_builds,
build_local_artifacts,
Expand Down Expand Up @@ -621,18 +630,20 @@ fn github_runner_for_target(
/// Select the dist installer approach for a given Github Runner
fn install_dist_for_targets<'a>(
targets: &'a [&'a TargetTripleRef],
install_sh: &'a str,
install_ps1: &'a str,
) -> &'a str {
install_strategy: &'a DistInstallStrategy,
) -> GhaRunStep {
// FIXME: when doing cross-compilation, `host != runner`, and we should
// pick something that runs on the host. We need knowledge about "which
// platform is this GitHub runner" ahead of time to do that, though.

for target in targets {
if target.is_linux() || target.is_apple() {
return install_sh;
return install_strategy.bash().into();
} else if target.is_windows() {
return install_ps1;
return install_strategy.powershell().into();
}
}

unreachable!("internal error: unknown target triple!?")
panic!("unsupported target triple(s) {targets:?}");
}

fn brewfile_from(packages: &[String]) -> String {
Expand Down
123 changes: 81 additions & 42 deletions cargo-dist/src/backend/ci/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! Support for generating CI scripts for running dist
use cargo_dist_schema::{DashScript, PowershellScript};
use semver::Version;
use serde::Serialize;

use crate::config::v0::CargoDistUrlOverrideRef;

use self::github::GithubCiInfo;

Expand All @@ -17,52 +21,87 @@ pub struct CiInfo {
pub github: Option<GithubCiInfo>,
}

/// Get the command to invoke to install dist via sh script
fn install_dist_sh_for_version(version: &Version) -> String {
if let Some(git) = install_dist_git(version) {
return git;
}
let format = cargo_dist_schema::format_of_version(version);
let installer_name = if format.unsupported() {
// FIXME: we should probably do this check way higher up and produce a proper err...
panic!("requested dist v{version}, which is not supported by the this copy of dist ({SELF_DIST_VERSION})");
} else if format.artifact_names_contain_versions() {
format!("cargo-dist-v{version}-installer.sh")
} else {
"cargo-dist-installer.sh".to_owned()
};
/// Gives us the full information re: the version of dist we're supposed
/// to install/run in CI
struct DistInstallSettings<'a> {
version: &'a Version,
url_override: Option<&'a CargoDistUrlOverrideRef>,
}

// FIXME: it would be nice if these values were somehow using all the machinery
// to compute these values for packages we build *BUT* it's messy and not that important
let installer_url = format!("{BASE_DIST_FETCH_URL}/v{version}/{installer_name}");
format!("curl --proto '=https' --tlsv1.2 -LsSf {installer_url} | sh")
/// The strategy used to install dist in CI
#[derive(Debug, Clone, Serialize)]
pub enum DistInstallStrategy {
/// Download an installer and run it
Installer {
/// the prefix of the installer url, e.g.
installer_url: String,
/// the installer name, without `.sh` or `.ps1`
installer_name: String,
},
/// Run `cargo install --git` (slow!)
GitBranch {
/// the branch to install from — from <https://github.com/axodotdev/cargo-dist>
branch: String,
},
}

/// Get the command to invoke to install dist via ps1 script
fn install_dist_ps1_for_version(version: &Version) -> String {
if let Some(git) = install_dist_git(version) {
return git;
}
let format = cargo_dist_schema::format_of_version(version);
let installer_name = if format.unsupported() {
// FIXME: we should probably do this check way higher up and produce a proper err...
panic!("requested dist v{version}, which is not supported by the this copy of dist ({SELF_DIST_VERSION})");
} else if format.artifact_names_contain_versions() {
format!("cargo-dist-v{version}-installer.ps1")
} else {
"cargo-dist-installer.ps1".to_owned()
};
impl DistInstallSettings<'_> {
fn install_strategy(&self) -> DistInstallStrategy {
if let Some(branch) = self.version.pre.strip_prefix("github-") {
return DistInstallStrategy::GitBranch {
branch: branch.to_owned(),
};
}

if let Some(url) = self.url_override.as_ref() {
return DistInstallStrategy::Installer {
installer_url: url.as_str().to_owned(),
installer_name: "cargo-dist-installer".to_owned(),
};
}

// FIXME: it would be nice if these values were somehow using all the machinery
// to compute these values for packages we build *BUT* it's messy and not that important
let installer_url = format!("{BASE_DIST_FETCH_URL}/v{version}/{installer_name}");
format!(r#"powershell -c "irm {installer_url} | iex""#)
let version = self.version;
let format = cargo_dist_schema::format_of_version(version);
let installer_name = if format.unsupported() {
// FIXME: we should probably do this check way higher up and produce a proper err...
panic!("requested dist v{version}, which is not supported by the this copy of dist ({SELF_DIST_VERSION})");
} else if format.artifact_names_contain_versions() {
format!("cargo-dist-v{version}-installer")
} else {
"cargo-dist-installer".to_owned()
};

DistInstallStrategy::Installer {
// FIXME: it would be nice if these values were somehow using all the machinery
// to compute these values for packages we build *BUT* it's messy and not that important
installer_url: format!("{BASE_DIST_FETCH_URL}/v{version}"),
installer_name,
}
}
}

/// Cute little hack for developing dist itself: if we see a version like "0.0.3-github-config"
/// then install from the main github repo with branch=config!
fn install_dist_git(version: &Version) -> Option<String> {
version.pre.strip_prefix("github-").map(|branch| {
format!("cargo install --git https://github.com/axodotdev/cargo-dist/ --branch={branch} cargo-dist")
})
impl DistInstallStrategy {
/// Returns a bit of powershell to install the requested version of dist
fn powershell(&self) -> PowershellScript {
PowershellScript::new(match self {
DistInstallStrategy::Installer { installer_url, installer_name } => format!(
"irm {installer_url}/{installer_name}.ps1 | iex"
),
DistInstallStrategy::GitBranch { branch } => format!(
"cargo install --git https://github.com/axodotdev/cargo-dist/ --branch={branch} cargo-dist"
),
})
}

/// Returns a bit of bash to install the requested version of dist
pub fn bash(&self) -> DashScript {
DashScript::new(match self {
DistInstallStrategy::Installer { installer_url, installer_name } => format!(
"curl --proto '=https' --tlsv1.2 -LsSf {installer_url}/{installer_name}.sh | sh"
),
DistInstallStrategy::GitBranch { branch } => format!(
"cargo install --git https://github.com/axodotdev/cargo-dist/ --branch={branch} cargo-dist"
),
})
}
}
19 changes: 18 additions & 1 deletion cargo-dist/src/config/v0.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! v0 config
use camino::{Utf8Path, Utf8PathBuf};
use cargo_dist_schema::GithubRunner;
use cargo_dist_schema::{declare_strongly_typed_string, GithubRunner};
use semver::Version;
use serde::{Deserialize, Serialize};
use tracing::log::warn;
Expand All @@ -17,6 +17,14 @@ pub struct GenericConfig {
pub dist: Option<DistMetadata>,
}

declare_strongly_typed_string! {
/// A URL to use to install `cargo-dist` (with the installer script).
/// This overwrites `cargo_dist_version` and expects the URL to have
/// a similar structure to `./target/distrib` after running `dist build`
/// on itself.
pub struct CargoDistUrlOverride => &CargoDistUrlOverrideRef;
}

/// Contents of METADATA_DIST in Cargo.toml files
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[serde(rename_all = "kebab-case")]
Expand All @@ -32,6 +40,10 @@ pub struct DistMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub cargo_dist_version: Option<Version>,

/// See [`CargoDistUrlOverride`]
#[serde(skip_serializing_if = "Option::is_none")]
pub cargo_dist_url_override: Option<CargoDistUrlOverride>,

/// (deprecated) The intended version of Rust/Cargo to build with (rustup toolchain syntax)
///
/// When generating full tasks graphs (such as CI scripts) we will pick this version.
Expand Down Expand Up @@ -453,6 +465,7 @@ impl DistMetadata {
extra_artifacts,
// The rest of these don't include relative paths
cargo_dist_version: _,
cargo_dist_url_override: _,
rust_toolchain_version: _,
dist: _,
ci: _,
Expand Down Expand Up @@ -548,6 +561,7 @@ impl DistMetadata {
// This is intentionally written awkwardly to make you update it
let DistMetadata {
cargo_dist_version,
cargo_dist_url_override,
rust_toolchain_version,
dist,
ci,
Expand Down Expand Up @@ -614,6 +628,9 @@ impl DistMetadata {
if cargo_dist_version.is_some() {
warn!("package.metadata.dist.cargo-dist-version is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path);
}
if cargo_dist_url_override.is_some() {
warn!("package.metadata.dist.cargo-dist-url-override is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path);
}
if rust_toolchain_version.is_some() {
warn!("package.metadata.dist.rust-toolchain-version is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path);
}
Expand Down
Loading

0 comments on commit d97bb5e

Please sign in to comment.