From 532d29b05234fe5cefa945349adc1f93c3f3892c Mon Sep 17 00:00:00 2001 From: joker Date: Fri, 12 Jun 2026 18:24:06 +0800 Subject: [PATCH] refactor: unify config and manifest into ~/.easywork/ directory - Add EASYWORK_HOME constant and _ensure_easywork_home() helper - Move CONFIG_FILE from ~/.easywork.conf to ~/.easywork/config - Move MANIFEST_FILE from ~/.easywork.manifest to ~/.easywork/manifest - Update all internal references, tests, and documentation - Remove legacy migration logic (breaking change, no backward compat) Closes #??? --- .gitignore | 2 ++ README.md | 4 ++-- bin/easywork | 46 +++++++++++++++++++++++----------------- easywork.conf.example | 4 ++-- lib/common.sh | 16 ++++++++++++-- tests/helpers/mocks.bash | 5 +++-- tests/test_cli.bats | 2 +- tests/test_e2e.bats | 18 +++++++++------- tests/test_unit.bats | 2 +- 9 files changed, 62 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 0c7bab9..520242c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,7 @@ # EasyWork local files (do not commit) easywork.conf +.easywork/config +.easywork/manifest *.tmp *.bak diff --git a/README.md b/README.md index eba8c02..c11e531 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ easywork <命令> [参数] [选项] | `uninstall` | 卸载全部组件 | | `uninstall <模块名>` | 卸载指定组件 | | `config` | 查看配置文件内容及元信息 | -| `config edit` | 编辑配置文件(`~/.easywork.conf`) | +| `config edit` | 编辑配置文件(`~/.easywork/config`) | | `version` | 查看版本、安装日期和已安装组件 | | `update` | 检查并升级到最新版本 | | `help` | 显示帮助信息 | @@ -329,7 +329,7 @@ easywork <命令> [参数] [选项] ## 配置说明 -EasyWork 的配置文件位于 `~/.easywork.conf`。当你运行 `easywork git` 并选择 personal 或 work 身份后,EasyWork 会自动将身份信息写回该配置文件,下次无需重新输入。 +EasyWork 的配置文件位于 `~/.easywork/config`。当你运行 `easywork git` 并选择 personal 或 work 身份后,EasyWork 会自动将身份信息写回该配置文件,下次无需重新输入。 示例配置内容: diff --git a/bin/easywork b/bin/easywork index a83c762..d739f37 100755 --- a/bin/easywork +++ b/bin/easywork @@ -31,7 +31,7 @@ fi if $IS_PIPED; then EASYWORK_RAW_URL="${EASYWORK_RAW_URL:-https://raw.githubusercontent.com/EasyIndie/EasyWork/main}" else - EASYWORK_RAW_URL="${EASYWORK_RAW_URL:-https://raw.githubusercontent.com/EasyIndie/EasyWork/v${EASYWORK_VERSION}}" + EASYWORK_RAW_URL="${EASYWORK_RAW_URL:-https://raw.githubusercontent.com/EasyIndie/EasyWork/${EASYWORK_VERSION}}" fi # ─── Source Common Library ──────────────────────────────────── @@ -45,30 +45,38 @@ else _CACHE_DIR="$HOME/.easywork/lib/v${EASYWORK_VERSION}" mkdir -p "$_CACHE_DIR" - _download_common() { - curl -fsSL --proto '=https' --tlsv1.2 --retry 3 \ - -o "$_CACHE_DIR/common.sh" \ - "${EASYWORK_RAW_URL}/lib/common.sh" 2> /dev/null - } + # Check cache first — avoids re-downloading on every invocation + if [[ -f "$_CACHE_DIR/common.sh" ]]; then + source "$_CACHE_DIR/common.sh" + LIB_DIR="$_CACHE_DIR" + else + mkdir -p "$_CACHE_DIR" + + _download_common() { + curl -fsSL --proto '=https' --tlsv1.2 --retry 3 \ + -o "$_CACHE_DIR/common.sh" \ + "${EASYWORK_RAW_URL}/lib/common.sh" 2> /dev/null + } - if ! _download_common; then - # Fallback: version tag doesn't exist → use main branch - echo "[WARN] 版本 tag 不存在,使用 main 分支" >&2 - EASYWORK_RAW_URL="https://raw.githubusercontent.com/EasyIndie/EasyWork/main" if ! _download_common; then - echo "[ERROR] 无法下载 common.sh,请检查网络连接" - echo "[INFO] URL: ${EASYWORK_RAW_URL}/lib/common.sh" - exit 2 + # Fallback: version tag doesn't exist → use main branch + echo "[WARN] 版本 tag 不存在,使用 main 分支" >&2 + EASYWORK_RAW_URL="https://raw.githubusercontent.com/EasyIndie/EasyWork/main" + if ! _download_common; then + echo "[ERROR] 无法下载 common.sh,请检查网络连接" + echo "[INFO] URL: ${EASYWORK_RAW_URL}/lib/common.sh" + exit 2 + fi fi - fi - source "$_CACHE_DIR/common.sh" - LIB_DIR="$_CACHE_DIR" + source "$_CACHE_DIR/common.sh" + LIB_DIR="$_CACHE_DIR" + fi fi # Channel: dev (development) or empty (release) -# Local checkout or main-branch URL → dev; standalone with version tag → release -if $IS_PIPED || [[ "${EASYWORK_RAW_URL:-}" == *"/main" ]] || [[ -d "${EASYWORK_ROOT:-}/.git" ]]; then +# Piped or local git checkout → dev; installed release binary → release +if $IS_PIPED || [[ -d "${EASYWORK_ROOT:-}/.git" ]]; then EASYWORK_CHANNEL="dev" else EASYWORK_CHANNEL="" @@ -662,7 +670,7 @@ _finalize_uninstall() { else local answer="y" if [[ "${YES_MODE:-false}" != "true" ]]; then - read -r -p " 保留 ~/.easywork.conf 以便将来使用?[Y/n] " answer + read -r -p " 保留 $(config_path) 以便将来使用?[Y/n] " answer elif [[ "${REMOVE_CONFIG:-false}" == "true" ]]; then answer="n" else diff --git a/easywork.conf.example b/easywork.conf.example index 0e34fe4..76fba27 100644 --- a/easywork.conf.example +++ b/easywork.conf.example @@ -1,6 +1,6 @@ # ── EasyWork 配置文件 ──────────────────────────────────── -# 复制为 ~/.easywork.conf 即可生效: -# cp easywork.conf.example ~/.easywork.conf +# 复制为 ~/.easywork/config 即可生效: +# cp easywork.conf.example ~/.easywork/config # # 配置文件由 easywork config 命令管理,支持: # easywork config 查看配置内容 diff --git a/lib/common.sh b/lib/common.sh index 917d1ac..56db1b4 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -9,6 +9,16 @@ set -euo pipefail # Version (set by bin/easywork; default for standalone module usage) EASYWORK_VERSION="${EASYWORK_VERSION:-1.0.0}" +# EasyWork home directory — centralizes all CLI config, manifest, cache, and completions +EASYWORK_HOME="${HOME}/.easywork" + +# Ensure the home directory exists +_ensure_easywork_home() { + if [[ ! -d "$EASYWORK_HOME" ]]; then + mkdir -p "$EASYWORK_HOME" + fi +} + # ─── Exit Codes ─────────────────────────────────────────────── export EXIT_SUCCESS=0 export EXIT_ERROR=1 @@ -216,7 +226,7 @@ replace_managed_section() { } # ─── Manifest Management ────────────────────────────────────── -MANIFEST_FILE="$HOME/.easywork.manifest" +MANIFEST_FILE="${EASYWORK_HOME}/manifest" manifest_file() { echo "$MANIFEST_FILE"; } @@ -259,6 +269,7 @@ manifest_list_installed() { manifest_init() { local version="$1" + _ensure_easywork_home cat > "$MANIFEST_FILE" << EOF # EasyWork Manifest — auto-generated, do not edit easywork_version=${version} @@ -411,7 +422,7 @@ manifest_read_section_key() { } # ─── Config File Management ─────────────────────────────────── -CONFIG_FILE="${HOME}/.easywork.conf" +CONFIG_FILE="${EASYWORK_HOME}/config" CONFIG_EXAMPLE="${EASYWORK_ROOT:-.}/easywork.conf.example" config_path() { echo "$CONFIG_FILE"; } @@ -426,6 +437,7 @@ config_load() { } config_init() { + _ensure_easywork_home if ! config_exists; then if [[ -f "$CONFIG_EXAMPLE" ]]; then cp "$CONFIG_EXAMPLE" "$CONFIG_FILE" diff --git a/tests/helpers/mocks.bash b/tests/helpers/mocks.bash index 74b2202..0083e88 100644 --- a/tests/helpers/mocks.bash +++ b/tests/helpers/mocks.bash @@ -18,14 +18,15 @@ setup_mocks() { mkdir -p "${TEST_HOME}" # Override manifest and config paths - export MANIFEST_FILE="${TEST_HOME}/.easywork.manifest" - export CONFIG_FILE="${TEST_HOME}/.easywork.conf" + export MANIFEST_FILE="${TEST_HOME}/.easywork/manifest" + export CONFIG_FILE="${TEST_HOME}/.easywork/config" export SH_CONFIG_FILE="${TEST_HOME}/.sh_config_custom" export GIT_CONFIG_FILE="${TEST_HOME}/.gitconfig" export VIMRC_FILE="${TEST_HOME}/.vimrc" export VIM_DIR="${TEST_HOME}/.vim" export TEMP_DIR="${TEST_HOME}/tmp" mkdir -p "${TEMP_DIR}" + mkdir -p "${TEST_HOME}/.easywork" export TMPDIR="${TEMP_DIR}" # Mock curl: capture calls instead of making real network requests diff --git a/tests/test_cli.bats b/tests/test_cli.bats index e77dc9a..0bfa256 100644 --- a/tests/test_cli.bats +++ b/tests/test_cli.bats @@ -46,5 +46,5 @@ teardown() { teardown_mocks; } @test "cli: config shows path" { run bash "${BATS_TEST_DIRNAME}/../bin/easywork" config - [[ "$output" =~ "配置文件路径" ]] || [[ "$output" =~ ".easywork.conf" ]] + [[ "$output" =~ "配置文件路径" ]] || [[ "$output" =~ ".easywork/config" ]] } diff --git a/tests/test_e2e.bats b/tests/test_e2e.bats index 1f26b3c..1d97ebb 100644 --- a/tests/test_e2e.bats +++ b/tests/test_e2e.bats @@ -82,7 +82,7 @@ teardown() { @test "e2e: config creates generic config" { run easywork config [[ "$status" -eq 0 ]] - run cat "$TEST_HOME/.easywork.conf" + run cat "$TEST_HOME/.easywork/config" [[ ! "$output" =~ "Your Name" ]] } @@ -96,7 +96,7 @@ teardown() { @test "e2e: piped reinstall overwrites" { mkdir -p "$TEST_HOME/.easywork" - echo "easywork_version=1.0.0" > "$TEST_HOME/.easywork.manifest" + echo "easywork_version=1.0.0" > "$TEST_HOME/.easywork/manifest" run bash -c "cat ${EASYWORK_ROOT}/bin/easywork | PATH=${TEST_HOME}/.local/bin:\$PATH HOME=${TEST_HOME} bash -s -- install --dry-run" 2>&1 [[ "$output" =~ "CLI 准备就绪" ]] } @@ -114,9 +114,9 @@ teardown() { @test "e2e: install --yes creates files" { run easywork install --yes [[ "$status" -eq 0 ]] - [[ -f "$TEST_HOME/.easywork.manifest" ]] + [[ -f "$TEST_HOME/.easywork/manifest" ]] [[ -f "$TEST_HOME/.sh_config_custom" ]] - run cat "$TEST_HOME/.easywork.manifest" + run cat "$TEST_HOME/.easywork/manifest" [[ "$output" =~ "shell" ]] } @@ -130,7 +130,7 @@ teardown() { easywork install --yes 2> /dev/null run easywork uninstall --yes --remove-config [[ "$status" -eq 0 ]] - [[ ! -f "$TEST_HOME/.easywork.manifest" ]] + [[ ! -f "$TEST_HOME/.easywork/manifest" ]] } # ─── D: Single module ─────────────────────────────────────── @@ -154,7 +154,7 @@ teardown() { easywork install --yes 2> /dev/null run easywork uninstall vim --yes [[ "$status" -eq 0 ]] - run cat "$TEST_HOME/.easywork.manifest" + run cat "$TEST_HOME/.easywork/manifest" [[ "$output" =~ "shell" ]] [[ ! "$output" =~ "vim" ]] } @@ -162,7 +162,8 @@ teardown() { # ─── E: Git specifics ─────────────────────────────────────── @test "e2e: git with config values" { - cat > "$TEST_HOME/.easywork.conf" << 'EOF' + mkdir -p "$TEST_HOME/.easywork" + cat > "$TEST_HOME/.easywork/config" << 'EOF' ## git GIT_PERSONAL_NAME="Test User" GIT_PERSONAL_EMAIL="test@example.com" @@ -173,7 +174,8 @@ EOF } @test "e2e: git dry-run with empty config uses dummy values" { - echo "# empty" > "$TEST_HOME/.easywork.conf" + mkdir -p "$TEST_HOME/.easywork" + echo "# empty" > "$TEST_HOME/.easywork/config" run easywork install git --dry-run --yes [[ "$status" -eq 0 ]] # Dry-run fills in dummy values for preview diff --git a/tests/test_unit.bats b/tests/test_unit.bats index d9263ea..673404e 100644 --- a/tests/test_unit.bats +++ b/tests/test_unit.bats @@ -88,7 +88,7 @@ teardown() { teardown_mocks; } @test "unit: config_path returns path" { run config_path - [[ "$output" =~ ".easywork.conf" ]] + [[ "$output" =~ ".easywork/config" ]] } @test "unit: config_init creates config" {