diff --git a/CHANGELOG.md b/CHANGELOG.md index 6363d51b8..20d485837 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Unreleased +## `github-build-setup` Job Customization + +It's now possible to specify to which jobs `github-build-setup` steps are added. + +```toml +github-build-setup = "build-steps.yml" +github-build-setup-jobs = ["plan", "build-local-artifacts", "build-global-artifacts", "host"] +``` + +If not configured, this defaults to `["build-local-artifacts"]`. + +- impl @arusahni [feat: optionally apply `github-build-setup` steps to additional jobs](https://github.com/axodotdev/cargo-dist/pull/2070) + # Version 0.30.0 (2025-09-07) This release contains several improvements to ZIP archives, the installers and additional build workflow customization options. diff --git a/book/src/reference/config.md b/book/src/reference/config.md index 7690e38b1..292a05f07 100644 --- a/book/src/reference/config.md +++ b/book/src/reference/config.md @@ -95,6 +95,7 @@ We're currently in the middle of [a major config migration](https://github.com/a * [`github-custom-job-permissions`](#github-custom-job-permissions) * [`github-custom-runners`](#github-custom-runners) * [`github-build-setup`](#github-build-setup) + * [`github-build-setup-jobs`](#github-build-setup-jobs) * [`github-action-commits`](#github-action-commits) * [custom ci jobs](#custom-ci-jobs) * [`plan-jobs`](#plan-jobs) @@ -1382,8 +1383,28 @@ These settings are specific to [your dist GitHub CI][github-ci]. This configuration value should be a path relative to the repository your `.github/workflows` directory. The file located at that path should contain a yaml array of [steps][github-workflow-step] which will be -performed before we call `dist build`. +performed before we call `dist build` in the `build-local-artifacts` job. These +steps can be added to additional jobs by defining +[`github-build-setup-jobs`](#github-build-setup-jobs). +#### `github-build-setup-jobs` + +> since 1.0.0
[global-only][]
+> šŸ”§ this is an experimental feature! \ +> [šŸ“– read the ci customization guide!][github-ci] \ +> default = `` +> +> *in your dist-workspace.toml or dist.toml:* +> ```toml +> [dist] +> # Defaults to "build-local-artifacts" +> github-build-setup-jobs = ["plan", "build-local-artifacts"] +> ``` + +This configuration value should accompany +[`github-build-setup`](#github-build-setup). When not specified, it defaults to +`["build-local-artifacts"]`. Otherwise, the listed jobs will have the steps +defined in `github-build-setup` added. #### `github-custom-job-permissions` diff --git a/cargo-dist/src/backend/ci/github.rs b/cargo-dist/src/backend/ci/github.rs index 426cf5170..4794a6403 100644 --- a/cargo-dist/src/backend/ci/github.rs +++ b/cargo-dist/src/backend/ci/github.rs @@ -100,6 +100,8 @@ pub struct GithubCiInfo { pub root_permissions: Option, /// Extra build steps pub github_build_setup: Vec, + /// The jobs to which the [`GithubCiInfo::github_build_setup`] steps should be prepended + pub github_build_setup_jobs: Vec, /// Info about making a GitHub Release (if we're making one) #[serde(flatten)] pub github_release: Option, @@ -372,6 +374,7 @@ impl GithubCiInfo { }) .transpose()? .unwrap_or_default(); + let github_build_setup_jobs = ci_config.build_setup_jobs.clone(); let default_action_versions = [ ("actions/checkout", "v4"), @@ -420,6 +423,7 @@ impl GithubCiInfo { hosting_providers, root_permissions, github_build_setup, + github_build_setup_jobs, github_release, actions, need_cargo_auditable, diff --git a/cargo-dist/src/config/v0.rs b/cargo-dist/src/config/v0.rs index 9863a45b0..3758465d3 100644 --- a/cargo-dist/src/config/v0.rs +++ b/cargo-dist/src/config/v0.rs @@ -539,10 +539,14 @@ pub struct DistMetadata { #[serde(default, with = "opt_string_or_vec")] pub install_libraries: Option>, - /// Any additional steps that need to be performed before building local artifacts + /// Any additional steps that need to be performed before executing certain job steps #[serde(default)] pub github_build_setup: Option, + /// The jobs to which the [`DistMetadata::github_build_setup`] steps should be prepended + #[serde(default)] + pub github_build_setup_jobs: Option>, + /// Configuration specific to Mac .pkg installers #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] @@ -645,6 +649,7 @@ impl DistMetadata { package_libraries: _, install_libraries: _, github_build_setup: _, + github_build_setup_jobs: _, mac_pkg_config: _, min_glibc_version: _, binaries: _, @@ -752,6 +757,7 @@ impl DistMetadata { package_libraries, install_libraries, github_build_setup, + github_build_setup_jobs, mac_pkg_config, min_glibc_version, binaries, @@ -880,6 +886,9 @@ impl DistMetadata { if github_build_setup.is_some() { warn!("package.metadata.dist.github-build-setup is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path); } + if github_build_setup_jobs.is_some() { + warn!("package.metadata.dist.github-build-setup-jobs is set, but this is only accepted in workspace.metadata (value is being ignored): {}", package_manifest_path); + } // Merge non-global settings if installers.is_none() { diff --git a/cargo-dist/src/config/v0_to_v1.rs b/cargo-dist/src/config/v0_to_v1.rs index 73e9f58f7..ee486363c 100644 --- a/cargo-dist/src/config/v0_to_v1.rs +++ b/cargo-dist/src/config/v0_to_v1.rs @@ -88,6 +88,7 @@ impl DistMetadata { package_libraries, install_libraries, github_build_setup, + github_build_setup_jobs, min_glibc_version, binaries, cargo_auditable, @@ -165,6 +166,7 @@ impl DistMetadata { if github_custom_runners.is_some() || github_custom_job_permissions.is_some() || github_build_setup.is_some() + || github_build_setup_jobs.is_some() || github_action_commits.is_some() { Some(GithubCiLayer { @@ -172,6 +174,7 @@ impl DistMetadata { runners: github_custom_runners, permissions: github_custom_job_permissions, build_setup: github_build_setup, + build_setup_jobs: github_build_setup_jobs, action_commits: github_action_commits, }) } else { diff --git a/cargo-dist/src/config/v1/ci/github.rs b/cargo-dist/src/config/v1/ci/github.rs index 52ef18912..e4c3c0a05 100644 --- a/cargo-dist/src/config/v1/ci/github.rs +++ b/cargo-dist/src/config/v1/ci/github.rs @@ -25,10 +25,14 @@ pub struct GithubCiLayer { #[serde(skip_serializing_if = "Option::is_none")] pub permissions: Option>, - /// Custom permissions for jobs + /// Custom steps for jobs #[serde(skip_serializing_if = "Option::is_none")] pub build_setup: Option, + /// What jobs to which the [`GithubCiLayer::build_setup`] steps should be prepended + #[serde(skip_serializing_if = "Option::is_none")] + pub build_setup_jobs: Option>, + /// Use these commits for actions #[serde(skip_serializing_if = "Option::is_none")] pub action_commits: Option>, @@ -46,9 +50,12 @@ pub struct GithubCiConfig { /// Custom permissions for jobs pub permissions: SortedMap, - /// Custom permissions for jobs + /// Custom steps for jobs pub build_setup: Option, + /// What jobs to which the [`GithubCiConfig::build_setup`] steps should be prepended + pub build_setup_jobs: Vec, + /// Use these commits for github actions pub action_commits: SortedMap, } @@ -62,6 +69,7 @@ impl GithubCiConfig { permissions: Default::default(), action_commits: Default::default(), build_setup: None, + build_setup_jobs: vec!["build-local-artifacts".to_string()], } } } @@ -75,6 +83,7 @@ impl ApplyLayer for GithubCiConfig { runners, permissions, build_setup, + build_setup_jobs, action_commits, }: Self::Layer, ) { @@ -143,6 +152,7 @@ impl ApplyLayer for GithubCiConfig { })); self.permissions.apply_val(permissions); self.build_setup.apply_opt(build_setup); + self.build_setup_jobs.apply_val(build_setup_jobs); self.action_commits.apply_val(action_commits); } } @@ -155,6 +165,7 @@ impl ApplyLayer for GithubCiLayer { runners, permissions, build_setup, + build_setup_jobs, action_commits, }: Self::Layer, ) { @@ -162,6 +173,7 @@ impl ApplyLayer for GithubCiLayer { self.runners.apply_opt(runners); self.permissions.apply_opt(permissions); self.build_setup.apply_opt(build_setup); + self.build_setup_jobs.apply_opt(build_setup_jobs); self.action_commits.apply_opt(action_commits); } } diff --git a/cargo-dist/src/init/v0.rs b/cargo-dist/src/init/v0.rs index 2b2527376..e8fffd343 100644 --- a/cargo-dist/src/init/v0.rs +++ b/cargo-dist/src/init/v0.rs @@ -252,6 +252,7 @@ fn get_new_dist_metadata( package_libraries: None, install_libraries: None, github_build_setup: None, + github_build_setup_jobs: None, mac_pkg_config: None, min_glibc_version: None, binaries: None, @@ -765,6 +766,7 @@ fn apply_dist_to_metadata(metadata: &mut toml_edit::Item, meta: &DistMetadata) { bin_aliases: _, system_dependencies: _, github_build_setup: _, + github_build_setup_jobs: _, binaries: _, } = &meta; diff --git a/cargo-dist/templates/ci/github/release.yml.j2 b/cargo-dist/templates/ci/github/release.yml.j2 index 1e01a0023..258d9ac0a 100644 --- a/cargo-dist/templates/ci/github/release.yml.j2 +++ b/cargo-dist/templates/ci/github/release.yml.j2 @@ -128,6 +128,53 @@ jobs: with: name: cargo-dist-cache path: ~/.cargo/bin/dist + {{%- if "plan" in github_build_setup_jobs %}} + {{%- for step in github_build_setup %}} + - name: {{{ step.name }}} + {{%- if step.id is not undefined %}} + id: {{{ step.id }}} + {{%- endif %}} + {{%- if step.uses is not undefined %}} + uses: {{{ step.uses }}} + {{%- endif %}} + {{%- if step.if is not undefined %}} + if: {{{ step.if }}} + {{%- endif %}} + {{%- if step.run is not undefined %}} + {{%- if step.run is multiline %}} + run: | + {{{ step.run|indent(10) }}} + {{%- else %}} + run: {{{ step.run }}} + {{%- endif %}} + {{%- endif %}} + {{%- if step.working_directory is not undefined %}} + working-directory: {{{ step.working_directory }}} + {{%- endif %}} + {{%- if step.shell is not undefined %}} + shell: {{{ step.shell }}} + {{%- endif %}} + {{%- if not step.with is empty %}} + with: + {{%- for (var,value) in step.with|items %}} + {{%- if value is mapping %}} + {{{ var }}}: + {{%- for (var,value) in value|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- else %}} + {{{ var }}}: {{{ value }}} + {{%- endif %}} + {{%- endfor %}} + {{%- endif %}} + {{%- if not step.env is empty %}} + env: + {{%- for (var,value) in step.env|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- endif %}} + {{%- endfor %}} + {{%- endif %}} # sure would be cool if github gave us proper conditionals... # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible # functionality based on whether this is a pull_request, and whether it's from a fork. @@ -229,6 +276,7 @@ jobs: - name: Use rustup to set correct Rust version run: rustup update {{{ rust_version }}} --no-self-update && rustup default {{{ rust_version }}} {{%- endif %}} + {{%- if "build-local-artifacts" in github_build_setup_jobs %}} {{%- for step in github_build_setup %}} - name: {{{ step.name }}} {{%- if step.id is not undefined %}} @@ -280,6 +328,7 @@ jobs: timeout-minutes: {{{ step.timeout_minutes }}} {{%- endif %}} {{%- endfor %}} + {{%- endif %}} {{%- if cache_builds %}} - uses: {{{actions["swatinem/rust-cache"] | safe }}} with: @@ -415,6 +464,53 @@ jobs: pattern: artifacts-* path: target/distrib/ merge-multiple: true + {{%- if "build-global-artifacts" in github_build_setup_jobs %}} + {{%- for step in github_build_setup %}} + - name: {{{ step.name }}} + {{%- if step.id is not undefined %}} + id: {{{ step.id }}} + {{%- endif %}} + {{%- if step.uses is not undefined %}} + uses: {{{ step.uses }}} + {{%- endif %}} + {{%- if step.if is not undefined %}} + if: {{{ step.if }}} + {{%- endif %}} + {{%- if step.run is not undefined %}} + {{%- if step.run is multiline %}} + run: | + {{{ step.run|indent(10) }}} + {{%- else %}} + run: {{{ step.run }}} + {{%- endif %}} + {{%- endif %}} + {{%- if step.working_directory is not undefined %}} + working-directory: {{{ step.working_directory }}} + {{%- endif %}} + {{%- if step.shell is not undefined %}} + shell: {{{ step.shell }}} + {{%- endif %}} + {{%- if not step.with is empty %}} + with: + {{%- for (var,value) in step.with|items %}} + {{%- if value is mapping %}} + {{{ var }}}: + {{%- for (var,value) in value|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- else %}} + {{{ var }}}: {{{ value }}} + {{%- endif %}} + {{%- endfor %}} + {{%- endif %}} + {{%- if not step.env is empty %}} + env: + {{%- for (var,value) in step.env|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- endif %}} + {{%- endfor %}} + {{%- endif %}} - id: cargo-dist shell: bash run: | @@ -524,6 +620,53 @@ jobs: merge-multiple: true {{%- if "github" in hosting_providers and release_phase == "announce" %}} # This is a harmless no-op for GitHub Releases, hosting for that happens in "announce" + {{%- endif %}} + {{%- if "host" in github_build_setup_jobs %}} + {{%- for step in github_build_setup %}} + - name: {{{ step.name }}} + {{%- if step.id is not undefined %}} + id: {{{ step.id }}} + {{%- endif %}} + {{%- if step.uses is not undefined %}} + uses: {{{ step.uses }}} + {{%- endif %}} + {{%- if step.if is not undefined %}} + if: {{{ step.if }}} + {{%- endif %}} + {{%- if step.run is not undefined %}} + {{%- if step.run is multiline %}} + run: | + {{{ step.run|indent(10) }}} + {{%- else %}} + run: {{{ step.run }}} + {{%- endif %}} + {{%- endif %}} + {{%- if step.working_directory is not undefined %}} + working-directory: {{{ step.working_directory }}} + {{%- endif %}} + {{%- if step.shell is not undefined %}} + shell: {{{ step.shell }}} + {{%- endif %}} + {{%- if not step.with is empty %}} + with: + {{%- for (var,value) in step.with|items %}} + {{%- if value is mapping %}} + {{{ var }}}: + {{%- for (var,value) in value|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- else %}} + {{{ var }}}: {{{ value }}} + {{%- endif %}} + {{%- endfor %}} + {{%- endif %}} + {{%- if not step.env is empty %}} + env: + {{%- for (var,value) in step.env|items %}} + {{{ var }}}: {{{ value }}} + {{%- endfor %}} + {{%- endif %}} + {{%- endfor %}} {{%- endif %}} - id: host shell: bash diff --git a/cargo-dist/tests/integration-tests.rs b/cargo-dist/tests/integration-tests.rs index 43b472522..d708c212c 100644 --- a/cargo-dist/tests/integration-tests.rs +++ b/cargo-dist/tests/integration-tests.rs @@ -1905,6 +1905,52 @@ identifier = "dev.axo.axolotsay" }) } + +#[test] +fn axolotlsay_custom_job_build_setup_steps() -> Result<(), miette::Report> { + let test_name = _function_name!(); + AXOLOTLSAY + .run_test(|ctx| { + ctx.workspace_write_file(".github/workflows/build_setup.yml", + include_str!("../../cargo-dist/tests/build_setup.yml"))?; + let dist_version = ctx.tools.cargo_dist.version().unwrap(); + ctx.patch_cargo_toml(format!(r#" +[workspace.metadata.dist] +cargo-dist-version = "{dist_version}" +installers = ["shell", "powershell", "homebrew", "npm", "msi", "pkg"] +tap = "axodotdev/homebrew-packages" +publish-jobs = ["homebrew", "npm"] +targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"] +install-success-msg = ">o_o< everything's installed!" +ci = ["github"] +unix-archive = ".tar.gz" +windows-archive = ".tar.gz" +npm-scope ="@axodotdev" +github-build-setup = "build_setup.yml" +github-build-setup-jobs = ["plan", "build-local-artifacts", "host"] + +[package.metadata.wix] +upgrade-guid = "B36177BE-EA4D-44FB-B05C-EDDABDAA95CA" +path-guid = "BFD25009-65A4-4D1E-97F1-0030465D90D6" + +[package.metadata.dist.mac-pkg-config] +identifier = "dev.axo.axolotsay" + +"# + ))?; + + // Run generate to make sure stuff is up to date before running other commands + let ci_result = ctx.cargo_dist_generate(test_name)?; + let ci_snap = ci_result.check_all()?; + // Do usual build+plan checks + let main_result = ctx.cargo_dist_build_and_plan(test_name)?; + let main_snap = main_result.check_all(&ctx, ".cargo/bin/")?; + // snapshot all + main_snap.join(ci_snap).snap(); + Ok(()) + }) +} + #[test] fn axolotlsay_dist_url_override() -> Result<(), miette::Report> { let test_name = _function_name!(); diff --git a/cargo-dist/tests/snapshots/axolotlsay_custom_job_build_setup_steps.snap b/cargo-dist/tests/snapshots/axolotlsay_custom_job_build_setup_steps.snap new file mode 100644 index 000000000..aaafc1794 --- /dev/null +++ b/cargo-dist/tests/snapshots/axolotlsay_custom_job_build_setup_steps.snap @@ -0,0 +1,4928 @@ +--- +source: cargo-dist/tests/gallery/dist/snapshot.rs +expression: self.payload +--- +================ axolotlsay-installer.sh ================ +#!/bin/sh +# shellcheck shell=dash +# shellcheck disable=SC2039 # local is non-POSIX +# +# Licensed under the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +# This runs on Unix shells like bash/dash/ksh/zsh. It uses the common `local` +# extension. Note: Most shells limit `local` to 1 var per line, contra bash. + +# Some versions of ksh have no `local` keyword. Alias it to `typeset`, but +# beware this makes variables global with f()-style function syntax in ksh93. +# mksh has this alias by default. +has_local() { + # shellcheck disable=SC2034 # deliberately unused + local _has_local +} + +has_local 2>/dev/null || alias local=typeset + +set -u + +APP_NAME="axolotlsay" +APP_VERSION="0.2.2" +# Look for GitHub Enterprise-style base URL first +if [ -n "${AXOLOTLSAY_INSTALLER_GHE_BASE_URL:-}" ]; then + INSTALLER_BASE_URL="$AXOLOTLSAY_INSTALLER_GHE_BASE_URL" +else + INSTALLER_BASE_URL="${AXOLOTLSAY_INSTALLER_GITHUB_BASE_URL:-https://github.com}" +fi +if [ -n "${AXOLOTLSAY_DOWNLOAD_URL:-}" ]; then + ARTIFACT_DOWNLOAD_URL="$AXOLOTLSAY_DOWNLOAD_URL" +elif [ -n "${INSTALLER_DOWNLOAD_URL:-}" ]; then + ARTIFACT_DOWNLOAD_URL="$INSTALLER_DOWNLOAD_URL" +else + ARTIFACT_DOWNLOAD_URL="${INSTALLER_BASE_URL}/axodotdev/axolotlsay/releases/download/v0.2.2" +fi +if [ -n "${AXOLOTLSAY_PRINT_VERBOSE:-}" ]; then + PRINT_VERBOSE="$AXOLOTLSAY_PRINT_VERBOSE" +else + PRINT_VERBOSE=${INSTALLER_PRINT_VERBOSE:-0} +fi +if [ -n "${AXOLOTLSAY_PRINT_QUIET:-}" ]; then + PRINT_QUIET="$AXOLOTLSAY_PRINT_QUIET" +else + PRINT_QUIET=${INSTALLER_PRINT_QUIET:-0} +fi +if [ -n "${AXOLOTLSAY_NO_MODIFY_PATH:-}" ]; then + NO_MODIFY_PATH="$AXOLOTLSAY_NO_MODIFY_PATH" +else + NO_MODIFY_PATH=${INSTALLER_NO_MODIFY_PATH:-0} +fi +if [ "${AXOLOTLSAY_DISABLE_UPDATE:-0}" = "1" ]; then + INSTALL_UPDATER=0 +else + INSTALL_UPDATER=1 +fi +UNMANAGED_INSTALL="${AXOLOTLSAY_UNMANAGED_INSTALL:-}" +if [ -n "${UNMANAGED_INSTALL}" ]; then + NO_MODIFY_PATH=1 + INSTALL_UPDATER=0 +fi +AUTH_TOKEN="${AXOLOTLSAY_GITHUB_TOKEN:-}" + +read -r RECEIPT <&2 + say_verbose " from $_url" 1>&2 + say_verbose " to $_file" 1>&2 + + ensure mkdir -p "$_dir" + + if ! downloader "$_url" "$_file"; then + say "failed to download $_url" + say "this may be a standard network error, but it may also indicate" + say "that $APP_NAME's release process is not working. When in doubt" + say "please feel free to open an issue!" + exit 1 + fi + + if [ -n "${_checksum_style:-}" ]; then + verify_checksum "$_file" "$_checksum_style" "$_checksum_value" + else + say "no checksums to verify" + fi + + # ...and then the updater, if it exists + if [ -n "$_updater_name" ] && [ "$INSTALL_UPDATER" = "1" ]; then + local _updater_url="$ARTIFACT_DOWNLOAD_URL/$_updater_name" + # This renames the artifact while doing the download, removing the + # target triple and leaving just the appname-update format + local _updater_file="$_dir/$APP_NAME-update" + + if ! downloader "$_updater_url" "$_updater_file"; then + say "failed to download $_updater_url" + say "this may be a standard network error, but it may also indicate" + say "that $APP_NAME's release process is not working. When in doubt" + say "please feel free to open an issue!" + exit 1 + fi + + # Add the updater to the list of binaries to install + _bins="$_bins $APP_NAME-update" + fi + + # unpack the archive + case "$_zip_ext" in + ".zip") + ensure unzip -q "$_file" -d "$_dir" + ;; + + ".tar."*) + ensure tar xf "$_file" --strip-components 1 -C "$_dir" + ;; + *) + err "unknown archive format: $_zip_ext" + ;; + esac + + install "$_dir" "$_bins" "$_libs" "$_staticlibs" "$_arch" "$@" + local _retval=$? + if [ "$_retval" != 0 ]; then + return "$_retval" + fi + + ignore rm -rf "$_dir" + + # Install the install receipt + if [ "$INSTALL_UPDATER" = "1" ]; then + if ! mkdir -p "$RECEIPT_HOME"; then + err "unable to create receipt directory at $RECEIPT_HOME" + else + echo "$RECEIPT" > "$RECEIPT_HOME/$APP_NAME-receipt.json" + # shellcheck disable=SC2320 + local _retval=$? + fi + else + local _retval=0 + fi + + return "$_retval" +} + +# Replaces $HOME with the variable name for display to the user, +# only if $HOME is defined. +replace_home() { + local _str="$1" + + if [ -n "${HOME:-}" ]; then + echo "$_str" | sed "s,$HOME,\$HOME," + else + echo "$_str" + fi +} + +json_binary_aliases() { + local _arch="$1" + + case "$_arch" in + "aarch64-apple-darwin") + echo '{}' + ;; + "x86_64-apple-darwin") + echo '{}' + ;; + "x86_64-pc-windows-gnu") + echo '{}' + ;; + "x86_64-unknown-linux-gnu") + echo '{}' + ;; + *) + echo '{}' + ;; + esac +} + +aliases_for_binary() { + local _bin="$1" + local _arch="$2" + + case "$_arch" in + "aarch64-apple-darwin") + case "$_bin" in + *) + echo "" + ;; + esac + ;; + "x86_64-apple-darwin") + case "$_bin" in + *) + echo "" + ;; + esac + ;; + "x86_64-pc-windows-gnu") + case "$_bin" in + *) + echo "" + ;; + esac + ;; + "x86_64-unknown-linux-gnu") + case "$_bin" in + *) + echo "" + ;; + esac + ;; + *) + echo "" + ;; + esac +} + +select_archive_for_arch() { + local _true_arch="$1" + local _archive + + # try each archive, checking runtime conditions like libc versions + # accepting the first one that matches, as it's the best match + case "$_true_arch" in + "aarch64-apple-darwin") + _archive="axolotlsay-aarch64-apple-darwin.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + _archive="axolotlsay-x86_64-apple-darwin.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + "aarch64-pc-windows-msvc") + _archive="axolotlsay-x86_64-pc-windows-msvc.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + "x86_64-apple-darwin") + _archive="axolotlsay-x86_64-apple-darwin.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + "x86_64-pc-windows-gnu") + _archive="axolotlsay-x86_64-pc-windows-msvc.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + "x86_64-pc-windows-msvc") + _archive="axolotlsay-x86_64-pc-windows-msvc.tar.gz" + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + "x86_64-unknown-linux-gnu") + _archive="axolotlsay-x86_64-unknown-linux-gnu.tar.gz" + if ! check_glibc "2" "31"; then + _archive="" + fi + if [ -n "$_archive" ]; then + echo "$_archive" + return 0 + fi + ;; + *) + err "there isn't a download for your platform $_true_arch" + ;; + esac + err "no compatible downloads were found for your platform $_true_arch" +} + +check_glibc() { + local _min_glibc_major="$1" + local _min_glibc_series="$2" + + # Parsing version out from line 1 like: + # ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35 + _local_glibc="$(ldd --version | awk -F' ' '{ if (FNR<=1) print $NF }')" + + if [ "$(echo "${_local_glibc}" | awk -F. '{ print $1 }')" = "$_min_glibc_major" ] && [ "$(echo "${_local_glibc}" | awk -F. '{ print $2 }')" -ge "$_min_glibc_series" ]; then + return 0 + else + say "System glibc version (\`${_local_glibc}') is too old; checking alternatives" >&2 + return 1 + fi +} + +# See discussion of late-bound vs early-bound for why we use single-quotes with env vars +# shellcheck disable=SC2016 +install() { + # This code needs to both compute certain paths for itself to write to, and + # also write them to shell/rc files so that they can look them up to e.g. + # add them to PATH. This requires an active distinction between paths + # and expressions that can compute them. + # + # The distinction lies in when we want env-vars to be evaluated. For instance + # if we determine that we want to install to $HOME/.myapp, which do we add + # to e.g. $HOME/.profile: + # + # * early-bound: export PATH="/home/myuser/.myapp:$PATH" + # * late-bound: export PATH="$HOME/.myapp:$PATH" + # + # In this case most people would prefer the late-bound version, but in other + # cases the early-bound version might be a better idea. In particular when using + # other env-vars than $HOME, they are more likely to be only set temporarily + # for the duration of this install script, so it's more advisable to erase their + # existence with early-bounding. + # + # This distinction is handled by "double-quotes" (early) vs 'single-quotes' (late). + # + # However if we detect that "$SOME_VAR/..." is a subdir of $HOME, we try to rewrite + # it to be '$HOME/...' to get the best of both worlds. + # + # This script has a few different variants, the most complex one being the + # CARGO_HOME version which attempts to install things to Cargo's bin dir, + # potentially setting up a minimal version if the user hasn't ever installed Cargo. + # + # In this case we need to: + # + # * Install to $HOME/.cargo/bin/ + # * Create a shell script at $HOME/.cargo/env that: + # * Checks if $HOME/.cargo/bin/ is on PATH + # * and if not prepends it to PATH + # * Edits $INFERRED_HOME/.profile to run $HOME/.cargo/env (if the line doesn't exist) + # + # To do this we need these 4 values: + + # The actual path we're going to install to + local _install_dir + # The directory C dynamic/static libraries install to + local _lib_install_dir + # The install prefix we write to the receipt. + # For organized install methods like CargoHome, which have + # subdirectories, this is the root without `/bin`. For other + # methods, this is the same as `_install_dir`. + local _receipt_install_dir + # Path to the an shell script that adds install_dir to PATH + local _env_script_path + # Potentially-late-bound version of install_dir to write env_script + local _install_dir_expr + # Potentially-late-bound version of env_script_path to write to rcfiles like $HOME/.profile + local _env_script_path_expr + # Forces the install to occur at this path, not the default + local _force_install_dir + # Which install layout to use - "flat" or "hierarchical" + local _install_layout="unspecified" + # A list of binaries which are shadowed in the PATH + local _shadowed_bins="" + + # Check the newer app-specific variable before falling back + # to the older generic one + if [ -n "${AXOLOTLSAY_INSTALL_DIR:-}" ]; then + _force_install_dir="$AXOLOTLSAY_INSTALL_DIR" + _install_layout="cargo-home" + elif [ -n "${CARGO_DIST_FORCE_INSTALL_DIR:-}" ]; then + _force_install_dir="$CARGO_DIST_FORCE_INSTALL_DIR" + _install_layout="cargo-home" + elif [ -n "$UNMANAGED_INSTALL" ]; then + _force_install_dir="$UNMANAGED_INSTALL" + _install_layout="flat" + fi + + # Check if the install layout should be changed from `flat` to `cargo-home` + # for backwards compatible updates of applications that switched layouts. + if [ -n "${_force_install_dir:-}" ]; then + if [ "$_install_layout" = "flat" ]; then + # If the install directory is targeting the Cargo home directory, then + # we assume this application was previously installed that layout + if [ "$_force_install_dir" = "${CARGO_HOME:-${INFERRED_HOME:-}/.cargo}" ]; then + _install_layout="cargo-home" + fi + fi + fi + + # Before actually consulting the configured install strategy, see + # if we're overriding it. + if [ -n "${_force_install_dir:-}" ]; then + case "$_install_layout" in + "hierarchical") + _install_dir="$_force_install_dir/bin" + _lib_install_dir="$_force_install_dir/lib" + _receipt_install_dir="$_force_install_dir" + _env_script_path="$_force_install_dir/env" + _install_dir_expr="$(replace_home "$_force_install_dir/bin")" + _env_script_path_expr="$(replace_home "$_force_install_dir/env")" + ;; + "cargo-home") + _install_dir="$_force_install_dir/bin" + _lib_install_dir="$_force_install_dir/bin" + _receipt_install_dir="$_force_install_dir" + _env_script_path="$_force_install_dir/env" + _install_dir_expr="$(replace_home "$_force_install_dir/bin")" + _env_script_path_expr="$(replace_home "$_force_install_dir/env")" + ;; + "flat") + _install_dir="$_force_install_dir" + _lib_install_dir="$_force_install_dir" + _receipt_install_dir="$_install_dir" + _env_script_path="$_force_install_dir/env" + _install_dir_expr="$(replace_home "$_force_install_dir")" + _env_script_path_expr="$(replace_home "$_force_install_dir/env")" + ;; + *) + err "Unrecognized install layout: $_install_layout" + ;; + esac + fi + if [ -z "${_install_dir:-}" ]; then + _install_layout="cargo-home" + # first try $CARGO_HOME, then fallback to $HOME/.cargo + if [ -n "${CARGO_HOME:-}" ]; then + _receipt_install_dir="$CARGO_HOME" + _install_dir="$CARGO_HOME/bin" + _lib_install_dir="$CARGO_HOME/bin" + _env_script_path="$CARGO_HOME/env" + # Initially make this early-bound to erase the potentially-temporary env-var + _install_dir_expr="$_install_dir" + _env_script_path_expr="$_env_script_path" + # If CARGO_HOME was set but it ended up being the default $HOME-based path, + # then keep things late-bound. Otherwise bake the value for safety. + # This is what rustup does, and accurately reproducing it is useful. + if [ -n "${INFERRED_HOME:-}" ]; then + if [ "$INFERRED_HOME/.cargo/bin" = "$_install_dir" ]; then + _install_dir_expr="$INFERRED_HOME_EXPRESSION/.cargo/bin" + _env_script_path_expr="$INFERRED_HOME_EXPRESSION/.cargo/env" + fi + fi + elif [ -n "${INFERRED_HOME:-}" ]; then + _receipt_install_dir="$INFERRED_HOME/.cargo" + _install_dir="$INFERRED_HOME/.cargo/bin" + _lib_install_dir="$INFERRED_HOME/.cargo/bin" + _env_script_path="$INFERRED_HOME/.cargo/env" + _install_dir_expr="$INFERRED_HOME_EXPRESSION/.cargo/bin" + _env_script_path_expr="$INFERRED_HOME_EXPRESSION/.cargo/env" + fi + fi + + if [ -z "$_install_dir_expr" ]; then + err "could not find a valid path to install to!" + fi + + # Identical to the sh version, just with a .fish file extension + # We place it down here to wait until it's been assigned in every + # path. + _fish_env_script_path="${_env_script_path}.fish" + _fish_env_script_path_expr="${_env_script_path_expr}.fish" + + # Replace the temporary cargo home with the calculated one + RECEIPT=$(echo "$RECEIPT" | sed "s,AXO_INSTALL_PREFIX,$_receipt_install_dir,") + # Also replace the aliases with the arch-specific one + RECEIPT=$(echo "$RECEIPT" | sed "s'\"binary_aliases\":{}'\"binary_aliases\":$(json_binary_aliases "$_arch")'") + # And replace the install layout + RECEIPT=$(echo "$RECEIPT" | sed "s'\"install_layout\":\"unspecified\"'\"install_layout\":\"$_install_layout\"'") + if [ "$NO_MODIFY_PATH" = "1" ]; then + RECEIPT=$(echo "$RECEIPT" | sed "s'\"modify_path\":true'\"modify_path\":false'") + fi + + say "installing to $_install_dir" + ensure mkdir -p "$_install_dir" + ensure mkdir -p "$_lib_install_dir" + + # copy all the binaries to the install dir + local _src_dir="$1" + local _bins="$2" + local _libs="$3" + local _staticlibs="$4" + local _arch="$5" + for _bin_name in $_bins; do + local _bin="$_src_dir/$_bin_name" + ensure mv "$_bin" "$_install_dir" + # unzip seems to need this chmod + ensure chmod +x "$_install_dir/$_bin_name" + for _dest in $(aliases_for_binary "$_bin_name" "$_arch"); do + ln -sf "$_install_dir/$_bin_name" "$_install_dir/$_dest" + done + say " $_bin_name" + done + # Like the above, but no aliases + for _lib_name in $_libs; do + local _lib="$_src_dir/$_lib_name" + ensure mv "$_lib" "$_lib_install_dir" + # unzip seems to need this chmod + ensure chmod +x "$_lib_install_dir/$_lib_name" + say " $_lib_name" + done + for _lib_name in $_staticlibs; do + local _lib="$_src_dir/$_lib_name" + ensure mv "$_lib" "$_lib_install_dir" + # unzip seems to need this chmod + ensure chmod +x "$_lib_install_dir/$_lib_name" + say " $_lib_name" + done + + say ">o_o< everything's installed!" + + # Avoid modifying the users PATH if they are managing their PATH manually + case :$PATH: + in *:$_install_dir:*) NO_MODIFY_PATH=1 ;; + *) ;; + esac + + if [ "0" = "$NO_MODIFY_PATH" ]; then + add_install_dir_to_ci_path "$_install_dir" + add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile" "sh" + exit1=$? + shotgun_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".profile .bashrc .bash_profile .bash_login" "sh" + exit2=$? + add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" ".zshrc .zshenv" "sh" + exit3=$? + # This path may not exist by default + ensure mkdir -p "$INFERRED_HOME/.config/fish/conf.d" + exit4=$? + add_install_dir_to_path "$_install_dir_expr" "$_fish_env_script_path" "$_fish_env_script_path_expr" ".config/fish/conf.d/$APP_NAME.env.fish" "fish" + exit5=$? + + if [ "${exit1:-0}" = 1 ] || [ "${exit2:-0}" = 1 ] || [ "${exit3:-0}" = 1 ] || [ "${exit4:-0}" = 1 ] || [ "${exit5:-0}" = 1 ]; then + say "" + say "To add $_install_dir_expr to your PATH, either restart your shell or run:" + say "" + say " source $_env_script_path_expr (sh, bash, zsh)" + say " source $_fish_env_script_path_expr (fish)" + fi + fi + + _shadowed_bins="$(check_for_shadowed_bins "$_install_dir" "$_bins")" + if [ -n "$_shadowed_bins" ]; then + warn "The following commands are shadowed by other commands in your PATH:$_shadowed_bins" + fi +} + +check_for_shadowed_bins() { + local _install_dir="$1" + local _bins="$2" + local _shadow + + for _bin_name in $_bins; do + _shadow="$(command -v "$_bin_name")" + if [ -n "$_shadow" ] && [ "$_shadow" != "$_install_dir/$_bin_name" ]; then + _shadowed_bins="$_shadowed_bins $_bin_name" + fi + done + + echo "$_shadowed_bins" +} + +print_home_for_script() { + local script="$1" + + local _home + case "$script" in + # zsh has a special ZDOTDIR directory, which if set + # should be considered instead of $HOME + .zsh*) + if [ -n "${ZDOTDIR:-}" ]; then + _home="$ZDOTDIR" + else + _home="$INFERRED_HOME" + fi + ;; + *) + _home="$INFERRED_HOME" + ;; + esac + + echo "$_home" +} + +add_install_dir_to_ci_path() { + # Attempt to do CI-specific rituals to get the install-dir on PATH faster + local _install_dir="$1" + + # If GITHUB_PATH is present, then write install_dir to the file it refs. + # After each GitHub Action, the contents will be added to PATH. + # So if you put a curl | sh for this script in its own "run" step, + # the next step will have this dir on PATH. + # + # Note that GITHUB_PATH will not resolve any variables, so we in fact + # want to write install_dir and not install_dir_expr + if [ -n "${GITHUB_PATH:-}" ]; then + ensure echo "$_install_dir" >> "$GITHUB_PATH" + fi +} + +add_install_dir_to_path() { + # Edit rcfiles ($HOME/.profile) to add install_dir to $PATH + # + # We do this slightly indirectly by creating an "env" shell script which checks if install_dir + # is on $PATH already, and prepends it if not. The actual line we then add to rcfiles + # is to just source that script. This allows us to blast it into lots of different rcfiles and + # have it run multiple times without causing problems. It's also specifically compatible + # with the system rustup uses, so that we don't conflict with it. + local _install_dir_expr="$1" + local _env_script_path="$2" + local _env_script_path_expr="$3" + local _rcfiles="$4" + local _shell="$5" + + if [ -n "${INFERRED_HOME:-}" ]; then + local _target + local _home + + # Find the first file in the array that exists and choose + # that as our target to write to + for _rcfile_relative in $_rcfiles; do + _home="$(print_home_for_script "$_rcfile_relative")" + local _rcfile="$_home/$_rcfile_relative" + + if [ -f "$_rcfile" ]; then + _target="$_rcfile" + break + fi + done + + # If we didn't find anything, pick the first entry in the + # list as the default to create and write to + if [ -z "${_target:-}" ]; then + local _rcfile_relative + _rcfile_relative="$(echo "$_rcfiles" | awk '{ print $1 }')" + _home="$(print_home_for_script "$_rcfile_relative")" + _target="$_home/$_rcfile_relative" + fi + + # `source x` is an alias for `. x`, and the latter is more portable/actually-posix. + # This apparently comes up a lot on freebsd. It's easy enough to always add + # the more robust line to rcfiles, but when telling the user to apply the change + # to their current shell ". x" is pretty easy to misread/miscopy, so we use the + # prettier "source x" line there. Hopefully people with Weird Shells are aware + # this is a thing and know to tweak it (or just restart their shell). + local _robust_line=". \"$_env_script_path_expr\"" + local _pretty_line="source \"$_env_script_path_expr\"" + + # Add the env script if it doesn't already exist + if [ ! -f "$_env_script_path" ]; then + say_verbose "creating $_env_script_path" + if [ "$_shell" = "sh" ]; then + write_env_script_sh "$_install_dir_expr" "$_env_script_path" + else + write_env_script_fish "$_install_dir_expr" "$_env_script_path" + fi + else + say_verbose "$_env_script_path already exists" + fi + + # Check if the line is already in the rcfile + # grep: 0 if matched, 1 if no match, and 2 if an error occurred + # + # Ideally we could use quiet grep (-q), but that makes "match" and "error" + # have the same behaviour, when we want "no match" and "error" to be the same + # (on error we want to create the file, which >> conveniently does) + # + # We search for both kinds of line here just to do the right thing in more cases. + if ! grep -F "$_robust_line" "$_target" > /dev/null 2>/dev/null && \ + ! grep -F "$_pretty_line" "$_target" > /dev/null 2>/dev/null + then + # If the script now exists, add the line to source it to the rcfile + # (This will also create the rcfile if it doesn't exist) + if [ -f "$_env_script_path" ]; then + local _line + # Fish has deprecated `.` as an alias for `source` and + # it will be removed in a later version. + # https://fishshell.com/docs/current/cmds/source.html + # By contrast, `.` is the traditional syntax in sh and + # `source` isn't always supported in all circumstances. + if [ "$_shell" = "fish" ]; then + _line="$_pretty_line" + else + _line="$_robust_line" + fi + say_verbose "adding $_line to $_target" + # prepend an extra newline in case the user's file is missing a trailing one + ensure echo "" >> "$_target" + ensure echo "$_line" >> "$_target" + return 1 + fi + else + say_verbose "$_install_dir already on PATH" + fi + fi +} + +shotgun_install_dir_to_path() { + # Edit rcfiles ($HOME/.profile) to add install_dir to $PATH + # (Shotgun edition - write to all provided files that exist rather than just the first) + local _install_dir_expr="$1" + local _env_script_path="$2" + local _env_script_path_expr="$3" + local _rcfiles="$4" + local _shell="$5" + + if [ -n "${INFERRED_HOME:-}" ]; then + local _found=false + local _home + + for _rcfile_relative in $_rcfiles; do + _home="$(print_home_for_script "$_rcfile_relative")" + local _rcfile_abs="$_home/$_rcfile_relative" + + if [ -f "$_rcfile_abs" ]; then + _found=true + add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfile_relative" "$_shell" + fi + done + + # Fall through to previous "create + write to first file in list" behavior + if [ "$_found" = false ]; then + add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr" "$_rcfiles" "$_shell" + fi + fi +} + +write_env_script_sh() { + # write this env script to the given path (this cat/EOF stuff is a "heredoc" string) + local _install_dir_expr="$1" + local _env_script_path="$2" + ensure cat < "$_env_script_path" +#!/bin/sh +# add binaries to PATH if they aren't added yet +# affix colons on either side of \$PATH to simplify matching +case ":\${PATH}:" in + *:"$_install_dir_expr":*) + ;; + *) + # Prepending path in case a system-installed binary needs to be overridden + export PATH="$_install_dir_expr:\$PATH" + ;; +esac +EOF +} + +write_env_script_fish() { + # write this env script to the given path (this cat/EOF stuff is a "heredoc" string) + local _install_dir_expr="$1" + local _env_script_path="$2" + ensure cat < "$_env_script_path" +if not contains "$_install_dir_expr" \$PATH + # Prepending path in case a system-installed binary needs to be overridden + set -x PATH "$_install_dir_expr" \$PATH +end +EOF +} + +get_current_exe() { + # Returns the executable used for system architecture detection + # This is only run on Linux + local _current_exe + if test -L /proc/self/exe ; then + _current_exe=/proc/self/exe + else + warn "Unable to find /proc/self/exe. System architecture detection might be inaccurate." + if test -n "$SHELL" ; then + _current_exe=$SHELL + else + need_cmd /bin/sh + _current_exe=/bin/sh + fi + warn "Falling back to $_current_exe." + fi + echo "$_current_exe" +} + +get_bitness() { + need_cmd head + # Architecture detection without dependencies beyond coreutils. + # ELF files start out "\x7fELF", and the following byte is + # 0x01 for 32-bit and + # 0x02 for 64-bit. + # The printf builtin on some shells like dash only supports octal + # escape sequences, so we use those. + local _current_exe=$1 + local _current_exe_head + _current_exe_head=$(head -c 5 "$_current_exe") + if [ "$_current_exe_head" = "$(printf '\177ELF\001')" ]; then + echo 32 + elif [ "$_current_exe_head" = "$(printf '\177ELF\002')" ]; then + echo 64 + else + err "unknown platform bitness" + fi +} + +is_host_amd64_elf() { + local _current_exe=$1 + + need_cmd head + need_cmd tail + # ELF e_machine detection without dependencies beyond coreutils. + # Two-byte field at offset 0x12 indicates the CPU, + # but we're interested in it being 0x3E to indicate amd64, or not that. + local _current_exe_machine + _current_exe_machine=$(head -c 19 "$_current_exe" | tail -c 1) + [ "$_current_exe_machine" = "$(printf '\076')" ] +} + +get_endianness() { + local _current_exe=$1 + local cputype=$2 + local suffix_eb=$3 + local suffix_el=$4 + + # detect endianness without od/hexdump, like get_bitness() does. + need_cmd head + need_cmd tail + + local _current_exe_endianness + _current_exe_endianness="$(head -c 6 "$_current_exe" | tail -c 1)" + if [ "$_current_exe_endianness" = "$(printf '\001')" ]; then + echo "${cputype}${suffix_el}" + elif [ "$_current_exe_endianness" = "$(printf '\002')" ]; then + echo "${cputype}${suffix_eb}" + else + err "unknown platform endianness" + fi +} + +# Detect the Linux/LoongArch UAPI flavor, with all errors being non-fatal. +# Returns 0 or 234 in case of successful detection, 1 otherwise (/tmp being +# noexec, or other causes). +check_loongarch_uapi() { + need_cmd base64 + + local _tmp + if ! _tmp="$(ensure mktemp)"; then + return 1 + fi + + # Minimal Linux/LoongArch UAPI detection, exiting with 0 in case of + # upstream ("new world") UAPI, and 234 (-EINVAL truncated) in case of + # old-world (as deployed on several early commercial Linux distributions + # for LoongArch). + # + # See https://gist.github.com/xen0n/5ee04aaa6cecc5c7794b9a0c3b65fc7f for + # source to this helper binary. + ignore base64 -d > "$_tmp" <&1 | grep -q 'musl'; then + _clibtype="musl-dynamic" + else + # Assume all other linuxes are glibc (even if wrong, static libc fallback will apply) + _clibtype="gnu" + fi + fi + + if [ "$_ostype" = Darwin ]; then + # Darwin `uname -m` can lie due to Rosetta shenanigans. If you manage to + # invoke a native shell binary and then a native uname binary, you can + # get the real answer, but that's hard to ensure, so instead we use + # `sysctl` (which doesn't lie) to check for the actual architecture. + if [ "$_cputype" = i386 ]; then + # Handling i386 compatibility mode in older macOS versions (<10.15) + # running on x86_64-based Macs. + # Starting from 10.15, macOS explicitly bans all i386 binaries from running. + # See: + + # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. + if sysctl hw.optional.x86_64 2> /dev/null || true | grep -q ': 1'; then + _cputype=x86_64 + fi + elif [ "$_cputype" = x86_64 ]; then + # Handling x86-64 compatibility mode (a.k.a. Rosetta 2) + # in newer macOS versions (>=11) running on arm64-based Macs. + # Rosetta 2 is built exclusively for x86-64 and cannot run i386 binaries. + + # Avoid `sysctl: unknown oid` stderr output and/or non-zero exit code. + if sysctl hw.optional.arm64 2> /dev/null || true | grep -q ': 1'; then + _cputype=arm64 + fi + fi + fi + + if [ "$_ostype" = SunOS ]; then + # Both Solaris and illumos presently announce as "SunOS" in "uname -s" + # so use "uname -o" to disambiguate. We use the full path to the + # system uname in case the user has coreutils uname first in PATH, + # which has historically sometimes printed the wrong value here. + if [ "$(/usr/bin/uname -o)" = illumos ]; then + _ostype=illumos + fi + + # illumos systems have multi-arch userlands, and "uname -m" reports the + # machine hardware name; e.g., "i86pc" on both 32- and 64-bit x86 + # systems. Check for the native (widest) instruction set on the + # running kernel: + if [ "$_cputype" = i86pc ]; then + _cputype="$(isainfo -n)" + fi + fi + + local _current_exe + case "$_ostype" in + + Android) + _ostype=linux-android + ;; + + Linux) + _current_exe=$(get_current_exe) + _ostype=unknown-linux-$_clibtype + _bitness=$(get_bitness "$_current_exe") + ;; + + FreeBSD) + _ostype=unknown-freebsd + ;; + + NetBSD) + _ostype=unknown-netbsd + ;; + + DragonFly) + _ostype=unknown-dragonfly + ;; + + Darwin) + _ostype=apple-darwin + ;; + + illumos) + _ostype=unknown-illumos + ;; + + MINGW* | MSYS* | CYGWIN* | Windows_NT) + _ostype=pc-windows-gnu + ;; + + *) + err "unrecognized OS type: $_ostype" + ;; + + esac + + case "$_cputype" in + + i386 | i486 | i686 | i786 | x86) + _cputype=i686 + ;; + + xscale | arm) + _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + fi + ;; + + armv6l) + _cputype=arm + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + + armv7l | armv8l) + _cputype=armv7 + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + + aarch64 | arm64) + _cputype=aarch64 + ;; + + x86_64 | x86-64 | x64 | amd64) + _cputype=x86_64 + ;; + + mips) + _cputype=$(get_endianness "$_current_exe" mips '' el) + ;; + + mips64) + if [ "$_bitness" -eq 64 ]; then + # only n64 ABI is supported for now + _ostype="${_ostype}abi64" + _cputype=$(get_endianness "$_current_exe" mips64 '' el) + fi + ;; + + ppc) + _cputype=powerpc + ;; + + ppc64) + _cputype=powerpc64 + ;; + + ppc64le) + _cputype=powerpc64le + ;; + + s390x) + _cputype=s390x + ;; + riscv64) + _cputype=riscv64gc + ;; + loongarch64) + _cputype=loongarch64 + ensure_loongarch_uapi + ;; + *) + err "unknown CPU type: $_cputype" + + esac + + # Detect 64-bit linux with 32-bit userland + if [ "${_ostype}" = unknown-linux-gnu ] && [ "${_bitness}" -eq 32 ]; then + case $_cputype in + x86_64) + # 32-bit executable for amd64 = x32 + if is_host_amd64_elf "$_current_exe"; then { + err "x32 linux unsupported" + }; else + _cputype=i686 + fi + ;; + mips64) + _cputype=$(get_endianness "$_current_exe" mips '' el) + ;; + powerpc64) + _cputype=powerpc + ;; + aarch64) + _cputype=armv7 + if [ "$_ostype" = "linux-android" ]; then + _ostype=linux-androideabi + else + _ostype="${_ostype}eabihf" + fi + ;; + riscv64gc) + err "riscv64 with 32-bit userland unsupported" + ;; + esac + fi + + # Detect armv7 but without the CPU features Rust needs in that build, + # and fall back to arm. + if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then + if ! (ensure grep '^Features' /proc/cpuinfo | grep -E -q 'neon|simd') ; then + # Either `/proc/cpuinfo` is malformed or unavailable, or + # at least one processor does not have NEON (which is asimd on armv8+). + _cputype=arm + fi + fi + + _arch="${_cputype}-${_ostype}" + + RETVAL="$_arch" +} + +say() { + if [ "0" = "$PRINT_QUIET" ]; then + echo "$1" + fi +} + +say_verbose() { + if [ "1" = "$PRINT_VERBOSE" ]; then + echo "$1" + fi +} + +warn() { + if [ "0" = "$PRINT_QUIET" ]; then + local red + local reset + red=$(tput setaf 1 2>/dev/null || echo '') + reset=$(tput sgr0 2>/dev/null || echo '') + say "${red}WARN${reset}: $1" >&2 + fi +} + +err() { + if [ "0" = "$PRINT_QUIET" ]; then + local red + local reset + red=$(tput setaf 1 2>/dev/null || echo '') + reset=$(tput sgr0 2>/dev/null || echo '') + say "${red}ERROR${reset}: $1" >&2 + fi + exit 1 +} + +need_cmd() { + if ! check_cmd "$1" + then err "need '$1' (command not found)" + fi +} + +check_cmd() { + command -v "$1" > /dev/null 2>&1 + return $? +} + +assert_nz() { + if [ -z "$1" ]; then err "assert_nz $2"; fi +} + +# Run a command that should never fail. If the command fails execution +# will immediately terminate with an error showing the failing +# command. +ensure() { + if ! "$@"; then err "command failed: $*"; fi +} + +# This is just for indicating that commands' results are being +# intentionally ignored. Usually, because it's being executed +# as part of error handling. +ignore() { + "$@" +} + +# This wraps curl or wget. Try curl first, if not installed, +# use wget instead. +downloader() { + # Check if we have a broken snap curl + # https://github.com/boukendesho/curl-snap/issues/1 + _snap_curl=0 + if command -v curl > /dev/null 2>&1; then + _curl_path=$(command -v curl) + if echo "$_curl_path" | grep "/snap/" > /dev/null 2>&1; then + _snap_curl=1 + fi + fi + + # Check if we have a working (non-snap) curl + if check_cmd curl && [ "$_snap_curl" = "0" ] + then _dld=curl + # Try wget for both no curl and the broken snap curl + elif check_cmd wget + then _dld=wget + # If we can't fall back from broken snap curl to wget, report the broken snap curl + elif [ "$_snap_curl" = "1" ] + then + say "curl installed with snap cannot be used to install $APP_NAME" + say "due to missing permissions. Please uninstall it and" + say "reinstall curl with a different package manager (e.g., apt)." + say "See https://github.com/boukendesho/curl-snap/issues/1" + exit 1 + else _dld='curl or wget' # to be used in error message of need_cmd + fi + + if [ "$1" = --check ] + then need_cmd "$_dld" + elif [ "$_dld" = curl ]; then + if [ -n "${AUTH_TOKEN:-}" ]; then + curl -sSfL --header "Authorization: Bearer ${AUTH_TOKEN}" "$1" -o "$2" + else + curl -sSfL "$1" -o "$2" + fi + elif [ "$_dld" = wget ]; then + if [ -n "${AUTH_TOKEN:-}" ]; then + wget --header "Authorization: Bearer ${AUTH_TOKEN}" "$1" -O "$2" + else + wget "$1" -O "$2" + fi + else err "Unknown downloader" # should not reach here + fi +} + +verify_checksum() { + local _file="$1" + local _checksum_style="$2" + local _checksum_value="$3" + local _calculated_checksum + + if [ -z "$_checksum_value" ]; then + return 0 + fi + case "$_checksum_style" in + sha256) + if ! check_cmd sha256sum; then + say "skipping sha256 checksum verification (it requires the 'sha256sum' command)" + return 0 + fi + _calculated_checksum="$(sha256sum -b "$_file" | awk '{printf $1}')" + ;; + sha512) + if ! check_cmd sha512sum; then + say "skipping sha512 checksum verification (it requires the 'sha512sum' command)" + return 0 + fi + _calculated_checksum="$(sha512sum -b "$_file" | awk '{printf $1}')" + ;; + sha3-256) + if ! check_cmd openssl; then + say "skipping sha3-256 checksum verification (it requires the 'openssl' command)" + return 0 + fi + _calculated_checksum="$(openssl dgst -sha3-256 "$_file" | awk '{printf $NF}')" + ;; + sha3-512) + if ! check_cmd openssl; then + say "skipping sha3-512 checksum verification (it requires the 'openssl' command)" + return 0 + fi + _calculated_checksum="$(openssl dgst -sha3-512 "$_file" | awk '{printf $NF}')" + ;; + blake2s) + if ! check_cmd b2sum; then + say "skipping blake2s checksum verification (it requires the 'b2sum' command)" + return 0 + fi + # Test if we have official b2sum with blake2s support + local _well_known_blake2s_checksum="93314a61f470985a40f8da62df10ba0546dc5216e1d45847bf1dbaa42a0e97af" + local _test_blake2s + _test_blake2s="$(printf "can do blake2s" | b2sum -a blake2s | awk '{printf $1}')" || _test_blake2s="" + + if [ "X$_test_blake2s" = "X$_well_known_blake2s_checksum" ]; then + _calculated_checksum="$(b2sum -a blake2s "$_file" | awk '{printf $1}')" || _calculated_checksum="" + else + say "skipping blake2s checksum verification (installed b2sum doesn't support blake2s)" + return 0 + fi + ;; + blake2b) + if ! check_cmd b2sum; then + say "skipping blake2b checksum verification (it requires the 'b2sum' command)" + return 0 + fi + _calculated_checksum="$(b2sum "$_file" | awk '{printf $1}')" + ;; + false) + ;; + *) + say "skipping unknown checksum style: $_checksum_style" + return 0 + ;; + esac + + if [ "$_calculated_checksum" != "$_checksum_value" ]; then + err "checksum mismatch + want: $_checksum_value + got: $_calculated_checksum" + fi +} + +download_binary_and_run_installer "$@" || exit 1 + +================ axolotlsay.rb ================ +class Axolotlsay < Formula + desc "šŸ’¬ a CLI for learning to distribute CLIs in rust" + homepage "https://github.com/axodotdev/axolotlsay" + version "0.2.2" + if OS.mac? + if Hardware::CPU.arm? + url "https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-aarch64-apple-darwin.tar.gz" + end + if Hardware::CPU.intel? + url "https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-apple-darwin.tar.gz" + end + end + if OS.linux? + if Hardware::CPU.intel? + url "https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-unknown-linux-gnu.tar.gz" + end + end + license any_of: ["MIT", "Apache-2.0"] + + BINARY_ALIASES = { + "aarch64-apple-darwin": {}, + "x86_64-apple-darwin": {}, + "x86_64-pc-windows-gnu": {}, + "x86_64-unknown-linux-gnu": {} + } + + def target_triple + cpu = Hardware::CPU.arm? ? "aarch64" : "x86_64" + os = OS.mac? ? "apple-darwin" : "unknown-linux-gnu" + + "#{cpu}-#{os}" + end + + def install_binary_aliases! + BINARY_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 OS.mac? && Hardware::CPU.arm? + bin.install "axolotlsay" + end + if OS.mac? && Hardware::CPU.intel? + bin.install "axolotlsay" + end + if OS.linux? && Hardware::CPU.intel? + bin.install "axolotlsay" + end + + install_binary_aliases! + + # Homebrew will automatically install these, so we don't need to do that + doc_files = Dir["README.*", "readme.*", "LICENSE", "LICENSE.*", "CHANGELOG.*"] + leftover_contents = Dir["*"] - doc_files + + # Install any leftover files in pkgshare; these are probably config or + # sample files. + pkgshare.install(*leftover_contents) unless leftover_contents.empty? + end +end + +================ axolotlsay-installer.ps1 ================ +# Licensed under the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +<# +.SYNOPSIS + +The installer for axolotlsay 0.2.2 + +.DESCRIPTION + +This script detects what platform you're on and fetches an appropriate archive from +https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2 +then unpacks the binaries and installs them to + + $env:CARGO_HOME/bin (or $HOME/.cargo/bin) + +It will then add that dir to PATH by editing your Environment.Path registry key + +.PARAMETER ArtifactDownloadUrl +The URL of the directory where artifacts can be fetched from + +.PARAMETER NoModifyPath +Don't add the install directory to PATH + +.PARAMETER Help +Print help + +#> + +param ( + [Parameter(HelpMessage = "The URL of the directory where artifacts can be fetched from")] + [string]$ArtifactDownloadUrl = 'https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2', + [Parameter(HelpMessage = "Don't add the install directory to PATH")] + [switch]$NoModifyPath, + [Parameter(HelpMessage = "Print Help")] + [switch]$Help +) + +$app_name = 'axolotlsay' +$app_version = '0.2.2' +if ($env:AXOLOTLSAY_INSTALLER_GHE_BASE_URL) { + $installer_base_url = $env:AXOLOTLSAY_INSTALLER_GHE_BASE_URL +} elseif ($env:AXOLOTLSAY_INSTALLER_GITHUB_BASE_URL) { + $installer_base_url = $env:AXOLOTLSAY_INSTALLER_GITHUB_BASE_URL +} else { + $installer_base_url = "https://github.com" +} +if ($env:AXOLOTLSAY_DOWNLOAD_URL) { + $ArtifactDownloadUrl = $env:AXOLOTLSAY_DOWNLOAD_URL +} elseif ($env:INSTALLER_DOWNLOAD_URL) { + $ArtifactDownloadUrl = $env:INSTALLER_DOWNLOAD_URL +} else { + $ArtifactDownloadUrl = "$installer_base_url/axodotdev/axolotlsay/releases/download/v0.2.2" +} +$auth_token = $env:AXOLOTLSAY_GITHUB_TOKEN + +$receipt = @" +{"binaries":["CARGO_DIST_BINS"],"binary_aliases":{},"cdylibs":["CARGO_DIST_DYLIBS"],"cstaticlibs":["CARGO_DIST_STATICLIBS"],"install_layout":"unspecified","install_prefix":"AXO_INSTALL_PREFIX","modify_path":true,"provider":{"source":"cargo-dist","version":"CENSORED"},"source":{"app_name":"axolotlsay","name":"axolotlsay","owner":"axodotdev","release_type":"github"},"version":"CENSORED"} +"@ +if ($env:XDG_CONFIG_HOME) { + $receipt_home = "${env:XDG_CONFIG_HOME}\axolotlsay" +} else { + $receipt_home = "${env:LOCALAPPDATA}\axolotlsay" +} + +if ($env:AXOLOTLSAY_DISABLE_UPDATE) { + $install_updater = $false +} else { + $install_updater = $true +} + +if ($NoModifyPath) { + Write-Information "-NoModifyPath has been deprecated; please set AXOLOTLSAY_NO_MODIFY_PATH=1 in the environment" +} + +if ($env:AXOLOTLSAY_NO_MODIFY_PATH) { + $NoModifyPath = $true +} + +$unmanaged_install = $env:AXOLOTLSAY_UNMANAGED_INSTALL + +if ($unmanaged_install) { + $NoModifyPath = $true + $install_updater = $false +} + +function Install-Binary($install_args) { + if ($Help) { + Get-Help $PSCommandPath -Detailed + Exit + } + + Initialize-Environment + + # Platform info injected by dist + $platforms = @{ + "aarch64-pc-windows-msvc" = @{ + "artifact_name" = "axolotlsay-x86_64-pc-windows-msvc.tar.gz" + "bins" = @("axolotlsay.exe") + "libs" = @() + "staticlibs" = @() + "zip_ext" = ".tar.gz" + "aliases" = @{ + } + "aliases_json" = '{}' + } + "x86_64-pc-windows-gnu" = @{ + "artifact_name" = "axolotlsay-x86_64-pc-windows-msvc.tar.gz" + "bins" = @("axolotlsay.exe") + "libs" = @() + "staticlibs" = @() + "zip_ext" = ".tar.gz" + "aliases" = @{ + } + "aliases_json" = '{}' + } + "x86_64-pc-windows-msvc" = @{ + "artifact_name" = "axolotlsay-x86_64-pc-windows-msvc.tar.gz" + "bins" = @("axolotlsay.exe") + "libs" = @() + "staticlibs" = @() + "zip_ext" = ".tar.gz" + "aliases" = @{ + } + "aliases_json" = '{}' + } + } + + $fetched = Download "$ArtifactDownloadUrl" $platforms + # FIXME: add a flag that lets the user not do this step + try { + Invoke-Installer -artifacts $fetched -platforms $platforms "$install_args" + } catch { + throw @" +We encountered an error trying to perform the installation; +please review the error messages below. + +$_ +"@ + } +} + +function Get-TargetTriple($platforms) { + $double = Get-Arch + if ($platforms.Contains("$double-msvc")) { + return "$double-msvc" + } else { + return "$double-gnu" + } +} + +function Get-Arch() { + try { + # NOTE: this might return X64 on ARM64 Windows, which is OK since emulation is available. + # It works correctly starting in PowerShell Core 7.3 and Windows PowerShell in Win 11 22H2. + # Ideally this would just be + # [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture + # but that gets a type from the wrong assembly on Windows PowerShell (i.e. not Core) + $a = [System.Reflection.Assembly]::LoadWithPartialName("System.Runtime.InteropServices.RuntimeInformation") + $t = $a.GetType("System.Runtime.InteropServices.RuntimeInformation") + $p = $t.GetProperty("OSArchitecture") + # Possible OSArchitecture Values: https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.architecture + # Rust supported platforms: https://doc.rust-lang.org/stable/rustc/platform-support.html + switch ($p.GetValue($null).ToString()) + { + "X86" { return "i686-pc-windows" } + "X64" { return "x86_64-pc-windows" } + "Arm" { return "thumbv7a-pc-windows" } + "Arm64" { return "aarch64-pc-windows" } + } + } catch { + # The above was added in .NET 4.7.1, so Windows PowerShell in versions of Windows + # prior to Windows 10 v1709 may not have this API. + Write-Verbose "Get-TargetTriple: Exception when trying to determine OS architecture." + Write-Verbose $_ + } + + # This is available in .NET 4.0. We already checked for PS 5, which requires .NET 4.5. + Write-Verbose("Get-TargetTriple: falling back to Is64BitOperatingSystem.") + if ([System.Environment]::Is64BitOperatingSystem) { + return "x86_64-pc-windows" + } else { + return "i686-pc-windows" + } +} + +function Download($download_url, $platforms) { + $arch = Get-TargetTriple $platforms + + if (-not $platforms.ContainsKey($arch)) { + $platforms_json = ConvertTo-Json $platforms + throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json" + } + + # Lookup what we expect this platform to look like + $info = $platforms[$arch] + $zip_ext = $info["zip_ext"] + $bin_names = $info["bins"] + $lib_names = $info["libs"] + $staticlib_names = $info["staticlibs"] + $artifact_name = $info["artifact_name"] + + # Make a new temp dir to unpack things to + $tmp = New-Temp-Dir + $dir_path = "$tmp\$app_name$zip_ext" + + # Download and unpack! + $url = "$download_url/$artifact_name" + Write-Information "Downloading $app_name $app_version ($arch)" + Write-Verbose " from $url" + Write-Verbose " to $dir_path" + $wc = New-Object Net.Webclient + if ($auth_token) { + $wc.Headers["Authorization"] = "Bearer $auth_token" + } + $wc.downloadFile($url, $dir_path) + + Write-Verbose "Unpacking to $tmp" + + # Select the tool to unpack the files with. + # + # As of windows 10(?), powershell comes with tar preinstalled, but in practice + # it only seems to support .tar.gz, and not xz/zstd. Still, we should try to + # forward all tars to it in case the user has a machine that can handle it! + switch -Wildcard ($zip_ext) { + ".zip" { + Expand-Archive -Path $dir_path -DestinationPath "$tmp"; + Break + } + ".tar.*" { + tar xf $dir_path --strip-components 1 -C "$tmp"; + Break + } + Default { + throw "ERROR: unknown archive format $zip_ext" + } + } + + # Let the next step know what to copy + $bin_paths = @() + foreach ($bin_name in $bin_names) { + Write-Verbose " Unpacked $bin_name" + $bin_paths += "$tmp\$bin_name" + } + $lib_paths = @() + foreach ($lib_name in $lib_names) { + Write-Verbose " Unpacked $lib_name" + $lib_paths += "$tmp\$lib_name" + } + $staticlib_paths = @() + foreach ($lib_name in $staticlib_names) { + Write-Verbose " Unpacked $lib_name" + $staticlib_paths += "$tmp\$lib_name" + } + + if (($null -ne $info["updater"]) -and $install_updater) { + $updater_id = $info["updater"]["artifact_name"] + $updater_url = "$download_url/$updater_id" + $out_name = "$tmp\axolotlsay-update.exe" + + $wc.downloadFile($updater_url, $out_name) + $bin_paths += $out_name + } + + return @{ + "bin_paths" = $bin_paths + "lib_paths" = $lib_paths + "staticlib_paths" = $staticlib_paths + } +} + +function Invoke-Installer($artifacts, $platforms) { + # Replaces the placeholder binary entry with the actual list of binaries + $arch = Get-TargetTriple $platforms + + if (-not $platforms.ContainsKey($arch)) { + $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] + + # Forces the install to occur at this path, not the default + $force_install_dir = $null + $install_layout = "unspecified" + # Check the newer app-specific variable before falling back + # to the older generic one + if (($env:AXOLOTLSAY_INSTALL_DIR)) { + $force_install_dir = $env:AXOLOTLSAY_INSTALL_DIR + $install_layout = "cargo-home" + } elseif (($env:CARGO_DIST_FORCE_INSTALL_DIR)) { + $force_install_dir = $env:CARGO_DIST_FORCE_INSTALL_DIR + $install_layout = "cargo-home" + } elseif ($unmanaged_install) { + $force_install_dir = $unmanaged_install + $install_layout = "flat" + } + + # Check if the install layout should be changed from `flat` to `cargo-home` + # for backwards compatible updates of applications that switched layouts. + if (($force_install_dir) -and ($install_layout -eq "flat")) { + # If the install directory is targeting the Cargo home directory, then + # we assume this application was previously installed that layout + # Note the installer passes the path with `\\` separators, but here they are + # `\` so we normalize for comparison. We don't use `Resolve-Path` because they + # may not exist. + $cargo_home = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { + Join-Path $(if ($HOME) { $HOME } else { "." }) ".cargo" + } + if ($force_install_dir.Replace('\\', '\') -eq $cargo_home) { + $install_layout = "cargo-home" + } + } + + # The actual path we're going to install to + $dest_dir = $null + $dest_dir_lib = $null + # The install prefix we write to the receipt. + # For organized install methods like CargoHome, which have + # subdirectories, this is the root without `/bin`. For other + # methods, this is the same as `_install_dir`. + $receipt_dest_dir = $null + # Before actually consulting the configured install strategy, see + # if we're overriding it. + if (($force_install_dir)) { + switch ($install_layout) { + "hierarchical" { + $dest_dir = Join-Path $force_install_dir "bin" + $dest_dir_lib = Join-Path $force_install_dir "lib" + } + "cargo-home" { + $dest_dir = Join-Path $force_install_dir "bin" + $dest_dir_lib = $dest_dir + } + "flat" { + $dest_dir = $force_install_dir + $dest_dir_lib = $dest_dir + } + Default { + throw "Error: unrecognized installation layout: $install_layout" + } + } + $receipt_dest_dir = $force_install_dir + } + if (-Not $dest_dir) { + # first try $env:CARGO_HOME, then fallback to $HOME + # (for whatever reason $HOME is not a normal env var and doesn't need the $env: prefix) + $root = if (($base_dir = $env:CARGO_HOME)) { + $base_dir + } elseif (($base_dir = $HOME)) { + Join-Path $base_dir ".cargo" + } else { + throw "ERROR: could not find your HOME dir or CARGO_HOME to install binaries to" + } + + $dest_dir = Join-Path $root "bin" + $dest_dir_lib = $dest_dir + $receipt_dest_dir = $root + $install_layout = "cargo-home" + } + + # Looks like all of the above assignments failed + if (-Not $dest_dir) { + throw "ERROR: could not find a valid path to install to; please check the installation instructions" + } + + # The replace call here ensures proper escaping is inlined into the receipt + $receipt = $receipt.Replace('AXO_INSTALL_PREFIX', $receipt_dest_dir.replace("\", "\\")) + $receipt = $receipt.Replace('"install_layout":"unspecified"', -join('"install_layout":"', $install_layout, '"')) + + $dest_dir = New-Item -Force -ItemType Directory -Path $dest_dir + $dest_dir_lib = New-Item -Force -ItemType Directory -Path $dest_dir_lib + Write-Information "Installing to $dest_dir" + # Just copy the binaries from the temp location to the install dir + foreach ($bin_path in $artifacts["bin_paths"]) { + $installed_file = Split-Path -Path "$bin_path" -Leaf + Copy-Item "$bin_path" -Destination "$dest_dir" -ErrorAction Stop + Remove-Item "$bin_path" -Recurse -Force -ErrorAction Stop + Write-Information " $installed_file" + + 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 -ErrorAction Stop + } + } + } + foreach ($lib_path in $artifacts["lib_paths"]) { + $installed_file = Split-Path -Path "$lib_path" -Leaf + Copy-Item "$lib_path" -Destination "$dest_dir_lib" -ErrorAction Stop + Remove-Item "$lib_path" -Recurse -Force -ErrorAction Stop + Write-Information " $installed_file" + } + foreach ($lib_path in $artifacts["staticlib_paths"]) { + $installed_file = Split-Path -Path "$lib_path" -Leaf + Copy-Item "$lib_path" -Destination "$dest_dir_lib" -ErrorAction Stop + Remove-Item "$lib_path" -Recurse -Force -ErrorAction Stop + Write-Information " $installed_file" + } + + $formatted_bins = ($info["bins"] | ForEach-Object { '"' + $_ + '"' }) -join "," + $receipt = $receipt.Replace('"CARGO_DIST_BINS"', $formatted_bins) + $formatted_libs = ($info["libs"] | ForEach-Object { '"' + $_ + '"' }) -join "," + $receipt = $receipt.Replace('"CARGO_DIST_DYLIBS"', $formatted_libs) + $formatted_staticlibs = ($info["staticlibs"] | ForEach-Object { '"' + $_ + '"' }) -join "," + $receipt = $receipt.Replace('"CARGO_DIST_STATICLIBS"', $formatted_staticlibs) + # Also replace the aliases with the arch-specific one + $receipt = $receipt.Replace('"binary_aliases":{}', -join('"binary_aliases":', $info['aliases_json'])) + if ($NoModifyPath) { + $receipt = $receipt.Replace('"modify_path":true', '"modify_path":false') + } + + # Write the install receipt + if ($install_updater) { + $null = New-Item -Path $receipt_home -ItemType "directory" -ErrorAction SilentlyContinue + # Trying to get Powershell 5.1 (not 6+, which is fake and lies) to write utf8 is a crime + # because "Out-File -Encoding utf8" actually still means utf8BOM, so we need to pull out + # .NET's APIs which actually do what you tell them (also apparently utf8NoBOM is the + # default in newer .NETs but I'd rather not rely on that at this point). + $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False + [IO.File]::WriteAllLines("$receipt_home/axolotlsay-receipt.json", "$receipt", $Utf8NoBomEncoding) + } + + # Respect the environment, but CLI takes precedence + if ($null -eq $NoModifyPath) { + $NoModifyPath = $env:INSTALLER_NO_MODIFY_PATH + } + + Write-Information ">o_o< everything's installed!" + if (-not $NoModifyPath) { + Add-Ci-Path $dest_dir + if (Add-Path $dest_dir) { + Write-Information "" + Write-Information "To add $dest_dir to your PATH, either restart your shell or run:" + Write-Information "" + Write-Information " set Path=$dest_dir;%Path% (cmd)" + Write-Information " `$env:Path = `"$dest_dir;`$env:Path`" (powershell)" + } + } +} + +# Attempt to do CI-specific rituals to get the install-dir on PATH faster +function Add-Ci-Path($OrigPathToAdd) { + # If GITHUB_PATH is present, then write install_dir to the file it refs. + # After each GitHub Action, the contents will be added to PATH. + # So if you put a curl | sh for this script in its own "run" step, + # the next step will have this dir on PATH. + # + # Note that GITHUB_PATH will not resolve any variables, so we in fact + # want to write the install dir and not an expression that evals to it + if (($gh_path = $env:GITHUB_PATH)) { + Write-Output "$OrigPathToAdd" | Out-File -FilePath "$gh_path" -Encoding utf8 -Append + } +} + +# Try to permanently add the given path to the user-level +# PATH via the registry +# +# Returns true if the registry was modified, otherwise returns false +# (indicating it was already on PATH) +# +# This is a lightly modified version of this solution: +# https://stackoverflow.com/questions/69236623/adding-path-permanently-to-windows-using-powershell-doesnt-appear-to-work/69239861#69239861 +function Add-Path($LiteralPath) { + Write-Verbose "Adding $LiteralPath to your user-level PATH" + + $RegistryPath = 'registry::HKEY_CURRENT_USER\Environment' + + # Note the use of the .GetValue() method to ensure that the *unexpanded* value is returned. + # If 'Path' is not an existing item in the registry, '' is returned. + $CurrentDirectories = (Get-Item -LiteralPath $RegistryPath).GetValue('Path', '', 'DoNotExpandEnvironmentNames') -split ';' -ne '' + + if ($LiteralPath -in $CurrentDirectories) { + Write-Verbose "Install directory $LiteralPath already on PATH, all done!" + return $false + } + + Write-Verbose "Actually mutating 'Path' Property" + + # Add the new path to the front of the PATH. + # The ',' turns $LiteralPath into an array, which the array of + # $CurrentDirectories is then added to. + $NewPath = (,$LiteralPath + $CurrentDirectories) -join ';' + + # Update the registry. Will create the property if it did not already exist. + # Note the use of ExpandString to create a registry property with a REG_EXPAND_SZ data type. + Set-ItemProperty -Type ExpandString -LiteralPath $RegistryPath Path $NewPath + + # Broadcast WM_SETTINGCHANGE to get the Windows shell to reload the + # updated environment, via a dummy [Environment]::SetEnvironmentVariable() operation. + $DummyName = 'cargo-dist-' + [guid]::NewGuid().ToString() + [Environment]::SetEnvironmentVariable($DummyName, 'cargo-dist-dummy', 'User') + [Environment]::SetEnvironmentVariable($DummyName, [NullString]::value, 'User') + + Write-Verbose "Successfully added $LiteralPath to your user-level PATH" + return $true +} + +function Initialize-Environment() { + If (($PSVersionTable.PSVersion.Major) -lt 5) { + throw @" +Error: PowerShell 5 or later is required to install $app_name. +Upgrade PowerShell: + + https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell + +"@ + } + + # show notification to change execution policy: + $allowedExecutionPolicy = @('Unrestricted', 'RemoteSigned', 'Bypass') + If ((Get-ExecutionPolicy).ToString() -notin $allowedExecutionPolicy) { + throw @" +Error: PowerShell requires an execution policy in [$($allowedExecutionPolicy -join ", ")] to run $app_name. For example, to set the execution policy to 'RemoteSigned' please run: + + Set-ExecutionPolicy RemoteSigned -scope CurrentUser + +"@ + } + + # GitHub requires TLS 1.2 + If ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') { + throw @" +Error: Installing $app_name requires at least .NET Framework 4.5 +Please download and install it first: + + https://www.microsoft.com/net/download + +"@ + } +} + +function New-Temp-Dir() { + [CmdletBinding(SupportsShouldProcess)] + param() + $parent = [System.IO.Path]::GetTempPath() + [string] $name = [System.Guid]::NewGuid() + New-Item -ItemType Directory -Path (Join-Path $parent $name) +} + +# PSScriptAnalyzer doesn't like how we use our params as globals, this calms it +$Null = $ArtifactDownloadUrl, $NoModifyPath, $Help +# Make Write-Information statements be visible +$InformationPreference = "Continue" + +# The default interactive handler +try { + Install-Binary "$Args" +} catch { + Write-Information $_ + exit 1 +} + +================ axolotlsay-npm-package.tar.gz/package/.gitignore ================ +/node_modules + + +================ axolotlsay-npm-package.tar.gz/package/CHANGELOG.md ================ +# Version 0.2.2 + +```text + +----------------------------------+ + | now with arm64 linux binaries!!! | + +----------------------------------+ + / +≽(ā—• į“— ā—•)≼ +``` + +# Version 0.2.1 + +```text + +--------------------------------------+ + | now with linux static musl binary!!! | + +--------------------------------------+ + / +≽(ā—• į“— ā—•)≼ +``` + +# Version 0.2.0 + +```text + +-----------------------------------------+ + | now with homebrew and msi installers!!! | + +-----------------------------------------+ + / +≽(ā—• į“— ā—•)≼ +``` + +# Version 0.1.0 + +```text + +------------------------+ + | the initial release!!! | + +------------------------+ + / +≽(ā—• į“— ā—•)≼ +``` + +================ axolotlsay-npm-package.tar.gz/package/LICENSE-APACHE ================ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2022-2024 Axo Developer Co. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +================ axolotlsay-npm-package.tar.gz/package/LICENSE-MIT ================ +Copyright (c) 2022-2024 Axo Developer Co. + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +================ axolotlsay-npm-package.tar.gz/package/README.md ================ +# axolotlsay +> šŸ’¬ a CLI for learning to distribute CLIs in rust + + +## Usage + +```sh +> axolotlsay "hello world" + + +-------------+ + | hello world | + +-------------+ + / +≽(ā—• į“— ā—•)≼ +``` + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or [opensource.org/licenses/MIT](https://opensource.org/licenses/MIT)) + +at your option. + +================ axolotlsay-npm-package.tar.gz/package/binary-install.js ================ +const { createWriteStream, existsSync, mkdirSync, mkdtemp } = require("fs"); +const { join, sep } = require("path"); +const { spawnSync } = require("child_process"); +const { tmpdir } = require("os"); + +const axios = require("axios"); +const rimraf = require("rimraf"); +const tmpDir = tmpdir(); + +const error = (msg) => { + console.error(msg); + process.exit(1); +}; + +class Package { + constructor(platform, name, url, filename, zipExt, binaries) { + let errors = []; + if (typeof url !== "string") { + errors.push("url must be a string"); + } else { + try { + new URL(url); + } catch (e) { + errors.push(e); + } + } + if (name && typeof name !== "string") { + errors.push("package name must be a string"); + } + if (!name) { + errors.push("You must specify the name of your package"); + } + if (binaries && typeof binaries !== "object") { + errors.push("binaries must be a string => string map"); + } + if (!binaries) { + errors.push("You must specify the binaries in the package"); + } + + if (errors.length > 0) { + let errorMsg = + "One or more of the parameters you passed to the Binary constructor are invalid:\n"; + errors.forEach((error) => { + errorMsg += error; + }); + errorMsg += + '\n\nCorrect usage: new Package("my-binary", "https://example.com/binary/download.tar.gz", {"my-binary": "my-binary"})'; + error(errorMsg); + } + + this.platform = platform; + this.url = url; + this.name = name; + this.filename = filename; + this.zipExt = zipExt; + this.installDirectory = join(__dirname, "node_modules", ".bin_real"); + this.binaries = binaries; + + if (!existsSync(this.installDirectory)) { + mkdirSync(this.installDirectory, { recursive: true }); + } + } + + exists() { + for (const binaryName in this.binaries) { + const binRelPath = this.binaries[binaryName]; + const binPath = join(this.installDirectory, binRelPath); + if (!existsSync(binPath)) { + return false; + } + } + return true; + } + + install(fetchOptions, suppressLogs = false) { + if (this.exists()) { + if (!suppressLogs) { + console.error( + `${this.name} is already installed, skipping installation.`, + ); + } + return Promise.resolve(); + } + + if (existsSync(this.installDirectory)) { + rimraf.sync(this.installDirectory); + } + + mkdirSync(this.installDirectory, { recursive: true }); + + if (!suppressLogs) { + console.error(`Downloading release from ${this.url}`); + } + + return axios({ ...fetchOptions, url: this.url, responseType: "stream" }) + .then((res) => { + return new Promise((resolve, reject) => { + mkdtemp(`${tmpDir}${sep}`, (err, directory) => { + let tempFile = join(directory, this.filename); + const sink = res.data.pipe(createWriteStream(tempFile)); + sink.on("error", (err) => reject(err)); + sink.on("close", () => { + if (/\.tar\.*/.test(this.zipExt)) { + const result = spawnSync("tar", [ + "xf", + tempFile, + // The tarballs are stored with a leading directory + // component; we strip one component in the + // shell installers too. + "--strip-components", + "1", + "-C", + this.installDirectory, + ]); + if (result.status == 0) { + resolve(); + } else if (result.error) { + reject(result.error); + } else { + reject( + new Error( + `An error occurred untarring the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`, + ), + ); + } + } else if (this.zipExt == ".zip") { + let result; + if (this.platform.artifactName.includes("windows")) { + // Windows does not have "unzip" by default on many installations, instead + // we use Expand-Archive from powershell + result = spawnSync("powershell.exe", [ + "-NoProfile", + "-NonInteractive", + "-Command", + `& { + param([string]$LiteralPath, [string]$DestinationPath) + Expand-Archive -LiteralPath $LiteralPath -DestinationPath $DestinationPath -Force + }`, + tempFile, + this.installDirectory, + ]); + } else { + result = spawnSync("unzip", [ + "-q", + tempFile, + "-d", + this.installDirectory, + ]); + } + + if (result.status == 0) { + resolve(); + } else if (result.error) { + reject(result.error); + } else { + reject( + new Error( + `An error occurred unzipping the artifact: stdout: ${result.stdout}; stderr: ${result.stderr}`, + ), + ); + } + } else { + reject( + new Error(`Unrecognized file extension: ${this.zipExt}`), + ); + } + }); + }); + }); + }) + .then(() => { + if (!suppressLogs) { + console.error(`${this.name} has been installed!`); + } + }) + .catch((e) => { + error(`Error fetching release: ${e.message}`); + }); + } + + run(binaryName, fetchOptions) { + const promise = !this.exists() + ? this.install(fetchOptions, true) + : Promise.resolve(); + + promise + .then(() => { + const [, , ...args] = process.argv; + + const options = { cwd: process.cwd(), stdio: "inherit" }; + + const binRelPath = this.binaries[binaryName]; + if (!binRelPath) { + error(`${binaryName} is not a known binary in ${this.name}`); + } + const binPath = join(this.installDirectory, binRelPath); + const result = spawnSync(binPath, args, options); + + if (result.error) { + error(result.error); + } + + process.exit(result.status); + }) + .catch((e) => { + error(e.message); + process.exit(1); + }); + } +} + +module.exports.Package = Package; + +================ axolotlsay-npm-package.tar.gz/package/binary.js ================ +const { Package } = require("./binary-install"); +const os = require("os"); +const cTable = require("console.table"); +const libc = require("detect-libc"); +const { configureProxy } = require("axios-proxy-builder"); + +const error = (msg) => { + console.error(msg); + process.exit(1); +}; + +const { + name, + artifactDownloadUrl, + supportedPlatforms, + glibcMinimum, +} = require("./package.json"); + +const builderGlibcMajorVersion = glibcMinimum.major; +const builderGlibcMInorVersion = glibcMinimum.series; + +const getPlatform = () => { + const rawOsType = os.type(); + const rawArchitecture = os.arch(); + + // We want to use rust-style target triples as the canonical key + // for a platform, so translate the "os" library's concepts into rust ones + let osType = ""; + switch (rawOsType) { + case "Windows_NT": + osType = "pc-windows-msvc"; + break; + case "Darwin": + osType = "apple-darwin"; + break; + case "Linux": + osType = "unknown-linux-gnu"; + break; + } + + let arch = ""; + switch (rawArchitecture) { + case "x64": + arch = "x86_64"; + break; + case "arm64": + arch = "aarch64"; + break; + } + + if (rawOsType === "Linux") { + if (libc.familySync() == "musl") { + osType = "unknown-linux-musl-dynamic"; + } else if (libc.isNonGlibcLinuxSync()) { + console.warn( + "Your libc is neither glibc nor musl; trying static musl binary instead", + ); + osType = "unknown-linux-musl-static"; + } else { + let libcVersion = libc.versionSync(); + let splitLibcVersion = libcVersion.split("."); + let libcMajorVersion = splitLibcVersion[0]; + let libcMinorVersion = splitLibcVersion[1]; + if ( + libcMajorVersion != builderGlibcMajorVersion || + libcMinorVersion < builderGlibcMInorVersion + ) { + // We can't run the glibc binaries, but we can run the static musl ones + // if they exist + console.warn( + "Your glibc isn't compatible; trying static musl binary instead", + ); + osType = "unknown-linux-musl-static"; + } + } + } + + // Assume the above succeeded and build a target triple to look things up with. + // If any of it failed, this lookup will fail and we'll handle it like normal. + let targetTriple = `${arch}-${osType}`; + let platform = supportedPlatforms[targetTriple]; + + if (!platform) { + error( + `Platform with type "${rawOsType}" and architecture "${rawArchitecture}" is not supported by ${name}.\nYour system must be one of the following:\n\n${Object.keys( + supportedPlatforms, + ).join(",")}`, + ); + } + + return platform; +}; + +const getPackage = () => { + const platform = getPlatform(); + const url = `${artifactDownloadUrl}/${platform.artifactName}`; + let filename = platform.artifactName; + let ext = platform.zipExt; + let binary = new Package(platform, name, url, filename, ext, platform.bins); + + return binary; +}; + +const install = (suppressLogs) => { + if (!artifactDownloadUrl || artifactDownloadUrl.length === 0) { + console.warn("in demo mode, not installing binaries"); + return; + } + const package = getPackage(); + const proxy = configureProxy(package.url); + + return package.install(proxy, suppressLogs); +}; + +const run = (binaryName) => { + const package = getPackage(); + const proxy = configureProxy(package.url); + + package.run(binaryName, proxy); +}; + +module.exports = { + install, + run, + getPackage, +}; + +================ axolotlsay-npm-package.tar.gz/package/install.js ================ +#!/usr/bin/env node + +const { install } = require("./binary"); +install(false); + +================ axolotlsay-npm-package.tar.gz/package/npm-shrinkwrap.json ================ +{ + "lockfileVersion": 3, + "name": "@axodotdev/axolotlsay", + "packages": { + "": { + "bin": { + "axolotlsay": "run-axolotlsay.js" + }, + "dependencies": { + "axios": "^1.11.0", + "axios-proxy-builder": "^0.1.2", + "console.table": "^0.10.0", + "detect-libc": "^2.0.4", + "rimraf": "^6.0.1" + }, + "devDependencies": { + "prettier": "^3.6.2" + }, + "engines": { + "node": ">=14", + "npm": ">=6" + }, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "name": "@axodotdev/axolotlsay", + "version": "0.2.2" + }, + "node_modules/@isaacs/balanced-match": { + "engines": { + "node": "20 || >=22" + }, + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "version": "4.0.1" + }, + "node_modules/@isaacs/brace-expansion": { + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "version": "5.0.0" + }, + "node_modules/@isaacs/cliui": { + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + }, + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "version": "8.0.2" + }, + "node_modules/ansi-regex": { + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + }, + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "version": "6.1.0" + }, + "node_modules/ansi-styles": { + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + }, + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "version": "6.2.1" + }, + "node_modules/asynckit": { + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "version": "0.4.0" + }, + "node_modules/axios": { + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + }, + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "version": "1.11.0" + }, + "node_modules/axios-proxy-builder": { + "dependencies": { + "tunnel": "^0.0.6" + }, + "integrity": "sha512-6uBVsBZzkB3tCC8iyx59mCjQckhB8+GQrI9Cop8eC7ybIsvs/KtnNgEBfRMSEa7GqK2VBGUzgjNYMdPIfotyPA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/axios-proxy-builder/-/axios-proxy-builder-0.1.2.tgz", + "version": "0.1.2" + }, + "node_modules/call-bind-apply-helpers": { + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "version": "1.0.2" + }, + "node_modules/clone": { + "engines": { + "node": ">=0.8" + }, + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "version": "1.0.4" + }, + "node_modules/color-convert": { + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + }, + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "version": "2.0.1" + }, + "node_modules/color-name": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "version": "1.1.4" + }, + "node_modules/combined-stream": { + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "version": "1.0.8" + }, + "node_modules/console.table": { + "dependencies": { + "easy-table": "1.1.0" + }, + "engines": { + "node": "> 0.10" + }, + "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", + "version": "0.10.0" + }, + "node_modules/cross-spawn": { + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + }, + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "version": "7.0.6" + }, + "node_modules/defaults": { + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "version": "1.0.4" + }, + "node_modules/delayed-stream": { + "engines": { + "node": ">=0.4.0" + }, + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "version": "1.0.0" + }, + "node_modules/detect-libc": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "version": "2.0.4" + }, + "node_modules/dunder-proto": { + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "version": "1.0.1" + }, + "node_modules/eastasianwidth": { + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "version": "0.2.0" + }, + "node_modules/easy-table": { + "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==", + "license": "MIT", + "optionalDependencies": { + "wcwidth": ">=1.0.1" + }, + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/emoji-regex": { + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "version": "9.2.2" + }, + "node_modules/es-define-property": { + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "version": "1.0.1" + }, + "node_modules/es-errors": { + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "version": "1.3.0" + }, + "node_modules/es-object-atoms": { + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "version": "1.1.1" + }, + "node_modules/es-set-tostringtag": { + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "version": "2.1.0" + }, + "node_modules/follow-redirects": { + "engines": { + "node": ">=4.0" + }, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "license": "MIT", + "peerDependenciesMeta": { + "debug": { + "optional": true + } + }, + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "version": "1.15.6" + }, + "node_modules/foreground-child": { + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "version": "3.3.1" + }, + "node_modules/form-data": { + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + }, + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "version": "4.0.4" + }, + "node_modules/function-bind": { + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "version": "1.1.2" + }, + "node_modules/get-intrinsic": { + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "version": "1.3.0" + }, + "node_modules/get-proto": { + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "version": "1.0.1" + }, + "node_modules/glob": { + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "version": "11.0.3" + }, + "node_modules/gopd": { + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "version": "1.2.0" + }, + "node_modules/has-symbols": { + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/has-tostringtag": { + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "version": "1.0.2" + }, + "node_modules/hasown": { + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "version": "2.0.2" + }, + "node_modules/is-fullwidth-code-point": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "version": "3.0.0" + }, + "node_modules/isexe": { + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "version": "2.0.0" + }, + "node_modules/jackspeak": { + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "license": "BlueOak-1.0.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "version": "4.1.1" + }, + "node_modules/lru-cache": { + "engines": { + "node": "20 || >=22" + }, + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "version": "11.1.0" + }, + "node_modules/math-intrinsics": { + "engines": { + "node": ">= 0.4" + }, + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/mime-db": { + "engines": { + "node": ">= 0.6" + }, + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "version": "1.52.0" + }, + "node_modules/mime-types": { + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + }, + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "version": "2.1.35" + }, + "node_modules/minimatch": { + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "version": "10.0.3" + }, + "node_modules/minipass": { + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "version": "7.1.2" + }, + "node_modules/package-json-from-dist": { + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "version": "1.0.1" + }, + "node_modules/path-key": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "version": "3.1.1" + }, + "node_modules/path-scurry": { + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "version": "2.0.0" + }, + "node_modules/prettier": { + "bin": { + "prettier": "bin/prettier.cjs" + }, + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + }, + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "version": "3.6.2" + }, + "node_modules/proxy-from-env": { + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "version": "1.1.0" + }, + "node_modules/rimraf": { + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "version": "6.0.1" + }, + "node_modules/shebang-command": { + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "version": "2.0.0" + }, + "node_modules/shebang-regex": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "version": "3.0.0" + }, + "node_modules/signal-exit": { + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "version": "4.1.0" + }, + "node_modules/string-width": { + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "version": "5.1.2" + }, + "node_modules/string-width-cjs": { + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "name": "string-width", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "version": "4.2.3" + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "version": "5.0.1" + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "version": "8.0.0" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "version": "6.0.1" + }, + "node_modules/strip-ansi": { + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + }, + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "version": "7.1.0" + }, + "node_modules/strip-ansi-cjs": { + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "name": "strip-ansi", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "version": "6.0.1" + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "version": "5.0.1" + }, + "node_modules/tunnel": { + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + }, + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "version": "0.0.6" + }, + "node_modules/wcwidth": { + "dependencies": { + "defaults": "^1.0.3" + }, + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "license": "MIT", + "optional": true, + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "version": "1.0.1" + }, + "node_modules/which": { + "bin": { + "node-which": "bin/node-which" + }, + "dependencies": { + "isexe": "^2.0.0" + }, + "engines": { + "node": ">= 8" + }, + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "version": "2.0.2" + }, + "node_modules/wrap-ansi": { + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + }, + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "version": "8.1.0" + }, + "node_modules/wrap-ansi-cjs": { + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + }, + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "name": "wrap-ansi", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "version": "7.0.0" + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "engines": { + "node": ">=8" + }, + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "version": "5.0.1" + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + }, + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "version": "4.3.0" + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "version": "8.0.0" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "version": "4.2.3" + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + }, + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "version": "6.0.1" + } + }, + "requires": true, + "version": "0.2.2" +} +================ axolotlsay-npm-package.tar.gz/package/package.json ================ +{ + "artifactDownloadUrl": "https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2", + "author": "axodotdev ", + "bin": { + "axolotlsay": "run-axolotlsay.js" + }, + "dependencies": { + "axios": "^1.11.0", + "axios-proxy-builder": "^0.1.2", + "console.table": "^0.10.0", + "detect-libc": "^2.0.4", + "rimraf": "^6.0.1" + }, + "description": "šŸ’¬ a CLI for learning to distribute CLIs in rust", + "devDependencies": { + "prettier": "^3.6.2" + }, + "engines": { + "node": ">=14", + "npm": ">=6" + }, + "glibcMinimum": { + "major": 2, + "series": 31 + }, + "homepage": "https://github.com/axodotdev/axolotlsay", + "license": "MIT OR Apache-2.0", + "name": "@axodotdev/axolotlsay", + "preferUnplugged": true, + "repository": "https://github.com/axodotdev/axolotlsay.git", + "scripts": { + "fmt": "prettier --write **/*.js", + "fmt:check": "prettier --check **/*.js", + "postinstall": "node ./install.js" + }, + "supportedPlatforms": { + "aarch64-apple-darwin": { + "artifactName": "axolotlsay-aarch64-apple-darwin.tar.gz", + "bins": { + "axolotlsay": "axolotlsay" + }, + "zipExt": ".tar.gz" + }, + "aarch64-pc-windows-msvc": { + "artifactName": "axolotlsay-x86_64-pc-windows-msvc.tar.gz", + "bins": { + "axolotlsay": "axolotlsay.exe" + }, + "zipExt": ".tar.gz" + }, + "x86_64-apple-darwin": { + "artifactName": "axolotlsay-x86_64-apple-darwin.tar.gz", + "bins": { + "axolotlsay": "axolotlsay" + }, + "zipExt": ".tar.gz" + }, + "x86_64-pc-windows-gnu": { + "artifactName": "axolotlsay-x86_64-pc-windows-msvc.tar.gz", + "bins": { + "axolotlsay": "axolotlsay.exe" + }, + "zipExt": ".tar.gz" + }, + "x86_64-pc-windows-msvc": { + "artifactName": "axolotlsay-x86_64-pc-windows-msvc.tar.gz", + "bins": { + "axolotlsay": "axolotlsay.exe" + }, + "zipExt": ".tar.gz" + }, + "x86_64-unknown-linux-gnu": { + "artifactName": "axolotlsay-x86_64-unknown-linux-gnu.tar.gz", + "bins": { + "axolotlsay": "axolotlsay" + }, + "zipExt": ".tar.gz" + } + }, + "version": "0.2.2", + "volta": { + "node": "18.14.1", + "npm": "9.5.0" + } +} +================ axolotlsay-npm-package.tar.gz/package/run-axolotlsay.js ================ +#!/usr/bin/env node + +const { run } = require("./binary"); +run("axolotlsay"); + +================ sha256.sum ================ +CENSORED (see https://github.com/axodotdev/cargo-dist/issues/1477) axolotlsay-npm-package.tar.gz +CENSORED (see https://github.com/axodotdev/cargo-dist/issues/1477) source.tar.gz + + +================ dist-manifest.json ================ +{ + "dist_version": "CENSORED", + "announcement_tag": "v0.2.2", + "announcement_tag_is_implicit": true, + "announcement_is_prerelease": false, + "announcement_title": "Version 0.2.2", + "announcement_changelog": "```text\n +----------------------------------+\n | now with arm64 linux binaries!!! |\n +----------------------------------+\n /\n≽(ā—• į“— ā—•)≼\n```", + "announcement_github_body": "## Release Notes\n\n```text\n +----------------------------------+\n | now with arm64 linux binaries!!! |\n +----------------------------------+\n /\n≽(ā—• į“— ā—•)≼\n```\n\n## Install axolotlsay 0.2.2\n\n### Install prebuilt binaries via shell script\n\n```sh\ncurl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-installer.sh | sh\n```\n\n### Install prebuilt binaries via powershell script\n\n```sh\npowershell -ExecutionPolicy Bypass -c \"irm https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-installer.ps1 | iex\"\n```\n\n### Install prebuilt binaries via Homebrew\n\n```sh\nbrew install axodotdev/packages/axolotlsay\n```\n\n### Install prebuilt binaries into your npm project\n\n```sh\nnpm install @axodotdev/axolotlsay@0.2.2\n```\n\n## Download axolotlsay 0.2.2\n\n| File | Platform | Checksum |\n|--------|----------|----------|\n| [axolotlsay-aarch64-apple-darwin.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-aarch64-apple-darwin.tar.gz.sha256) |\n| [axolotlsay-aarch64-apple-darwin.pkg](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-aarch64-apple-darwin.pkg) | Apple Silicon macOS | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-aarch64-apple-darwin.pkg.sha256) |\n| [axolotlsay-x86_64-apple-darwin.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-apple-darwin.tar.gz.sha256) |\n| [axolotlsay-x86_64-apple-darwin.pkg](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-apple-darwin.pkg) | Intel macOS | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-apple-darwin.pkg.sha256) |\n| [axolotlsay-x86_64-pc-windows-msvc.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-pc-windows-msvc.tar.gz) | x64 Windows | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256) |\n| [axolotlsay-x86_64-pc-windows-msvc.msi](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-pc-windows-msvc.msi) | x64 Windows | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-pc-windows-msvc.msi.sha256) |\n| [axolotlsay-x86_64-unknown-linux-gnu.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256) |\n\n", + "releases": [ + { + "app_name": "axolotlsay", + "app_version": "0.2.2", + "env": { + "install_dir_env_var": "AXOLOTLSAY_INSTALL_DIR", + "unmanaged_dir_env_var": "AXOLOTLSAY_UNMANAGED_INSTALL", + "disable_update_env_var": "AXOLOTLSAY_DISABLE_UPDATE", + "no_modify_path_env_var": "AXOLOTLSAY_NO_MODIFY_PATH", + "print_quiet_env_var": "AXOLOTLSAY_PRINT_QUIET", + "print_verbose_env_var": "AXOLOTLSAY_PRINT_VERBOSE", + "download_url_env_var": "AXOLOTLSAY_DOWNLOAD_URL", + "github_base_url_env_var": "AXOLOTLSAY_INSTALLER_GITHUB_BASE_URL", + "ghe_base_url_env_var": "AXOLOTLSAY_INSTALLER_GHE_BASE_URL", + "github_token_env_var": "AXOLOTLSAY_GITHUB_TOKEN" + }, + "display_name": "axolotlsay", + "display": true, + "artifacts": [ + "source.tar.gz", + "source.tar.gz.sha256", + "axolotlsay-installer.sh", + "axolotlsay-installer.ps1", + "axolotlsay.rb", + "axolotlsay-npm-package.tar.gz", + "sha256.sum", + "axolotlsay-aarch64-apple-darwin.tar.gz", + "axolotlsay-aarch64-apple-darwin.tar.gz.sha256", + "axolotlsay-aarch64-apple-darwin.pkg", + "axolotlsay-aarch64-apple-darwin.pkg.sha256", + "axolotlsay-x86_64-apple-darwin.tar.gz", + "axolotlsay-x86_64-apple-darwin.tar.gz.sha256", + "axolotlsay-x86_64-apple-darwin.pkg", + "axolotlsay-x86_64-apple-darwin.pkg.sha256", + "axolotlsay-x86_64-pc-windows-msvc.tar.gz", + "axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256", + "axolotlsay-x86_64-pc-windows-msvc.msi", + "axolotlsay-x86_64-pc-windows-msvc.msi.sha256", + "axolotlsay-x86_64-unknown-linux-gnu.tar.gz", + "axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256" + ], + "hosting": { + "github": { + "artifact_base_url": "https://github.com", + "artifact_download_path": "/axodotdev/axolotlsay/releases/download/v0.2.2", + "owner": "axodotdev", + "repo": "axolotlsay" + } + } + } + ], + "artifacts": { + "axolotlsay-aarch64-apple-darwin.pkg": { + "name": "axolotlsay-aarch64-apple-darwin.pkg", + "kind": "installer", + "target_triples": [ + "aarch64-apple-darwin" + ], + "assets": [ + { + "id": "axolotlsay-aarch64-apple-darwin-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay", + "kind": "executable" + } + ], + "description": "install via pkg", + "checksum": "axolotlsay-aarch64-apple-darwin.pkg.sha256" + }, + "axolotlsay-aarch64-apple-darwin.pkg.sha256": { + "name": "axolotlsay-aarch64-apple-darwin.pkg.sha256", + "kind": "checksum", + "target_triples": [ + "aarch64-apple-darwin" + ] + }, + "axolotlsay-aarch64-apple-darwin.tar.gz": { + "name": "axolotlsay-aarch64-apple-darwin.tar.gz", + "kind": "executable-zip", + "target_triples": [ + "aarch64-apple-darwin" + ], + "assets": [ + { + "name": "CHANGELOG.md", + "path": "CHANGELOG.md", + "kind": "changelog" + }, + { + "name": "LICENSE-APACHE", + "path": "LICENSE-APACHE", + "kind": "license" + }, + { + "name": "LICENSE-MIT", + "path": "LICENSE-MIT", + "kind": "license" + }, + { + "name": "README.md", + "path": "README.md", + "kind": "readme" + }, + { + "id": "axolotlsay-aarch64-apple-darwin-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay", + "kind": "executable" + } + ], + "checksum": "axolotlsay-aarch64-apple-darwin.tar.gz.sha256" + }, + "axolotlsay-aarch64-apple-darwin.tar.gz.sha256": { + "name": "axolotlsay-aarch64-apple-darwin.tar.gz.sha256", + "kind": "checksum", + "target_triples": [ + "aarch64-apple-darwin" + ] + }, + "axolotlsay-installer.ps1": { + "name": "axolotlsay-installer.ps1", + "kind": "installer", + "target_triples": [ + "aarch64-pc-windows-msvc", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc" + ], + "install_hint": "powershell -ExecutionPolicy Bypass -c \"irm https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-installer.ps1 | iex\"", + "description": "Install prebuilt binaries via powershell script" + }, + "axolotlsay-installer.sh": { + "name": "axolotlsay-installer.sh", + "kind": "installer", + "target_triples": [ + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-unknown-linux-gnu" + ], + "install_hint": "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/axolotlsay/releases/download/v0.2.2/axolotlsay-installer.sh | sh", + "description": "Install prebuilt binaries via shell script" + }, + "axolotlsay-npm-package.tar.gz": { + "name": "axolotlsay-npm-package.tar.gz", + "kind": "installer", + "target_triples": [ + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ], + "assets": [ + { + "name": ".gitignore", + "path": ".gitignore", + "kind": "unknown" + }, + { + "name": "CHANGELOG.md", + "path": "CHANGELOG.md", + "kind": "changelog" + }, + { + "name": "LICENSE-APACHE", + "path": "LICENSE-APACHE", + "kind": "license" + }, + { + "name": "LICENSE-MIT", + "path": "LICENSE-MIT", + "kind": "license" + }, + { + "name": "README.md", + "path": "README.md", + "kind": "readme" + }, + { + "name": "binary-install.js", + "path": "binary-install.js", + "kind": "unknown" + }, + { + "name": "binary.js", + "path": "binary.js", + "kind": "unknown" + }, + { + "name": "install.js", + "path": "install.js", + "kind": "unknown" + }, + { + "name": "npm-shrinkwrap.json", + "path": "npm-shrinkwrap.json", + "kind": "unknown" + }, + { + "name": "package.json", + "path": "package.json", + "kind": "unknown" + }, + { + "name": "run.js", + "path": "run.js", + "kind": "unknown" + } + ], + "install_hint": "npm install @axodotdev/axolotlsay@0.2.2", + "description": "Install prebuilt binaries into your npm project" + }, + "axolotlsay-x86_64-apple-darwin.pkg": { + "name": "axolotlsay-x86_64-apple-darwin.pkg", + "kind": "installer", + "target_triples": [ + "x86_64-apple-darwin" + ], + "assets": [ + { + "id": "axolotlsay-x86_64-apple-darwin-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay", + "kind": "executable" + } + ], + "description": "install via pkg", + "checksum": "axolotlsay-x86_64-apple-darwin.pkg.sha256" + }, + "axolotlsay-x86_64-apple-darwin.pkg.sha256": { + "name": "axolotlsay-x86_64-apple-darwin.pkg.sha256", + "kind": "checksum", + "target_triples": [ + "x86_64-apple-darwin" + ] + }, + "axolotlsay-x86_64-apple-darwin.tar.gz": { + "name": "axolotlsay-x86_64-apple-darwin.tar.gz", + "kind": "executable-zip", + "target_triples": [ + "x86_64-apple-darwin" + ], + "assets": [ + { + "name": "CHANGELOG.md", + "path": "CHANGELOG.md", + "kind": "changelog" + }, + { + "name": "LICENSE-APACHE", + "path": "LICENSE-APACHE", + "kind": "license" + }, + { + "name": "LICENSE-MIT", + "path": "LICENSE-MIT", + "kind": "license" + }, + { + "name": "README.md", + "path": "README.md", + "kind": "readme" + }, + { + "id": "axolotlsay-x86_64-apple-darwin-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay", + "kind": "executable" + } + ], + "checksum": "axolotlsay-x86_64-apple-darwin.tar.gz.sha256" + }, + "axolotlsay-x86_64-apple-darwin.tar.gz.sha256": { + "name": "axolotlsay-x86_64-apple-darwin.tar.gz.sha256", + "kind": "checksum", + "target_triples": [ + "x86_64-apple-darwin" + ] + }, + "axolotlsay-x86_64-pc-windows-msvc.msi": { + "name": "axolotlsay-x86_64-pc-windows-msvc.msi", + "kind": "installer", + "target_triples": [ + "x86_64-pc-windows-msvc" + ], + "assets": [ + { + "id": "axolotlsay-x86_64-pc-windows-msvc-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay.exe", + "kind": "executable" + } + ], + "description": "install via msi", + "checksum": "axolotlsay-x86_64-pc-windows-msvc.msi.sha256" + }, + "axolotlsay-x86_64-pc-windows-msvc.msi.sha256": { + "name": "axolotlsay-x86_64-pc-windows-msvc.msi.sha256", + "kind": "checksum", + "target_triples": [ + "x86_64-pc-windows-msvc" + ] + }, + "axolotlsay-x86_64-pc-windows-msvc.tar.gz": { + "name": "axolotlsay-x86_64-pc-windows-msvc.tar.gz", + "kind": "executable-zip", + "target_triples": [ + "x86_64-pc-windows-msvc" + ], + "assets": [ + { + "name": "CHANGELOG.md", + "path": "CHANGELOG.md", + "kind": "changelog" + }, + { + "name": "LICENSE-APACHE", + "path": "LICENSE-APACHE", + "kind": "license" + }, + { + "name": "LICENSE-MIT", + "path": "LICENSE-MIT", + "kind": "license" + }, + { + "name": "README.md", + "path": "README.md", + "kind": "readme" + }, + { + "id": "axolotlsay-x86_64-pc-windows-msvc-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay.exe", + "kind": "executable" + } + ], + "checksum": "axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256" + }, + "axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256": { + "name": "axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256", + "kind": "checksum", + "target_triples": [ + "x86_64-pc-windows-msvc" + ] + }, + "axolotlsay-x86_64-unknown-linux-gnu.tar.gz": { + "name": "axolotlsay-x86_64-unknown-linux-gnu.tar.gz", + "kind": "executable-zip", + "target_triples": [ + "x86_64-unknown-linux-gnu" + ], + "assets": [ + { + "name": "CHANGELOG.md", + "path": "CHANGELOG.md", + "kind": "changelog" + }, + { + "name": "LICENSE-APACHE", + "path": "LICENSE-APACHE", + "kind": "license" + }, + { + "name": "LICENSE-MIT", + "path": "LICENSE-MIT", + "kind": "license" + }, + { + "name": "README.md", + "path": "README.md", + "kind": "readme" + }, + { + "id": "axolotlsay-x86_64-unknown-linux-gnu-exe-axolotlsay", + "name": "axolotlsay", + "path": "axolotlsay", + "kind": "executable" + } + ], + "checksum": "axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256" + }, + "axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256": { + "name": "axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256", + "kind": "checksum", + "target_triples": [ + "x86_64-unknown-linux-gnu" + ] + }, + "axolotlsay.rb": { + "name": "axolotlsay.rb", + "kind": "installer", + "target_triples": [ + "aarch64-apple-darwin", + "x86_64-apple-darwin", + "x86_64-pc-windows-gnu", + "x86_64-unknown-linux-gnu" + ], + "install_hint": "brew install axodotdev/packages/axolotlsay", + "description": "Install prebuilt binaries via Homebrew" + }, + "sha256.sum": { + "name": "sha256.sum", + "kind": "unified-checksum" + }, + "source.tar.gz": { + "name": "source.tar.gz", + "kind": "source-tarball", + "checksum": "source.tar.gz.sha256" + }, + "source.tar.gz.sha256": { + "name": "source.tar.gz.sha256", + "kind": "checksum" + } + }, + "systems": { + "plan:all:": { + "id": "plan:all:", + "cargo_version_line": "CENSORED" + "build_environment": "indeterminate" + } + }, + "publish_prereleases": false, + "force_latest": false, + "ci": { + "github": { + "artifacts_matrix": { + "include": [ + { + "runner": "macos-13", + "host": "x86_64-apple-darwin", + "install_dist": { + "shell": "sh", + "run": "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh" + }, + "dist_args": "--artifacts=local --target=aarch64-apple-darwin", + "targets": [ + "aarch64-apple-darwin" + ], + "cache_provider": "github" + }, + { + "runner": "macos-13", + "host": "x86_64-apple-darwin", + "install_dist": { + "shell": "sh", + "run": "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh" + }, + "dist_args": "--artifacts=local --target=x86_64-apple-darwin", + "targets": [ + "x86_64-apple-darwin" + ], + "cache_provider": "github" + }, + { + "runner": "windows-2022", + "host": "x86_64-pc-windows-msvc", + "install_dist": { + "shell": "pwsh", + "run": "irm https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.ps1 | iex" + }, + "dist_args": "--artifacts=local --target=x86_64-pc-windows-msvc", + "targets": [ + "x86_64-pc-windows-msvc" + ], + "cache_provider": "github" + }, + { + "runner": "ubuntu-22.04", + "host": "x86_64-unknown-linux-gnu", + "install_dist": { + "shell": "sh", + "run": "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh" + }, + "dist_args": "--artifacts=local --target=x86_64-unknown-linux-gnu", + "targets": [ + "x86_64-unknown-linux-gnu" + ], + "cache_provider": "github" + } + ] + }, + "pr_run_mode": "plan" + } + }, + "linkage": [], + "upload_files": [] +} + +================ release.yml ================ +# This file was autogenerated by dist: https://axodotdev.github.io/cargo-dist +# +# Copyright 2022-2024, axodotdev +# SPDX-License-Identifier: MIT or Apache-2.0 +# +# CI that: +# +# * checks for a Git Tag that looks like a release +# * builds artifacts with dist (archives, installers, hashes) +# * uploads those artifacts to temporary workflow zip +# * on success, uploads the artifacts to a GitHub Release +# +# Note that the GitHub Release will be created with a generated +# title/body based on your changelogs. + +name: Release +permissions: + "contents": "write" + +# This task will run whenever you push a git tag that looks like a version +# like "1.0.0", "v0.1.0-prerelease.1", "my-app/0.1.0", "releases/v1.0.0", etc. +# Various formats will be parsed into a VERSION and an optional PACKAGE_NAME, where +# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION +# must be a Cargo-style SemVer Version (must have at least major.minor.patch). +# +# If PACKAGE_NAME is specified, then the announcement will be for that +# package (erroring out if it doesn't have the given version or isn't dist-able). +# +# If PACKAGE_NAME isn't specified, then the announcement will be for all +# (dist-able) packages in the workspace with that version (this mode is +# intended for workspaces with only one dist-able package, or with all dist-able +# packages versioned/released in lockstep). +# +# If you push multiple tags at once, separate instances of this workflow will +# spin up, creating an independent announcement for each one. However, GitHub +# will hard limit this to 3 tags per commit, as it will assume more tags is a +# mistake. +# +# If there's a prerelease-style suffix to the version, then the release(s) +# will be marked as a prerelease. +on: + pull_request: + push: + tags: + - '**[0-9]+.[0-9]+.[0-9]+*' + +jobs: + # Run 'dist plan' (or host) to determine what tasks we need to do + plan: + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.plan.outputs.manifest }} + tag: ${{ !github.event.pull_request && github.ref_name || '' }} + tag-flag: ${{ !github.event.pull_request && format('--tag={0}', github.ref_name) || '' }} + publishing: ${{ !github.event.pull_request }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install dist + # we specify bash to get pipefail; it guards against the `curl` command + # failing. otherwise `sh` won't catch that `curl` returned non-0 + shell: bash + run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh" + - name: Cache dist + uses: actions/upload-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/dist + - name: "Some build step" + uses: "some-action-user/some-action" + with: + "input1": "input1" + "input2": "input2" + - name: "Some Other build step" + uses: "some-action-user/some-other-action" + env: + "ENV_VAR": "${{ github.head_ref }}" + - name: "Some Run Step simple" + if: false + run: "echo \"hello world!\"" + - name: "Some Run Step Multi" + run: | + HW="hello world" + echo $HW + shell: "bash" + # sure would be cool if github gave us proper conditionals... + # so here's a doubly-nested ternary-via-truthiness to try to provide the best possible + # functionality based on whether this is a pull_request, and whether it's from a fork. + # (PRs run on the *source* but secrets are usually on the *target* -- that's *good* + # but also really annoying to build CI around when it needs secrets to work right.) + - id: plan + run: | + dist ${{ (!github.event.pull_request && format('host --steps=create --tag={0}', github.ref_name)) || 'plan' }} --output-format=json > plan-dist-manifest.json + echo "dist ran successfully" + cat plan-dist-manifest.json + echo "manifest=$(jq -c "." plan-dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + name: artifacts-plan-dist-manifest + path: plan-dist-manifest.json + + # Build and packages all the platform-specific things + build-local-artifacts: + name: build-local-artifacts (${{ join(matrix.targets, ', ') }}) + # Let the initial task tell us to not run (currently very blunt) + needs: + - plan + if: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix.include != null && (needs.plan.outputs.publishing == 'true' || fromJson(needs.plan.outputs.val).ci.github.pr_run_mode == 'upload') }} + strategy: + fail-fast: false + # Target platforms/runners are computed by dist in create-release. + # Each member of the matrix has the following arguments: + # + # - runner: the github runner + # - dist-args: cli flags to pass to dist + # - install-dist: expression to run to install dist on the runner + # + # Typically there will be: + # - 1 "global" task that builds universal installers + # - N "local" tasks that build each platform's binaries and platform-specific installers + matrix: ${{ fromJson(needs.plan.outputs.val).ci.github.artifacts_matrix }} + runs-on: ${{ matrix.runner }} + container: ${{ matrix.container && matrix.container.image || null }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json + steps: + - name: enable windows longpaths + run: | + git config --global core.longpaths true + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install Rust non-interactively if not already installed + if: ${{ matrix.container }} + run: | + if ! command -v cargo > /dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + echo "$HOME/.cargo/bin" >> $GITHUB_PATH + fi + - name: "Some build step" + uses: "some-action-user/some-action" + with: + "input1": "input1" + "input2": "input2" + - name: "Some Other build step" + uses: "some-action-user/some-other-action" + env: + "ENV_VAR": "${{ github.head_ref }}" + - name: "Some Run Step simple" + if: false + run: "echo \"hello world!\"" + - name: "Some Run Step Multi" + run: | + HW="hello world" + echo $HW + shell: "bash" + - name: Install dist + run: ${{ matrix.install_dist.run }} + # Get the dist-manifest + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: Install dependencies + run: | + ${{ matrix.packages_install }} + - name: Build artifacts + run: | + # Actually do builds and make zips and whatnot + dist build ${{ needs.plan.outputs.tag-flag }} --print=linkage --output-format=json ${{ matrix.dist_args }} > dist-manifest.json + echo "dist ran successfully" + - id: cargo-dist + name: Post-build + # We force bash here just because github makes it really hard to get values up + # to "real" actions without writing to env-vars, and writing to env-vars has + # inconsistent syntax between shell and powershell. + shell: bash + run: | + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + dist print-upload-files-from-manifest --manifest dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-local-${{ join(matrix.targets, '_') }} + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + + # Build and package all the platform-agnostic(ish) things + build-global-artifacts: + needs: + - plan + - build-local-artifacts + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Get all the local artifacts for the global tasks to use (for e.g. checksums) + - name: Fetch local artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - id: cargo-dist + shell: bash + run: | + dist build ${{ needs.plan.outputs.tag-flag }} --output-format=json "--artifacts=global" > dist-manifest.json + echo "dist ran successfully" + + # Parse out what we just built and upload it to scratch storage + echo "paths<> "$GITHUB_OUTPUT" + jq --raw-output ".upload_files[]" dist-manifest.json >> "$GITHUB_OUTPUT" + echo "EOF" >> "$GITHUB_OUTPUT" + + cp dist-manifest.json "$BUILD_MANIFEST_NAME" + - name: "Upload artifacts" + uses: actions/upload-artifact@v4 + with: + name: artifacts-build-global + path: | + ${{ steps.cargo-dist.outputs.paths }} + ${{ env.BUILD_MANIFEST_NAME }} + # Determines if we should publish/announce + host: + needs: + - plan + - build-local-artifacts + - build-global-artifacts + # Only run if we're "publishing", and only if local and global didn't fail (skipped is fine) + if: ${{ always() && needs.plan.outputs.publishing == 'true' && (needs.build-global-artifacts.result == 'skipped' || needs.build-global-artifacts.result == 'success') && (needs.build-local-artifacts.result == 'skipped' || needs.build-local-artifacts.result == 'success') }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + runs-on: "ubuntu-22.04" + outputs: + val: ${{ steps.host.outputs.manifest }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + - name: Install cached dist + uses: actions/download-artifact@v4 + with: + name: cargo-dist-cache + path: ~/.cargo/bin/ + - run: chmod +x ~/.cargo/bin/dist + # Fetch artifacts from scratch-storage + - name: Fetch artifacts + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: target/distrib/ + merge-multiple: true + - name: "Some build step" + uses: "some-action-user/some-action" + with: + "input1": "input1" + "input2": "input2" + - name: "Some Other build step" + uses: "some-action-user/some-other-action" + env: + "ENV_VAR": "${{ github.head_ref }}" + - name: "Some Run Step simple" + if: false + run: "echo \"hello world!\"" + - name: "Some Run Step Multi" + run: | + HW="hello world" + echo $HW + shell: "bash" + - id: host + shell: bash + run: | + dist host ${{ needs.plan.outputs.tag-flag }} --steps=upload --steps=release --output-format=json > dist-manifest.json + echo "artifacts uploaded and released successfully" + cat dist-manifest.json + echo "manifest=$(jq -c "." dist-manifest.json)" >> "$GITHUB_OUTPUT" + - name: "Upload dist-manifest.json" + uses: actions/upload-artifact@v4 + with: + # Overwrite the previous copy + name: artifacts-dist-manifest + path: dist-manifest.json + # Create a GitHub Release while uploading all files to it + - name: "Download GitHub Artifacts" + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: artifacts + merge-multiple: true + - name: Cleanup + run: | + # Remove the granular manifests + rm -f artifacts/*-dist-manifest.json + - name: Create GitHub Release + env: + PRERELEASE_FLAG: "${{ fromJson(steps.host.outputs.manifest).announcement_is_prerelease && '--prerelease' || '' }}" + ANNOUNCEMENT_TITLE: "${{ fromJson(steps.host.outputs.manifest).announcement_title }}" + ANNOUNCEMENT_BODY: "${{ fromJson(steps.host.outputs.manifest).announcement_github_body }}" + RELEASE_COMMIT: "${{ github.sha }}" + run: | + # Write and read notes from a file to avoid quoting breaking things + echo "$ANNOUNCEMENT_BODY" > $RUNNER_TEMP/notes.txt + + gh release create "${{ needs.plan.outputs.tag }}" --target "$RELEASE_COMMIT" $PRERELEASE_FLAG --title "$ANNOUNCEMENT_TITLE" --notes-file "$RUNNER_TEMP/notes.txt" artifacts/* + + publish-homebrew-formula: + needs: + - plan + - host + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PLAN: ${{ needs.plan.outputs.val }} + GITHUB_USER: "axo bot" + GITHUB_EMAIL: "admin+bot@axo.dev" + if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: true + repository: "axodotdev/homebrew-packages" + token: ${{ secrets.HOMEBREW_TAP_TOKEN }} + # So we have access to the formula + - name: Fetch homebrew formulae + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: Formula/ + merge-multiple: true + # This is extra complex because you can make your Formula name not match your app name + # so we need to find releases with a *.rb file, and publish with that filename. + - name: Commit formula files + run: | + git config --global user.name "${GITHUB_USER}" + git config --global user.email "${GITHUB_EMAIL}" + + for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith(".rb")] | any)'); do + filename=$(echo "$release" | jq '.artifacts[] | select(endswith(".rb"))' --raw-output) + name=$(echo "$filename" | sed "s/\.rb$//") + version=$(echo "$release" | jq .app_version --raw-output) + + export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" + brew update + # We avoid reformatting user-provided data such as the app description and homepage. + brew style --except-cops FormulaAudit/Homepage,FormulaAudit/Desc,FormulaAuditStrict --fix "Formula/${filename}" || true + + git add "Formula/${filename}" + git commit -m "${name} ${version}" + done + git push + + publish-npm: + needs: + - plan + - host + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PLAN: ${{ needs.plan.outputs.val }} + if: ${{ !fromJson(needs.plan.outputs.val).announcement_is_prerelease || fromJson(needs.plan.outputs.val).publish_prereleases }} + steps: + - name: Fetch npm packages + uses: actions/download-artifact@v4 + with: + pattern: artifacts-* + path: npm/ + merge-multiple: true + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + - run: | + for release in $(echo "$PLAN" | jq --compact-output '.releases[] | select([.artifacts[] | endswith("-npm-package.tar.gz")] | any)'); do + pkg=$(echo "$release" | jq '.artifacts[] | select(endswith("-npm-package.tar.gz"))' --raw-output) + npm publish --access public "./npm/${pkg}" + done + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + announce: + needs: + - plan + - host + - publish-homebrew-formula + - publish-npm + # use "always() && ..." to allow us to wait for all publish jobs while + # still allowing individual publish jobs to skip themselves (for prereleases). + # "host" however must run to completion, no skipping allowed! + if: ${{ always() && needs.host.result == 'success' && (needs.publish-homebrew-formula.result == 'skipped' || needs.publish-homebrew-formula.result == 'success') && (needs.publish-npm.result == 'skipped' || needs.publish-npm.result == 'success') }} + runs-on: "ubuntu-22.04" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + submodules: recursive + +================ main.wxs ================ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + 1 + + + + + + + + + + + + + + + + + +