Skip to content

統一エントリポイント ma.sh(依存ツールの推移的自動解決)(#182) - #196

Open
k-yoshimi wants to merge 19 commits into
developfrom
feat/182-ma-entrypoint
Open

統一エントリポイント ma.sh(依存ツールの推移的自動解決)(#182)#196
k-yoshimi wants to merge 19 commits into
developfrom
feat/182-ma-entrypoint

Conversation

@k-yoshimi

Copy link
Copy Markdown
Collaborator

概要

Fixes #182

トップレベルに ma.sh を追加し、アプリのビルドに必要なツールを推移的に解決して自動ビルドしてからアプリをインストールできるようにします。既存の個別フロー(cd apps/x; sh install.sh; sh link.sh)は一切変更していません。

sh ma.sh install <app> [mode]   # 依存ツールを解決→不足分をビルド→アプリをインストール
sh ma.sh list                   # 導入可能な app/tool 一覧([deps] = 依存を自動解決するアプリ)
sh ma.sh installed              # 導入済みコンポーネント(アプリ・ツール両方)
sh ma.sh help

設計(Phase 0 AI レビュー収束済み)

  • 依存宣言: 各 version.sh の任意変数 <NAME>_REQUIRES="tool1 tool2"(直接依存の tool 名のみ)。未宣言のアプリは従来どおり単体インストール(警告表示)
  • 解決器 scripts/ma_deps.sh: DFS で推移的トポロジカル順を生成、循環・不明ツール検出、ダイヤモンド依存は 1 回。純 POSIX sh(local の動的スコープを利用)で単体テスト可能
  • 可用性判定: (1) インストーラ実績 $MA_ROOT/env.d/<tool>vars.sh(マーカー)→ 済 / (2) find.shMA_HAVE_<TOOL>=yes(システム提供)→ 済 / (3) それ以外 → 要ビルド。部分インストール(prefix あり・マーカー無し)は「削除して再実行」と明示中断
  • 今回の投入: hphi とその依存チェーン(cmake / openmpi / lapack / scalapack)に REQUIRES を投入。ma_resolve hphi → cmake, openmpi, lapack, scalapack
  • 設計詳細: docs/superpowers/specs/2026-07-09-ma-entrypoint-design.md

実装・レビューの経緯

subagent-driven development(タスクごとに実装→spec+品質レビュー→修正)で 9 タスクを TDD 実装し、最後にブランチ全体レビューを実施:

  • ブランチ全体レビューで Important バグを検出・修正: find.sh を source する際、11 個の find.shSCRIPT_DIR=$(dirname $0) で再導出するため、source 時に $0 が親シェルになりパスが解決できずシステムツール検出が機能しなかった(例: システム LAPACK があっても再ビルド。fail-safe = 誤スキップはしない)。sh -c '. "$0" ...' <find.sh>$0 を find.sh 自身にして修正、dash で検証
  • version.sh を set -u 下で source する危険側リスク(依存の無言脱落)を set +u ラップで防止、resume テストの app 側 abort 検証、CI の shellcheck 対象拡張

テスト

  • 解決器ユニット(scripts/ma_deps_test.sh): 順序・推移・ダイヤモンド・循環・不明・可用性・lint
  • fixture 統合(scripts/ma_integration_test.sh): ビルド順・resume スキップ・部分インストール中断・app 側 abort・list/installed(実ビルドせず ma.sh のオーケストレーションを検証)
  • scripts/lint_version_sh.sh: version.sh 宣言専用チェック(複合コマンド ;/&&/|/backtick を拒否、$(...) は許容)
  • 全スイートが shdash の両方で PASS、shellcheck(--severity=warning -s sh)が全 5 ファイルでクリーン
  • CI に ma ジョブ追加(shellcheck + lint + 両テスト)

補足(マージ順)

🤖 Generated with Claude Code

k-yoshimi and others added 19 commits July 9, 2026 07:53
Design for a top-level ma.sh (install/list/installed/help) that
resolves an app's tool dependencies transitively, builds missing
tools in order via the existing tools/*/install.sh+link.sh, then
installs the app. Dependencies are declared per package as a
<NAME>_REQUIRES variable in version.sh; availability is decided
primarily by the installer's own env.d/<tool>vars.sh marker
(find.sh only covers 15/27 tools). Metadata is populated gradually,
starting with the hphi chain.

Refs #182

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address the design-review findings:
- must_fix (Codex): define partial-install/resume semantics — a
  half-built tool (prefix present, no env.d marker) is reported with a
  targeted "remove <prefix> and re-run" instruction instead of silently
  wedging; "resumable" narrowed to completed tools.
- must_fix (Antigravity): warn on install when an app has no REQUIRES,
  and mark apps that carry dependency metadata in `ma.sh list`, so the
  gradual rollout is not a silent no-op.
- Clarify system-tool env propagation (find.sh-found tools need none),
  find.sh variable normalization, resolver POSIX-sh constraints
  (newline sets, exact membership, no subshell state loss, version.sh
  declarative-only), env.sh validation and dangling-symlink handling.
- Specify CLI arg validation (no-args/-h/--help usage), tools build in
  default mode (documented limitation), expanded tests, and a
  resolved-questions + deferred (--force/--dry-run) section.

Refs #182

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Specify precedence: installer-state checks (complete marker / partial
  prefix) are evaluated before find.sh; find.sh is consulted only when
  the installer has no prefix for the tool.
- Add a version.sh declarative-only CI lint (assignments/comments only)
  so the resolver's side-effect-free sourcing cannot silently regress.

Refs #182

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Validate mode up front via apps/<app>/config/<mode>/ existence, so a
  bad mode errors before any dependency is built (was: only caught at
  the final app install).
- Capture ma_resolve output and check its exit status before the build
  loop, so a resolver error (cycle/unknown) aborts instead of being
  iterated as tool names.
- Harden the REQUIRES/MA_HAVE variable-name normalization to map every
  non-alphanumeric char to '_' (valid identifier for any dir name).
- Specify that `installed` scans both env.d (tools) and <app>/ (apps).
- Warn when building deps for a non-default app mode (built in default
  mode). Document presence-based (not version-matched) availability as
  an explicit first-cut non-goal.

Refs #182

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9-task TDD plan: ma_reqvar/ma_requires, ma_resolve (transitive +
cycle/unknown), ma_tool_status availability, ma.sh CLI skeleton +
arg validation, install build loop (resume + partial guard + env
reload), list/installed, version.sh declarative lint + hphi-chain
REQUIRES, CI job, docs. Each task ends with a runnable shell test.

Refs #182

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l guard

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QaWKJsSQqCakkMEKZpJcvP
ma__find_have preset SCRIPT_DIR and sourced find.sh in a subshell, but
11 real find.sh files (lapack, boost, fftw, eigen3, gsl, hdf5, libffi,
nfft, openssl, tcltk, zlib) ignore that and re-derive
SCRIPT_DIR=$(cd "$(dirname $0)"; pwd) themselves. When a file is
sourced, $0 stays the parent shell's (ma.sh), so dirname $0 resolves
at repo-root depth instead of the tool-dir depth those find.sh files
expect, and ../../scripts/cmake-find-package.sh can't be opened -
MA_HAVE_<TOOL> silently stays empty and system-installed tools like
LAPACK are never detected.

Run find.sh via `sh -c` with $0 pointed at the find.sh path itself, so
its own `dirname $0` resolves exactly as it does under the normal
install.sh flow. Verified under dash: lapack (Accelerate via cmake on
this machine) now reports MA_HAVE_LAPACK=yes instead of empty.
The existing find.sh availability test used a trivial fixture
(MA_HAVE_ST2=yes) that references neither $0 nor SCRIPT_DIR, so it
passed even while ma__find_have sourced find.sh with the wrong $0 (the
bug fixed in the previous commit). Add a st3 fixture whose find.sh
mirrors the real tools (lapack, boost, fftw, ...): it derives
SCRIPT_DIR from $0 and only reports MA_HAVE_ST3=yes if it can read a
sibling file next to itself. Confirmed this fails against the
pre-fix ma__find_have (expected [available] got [absent]) and passes
after.
ma_requires and ma_cmd_list source version.sh (external,
tool/app-owned metadata) inside a `set -u` context. If a future
version.sh references an unset variable before its _REQUIRES line,
that reference would abort the sourcing subshell under nounset and
silently produce an empty deps list -- a dropped dependency, which is
the dangerous direction to fail in. Wrap the `. version.sh` sourcing
with set +u/set -u, matching the pattern already used in
ma_do_install/ma_cmd_installed for util.sh/env.sh.

Behavior on the current (clean) tree is unchanged: `ma_resolve hphi`
still resolves to cmake/openmpi/lapack/scalapack and `ma.sh list`
output is identical.
The fixture app's fake install.sh always succeeded, so the "app
prefix exists -> install.sh aborts" behavior the surrounding comment
described was never exercised: the re-run command's exit status
wasn't even checked. Make the fixture install.sh emulate the real
install.sh scripts' guard (error + exit 127 if its own versioned
prefix already exists), and assert the second `ma.sh install appF`
now fails at the app step. Confirmed this assertion fails against the
old always-succeeds fixture and passes with the guard in place, while
the existing "tools not rebuilt" assertion keeps passing.
The ma job's shellcheck step only covered ma.sh, ma_deps.sh, and
lint_version_sh.sh, leaving ma_deps_test.sh and ma_integration_test.sh
(both nontrivial POSIX sh) unchecked in CI. Add them to the
shellcheck invocation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants