mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
chore: Add install.sh based installation option (#234)
This commit is contained in:
@@ -54,6 +54,12 @@ Get protected in seconds.
|
||||
|
||||
### 1. Install
|
||||
|
||||
**MacOS / Linux (Install Script)**
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/safedep/pmg/main/install.sh | sh
|
||||
```
|
||||
|
||||
**MacOS / Linux (Homebrew)**
|
||||
|
||||
```bash
|
||||
@@ -66,6 +72,8 @@ brew install safedep/tap/pmg
|
||||
npm install -g @safedep/pmg
|
||||
```
|
||||
|
||||
> **Note:** NPM-based installs can be fragile when Node.js is managed by version managers like [`mise`](https://mise.jdx.dev/) or [`asdf`](https://asdf-vm.com/), since the global `npm` bin path changes with the active Node version. Prefer the install script or Homebrew in those setups.
|
||||
|
||||
> See [Installation](#installation) for additional methods.
|
||||
|
||||
### 2. Setup
|
||||
@@ -140,6 +148,17 @@ PMG supports the tools you already use:
|
||||
|
||||
## Installation
|
||||
|
||||
<details>
|
||||
<summary><strong>Install Script (MacOS/Linux)</strong></summary>
|
||||
|
||||
Downloads the latest release from GitHub, verifies its SHA-256 checksum, and installs to `$HOME/.local/bin` (if on `PATH`) or `/usr/local/bin`.
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/safedep/pmg/main/install.sh | sh
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Homebrew (MacOS/Linux)</strong></summary>
|
||||
|
||||
@@ -157,6 +176,8 @@ brew install safedep/tap/pmg
|
||||
npm install -g @safedep/pmg
|
||||
```
|
||||
|
||||
> **Note:** NPM-based installs can be fragile when Node.js is managed by version managers like [`mise`](https://mise.jdx.dev/) or [`asdf`](https://asdf-vm.com/). The global `npm` bin path changes with the active Node version, so switching versions can leave `pmg` unavailable on `PATH` (or pointing to an old install). For these setups, prefer the install script or Homebrew.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
Executable
+148
@@ -0,0 +1,148 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
do_install() {
|
||||
REPO="safedep/pmg"
|
||||
BINARY="pmg"
|
||||
|
||||
# Prefer $HOME/.local/bin if it exists and is in PATH.
|
||||
INSTALL_DIR="/usr/local/bin"
|
||||
if [ -n "${HOME:-}" ]; then
|
||||
local_bin="$HOME/.local/bin"
|
||||
case ":${PATH}:" in
|
||||
*":${local_bin}:"*)
|
||||
INSTALL_DIR="$local_bin"
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Detect OS and architecture.
|
||||
OS="$(uname -s)"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
case "$OS" in
|
||||
Linux) os="Linux" ;;
|
||||
Darwin) os="Darwin" ;;
|
||||
MINGW* | MSYS* | CYGWIN*) os="Windows" ;;
|
||||
*)
|
||||
echo "Error: unsupported operating system: $OS" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64 | amd64) arch="x86_64" ;;
|
||||
aarch64 | arm64) arch="arm64" ;;
|
||||
i386 | i686) arch="i386" ;;
|
||||
*)
|
||||
echo "Error: unsupported architecture: $ARCH" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# macOS ships a universal binary.
|
||||
if [ "$os" = "Darwin" ]; then
|
||||
arch="all"
|
||||
fi
|
||||
|
||||
if [ "$os" = "Windows" ]; then
|
||||
BINARY="pmg.exe"
|
||||
fi
|
||||
|
||||
# Verify install directory exists.
|
||||
if [ ! -d "$INSTALL_DIR" ]; then
|
||||
echo "Error: install directory ${INSTALL_DIR} does not exist" >&2
|
||||
echo "Create it with: sudo mkdir -p ${INSTALL_DIR}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fetch latest release tag via redirect (avoids JSON parsing).
|
||||
echo "Fetching latest release..."
|
||||
tag=$(curl -fsSI -o /dev/null -w '%{redirect_url}' "https://github.com/${REPO}/releases/latest" | sed 's|.*/||')
|
||||
if [ -z "$tag" ]; then
|
||||
echo "Error: could not determine latest release" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Latest release: $tag"
|
||||
|
||||
# Build download URL.
|
||||
# Assets follow the pattern: pmg_{OS}_{arch}.{tar.gz|zip}
|
||||
if [ "$os" = "Windows" ]; then
|
||||
asset="pmg_${os}_${arch}.zip"
|
||||
else
|
||||
asset="pmg_${os}_${arch}.tar.gz"
|
||||
fi
|
||||
url="https://github.com/${REPO}/releases/download/${tag}/${asset}"
|
||||
|
||||
# Download archive and checksums.
|
||||
echo "Downloading ${asset}..."
|
||||
tmpdir=$(mktemp -d)
|
||||
trap 'rm -rf "$tmpdir"' EXIT
|
||||
checksums_url="https://github.com/${REPO}/releases/download/${tag}/checksums.txt"
|
||||
if ! curl -fsSL -o "${tmpdir}/${asset}" "$url"; then
|
||||
echo "Error: archive not available for ${os}/${arch}" >&2
|
||||
echo "Check available assets at https://github.com/${REPO}/releases/tag/${tag}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! curl -fsSL -o "${tmpdir}/checksums.txt" "$checksums_url"; then
|
||||
echo "Error: could not download checksums.txt from ${checksums_url}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify SHA-256 checksum.
|
||||
expected=$(grep " ${asset}$" "${tmpdir}/checksums.txt" | cut -d' ' -f1)
|
||||
if [ -z "$expected" ]; then
|
||||
echo "Error: no checksum entry found for ${asset} in checksums.txt" >&2
|
||||
exit 1
|
||||
fi
|
||||
if command -v sha256sum >/dev/null 2>&1; then
|
||||
actual=$(sha256sum "${tmpdir}/${asset}" | cut -d' ' -f1)
|
||||
elif command -v shasum >/dev/null 2>&1; then
|
||||
actual=$(shasum -a 256 "${tmpdir}/${asset}" | cut -d' ' -f1)
|
||||
else
|
||||
echo "Error: neither sha256sum nor shasum found; cannot verify download" >&2
|
||||
echo " Install one of them and re-run, or download manually from:" >&2
|
||||
echo " https://github.com/${REPO}/releases/tag/${tag}" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$actual" != "$expected" ]; then
|
||||
echo "Error: checksum mismatch for ${asset}" >&2
|
||||
echo " expected: $expected" >&2
|
||||
echo " actual: $actual" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Checksum verified."
|
||||
|
||||
if [ "$os" = "Windows" ]; then
|
||||
unzip -q -o "${tmpdir}/${asset}" "${BINARY}" -d "${tmpdir}"
|
||||
else
|
||||
tar -xzf "${tmpdir}/${asset}" -C "${tmpdir}" "${BINARY}"
|
||||
fi
|
||||
|
||||
if [ ! -f "${tmpdir}/${BINARY}" ]; then
|
||||
echo "Error: ${BINARY} not found in archive" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install.
|
||||
if [ -w "$INSTALL_DIR" ]; then
|
||||
install -m 755 "${tmpdir}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||
else
|
||||
echo "Installing to ${INSTALL_DIR} (requires sudo)..."
|
||||
sudo install -m 755 "${tmpdir}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
|
||||
fi
|
||||
|
||||
echo "Installed pmg ${tag} to ${INSTALL_DIR}/${BINARY}"
|
||||
|
||||
# Verify the install directory is in PATH.
|
||||
case ":${PATH}:" in
|
||||
*":${INSTALL_DIR}:"*) ;;
|
||||
*)
|
||||
echo "Warning: ${INSTALL_DIR} is not in your PATH. Add it with:" >&2
|
||||
echo " export PATH=\"${INSTALL_DIR}:\$PATH\"" >&2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
do_install
|
||||
Reference in New Issue
Block a user