Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,10 @@

Write-Host "Installed envx $version to $exe"
Update-UserPath $true

# An older manual install earlier on PATH would keep running instead.
$found = Get-Command envx -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
if ($onWindows -and $found -and $found.Source -ine $exe) {
Write-Warning "Another envx at $($found.Source) comes first on PATH and will run instead. See https://envx.sh/docs/windows#migrate"
}
}
7 changes: 6 additions & 1 deletion src/commands/auth/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ pub async fn command(args: Args, config: &mut Config) -> anyhow::Result<()> {
bail!("Key does not have a UUID, try `envx upload`");
}

let identity = format!(
"{} ({})",
crate::utils::messaging::safe(&key.primary_user_id),
key.fingerprint.chars().take(8).collect::<String>()
);
let key = key.unlock(&password);

let client = reqwest::Client::new();
Expand All @@ -47,7 +52,7 @@ pub async fn command(args: Args, config: &mut Config) -> anyhow::Result<()> {
let status = res.status();

if status.is_success() {
println!("Authenticated successfully.");
println!("Authenticated as {identity}");
if args.debug || args.verbose {
println!("{}", crate::utils::messaging::safe(&res.text().await?));
}
Expand Down
50 changes: 50 additions & 0 deletions src/commands/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,23 @@ async fn run_installer(script: &str) -> Result<()> {
async fn run_installer(script: &str) -> Result<()> {
let exe = std::env::current_exe()?;
let dir = exe.parent().context("Executable has no parent folder")?;
let standard = std::env::var("LOCALAPPDATA").ok().map(|local| {
std::path::Path::new(&local).join("Programs").join("envx")
});
if let Some(standard) = standard {
if !same_windows_dir(
&dir.to_string_lossy(),
&standard.to_string_lossy(),
) {
eprintln!(
"{} envx is installed in {}, not the standard {}.\nUpdating it in place. To move it, see {}",
"Warning:".yellow().bold(),
dir.display(),
standard.display(),
WINDOWS_MIGRATE_URL,
);
}
}
let path = std::env::temp_dir()
.join(format!("envx-install-{}.ps1", uuid::Uuid::new_v4()));
std::fs::write(&path, script)?;
Expand Down Expand Up @@ -153,6 +170,39 @@ async fn run_installer(script: &str) -> Result<()> {
Ok(())
}

#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
const WINDOWS_MIGRATE_URL: &str = "https://envx.sh/docs/windows#migrate";

/// Windows paths compare case-insensitively and ignore trailing separators.
#[cfg_attr(not(target_os = "windows"), allow(dead_code))]
fn same_windows_dir(a: &str, b: &str) -> bool {
let normalize = |p: &str| {
p.trim_start_matches(r"\\?\")
.replace('/', r"\")
.trim_end_matches('\\')
.to_lowercase()
};
normalize(a) == normalize(b)
}

#[cfg(test)]
mod windows_path_tests {
use super::same_windows_dir;
#[test]
fn standard_location_matches_regardless_of_case_and_separators() {
let standard = r"C:\Users\a\AppData\Local\Programs\envx";
assert!(same_windows_dir(
r"c:\users\A\appdata\local\programs\envx\",
standard
));
assert!(same_windows_dir(
r"\\?\C:\Users\a\AppData\Local\Programs\envx",
standard
));
assert!(!same_windows_dir(r"C:\envx", standard));
}
}

#[cfg(all(test, not(target_os = "windows")))]
mod tests {
use super::*;
Expand Down
3 changes: 2 additions & 1 deletion tests/human_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import json
import os
from pathlib import Path
import re
import shlex
import sqlite3
import subprocess
Expand Down Expand Up @@ -94,7 +95,7 @@ def do_DELETE(self):
assert "From Teammate (@account)" in run("inbox")
assert "Teammate (@account) · 22222222 · trusted" in run("friends")
assert "Fingerprint: pin" in run("friends", "--verbose")
assert run("auth").strip() == "Authenticated successfully."
assert re.fullmatch(r"Authenticated as .+ \([0-9a-f]{8}\)", run("auth").strip())
assert "server response" in run("auth", "--verbose")
for flags in [[], ["--verbose"], ["--json"]]:
output = run("project", "remove-user", "--project-id", PROJECT, "--user-id", PEER, "--yes", *flags)
Expand Down
Loading