mirror of
https://github.com/veeso/termscp.git
synced 2026-08-30 17:05:54 -07:00
ci: migrate project automation to Just (#442)
Deploy docs to GitHub Pages / deploy (push) Has been cancelled
Site / build-site (push) Has been cancelled
Install.sh / build (macos-latest) (push) Has been cancelled
Install.sh / build (ubuntu-latest) (push) Has been cancelled
CI / toolchain (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / install-scripts (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
CI / crates-macos-latest (push) Has been cancelled
Deploy docs to GitHub Pages / deploy (push) Has been cancelled
Site / build-site (push) Has been cancelled
Install.sh / build (macos-latest) (push) Has been cancelled
Install.sh / build (ubuntu-latest) (push) Has been cancelled
CI / toolchain (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / install-scripts (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
CI / crates-macos-latest (push) Has been cancelled
* 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
This commit is contained in:
committed by
GitHub
parent
08c51a32cc
commit
afbc74113f
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# termscp pre-commit hook.
|
||||
#
|
||||
# Runs three gates before a commit is recorded:
|
||||
# 1. trufflehog -- scan the staged tree for verified/unknown secrets
|
||||
# 2. dprint -- check formatting (Markdown, TOML, YAML, Rust)
|
||||
# 3. cargo-deny -- advisories, licenses, bans, and sources
|
||||
#
|
||||
# Install with `just setup_githooks` (sets core.hooksPath to .githooks).
|
||||
# Bypass in an emergency with `git commit --no-verify`.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
fail() {
|
||||
echo "pre-commit: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
command -v just >/dev/null 2>&1 || fail "just not found; install it to run the pre-commit checks"
|
||||
|
||||
if ! git diff --cached --quiet --diff-filter=ACMR --; then
|
||||
command -v trufflehog >/dev/null 2>&1 || fail "trufflehog not found; install it or commit with --no-verify"
|
||||
|
||||
# Check the exact tree that will be committed, not possibly different
|
||||
# working-tree contents. The trailing slash is required by checkout-index.
|
||||
index_tree="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf -- "$index_tree"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
git checkout-index --all --prefix="$index_tree/"
|
||||
|
||||
echo "pre-commit: scanning staged tree for secrets"
|
||||
(
|
||||
cd "$index_tree"
|
||||
just scan_secrets . --fail-on-scan-errors
|
||||
)
|
||||
|
||||
echo "pre-commit: checking staged-tree formatting"
|
||||
(
|
||||
cd "$index_tree"
|
||||
just fmt_check
|
||||
)
|
||||
|
||||
echo "pre-commit: checking staged-tree dependencies"
|
||||
(
|
||||
cd "$index_tree"
|
||||
just deny
|
||||
)
|
||||
fi
|
||||
|
||||
echo "pre-commit: all checks passed"
|
||||
@@ -4,7 +4,6 @@ about: Create a report of the bug you've encountered
|
||||
title: "[BUG] - ISSUE_TITLE"
|
||||
labels: bug
|
||||
assignees: veeso
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
@@ -4,7 +4,6 @@ about: Report a typo/error in a repository document
|
||||
title: "[COPY] - ISSUE_TITLE"
|
||||
labels: documentation
|
||||
assignees: veeso
|
||||
|
||||
---
|
||||
|
||||
## Report
|
||||
|
||||
@@ -4,7 +4,6 @@ about: Suggest an idea to improve termscp
|
||||
title: "[Feature Request] - FEATURE_TITLE"
|
||||
labels: "new feature"
|
||||
assignees: veeso
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
@@ -4,5 +4,4 @@ about: Ask what you want about the project
|
||||
title: "[QUESTION] - TITLE"
|
||||
labels: question
|
||||
assignees: veeso
|
||||
|
||||
---
|
||||
|
||||
@@ -4,7 +4,6 @@ about: Create a report of a security vulnerability
|
||||
title: "[SECURITY] - ISSUE_TITLE"
|
||||
labels: security
|
||||
assignees: veeso
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
@@ -29,12 +29,12 @@ Please select relevant options.
|
||||
- [ ] I formatted the code with `cargo fmt`
|
||||
- [ ] I checked my code using `cargo clippy` and reports no warnings
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have introduced no new *C-bindings*
|
||||
- [ ] I have introduced no new _C-bindings_
|
||||
- [ ] The changes I've made are Windows, MacOS, UNIX, Linux compatible (or I've handled them using `cfg target_os`)
|
||||
- [ ] I increased or maintained the code coverage for the project, compared to the previous commit
|
||||
|
||||
## Acceptance tests
|
||||
|
||||
wait for a *project maintainer* to fulfill this section...
|
||||
wait for a _project maintainer_ to fulfill this section...
|
||||
|
||||
- [ ] regression test: ...
|
||||
|
||||
+97
-27
@@ -5,12 +5,12 @@ on:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "*.md"
|
||||
- "./site/**/*"
|
||||
- "site/**"
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore:
|
||||
- "*.md"
|
||||
- "./site/**/*"
|
||||
- "site/**"
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
@@ -19,50 +19,120 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build-(${{ matrix.os }})
|
||||
toolchain:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
channel: ${{ steps.extract.outputs.result }}
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Extract toolchain channel from rust-toolchain.toml
|
||||
id: extract
|
||||
uses: mikefarah/yq@c14f446382944492701b16c1ddb48bb9dbe683e3 # v4.53.6
|
||||
with:
|
||||
cmd: yq '.toolchain.channel' rust-toolchain.toml
|
||||
|
||||
fmt:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Rust (nightly)
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
- name: Check formatting
|
||||
uses: dprint/check@9cb3a2b17a8e606d37aae341e49df3654933fc23 # v2.3
|
||||
|
||||
install-scripts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Check install scripts
|
||||
run: just check_install_scripts
|
||||
|
||||
crates:
|
||||
needs: toolchain
|
||||
name: crates-${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Linux dependencies
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt update && sudo apt install -y libdbus-1-dev libsmbclient-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libsmbclient-dev
|
||||
- name: Install macOS dependencies
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
brew install \
|
||||
pkg-config \
|
||||
samba
|
||||
pkg-config \
|
||||
samba
|
||||
brew link --force samba
|
||||
- name: Install nightly toolchain
|
||||
if: runner.os == 'Linux'
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: nightly
|
||||
components: rustfmt
|
||||
- name: Format
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo +nightly fmt --all -- --check
|
||||
- name: Install stable toolchain
|
||||
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
||||
with:
|
||||
toolchain: stable
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
components: clippy
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Build
|
||||
if: runner.os != 'Linux'
|
||||
run: cargo build
|
||||
- name: Run tests (Linux)
|
||||
run: just build_crates
|
||||
- name: Test (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: cargo test --no-default-features --features github-actions --no-fail-fast
|
||||
- name: Run tests
|
||||
run: just test "--no-default-features --features github-actions --no-fail-fast"
|
||||
- name: Test
|
||||
if: runner.os != 'Linux'
|
||||
run: cargo test --verbose --features github-actions
|
||||
run: just test "--verbose --features github-actions"
|
||||
- name: Clippy
|
||||
run: cargo clippy -- -Dwarnings
|
||||
run: just clippy "-- -D warnings"
|
||||
|
||||
doc:
|
||||
needs: toolchain
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Linux dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev libsmbclient-dev
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Build documentation
|
||||
run: just doc
|
||||
|
||||
deny:
|
||||
needs: toolchain
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install Rust
|
||||
uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable
|
||||
with:
|
||||
toolchain: ${{ needs.toolchain.outputs.channel }}
|
||||
- name: Install cargo-deny
|
||||
uses: taiki-e/install-action@37f7c5781271959fb65b6b35224e28652ff2b63d # v2.87.0
|
||||
with:
|
||||
tool: cargo-deny
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Check dependencies
|
||||
run: just deny
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install termscp from script
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Install mdBook
|
||||
@@ -58,9 +58,9 @@ jobs:
|
||||
<a href="./en-US/">termscp documentation</a>
|
||||
HTML
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
|
||||
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
||||
with:
|
||||
path: site_out
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
||||
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
||||
|
||||
@@ -22,23 +22,35 @@ jobs:
|
||||
outputs:
|
||||
version: ${{ inputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
persist-credentials: true
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Validate version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if [[ ! "$VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
||||
echo "invalid release version: $VERSION (expected MAJOR.MINOR.PATCH)" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
- name: Configure git identity
|
||||
run: |
|
||||
git config user.name "veeso"
|
||||
git config user.email "christian.visintin@veeso.dev"
|
||||
|
||||
- name: Install git-cliff
|
||||
uses: taiki-e/install-action@56545b37b57562edd73171cb6c62cc509db4c34e # v2
|
||||
uses: taiki-e/install-action@37f7c5781271959fb65b6b35224e28652ff2b63d # v2.87.0
|
||||
with:
|
||||
tool: git-cliff
|
||||
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
|
||||
- name: Bump version
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
@@ -47,7 +59,7 @@ jobs:
|
||||
- name: Generate CHANGELOG
|
||||
env:
|
||||
VERSION: ${{ inputs.version }}
|
||||
run: git-cliff --tag "v$VERSION" -o CHANGELOG.md
|
||||
run: just changelog "$VERSION"
|
||||
|
||||
- name: Generate release notes
|
||||
env:
|
||||
@@ -55,7 +67,7 @@ jobs:
|
||||
run: git-cliff --unreleased --tag "v$VERSION" --strip header -o RELEASE_NOTES.md
|
||||
|
||||
- name: Upload release notes
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-notes
|
||||
path: RELEASE_NOTES.md
|
||||
@@ -111,15 +123,20 @@ jobs:
|
||||
TARGET: ${{ matrix.target }}
|
||||
FEATURES: ${{ matrix.features }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: ${{ inputs.dry_run && github.sha || 'main' }}
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Install Rust target
|
||||
if: matrix.kind != 'windows'
|
||||
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)
|
||||
@@ -156,10 +173,10 @@ jobs:
|
||||
cargo install cargo-deb
|
||||
- name: Build (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: cargo build --release --features smb-vendored --target "$TARGET"
|
||||
run: just build_release "$TARGET" "--features smb-vendored"
|
||||
- name: Build deb (Linux)
|
||||
if: matrix.kind == 'linux'
|
||||
run: cargo deb --no-build --target "$TARGET" --features smb-vendored
|
||||
run: just package_deb "$TARGET"
|
||||
|
||||
# ---- macOS ----
|
||||
- name: Install deps (macOS)
|
||||
@@ -173,12 +190,12 @@ jobs:
|
||||
cpanm Parse::Yapp::Driver
|
||||
- name: Build (macOS)
|
||||
if: matrix.kind == 'macos'
|
||||
run: cargo build --release $FEATURES --target "$TARGET"
|
||||
run: just build_release "$TARGET" "$FEATURES"
|
||||
|
||||
# ---- Windows ----
|
||||
- name: Build (Windows)
|
||||
if: matrix.kind == 'windows'
|
||||
run: cargo build --release --features smb-vendored --target "$env:TARGET"
|
||||
run: just build_release "$env:TARGET" "--features smb-vendored"
|
||||
|
||||
# ---- Package posix (tar.gz) ----
|
||||
- name: Package (posix)
|
||||
@@ -204,7 +221,7 @@ jobs:
|
||||
run: cp target/"$TARGET"/debian/*.deb artifact/
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: build-${{ matrix.target }}
|
||||
path: artifact/*
|
||||
@@ -218,14 +235,14 @@ jobs:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: build-*
|
||||
path: dl
|
||||
merge-multiple: true
|
||||
|
||||
- name: Checkout homebrew tap
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
repository: veeso/homebrew-termscp
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
@@ -316,21 +333,21 @@ jobs:
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_PAT }}
|
||||
ref: ${{ inputs.dry_run && github.sha || 'main' }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Download build artifacts
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
pattern: build-*
|
||||
path: dl
|
||||
merge-multiple: true
|
||||
|
||||
- name: Download release notes
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: release-notes
|
||||
path: notes
|
||||
@@ -355,7 +372,7 @@ jobs:
|
||||
|
||||
- name: Upload assets artifact (dry run)
|
||||
if: ${{ inputs.dry_run }}
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: release-assets-dryrun
|
||||
path: out/*
|
||||
@@ -380,13 +397,14 @@ jobs:
|
||||
env:
|
||||
VERSION: ${{ needs.prepare.outputs.version }}
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
ref: main
|
||||
persist-credentials: false
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
|
||||
- name: Install dependencies (Linux)
|
||||
run: |
|
||||
@@ -421,12 +439,12 @@ jobs:
|
||||
|
||||
- name: Authenticate to crates.io
|
||||
id: auth
|
||||
uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # v1.0.4
|
||||
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
|
||||
|
||||
- name: Publish to crates.io
|
||||
env:
|
||||
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
|
||||
run: cargo publish --features smb-vendored
|
||||
run: just publish_crate
|
||||
|
||||
publish-choco:
|
||||
needs: [prepare, release]
|
||||
|
||||
@@ -9,30 +9,28 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: site
|
||||
|
||||
jobs:
|
||||
build-site:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version: 24
|
||||
cache: npm
|
||||
cache-dependency-path: site/package-lock.json
|
||||
- name: Install just
|
||||
uses: extractions/setup-just@53165ef7e734c5c07cb06b3c8e7b647c5aa16db3 # v4
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: just site_install
|
||||
- name: Format
|
||||
run: npm run format:check
|
||||
run: just site_fmt_check
|
||||
- name: Lint
|
||||
run: npm run check
|
||||
run: just site_check
|
||||
- name: Test
|
||||
run: npm test --if-present
|
||||
run: just site_test
|
||||
- name: Build
|
||||
run: npm run build
|
||||
run: just site_build
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: actions/stale@a20b814fb01b71def3bd6f56e7494d667ddf28da # v4.1.1
|
||||
- uses: actions/stale@4391f3da665fdf50b6810c1a66712fb9ba21aa93 # v11.0.0
|
||||
with:
|
||||
days-before-issue-stale: 30
|
||||
days-before-issue-close: 7
|
||||
|
||||
+66
-34
@@ -1,3 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 1.1.1
|
||||
|
||||
Released on 2026-06-08
|
||||
@@ -10,6 +12,7 @@ Released on 2026-06-08
|
||||
> crates.io versions are immutable (no overwrite) and Chocolatey's
|
||||
> moderation queue blocks a fast re-push, so a clean 1.1.1 without vergen
|
||||
> is the only fix.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
Released on 2026-06-08
|
||||
@@ -29,7 +32,7 @@ Released on 2026-06-08
|
||||
- **install:** add Windows PowerShell installer and copy buttons on site
|
||||
> Add install.ps1 mirroring install.sh for Windows: arch detection,
|
||||
> release zip download, binary extraction, user PATH update.
|
||||
>
|
||||
>
|
||||
> - copy install.ps1 to site public/ at build time (copy-install.mjs)
|
||||
> - serve /install.ps1 with text/plain Content-Type (vercel.json)
|
||||
> - add PowerShell one-liner to install page and README
|
||||
@@ -38,11 +41,11 @@ Released on 2026-06-08
|
||||
- **config:** move config dir to ~/.config/termscp on macOS and %USERPROFILE%\.termscp on Windows
|
||||
> Resolve the config directory through a single per-platform config_dir()
|
||||
> function instead of relying on dirs::config_dir everywhere:
|
||||
>
|
||||
>
|
||||
> - macOS: ~/.config/termscp (was ~/Library/Application Support/termscp)
|
||||
> - Windows: %USERPROFILE%\.termscp (was roaming %APPDATA%\termscp)
|
||||
> - Linux/other: /termscp (unchanged)
|
||||
>
|
||||
>
|
||||
> Existing users are migrated automatically on first run: when the new
|
||||
> directory is absent and the legacy location exists, the whole config
|
||||
> directory is moved to the new path. The cache directory stays at the
|
||||
@@ -54,7 +57,7 @@ Released on 2026-06-08
|
||||
> Single workflow_dispatch (version, dry_run) that bumps versions, regenerates
|
||||
> CHANGELOG via git-cliff, rebuilds site CSS, builds all targets, creates the
|
||||
> GitHub release, updates the Homebrew tap and publishes Chocolatey.
|
||||
>
|
||||
>
|
||||
> - dist/release/bump_version.sh: version replacer across all tracked locations (+tests)
|
||||
> - .github/workflows/release.yml: prepare -> build matrix -> homebrew/release -> choco
|
||||
> - retire build-artifacts.yml (merged into release.yml)
|
||||
@@ -66,7 +69,7 @@ Released on 2026-06-08
|
||||
- fix release notes generation in release workflow
|
||||
> prepare job failed: git-cliff --latest crashed with 'trim_start_matches on
|
||||
> null' because the checkout was shallow (no tags/history) so no release existed.
|
||||
>
|
||||
>
|
||||
> - checkout prepare with fetch-depth: 0 + fetch-tags so git-cliff sees full
|
||||
> history and tags (also fixes an otherwise-truncated CHANGELOG)
|
||||
> - generate release notes with --unreleased --tag v$VERSION instead of --latest:
|
||||
@@ -143,7 +146,7 @@ Released on 2026-06-08
|
||||
> Migrate the transfer progress UI to tuirealm 4, where the stdlib
|
||||
> `ProgressBar` widget was dropped, by rebuilding the dual-bar panel on
|
||||
> top of `Gauge`.
|
||||
>
|
||||
>
|
||||
> - Restore the unified two-bar look: the full bar (top) and partial bar
|
||||
> (bottom) draw joined borders so they read as a single panel; a single
|
||||
> file shows one fully-bordered bar.
|
||||
@@ -159,19 +162,19 @@ Released on 2026-06-08
|
||||
> its top border is dropped to join the seam with the full bar. That left
|
||||
> the partial bar with one inner row while the full bar kept two, so the
|
||||
> two gauges rendered at unequal heights.
|
||||
>
|
||||
>
|
||||
> - Move the filename from the partial bar's title into its gauge label.
|
||||
> - Skip setting an empty title so no phantom top-positioned title triggers
|
||||
> the inset.
|
||||
> - Put the panel title on the top (full) bar for multi-file transfers.
|
||||
> - Bump the two-bar popup height to fit the joined panel.
|
||||
>
|
||||
>
|
||||
> Also bump Cargo.lock and adapt the embedded terminal to the new vt100
|
||||
> `screen_mut()` API.
|
||||
- **copy:** prevent emptying file when copy destination is empty (#421)
|
||||
> An empty copy destination resolved to the source file's own path, so
|
||||
> std::fs::copy truncated the original file to 0 bytes.
|
||||
>
|
||||
>
|
||||
> - localhost::copy now refuses to copy a file onto itself, returning an
|
||||
> error instead of truncating it (root cause).
|
||||
> - action_copy treats an empty/whitespace destination as a cancel.
|
||||
@@ -180,7 +183,7 @@ Released on 2026-06-08
|
||||
> path. Downstream upload logic treats the queued destination as the full
|
||||
> file path and passes it straight to create_file, so transfers failed
|
||||
> with a Failure error when the remote target resolved to a directory.
|
||||
>
|
||||
>
|
||||
> Append each entry's file name to the destination directory at enqueue
|
||||
> time in both enqueue_file and enqueue_all, matching the single-file
|
||||
> transfer path which already builds the full target path.
|
||||
@@ -191,6 +194,7 @@ Released on 2026-06-08
|
||||
> The old manual dist/build/* scripts and dist/{deb,rpm}.sh are superseded by the
|
||||
> automated release workflow. Add the chocolatey package consumed by release.yml.
|
||||
- **site:** copy install.sh from repo root at build time (single source)
|
||||
|
||||
## 1.0.0
|
||||
|
||||
Released on 2026-04-18
|
||||
@@ -243,6 +247,7 @@ Released on 2026-04-18
|
||||
> `fs_pane_mut()`. This eliminates most `is_local_tab()` branching across
|
||||
> 15+ action files.
|
||||
> Key changes:
|
||||
>
|
||||
> - Add `fs: Box<dyn HostBridge>` to Pane, remove from FileTransferActivity
|
||||
> - Replace per-side method pairs with unified pane-dispatched methods
|
||||
> - Unify navigation (changedir, reload, scan, file_exists, has_file_changed)
|
||||
@@ -250,7 +255,7 @@ Released on 2026-04-18
|
||||
> - Replace assert!/panic!/unreachable! with proper error handling
|
||||
> - Fix typo "filetransfer_activiy" across ~29 files
|
||||
> - Add unit tests for Pane
|
||||
>
|
||||
>
|
||||
> Net result: -473 lines, single code path for most file operations.
|
||||
- replace lazy_static with std::sync::LazyLock
|
||||
- migrate from mod.rs to named module files
|
||||
@@ -278,14 +283,14 @@ Released on 2026-04-18
|
||||
> encryption (authenticated, with random nonces) while keeping a legacy
|
||||
> AES-128-CBC decryption path to transparently handle existing bookmarks.
|
||||
- replace recursive byte-counting with entry-based transfer progress (#395)
|
||||
> * fix: replace recursive byte-counting with entry-based transfer progress
|
||||
>
|
||||
> - fix: replace recursive byte-counting with entry-based transfer progress
|
||||
>
|
||||
> Replace the expensive recursive `get_total_transfer_size` pre-calculation
|
||||
> with a lightweight entry-based counter (`TransferProgress`) for the
|
||||
> overall progress bar. This avoids deep `list_dir` traversals before
|
||||
> transfers begin, which could cause FTP idle-timeout disconnections on
|
||||
> large directory trees.
|
||||
>
|
||||
>
|
||||
> The per-file byte-level progress bar (`ProgressStates`) remains
|
||||
> unchanged. Bytes are still tracked via `TransferStates::add_bytes` for
|
||||
> notification threshold logic.
|
||||
@@ -302,7 +307,7 @@ Released on 2026-04-18
|
||||
- sync browsing when entering a directory from filtered/fuzzy view
|
||||
- stabilize core error handling
|
||||
> Remove production panic and unwrap paths from core modules.
|
||||
>
|
||||
>
|
||||
> Propagate bookmark encryption failures, harden file watcher and temp mapped file handling, and clean up dead code in shared utilities.
|
||||
- normalize localhost relative path checks
|
||||
- use time-based redraw interval instead of progress-delta threshold
|
||||
@@ -341,9 +346,9 @@ Released on 2026-04-18
|
||||
> Upgrade tuirealm (3.x -> 4.0.0), tui-realm-stdlib (3 -> 4), tui-term
|
||||
> (0.2 -> 0.3). Apply all breaking changes from the 4.0 migration guide
|
||||
> across the termscp UI.
|
||||
>
|
||||
>
|
||||
> Key changes:
|
||||
>
|
||||
>
|
||||
> - Root-level re-exports removed; imports moved to module-qualified
|
||||
> paths (`tuirealm::application`, `::component`, `::event`, `::props`,
|
||||
> `::state`, `::subscription`, `::listener`, `::ratatui`). Same for
|
||||
@@ -394,6 +399,7 @@ Released on 2026-04-18
|
||||
### Style
|
||||
|
||||
- linter
|
||||
|
||||
## 0.19.1
|
||||
|
||||
Released on 2025-12-20
|
||||
@@ -407,6 +413,7 @@ Released on 2025-12-20
|
||||
- install.sh deb name
|
||||
- install.sh deb name
|
||||
- Updated dependencies to allow build on NetBSD
|
||||
|
||||
## 0.19.0
|
||||
|
||||
Released on 2025-11-11
|
||||
@@ -414,13 +421,13 @@ Released on 2025-11-11
|
||||
### Added
|
||||
|
||||
- Import bookmarks from ssh config with a CLI command (#364)
|
||||
> * feat: Import bookmarks from ssh config with a CLI command
|
||||
>
|
||||
> - feat: Import bookmarks from ssh config with a CLI command
|
||||
>
|
||||
> Use import-ssh-hosts to import all the possible hosts by the configured ssh config or the default one on your machine
|
||||
- Changed file overwrite behaviour (#366)
|
||||
> Now the user can choose for each file whether to overwrite, skip or overwrite all/skip all.
|
||||
- Added `<CTRL+S>` keybinding to get the total size of selected paths. (#367)
|
||||
> * feat: Added `<CTRL+S>` keybinding to get the total size of selected paths.
|
||||
> - feat: Added `<CTRL+S>` keybinding to get the total size of selected paths.
|
||||
- Merge branch '0.19.0'
|
||||
|
||||
### CI
|
||||
@@ -440,8 +447,8 @@ Released on 2025-11-11
|
||||
- typo in file open error message (#349)
|
||||
- SMB support for MacOS with vendored build of libsmbclient.
|
||||
- Report a message while calculating total size of files to transfer. (#362)
|
||||
> * fix: Report a message while calculating total size of files to transfer.
|
||||
>
|
||||
> - fix: Report a message while calculating total size of files to transfer.
|
||||
>
|
||||
> Currently, in case of huge transfers the app may look frozen while calculating the transfer size. We should at least report to the user we are actually doing something.
|
||||
- Issues with update checks (#363)
|
||||
> Removed error popup message if failed to check for updates.
|
||||
@@ -456,6 +463,7 @@ Released on 2025-11-11
|
||||
- 0.19 deps
|
||||
- remotefs-ssh 0.7.1
|
||||
> This version fixes compatibility with hosts which don't use bash/sh as the default shell.
|
||||
|
||||
## 0.18.0
|
||||
|
||||
Released on 2025-06-10
|
||||
@@ -464,7 +472,7 @@ Released on 2025-06-10
|
||||
|
||||
- **Updated dependencies** and updated the Rust edition to `2024`
|
||||
- Replaced the `Exec` popup with a fully functional terminal emulator (#348)
|
||||
> * feat: Replaced the `Exec` popup with a fully functional terminal emulator
|
||||
> - feat: Replaced the `Exec` popup with a fully functional terminal emulator
|
||||
- 0.18
|
||||
|
||||
### Fixed
|
||||
@@ -475,6 +483,7 @@ Released on 2025-06-10
|
||||
### Style
|
||||
|
||||
- catppuccin themes
|
||||
|
||||
## 0.17.0
|
||||
|
||||
Released on 2025-03-23
|
||||
@@ -523,6 +532,7 @@ Released on 2025-03-23
|
||||
- aws-s3 0.4.2
|
||||
- build docker for x86
|
||||
- so apparently native-tls vendored tries to build openssl on windows, wtf guys?
|
||||
|
||||
## 0.16.1
|
||||
|
||||
Released on 2024-11-12
|
||||
@@ -532,6 +542,7 @@ Released on 2024-11-12
|
||||
- cfg unix forbidden in rust .82
|
||||
- gg rust 1.82 for introducing a nice breaking change in config which was not mentioned in changelog
|
||||
- 0.16.1
|
||||
|
||||
## 0.16.0
|
||||
|
||||
Released on 2024-10-14
|
||||
@@ -550,6 +561,7 @@ Released on 2024-10-14
|
||||
- issue 292 New version alert was not displayed due to a semver regex issue. (#300)
|
||||
- 0.16
|
||||
- tiny ui issue
|
||||
|
||||
## 0.15.0
|
||||
|
||||
Released on 2024-10-03
|
||||
@@ -572,14 +584,14 @@ Released on 2024-10-03
|
||||
- issue 277 Fix a bug in the configuration page, which caused being stuck if the added SSH key was empty
|
||||
- popup texts
|
||||
- `isolated-tests` feature to run tests for releasing on distributions which run in isolated environments (#286)
|
||||
> * fix: `isolated-tests` feature to run tests for releasing on distributions which run in isolated environments
|
||||
>
|
||||
> * fix: cond
|
||||
> - fix: `isolated-tests` feature to run tests for releasing on distributions which run in isolated environments
|
||||
> - fix: cond
|
||||
- set date
|
||||
- github ci is stable and reliable (one worker broken each 2 weeks)
|
||||
- ci
|
||||
- readme
|
||||
- include build.rs
|
||||
|
||||
## 0.14.0
|
||||
|
||||
Released on 2024-07-17
|
||||
@@ -608,6 +620,7 @@ Released on 2024-07-17
|
||||
- german manual
|
||||
- removed support for RPM
|
||||
- changelog
|
||||
|
||||
## 0.13.0
|
||||
|
||||
Released on 2024-03-02
|
||||
@@ -624,6 +637,7 @@ Released on 2024-03-02
|
||||
- debian script
|
||||
- debian script
|
||||
- lint???
|
||||
|
||||
## 0.12.2
|
||||
|
||||
Released on 2023-10-01
|
||||
@@ -636,6 +650,7 @@ Released on 2023-10-01
|
||||
|
||||
- fmt
|
||||
- panic if the terminal screen is too small
|
||||
|
||||
## 0.12.1
|
||||
|
||||
Released on 2023-07-06
|
||||
@@ -659,6 +674,7 @@ Released on 2023-07-06
|
||||
- don't run CI on site/.md change
|
||||
- rustup target
|
||||
- don't update path breadcrumb if enter/scan dir failed (#203)
|
||||
|
||||
## 0.12.0
|
||||
|
||||
Released on 2023-05-16
|
||||
@@ -677,6 +693,7 @@ Released on 2023-05-16
|
||||
- pavao 0.2.3
|
||||
- macos script
|
||||
- release date
|
||||
|
||||
## 0.11.3
|
||||
|
||||
Released on 2023-04-19
|
||||
@@ -688,6 +705,7 @@ Released on 2023-04-19
|
||||
### Fixed
|
||||
|
||||
- relative paths windows (#167)
|
||||
|
||||
## 0.11.2
|
||||
|
||||
Released on 2023-04-18
|
||||
@@ -696,6 +714,7 @@ Released on 2023-04-18
|
||||
|
||||
- dependencies up-to-date
|
||||
- site 0.11.2
|
||||
|
||||
## 0.8.1
|
||||
|
||||
Released on 2022-03-22
|
||||
@@ -703,6 +722,7 @@ Released on 2022-03-22
|
||||
### Fixed
|
||||
|
||||
- footer listed "Delete" shortcut as "Make Dir"
|
||||
|
||||
## 0.8.0
|
||||
|
||||
Released on 2022-01-06
|
||||
@@ -710,6 +730,7 @@ Released on 2022-01-06
|
||||
### Arch
|
||||
|
||||
- install rust only if not found on local system
|
||||
|
||||
## 0.7.0
|
||||
|
||||
Released on 2021-10-12
|
||||
@@ -717,6 +738,7 @@ Released on 2021-10-12
|
||||
### Option
|
||||
|
||||
- prompt user when about to replace an existing file caused by a file transfer
|
||||
|
||||
## 0.6.1
|
||||
|
||||
Released on 2021-08-30
|
||||
@@ -724,6 +746,7 @@ Released on 2021-08-30
|
||||
### Fixed
|
||||
|
||||
- When copying files with tricky copy, the upper progress bar shows no text
|
||||
|
||||
## 0.5.1
|
||||
|
||||
Released on 2021-06-21
|
||||
@@ -731,6 +754,7 @@ Released on 2021-06-21
|
||||
### Fix
|
||||
|
||||
- target_family unix means also macos and linux; use BSD target_os
|
||||
|
||||
## 0.5.0
|
||||
|
||||
Released on 2021-05-23
|
||||
@@ -743,6 +767,7 @@ Released on 2021-05-23
|
||||
### Grcov
|
||||
|
||||
- exclude activities
|
||||
|
||||
## 0.4.1
|
||||
|
||||
Released on 2021-04-06
|
||||
@@ -755,18 +780,19 @@ Released on 2021-04-06
|
||||
### Readme
|
||||
|
||||
- one-liner for Homebrew
|
||||
> The one-liner command
|
||||
>
|
||||
> brew install veeso/termscp/termscp
|
||||
>
|
||||
> is equivalent to the two commands
|
||||
>
|
||||
> brew tap veeso/termscp
|
||||
> brew install termscp
|
||||
> The one-liner command
|
||||
>
|
||||
> brew install veeso/termscp/termscp
|
||||
>
|
||||
> is equivalent to the two commands
|
||||
>
|
||||
> brew tap veeso/termscp
|
||||
> brew install termscp
|
||||
|
||||
### SCP
|
||||
|
||||
- fixed symlink not properly detected
|
||||
|
||||
## 0.4.0
|
||||
|
||||
Released on 2021-03-27
|
||||
@@ -786,6 +812,7 @@ Released on 2021-03-27
|
||||
### View
|
||||
|
||||
- return String instead of id
|
||||
|
||||
## 0.3.3
|
||||
|
||||
Released on 2021-02-28
|
||||
@@ -793,6 +820,7 @@ Released on 2021-02-28
|
||||
### Git
|
||||
|
||||
- check for new updates (utils)
|
||||
|
||||
## 0.3.2
|
||||
|
||||
Released on 2021-01-24
|
||||
@@ -800,6 +828,7 @@ Released on 2021-01-24
|
||||
### Testing
|
||||
|
||||
- don't run on windows
|
||||
|
||||
## 0.3.0
|
||||
|
||||
Released on 2021-01-10
|
||||
@@ -834,6 +863,7 @@ Released on 2021-01-10
|
||||
### SetupActivity
|
||||
|
||||
- <CTRL+E> as <DEL>
|
||||
|
||||
## 0.2.0
|
||||
|
||||
Released on 2020-12-21
|
||||
@@ -845,6 +875,7 @@ Released on 2020-12-21
|
||||
### Scp
|
||||
|
||||
- when username was not provided, it didn't fallback to current username
|
||||
|
||||
## 0.1.2
|
||||
|
||||
Released on 2020-12-13
|
||||
@@ -852,6 +883,7 @@ Released on 2020-12-13
|
||||
### FsEntry
|
||||
|
||||
- :*::symlink is now a Option<Box<FsEntry>>; this improved symlinks, which gave errors some times
|
||||
|
||||
## 0.1.0
|
||||
|
||||
Released on 2020-12-06
|
||||
|
||||
@@ -12,28 +12,31 @@ termscp is a terminal file transfer client with a TUI (Terminal User Interface),
|
||||
|
||||
## Build & Development Commands
|
||||
|
||||
Task runner is `just` (modular recipes under `just/*.just`, imported by root `justfile`). Run `just --list` for the full set.
|
||||
|
||||
```bash
|
||||
# Build
|
||||
cargo build
|
||||
cargo build --release
|
||||
cargo build --no-default-features # minimal build without SMB/keyring
|
||||
just build_crates # cargo build --workspace
|
||||
just build_crates "--release"
|
||||
cargo build --no-default-features # minimal build without SMB/keyring (no just recipe)
|
||||
|
||||
# Test (CI-equivalent)
|
||||
cargo test --no-default-features --features github-actions --no-fail-fast
|
||||
just test "--no-default-features --features github-actions --no-fail-fast"
|
||||
|
||||
# Run a single test
|
||||
# Run a single test / a module (use cargo directly, just recipes don't take test names)
|
||||
cargo test <test_name> -- --nocapture
|
||||
|
||||
# Run tests for a module
|
||||
cargo test --lib filetransfer::
|
||||
cargo test --lib config::params::tests
|
||||
|
||||
# Lint
|
||||
cargo clippy -- -Dwarnings
|
||||
just clippy "-- -D warnings"
|
||||
|
||||
# Format
|
||||
cargo fmt --all -- --check # check only
|
||||
cargo fmt --all # fix
|
||||
# Format (dprint: Markdown, TOML, YAML, and Rust via nightly rustfmt)
|
||||
just fmt_check # check only
|
||||
just fmt # fix
|
||||
|
||||
# All code checks at once (fmt_check, clippy -D warnings, doc, deny, install script lint)
|
||||
just check_code
|
||||
```
|
||||
|
||||
### System Dependencies (for building)
|
||||
@@ -66,16 +69,16 @@ main.rs → parse CLI args → ActivityManager::new() → ActivityManager::run()
|
||||
|
||||
### Key Modules
|
||||
|
||||
| Module | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| **activity_manager** | `src/activity_manager.rs` | Orchestrates activity lifecycle and transitions |
|
||||
| **ui/activities** | `src/ui/activities/{auth,filetransfer,setup}/` | Three main screens, each implementing the `Activity` trait |
|
||||
| **ui/context** | `src/ui/context.rs` | Shared `Context` struct (terminal, config, bookmarks, theme) |
|
||||
| **filetransfer** | `src/filetransfer/` | Protocol enum, `RemoteFsBuilder`, connection parameters |
|
||||
| **host** | `src/host/` | `HostBridge` trait — abstracts local (`Localhost`) and remote (`RemoteBridged`) file operations |
|
||||
| **explorer** | `src/explorer/` | `FileExplorer` — directory navigation, sorting, filtering, transfer queue |
|
||||
| **system** | `src/system/` | `BookmarksClient`, `ConfigClient`, `ThemeProvider`, `SshKeyStorage`, `KeyStorage` trait |
|
||||
| **config** | `src/config/` | TOML-based serialization for themes, bookmarks, user params |
|
||||
| Module | Path | Purpose |
|
||||
| -------------------- | ---------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| **activity_manager** | `src/activity_manager.rs` | Orchestrates activity lifecycle and transitions |
|
||||
| **ui/activities** | `src/ui/activities/{auth,filetransfer,setup}/` | Three main screens, each implementing the `Activity` trait |
|
||||
| **ui/context** | `src/ui/context.rs` | Shared `Context` struct (terminal, config, bookmarks, theme) |
|
||||
| **filetransfer** | `src/filetransfer/` | Protocol enum, `RemoteFsBuilder`, connection parameters |
|
||||
| **host** | `src/host/` | `HostBridge` trait — abstracts local (`Localhost`) and remote (`RemoteBridged`) file operations |
|
||||
| **explorer** | `src/explorer/` | `FileExplorer` — directory navigation, sorting, filtering, transfer queue |
|
||||
| **system** | `src/system/` | `BookmarksClient`, `ConfigClient`, `ThemeProvider`, `SshKeyStorage`, `KeyStorage` trait |
|
||||
| **config** | `src/config/` | TOML-based serialization for themes, bookmarks, user params |
|
||||
|
||||
### Core Traits
|
||||
|
||||
@@ -86,6 +89,7 @@ main.rs → parse CLI args → ActivityManager::new() → ActivityManager::run()
|
||||
### Conditional Compilation
|
||||
|
||||
The `build.rs` defines cfg aliases via `cfg_aliases`:
|
||||
|
||||
- `posix`, `macos`, `linux`, `win` — platform shortcuts
|
||||
- `smb`, `smb_unix`, `smb_windows` — feature + platform combinations
|
||||
|
||||
@@ -106,6 +110,7 @@ Platform-specific dependencies: SSH and FTP crates use different TLS backends on
|
||||
|
||||
## Other conventions
|
||||
|
||||
- Always run `cargo +nightly fmt --all` and `cargo clippy --no-default-features -- -Dwarnings` after modifying Rust code
|
||||
- Always run `just fmt` and `just clippy "-- -D warnings"` after modifying Rust code
|
||||
- Always put plans to `./.claude/plans/`
|
||||
- When changing behavior that is documented under `docs/` (paths, config keys, commands, flags, etc.), update BOTH `docs/en-US/` and `docs/zh-CN/` to keep the translations in sync
|
||||
- All code must be cross-platform compatible (Windows, macOS, Linux) — avoid POSIX-only APIs, hardcoded path separators, or shell-specific behavior unless gated behind the `posix`/`win` cfg aliases
|
||||
|
||||
+10
-10
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
- Demonstrating empathy and kindness toward other people
|
||||
- Being respectful of differing opinions, viewpoints, and experiences
|
||||
- Giving and gracefully accepting constructive feedback
|
||||
- Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
- Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
- The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
- Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
- Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
+1
-1
@@ -150,5 +150,5 @@ You can view the developer guide [here](https://docs.termscp.rs/en-US/developer/
|
||||
|
||||
---
|
||||
|
||||
Thank you for any contribution!
|
||||
Thank you for any contribution!\
|
||||
Christian Visintin
|
||||
|
||||
Generated
+35
-35
@@ -514,7 +514,7 @@ dependencies = [
|
||||
"aws-smithy-runtime-api",
|
||||
"aws-smithy-types",
|
||||
"h2 0.3.27",
|
||||
"h2 0.4.14",
|
||||
"h2 0.4.19",
|
||||
"http 0.2.12",
|
||||
"http 1.4.2",
|
||||
"http-body 0.4.6",
|
||||
@@ -924,9 +924,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "chacha20"
|
||||
version = "0.10.0"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601"
|
||||
checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher 0.5.2",
|
||||
@@ -1117,7 +1117,7 @@ dependencies = [
|
||||
"crc",
|
||||
"digest 0.10.7",
|
||||
"rustversion",
|
||||
"spin 0.10.0",
|
||||
"spin 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1147,9 +1147,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
version = "0.9.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -1213,9 +1213,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crypto-bigint"
|
||||
version = "0.7.3"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42a0d26b245348befa0c121944541476763dcc46ede886c88f9d12e1697d27c3"
|
||||
checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271"
|
||||
dependencies = [
|
||||
"cpubits",
|
||||
"ctutils",
|
||||
@@ -1256,7 +1256,7 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21f41f23de7d24cdbda7f0c4d9c0351f99a4ceb258ef30e5c1927af8987ffe5a"
|
||||
dependencies = [
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"libm",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
@@ -1568,7 +1568,7 @@ dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1770,7 +1770,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "102d3643d30dd8b559613c5cced68317199597fffb278cdc88daa2ef7fafc935"
|
||||
dependencies = [
|
||||
"base16ct 1.0.0",
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"crypto-common 0.2.2",
|
||||
"digest 0.11.3",
|
||||
"ff 0.14.0",
|
||||
@@ -1826,7 +1826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2238,9 +2238,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.14"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733"
|
||||
checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
@@ -2492,7 +2492,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"h2 0.4.14",
|
||||
"h2 0.4.19",
|
||||
"http 1.4.2",
|
||||
"http-body 1.0.1",
|
||||
"httparse",
|
||||
@@ -2599,7 +2599,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2 0.6.4",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
@@ -3088,7 +3088,7 @@ version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
dependencies = [
|
||||
"spin 0.9.8",
|
||||
"spin 0.9.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4269,7 +4269,7 @@ version = "0.14.0-rc.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f845ec3240cd5ed5e1e31cf3ff633a5bf47c698dc4092ba9e767415b3d393406"
|
||||
dependencies = [
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"crypto-common 0.2.2",
|
||||
"ff 0.14.0",
|
||||
"rand_core 0.10.1",
|
||||
@@ -4335,7 +4335,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls 0.23.40",
|
||||
"socket2 0.6.4",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -4372,7 +4372,7 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2 0.6.4",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
@@ -4425,7 +4425,7 @@ version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||
dependencies = [
|
||||
"chacha20 0.10.0",
|
||||
"chacha20 0.10.2",
|
||||
"getrandom 0.4.2",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
@@ -4781,7 +4781,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2 0.4.14",
|
||||
"h2 0.4.19",
|
||||
"http 1.4.2",
|
||||
"http-body 1.0.1",
|
||||
"http-body-util",
|
||||
@@ -4895,7 +4895,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf"
|
||||
dependencies = [
|
||||
"const-oid 0.10.2",
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"crypto-primes",
|
||||
"digest 0.11.3",
|
||||
"pkcs1 0.8.0-rc.4",
|
||||
@@ -4931,7 +4931,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"cbc 0.2.1",
|
||||
"cipher 0.5.2",
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"ctr 0.10.1",
|
||||
"curve25519-dalek 5.0.0-rc.0",
|
||||
"data-encoding",
|
||||
@@ -5150,7 +5150,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys 0.12.1",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5796,20 +5796,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
version = "0.9.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591"
|
||||
checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
@@ -5868,7 +5868,7 @@ dependencies = [
|
||||
"aes 0.9.1",
|
||||
"aes-gcm 0.11.0-rc.4",
|
||||
"cbc 0.2.1",
|
||||
"chacha20 0.10.0",
|
||||
"chacha20 0.10.2",
|
||||
"cipher 0.5.2",
|
||||
"ctr 0.10.1",
|
||||
"ctutils",
|
||||
@@ -5898,7 +5898,7 @@ checksum = "7abf34aa716da5d5b4c496936d042ea282ab392092cd68a72ef6a8863ff8c96a"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"bytes",
|
||||
"crypto-bigint 0.7.3",
|
||||
"crypto-bigint 0.7.5",
|
||||
"ctutils",
|
||||
"digest 0.11.3",
|
||||
"pem-rfc7468 1.0.0",
|
||||
@@ -6117,10 +6117,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.4.2",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix 1.1.4",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7031,7 +7031,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+9
-23
@@ -1,17 +1,17 @@
|
||||
[package]
|
||||
name = "termscp"
|
||||
version = "1.1.1"
|
||||
edition = "2024"
|
||||
authors = ["Christian Visintin <christian.visintin@veeso.dev>"]
|
||||
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/veeso/termscp"
|
||||
categories = ["command-line-utilities"]
|
||||
edition = "2024"
|
||||
homepage = "https://termscp.rs"
|
||||
include = ["/src/**/*", "/build.rs", "/LICENSE", "/README.md", "/CHANGELOG.md"]
|
||||
keywords = ["terminal", "ftp", "scp", "sftp", "tui"]
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
rust-version = "1.89.0"
|
||||
repository = "https://github.com/veeso/termscp"
|
||||
rust-version = "1.98.0"
|
||||
description = "termscp is a feature rich terminal file transfer and explorer with support for SCP/SFTP/FTP/Kube/S3/WebDAV"
|
||||
|
||||
[package.metadata.rpm]
|
||||
package = "termscp"
|
||||
@@ -62,18 +62,10 @@ remotefs = "0.3"
|
||||
remotefs-aws-s3 = "0.4"
|
||||
remotefs-kube = "0.4"
|
||||
remotefs-smb = { version = "0.3", optional = true }
|
||||
remotefs-ssh = { version = "0.8", default-features = false, features = [
|
||||
"russh",
|
||||
] }
|
||||
remotefs-ssh = { version = "0.8", default-features = false, features = ["russh"] }
|
||||
remotefs-webdav = "0.2"
|
||||
rpassword = "7"
|
||||
self_update = { version = "0.42", default-features = false, features = [
|
||||
"archive-tar",
|
||||
"archive-zip",
|
||||
"compression-flate2",
|
||||
"compression-zip-deflate",
|
||||
"rustls",
|
||||
] }
|
||||
self_update = { version = "0.42", default-features = false, features = ["archive-tar", "archive-zip", "compression-flate2", "compression-zip-deflate", "rustls"] }
|
||||
semver = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
shellexpand = "3"
|
||||
@@ -91,16 +83,10 @@ whoami = "2"
|
||||
wildmatch = "2"
|
||||
|
||||
[target."cfg(any(target_os = \"linux\", target_os = \"freebsd\"))".dependencies]
|
||||
dbus-secret-service-keyring-store = { version = "1", features = [
|
||||
"crypto-rust",
|
||||
"vendored",
|
||||
] }
|
||||
dbus-secret-service-keyring-store = { version = "1", features = ["crypto-rust", "vendored"] }
|
||||
|
||||
[target."cfg(target_family = \"unix\")".dependencies]
|
||||
remotefs-ftp = { version = "0.4", features = [
|
||||
"native-tls",
|
||||
"native-tls-vendored",
|
||||
] }
|
||||
remotefs-ftp = { version = "0.4", features = ["native-tls", "native-tls-vendored"] }
|
||||
uzers = "0.12"
|
||||
|
||||
[target."cfg(target_family = \"windows\")".dependencies]
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import "./just/build.just"
|
||||
import "./just/changelog.just"
|
||||
import "./just/code_check.just"
|
||||
import "./just/publish.just"
|
||||
import "./just/site.just"
|
||||
import "./just/test.just"
|
||||
|
||||
# Lists all the available commands
|
||||
default:
|
||||
@just --list
|
||||
@@ -43,7 +43,7 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
|
||||
|
||||
## Features 🎁
|
||||
|
||||
- 📁 Different communication protocols
|
||||
- 📁 Different communication protocols
|
||||
- **SFTP**
|
||||
- **SCP**
|
||||
- **FTP** and **FTPS**
|
||||
@@ -51,31 +51,31 @@ Termscp is a feature rich terminal file transfer and explorer, with support for
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- **WebDAV**
|
||||
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
|
||||
- 🖥 Explore and operate on the remote and on the local machine file system with a handy UI
|
||||
- Create, remove, rename, search, view and edit files
|
||||
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
|
||||
- 📝 View and edit files with your favourite applications
|
||||
- 💁 SFTP/SCP authentication with SSH keys and username/password
|
||||
- 🐧 Compatible with Windows, Linux, FreeBSD, NetBSD and MacOS
|
||||
- 🐚 Embedded terminal for executing commands on the system.
|
||||
- 🎨 Make it yours!
|
||||
- ⭐ Connect to your favourite hosts through built-in bookmarks and recent connections
|
||||
- 📝 View and edit files with your favourite applications
|
||||
- 💁 SFTP/SCP authentication with SSH keys and username/password
|
||||
- 🐧 Compatible with Windows, Linux, FreeBSD, NetBSD and MacOS
|
||||
- 🐚 Embedded terminal for executing commands on the system.
|
||||
- 🎨 Make it yours!
|
||||
- Themes
|
||||
- Custom file explorer format
|
||||
- Customizable text editor
|
||||
- Customizable file sorting
|
||||
- and many other parameters...
|
||||
- 📫 Get notified via Desktop Notifications when a large file has been transferred
|
||||
- 🔭 Keep file changes synchronized with the remote host
|
||||
- 🔐 Save your password in your operating system key vault
|
||||
- 🦀 Rust-powered
|
||||
- 👀 Developed keeping an eye on performance
|
||||
- 🦄 Frequent awesome updates
|
||||
- 📫 Get notified via Desktop Notifications when a large file has been transferred
|
||||
- 🔭 Keep file changes synchronized with the remote host
|
||||
- 🔐 Save your password in your operating system key vault
|
||||
- 🦀 Rust-powered
|
||||
- 👀 Developed keeping an eye on performance
|
||||
- 🦄 Frequent awesome updates
|
||||
|
||||
---
|
||||
|
||||
## Get started 🚀
|
||||
|
||||
If you're considering to install termscp I want to thank you 💜 ! I hope you will enjoy termscp!
|
||||
If you're considering to install termscp I want to thank you 💜 ! I hope you will enjoy termscp!\
|
||||
If you want to contribute to this project, don't forget to check out our [contribute guide](CONTRIBUTING.md).
|
||||
|
||||
If you are a Linux, a FreeBSD or a MacOS user this simple shell script will install termscp on your system with a single command:
|
||||
@@ -131,10 +131,10 @@ These requirements are not forced required to run termscp, but to enjoy all of i
|
||||
|
||||
- **Linux/FreeBSD** users:
|
||||
- To **open** files via `V` (at least one of these)
|
||||
- *xdg-open*
|
||||
- *gio*
|
||||
- *gnome-open*
|
||||
- *kde-open*
|
||||
- _xdg-open_
|
||||
- _gio_
|
||||
- _gnome-open_
|
||||
- _kde-open_
|
||||
- **Linux** users:
|
||||
- A keyring manager: read more in the [User manual](https://docs.termscp.rs/en-US/configuration/password-security.html#linux-keyring)
|
||||
- **WSL** users
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# cargo-deny configuration for termscp.
|
||||
#
|
||||
# Run locally with `just deny`. The same command runs in CI and enforces
|
||||
# advisories, licenses, bans, and dependency sources.
|
||||
#
|
||||
# Docs: https://embarkstudios.github.io/cargo-deny/
|
||||
|
||||
[graph]
|
||||
all-features = true
|
||||
|
||||
[output]
|
||||
feature-depth = 1
|
||||
|
||||
[advisories]
|
||||
db-urls = ["https://github.com/rustsec/advisory-db"]
|
||||
yanked = "deny"
|
||||
unmaintained = "all"
|
||||
# These are temporary, reachable transitive-risk acceptances owned by the
|
||||
# termscp maintainers. Review or remove every exception by 2026-12-31. The
|
||||
# upgrade target is a remotefs/self_update release line that accepts each fixed
|
||||
# dependency version; until then, connections to untrusted endpoints remain an
|
||||
# acknowledged denial-of-service and certificate-validation risk.
|
||||
ignore = [
|
||||
# h2 0.3 is retained transitively by the reqwest 0.11/AWS HTTP stack; its
|
||||
# dependency constraints cannot select the fixed h2 0.4 release.
|
||||
{ id = "RUSTSEC-2026-0258", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade reqwest/AWS stack to fixed h2" },
|
||||
# number_prefix is retained by self_update through indicatif. It is
|
||||
# unmaintained, but has no reported vulnerability or compatible replacement.
|
||||
{ id = "RUSTSEC-2025-0119", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade self_update/indicatif" },
|
||||
# Both affected quick-xml lines are constrained by remotefs-webdav and
|
||||
# self_update to versions older than the fixed 0.41 release.
|
||||
{ id = "RUSTSEC-2026-0194", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade remotefs-webdav/self_update to quick-xml >=0.41" },
|
||||
{ id = "RUSTSEC-2026-0195", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade remotefs-webdav/self_update to quick-xml >=0.41" },
|
||||
# The SSH stack requires RSA, for which RustSec reports no safe upgrade.
|
||||
{ id = "RUSTSEC-2023-0071", reason = "owner: termscp maintainers; review by 2026-12-31; replace RSA dependency when upstream fix exists" },
|
||||
# russh-keys retains an older russh-cryptovec line and cannot select the
|
||||
# fixed 0.60.3 release without an upstream dependency update.
|
||||
{ id = "RUSTSEC-2026-0153", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade remotefs-ssh/russh-keys to russh-cryptovec >=0.60.3" },
|
||||
# rustls-pemfile is retained by the WebDAV and Kubernetes clients. Both
|
||||
# versions are unmaintained but have no reported vulnerability.
|
||||
{ id = "RUSTSEC-2025-0134", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade WebDAV/Kubernetes clients away from rustls-pemfile" },
|
||||
# The AWS HTTP stack retains rustls 0.21 and rustls-webpki 0.101, which cannot
|
||||
# select the fixed rustls-webpki release.
|
||||
{ id = "RUSTSEC-2026-0098", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade AWS HTTP stack to fixed rustls-webpki" },
|
||||
{ id = "RUSTSEC-2026-0099", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade AWS HTTP stack to fixed rustls-webpki" },
|
||||
{ id = "RUSTSEC-2026-0104", reason = "owner: termscp maintainers; review by 2026-12-31; upgrade AWS HTTP stack to fixed rustls-webpki" },
|
||||
]
|
||||
|
||||
[licenses]
|
||||
allow = [
|
||||
"Apache-2.0",
|
||||
"BSD-1-Clause",
|
||||
"BSD-2-Clause",
|
||||
"BSD-3-Clause",
|
||||
"BSL-1.0",
|
||||
"CC0-1.0",
|
||||
"CDLA-Permissive-2.0",
|
||||
"ISC",
|
||||
"MIT",
|
||||
"MIT-0",
|
||||
"MPL-2.0",
|
||||
"Unicode-3.0",
|
||||
"Unlicense",
|
||||
"Zlib",
|
||||
]
|
||||
confidence-threshold = 0.8
|
||||
exceptions = [
|
||||
# The WebDAV backend currently depends on rustydav, which declares GPL-3.0.
|
||||
# Keep this exception crate-scoped so no other GPL dependency is admitted.
|
||||
{ allow = ["GPL-3.0"], crate = "rustydav" },
|
||||
]
|
||||
|
||||
[licenses.private]
|
||||
ignore = false
|
||||
|
||||
[bans]
|
||||
multiple-versions = "warn"
|
||||
wildcards = "deny"
|
||||
allow-wildcard-paths = true
|
||||
highlight = "all"
|
||||
workspace-default-features = "allow"
|
||||
external-default-features = "allow"
|
||||
allow = []
|
||||
deny = []
|
||||
skip = []
|
||||
skip-tree = []
|
||||
|
||||
[sources]
|
||||
unknown-registry = "deny"
|
||||
unknown-git = "deny"
|
||||
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
|
||||
allow-git = []
|
||||
Vendored
+4
@@ -4,6 +4,10 @@
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${1:?usage: bump_version.sh <version> [date] [root]}"
|
||||
if [[ ! "$VERSION" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
||||
echo "invalid release version: $VERSION (expected MAJOR.MINOR.PATCH)" >&2
|
||||
exit 2
|
||||
fi
|
||||
DATE="${2:-$(date +%F)}"
|
||||
ROOT="${3:-$(git rev-parse --show-toplevel)}"
|
||||
|
||||
|
||||
@@ -47,20 +47,20 @@ are two quick fixes:
|
||||
1. Re-import the official theme. After each release the official themes are
|
||||
patched, so download the updated theme from the repository and re-import it:
|
||||
|
||||
```sh
|
||||
termscp theme <theme.toml>
|
||||
```
|
||||
```sh
|
||||
termscp theme <theme.toml>
|
||||
```
|
||||
|
||||
2. Edit your theme by hand. If you use a custom theme, edit the file and add the
|
||||
missing key. The theme is located at `$CONFIG_DIR/theme.toml`, where
|
||||
`$CONFIG_DIR` is:
|
||||
|
||||
- FreeBSD/Linux: `$HOME/.config/termscp`
|
||||
- macOS: `$HOME/.config/termscp`
|
||||
- Windows: `%USERPROFILE%\.termscp`
|
||||
- FreeBSD/Linux: `$HOME/.config/termscp`
|
||||
- macOS: `$HOME/.config/termscp`
|
||||
- Windows: `%USERPROFILE%\.termscp`
|
||||
|
||||
Missing keys are reported in the CHANGELOG under `BREAKING CHANGES` for the
|
||||
version you have just installed.
|
||||
Missing keys are reported in the CHANGELOG under `BREAKING CHANGES` for the
|
||||
version you have just installed.
|
||||
|
||||
## Styles
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ works best from different frameworks:
|
||||
more, read <https://github.com/veeso/tui-realm>.
|
||||
- **Components**: components are built around tui in order to reuse widgets. This
|
||||
is achieved through the `Component` trait, inspired by
|
||||
[React](https://reactjs.org/). Each component has its *Properties* and can have
|
||||
its *States*. Each component must handle input events, accept new properties,
|
||||
[React](https://reactjs.org/). Each component has its _Properties_ and can have
|
||||
its _States_. Each component must handle input events, accept new properties,
|
||||
and provide a method to **render** itself. This logic now lives in
|
||||
[tui-realm](https://github.com/veeso/tui-realm).
|
||||
- **Messages: an Elm-based approach**: input events are handled with an approach
|
||||
|
||||
+19
-19
@@ -43,7 +43,7 @@ termscp 是一个功能丰富的终端文件浏览和传输工具,支持 SCP/S
|
||||
|
||||
## 特性 🎁
|
||||
|
||||
- 📁 支持多种通信协议
|
||||
- 📁 支持多种通信协议
|
||||
- **SFTP**
|
||||
- **SCP**
|
||||
- **FTP** 和 **FTPS**
|
||||
@@ -51,31 +51,31 @@ termscp 是一个功能丰富的终端文件浏览和传输工具,支持 SCP/S
|
||||
- **S3**
|
||||
- **SMB**
|
||||
- **WebDAV**
|
||||
- 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作
|
||||
- 🖥 使用便捷的 UI 在远程和本地文件系统上浏览和操作
|
||||
- 创建、删除、重命名、搜索、查看和编辑文件
|
||||
- ⭐ 通过“内置书签”和“最近连接”快速连接到您喜爱的主机
|
||||
- 📝 使用您喜欢的应用程序查看和编辑文件
|
||||
- 💁 使用 SSH 密钥和用户名/密码进行 SFTP/SCP 身份验证
|
||||
- 🐧 兼容 Windows、Linux、FreeBSD、NetBSD 和 MacOS 操作系统
|
||||
- 🐚 内置终端,可在系统上执行命令。
|
||||
- 🎨 丰富的个性化设置!
|
||||
- ⭐ 通过“内置书签”和“最近连接”快速连接到您喜爱的主机
|
||||
- 📝 使用您喜欢的应用程序查看和编辑文件
|
||||
- 💁 使用 SSH 密钥和用户名/密码进行 SFTP/SCP 身份验证
|
||||
- 🐧 兼容 Windows、Linux、FreeBSD、NetBSD 和 MacOS 操作系统
|
||||
- 🐚 内置终端,可在系统上执行命令。
|
||||
- 🎨 丰富的个性化设置!
|
||||
- 主题
|
||||
- 自定义文件浏览器格式
|
||||
- 可自定义的文本编辑器
|
||||
- 可自定义的文件排序
|
||||
- 以及许多其他参数...
|
||||
- 📫 传输大文件时通过桌面通知获得提醒
|
||||
- 🔭 与远程主机文件更改保持同步
|
||||
- 🔐 将密码保存在操作系统密钥保管库中
|
||||
- 🦀 由 Rust 提供强力支持
|
||||
- 👀 开发时更注重性能
|
||||
- 🦄 频繁的精彩更新
|
||||
- 📫 传输大文件时通过桌面通知获得提醒
|
||||
- 🔭 与远程主机文件更改保持同步
|
||||
- 🔐 将密码保存在操作系统密钥保管库中
|
||||
- 🦀 由 Rust 提供强力支持
|
||||
- 👀 开发时更注重性能
|
||||
- 🦄 频繁的精彩更新
|
||||
|
||||
---
|
||||
|
||||
## 开始 🚀
|
||||
|
||||
如果您正在考虑安装 termscp,我想对您表示感谢 💜 ! 希望您会喜欢 termscp!
|
||||
如果您正在考虑安装 termscp,我想对您表示感谢 💜 ! 希望您会喜欢 termscp!\
|
||||
如果您想为此项目做出贡献,请不要忘记查看我们的[贡献指南](CONTRIBUTING.md)。
|
||||
|
||||
如果您是 Linux、FreeBSD 或 MacOS 用户,使用以下简单的 shell 脚本即可通过单行指令在您的系统上安装 termscp:
|
||||
@@ -131,10 +131,10 @@ pacman -S termscp
|
||||
|
||||
- **Linux/FreeBSD** 用户:
|
||||
- 用 `V` **打开**文件(至少其中之一)
|
||||
- *xdg-open*
|
||||
- *gio*
|
||||
- *gnome-open*
|
||||
- *kde-open*
|
||||
- _xdg-open_
|
||||
- _gio_
|
||||
- _gnome-open_
|
||||
- _kde-open_
|
||||
- **Linux** 用户:
|
||||
- 密钥环管理器:在[用户手册](https://docs.termscp.rs/zh-CN/configuration/password-security.html#linux-密钥环)中阅读更多内容
|
||||
- **WSL** 用户
|
||||
|
||||
+10
-10
@@ -18,16 +18,16 @@ termscp [options]... -b [bookmark-name] -b [bookmark-name] [local-wrkdir]
|
||||
|
||||
## 选项
|
||||
|
||||
| Key | 说明 |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `-b <bookmark-name>` | 将位置地址参数解析为书签名称。重复使用该标志可以打开多个书签。 |
|
||||
| `-D` | 启用 `TRACE` 日志级别(调试/详细日志)。 |
|
||||
| `-P <password>` | 从命令行提供密码。重复使用该标志可为多个远程主机提供密码;其顺序必须与地址参数一致。不推荐使用。 |
|
||||
| `-q` | 禁用日志记录。 |
|
||||
| `-T <ticks>` | 设置 UI 的 tick 间隔(以毫秒为单位)。默认值为 `10`。 |
|
||||
| `--wno-keyring` | 禁用系统 keyring 支持。 |
|
||||
| `-v` | 打印版本信息。 |
|
||||
| `--help` | 打印帮助页面。 |
|
||||
| Key | 说明 |
|
||||
| -------------------- | ------------------------------------------------ |
|
||||
| `-b <bookmark-name>` | 将位置地址参数解析为书签名称。重复使用该标志可以打开多个书签。 |
|
||||
| `-D` | 启用 `TRACE` 日志级别(调试/详细日志)。 |
|
||||
| `-P <password>` | 从命令行提供密码。重复使用该标志可为多个远程主机提供密码;其顺序必须与地址参数一致。不推荐使用。 |
|
||||
| `-q` | 禁用日志记录。 |
|
||||
| `-T <ticks>` | 设置 UI 的 tick 间隔(以毫秒为单位)。默认值为 `10`。 |
|
||||
| `--wno-keyring` | 禁用系统 keyring 支持。 |
|
||||
| `-v` | 打印版本信息。 |
|
||||
| `--help` | 打印帮助页面。 |
|
||||
|
||||
不推荐使用 `-P` 选项,因为密码可能会保留在 shell 历史记录中。请参阅书签和密码安全章节,了解更安全的凭据提供方式。
|
||||
|
||||
|
||||
@@ -20,18 +20,18 @@
|
||||
|
||||
以下是格式化器支持的键:
|
||||
|
||||
| 键 | 说明 |
|
||||
| --------- | ------------------------------------------------------------------------------------------------ |
|
||||
| `ATIME` | 最后访问时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{ATIME:8:%H:%M}`) |
|
||||
| `CTIME` | 创建时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{CTIME:8:%H:%M}`) |
|
||||
| `GROUP` | 所属组 |
|
||||
| `MTIME` | 最后修改时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{MTIME:8:%H:%M}`) |
|
||||
| `NAME` | 文件名(如果根目录与首个祖先目录之间的文件夹长度超过 `LENGTH`,则会被省略) |
|
||||
| `PATH` | 文件绝对路径(如果根目录与首个祖先目录之间的文件夹长度超过 `LENGTH`,则会被省略) |
|
||||
| `PEX` | 文件权限(UNIX 格式) |
|
||||
| `SIZE` | 文件大小(目录省略) |
|
||||
| `SYMLINK` | 符号链接目标(如果有,`-> {FILE_PATH}`) |
|
||||
| `USER` | 所属用户 |
|
||||
| 键 | 说明 |
|
||||
| --------- | --------------------------------------------------------------- |
|
||||
| `ATIME` | 最后访问时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{ATIME:8:%H:%M}`) |
|
||||
| `CTIME` | 创建时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{CTIME:8:%H:%M}`) |
|
||||
| `GROUP` | 所属组 |
|
||||
| `MTIME` | 最后修改时间(默认 `%b %d %Y %H:%M`);`EXTRA` 为时间格式(例如 `{MTIME:8:%H:%M}`) |
|
||||
| `NAME` | 文件名(如果根目录与首个祖先目录之间的文件夹长度超过 `LENGTH`,则会被省略) |
|
||||
| `PATH` | 文件绝对路径(如果根目录与首个祖先目录之间的文件夹长度超过 `LENGTH`,则会被省略) |
|
||||
| `PEX` | 文件权限(UNIX 格式) |
|
||||
| `SIZE` | 文件大小(目录省略) |
|
||||
| `SYMLINK` | 符号链接目标(如果有,`-> {FILE_PATH}`) |
|
||||
| `USER` | 所属用户 |
|
||||
|
||||
## 默认格式
|
||||
|
||||
|
||||
@@ -36,17 +36,17 @@ termscp 接受以下颜色格式:
|
||||
|
||||
1. 重新导入官方主题。每次发布后,官方主题都会被修补,因此从仓库下载更新后的主题并重新导入:
|
||||
|
||||
```sh
|
||||
termscp theme <theme.toml>
|
||||
```
|
||||
```sh
|
||||
termscp theme <theme.toml>
|
||||
```
|
||||
|
||||
2. 手动编辑你的主题。如果你使用自定义主题,请编辑该文件并添加缺失的键。主题位于 `$CONFIG_DIR/theme.toml`,其中 `$CONFIG_DIR` 为:
|
||||
|
||||
- FreeBSD/Linux:`$HOME/.config/termscp`
|
||||
- macOS:`$HOME/.config/termscp`
|
||||
- Windows:`%USERPROFILE%\.termscp`
|
||||
- FreeBSD/Linux:`$HOME/.config/termscp`
|
||||
- macOS:`$HOME/.config/termscp`
|
||||
- Windows:`%USERPROFILE%\.termscp`
|
||||
|
||||
缺失的键会在你刚安装的版本的 CHANGELOG 中 `BREAKING CHANGES` 部分列出。
|
||||
缺失的键会在你刚安装的版本的 CHANGELOG 中 `BREAKING CHANGES` 部分列出。
|
||||
|
||||
## 样式
|
||||
|
||||
@@ -54,44 +54,44 @@ termscp 接受以下颜色格式:
|
||||
|
||||
### 认证页面
|
||||
|
||||
| 键 | 说明 |
|
||||
| ---------------- | -------------------------- |
|
||||
| `auth_address` | IP 地址输入框的颜色 |
|
||||
| `auth_bookmarks` | 书签面板的颜色 |
|
||||
| `auth_password` | 密码输入框的颜色 |
|
||||
| `auth_port` | 端口号输入框的颜色 |
|
||||
| `auth_protocol` | 协议单选框组的颜色 |
|
||||
| `auth_recents` | 最近记录面板的颜色 |
|
||||
| `auth_username` | 用户名输入框的颜色 |
|
||||
| 键 | 说明 |
|
||||
| ---------------- | ----------- |
|
||||
| `auth_address` | IP 地址输入框的颜色 |
|
||||
| `auth_bookmarks` | 书签面板的颜色 |
|
||||
| `auth_password` | 密码输入框的颜色 |
|
||||
| `auth_port` | 端口号输入框的颜色 |
|
||||
| `auth_protocol` | 协议单选框组的颜色 |
|
||||
| `auth_recents` | 最近记录面板的颜色 |
|
||||
| `auth_username` | 用户名输入框的颜色 |
|
||||
|
||||
### 传输页面
|
||||
|
||||
| 键 | 说明 |
|
||||
| -------------------------------------- | -------------------------------------------------- |
|
||||
| `transfer_local_explorer_background` | 本地主机浏览器的背景色 |
|
||||
| `transfer_local_explorer_foreground` | 本地主机浏览器的前景色 |
|
||||
| `transfer_local_explorer_highlighted` | 本地主机浏览器的边框及高亮颜色 |
|
||||
| `transfer_remote_explorer_background` | 远程浏览器的背景色 |
|
||||
| `transfer_remote_explorer_foreground` | 远程浏览器的前景色 |
|
||||
| `transfer_remote_explorer_highlighted` | 远程浏览器的边框及高亮颜色 |
|
||||
| `transfer_log_background` | 日志面板的背景色 |
|
||||
| `transfer_log_window` | 日志面板的窗口颜色 |
|
||||
| `transfer_progress_bar_partial` | 部分进度条的颜色 |
|
||||
| `transfer_progress_bar_total` | 总进度条的颜色 |
|
||||
| `transfer_status_hidden` | 状态栏 "hidden" 标签的颜色 |
|
||||
| 键 | 说明 |
|
||||
| -------------------------------------- | ------------------------------- |
|
||||
| `transfer_local_explorer_background` | 本地主机浏览器的背景色 |
|
||||
| `transfer_local_explorer_foreground` | 本地主机浏览器的前景色 |
|
||||
| `transfer_local_explorer_highlighted` | 本地主机浏览器的边框及高亮颜色 |
|
||||
| `transfer_remote_explorer_background` | 远程浏览器的背景色 |
|
||||
| `transfer_remote_explorer_foreground` | 远程浏览器的前景色 |
|
||||
| `transfer_remote_explorer_highlighted` | 远程浏览器的边框及高亮颜色 |
|
||||
| `transfer_log_background` | 日志面板的背景色 |
|
||||
| `transfer_log_window` | 日志面板的窗口颜色 |
|
||||
| `transfer_progress_bar_partial` | 部分进度条的颜色 |
|
||||
| `transfer_progress_bar_total` | 总进度条的颜色 |
|
||||
| `transfer_status_hidden` | 状态栏 "hidden" 标签的颜色 |
|
||||
| `transfer_status_sorting` | 状态栏 "sorting" 标签的颜色;也适用于文件排序对话框 |
|
||||
| `transfer_status_sync_browsing` | 状态栏 "sync browsing" 标签的颜色 |
|
||||
| `transfer_status_sync_browsing` | 状态栏 "sync browsing" 标签的颜色 |
|
||||
|
||||
### 杂项
|
||||
|
||||
这些样式适用于应用程序的不同部分。
|
||||
|
||||
| 键 | 说明 |
|
||||
| ------------------- | -------------------------------- |
|
||||
| `misc_error_dialog` | 错误消息的颜色 |
|
||||
| `misc_info_dialog` | 信息对话框的颜色 |
|
||||
| 键 | 说明 |
|
||||
| ------------------- | ---------------- |
|
||||
| `misc_error_dialog` | 错误消息的颜色 |
|
||||
| `misc_info_dialog` | 信息对话框的颜色 |
|
||||
| `misc_input_dialog` | 输入对话框的颜色(例如复制文件) |
|
||||
| `misc_keys` | 按键文本的颜色 |
|
||||
| `misc_quit_dialog` | 退出对话框的颜色 |
|
||||
| `misc_save_dialog` | 保存对话框的颜色 |
|
||||
| `misc_warn_dialog` | 警告对话框的颜色 |
|
||||
| `misc_keys` | 按键文本的颜色 |
|
||||
| `misc_quit_dialog` | 退出对话框的颜色 |
|
||||
| `misc_save_dialog` | 保存对话框的颜色 |
|
||||
| `misc_warn_dialog` | 警告对话框的颜色 |
|
||||
|
||||
@@ -30,7 +30,7 @@ termscp 支持以下协议:SFTP、SCP、FTP/FTPS、Kube、S3、SMB 和 WebDAV
|
||||
|
||||
- **顶层的 Activities**:每个“视图”都是一个 Activity,并由 `Activity Manager` 来处理它们。这种方法受 Android 启发。它适用于具有不同视图的 ui,每个视图都有自己的组件和逻辑。Activities 与 `Context` 协作,`Context` 是用于在 activities 之间共享数据的数据持有者。
|
||||
- **Activities 显示 Applications**:每个 activity 可以显示不同的 **Applications**。一个 application 包含一个 **View**,它基本上是一个 **components** 列表,每个组件都有其属性。view 是组件的门面,同时也处理焦点,即当前处于活动状态的组件。你不能拥有多个活动组件,因此必须对此进行处理;与此同时,如果当前组件被销毁,焦点必须交还给之前处于活动状态的组件。**Application** 负责处理所有这些工作。要了解更多信息,请阅读 <https://github.com/veeso/tui-realm>。
|
||||
- **Components**:components 是围绕 tui 构建的,以便复用控件。这是通过 `Component` trait 实现的,该 trait 受 [React](https://reactjs.org/) 启发。每个组件都有其 *Properties*,并且可以拥有其 *States*。每个组件必须处理输入事件、接受新的属性,并提供一个用于**渲染**自身的方法。这一逻辑现在位于 [tui-realm](https://github.com/veeso/tui-realm) 中。
|
||||
- **Components**:components 是围绕 tui 构建的,以便复用控件。这是通过 `Component` trait 实现的,该 trait 受 [React](https://reactjs.org/) 启发。每个组件都有其 _Properties_,并且可以拥有其 _States_。每个组件必须处理输入事件、接受新的属性,并提供一个用于**渲染**自身的方法。这一逻辑现在位于 [tui-realm](https://github.com/veeso/tui-realm) 中。
|
||||
- **Messages:基于 Elm 的方法**:输入事件采用受 [Elm](https://elm-lang.org/) 启发的方法来处理。在 Elm 中,你使用三个基本函数来实现 ui:**update**、**view** 和 **init**。termscp 将 Elm update 函数的等价实现编写为一个递归函数内部的大型 match 分支,你可以在每个 activity 的 `update.rs` 文件中找到它。这个 match 分支处理组件为响应传入的输入事件而产生的消息,并促使 activity 改变其状态。
|
||||
|
||||
termscp 实现了一个名为 `Activity` 的 trait,它是 Android activity 的一个大幅精简版本。该 trait 提供以下方法:
|
||||
|
||||
@@ -2,48 +2,48 @@
|
||||
|
||||
以下按键可在文件浏览器中使用。随时按 `<H|F1>` 可打开应用内帮助。
|
||||
|
||||
| 按键 | 操作 |
|
||||
| -------------- | ---------------------------------------------------------------------- |
|
||||
| `<ESC>` | 断开与远程的连接并返回认证页面 |
|
||||
| `<BACKSPACE>` | 返回导航栈中的上一个目录 |
|
||||
| `<TAB>` | 切换当前活动的浏览器选项卡 |
|
||||
| `<RIGHT>` | 移动到远程浏览器选项卡 |
|
||||
| `<LEFT>` | 移动到本地浏览器选项卡 |
|
||||
| `<UP>` | 在所选列表中向上移动 |
|
||||
| `<DOWN>` | 在所选列表中向下移动 |
|
||||
| `<PGUP>` | 在所选列表中向上移动 8 行 |
|
||||
| `<PGDOWN>` | 在所选列表中向下移动 8 行 |
|
||||
| `<ENTER>` | 进入所选目录 |
|
||||
| `<SPACE>` | 上传或下载所选文件 |
|
||||
| `<BACKTAB>` | 在日志选项卡与浏览器之间切换 |
|
||||
| `<A>` | 切换是否显示隐藏文件 |
|
||||
| `<B>` | 选择文件的排序方式 |
|
||||
| `<C\|F5>` | 复制所选文件或目录 |
|
||||
| `<D\|F7>` | 新建目录 |
|
||||
| `<E\|F8\|DEL>` | 删除所选文件 |
|
||||
| `<F>` | 搜索文件(支持通配符匹配) |
|
||||
| `<G>` | 跳转到指定路径 |
|
||||
| `<H\|F1>` | 显示帮助 |
|
||||
| `<I>` | 显示所选文件或目录的信息 |
|
||||
| `<K>` | 创建指向当前所选条目的符号链接 |
|
||||
| `<L>` | 重新加载当前目录的内容,或清除当前选择 |
|
||||
| `<M>` | 选择一个文件 |
|
||||
| `<N>` | 使用提供的名称创建新文件 |
|
||||
| `<O\|F4>` | 在文本编辑器中编辑所选文件 |
|
||||
| `<P>` | 打开日志面板 |
|
||||
| `<Q\|F10>` | 退出 termscp |
|
||||
| `<R\|F6>` | 重命名所选文件 |
|
||||
| `<S\|F2>` | 将所选文件另存为新名称 |
|
||||
| `<T>` | 将所选路径上的更改同步到远程 |
|
||||
| `<U>` | 进入上级目录 |
|
||||
| `<V\|F3>` | 使用该文件类型的默认程序打开所选文件 |
|
||||
| `<W>` | 使用你指定的程序打开所选文件 |
|
||||
| `<X>` | 执行命令 |
|
||||
| `<Y>` | 切换同步浏览 |
|
||||
| `<Z>` | 更改文件模式 |
|
||||
| `</>` | 过滤文件(同时支持正则表达式和通配符匹配) |
|
||||
| `<CTRL+A>` | 选择所有文件 |
|
||||
| `<ALT+A>` | 取消选择所有文件 |
|
||||
| `<CTRL+C>` | 中止文件传输过程 |
|
||||
| `<CTRL+S>` | 获取所选路径的总大小 |
|
||||
| `<CTRL+T>` | 显示所有已同步的路径 |
|
||||
| 按键 | 操作 |
|
||||
| -------------- | --------------------- |
|
||||
| `<ESC>` | 断开与远程的连接并返回认证页面 |
|
||||
| `<BACKSPACE>` | 返回导航栈中的上一个目录 |
|
||||
| `<TAB>` | 切换当前活动的浏览器选项卡 |
|
||||
| `<RIGHT>` | 移动到远程浏览器选项卡 |
|
||||
| `<LEFT>` | 移动到本地浏览器选项卡 |
|
||||
| `<UP>` | 在所选列表中向上移动 |
|
||||
| `<DOWN>` | 在所选列表中向下移动 |
|
||||
| `<PGUP>` | 在所选列表中向上移动 8 行 |
|
||||
| `<PGDOWN>` | 在所选列表中向下移动 8 行 |
|
||||
| `<ENTER>` | 进入所选目录 |
|
||||
| `<SPACE>` | 上传或下载所选文件 |
|
||||
| `<BACKTAB>` | 在日志选项卡与浏览器之间切换 |
|
||||
| `<A>` | 切换是否显示隐藏文件 |
|
||||
| `<B>` | 选择文件的排序方式 |
|
||||
| `<C\|F5>` | 复制所选文件或目录 |
|
||||
| `<D\|F7>` | 新建目录 |
|
||||
| `<E\|F8\|DEL>` | 删除所选文件 |
|
||||
| `<F>` | 搜索文件(支持通配符匹配) |
|
||||
| `<G>` | 跳转到指定路径 |
|
||||
| `<H\|F1>` | 显示帮助 |
|
||||
| `<I>` | 显示所选文件或目录的信息 |
|
||||
| `<K>` | 创建指向当前所选条目的符号链接 |
|
||||
| `<L>` | 重新加载当前目录的内容,或清除当前选择 |
|
||||
| `<M>` | 选择一个文件 |
|
||||
| `<N>` | 使用提供的名称创建新文件 |
|
||||
| `<O\|F4>` | 在文本编辑器中编辑所选文件 |
|
||||
| `<P>` | 打开日志面板 |
|
||||
| `<Q\|F10>` | 退出 termscp |
|
||||
| `<R\|F6>` | 重命名所选文件 |
|
||||
| `<S\|F2>` | 将所选文件另存为新名称 |
|
||||
| `<T>` | 将所选路径上的更改同步到远程 |
|
||||
| `<U>` | 进入上级目录 |
|
||||
| `<V\|F3>` | 使用该文件类型的默认程序打开所选文件 |
|
||||
| `<W>` | 使用你指定的程序打开所选文件 |
|
||||
| `<X>` | 执行命令 |
|
||||
| `<Y>` | 切换同步浏览 |
|
||||
| `<Z>` | 更改文件模式 |
|
||||
| `</>` | 过滤文件(同时支持正则表达式和通配符匹配) |
|
||||
| `<CTRL+A>` | 选择所有文件 |
|
||||
| `<ALT+A>` | 取消选择所有文件 |
|
||||
| `<CTRL+C>` | 中止文件传输过程 |
|
||||
| `<CTRL+S>` | 获取所选路径的总大小 |
|
||||
| `<CTRL+T>` | 显示所有已同步的路径 |
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"$schema": "https://dprint.dev/schemas/v0.json",
|
||||
"indentWidth": 2,
|
||||
"lineWidth": 80,
|
||||
"newLineKind": "lf",
|
||||
"markdown": {
|
||||
"textWrap": "maintain"
|
||||
},
|
||||
"toml": {},
|
||||
"yaml": {},
|
||||
"exec": {
|
||||
"cwd": "${configDir}",
|
||||
"commands": [
|
||||
{
|
||||
"command": "rustup run nightly rustfmt --edition 2024",
|
||||
"exts": ["rs"],
|
||||
"cacheKeyFiles": ["rustfmt.toml", "rust-toolchain.toml"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"excludes": [
|
||||
"**/target",
|
||||
"**/node_modules",
|
||||
"**/*-lock.json",
|
||||
"Cargo.lock",
|
||||
"docs/book",
|
||||
"docs/zh-CN/cli/cli.md",
|
||||
"docs/zh-CN/configuration/explorer-format.md",
|
||||
"docs/zh-CN/configuration/themes.md",
|
||||
"docs/zh-CN/usage/keyboard-shortcuts.md",
|
||||
"**/tests/fixtures"
|
||||
],
|
||||
"plugins": [
|
||||
"https://plugins.dprint.dev/markdown-0.22.1.wasm@4906fbb038977732aae0e216e4b0b957e2722f8d79282660ccb36d27dd051f17",
|
||||
"https://plugins.dprint.dev/toml-0.7.0.wasm@0126c8112691542d30b52a639076ecc83e07bace877638cee7c6915fd36b8629",
|
||||
"https://plugins.dprint.dev/g-plane/pretty_yaml-v0.6.0.wasm@40a2fdda7040317eb1b23520f3a00769a5571eedb049c4ca9175c1b9eeba01ae",
|
||||
"https://plugins.dprint.dev/dprint/exec-0.6.2.json@df98f54ffd3092b8a841aedd6d098a2651f16d0a796a40535774f1a8b4b9d463"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
# Build everything
|
||||
[group('build')]
|
||||
build_all: build_crates
|
||||
|
||||
# Build the Rust crate
|
||||
[group('build')]
|
||||
build_crates args="":
|
||||
cargo build --workspace {{ args }}
|
||||
|
||||
# Build all Rust crates in release mode
|
||||
[group('build')]
|
||||
build_crates_release:
|
||||
just build_crates "--release"
|
||||
|
||||
# Build a release binary for a target triple
|
||||
[group('build')]
|
||||
build_release target features="":
|
||||
cargo build --locked --release --target {{ target }} {{ features }}
|
||||
|
||||
# Package an already-built Linux release as a Debian package
|
||||
[group('build')]
|
||||
package_deb target:
|
||||
cargo deb --no-build --target {{ target }} --features smb-vendored
|
||||
|
||||
# Update Cargo.lock; pass cargo update arguments to scope the update.
|
||||
[group('build')]
|
||||
update_lock args="":
|
||||
cargo update {{ args }}
|
||||
|
||||
# Clean build artifacts
|
||||
[group('build')]
|
||||
[confirm("Are you sure you want to clean the build artifacts?")]
|
||||
clean:
|
||||
cargo clean
|
||||
@@ -0,0 +1,44 @@
|
||||
set positional-arguments
|
||||
|
||||
# Print the unreleased changelog section to stdout (preview only), e.g. `just changelog_preview 8.1.0`
|
||||
[group('changelog')]
|
||||
changelog_preview version:
|
||||
git-cliff --config cliff.toml --unreleased --tag "v$1" --strip all
|
||||
|
||||
# Add a new entry to CHANGELOG.md from the unreleased conventional commits, e.g. `just changelog 8.1.0`
|
||||
[group('changelog')]
|
||||
changelog version:
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
version="$1"
|
||||
if [[ ! "$version" =~ ^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
||||
echo "invalid release version: $version (expected MAJOR.MINOR.PATCH)" >&2
|
||||
exit 2
|
||||
fi
|
||||
tag="v$version"
|
||||
section="$(git-cliff --config cliff.toml --unreleased --tag "$tag" --strip all)"
|
||||
if [ -z "$section" ]; then
|
||||
echo "No unreleased conventional commits found; nothing to add." >&2
|
||||
exit 0
|
||||
fi
|
||||
anchor="$(printf '%s' "$version" | tr -d '.')"
|
||||
secfile="$(mktemp)"
|
||||
tmp="$(mktemp)"
|
||||
printf '%s\n' "$section" > "$secfile"
|
||||
# Insert a TOC entry before the first existing version entry and the rendered
|
||||
# section before the first existing version heading, keeping the title + TOC.
|
||||
awk -v secfile="$secfile" -v ver="$version" -v anc="$anchor" '
|
||||
!toc_done && /^[[:space:]]*- \[[0-9]/ {
|
||||
print " - [" ver "](#" anc ")"
|
||||
toc_done = 1
|
||||
}
|
||||
!body_done && /^## [0-9]/ {
|
||||
while ((getline line < secfile) > 0) print line
|
||||
print ""
|
||||
body_done = 1
|
||||
}
|
||||
{ print }
|
||||
' CHANGELOG.md > "$tmp"
|
||||
rm -f "$secfile"
|
||||
mv "$tmp" CHANGELOG.md
|
||||
echo "CHANGELOG.md updated for $tag"
|
||||
@@ -0,0 +1,57 @@
|
||||
alias lint := clippy
|
||||
|
||||
# Format all sources (Markdown, TOML, YAML and Rust via nightly rustfmt) with dprint
|
||||
[group('code_check')]
|
||||
fmt args="":
|
||||
dprint fmt {{ args }}
|
||||
|
||||
# Check formatting of all sources with dprint (no writes)
|
||||
[group('code_check')]
|
||||
fmt_check args="":
|
||||
dprint check {{ args }}
|
||||
|
||||
# Run clippy on all targets
|
||||
[group('code_check')]
|
||||
clippy args="":
|
||||
cargo clippy --workspace --all-targets {{ args }}
|
||||
|
||||
# Build the crate documentation, denying warnings
|
||||
[group('code_check')]
|
||||
doc args="":
|
||||
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps {{ args }}
|
||||
|
||||
# Check dependencies for advisories, licenses, bans and sources (cargo-deny)
|
||||
[group('code_check')]
|
||||
deny args="":
|
||||
cargo deny check {{ args }}
|
||||
|
||||
# Scan for secrets with trufflehog (defaults to the whole working tree)
|
||||
[group('code_check')]
|
||||
scan_secrets *args=".":
|
||||
trufflehog filesystem {{ args }} --results=verified,unknown --fail --no-update
|
||||
|
||||
# Point git at the tracked .githooks directory (installs the pre-commit hook)
|
||||
[group('code_check')]
|
||||
setup_githooks:
|
||||
git config core.hooksPath .githooks
|
||||
@echo "git hooks installed: core.hooksPath = .githooks"
|
||||
|
||||
# Lint the install scripts (shellcheck; PowerShell parse when pwsh is available)
|
||||
[group('code_check')]
|
||||
check_install_scripts:
|
||||
sh -n install.sh
|
||||
shellcheck install.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 \
|
||||
echo "pwsh not found: skipping install.ps1 parse check"; \
|
||||
fi
|
||||
|
||||
# Run all code checks. Fails if any check fails
|
||||
[group('code_check')]
|
||||
check_code:
|
||||
just fmt_check
|
||||
just clippy "-- -D warnings"
|
||||
just doc
|
||||
just deny
|
||||
just check_install_scripts
|
||||
@@ -0,0 +1,4 @@
|
||||
# Publish the termscp crate
|
||||
[group('publish')]
|
||||
publish_crate args="":
|
||||
cargo publish --locked --features smb-vendored {{ args }}
|
||||
@@ -0,0 +1,28 @@
|
||||
# Install website dependencies from the lockfile
|
||||
[group('site')]
|
||||
site_install:
|
||||
cd site && npm ci
|
||||
|
||||
# Check website formatting
|
||||
[group('site')]
|
||||
site_fmt_check:
|
||||
cd site && npm run format:check
|
||||
|
||||
# Run Astro and TypeScript checks
|
||||
[group('site')]
|
||||
site_check:
|
||||
cd site && npm run check
|
||||
|
||||
# Run website tests when the package defines them
|
||||
[group('site')]
|
||||
site_test:
|
||||
cd site && npm test --if-present
|
||||
|
||||
# Build the website
|
||||
[group('site')]
|
||||
site_build:
|
||||
cd site && npm run build
|
||||
|
||||
# Run every website validation step
|
||||
[group('site')]
|
||||
site_ci: site_fmt_check site_check site_test site_build
|
||||
@@ -0,0 +1,13 @@
|
||||
# Run all tests
|
||||
[group('test')]
|
||||
test_all: test
|
||||
|
||||
# Run the Rust test suite
|
||||
[group('test')]
|
||||
test args="":
|
||||
cargo test --workspace {{ args }}
|
||||
|
||||
# Generate an LCOV code coverage report for the Rust workspace (requires cargo-llvm-cov)
|
||||
[group('test')]
|
||||
coverage output="lcov.info":
|
||||
cargo llvm-cov --workspace --lcov --output-path {{ output }}
|
||||
@@ -0,0 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "1.98.0"
|
||||
components = ["clippy", "rustfmt"]
|
||||
@@ -200,7 +200,7 @@ mod tests {
|
||||
.unwrap(),
|
||||
PathBuf::from("/home/omar/.ssh/beaglebone.key")
|
||||
);
|
||||
assert!(cfg.remote.ssh_keys.get(&String::from("1.1.1.1")).is_none());
|
||||
assert!(!cfg.remote.ssh_keys.contains_key("1.1.1.1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -240,7 +240,7 @@ mod tests {
|
||||
.unwrap(),
|
||||
PathBuf::from("/home/omar/.ssh/beaglebone.key")
|
||||
);
|
||||
assert!(cfg.remote.ssh_keys.get(&String::from("1.1.1.1")).is_none());
|
||||
assert!(!cfg.remote.ssh_keys.contains_key("1.1.1.1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+8
-8
@@ -401,7 +401,7 @@ mod tests {
|
||||
assert_eq!(explorer.dirstack.len(), 2);
|
||||
assert_eq!(*explorer.dirstack.get(1).unwrap(), PathBuf::from("/dev"));
|
||||
assert_eq!(
|
||||
*explorer.dirstack.get(0).unwrap(),
|
||||
*explorer.dirstack.front().unwrap(),
|
||||
PathBuf::from("/home/omar")
|
||||
);
|
||||
}
|
||||
@@ -425,7 +425,7 @@ mod tests {
|
||||
assert!(explorer.get(100).is_none());
|
||||
//assert_eq!(explorer.count(), 6);
|
||||
// Verify (files are sorted by name)
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), ".git");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), ".git");
|
||||
// Iter files (all)
|
||||
assert_eq!(explorer.iter_files_all().count(), 6);
|
||||
// Iter files (hidden excluded) (.git, .gitignore are hidden)
|
||||
@@ -453,7 +453,7 @@ mod tests {
|
||||
]);
|
||||
explorer.sort_by(FileSorting::Name);
|
||||
// First entry should be "Cargo.lock"
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "Cargo.lock");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "Cargo.lock");
|
||||
// Last should be "src"
|
||||
assert_eq!(explorer.files.get(8).unwrap().name(), "src");
|
||||
}
|
||||
@@ -469,7 +469,7 @@ mod tests {
|
||||
explorer.set_files(vec![entry1, entry2]);
|
||||
explorer.sort_by(FileSorting::ModifyTime);
|
||||
// First entry should be "CODE_OF_CONDUCT.md"
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "CODE_OF_CONDUCT.md");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "CODE_OF_CONDUCT.md");
|
||||
// Last should be "src"
|
||||
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
|
||||
}
|
||||
@@ -485,7 +485,7 @@ mod tests {
|
||||
explorer.set_files(vec![entry1, entry2]);
|
||||
explorer.sort_by(FileSorting::CreationTime);
|
||||
// First entry should be "CODE_OF_CONDUCT.md"
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "CODE_OF_CONDUCT.md");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "CODE_OF_CONDUCT.md");
|
||||
// Last should be "src"
|
||||
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
|
||||
}
|
||||
@@ -501,7 +501,7 @@ mod tests {
|
||||
]);
|
||||
explorer.sort_by(FileSorting::Size);
|
||||
// Directory has size 4096
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "src");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "src");
|
||||
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
|
||||
assert_eq!(explorer.files.get(2).unwrap().name(), "CONTRIBUTING.md");
|
||||
}
|
||||
@@ -525,7 +525,7 @@ mod tests {
|
||||
explorer.sort_by(FileSorting::Name);
|
||||
explorer.group_dirs_by(Some(GroupDirs::First));
|
||||
// First entry should be "docs"
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "docs");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "docs");
|
||||
assert_eq!(explorer.files.get(1).unwrap().name(), "src");
|
||||
// 3rd is file first for alphabetical order
|
||||
assert_eq!(explorer.files.get(2).unwrap().name(), "Cargo.lock");
|
||||
@@ -555,7 +555,7 @@ mod tests {
|
||||
assert_eq!(explorer.files.get(8).unwrap().name(), "docs");
|
||||
assert_eq!(explorer.files.get(9).unwrap().name(), "src");
|
||||
// first is file for alphabetical order
|
||||
assert_eq!(explorer.files.get(0).unwrap().name(), "Cargo.lock");
|
||||
assert_eq!(explorer.files.first().unwrap().name(), "Cargo.lock");
|
||||
// Last in files should be "README.md" (last file for alphabetical ordening)
|
||||
assert_eq!(explorer.files.get(7).unwrap().name(), "README.md");
|
||||
}
|
||||
|
||||
+17
-15
@@ -602,9 +602,11 @@ mod tests {
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
use super::*;
|
||||
use crate::utils::test_helpers::create_sample_file;
|
||||
#[cfg(posix)]
|
||||
use crate::utils::test_helpers::make_file_at;
|
||||
#[cfg(posix)]
|
||||
use crate::utils::test_helpers::make_fsentry;
|
||||
use crate::utils::test_helpers::{create_sample_file, make_file_at};
|
||||
|
||||
#[test]
|
||||
fn test_host_error_new() {
|
||||
@@ -632,13 +634,13 @@ mod tests {
|
||||
#[test]
|
||||
#[cfg(win)]
|
||||
fn test_host_localhost_new() {
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from("C:\\users")).ok().unwrap();
|
||||
let host: Localhost = Localhost::new(PathBuf::from("C:\\users")).ok().unwrap();
|
||||
assert_eq!(host.wrkdir, PathBuf::from("C:\\users"));
|
||||
// Scan dir
|
||||
let entries = std::fs::read_dir(PathBuf::from("C:\\users").as_path()).unwrap();
|
||||
let mut counter: usize = 0;
|
||||
for _ in entries {
|
||||
counter = counter + 1;
|
||||
counter += 1;
|
||||
}
|
||||
assert_eq!(host.files.len(), counter);
|
||||
}
|
||||
@@ -769,7 +771,7 @@ mod tests {
|
||||
let host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let files: Vec<File> = host.files.clone();
|
||||
// Verify files
|
||||
let file_0: &File = files.get(0).unwrap();
|
||||
let file_0: &File = files.first().unwrap();
|
||||
if file_0.name() == *"foo.txt" {
|
||||
assert!(file_0.metadata.symlink.is_none());
|
||||
} else {
|
||||
@@ -827,7 +829,7 @@ mod tests {
|
||||
let files: Vec<File> = host.files.clone();
|
||||
assert_eq!(files.len(), 1); // There should be 1 file now
|
||||
// Remove file
|
||||
assert!(host.remove(files.get(0).unwrap()).is_ok());
|
||||
assert!(host.remove(files.first().unwrap()).is_ok());
|
||||
// There should be 0 files now
|
||||
let files: Vec<File> = host.files.clone();
|
||||
assert_eq!(files.len(), 0); // There should be 0 files now
|
||||
@@ -836,7 +838,7 @@ mod tests {
|
||||
// Delete directory
|
||||
let files: Vec<File> = host.files.clone();
|
||||
assert_eq!(files.len(), 1); // There should be 1 file now
|
||||
assert!(host.remove(files.get(0).unwrap()).is_ok());
|
||||
assert!(host.remove(files.first().unwrap()).is_ok());
|
||||
// Remove unexisting directory
|
||||
assert!(
|
||||
host.remove(&make_fsentry(PathBuf::from("/a/b/c/d"), true))
|
||||
@@ -859,22 +861,22 @@ mod tests {
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let files: Vec<File> = host.files.clone();
|
||||
assert_eq!(files.len(), 1); // There should be 1 file now
|
||||
assert_eq!(files.get(0).unwrap().name(), "foo.txt");
|
||||
assert_eq!(files.first().unwrap().name(), "foo.txt");
|
||||
// Rename file
|
||||
let dst_path: PathBuf =
|
||||
PathBuf::from(format!("{}/bar.txt", tmpdir.path().display()).as_str());
|
||||
assert!(
|
||||
host.rename(files.get(0).unwrap(), dst_path.as_path())
|
||||
host.rename(files.first().unwrap(), dst_path.as_path())
|
||||
.is_ok()
|
||||
);
|
||||
// There should be still 1 file now, but named bar.txt
|
||||
let files: Vec<File> = host.files.clone();
|
||||
assert_eq!(files.len(), 1); // There should be 0 files now
|
||||
assert_eq!(files.get(0).unwrap().name(), "bar.txt");
|
||||
assert_eq!(files.first().unwrap().name(), "bar.txt");
|
||||
// Fail
|
||||
let bad_path: PathBuf = PathBuf::from("/asdailsjoidoewojdijow/ashdiuahu");
|
||||
assert!(
|
||||
host.rename(files.get(0).unwrap(), bad_path.as_path())
|
||||
host.rename(files.first().unwrap(), bad_path.as_path())
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
@@ -939,7 +941,7 @@ mod tests {
|
||||
file2_path.push("bar.txt");
|
||||
// Create host
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let file1_entry: File = host.files.get(0).unwrap().clone();
|
||||
let file1_entry: File = host.files.first().unwrap().clone();
|
||||
assert_eq!(file1_entry.name(), String::from("foo.txt"));
|
||||
// Copy
|
||||
assert!(host.copy(&file1_entry, file2_path.as_path()).is_ok());
|
||||
@@ -969,7 +971,7 @@ mod tests {
|
||||
let file2_path: PathBuf = PathBuf::from("bar.txt");
|
||||
// Create host
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let file1_entry: File = host.files.get(0).unwrap().clone();
|
||||
let file1_entry: File = host.files.first().unwrap().clone();
|
||||
assert_eq!(file1_entry.name(), String::from("foo.txt"));
|
||||
// Copy
|
||||
assert!(host.copy(&file1_entry, file2_path.as_path()).is_ok());
|
||||
@@ -989,7 +991,7 @@ mod tests {
|
||||
assert!(file1.write_all(b"Hello world!\n").is_ok());
|
||||
// Create host
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let file1_entry: File = host.files.get(0).unwrap().clone();
|
||||
let file1_entry: File = host.files.first().unwrap().clone();
|
||||
assert_eq!(file1_entry.name(), String::from("foo.txt"));
|
||||
// Copy with empty destination -> must fail and leave file untouched
|
||||
assert!(
|
||||
@@ -1022,7 +1024,7 @@ mod tests {
|
||||
dir_dest.push("test_dest_dir/");
|
||||
// Create host
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let dir_src_entry: File = host.files.get(0).unwrap().clone();
|
||||
let dir_src_entry: File = host.files.first().unwrap().clone();
|
||||
assert_eq!(dir_src_entry.name(), String::from("test_dir"));
|
||||
// Copy
|
||||
assert!(host.copy(&dir_src_entry, dir_dest.as_path()).is_ok());
|
||||
@@ -1052,7 +1054,7 @@ mod tests {
|
||||
let dir_dest: PathBuf = PathBuf::from("test_dest_dir/");
|
||||
// Create host
|
||||
let mut host: Localhost = Localhost::new(PathBuf::from(tmpdir.path())).ok().unwrap();
|
||||
let dir_src_entry: File = host.files.get(0).unwrap().clone();
|
||||
let dir_src_entry: File = host.files.first().unwrap().clone();
|
||||
assert_eq!(dir_src_entry.name(), String::from("test_dir"));
|
||||
// Copy
|
||||
assert!(host.copy(&dir_src_entry, dir_dest.as_path()).is_ok());
|
||||
|
||||
+1
-7
@@ -88,13 +88,7 @@ fn parse_args(args: Args) -> Result<RunOpts, String> {
|
||||
// Match ticks
|
||||
run_opts.ticks = Duration::from_millis(args.ticks);
|
||||
// Remote argument
|
||||
match RemoteArgs::try_from(&args) {
|
||||
Err(err) => return Err(err),
|
||||
Ok(remote) => {
|
||||
// Set params
|
||||
run_opts.remote = remote;
|
||||
}
|
||||
}
|
||||
run_opts.remote = RemoteArgs::try_from(&args)?;
|
||||
|
||||
// set activity based on remote state
|
||||
run_opts.task = if run_opts.remote.remote.is_none() {
|
||||
|
||||
@@ -68,7 +68,8 @@ impl Update {
|
||||
}
|
||||
|
||||
/// Returns whether a new version of termscp is available
|
||||
/// In case of success returns Ok(Option<Release>), where the Option is Some(new_version);
|
||||
/// In case of success returns `Ok(Option<Release>)`, where the option is
|
||||
/// `Some(new_version)`;
|
||||
/// otherwise if no version is available, return None
|
||||
/// In case of error returns Error with the error description
|
||||
pub fn is_new_version_available() -> Result<Option<Release>, UpdateError> {
|
||||
|
||||
@@ -767,7 +767,7 @@ mod tests {
|
||||
// Limit is 2
|
||||
assert_eq!(client.iter_recents().count(), 2);
|
||||
// Check that 192.168.1.1 has been removed
|
||||
let key: String = client.iter_recents().next().unwrap().to_string();
|
||||
let key: String = client.iter_recents().next().unwrap().clone();
|
||||
assert!(matches!(
|
||||
client
|
||||
.hosts
|
||||
@@ -781,7 +781,7 @@ mod tests {
|
||||
.as_str(),
|
||||
"192.168.1.2" | "192.168.1.3"
|
||||
));
|
||||
let key: String = client.iter_recents().nth(1).unwrap().to_string();
|
||||
let key: String = client.iter_recents().nth(1).unwrap().clone();
|
||||
assert!(matches!(
|
||||
client
|
||||
.hosts
|
||||
@@ -938,7 +938,7 @@ mod tests {
|
||||
let protocol = params.protocol;
|
||||
let p = params.params.generic_params().unwrap();
|
||||
(
|
||||
p.address.to_string(),
|
||||
p.address.clone(),
|
||||
p.port,
|
||||
protocol,
|
||||
p.username.as_ref().cloned().unwrap_or_default(),
|
||||
|
||||
@@ -595,7 +595,7 @@ mod tests {
|
||||
client.set_local_file_fmt(String::from("{NAME}"));
|
||||
assert_eq!(client.get_local_file_fmt().unwrap(), String::from("{NAME}"));
|
||||
// Delete
|
||||
client.set_local_file_fmt(String::from(""));
|
||||
client.set_local_file_fmt(String::new());
|
||||
assert_eq!(client.get_local_file_fmt(), None);
|
||||
}
|
||||
|
||||
@@ -613,7 +613,7 @@ mod tests {
|
||||
String::from("{NAME}")
|
||||
);
|
||||
// Delete
|
||||
client.set_remote_file_fmt(String::from(""));
|
||||
client.set_remote_file_fmt(String::new());
|
||||
assert_eq!(client.get_remote_file_fmt(), None);
|
||||
}
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ mod tests {
|
||||
let mut f: File = OpenOptions::new()
|
||||
.create(true)
|
||||
.write(true)
|
||||
.truncate(true)
|
||||
.open(conf_dir.as_path())
|
||||
.ok()
|
||||
.unwrap();
|
||||
|
||||
@@ -294,7 +294,7 @@ mod test {
|
||||
);
|
||||
// unwatch
|
||||
assert!(watcher.unwatch(tempdir.path()).is_ok());
|
||||
assert!(watcher.paths.get(tempdir.path()).is_none());
|
||||
assert!(!watcher.paths.contains_key(tempdir.path()));
|
||||
// close tempdir
|
||||
assert!(tempdir.close().is_ok());
|
||||
}
|
||||
@@ -315,7 +315,7 @@ mod test {
|
||||
watcher.unwatch(subdir.as_path()).unwrap().as_path(),
|
||||
Path::new(tempdir.path())
|
||||
);
|
||||
assert!(watcher.paths.get(tempdir.path()).is_none());
|
||||
assert!(!watcher.paths.contains_key(tempdir.path()));
|
||||
// close tempdir
|
||||
assert!(tempdir.close().is_ok());
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ impl Pane {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::*;
|
||||
use crate::explorer::builder::FileExplorerBuilder;
|
||||
use crate::host::Localhost;
|
||||
@@ -52,6 +50,6 @@ mod tests {
|
||||
fn test_pane_pwd() {
|
||||
let mut pane = make_pane();
|
||||
let pwd = pane.fs.pwd().unwrap();
|
||||
assert_eq!(pwd, PathBuf::from(std::env::temp_dir()));
|
||||
assert_eq!(pwd, std::env::temp_dir());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,8 @@ impl FileTransferActivity {
|
||||
/// Shared scan walk. `remote_side` selects which pane lists directories
|
||||
/// (remote for downloads, local for uploads).
|
||||
///
|
||||
/// The walk is abortable via [`crate::ui::activities::filetransfer::lib::TransferStates::aborted`]
|
||||
/// The walk is abortable via
|
||||
/// [`TransferStates::aborted`](crate::ui::activities::filetransfer::lib::transfer::TransferStates::aborted)
|
||||
/// and periodically redraws a "Scanning…" popup to keep the UI responsive.
|
||||
fn scan_worklist(
|
||||
&mut self,
|
||||
|
||||
@@ -15,8 +15,8 @@ use super::{Id, IdSsh, IdTheme, SetupActivity, ViewLayout};
|
||||
use crate::config::themes::Theme;
|
||||
|
||||
impl SetupActivity {
|
||||
/// On <ESC>, if there are changes in the configuration, the quit dialog must be shown, otherwise
|
||||
/// we can exit without any problem
|
||||
/// On `ESC`, if there are changes in the configuration, the quit dialog
|
||||
/// must be shown; otherwise, we can exit without any problem.
|
||||
pub(super) fn action_on_esc(&mut self) {
|
||||
if self.config_changed() {
|
||||
self.mount_quit();
|
||||
|
||||
+4
-2
@@ -43,13 +43,15 @@ pub fn fmt_millis(duration: Duration) -> String {
|
||||
}
|
||||
|
||||
/// Elide a path if longer than width
|
||||
/// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}
|
||||
/// In this case, the path is formatted to
|
||||
/// `{ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}`.
|
||||
pub fn fmt_path_elide(p: &Path, width: usize) -> String {
|
||||
fmt_path_elide_ex(p, width, 0)
|
||||
}
|
||||
|
||||
/// Elide a path if longer than width
|
||||
/// In this case, the path is formatted to {ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}
|
||||
/// In this case, the path is formatted to
|
||||
/// `{ANCESTOR[0]}/…/{PARENT[0]}/{BASENAME}`.
|
||||
/// This function allows to specify an extra length to consider to elide path
|
||||
pub fn fmt_path_elide_ex(p: &Path, width: usize, extra_len: usize) -> String {
|
||||
let fmt_path: String = format!("{}", p.display());
|
||||
|
||||
+4
-4
@@ -68,7 +68,7 @@ static BYTESIZE_REGEX: Lazy<Regex> = lazy_regex!(r"(:?([0-9])+)( )*(:?[KMGTP])?B
|
||||
/// SFTP => 22
|
||||
/// FTP => 21
|
||||
/// The option string has the following syntax
|
||||
/// [protocol://][username@]{address}[:port][:path]
|
||||
/// `[protocol://][username@]{address}[:port][:path]`
|
||||
/// The only argument which is mandatory is address
|
||||
/// NOTE: possible strings
|
||||
/// - 172.26.104.1
|
||||
@@ -80,17 +80,17 @@ static BYTESIZE_REGEX: Lazy<Regex> = lazy_regex!(r"(:?([0-9])+)( )*(:?[KMGTP])?B
|
||||
///
|
||||
/// For s3:
|
||||
///
|
||||
/// s3://<bucket-name>@<region>[:profile][:/wrkdir]
|
||||
/// `s3://<bucket-name>@<region>[:profile][:/wrkdir]`
|
||||
///
|
||||
/// For SMB:
|
||||
///
|
||||
/// on UNIX derived (macos, linux, ...)
|
||||
///
|
||||
/// smb://[username@]<address>[:port]/<share>[/path]
|
||||
/// `smb://[username@]<address>[:port]/<share>[/path]`
|
||||
///
|
||||
/// on Windows
|
||||
///
|
||||
/// \\<address>\<share>[\path]
|
||||
/// `\\<address>\<share>[\path]`
|
||||
///
|
||||
pub fn parse_remote_opt(s: &str) -> Result<FileTransferParams, String> {
|
||||
remote::parse_remote_opt(s)
|
||||
|
||||
Reference in New Issue
Block a user