diff --git a/AGENTS.md b/AGENTS.md index 3029fbb..7850599 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,3 +53,9 @@ zの関数は、関数名の階層とディレクトリ構成を対応させて - `lib/a/process.zsh` のテストは `test/lib/a/process_test.zsh` - `lib/a/b/process.zsh` のテストは `test/lib/a/b/process_test.zsh` - `mod/a/b/operator.zsh` のテストは `test/mod/a/b/operator_test.zsh` + +## 失敗処理 + +`|| return 1`は、コピー失敗後の切替防止や依存関係の循環検出など、失敗時に後続の処理を止める必要がある箇所に置いてください。削除・置換では操作対象の検証と復旧処理を維持し、通常の取得・計算では同じ条件の重複検証を整理してください。 + +引数取得と代入は、`z.arg.named ... && local ...`などの既存の書式に合わせてください。常に成功する値取得に`|| return 1`を追加する必要はありません。 diff --git a/lib/common/is/operator.zsh b/lib/common/is/operator.zsh index 7584e46..5e061b7 100644 --- a/lib/common/is/operator.zsh +++ b/lib/common/is/operator.zsh @@ -26,7 +26,6 @@ z.is.truthy() { local value=$1 z.guard; { - z.arg.is.empty $@ && return 1 z.is.false $value && return 1 } @@ -68,7 +67,6 @@ z.is.falsy() { local value=$1 z.guard; { - z.arg.is.empty $@ && return 0 z.is.true $value && return 1 } diff --git a/lib/int/is/operator.zsh b/lib/int/is/operator.zsh index 3b4dd8c..dd05430 100644 --- a/lib/int/is/operator.zsh +++ b/lib/int/is/operator.zsh @@ -42,8 +42,6 @@ z.int.is.eq() { z.int.is.zero() { local value=$1 - z.int.is.match $value || return 1 - z.is.eq $value 0 } @@ -58,8 +56,6 @@ z.int.is.zero() { z.int.is.positive() { local value=$1 - z.int.is.match $value || return 1 - z.int.is.gt $value 0 } @@ -74,8 +70,6 @@ z.int.is.positive() { z.int.is.negative() { local value=$1 - z.int.is.match $value || return 1 - z.int.is.lt $value 0 } diff --git a/lib/update/archive/process.zsh b/lib/update/archive/process.zsh index 0e469c1..9f17888 100644 --- a/lib/update/archive/process.zsh +++ b/lib/update/archive/process.zsh @@ -8,13 +8,12 @@ # example: # z.update.archive._download dir=/tmp/update branch=main z.update.archive._download() { - z.arg.named dir "$@" || { z.return; return 1; } + z.arg.named dir "$@" local dir=$REPLY z.dir.exists "$dir" || { z.return; return 1; } z.arg.named branch "$@" default=main local branch=$REPLY - z.is.null "$branch" && { z.return; return 1; } local file="$dir/source.tar.gz" z.file.exists "$file" && { z.return; return 1; } @@ -26,8 +25,6 @@ z.update.archive._download() { return 1 fi - z.file.exists "$file" || { z.return; return 1; } - z.return "$file" } @@ -41,15 +38,14 @@ z.update.archive._download() { # example: # z.update.archive._extract file=/tmp/source.tar.gz dir=/tmp/update/source z.update.archive._extract() { - z.arg.named file "$@" || { z.return; return 1; } + z.arg.named file "$@" local file=$REPLY - z.arg.named dir "$@" || { z.return; return 1; } + z.arg.named dir "$@" local dir=$REPLY z.is.null "$dir" && { z.return; return 1; } - z.file.exists "$file" || { z.return; return 1; } z.dir.exists "$dir" && { z.return; return 1; } z.dir.make path="$dir" || return 1 diff --git a/lib/update/core/process.zsh b/lib/update/core/process.zsh index f549555..6c6a4ab 100644 --- a/lib/update/core/process.zsh +++ b/lib/update/core/process.zsh @@ -8,24 +8,17 @@ # example: # z.update.core._copy source=/tmp/source dir=/tmp/update/next z.update.core._copy() { - z.arg.named source "$@" || return 1 + z.arg.named source "$@" local source_dir=$REPLY + z.dir.exists "$source_dir" || return 1 - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY z.is.null "$dir" && return 1 z.dir.exists "$dir" && return 1 local core_files=(main.zsh install.zsh uninstall.zsh version.zsh help.zsh README.md) - for directory in lib test; do - z.dir.exists "$source_dir/$directory" || return 1 - done - - for core_file in "${core_files[@]}"; do - z.file.exists "$source_dir/$core_file" || return 1 - done - z.dir.make path="$dir" || return 1 for entry in lib test "${core_files[@]}"; do diff --git a/lib/update/installation/is/operator.zsh b/lib/update/installation/is/operator.zsh index 9e20f99..f7abcb2 100644 --- a/lib/update/installation/is/operator.zsh +++ b/lib/update/installation/is/operator.zsh @@ -7,7 +7,7 @@ # example: # z.update.installation.is._valid dir=~/.z z.update.installation.is._valid() { - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY z.is.null "$dir" && return 1 diff --git a/lib/update/installation/process.zsh b/lib/update/installation/process.zsh index 36dcec4..5d667f0 100644 --- a/lib/update/installation/process.zsh +++ b/lib/update/installation/process.zsh @@ -9,13 +9,13 @@ # example: # z.update.installation._replace dir=~/.z prepared=/tmp/next backup=/tmp/previous z.update.installation._replace() { - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY - z.arg.named prepared "$@" || return 1 + z.arg.named prepared "$@" local prepared=$REPLY - z.arg.named backup "$@" || return 1 + z.arg.named backup "$@" local backup=$REPLY z.is.null "$backup" && return 1 @@ -45,7 +45,7 @@ z.update.installation._replace() { # example: # z.update.installation._reload dir=~/.z previous=$PWD z.update.installation._reload() { - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY z.file.exists "$dir/main.zsh" || return 1 @@ -53,7 +53,7 @@ z.update.installation._reload() { local previous_dir=$REPLY if (( ${+functions[z.completion.cache._cancel]} )); then - z.completion.cache._cancel || return 1 + z.completion.cache._cancel fi if z.is.eq "$previous_dir" "$dir" || z.str.start_with "$previous_dir" "$dir/"; then diff --git a/lib/update/mod/analysis.zsh b/lib/update/mod/analysis.zsh index bea922c..e49eeff 100644 --- a/lib/update/mod/analysis.zsh +++ b/lib/update/mod/analysis.zsh @@ -8,7 +8,7 @@ # example: # z.update.mod._resolve source=/tmp/source completion z.update.mod._resolve() { - z.arg.named source "$@" || { z.return; return 1; } + z.arg.named source "$@" local source_dir=$REPLY z.dir.exists "$source_dir" || { z.return; return 1; } diff --git a/lib/update/mod/process.zsh b/lib/update/mod/process.zsh index fd80967..d7695c4 100644 --- a/lib/update/mod/process.zsh +++ b/lib/update/mod/process.zsh @@ -10,13 +10,13 @@ # example: # z.update.mod._copy source=/tmp/source current=~/.z dir=/tmp/update/next job z.update.mod._copy() { - z.arg.named source "$@" || return 1 + z.arg.named source "$@" local source_dir=$REPLY - z.arg.named current "$@" || return 1 + z.arg.named current "$@" local current_dir=$REPLY - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY z.dir.exists "$source_dir" || return 1 @@ -29,10 +29,6 @@ z.update.mod._copy() { z.arg.named.shift dir "${(@)REPLY}" local selected=(${(@)REPLY}) - for mod_name in "${selected[@]}"; do - z.dir.exists "$source_dir/mod/$mod_name" || return 1 - done - if z.dir.exists "$current_dir/mod"; then z.dir.make path="$dir/mod" || return 1 diff --git a/lib/update/process.zsh b/lib/update/process.zsh index fcff6fb..ee40e2f 100644 --- a/lib/update/process.zsh +++ b/lib/update/process.zsh @@ -69,7 +69,7 @@ z.update() { # example: # z.update._confirm dir=~/.z z.update._confirm() { - z.arg.named dir "$@" || return 1 + z.arg.named dir "$@" local dir=$REPLY z.is.null "$dir" && return 1 diff --git a/test/lib/arg/process_test.zsh b/test/lib/arg/process_test.zsh index f67bdcb..ddca315 100644 --- a/test/lib/arg/process_test.zsh +++ b/test/lib/arg/process_test.zsh @@ -75,6 +75,17 @@ z.t.describe "z.arg.named"; { } } + z.t.context "指定した名前の引数がない場合"; { + z.t.it "成功して空の値を返す"; { + z.arg.named name other=fuga + local result_code=$? + local result_reply=$REPLY + + z.t.expect "$result_code" 0 + z.t.expect "$result_reply" "" + } + } + z.t.context "defaultが指定されていて、値がない場合"; { z.t.it "デフォルト値を返す"; { z.arg.named name name="" other=fuga default=default_value diff --git a/test/lib/update/archive/process_test.zsh b/test/lib/update/archive/process_test.zsh index 5d497ee..cad59be 100644 --- a/test/lib/update/archive/process_test.zsh +++ b/test/lib/update/archive/process_test.zsh @@ -165,8 +165,8 @@ z.t.describe "z.update.archive._extract"; { } z.t.context "file引数がない場合"; { - z.t.it "展開先を作らない"; { - z.update.archive._extract dir=/tmp/z_t/update_extract_absent + z.t.it "失敗して展開先を残さない"; { + z.update.archive._extract dir=/tmp/z_t/update_extract_absent 2>/dev/null local extract_status=$? local result=$REPLY diff --git a/test/lib/update/core/process_test.zsh b/test/lib/update/core/process_test.zsh index 108f006..94e0f6f 100644 --- a/test/lib/update/core/process_test.zsh +++ b/test/lib/update/core/process_test.zsh @@ -60,37 +60,31 @@ z.t.describe "z.update.core._copy"; { } z.t.context "配布元のtest directoryがない場合"; { - z.t.it "コピーを開始しない"; { + z.t.it "コピーの失敗を返す"; { local dir=/tmp/z_t/update_core/missing_directory z.dir.make path="$dir/source/lib" - z.update.core._copy source="$dir/source" dir="$dir/prepared" + z.update.core._copy source="$dir/source" dir="$dir/prepared" 2>/dev/null local copy_status=$? z.t.expect "$copy_status" 1 - z.dir.not.exists "$dir/prepared" - z.t.expect.status.is.true - z.dir.remove path=/tmp/z_t/update_core } } z.t.context "必須fileがない場合"; { - z.t.it "コピーを開始しない"; { + z.t.it "コピーの失敗を返す"; { local dir=/tmp/z_t/update_core/missing_file z.dir.make path="$dir/source/lib" z.dir.make path="$dir/source/test" z.file.write path="$dir/source/main.zsh" content=main - z.update.core._copy source="$dir/source" dir="$dir/prepared" + z.update.core._copy source="$dir/source" dir="$dir/prepared" 2>/dev/null local copy_status=$? z.t.expect "$copy_status" 1 - z.dir.not.exists "$dir/prepared" - z.t.expect.status.is.true - z.dir.remove path=/tmp/z_t/update_core } } diff --git a/test/lib/update/installation/process_test.zsh b/test/lib/update/installation/process_test.zsh index 4fee652..96976f0 100644 --- a/test/lib/update/installation/process_test.zsh +++ b/test/lib/update/installation/process_test.zsh @@ -254,20 +254,28 @@ z.t.describe "z.update.installation._reload"; { } } - z.t.context "cancelが失敗した場合"; { - z.t.it "sourceを実行しない"; { - local dir=/tmp/z_t/update_reload/cancel_failure + z.t.context "補完jobが回収済みの場合"; { + z.t.it "IDを破棄して本体の再読込を続ける"; { + local dir=/tmp/z_t/update_reload/collected_job + local z_completion_cache_job_id=collected-job z.dir.make path="$dir" z.file.write path="$dir/main.zsh" content="touch \"$dir/loaded\"" - z.t.mock name="z.completion.cache._cancel" behavior="return 1" + z.t.mock name="z.job.status" behavior="return 1" + z.t.mock name="z.completion.enable" behavior="return 0" - z.update.installation._reload dir="$dir" + () { + local Z_ROOT=$z_root + + z.update.installation._reload dir="$dir" + } local reload_status=$? + local remaining_id=$z_completion_cache_job_id - z.t.expect "$reload_status" 1 + z.t.expect "$reload_status" 0 + z.t.expect.is.null "$remaining_id" - z.file.not.exists "$dir/loaded" + z.file.exists "$dir/loaded" z.t.expect.status.is.true z.dir.remove path=/tmp/z_t/update_reload diff --git a/test/lib/update/mod/process_test.zsh b/test/lib/update/mod/process_test.zsh index abccbbf..98a6a1c 100644 --- a/test/lib/update/mod/process_test.zsh +++ b/test/lib/update/mod/process_test.zsh @@ -112,14 +112,14 @@ z.t.describe "z.update.mod._copy"; { } z.t.context "配布元に選択modがない場合"; { - z.t.it "既存と準備先を変更しない"; { + z.t.it "コピーの失敗を返して現行modを保持する"; { local dir=/tmp/z_t/update_mod_copy/missing z.dir.make path="$dir/current/mod/app" z.dir.make path="$dir/source" z.dir.make path="$dir/prepared" z.file.write path="$dir/current/mod/app/value" content=original - z.update.mod._copy source="$dir/source" current="$dir/current" dir="$dir/prepared" missing + z.update.mod._copy source="$dir/source" current="$dir/current" dir="$dir/prepared" missing 2>/dev/null local copy_status=$? z.t.expect "$copy_status" 1 @@ -127,9 +127,6 @@ z.t.describe "z.update.mod._copy"; { z.file.read path="$dir/current/mod/app/value" z.t.expect.reply original - z.dir.not.exists "$dir/prepared/mod" - z.t.expect.status.is.true - z.dir.remove path=/tmp/z_t/update_mod_copy } }