Compare commits

..

5 Commits

Author SHA1 Message Date
veeso f54c50f6ef chore: release v1.2.0 2026-09-03 11:57:52 +00:00
Christian Visintin 325c8ceee7 ci(release): add dprint 2026-09-03 13:57:03 +02:00
Christian Visintin ebfaeb956c chore(release): release 1.2.0 (#448) 2026-09-03 13:44:07 +02:00
Christian Visintin 133ec898d8 ci(release): build Linux artifacts as static musl binaries (#447)
Build Linux release artifacts as statically linked musl binaries for x86_64 and aarch64, update packaging and updater handling, and document the reduced runtime requirements.

Keep release version preparation locked without refreshing dependencies or committing Cargo.lock.

Closes #440
2026-09-03 13:31:16 +02:00
Christian Visintin 1587d3d625 build: bump remotefs-smb 0.5.0 (#446)
CI / toolchain (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / install-scripts (push) Has been cancelled
Install.sh / build (ubuntu-latest) (push) Has been cancelled
Install.sh / build (macos-latest) (push) Has been cancelled
Site / build-site (push) Has been cancelled
CI / crates-macos-latest (push) Has been cancelled
CI / crates-ubuntu-latest (push) Has been cancelled
CI / crates-windows-latest (push) Has been cancelled
CI / doc (push) Has been cancelled
CI / deny (push) Has been cancelled
* build: bump remotefs-smb 0.5.0

* fix(smb): windows build
2026-09-03 10:20:33 +02:00
22 changed files with 540 additions and 227 deletions
-154
View File
@@ -1,154 +0,0 @@
name: Linux musl probe
on:
push:
branches:
- "test/440-musl-release"
paths:
- ".github/workflows/musl.yml"
- "Cargo.lock"
- "Cargo.toml"
- "src/**"
workflow_dispatch:
permissions:
contents: read
jobs:
build:
name: build-${{ matrix.target }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-musl
runner: ubuntu-24.04
- target: aarch64-unknown-linux-musl
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Build and audit static binary
env:
TARGET: ${{ matrix.target }}
run: |
docker run --rm \
--env TARGET \
--volume "$GITHUB_WORKSPACE:/work" \
--workdir /work \
rust:1.98-alpine3.22 \
sh -euxc '
apk add --no-cache \
bison \
binutils \
build-base \
file \
flex \
git \
gnutls-dev \
libgit2-dev \
libgit2-static \
libunistring-dev \
libunistring-static \
linux-headers \
openssl-dev \
openssl-libs-static \
perl \
perl-parse-yapp \
pkgconf \
python3 \
wget \
xz \
zlib-dev \
zlib-static
rustup target add "$TARGET"
cargo fetch --locked
NATIVE_CFLAGS="-O2 -fPIC"
if [ "$TARGET" = "aarch64-unknown-linux-musl" ]; then
NATIVE_CFLAGS="$NATIVE_CFLAGS -mno-outline-atomics"
fi
export CFLAGS="$NATIVE_CFLAGS"
mkdir -p /tmp/native
wget -q https://ftp.gnu.org/gnu/nettle/nettle-3.10.1.tar.gz \
-O /tmp/native/nettle.tar.gz
tar -xzf /tmp/native/nettle.tar.gz -C /tmp/native
cd /tmp/native/nettle-3.10.1
./configure \
--prefix=/tmp/native/nettle \
--disable-shared \
--enable-static \
--disable-documentation \
--enable-mini-gmp
make -j$(getconf _NPROCESSORS_ONLN)
make install
wget -q https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-3.8.13.tar.xz \
-O /tmp/native/gnutls.tar.xz
tar -xf /tmp/native/gnutls.tar.xz -C /tmp/native
cd /tmp/native/gnutls-3.8.13
PKG_CONFIG_PATH=/tmp/native/nettle/lib/pkgconfig \
./configure \
--prefix=/tmp/native/gnutls \
--disable-shared \
--enable-static \
--disable-doc \
--disable-tests \
--disable-nls \
--disable-hardware-acceleration \
--with-nettle-mini \
--with-included-libtasn1 \
--with-included-unistring \
--without-idn \
--without-p11-kit \
--without-brotli \
--without-zstd \
--without-zlib
make -j$(getconf _NPROCESSORS_ONLN)
make install
mkdir -p /tmp/native/pkgconfig
sed \
-e "s#^Libs:.*#Libs: -L/tmp/native/gnutls/lib -lgnutls -latomic -L/tmp/native/nettle/lib -lhogweed -lnettle#" \
-e "/^Requires.private:/d" \
-e "s#^Cflags:.*#Cflags: -I/tmp/native/gnutls/include -I/tmp/native/nettle/include#" \
/tmp/native/gnutls/lib/pkgconfig/gnutls.pc \
> /tmp/native/pkgconfig/gnutls.pc
cd /work
PAVAO_SRC=$(find "${CARGO_HOME:-/usr/local/cargo}/registry/src" \
-type d -name "pavao-src-4.24.6" -print -quit)
test -n "$PAVAO_SRC"
cp -R "$PAVAO_SRC" /tmp/pavao-src
perl -0pi -e "s#( \\\"lib/replace/replace\\.c\\\",\\n)#\$1 \\\"lib/replace/closefrom.c\\\",\\n \\\"lib/replace/strptime.c\\\",\\n#" \
/tmp/pavao-src/src/lib.rs
cat >> Cargo.toml <<EOF
[patch.crates-io]
pavao-src = { path = "/tmp/pavao-src" }
EOF
cargo update -p pavao-src@4.24.6
export PKG_CONFIG_ALL_STATIC=1
export PKG_CONFIG_PATH=/tmp/native/pkgconfig:/tmp/native/nettle/lib/pkgconfig:/usr/lib/pkgconfig
export RUSTFLAGS="-C target-feature=+crt-static -C link-arg=-static"
cargo build --locked --release --target "$TARGET" \
--features smb-vendored
file "target/$TARGET/release/termscp"
readelf -l "target/$TARGET/release/termscp" | \
tee /tmp/program-headers.txt
readelf -d "target/$TARGET/release/termscp" | \
tee /tmp/dynamic-section.txt
! grep -q INTERP /tmp/program-headers.txt
! grep -q NEEDED /tmp/dynamic-section.txt
'
- name: Upload verified binary
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.target }}
path: target/${{ matrix.target }}/release/termscp
if-no-files-found: error
retention-days: 7
+62 -53
View File
@@ -21,6 +21,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
version: ${{ inputs.version }}
prepared_ref: ${{ steps.prepared-ref.outputs.ref }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
@@ -44,9 +45,9 @@ jobs:
git config user.email "christian.visintin@veeso.dev"
- name: Install git-cliff
uses: taiki-e/install-action@37f7c5781271959fb65b6b35224e28652ff2b63d # v2.87.0
uses: taiki-e/install-action@e67fa11c4b9316fa714ddf0abed07a0c3143b95b # v2.87.4
with:
tool: git-cliff
tool: git-cliff,dprint
- name: Install just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
@@ -66,6 +67,9 @@ jobs:
VERSION: ${{ inputs.version }}
run: git-cliff --unreleased --tag "v$VERSION" --strip header -o RELEASE_NOTES.md
- name: Verify Cargo.lock is unchanged
run: git diff --exit-code -- Cargo.lock
- name: Upload release notes
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
@@ -84,10 +88,22 @@ jobs:
VERSION: ${{ inputs.version }}
run: |
rm -f RELEASE_NOTES.md
git add -A
git add -A -- . ':!Cargo.lock'
git diff --cached --exit-code -- Cargo.lock
git commit -m "chore: release v$VERSION"
git push origin HEAD:main
- name: Export prepared ref
id: prepared-ref
env:
DRY_RUN: ${{ inputs.dry_run }}
run: |
if [ "$DRY_RUN" = "true" ]; then
echo "ref=$GITHUB_SHA" >> "$GITHUB_OUTPUT"
else
echo "ref=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
fi
build:
needs: prepare
name: build-${{ matrix.target }}
@@ -95,14 +111,12 @@ jobs:
fail-fast: false
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
- target: x86_64-unknown-linux-musl
os: ubuntu-24.04
kind: linux
deb_suffix: amd64
- target: aarch64-unknown-linux-gnu
- target: aarch64-unknown-linux-musl
os: ubuntu-24.04-arm
kind: linux
deb_suffix: arm64
- target: aarch64-apple-darwin
os: macos-latest
kind: macos
@@ -125,58 +139,44 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs.dry_run && github.sha || 'main' }}
ref: ${{ needs.prepare.outputs.prepared_ref }}
persist-credentials: false
fetch-depth: 0
fetch-tags: true
- name: Prepare release version
shell: bash
run: |
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
cargo update --package termscp --precise "$VERSION"
cargo metadata --locked --no-deps --format-version 1 > /dev/null
- name: Install just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
- name: Install Rust target
if: matrix.kind != 'windows'
if: matrix.kind == 'macos'
run: rustup target add "$TARGET"
- name: Install Rust target
if: matrix.kind == 'windows'
run: rustup target add "$env:TARGET"
# ---- Linux: native per-arch build (x86_64 on ubuntu-latest, aarch64 on ubuntu-24.04-arm) ----
- name: Install dependencies (Linux)
# ---- Linux: static musl build in a pinned Alpine container ----
- name: Install cargo-deb (Linux)
if: matrix.kind == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y \
make \
libgit2-dev \
build-essential \
pkg-config \
libbsd-dev \
libcap-dev \
libcups2-dev \
libgnutls28-dev \
libicu-dev \
libjansson-dev \
libkeyutils-dev \
libldap2-dev \
zlib1g-dev \
libpam0g-dev \
libacl1-dev \
libarchive-dev \
flex \
bison \
libntirpc-dev \
libtracker-sparql-3.0-dev \
libglib2.0-dev \
libdbus-1-dev \
libsasl2-dev \
libunistring-dev \
cpanminus
sudo cpanm Parse::Yapp::Driver
cargo install cargo-deb
run: cargo install cargo-deb --locked
- name: Build (Linux)
if: matrix.kind == 'linux'
run: just build_release "$TARGET" "--features smb-vendored"
run: just build_musl "$TARGET"
- name: Build deb (Linux)
if: matrix.kind == 'linux'
run: just package_deb "$TARGET"
run: cargo deb --locked --no-build --target "$TARGET" --features smb-vendored
- name: Verify deb declares no runtime dependencies (Linux)
if: matrix.kind == 'linux'
run: |
deb=$(ls target/"$TARGET"/debian/*.deb)
depends=$(dpkg-deb -f "$deb" Depends)
if [ -n "$depends" ]; then
echo "static deb must have no Depends, got: $depends" >&2
exit 1
fi
# ---- macOS ----
- name: Install deps (macOS)
@@ -229,7 +229,7 @@ jobs:
if-no-files-found: error
publish-homebrew:
needs: [prepare, build]
needs: [prepare, build, release]
runs-on: ubuntu-latest
env:
VERSION: ${{ needs.prepare.outputs.version }}
@@ -255,8 +255,8 @@ jobs:
cd "$GITHUB_WORKSPACE"
SHA_MAC_ARM=$(cat dl/aarch64-apple-darwin.sha256)
SHA_MAC_X64=$(cat dl/x86_64-apple-darwin.sha256)
SHA_LIN_ARM=$(cat dl/aarch64-unknown-linux-gnu.sha256)
SHA_LIN_X64=$(cat dl/x86_64-unknown-linux-gnu.sha256)
SHA_LIN_ARM=$(cat dl/aarch64-unknown-linux-musl.sha256)
SHA_LIN_X64=$(cat dl/x86_64-unknown-linux-musl.sha256)
BASE="https://github.com/veeso/termscp/releases/latest/download"
cat > tap/Formula/termscp.rb <<EOF
class Termscp < Formula
@@ -293,14 +293,12 @@ jobs:
end
on_linux do
depends_on "dbus"
on_arm do
url "$BASE/termscp-v$VERSION-aarch64-unknown-linux-gnu.tar.gz"
url "$BASE/termscp-v$VERSION-aarch64-unknown-linux-musl.tar.gz"
sha256 "$SHA_LIN_ARM"
end
on_intel do
url "$BASE/termscp-v$VERSION-x86_64-unknown-linux-gnu.tar.gz"
url "$BASE/termscp-v$VERSION-x86_64-unknown-linux-musl.tar.gz"
sha256 "$SHA_LIN_X64"
end
end
@@ -336,9 +334,15 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
token: ${{ secrets.RELEASE_PAT }}
ref: ${{ inputs.dry_run && github.sha || 'main' }}
ref: ${{ needs.prepare.outputs.prepared_ref }}
persist-credentials: true
- name: Prepare release version
run: |
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
cargo update --package termscp --precise "$VERSION"
cargo metadata --locked --no-deps --format-version 1 > /dev/null
- name: Download build artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
@@ -399,10 +403,15 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: main
ref: ${{ needs.prepare.outputs.prepared_ref }}
persist-credentials: false
fetch-depth: 0
fetch-tags: true
- name: Prepare release version
run: |
dist/release/bump_version.sh "$VERSION" "$(date +%F)"
cargo update --package termscp --precise "$VERSION"
cargo metadata --locked --no-deps --format-version 1 > /dev/null
- name: Install just
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
+158
View File
@@ -1,5 +1,163 @@
# Changelog
## 1.2.0
Released on 2026-09-03
### Added
- **site:** add privacy policy page (#435)
> Add a GDPR privacy policy covering Vercel hosting/server logs and
> EU-hosted Umami analytics, and link it from the footer.
- **gcs:** add Google Cloud Storage support (#443)
> - feat(gcs): add Google Cloud Storage support
- add support for all ssh2 config parameters.
> Achieved by bumping `remotefs-ssh` to `0.9`.
>
> Added support for these parameters:
>
> - Compression
> - Host key certificates
> - CA signature algorithms
> - keys to agents
> - ProxyJump
> - Server alive intervals
> - Agent forwarding
> - Remote forwarding
> - Bind address
> - Bind interface
> - Connection attempts
> - TCP Keepalive
> - Accepted public key algos
> - Certificate files
- **ssh:** auto-fill ssh config parameters in auth form
> Resolve SSH host parameters in auth forms and CLI connections while preserving explicit user, bookmark, and parsed alias values. Continue forwarding SSH config files for HostName and other SSH options, and document the precedence in English and Chinese.
- **smb:** add SMB dialect selection and persistence (#445)
> Support Auto, SMB1, SMB2, and SMB3 selection on Unix, bound negotiation to the selected dialect family, preserve legacy bookmarks as Auto, and document the new option. Windows keeps operating-system-managed negotiation.
### CI
- remove Codeberg mirror workflow. I do not support Codeberg mission anymore
- migrate project automation to Just (#442)
> - ci: migrate project automation to Just
>
> Centralize build, test, release, dependency, hook, and website commands in Just recipes. Pin workflow tooling, use the repository toolchain, and run the complete validation set in CI.
>
> - ci: codex being codex
> - docs: update CLAUDE.md for just task runner migration
>
> Reflect the switch to just recipes for build/test/clippy/fmt, note
> dprint replacing raw rustfmt, and add a cross-platform code requirement.
>
> - fix: resolve clippy warnings breaking CI on ubuntu and windows
>
> Use clone() instead of implicit to_string() on already-owned String
> values, gate the windows-only unused make_file_at import behind
> cfg(posix), and fix unused mut / manual assign-op in the windows-only
> localhost test.
>
> - fix: fmt
- **release:** build Linux artifacts as static musl binaries (#447)
> Build Linux release artifacts as statically linked musl binaries for x86_64 and aarch64, update packaging and updater handling, and document the reduced runtime requirements.
>
> Keep release version preparation locked without refreshing dependencies or committing Cargo.lock.
- **release:** add dprint
### Fixed
- **publish:** anchor include globs to crate root
> Unanchored include patterns (LICENSE, README.md) matched at any depth
> via gitignore-glob semantics, pulling 437 site/node_modules files into
> the package and breaking cargo publish's dirty check.
- print actual reason for failed host params collecting
> previously, we didn't show any reason for failed collecting of host params in the auth form, but just a generic message
### Build
- **deps:** update aes-gcm to 0.11
> Migrate nonce generation and parsing to the aes-gcm 0.11 API while preserving the encrypted payload format.
- bump remotefs-smb 0.5.0 (#446)
> - build: bump remotefs-smb 0.5.0
> - fix(smb): windows build
## 1.2.0
Released on 2026-09-03
### Added
- **site:** add privacy policy page (#435)
> Add a GDPR privacy policy covering Vercel hosting/server logs and
> EU-hosted Umami analytics, and link it from the footer.
- **gcs:** add Google Cloud Storage support (#443)
> - feat(gcs): add Google Cloud Storage support
- add support for all ssh2 config parameters.
> Achieved by bumping `remotefs-ssh` to `0.9`.
>
> Added support for these parameters:
>
> - Compression
> - Host key certificates
> - CA signature algorithms
> - keys to agents
> - ProxyJump
> - Server alive intervals
> - Agent forwarding
> - Remote forwarding
> - Bind address
> - Bind interface
> - Connection attempts
> - TCP Keepalive
> - Accepted public key algos
> - Certificate files
- **ssh:** auto-fill ssh config parameters in auth form
> Resolve SSH host parameters in auth forms and CLI connections while preserving explicit user, bookmark, and parsed alias values. Continue forwarding SSH config files for HostName and other SSH options, and document the precedence in English and Chinese.
- **smb:** add SMB dialect selection and persistence (#445)
> Support Auto, SMB1, SMB2, and SMB3 selection on Unix, bound negotiation to the selected dialect family, preserve legacy bookmarks as Auto, and document the new option. Windows keeps operating-system-managed negotiation.
### CI
- migrate project automation to Just (#442)
> - ci: migrate project automation to Just
>
> Centralize build, test, release, dependency, hook, and website commands in Just recipes. Pin workflow tooling, use the repository toolchain, and run the complete validation set in CI.
>
> - ci: codex being codex
> - docs: update CLAUDE.md for just task runner migration
>
> Reflect the switch to just recipes for build/test/clippy/fmt, note
> dprint replacing raw rustfmt, and add a cross-platform code requirement.
>
> - fix: resolve clippy warnings breaking CI on ubuntu and windows
>
> Use clone() instead of implicit to_string() on already-owned String
> values, gate the windows-only unused make_file_at import behind
> cfg(posix), and fix unused mut / manual assign-op in the windows-only
> localhost test.
>
> - fix: fmt
- **release:** build Linux artifacts as static musl binaries (#447)
> Build Linux release artifacts as statically linked musl binaries for x86_64 and aarch64, update packaging and updater handling, and document the reduced runtime requirements.
>
> Keep release version preparation locked without refreshing dependencies or committing Cargo.lock.
### Fixed
- **publish:** anchor include globs to crate root
> Unanchored include patterns (LICENSE, README.md) matched at any depth
> via gitignore-glob semantics, pulling 437 site/node_modules files into
> the package and breaking cargo publish's dirty check.
- print actual reason for failed host params collecting
> previously, we didn't show any reason for failed collecting of host params in the auth form, but just a generic message
### Build
- **deps:** update aes-gcm to 0.11
> Migrate nonce generation and parsing to the aes-gcm 0.11 API while preserving the encrypted payload format.
- bump remotefs-smb 0.5.0 (#446)
> - build: bump remotefs-smb 0.5.0
> - fix(smb): windows build
## 1.1.1
Released on 2026-06-08
Generated
+5 -5
View File
@@ -3487,9 +3487,9 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
[[package]]
name = "lru"
version = "0.18.3"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d317b4b9eb398e6acce275758ec6125535505e7a146fb1a9b8bda2451b0ff4c"
checksum = "ff9840bcc50b71349309900da0ce7279aa336ae71d73250b07998932c7d97c25"
dependencies = [
"hashbrown 0.17.1",
]
@@ -4908,9 +4908,9 @@ dependencies = [
[[package]]
name = "remotefs-smb"
version = "0.5.0"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31220bffe8a75a01411fab30d90270ce40a8fdf021521a9c9f2cfecc6a29f5d5"
checksum = "63d9b82c3ca50c6a7cbc923b286192178a6c675476802524e37b41a27c414c57"
dependencies = [
"filetime",
"libc",
@@ -6256,7 +6256,7 @@ dependencies = [
[[package]]
name = "termscp"
version = "1.1.1"
version = "1.2.0"
dependencies = [
"aes 0.9.3",
"aes-gcm",
+2 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "termscp"
version = "1.1.1"
version = "1.2.0"
authors = ["Christian Visintin <christian.visintin@veeso.dev>"]
categories = ["command-line-utilities"]
edition = "2024"
@@ -25,6 +25,7 @@ termscp = { path = "/usr/bin/termscp" }
[package.metadata.deb]
maintainer = "Christian Visintin <christian.visintin@veeso.dev>"
copyright = "2025, Christian Visintin <christian.visintin@veeso.dev>"
depends = ""
extended-description-file = "docs/misc/README.deb.txt"
[features]
+6
View File
@@ -117,6 +117,12 @@ For more information or other platforms, please visit [termscp.rs](https://terms
### Requirements ❗
The official Linux binaries and `.deb` packages are statically linked against
musl and have **no runtime requirements**: they run on any distribution and
any glibc version.
These are only required to build termscp from source:
- **Linux** users:
- libdbus-1
- pkg-config
+1 -1
View File
@@ -3,7 +3,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2015/06/nuspec.xsd">
<metadata>
<id>termscp</id>
<version>1.1.1</version>
<version>1.2.0</version>
<title>termSCP</title>
<authors>Christian Visintin</authors>
<owners>Christian Visintin</owners>
+2 -2
View File
@@ -5,10 +5,10 @@ $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)"
$is_arm64 = $env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64'
if ($is_arm64) {
$url = 'https://github.com/veeso/termscp/releases/download/v1.1.1/termscp-v1.1.1-msvc.zip'
$url = 'https://github.com/veeso/termscp/releases/download/v1.2.0/termscp-v1.2.0-msvc.zip'
$checksum = 'f6ad6c62f1578562f9af4bcee93bd4cc429cb52219c3636359b008db8789587e'
} else {
$url = 'https://github.com/veeso/termscp/releases/download/v1.1.1/termscp-v1.1.1-x86_64-pc-windows-msvc.zip'
$url = 'https://github.com/veeso/termscp/releases/download/v1.2.0/termscp-v1.2.0-x86_64-pc-windows-msvc.zip'
$checksum = 'd7796081b6f67b82acfa94557aa6852d12a33daab3cca6490660b20e42752005'
}
Vendored Executable
+52
View File
@@ -0,0 +1,52 @@
#!/usr/bin/env sh
# Builds a static musl termscp release binary for the given target triple
# inside a pinned Alpine container.
#
# Usage: dist/release/build_musl.sh <target-triple>
set -eu
IMAGE="rust:1.98-alpine3.22"
TARGET="${1:-}"
if [ -z "$TARGET" ]; then
echo "usage: $0 <target-triple>" >&2
exit 2
fi
case "$TARGET" in
x86_64-unknown-linux-musl) PLATFORM="linux/amd64" ;;
aarch64-unknown-linux-musl) PLATFORM="linux/arm64" ;;
*)
echo "unsupported target: $TARGET" >&2
exit 2
;;
esac
WORKSPACE="$(CDPATH='' cd -- "$(dirname -- "$0")/../.." && pwd)"
# The container appends a [patch.crates-io] section to Cargo.toml and updates
# Cargo.lock; keep byte-exact copies so the workspace is clean afterwards.
BACKUP_DIR="$(mktemp -d)"
cp -p "$WORKSPACE/Cargo.toml" "$BACKUP_DIR/Cargo.toml"
cp -p "$WORKSPACE/Cargo.lock" "$BACKUP_DIR/Cargo.lock"
restore_manifests() {
cp -p "$BACKUP_DIR/Cargo.toml" "$WORKSPACE/Cargo.toml"
cp -p "$BACKUP_DIR/Cargo.lock" "$WORKSPACE/Cargo.lock"
rm -rf "$BACKUP_DIR"
}
trap restore_manifests EXIT
HOST_UID="$(id -u)"
HOST_GID="$(id -g)"
export TARGET HOST_UID HOST_GID
docker run --rm \
--platform "$PLATFORM" \
--env TARGET \
--env HOST_UID \
--env HOST_GID \
--volume "$WORKSPACE:/work" \
--workdir /work \
"$IMAGE" \
sh /work/dist/release/build_musl_container.sh
+143
View File
@@ -0,0 +1,143 @@
#!/usr/bin/env sh
# Builds a static musl termscp binary. Runs INSIDE the Alpine container
# started by dist/release/build_musl.sh; /work is the mounted workspace.
#
# Required environment: TARGET, HOST_UID, HOST_GID.
set -eux
NETTLE_VERSION="3.10.1"
GNUTLS_VERSION="3.8.13"
PAVAO_SRC_VERSION="4.24.6"
cleanup() {
chown -R "$HOST_UID:$HOST_GID" /work
}
trap cleanup EXIT
apk add --no-cache \
bison \
binutils \
build-base \
file \
flex \
git \
gnutls-dev \
libgit2-dev \
libgit2-static \
libunistring-dev \
libunistring-static \
linux-headers \
openssl-dev \
openssl-libs-static \
perl \
perl-parse-yapp \
pkgconf \
python3 \
wget \
xz \
zlib-dev \
zlib-static
rustup target add "$TARGET"
cargo fetch --locked
NATIVE_CFLAGS="-O2 -fPIC"
if [ "$TARGET" = "aarch64-unknown-linux-musl" ]; then
NATIVE_CFLAGS="$NATIVE_CFLAGS -mno-outline-atomics"
fi
export CFLAGS="$NATIVE_CFLAGS"
# -- static nettle (GnuTLS crypto backend); mini-gmp avoids a GMP dependency
mkdir -p /tmp/native
wget -q "https://ftp.gnu.org/gnu/nettle/nettle-$NETTLE_VERSION.tar.gz" \
-O /tmp/native/nettle.tar.gz
tar -xzf /tmp/native/nettle.tar.gz -C /tmp/native
cd "/tmp/native/nettle-$NETTLE_VERSION"
./configure \
--prefix=/tmp/native/nettle \
--disable-shared \
--enable-static \
--disable-documentation \
--enable-mini-gmp
make -j"$(getconf _NPROCESSORS_ONLN)"
make install
# -- static GnuTLS; every optional backend is disabled so nothing links
# against a shared library
wget -q "https://www.gnupg.org/ftp/gcrypt/gnutls/v3.8/gnutls-$GNUTLS_VERSION.tar.xz" \
-O /tmp/native/gnutls.tar.xz
tar -xf /tmp/native/gnutls.tar.xz -C /tmp/native
cd "/tmp/native/gnutls-$GNUTLS_VERSION"
PKG_CONFIG_PATH=/tmp/native/nettle/lib/pkgconfig \
./configure \
--prefix=/tmp/native/gnutls \
--disable-shared \
--enable-static \
--disable-doc \
--disable-tests \
--disable-nls \
--disable-hardware-acceleration \
--with-nettle-mini \
--with-included-libtasn1 \
--with-included-unistring \
--without-idn \
--without-p11-kit \
--without-brotli \
--without-zstd \
--without-zlib
make -j"$(getconf _NPROCESSORS_ONLN)"
make install
# -- flatten gnutls.pc: pkg-config must hand the linker the static archives
# directly, with no Requires.private chain to resolve
mkdir -p /tmp/native/pkgconfig
sed \
-e "s#^Libs:.*#Libs: -L/tmp/native/gnutls/lib -lgnutls -latomic -L/tmp/native/nettle/lib -lhogweed -lnettle#" \
-e "/^Requires.private:/d" \
-e "s#^Cflags:.*#Cflags: -I/tmp/native/gnutls/include -I/tmp/native/nettle/include#" \
/tmp/native/gnutls/lib/pkgconfig/gnutls.pc \
> /tmp/native/pkgconfig/gnutls.pc
# -- pavao-src: Samba's replacement library omits two sources that musl needs
cd /work
PAVAO_SRC=$(find "${CARGO_HOME:-/usr/local/cargo}/registry/src" \
-type d -name "pavao-src-$PAVAO_SRC_VERSION" -print -quit)
test -n "$PAVAO_SRC"
cp -R "$PAVAO_SRC" /tmp/pavao-src
perl -0pi -e "s#( \\\"lib/replace/replace\\.c\\\",\\n)#\$1 \\\"lib/replace/closefrom.c\\\",\\n \\\"lib/replace/strptime.c\\\",\\n#" \
/tmp/pavao-src/src/lib.rs
cat >> Cargo.toml <<EOF
[patch.crates-io]
pavao-src = { path = "/tmp/pavao-src" }
EOF
cargo update -p "pavao-src@$PAVAO_SRC_VERSION"
export PKG_CONFIG_ALL_STATIC=1
export PKG_CONFIG_PATH=/tmp/native/pkgconfig:/tmp/native/nettle/lib/pkgconfig:/usr/lib/pkgconfig
export RUSTFLAGS="-C target-feature=+crt-static -C link-arg=-static"
cargo build --locked --release --target "$TARGET" --features smb-vendored
# -- prove the binary is static: no interpreter, no shared libraries
file "target/$TARGET/release/termscp"
if readelf -l "target/$TARGET/release/termscp" > /tmp/program-headers.txt; then
cat /tmp/program-headers.txt
else
status=$?
cat /tmp/program-headers.txt
exit "$status"
fi
if readelf -d "target/$TARGET/release/termscp" > /tmp/dynamic-section.txt; then
cat /tmp/dynamic-section.txt
else
status=$?
cat /tmp/dynamic-section.txt
exit "$status"
fi
if grep -q INTERP /tmp/program-headers.txt; then
exit 1
fi
if grep -q NEEDED /tmp/dynamic-section.txt; then
exit 1
fi
+20 -1
View File
@@ -44,9 +44,28 @@ Install termscp from the official repositories:
pacman -S termscp
```
## Official binaries
Official release binaries are published for these targets:
- GNU/Linux:
- `x86_64-unknown-linux-musl`
- `aarch64-unknown-linux-musl`
- macOS:
- `x86_64-apple-darwin`
- `aarch64-apple-darwin`
- Windows:
- `x86_64-pc-windows-msvc`
- `aarch64-pc-windows-msvc`
The Linux binaries, and the `.deb` package built from them, are statically
linked against musl. They have no runtime dependencies: they run on any Linux
distribution and any glibc version, with no system packages to install.
## Requirements
The following system dependencies are required to run termscp.
The official binaries do not require these dependencies. They are needed only
to build termscp from source, for example with `cargo install termscp`:
- Linux users:
- libdbus-1
+4
View File
@@ -117,6 +117,10 @@ pacman -S termscp
### 依赖 ❗
官方 Linux 二进制文件和 `.deb` 包静态链接了 musl,**没有任何运行时依赖**:可在任意发行版、任意 glibc 版本上运行。
以下依赖仅在从源码构建 termscp 时需要:
- **Linux** 用户:
- libdbus-1
- pkg-config
+17 -1
View File
@@ -42,9 +42,25 @@ pkgin install termscp
pacman -S termscp
```
## 官方二进制文件
官方发布的二进制文件支持以下目标:
- GNU/Linux
- `x86_64-unknown-linux-musl`
- `aarch64-unknown-linux-musl`
- macOS
- `x86_64-apple-darwin`
- `aarch64-apple-darwin`
- Windows
- `x86_64-pc-windows-msvc`
- `aarch64-pc-windows-msvc`
Linux 二进制文件以及由其构建的 `.deb` 包都静态链接了 musl。它们没有任何运行时依赖:可在任意 Linux 发行版、任意 glibc 版本上运行,无需安装任何系统软件包。
## 系统要求
运行 termscp 需要以下系统依赖。
官方二进制文件不需要以下依赖。它们仅在从源码构建 termscp 时才需要,例如使用 `cargo install termscp`
- Linux 用户:
- libdbus-1
+1 -1
View File
@@ -26,7 +26,7 @@
#>
[CmdletBinding()]
param(
[string]$Version = "1.1.1",
[string]$Version = "1.2.0",
[string]$InstallDir = "$env:LOCALAPPDATA\Programs\termscp",
[Alias("Yes")]
[switch]$Force
+1 -1
View File
@@ -9,7 +9,7 @@
# -f, -y, --force, --yes
# Skip the confirmation prompt during installation
TERMSCP_VERSION="1.1.1"
TERMSCP_VERSION="1.2.0"
GITHUB_URL="https://github.com/veeso/termscp/releases/download/v${TERMSCP_VERSION}"
DEB_URL_AMD64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}-1_amd64.deb"
DEB_URL_AARCH64="${GITHUB_URL}/termscp_${TERMSCP_VERSION}-1_arm64.deb"
+5
View File
@@ -17,6 +17,11 @@ build_crates_release:
build_release target features="":
cargo build --locked --release --target {{ target }} {{ features }}
# Build a static musl Linux release binary in a pinned Alpine container
[group('build')]
build_musl target:
dist/release/build_musl.sh {{ target }}
# Package an already-built Linux release as a Debian package
[group('build')]
package_deb target:
+1
View File
@@ -42,3 +42,4 @@ changelog version:
rm -f "$secfile"
mv "$tmp" CHANGELOG.md
echo "CHANGELOG.md updated for $tag"
just fmt CHANGELOG.md
+3 -1
View File
@@ -35,7 +35,9 @@ setup_githooks:
[group('code_check')]
check_install_scripts:
sh -n install.sh
shellcheck install.sh
sh -n dist/release/build_musl.sh
sh -n dist/release/build_musl_container.sh
shellcheck install.sh dist/release/build_musl.sh dist/release/build_musl_container.sh
@if command -v pwsh >/dev/null 2>&1; then \
pwsh -NoProfile -Command '$t = $null; $e = $null; $null = [System.Management.Automation.Language.Parser]::ParseFile("install.ps1", [ref]$t, [ref]$e); if ($e) { $e; exit 1 }'; \
else \
+1 -1
View File
@@ -1,3 +1,3 @@
export const DOCS_URL = "https://docs.termscp.rs";
export const GITHUB_URL = "https://github.com/veeso/termscp";
export const VERSION = "1.1.1";
export const VERSION = "1.2.0";
+5 -2
View File
@@ -72,9 +72,12 @@ const methods = [
Update anytime with <span class="text-green">termscp --update</span>.
</p>
<p class="mt-2 text-sm text-overlay">
Linux build deps: <span class="text-text">libdbus-1</span>, <span
Official Linux binaries and .deb packages are statically linked against <span
class="text-text">musl</span
>: no runtime dependencies, any distribution, any glibc version. Building
from source still needs <span class="text-text">libdbus-1</span>, <span
class="text-text">pkg-config</span
>, <span class="text-text">libsmbclient</span>. More details in the <a
> and <span class="text-text">libsmbclient</span>. More details in the <a
href={DOCS_URL}
class="text-blue hover:underline">docs</a
>.
+4 -3
View File
@@ -11,10 +11,11 @@ use remotefs_ftp::FtpFs;
use remotefs_gcs::credentials::service_account;
use remotefs_gcs::{GoogleCloudStorageCredentials, GoogleCloudStorageFs};
use remotefs_kube::KubeMultiPodFs as KubeFs;
#[cfg(smb)]
use remotefs_smb::{PavaoSmbCredentials as SmbCredentials, PavaoSmbFs as SmbFs};
#[cfg(smb_unix)]
use remotefs_smb::{PavaoSmbOptions as SmbOptions, SmbDialect as RemoteSmbDialect};
use remotefs_smb::{
PavaoSmbCredentials as SmbCredentials, PavaoSmbFs as SmbFs, PavaoSmbOptions as SmbOptions,
SmbDialect as RemoteSmbDialect,
};
#[cfg(smb_windows)]
use remotefs_smb::{WNetSmbCredentials as SmbCredentials, WNetSmbFs as SmbFs};
use remotefs_ssh::{
+47
View File
@@ -50,6 +50,20 @@ impl Update {
self
}
/// Maps a build target triple onto the target triple used to name the
/// official release assets.
///
/// Official Linux binaries are statically linked against musl, so a
/// termscp built against glibc (for example via `cargo install`) must
/// still download the `-musl` asset.
fn map_release_target(target: &str) -> String {
if target.contains("-linux-") {
target.replace("-gnu", "-musl")
} else {
target.to_string()
}
}
/// Installs the latest available release using the configured update options.
pub fn upgrade(self) -> Result<UpdateStatus, UpdateError> {
info!("Updating termscp...");
@@ -58,6 +72,7 @@ impl Update {
.repo_owner("veeso")
.repo_name("termscp")
.bin_name("termscp")
.target(&Self::map_release_target(self_update::get_target()))
.current_version(cargo_crate_version!())
.no_confirm(!self.ask_confirm)
.show_download_progress(self.progress)
@@ -180,6 +195,38 @@ mod test {
assert_eq!(upd.progress, true);
}
#[test]
fn should_map_linux_release_target_to_musl() {
assert_eq!(
Update::map_release_target("x86_64-unknown-linux-gnu"),
"x86_64-unknown-linux-musl".to_string()
);
assert_eq!(
Update::map_release_target("aarch64-unknown-linux-gnu"),
"aarch64-unknown-linux-musl".to_string()
);
}
#[test]
fn should_leave_non_gnu_linux_release_target_unchanged() {
assert_eq!(
Update::map_release_target("x86_64-unknown-linux-musl"),
"x86_64-unknown-linux-musl".to_string()
);
}
#[test]
fn should_leave_other_platform_release_targets_unchanged() {
assert_eq!(
Update::map_release_target("aarch64-apple-darwin"),
"aarch64-apple-darwin".to_string()
);
assert_eq!(
Update::map_release_target("x86_64-pc-windows-msvc"),
"x86_64-pc-windows-msvc".to_string()
);
}
#[test]
#[cfg(all(
not(all(