Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow specifying binary aliases / links #964

Merged
merged 2 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cargo-dist/src/backend/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//!
//! In the future this might get split up into submodules.

use std::collections::BTreeMap;

use camino::Utf8PathBuf;
use serde::Serialize;

Expand Down Expand Up @@ -59,6 +61,8 @@ pub struct InstallerInfo {
pub install_paths: Vec<JinjaInstallPathStrategy>,
/// Install receipt to write, if any
pub receipt: Option<InstallReceipt>,
/// Aliases to install binaries under
pub aliases: BTreeMap<String, BTreeMap<String, Vec<String>>>,
}

/// A fake fragment of an ExecutableZip artifact for installers
Expand Down
9 changes: 9 additions & 0 deletions cargo-dist/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ pub struct DistMetadata {
#[serde(skip_serializing_if = "Option::is_none")]
pub github_custom_runners: Option<HashMap<String, String>>,

/// Aliases to install binaries as
#[serde(skip_serializing_if = "Option::is_none")]
pub aliases: Option<BTreeMap<String, Vec<String>>>,

/// a prefix to add to the release.yml and tag pattern so that
/// cargo-dist can co-exist with other release workflows in complex workspaces
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -393,6 +397,7 @@ impl DistMetadata {
hosting: _,
extra_artifacts: _,
github_custom_runners: _,
aliases: _,
tag_namespace: _,
install_updater: _,
} = self;
Expand Down Expand Up @@ -462,6 +467,7 @@ impl DistMetadata {
hosting,
extra_artifacts,
github_custom_runners,
aliases,
tag_namespace,
install_updater,
} = self;
Expand Down Expand Up @@ -591,6 +597,9 @@ impl DistMetadata {
if github_custom_runners.is_none() {
*github_custom_runners = workspace_config.github_custom_runners.clone();
}
if aliases.is_none() {
*aliases = workspace_config.aliases.clone();
}
if install_updater.is_none() {
*install_updater = workspace_config.install_updater;
}
Expand Down
2 changes: 2 additions & 0 deletions cargo-dist/src/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ fn get_new_dist_metadata(
hosting: None,
extra_artifacts: None,
github_custom_runners: None,
aliases: None,
tag_namespace: None,
install_updater: None,
}
Expand Down Expand Up @@ -830,6 +831,7 @@ fn apply_dist_to_metadata(metadata: &mut toml_edit::Item, meta: &DistMetadata) {
tag_namespace,
extra_artifacts: _,
github_custom_runners: _,
aliases: _,
install_updater,
} = &meta;

Expand Down
67 changes: 66 additions & 1 deletion cargo-dist/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
//! Also note that the BuildSteps for installers are basically monolithic "build that installer"
//! steps to give them the freedom to do whatever they need to do.

use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};

use axoprocess::Cmd;
use axoproject::{PackageId, PackageIdx, WorkspaceInfo};
Expand Down Expand Up @@ -129,6 +129,40 @@ pub struct ReleaseIdx(pub usize);
#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)]
pub struct BinaryIdx(pub usize);

/// A convenience wrapper around a map of aliases
#[derive(Debug)]
pub struct Aliases(BTreeMap<String, Vec<String>>);

impl Aliases {
/// Returns a formatted copy of the map, with file extensions added
/// if necessary.
pub fn for_target(&self, target: &str) -> BTreeMap<String, Vec<String>> {
if target.contains("windows") {
BTreeMap::from_iter(self.0.iter().map(|(k, v)| {
(
format!("{k}.exe"),
v.iter().map(|name| format!("{name}.exe")).collect(),
)
}))
} else {
self.0.clone()
}
}

/// Returns a map of aliases for each target triple, with
/// executable extensions added if necessary.
pub fn for_targets(
&self,
targets: &[String],
) -> BTreeMap<String, BTreeMap<String, Vec<String>>> {
BTreeMap::from_iter(
targets
.iter()
.map(|target| (target.to_owned(), self.for_target(target))),
)
}
}

/// The graph of all work that cargo-dist needs to do on this invocation.
///
/// All work is precomputed at the start of execution because only discovering
Expand Down Expand Up @@ -222,6 +256,8 @@ pub struct DistGraph {
pub extra_artifacts: Vec<ExtraArtifact>,
/// Custom GitHub runners, mapped by triple target
pub github_custom_runners: HashMap<String, String>,
/// Aliases to publish binaries under, mapped source to target (ln style)
pub aliases: Aliases,
/// LIES ALL LIES
pub local_builds_are_lies: bool,
/// Prefix git tags must include to be picked up (also renames release.yml)
Expand Down Expand Up @@ -807,6 +843,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
hosting,
extra_artifacts,
github_custom_runners: _,
aliases: _,
install_updater,
} = &workspace_metadata;

Expand Down Expand Up @@ -1020,6 +1057,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
.github_custom_runners
.clone()
.unwrap_or_default(),
aliases: Aliases(workspace_metadata.aliases.clone().unwrap_or_default()),
install_updater: install_updater.unwrap_or_default(),
},
manifest: DistManifest {
Expand Down Expand Up @@ -1798,6 +1836,11 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
return;
};

let triples: Vec<String> = artifacts
.iter()
.flat_map(|a| a.target_triples.clone())
.collect();

let installer_artifact = Artifact {
id: artifact_name,
target_triples: target_triples.into_iter().collect(),
Expand All @@ -1820,6 +1863,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
hint,
desc,
receipt: InstallReceipt::from_metadata(&self.inner, release),
aliases: self.inner.aliases.for_targets(&triples),
})),
is_global: true,
};
Expand Down Expand Up @@ -2050,6 +2094,11 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
.map(|(name, _)| name)
.collect();

let triples: Vec<String> = artifacts
.iter()
.flat_map(|a| a.target_triples.clone())
.collect();

let installer_artifact = Artifact {
id: artifact_name,
target_triples: target_triples.into_iter().collect(),
Expand Down Expand Up @@ -2088,6 +2137,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
hint,
desc,
receipt: None,
aliases: self.inner.aliases.for_targets(&triples),
},
})),
is_global: true,
Expand Down Expand Up @@ -2161,6 +2211,11 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
return;
};

let triples: Vec<String> = artifacts
.iter()
.flat_map(|a| a.target_triples.clone())
.collect();

let installer_artifact = Artifact {
id: artifact_name,
target_triples: target_triples.into_iter().collect(),
Expand All @@ -2183,6 +2238,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
hint,
desc,
receipt: InstallReceipt::from_metadata(&self.inner, release),
aliases: self.inner.aliases.for_targets(&triples),
})),
is_global: true,
};
Expand Down Expand Up @@ -2372,6 +2428,11 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
return;
};

let triples: Vec<String> = artifacts
.iter()
.flat_map(|a| a.target_triples.clone())
.collect();

let installer_artifact = Artifact {
id: artifact_name,
target_triples: target_triples.into_iter().collect(),
Expand Down Expand Up @@ -2411,6 +2472,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
hint,
desc,
receipt: None,
aliases: self.inner.aliases.for_targets(&triples),
},
})),
is_global: true,
Expand Down Expand Up @@ -3094,6 +3156,8 @@ pub struct InstallReceipt {
pub version: String,
/// The software which installed this receipt
pub provider: Provider,
/// A list of aliases binaries were installed under
pub aliases: BTreeMap<String, Vec<String>>,
}

impl InstallReceipt {
Expand Down Expand Up @@ -3125,6 +3189,7 @@ impl InstallReceipt {
source: ProviderSource::CargoDist,
version: env!("CARGO_PKG_VERSION").to_owned(),
},
aliases: BTreeMap::default(),
})
}
}
20 changes: 19 additions & 1 deletion cargo-dist/templates/installer/homebrew.rb.j2
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,23 @@ class {{ formula_class }} < Formula
{%- endfor %}
{%- endif %}

ALIASES = {{ inner.aliases }}

def target_triple
cpu = Hardware::CPU.arm? ? "aarch64" : "x86_64"
os = OS.mac? ? "apple-darwin" : "unknown-linux-gnu"

"#{cpu}-#{os}"
end

def install_aliases!
ALIASES[target_triple.to_sym].each do |source, dests|
dests.each do |dest|
bin.install_symlink bin/source.to_s => dest
end
end
end

def install
{%- if arm64_macos.binaries %}
if OS.mac? && Hardware::CPU.arm?
Expand All @@ -86,7 +103,8 @@ class {{ formula_class }} < Formula
if OS.linux? && Hardware::CPU.intel?
bin.install {% for binary in x86_64_linux.binaries %}"{{ binary }}"{{ ", " if not loop.last else "" }}{% endfor %}
end
{%- endif %}
{% endif %}
install_aliases!

# Homebrew will automatically install these, so we don't need to do that
doc_files = Dir["README.*", "readme.*", "LICENSE", "LICENSE.*", "CHANGELOG.*"]
Expand Down
49 changes: 34 additions & 15 deletions cargo-dist/templates/installer/installer.ps1.j2
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ function Install-Binary($install_args) {
"{{ bin }}"{{ ", " if not loop.last else "" }}
{%- endfor %}
"zip_ext" = "{{ artifact.zip_style }}"
"aliases" = @{
{%- for source, dests in aliases[artifact.target_triples[0]] | items %}
"{{ source }}" = {% for dest in dests -%}
"{{ dest }}"{{ ", " if not loop.last else "" }}
{%- endfor %}
{%- endfor %}
}
"aliases_json" = '{{ aliases[artifact.target_triples[0]] | tojson }}'
}
{%- endfor %}
}
Expand Down Expand Up @@ -197,6 +205,23 @@ function Download($download_url, $platforms) {
}

function Invoke-Installer($bin_paths, $platforms) {
# Replaces the placeholder binary entry with the actual list of binaries
$arch = Get-TargetTriple

if (-not $platforms.ContainsKey($arch)) {
# X64 is well-supported, including in emulation on ARM64
Write-Verbose "$arch is not available, falling back to X64"
$arch = "x86_64-pc-windows-msvc"
}

if (-not $platforms.ContainsKey($arch)) {
# should not be possible, as currently we always produce X64 binaries.
$platforms_json = ConvertTo-Json $platforms
throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json"
}

$info = $platforms[$arch]

$dest_dir = $null
# Before actually consulting the configured install strategy, see
# if we're overriding it.
Expand Down Expand Up @@ -253,26 +278,20 @@ function Invoke-Installer($bin_paths, $platforms) {
Copy-Item "$bin_path" -Destination "$dest_dir"
Remove-Item "$bin_path" -Recurse -Force
Write-Information " $installed_file"
}

# Replaces the placeholder binary entry with the actual list of binaries
$arch = Get-TargetTriple

if (-not $platforms.ContainsKey($arch)) {
# X64 is well-supported, including in emulation on ARM64
Write-Verbose "$arch is not available, falling back to X64"
$arch = "x86_64-pc-windows-msvc"
}

if (-not $platforms.ContainsKey($arch)) {
# should not be possible, as currently we always produce X64 binaries.
$platforms_json = ConvertTo-Json $platforms
throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json"
if (($dests = $info["aliases"][$installed_file])) {
$source = Join-Path "$dest_dir" "$installed_file"
foreach ($dest_name in $dests) {
$dest = Join-Path $dest_dir $dest_name
$null = New-Item -ItemType HardLink -Target "$source" -Path "$dest" -Force
}
}
}

$info = $platforms[$arch]
$formatted_bins = ($info["bins"] | ForEach-Object { '"' + $_ + '"' }) -join ","
$receipt = $receipt.Replace('"CARGO_DIST_BINS"', $formatted_bins)
# Also replace the aliases with the arch-specific one
$receipt = $receipt.Replace('"aliases":{}', -join('"aliases":', $info['aliases_json']))

# Write the install receipt
$null = New-Item -Path $receipt_home -ItemType "directory" -ErrorAction SilentlyContinue
Expand Down
Loading
Loading