Skip to content

Commit

Permalink
Merge pull request #1410 from axodotdev/ci-mode
Browse files Browse the repository at this point in the history
feat: unmanaged installs
  • Loading branch information
mistydemeo authored Sep 17, 2024
2 parents 05382f6 + b28b89f commit 9e97a0c
Show file tree
Hide file tree
Showing 60 changed files with 4,242 additions and 1,124 deletions.
34 changes: 29 additions & 5 deletions cargo-dist-schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,19 @@ pub struct SystemInfo {
pub build_environment: BuildEnvironment,
}

/// Release-specific environment variables
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct EnvironmentVariables {
/// Environment variable to force an install location
pub install_dir_env_var: String,
/// Environment variable to force an unmanaged install location
pub unmanaged_dir_env_var: String,
/// Environment variable to disable updater features
pub disable_update_env_var: String,
/// Environment variable to disable modifying the path
pub no_modify_path_env_var: String,
}

/// A Release of an Application
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Release {
Expand All @@ -291,10 +304,10 @@ pub struct Release {
/// The version of the app
// FIXME: should be a Version but JsonSchema doesn't support (yet?)
pub app_version: String,
/// Environment variable to force an install location
/// Environment variables which control this release's installer's behaviour
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub install_dir_env_var: Option<String>,
pub env: Option<EnvironmentVariables>,
/// Alternative display name that can be prettier
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -610,12 +623,23 @@ impl DistManifest {
if let Some(position) = self.releases.iter().position(|r| r.app_name == name) {
&mut self.releases[position]
} else {
let install_dir_env_var =
Some(name.to_ascii_uppercase().replace('-', "_") + "_INSTALL_DIR");
let env_app_name = name.to_ascii_uppercase().replace('-', "_");
let install_dir_env_var = format!("{env_app_name}_INSTALL_DIR");
let unmanaged_dir_env_var = format!("{env_app_name}_UNMANAGED_INSTALL");
let disable_update_env_var = format!("{env_app_name}_DISABLE_UPDATE");
let no_modify_path_env_var = format!("{env_app_name}_NO_MODIFY_PATH");

let environment_variables = EnvironmentVariables {
install_dir_env_var,
unmanaged_dir_env_var,
disable_update_env_var,
no_modify_path_env_var,
};

self.releases.push(Release {
app_name: name,
app_version: version,
install_dir_env_var,
env: Some(environment_variables),
artifacts: vec![],
hosting: Hosting::default(),
display: None,
Expand Down
46 changes: 39 additions & 7 deletions cargo-dist-schema/src/snapshots/cargo_dist_schema__emit.snap
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,34 @@ expression: json_schema
}
}
},
"EnvironmentVariables": {
"description": "Release-specific environment variables",
"type": "object",
"required": [
"disable_update_env_var",
"install_dir_env_var",
"no_modify_path_env_var",
"unmanaged_dir_env_var"
],
"properties": {
"disable_update_env_var": {
"description": "Environment variable to disable updater features",
"type": "string"
},
"install_dir_env_var": {
"description": "Environment variable to force an install location",
"type": "string"
},
"no_modify_path_env_var": {
"description": "Environment variable to disable modifying the path",
"type": "string"
},
"unmanaged_dir_env_var": {
"description": "Environment variable to force an unmanaged install location",
"type": "string"
}
}
},
"GithubCiInfo": {
"description": "Github CI backend",
"type": "object",
Expand Down Expand Up @@ -970,20 +998,24 @@ expression: json_schema
"null"
]
},
"env": {
"description": "Environment variables which control this release's installer's behaviour",
"anyOf": [
{
"$ref": "#/definitions/EnvironmentVariables"
},
{
"type": "null"
}
]
},
"hosting": {
"description": "Hosting info",
"allOf": [
{
"$ref": "#/definitions/Hosting"
}
]
},
"install_dir_env_var": {
"description": "Environment variable to force an install location",
"type": [
"string",
"null"
]
}
}
},
Expand Down
6 changes: 6 additions & 0 deletions cargo-dist/src/backend/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ pub struct InstallerInfo {
pub platform_support: Option<PlatformSupport>,
/// Environment variable to force an install location
pub install_dir_env_var: String,
/// Like the above, but for unmanaged installs
pub unmanaged_dir_env_var: String,
/// Environment variable to disable self-update features
pub disable_update_env_var: String,
/// Environment variable to disable modifying the path
pub no_modify_path_env_var: String,
}

/// A fake fragment of an ExecutableZip artifact for installers
Expand Down
36 changes: 30 additions & 6 deletions cargo-dist/src/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1684,10 +1684,16 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
.manifest
.release_by_name(&release.app_name)
.expect("couldn't find the release!?");
let install_dir_env_var = schema_release
.install_dir_env_var
.to_owned()

let env_vars = schema_release
.env
.as_ref()
.expect("couldn't determine app-specific environment variable!?");
let install_dir_env_var = env_vars.install_dir_env_var.to_owned();
let unmanaged_dir_env_var = env_vars.unmanaged_dir_env_var.to_owned();
let disable_update_env_var = env_vars.disable_update_env_var.to_owned();
let no_modify_path_env_var = env_vars.no_modify_path_env_var.to_owned();

let download_url = schema_release
.artifact_download_url()
.expect("couldn't compute a URL to download artifacts from!?");
Expand Down Expand Up @@ -1745,6 +1751,9 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
runtime_conditions,
platform_support: None,
install_dir_env_var,
unmanaged_dir_env_var,
disable_update_env_var,
no_modify_path_env_var,
})),
is_global: true,
};
Expand Down Expand Up @@ -1907,6 +1916,9 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
platform_support: None,
// Not actually needed for this installer type
install_dir_env_var: String::new(),
unmanaged_dir_env_var: String::new(),
disable_update_env_var: String::new(),
no_modify_path_env_var: String::new(),
},
install_libraries: config.install_libraries.clone(),
})),
Expand All @@ -1933,10 +1945,16 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
.manifest
.release_by_name(&release.app_name)
.expect("couldn't find the release!?");
let install_dir_env_var = schema_release
.install_dir_env_var
.to_owned()

let env_vars = schema_release
.env
.as_ref()
.expect("couldn't determine app-specific environment variable!?");
let install_dir_env_var = env_vars.install_dir_env_var.to_owned();
let unmanaged_dir_env_var = env_vars.unmanaged_dir_env_var.to_owned();
let disable_update_env_var = env_vars.disable_update_env_var.to_owned();
let no_modify_path_env_var = env_vars.no_modify_path_env_var.to_owned();

let download_url = schema_release
.artifact_download_url()
.expect("couldn't compute a URL to download artifacts from!?");
Expand Down Expand Up @@ -1990,6 +2008,9 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
runtime_conditions: RuntimeConditions::default(),
platform_support: None,
install_dir_env_var,
unmanaged_dir_env_var,
disable_update_env_var,
no_modify_path_env_var,
})),
is_global: true,
};
Expand Down Expand Up @@ -2110,6 +2131,9 @@ impl<'pkg_graph> DistGraphBuilder<'pkg_graph> {
platform_support: None,
// Not actually needed for this installer type
install_dir_env_var: String::new(),
unmanaged_dir_env_var: String::new(),
disable_update_env_var: String::new(),
no_modify_path_env_var: String::new(),
},
})),
is_global: true,
Expand Down
56 changes: 41 additions & 15 deletions cargo-dist/templates/installer/installer.ps1.j2
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ $receipt = @"
"@
$receipt_home = "${env:LOCALAPPDATA}\{{ app_name }}"

if ($env:{{ disable_update_env_var }}) {
$install_updater = $false
} else {
$install_updater = $true
}

$NoModifyPath = $false
if ($env:{{ no_modify_path_env_var }}) {
$NoModifyPath = $true
}

$unmanaged_install = $env:{{ unmanaged_dir_env_var }}

if ($unmanaged_install) {
$NoModifyPath = $true
$install_updater = $false
}

function Install-Binary($install_args) {
if ($Help) {
Get-Help $PSCommandPath -Detailed
Expand Down Expand Up @@ -219,7 +237,7 @@ function Download($download_url, $platforms) {
$staticlib_paths += "$tmp\$lib_name"
}

if ($null -ne $info["updater"]) {
if (($null -ne $info["updater"]) -and $install_updater) {
$updater_id = $info["updater"]["artifact_name"]
$updater_url = "$download_url/$updater_id"
$out_name = "$tmp\{{ app_name }}-update.exe"
Expand Down Expand Up @@ -248,12 +266,18 @@ function Invoke-Installer($artifacts, $platforms) {

# Forces the install to occur at this path, not the default
$force_install_dir = $null
$flat_install_layout = $false
# Check the newer app-specific variable before falling back
# to the older generic one
if (($env:{{ install_dir_env_var }})) {
$force_install_dir = $env:{{ install_dir_env_var }}
$flat_install_layout = {% if install_paths | selectattr("kind", "equalto", "CargoHome") -%} $false {%- else -%} $true {%- endif %}
} elseif (($env:CARGO_DIST_FORCE_INSTALL_DIR)) {
$force_install_dir = $env:CARGO_DIST_FORCE_INSTALL_DIR
$flat_install_layout = {% if install_paths | selectattr("kind", "equalto", "CargoHome") -%} $false {%- else -%} $true {%- endif %}
} elseif ($unmanaged_install) {
$force_install_dir = $unmanaged_install
$flat_install_layout = $true
}

# The actual path we're going to install to
Expand All @@ -267,13 +291,13 @@ function Invoke-Installer($artifacts, $platforms) {
# Before actually consulting the configured install strategy, see
# if we're overriding it.
if (($force_install_dir)) {
{% if install_paths| selectattr("kind", "equalto", "CargoHome") %}
$dest_dir = Join-Path $force_install_dir "bin"
$dest_dir_lib = $dest_dir
{%- else -%}
$dest_dir = $force_install_dir
$dest_dir_lib = $dest_dir
{%- endif %}
if (-not $flat_install_layout) {
$dest_dir = Join-Path $force_install_dir "bin"
$dest_dir_lib = $dest_dir
} else {
$dest_dir = $force_install_dir
$dest_dir_lib = $dest_dir
}
$receipt_dest_dir = $force_install_dir
}
{%- for install_path in install_paths %}
Expand Down Expand Up @@ -361,13 +385,15 @@ function Invoke-Installer($artifacts, $platforms) {
$receipt = $receipt.Replace('"binary_aliases":{}', -join('"binary_aliases":', $info['aliases_json']))

# Write the install receipt
$null = New-Item -Path $receipt_home -ItemType "directory" -ErrorAction SilentlyContinue
# Trying to get Powershell 5.1 (not 6+, which is fake and lies) to write utf8 is a crime
# because "Out-File -Encoding utf8" actually still means utf8BOM, so we need to pull out
# .NET's APIs which actually do what you tell them (also apparently utf8NoBOM is the
# default in newer .NETs but I'd rather not rely on that at this point).
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[IO.File]::WriteAllLines("$receipt_home/{{ app_name }}-receipt.json", "$receipt", $Utf8NoBomEncoding)
if ($install_updater) {
$null = New-Item -Path $receipt_home -ItemType "directory" -ErrorAction SilentlyContinue
# Trying to get Powershell 5.1 (not 6+, which is fake and lies) to write utf8 is a crime
# because "Out-File -Encoding utf8" actually still means utf8BOM, so we need to pull out
# .NET's APIs which actually do what you tell them (also apparently utf8NoBOM is the
# default in newer .NETs but I'd rather not rely on that at this point).
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
[IO.File]::WriteAllLines("$receipt_home/{{ app_name }}-receipt.json", "$receipt", $Utf8NoBomEncoding)
}

# Respect the environment, but CLI takes precedence
if ($null -eq $NoModifyPath) {
Expand Down
Loading

0 comments on commit 9e97a0c

Please sign in to comment.