Repository: axodotdev/cargo-dist
Pull request #359 (2023-08-24 18:13:01)

feat: add publish_jobs config field
This is a quick spike of the new `publish_jobs` config field. Now, instead of just using `tap` to decide whether to enable a Homebrew publish job, we also have this new field. Right now, we don't explicitly ask the user to enable it and instead implicitly enable it if `tap` is enabled, but we can update the `init` UI for that if we want.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 3bf493f1..b1bd1fd2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -20,6 +20,8 @@ ci = ["github"]
 installers = ["shell", "powershell", "homebrew"]
 # A GitHub repo to push Homebrew formulas to
 tap = "axodotdev/homebrew-tap"
+# Publish jobs to run in CI
+publish-jobs = ["homebrew"]
 # Target platforms to build apps for (Rust target-triple syntax)
 targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
 
diff --git a/cargo-dist/src/backend/ci/github.rs b/cargo-dist/src/backend/ci/github.rs
index e0e5b1c7..f329faa2 100644
--- a/cargo-dist/src/backend/ci/github.rs
+++ b/cargo-dist/src/backend/ci/github.rs
@@ -21,6 +21,7 @@ struct CiInfo {
     local_tasks: Vec<CiTask>,
     global_task: Option<CiTask>,
     tap: Option<String>,
+    publish_jobs: Vec<String>,
 }
 
 #[derive(Debug, Serialize)]
@@ -94,6 +95,7 @@ fn compute_ci_info(dist: &DistGraph) -> CiInfo {
         None
     };
     let tap = dist.tap.clone();
+    let publish_jobs = dist.publish_jobs.iter().map(|j| j.to_string()).collect();
 
     // Figure out what Local Artifact tasks we need
     let local_runs = if dist.merge_tasks {
@@ -124,6 +126,7 @@ fn compute_ci_info(dist: &DistGraph) -> CiInfo {
         local_tasks,
         global_task,
         tap,
+        publish_jobs,
     }
 }
 
diff --git a/cargo-dist/src/config.rs b/cargo-dist/src/config.rs
index 0e7aab43..d6d692d0 100644
--- a/cargo-dist/src/config.rs
+++ b/cargo-dist/src/config.rs
@@ -221,6 +221,13 @@ pub struct DistMetadata {
     #[serde(skip_serializing_if = "Option::is_none")]
     #[serde(rename = "all-features")]
     pub all_features: Option<bool>,
+
+    /// Publish jobs to run in CI
+    ///
+    /// (defaults to none)
+    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(rename = "publish-jobs")]
+    pub publish_jobs: Option<Vec<PublishStyle>>,
 }
 
 impl DistMetadata {
@@ -248,6 +255,7 @@ impl DistMetadata {
             features: _,
             default_features: _,
             all_features: _,
+            publish_jobs: _,
         } = self;
         if let Some(include) = include {
             for include in include {
@@ -284,6 +292,7 @@ impl DistMetadata {
             features,
             default_features,
             all_features,
+            publish_jobs,
         } = self;
 
         // Check for global settings on local packages
@@ -346,6 +355,9 @@ impl DistMetadata {
         if tap.is_none() {
             *tap = workspace_config.tap.clone();
         }
+        if publish_jobs.is_none() {
+            *publish_jobs = workspace_config.publish_jobs.clone();
+        }
 
         // This was historically implemented as extend, but I'm not convinced the
         // inconsistency is worth the inconvenience...
@@ -439,6 +451,23 @@ impl std::fmt::Display for InstallerStyle {
     }
 }
 
+/// The publish jobs we should run
+#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
+pub enum PublishStyle {
+    /// Publish a Homebrew formula to a tap repository
+    #[serde(rename = "homebrew")]
+    Homebrew,
+}
+
+impl std::fmt::Display for PublishStyle {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let string = match self {
+            PublishStyle::Homebrew => "homebrew",
+        };
+        string.fmt(f)
+    }
+}
+
 /// The style of zip/tarball to make
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum ZipStyle {
diff --git a/cargo-dist/src/init.rs b/cargo-dist/src/init.rs
index 4eae6b36..3018cdf6 100644
--- a/cargo-dist/src/init.rs
+++ b/cargo-dist/src/init.rs
@@ -7,7 +7,10 @@ use semver::Version;
 use serde::Deserialize;
 
 use crate::{
-    config::{self, CiStyle, CompressionImpl, Config, DistMetadata, InstallerStyle, ZipStyle},
+    config::{
+        self, CiStyle, CompressionImpl, Config, DistMetadata, InstallerStyle, PublishStyle,
+        ZipStyle,
+    },
     do_generate_ci,
     errors::{DistError, DistResult, Result},
     GenerateCiArgs, SortedMap, METADATA_DIST, PROFILE_DIST,
@@ -200,6 +203,7 @@ fn get_new_dist_metadata(
             features: None,
             default_features: None,
             all_features: None,
+            publish_jobs: None,
         }
     };
 
@@ -440,6 +444,8 @@ fn get_new_dist_metadata(
         eprintln!();
     }
 
+    let mut publish_jobs = orig_meta.publish_jobs.clone().unwrap_or(vec![]);
+
     // Special handling of the Homebrew installer
     if meta
         .installers
@@ -475,6 +481,8 @@ fn get_new_dist_metadata(
                 meta.tap = None;
             } else {
                 meta.tap = Some(tap.to_owned());
+                publish_jobs.push(PublishStyle::Homebrew);
+
                 eprintln!("{check} Homebrew package will be published to {tap}");
 
                 eprintln!(
@@ -487,6 +495,12 @@ fn get_new_dist_metadata(
         }
     }
 
+    meta.publish_jobs = if publish_jobs.is_empty() {
+        None
+    } else {
+        Some(publish_jobs)
+    };
+
     // Special handling of the npm installer
     if meta
         .installers
@@ -617,6 +631,7 @@ fn update_toml_metadata(
         features,
         all_features,
         default_features,
+        publish_jobs,
     } = &meta;
 
     apply_optional_value(
@@ -759,6 +774,13 @@ fn update_toml_metadata(
         *all_features,
     );
 
+    apply_string_list(
+        table,
+        "publish-jobs",
+        "# Publish jobs to run in CI\n",
+        publish_jobs.as_ref(),
+    );
+
     // Finalize the table
     table
         .decor_mut()
diff --git a/cargo-dist/src/tasks.rs b/cargo-dist/src/tasks.rs
index b873e802..5da51dcf 100644
--- a/cargo-dist/src/tasks.rs
+++ b/cargo-dist/src/tasks.rs
@@ -68,7 +68,7 @@ use crate::{
     },
     config::{
         self, ArtifactMode, ChecksumStyle, CiStyle, CompressionImpl, Config, DistMetadata,
-        InstallPathStrategy, InstallerStyle, ZipStyle,
+        InstallPathStrategy, InstallerStyle, PublishStyle, ZipStyle,
     },
     errors::{DistError, DistResult, Result},
 };
@@ -180,6 +180,8 @@ pub struct DistGraph {
     pub variants: Vec<ReleaseVariant>,
     /// Logical releases that artifacts are grouped under
     pub releases: Vec<Release>,
+    /// List of publish jobs to run
+    pub publish_jobs: Vec<PublishStyle>,
     /// A GitHub repo to publish the Homebrew formula to
     pub tap: Option<String>,
 }
@@ -621,6 +623,8 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
             checksum: _,
             // Only the final value merged into a package_config matters
             install_path: _,
+            // Only the final value merged into a package_config matters
+            publish_jobs: _,
             features,
             default_features: no_default_features,
             all_features,
@@ -669,6 +673,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
         };
 
         let templates = Templates::new()?;
+        let publish_jobs = workspace_metadata.publish_jobs.clone().unwrap_or(vec![]);
 
         Ok(Self {
             inner: DistGraph {
@@ -696,6 +701,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
                 variants: vec![],
                 releases: vec![],
                 tap: workspace_metadata.tap.clone(),
+                publish_jobs,
             },
             package_metadata,
             workspace_metadata,
@@ -1177,7 +1183,7 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
             warn!("skipping Homebrew formula: couldn't compute a URL to download artifacts from");
             return;
         };
-        // TODO ensure this is Homebrew-legal
+
         let artifact_name = format!("{release_id}.rb");
         let artifact_path = self.inner.dist_dir.join(&artifact_name);
 
@@ -1268,6 +1274,13 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
         let app_homepage_url = release.app_homepage_url.clone();
         let tap = release.tap.clone();
 
+        if tap.is_some() && !self.inner.publish_jobs.contains(&PublishStyle::Homebrew) {
+            warn!("A Homebrew tap was specified but the Homebrew publish job is disabled\n  consider adding \"homebrew\" to publish-jobs in Cargo.toml");
+        }
+        if self.inner.publish_jobs.contains(&PublishStyle::Homebrew) && tap.is_none() {
+            warn!("The Homebrew publish job is enabled but no tap was specified\n  consider setting the tap field in Cargo.toml");
+        }
+
         let formula_name = to_class_case(&app_name);
 
         let installer_artifact = Artifact {
diff --git a/cargo-dist/templates/ci/github_ci.yml.j2 b/cargo-dist/templates/ci/github_ci.yml.j2
index a7b9d792..5be9660b 100644
--- a/cargo-dist/templates/ci/github_ci.yml.j2
+++ b/cargo-dist/templates/ci/github_ci.yml.j2
@@ -170,7 +170,7 @@ jobs:
           gh release upload ${{ github.ref_name }} $(cat uploads.txt)
           echo "uploaded!"
 
-{{%- if tap %}}
+{{%- if 'homebrew' in publish_jobs and tap %}}
 
   upload-homebrew-formula:
     needs: [create-release, upload-global-artifacts]


Test patch:
diff --git a/cargo-dist/tests/integration-tests.rs b/cargo-dist/tests/integration-tests.rs
index 9519d5c0..a7216956 100644
--- a/cargo-dist/tests/integration-tests.rs
+++ b/cargo-dist/tests/integration-tests.rs
@@ -36,6 +36,38 @@ fn axolotlsay_basic() -> Result<(), miette::Report> {
 cargo-dist-version = "{dist_version}"
 installers = ["shell", "powershell", "homebrew", "npm"]
 tap = "axodotdev/homebrew-packages"
+publish-jobs = ["homebrew"]
+targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
+ci = ["github"]
+unix-archive = ".tar.gz"
+windows-archive = ".tar.gz"
+scope = "@axodotdev"
+
+"#
+        ))?;
+
+        // 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/")?;
+        // Check generate-ci
+        let ci_result = ctx.cargo_dist_generate_ci(test_name)?;
+        let ci_snap = ci_result.check_all()?;
+        // snapshot all
+        main_snap.join(ci_snap).snap();
+        Ok(())
+    })
+}
+
+#[test]
+fn axolotlsay_no_homebrew_publish() -> Result<(), miette::Report> {
+    let test_name = _function_name!();
+    AXOLOTLSAY.run_test(|ctx| {
+        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"]
+tap = "axodotdev/homebrew-packages"
 targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
 ci = ["github"]
 unix-archive = ".tar.gz"
@@ -70,6 +102,7 @@ rust-toolchain-version = "1.67.1"
 ci = ["github"]
 installers = ["shell", "powershell", "homebrew"]
 tap = "mistydemeo/homebrew-formulae"
+publish-jobs = ["homebrew"]
 targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
 
 "#
@@ -105,6 +138,7 @@ rust-toolchain-version = "1.67.1"
 ci = ["github"]
 installers = ["shell", "powershell", "homebrew"]
 tap = "mistydemeo/homebrew-formulae"
+publish-jobs = ["homebrew"]
 targets = ["x86_64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", "aarch64-apple-darwin"]
 
 "#
diff --git a/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
new file mode 100644
index 00000000..a14084b8
--- /dev/null
+++ b/cargo-dist/tests/snapshots/axolotlsay_no_homebrew_publish.snap
@@ -0,0 +1,2296 @@
+---
+source: cargo-dist/tests/gallery/dist.rs
+expression: self.payload
+---
+================ installer.sh ================
+#!/bin/sh
+# shellcheck shell=dash
+#
+# Licensed under the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+if [ "$KSH_VERSION" = 'Version JM 93t+ 2010-03-05' ]; then
+    # The version of ksh93 that ships with many illumos systems does not
+    # support the "local" extension.  Print a message rather than fail in
+    # subtle ways later on:
+    echo 'this installer does not work with this ksh93 version; please try bash!' >&2
+    exit 1
+fi
+
+set -u
+
+APP_NAME="axolotlsay"
+APP_VERSION="0.1.0"
+ARTIFACT_DOWNLOAD_URL="${INSTALLER_DOWNLOAD_URL:-https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0}"
+PRINT_VERBOSE=${INSTALLER_PRINT_VERBOSE:-0}
+PRINT_QUIET=${INSTALLER_PRINT_QUIET:-0}
+NO_MODIFY_PATH=${INSTALLER_NO_MODIFY_PATH:-0}
+
+usage() {
+    # print help (this cat/EOF stuff is a "heredoc" string)
+    cat <<EOF
+axolotlsay-installer.sh
+
+The installer for axolotlsay 0.1.0
+
+This script detects what platform you're on and fetches an appropriate archive from
+https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0
+then unpacks the binaries and installs them to \$CARGO_HOME/bin (\$HOME/.cargo/bin)
+
+It will then add that dir to PATH by adding the appropriate line to \$HOME/.profile
+
+USAGE:
+    axolotlsay-installer.sh [OPTIONS]
+
+OPTIONS:
+    -v, --verbose
+            Enable verbose output
+
+    -q, --quiet
+            Disable progress output
+
+        --no-modify-path
+            Don't configure the PATH environment variable
+
+    -h, --help
+            Print help information
+EOF
+}
+
+download_binary_and_run_installer() {
+    downloader --check
+    need_cmd uname
+    need_cmd mktemp
+    need_cmd chmod
+    need_cmd mkdir
+    need_cmd rm
+    need_cmd tar
+    need_cmd which
+    need_cmd grep
+    need_cmd cat
+
+    for arg in "$@"; do
+        case "$arg" in
+            --help)
+                usage
+                exit 0
+                ;;
+            --quiet)
+                PRINT_QUIET=1
+                ;;
+            --verbose)
+                PRINT_VERBOSE=1
+                ;;
+            --no-modify-path)
+                NO_MODIFY_PATH=1
+                ;;
+            *)
+                OPTIND=1
+                if [ "${arg%%--*}" = "" ]; then
+                    err "unknown option $arg"
+                fi
+                while getopts :hvq sub_arg "$arg"; do
+                    case "$sub_arg" in
+                        h)
+                            usage
+                            exit 0
+                            ;;
+                        v)
+                            # user wants to skip the prompt --
+                            # we don't need /dev/tty
+                            PRINT_VERBOSE=1
+                            ;;
+                        q)
+                            # user wants to skip the prompt --
+                            # we don't need /dev/tty
+                            PRINT_QUIET=1
+                            ;;
+                        *)
+                            err "unknown option -$OPTARG"
+                            ;;
+                        esac
+                done
+                ;;
+        esac
+    done
+
+    get_architecture || return 1
+    local _arch="$RETVAL"
+    assert_nz "$_arch" "arch"
+
+    local _bins
+    local _zip_ext
+    local _artifact_name
+
+    # Lookup what to download/unpack based on platform
+    case "$_arch" in 
+        "aarch64-apple-darwin")
+            _artifact_name="axolotlsay-aarch64-apple-darwin.tar.gz"
+            _zip_ext=".tar.gz"
+            _bins="axolotlsay"
+            ;;
+        "x86_64-apple-darwin")
+            _artifact_name="axolotlsay-x86_64-apple-darwin.tar.gz"
+            _zip_ext=".tar.gz"
+            _bins="axolotlsay"
+            ;;
+        "x86_64-unknown-linux-gnu")
+            _artifact_name="axolotlsay-x86_64-unknown-linux-gnu.tar.gz"
+            _zip_ext=".tar.gz"
+            _bins="axolotlsay"
+            ;;
+        *)
+            err "there isn't a package for $_arch"
+            ;;
+    esac
+
+    # download the archive
+    local _url="$ARTIFACT_DOWNLOAD_URL/$_artifact_name"
+    local _dir
+    if ! _dir="$(ensure mktemp -d)"; then
+        # Because the previous command ran in a subshell, we must manually
+        # propagate exit status.
+        exit 1
+    fi
+    local _file="$_dir/input$_zip_ext"
+
+    say "downloading $APP_NAME $APP_VERSION ${_arch}" 1>&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
+
+    # 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" "$@"
+    local _retval=$?
+
+    ignore rm -rf "$_dir"
+
+    return "$_retval"
+}
+
+# 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).
+    #
+    # 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 $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
+    # 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
+
+
+    # first try CARGO_HOME, then fallback to HOME
+    if [ -n "${CARGO_HOME:-}" ]; then
+        _install_dir="$CARGO_HOME/bin"
+        _env_script_path="$CARGO_HOME/env"
+        # 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 "${HOME:-}" ]; then
+            if [ "$HOME/.cargo/bin" = "$_install_dir" ]; then
+                _install_dir_expr='$HOME/.cargo/bin'
+                _env_script_path_expr='$HOME/.cargo/env'
+            else
+                _install_dir_expr="$_install_dir"
+                _env_script_path_expr="$_env_script_path"
+            fi
+        else
+            _install_dir_expr="$_install_dir"
+            _env_script_path_expr="$_env_script_path"
+        fi
+    elif [ -n "${HOME:-}" ]; then
+        _install_dir="$HOME/.cargo/bin"
+        _env_script_path="$HOME/.cargo/env"
+        _install_dir_expr='$HOME/.cargo/bin'
+        _env_script_path_expr='$HOME/.cargo/env'
+    else
+        err "could not find your CARGO_HOME or HOME dir to install binaries to"
+    fi
+
+    say "installing to $_install_dir"
+    ensure mkdir -p "$_install_dir"
+
+    # copy all the binaries to the install dir
+    local _src_dir="$1"
+    local _bins="$2"
+    for _bin_name in $_bins; do
+        local _bin="$_src_dir/$_bin_name"
+        ensure cp "$_bin" "$_install_dir"
+        # unzip seems to need this chmod
+        ensure chmod +x "$_install_dir/$_bin_name"
+        say "  $_bin_name"
+    done
+
+    say "everything's installed!"
+
+    if [ "0" = "$NO_MODIFY_PATH" ]; then
+        add_install_dir_to_path "$_install_dir_expr" "$_env_script_path" "$_env_script_path_expr"
+    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"
+    if [ -n "${HOME:-}" ]; then
+        local _rcfile="$HOME/.profile"
+        # `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"
+            write_env_script "$_install_dir_expr" "$_env_script_path"
+        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" "$_rcfile" > /dev/null 2>/dev/null && \
+           ! grep -F "$_pretty_line" "$_rcfile" > /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
+                say_verbose "adding $_robust_line to $_rcfile"
+                ensure echo "$_robust_line" >> "$_rcfile"
+                say ""
+                say "To add $_install_dir_expr to your PATH, either restart your shell or run:"
+                say ""
+                say "    $_pretty_line"
+            fi
+        else
+            say_verbose "$_install_dir already on PATH"
+        fi
+    fi
+}
+
+write_env_script() {
+    # 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 <<EOF > "$_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
+}
+
+check_proc() {
+    # Check for /proc by looking for the /proc/self/exe link
+    # This is only run on Linux
+    if ! test -L /proc/self/exe ; then
+        err "fatal: Unable to find /proc/self/exe.  Is /proc mounted?  Installation cannot proceed without /proc."
+    fi
+}
+
+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_head
+    _current_exe_head=$(head -c 5 /proc/self/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() {
+    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 /proc/self/exe | tail -c 1)
+    [ "$_current_exe_machine" = "$(printf '\076')" ]
+}
+
+get_endianness() {
+    local cputype=$1
+    local suffix_eb=$2
+    local suffix_el=$3
+
+    # 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 /proc/self/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
+}
+
+get_architecture() {
+    local _ostype
+    local _cputype
+    _ostype="$(uname -s)"
+    _cputype="$(uname -m)"
+    local _clibtype="gnu"
+
+    if [ "$_ostype" = Linux ]; then
+        if [ "$(uname -o)" = Android ]; then
+            _ostype=Android
+        fi
+        if ldd --version 2>&1 | grep -q 'musl'; then
+            _clibtype="musl"
+        fi
+    fi
+
+    if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
+        # Darwin `uname -m` lies
+        if sysctl hw.optional.x86_64 | grep -q ': 1'; then
+            _cputype=x86_64
+        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
+
+    case "$_ostype" in
+
+        Android)
+            _ostype=linux-android
+            ;;
+
+        Linux)
+            check_proc
+            _ostype=unknown-linux-$_clibtype
+            _bitness=$(get_bitness)
+            ;;
+
+        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 mips '' el)
+            ;;
+
+        mips64)
+            if [ "$_bitness" -eq 64 ]; then
+                # only n64 ABI is supported for now
+                _ostype="${_ostype}abi64"
+                _cputype=$(get_endianness mips64 '' el)
+            fi
+            ;;
+
+        ppc)
+            _cputype=powerpc
+            ;;
+
+        ppc64)
+            _cputype=powerpc64
+            ;;
+
+        ppc64le)
+            _cputype=powerpc64le
+            ;;
+
+        s390x)
+            _cputype=s390x
+            ;;
+        riscv64)
+            _cputype=riscv64gc
+            ;;
+        loongarch64)
+            _cputype=loongarch64
+            ;;
+        *)
+            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; then {
+                    err "x32 linux unsupported"
+                }; else
+                    _cputype=i686
+                fi
+                ;;
+            mips64)
+                _cputype=$(get_endianness 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
+
+    # treat armv7 systems without neon as plain arm
+    if [ "$_ostype" = "unknown-linux-gnueabihf" ] && [ "$_cputype" = armv7 ]; then
+        if ensure grep '^Features' /proc/cpuinfo | grep -q -v neon; then
+            # At least one processor does not have NEON.
+            _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
+}
+
+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() {
+    if check_cmd curl
+    then _dld=curl
+    elif check_cmd wget
+    then _dld=wget
+    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 curl -sSfL "$1" -o "$2"
+    elif [ "$_dld" = wget ]
+    then wget "$1" -O "$2"
+    else err "Unknown downloader"   # should not reach here
+    fi
+}
+
+download_binary_and_run_installer "$@" || exit 1
+
+================ formula.rb ================
+class Axolotlsay < Formula
+  desc "💬 a CLI for learning to distribute CLIs in rust"
+  if Hardware::CPU.type == :arm
+    url "https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-aarch64-apple-darwin.tar.gz"
+  else
+    url "https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-apple-darwin.tar.gz"
+  end
+  version "0.1.0"
+  license "MIT OR Apache-2.0"
+
+  def install
+    bin.install "axolotlsay"
+
+    # 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
+
+================ installer.ps1 ================
+# Licensed under the MIT license
+# <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+<#
+.SYNOPSIS
+
+The installer for axolotlsay 0.1.0
+
+.DESCRIPTION
+
+This script detects what platform you're on and fetches an appropriate archive from
+https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0
+then unpacks the binaries and installs them to $env:CARGO_HOME\bin ($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.1.0',
+    [Parameter(HelpMessage = "Don't add the install directory to PATH")]
+    [switch]$NoModifyPath,
+    [Parameter(HelpMessage = "Print Help")]
+    [switch]$Help
+)
+
+$app_name = 'axolotlsay'
+$app_version = '0.1.0'
+
+function Install-Binary($install_args) {
+  if ($Help) {
+    Get-Help $PSCommandPath -Detailed
+    Exit
+  }
+  $old_erroractionpreference = $ErrorActionPreference
+  $ErrorActionPreference = 'stop'
+
+  Initialize-Environment
+
+  # Platform info injected by cargo-dist
+  $platforms = @{
+    "x86_64-pc-windows-msvc" = @{
+      "artifact_name" = "axolotlsay-x86_64-pc-windows-msvc.tar.gz"
+      "bins" = "axolotlsay.exe"
+      "zip_ext" = ".tar.gz"
+    }
+  }
+
+  $fetched = Download "$ArtifactDownloadUrl" $platforms
+  # FIXME: add a flag that lets the user not do this step
+  Invoke-Installer $fetched "$install_args"
+
+  $ErrorActionPreference = $old_erroractionpreference
+}
+
+function Get-TargetTriple() {
+  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-msvc" }
+      "X64" { return "x86_64-pc-windows-msvc" }
+      "Arm" { return "thumbv7a-pc-windows-msvc" }
+      "Arm64" { return "aarch64-pc-windows-msvc" }
+    }
+  } 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-msvc"
+  } else {
+    return "i686-pc-windows-msvc"
+  }
+}
+
+function Download($download_url, $platforms) {
+  $arch = Get-TargetTriple
+
+  if (-not $platforms.ContainsKey($arch)) {
+    # X64 is well-supported, including in emulation on ARM64
+    Write-Verbose "$arch is not availablem falling back to X64"
+    $arch = "x86_64-pc-windows-msvc"
+  }
+
+  if (-not $platforms.ContainsKey($arch)) {
+    # should not be possible, as currently we always produce X64 binaries.
+    $platforms_json = ConvertTo-Json $platforms
+    throw "ERROR: could not find binaries for this platform. Last platform tried: $arch platform info: $platforms_json"
+  }
+
+  # Lookup what we expect this platform to look like
+  $info = $platforms[$arch]
+  $zip_ext = $info["zip_ext"]
+  $bin_names = $info["bins"]
+  $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
+  $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"
+  }
+  return $bin_paths
+}
+
+function Invoke-Installer($bin_paths) {
+
+  # first try CARGO_HOME, then fallback to HOME
+  # (for whatever reason $HOME is not a normal env var and doesn't need the $env: prefix)
+  $dest_dir = if (($base_dir = $env:CARGO_HOME)) {
+    Join-Path $base_dir "bin"
+  } elseif (($base_dir = $HOME)) {
+    Join-Path $base_dir ".cargo\bin"
+  } else {
+    throw "ERROR: could not find your HOME dir or CARGO_HOME to install binaries to"
+  }
+
+  $dest_dir = New-Item -Force -ItemType Directory -Path $dest_dir
+  Write-Information "Installing to $dest_dir"
+  # Just copy the binaries from the temp location to the install dir
+  foreach ($bin_path in $bin_paths) {
+    $installed_file = Split-Path -Path "$bin_path" -Leaf
+    Copy-Item "$bin_path" -Destination "$dest_dir"
+    Remove-Item "$bin_path" -Recurse -Force
+    Write-Information "  $installed_file"
+  }
+
+  Write-Information "Everything's installed!"
+  if (-not $NoModifyPath) {
+    if (Add-Path $dest_dir) {
+        Write-Information ""
+        Write-Information "$dest_dir was added to your PATH, you may need to restart your shell for that to take effect."
+    }
+  }
+}
+
+# Try to add the given path to PATH via the registry
+#
+# Returns true if the registry was modified, otherwise returns false
+# (indicating it was already on PATH)
+function Add-Path($OrigPathToAdd) {
+  $RegistryPath = "HKCU:\Environment"
+  $PropertyName = "Path"
+  $PathToAdd = $OrigPathToAdd
+
+  $Item = if (Test-Path $RegistryPath) {
+    # If the registry key exists, get it
+    Get-Item -Path $RegistryPath
+  } else {
+    # If the registry key doesn't exist, create it
+    Write-Verbose  "Creating $RegistryPath"
+    New-Item -Path $RegistryPath -Force
+  }
+
+  $OldPath = ""
+  try {
+    # Try to get the old PATH value. If that fails, assume we're making it from scratch.
+    # Otherwise assume there's already paths in here and use a ; separator
+    $OldPath = $Item | Get-ItemPropertyValue -Name $PropertyName
+    $PathToAdd = "$PathToAdd;"
+  } catch {
+    # We'll be creating the PATH from scratch
+    Write-Verbose "Adding $PropertyName Property to $RegistryPath"
+  }
+
+  # Check if the path is already there
+  #
+  # We don't want to incorrectly match "C:\blah\" to "C:\blah\blah\", so we include the semicolon
+  # delimiters when searching, ensuring exact matches. To avoid corner cases we add semicolons to
+  # both sides of the input, allowing us to pretend we're always in the middle of a list.
+  if (";$OldPath;" -like "*;$OrigPathToAdd;*") {
+    # Already on path, nothing to do
+    Write-Verbose "install dir already on PATH, all done!"
+    return $false
+  } else {
+    # Actually update PATH
+    Write-Verbose "Adding $OrigPathToAdd to your PATH"
+    $NewPath = $PathToAdd + $OldPath
+    # We use -Force here to make the value already existing not be an error
+    $Item | New-ItemProperty -Name $PropertyName -Value $NewPath -PropertyType String -Force | Out-Null
+    return $true
+  }
+}
+
+function Initialize-Environment() {
+  If (($PSVersionTable.PSVersion.Major) -lt 5) {
+    Write-Error "PowerShell 5 or later is required to install $app_name."
+    Write-Error "Upgrade PowerShell: https://docs.microsoft.com/en-us/powershell/scripting/setup/installing-windows-powershell"
+    break
+  }
+
+  # show notification to change execution policy:
+  $allowedExecutionPolicy = @('Unrestricted', 'RemoteSigned', 'ByPass')
+  If ((Get-ExecutionPolicy).ToString() -notin $allowedExecutionPolicy) {
+    Write-Error "PowerShell requires an execution policy in [$($allowedExecutionPolicy -join ", ")] to run $app_name."
+    Write-Error "For example, to set the execution policy to 'RemoteSigned' please run :"
+    Write-Error "'Set-ExecutionPolicy RemoteSigned -scope CurrentUser'"
+    break
+  }
+
+  # GitHub requires TLS 1.2
+  If ([System.Enum]::GetNames([System.Net.SecurityProtocolType]) -notcontains 'Tls12') {
+    Write-Error "Installing $app_name requires at least .NET Framework 4.5"
+    Write-Error "Please download and install it first:"
+    Write-Error "https://www.microsoft.com/net/download"
+    break
+  }
+}
+
+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"
+Install-Binary "$Args"
+
+================ npm-package.tar.gz/package/.gitignore ================
+/node_modules
+
+================ npm-package.tar.gz/package/CHANGELOG.md ================
+# Version 0.1.0
+
+```text
+         +------------------------+
+         | the initial release!!! |
+         +------------------------+
+        /
+≽(◕ ᴗ ◕)≼
+```
+================ 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 2023 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.
+
+================ npm-package.tar.gz/package/LICENSE-MIT ================
+Copyright (c) 2023 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.
+
+================ 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.
+
+================ npm-package.tar.gz/package/binary.js ================
+const { Binary } = 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 { version } = require("./package.json");
+const name = "axolotlsay";
+const artifact_download_url = "https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0";
+
+const supportedPlatforms = {
+  "aarch64-apple-darwin": {
+    "artifact_name": "axolotlsay-aarch64-apple-darwin.tar.gz",
+    "bins": ["axolotlsay"],
+    "zip_ext": ".tar.gz"
+  },
+  "x86_64-apple-darwin": {
+    "artifact_name": "axolotlsay-x86_64-apple-darwin.tar.gz",
+    "bins": ["axolotlsay"],
+    "zip_ext": ".tar.gz"
+  },
+  "x86_64-pc-windows-msvc": {
+    "artifact_name": "axolotlsay-x86_64-pc-windows-msvc.tar.gz",
+    "bins": ["axolotlsay.exe"],
+    "zip_ext": ".tar.gz"
+  },
+  "x86_64-unknown-linux-gnu": {
+    "artifact_name": "axolotlsay-x86_64-unknown-linux-gnu.tar.gz",
+    "bins": ["axolotlsay"],
+    "zip_ext": ".tar.gz"
+  }
+};
+
+const getPlatform = () => {
+  const raw_os_type = os.type();
+  const raw_architecture = 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 os_type = "";
+  switch (raw_os_type) {
+    case "Windows_NT":
+      os_type = "pc-windows-msvc";
+      break;
+    case "Darwin":
+      os_type = "apple-darwin";
+      break;
+    case "Linux":
+      os_type = "unknown-linux-gnu"
+      break;
+  }
+
+  let arch = "";
+  switch (raw_architecture) {
+    case "x64":
+      arch = "x86_64";
+      break;
+    case "arm64":
+      arch = "aarch64";
+      break;
+  }
+
+  // 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 target_triple = `${arch}-${os_type}`;
+  let platform = supportedPlatforms[target_triple];
+
+  if (!platform) {
+    error(
+      `Platform with type "${raw_os_type}" and architecture "${raw_architecture}" is not supported by ${name}.\nYour system must be one of the following:\n\n${Object.keys(supportedPlatforms).join(",")}`
+    );
+  }
+
+  // These are both situation where you might toggle to unknown-linux-musl but we don't support that yet
+  if (raw_os_type === "Linux") {
+    if (libc.isNonGlibcLinuxSync()) {
+      error("This operating system does not support dynamic linking to glibc.");
+    } else {
+      let libc_version = libc.versionSync();
+      let split_libc_version = libc_version.split(".");
+      let libc_major_version = split_libc_version[0];
+      let libc_minor_version = split_libc_version[1];
+      let min_major_version = 2;
+      let min_minor_version = 17;
+      if (
+        libc_major_version < min_major_version ||
+        libc_minor_version < min_minor_version
+      ) {
+        error(
+          `This operating system needs glibc >= ${min_major_version}.${min_minor_version}, but only has ${libc_version} installed.`
+        );
+      }
+    }
+  }
+
+  return platform;
+};
+
+const getBinary = () => {
+  const platform = getPlatform();
+  const url = `${artifact_download_url}/${platform.artifact_name}`;
+
+  if (platform.bins.length > 1) {
+    // Not yet supported
+    error("this app has multiple binaries, which isn't yet implemented");
+  }
+  let binary = new Binary(platform.bins[0], url);
+
+  return binary;
+};
+
+const install = (suppressLogs) => {
+  const binary = getBinary();
+  const proxy = configureProxy(binary.url);
+
+  return binary.install(proxy, suppressLogs);
+};
+
+const run = () => {
+  const binary = getBinary();
+  binary.run();
+};
+
+module.exports = {
+  install,
+  run,
+  getBinary,
+};
+
+================ npm-package.tar.gz/package/install.js ================
+#!/usr/bin/env node
+
+const { install } = require("./binary");
+install(false);
+
+================ npm-package.tar.gz/package/npm-shrinkwrap.json ================
+{
+  "name": "axolotlsay",
+  "version": "0.1.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "axolotlsay",
+      "version": "0.1.0",
+      "license": "MIT OR Apache-2.0",
+      "hasInstallScript": true,
+      "dependencies": {
+        "axios-proxy-builder": "^0.1.1",
+        "binary-install": "^1.0.6",
+        "console.table": "^0.10.0",
+        "detect-libc": "^2.0.0"
+      },
+      "bin": {
+        "rover": "run.js"
+      },
+      "devDependencies": {
+        "prettier": "2.8.4"
+      },
+      "engines": {
+        "node": ">=14",
+        "npm": ">=6"
+      }
+    },
+    "node_modules/axios": {
+      "version": "0.26.1",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
+      "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
+      "dependencies": {
+        "follow-redirects": "^1.14.8"
+      }
+    },
+    "node_modules/axios-proxy-builder": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/axios-proxy-builder/-/axios-proxy-builder-0.1.2.tgz",
+      "integrity": "sha512-6uBVsBZzkB3tCC8iyx59mCjQckhB8+GQrI9Cop8eC7ybIsvs/KtnNgEBfRMSEa7GqK2VBGUzgjNYMdPIfotyPA==",
+      "dependencies": {
+        "tunnel": "^0.0.6"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/binary-install": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/binary-install/-/binary-install-1.0.6.tgz",
+      "integrity": "sha512-h3K4jaC4jEauK3csXI9GxGBJldkpuJlHCIBv8i+XBNhPuxnlERnD1PWVczQYDqvhJfv0IHUbB3lhDrZUMHvSgw==",
+      "dependencies": {
+        "axios": "^0.26.1",
+        "rimraf": "^3.0.2",
+        "tar": "^6.1.11"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+      "optional": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/console.table": {
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz",
+      "integrity": "sha512-dPyZofqggxuvSf7WXvNjuRfnsOk1YazkVP8FdxH4tcH2c37wc79/Yl6Bhr7Lsu00KMgy2ql/qCMuNu8xctZM8g==",
+      "dependencies": {
+        "easy-table": "1.1.0"
+      },
+      "engines": {
+        "node": "> 0.10"
+      }
+    },
+    "node_modules/defaults": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz",
+      "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==",
+      "optional": true,
+      "dependencies": {
+        "clone": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/detect-libc": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
+      "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/easy-table": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz",
+      "integrity": "sha512-oq33hWOSSnl2Hoh00tZWaIPi1ievrD9aFG82/IgjlycAnW9hHx5PkJiXpxPsgEE+H7BsbVQXFVFST8TEXS6/pA==",
+      "optionalDependencies": {
+        "wcwidth": ">=1.0.1"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/fs-minipass": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/fs-minipass/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz",
+      "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minizlib": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+      "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+      "dependencies": {
+        "minipass": "^3.0.0",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/minizlib/node_modules/minipass": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+      "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/prettier": {
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz",
+      "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "url": "https://github.com/prettier/prettier?sponsor=1"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/tar": {
+      "version": "6.1.13",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz",
+      "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==",
+      "dependencies": {
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.0.0",
+        "minipass": "^4.0.0",
+        "minizlib": "^2.1.1",
+        "mkdirp": "^1.0.3",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "engines": {
+        "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+      }
+    },
+    "node_modules/wcwidth": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+      "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==",
+      "optional": true,
+      "dependencies": {
+        "defaults": "^1.0.3"
+      }
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+    }
+  }
+}
+
+================ npm-package.tar.gz/package/package.json ================
+{
+  "name": "axolotlsay",
+  "version": "0.1.0",
+  "description": "💬 a CLI for learning to distribute CLIs in rust",
+  "repository": "https://github.com/axodotdev/axolotlsay",
+  "license": "MIT OR Apache-2.0",
+  "bin": {
+    "axolotlsay": "run.js"
+  },
+  "scripts": {
+    "postinstall": "node ./install.js",
+    "fmt": "prettier --write **/*.js",
+    "fmt:check": "prettier --check **/*.js"
+  },
+  "engines": {
+    "node": ">=14",
+    "npm": ">=6"
+  },
+  "volta": {
+    "node": "18.14.1",
+    "npm": "9.5.0"
+  },
+  "dependencies": {
+    "axios-proxy-builder": "^0.1.1",
+    "binary-install": "^1.0.6",
+    "console.table": "^0.10.0",
+    "detect-libc": "^2.0.0"
+  },
+  "devDependencies": {
+    "prettier": "2.8.4"
+  }
+}
+
+================ npm-package.tar.gz/package/run.js ================
+#!/usr/bin/env node
+
+const { run, install: maybeInstall } = require("./binary");
+maybeInstall(true).then(run);
+
+================ dist-manifest.json ================
+{
+  "dist_version": "CENSORED",
+  "announcement_tag": "v0.1.0",
+  "announcement_is_prerelease": false,
+  "announcement_title": "Version 0.1.0",
+  "announcement_changelog": "```text\n         +------------------------+\n         | the initial release!!! |\n         +------------------------+\n        /\n≽(◕ ᴗ ◕)≼\n```",
+  "announcement_github_body": "## Release Notes\n\n```text\n         +------------------------+\n         | the initial release!!! |\n         +------------------------+\n        /\n≽(◕ ᴗ ◕)≼\n```\n\n## Install axolotlsay 0.1.0\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.1.0/axolotlsay-installer.sh | sh\n```\n\n### Install prebuilt binaries via powershell script\n\n```sh\nirm https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-installer.ps1 | iex\n```\n\n### Install prebuilt binaries via Homebrew\n\n```sh\nbrew install axodotdev/homebrew-packages/axolotlsay\n```\n\n### Install prebuilt binaries into your npm project\n\n```sh\nnpm install axolotlsay@0.1.0\n```\n\n## Download axolotlsay 0.1.0\n\n|        |        |\n|--------|--------|\n| [axolotlsay-aarch64-apple-darwin.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-aarch64-apple-darwin.tar.gz) | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-aarch64-apple-darwin.tar.gz.sha256) |\n| [axolotlsay-x86_64-apple-darwin.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-apple-darwin.tar.gz) | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-apple-darwin.tar.gz.sha256) |\n| [axolotlsay-x86_64-pc-windows-msvc.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-pc-windows-msvc.tar.gz) | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256) |\n| [axolotlsay-x86_64-unknown-linux-gnu.tar.gz](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-unknown-linux-gnu.tar.gz) | [checksum](https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256) |\n\n",
+  "system_info": {
+    "cargo_version_line": "CENSORED"
+  },
+  "releases": [
+    {
+      "app_name": "axolotlsay",
+      "app_version": "0.1.0",
+      "artifacts": [
+        "axolotlsay-installer.sh",
+        "axolotlsay-installer.ps1",
+        "axolotlsay.rb",
+        "axolotlsay-npm-package.tar.gz",
+        "axolotlsay-aarch64-apple-darwin.tar.gz",
+        "axolotlsay-aarch64-apple-darwin.tar.gz.sha256",
+        "axolotlsay-x86_64-apple-darwin.tar.gz",
+        "axolotlsay-x86_64-apple-darwin.tar.gz.sha256",
+        "axolotlsay-x86_64-pc-windows-msvc.tar.gz",
+        "axolotlsay-x86_64-pc-windows-msvc.tar.gz.sha256",
+        "axolotlsay-x86_64-unknown-linux-gnu.tar.gz",
+        "axolotlsay-x86_64-unknown-linux-gnu.tar.gz.sha256"
+      ]
+    }
+  ],
+  "artifacts": {
+    "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"
+        },
+        {
+          "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": [
+        "x86_64-pc-windows-msvc"
+      ],
+      "install_hint": "irm https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/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-unknown-linux-gnu"
+      ],
+      "install_hint": "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/axolotlsay/releases/download/v0.1.0/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",
+        "x86_64-apple-darwin",
+        "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.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 axolotlsay@0.1.0",
+      "description": "Install prebuilt binaries into your npm project"
+    },
+    "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"
+        },
+        {
+          "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.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"
+        },
+        {
+          "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"
+        },
+        {
+          "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"
+      ],
+      "install_hint": "brew install axodotdev/homebrew-packages/axolotlsay",
+      "description": "Install prebuilt binaries via Homebrew"
+    }
+  }
+}
+
+================ github-ci.yml ================
+# Copyright 2022-2023, axodotdev
+# SPDX-License-Identifier: MIT or Apache-2.0
+#
+# CI that:
+#
+# * checks for a Git Tag that looks like a release
+# * creates a Github Release™ and fills in its text
+# * builds artifacts with cargo-dist (executable-zips, installers)
+# * uploads those artifacts to the Github Release™
+#
+# Note that the Github Release™ will be created before the artifacts,
+# so there will be a few minutes where the release has no artifacts
+# and then they will slowly trickle in, possibly failing. To make
+# this more pleasant we mark the release as a "draft" until all
+# artifacts have been successfully uploaded. This allows you to
+# choose what to do with partial successes and avoids spamming
+# anyone with notifications before the release is actually ready.
+name: Release
+
+permissions:
+  contents: write
+
+# This task will run whenever you push a git tag that looks like a version
+# like "v1", "v1.2.0", "v0.1.0-prerelease01", "my-app-v1.0.0", etc.
+# The version will be roughly parsed as ({PACKAGE_NAME}-)?v{VERSION}, where
+# PACKAGE_NAME must be the name of a Cargo package in your workspace, and VERSION
+# must be a Cargo-style SemVer Version.
+#
+# If PACKAGE_NAME is specified, then we will create a Github Release™ for that
+# package (erroring out if it doesn't have the given version or isn't cargo-dist-able).
+#
+# If PACKAGE_NAME isn't specified, then we will create a Github Release™ for all
+# (cargo-dist-able) packages in the workspace with that version (this is 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 Github Release™ for each one.
+#
+# If there's a prerelease-style suffix to the version then the Github Release™
+# will be marked as a prerelease.
+on:
+  push:
+    tags:
+      - '*-?v[0-9]+*'
+
+jobs:
+  # Create the Github Release™ so the packages have something to be uploaded to
+  create-release:
+    runs-on: ubuntu-latest
+    outputs:
+      has-releases: ${{ steps.create-release.outputs.has-releases }}
+      releases: ${{ steps.create-release.outputs.releases }}
+    env:
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: Install cargo-dist
+        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh"
+      - id: create-release
+        run: |
+          cargo dist plan --tag=${{ github.ref_name }} --output-format=json > dist-manifest.json
+          echo "dist plan ran successfully"
+          cat dist-manifest.json
+
+          # Create the Github Release™ based on what cargo-dist thinks it should be
+          ANNOUNCEMENT_TITLE=$(jq --raw-output ".announcement_title" dist-manifest.json)
+          IS_PRERELEASE=$(jq --raw-output ".announcement_is_prerelease" dist-manifest.json)
+          jq --raw-output ".announcement_github_body" dist-manifest.json > new_dist_announcement.md
+          gh release create ${{ github.ref_name }} --draft --prerelease="$IS_PRERELEASE" --title="$ANNOUNCEMENT_TITLE" --notes-file=new_dist_announcement.md
+          echo "created announcement!"
+
+          # Upload the manifest to the Github Release™
+          gh release upload ${{ github.ref_name }} dist-manifest.json
+          echo "uploaded manifest!"
+
+          # Disable all the upload-artifacts tasks if we have no actual releases
+          HAS_RELEASES=$(jq --raw-output ".releases != null" dist-manifest.json)
+          echo "has-releases=$HAS_RELEASES" >> "$GITHUB_OUTPUT"
+          echo "releases=$(jq --compact-output ".releases" dist-manifest.json)" >> "$GITHUB_OUTPUT"
+
+  # Build and packages all the platform-specific things
+  upload-local-artifacts:
+    # Let the initial task tell us to not run (currently very blunt)
+    needs: create-release
+    if: ${{ needs.create-release.outputs.has-releases == 'true' }}
+    strategy:
+      fail-fast: false
+      matrix:
+        # For these target platforms
+        include:
+        - os: "macos-11"
+          dist-args: "--artifacts=local --target=aarch64-apple-darwin"
+          install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh"
+        - os: "macos-11"
+          dist-args: "--artifacts=local --target=x86_64-apple-darwin"
+          install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh"
+        - os: "windows-2019"
+          dist-args: "--artifacts=local --target=x86_64-pc-windows-msvc"
+          install-dist: "irm  https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.ps1 | iex"
+        - os: "ubuntu-20.04"
+          dist-args: "--artifacts=local --target=x86_64-unknown-linux-gnu"
+          install-dist: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh"
+    runs-on: ${{ matrix.os }}
+    env:
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: Install cargo-dist
+        run: ${{ matrix.install-dist }}
+      - name: Run cargo-dist
+        # This logic is a bit janky because it's trying to be a polyglot between
+        # powershell and bash since this will run on windows, macos, and linux!
+        # The two platforms don't agree on how to talk about env vars but they
+        # do agree on 'cat' and '$()' so we use that to marshal values between commands.
+        run: |
+          # Actually do builds and make zips and whatnot
+          cargo dist build --tag=${{ github.ref_name }} --output-format=json ${{ matrix.dist-args }} > dist-manifest.json
+          echo "dist ran successfully"
+          cat dist-manifest.json
+
+          # Parse out what we just built and upload it to the Github Release™
+          jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt
+          echo "uploading..."
+          cat uploads.txt
+          gh release upload ${{ github.ref_name }} $(cat uploads.txt)
+          echo "uploaded!"
+
+  # Build and packages all the platform-agnostic(ish) things
+  upload-global-artifacts:
+    needs: upload-local-artifacts
+    runs-on: "ubuntu-20.04"
+    env:
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: Install cargo-dist
+        run: "curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/vSOME_VERSION/cargo-dist-installer.sh | sh"
+      # Get all the local artifacts for the global tasks to use (for e.g. checksums)
+      - name: Fetch local artifacts
+        run: |
+          gh release download ${{ github.ref_name }} --dir target/distrib/
+      - name: Run cargo-dist
+        # This logic is a bit janky because it's trying to be a polyglot between
+        # powershell and bash since this will run on windows, macos, and linux!
+        # The two platforms don't agree on how to talk about env vars but they
+        # do agree on 'cat' and '$()' so we use that to marshal values between commands.
+        run: |
+          cargo dist build --tag=${{ github.ref_name }} --output-format=json "--artifacts=global" > dist-manifest.json
+          echo "dist ran successfully"
+          cat dist-manifest.json
+
+          # Parse out what we just built and upload it to the Github Release™
+          jq --raw-output ".artifacts[]?.path | select( . != null )" dist-manifest.json > uploads.txt
+          echo "uploading..."
+          cat uploads.txt
+          gh release upload ${{ github.ref_name }} $(cat uploads.txt)
+          echo "uploaded!"
+
+  # Mark the Github Release™ as a non-draft now that everything has succeeded!
+  publish-release:
+    # Only run after all the other tasks, but it's ok if upload-artifacts was skipped
+    needs: [create-release, upload-local-artifacts, upload-global-artifacts]
+    if: ${{ always() && needs.create-release.result == 'success' && (needs.upload-local-artifacts.result == 'skipped' || needs.upload-local-artifacts.result == 'success') && (needs.upload-global-artifacts.result == 'skipped' || needs.upload-global-artifacts.result == 'success') }}
+    runs-on: ubuntu-latest
+    env:
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: recursive
+      - name: mark release as non-draft
+        run: |
+          gh release edit ${{ github.ref_name }} --draft=false
+
+