@osfactory/har 0.64.2 → 1.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +15751 -6548
- package/dist/prompts/system-authoring.md +155 -0
- package/dist/templates/adaptation-prompt-init.md +67 -43
- package/dist/templates/adaptation-prompt-maintain.md +38 -38
- package/dist/templates/adaptation-prompt-plugin.md +40 -0
- package/dist/templates/agent-skills/har-maintain.md +2 -2
- package/dist/templates/agent-skills/setup-har.md +6 -4
- package/dist/templates/cursor-rule.mdc.template +3 -3
- package/dist/templates/har-boilerplate/docker-compose.agent.yml +1 -1
- package/dist/templates/har-boilerplate/harness.env +11 -155
- package/dist/templates/har-boilerplate/stages.json +51 -2
- package/dist/templates/har-boilerplate-cli/docker-compose.agent.yml +1 -1
- package/dist/templates/har-boilerplate-cli/harness.env +12 -138
- package/dist/templates/har-boilerplate-cli/stages.json +42 -2
- package/dist/templates/har-boilerplate-ios/harness.env +10 -126
- package/dist/templates/har-boilerplate-ios/stages.json +42 -2
- package/dist/templates/migration-prompt.md +54 -0
- package/dist/templates/plugins/custom-stage-skeleton.sh +11 -20
- package/dist/templates/plugins/gitleaks/.github/workflows/gitleaks.yml +1 -1
- package/dist/templates/plugins/gitleaks/.har/stages/GITLEAKS.md +1 -1
- package/dist/templates/plugins/gitleaks/.har/stages/secrets-scan.sh +8 -23
- package/dist/templates/plugins/gitleaks/README.md +1 -1
- package/dist/templates/plugins/gitleaks/template.manifest.json +20 -5
- package/dist/templates/plugins/kerno/.github/workflows/kerno.yml +1 -1
- package/dist/templates/plugins/kerno/.har/stages/backend-validation.sh +8 -23
- package/dist/templates/plugins/kerno/README.md +1 -1
- package/dist/templates/plugins/kerno/template.manifest.json +20 -9
- package/dist/templates/plugins/local-plugin-skeleton/README.md +46 -0
- package/dist/templates/plugins/playwright/.har/stages/browser-e2e.sh +8 -23
- package/dist/templates/plugins/playwright/template.manifest.json +36 -13
- package/dist/templates/plugins/rocketsim/.har/stages/rocketsim-flows.sh +8 -23
- package/dist/templates/plugins/rocketsim/template.manifest.json +20 -8
- package/dist/templates/plugins/semgrep/.har/stages/sast.sh +10 -26
- package/dist/templates/plugins/semgrep/README.md +1 -1
- package/dist/templates/plugins/semgrep/template.manifest.json +16 -7
- package/dist/templates/plugins/trivy/.har/stages/vuln-scan.sh +8 -23
- package/dist/templates/plugins/trivy/README.md +1 -1
- package/dist/templates/plugins/trivy/template.manifest.json +20 -8
- package/dist/templates/{har-boilerplate-cli/CLAUDE.agent.md → profiles/cli/docs/claude-agent/definition-of-done.md} +0 -42
- package/dist/templates/profiles/cli/docs/claude-agent/do-not.md +6 -0
- package/dist/templates/profiles/cli/docs/claude-agent/environment.md +12 -0
- package/dist/templates/profiles/cli/docs/claude-agent/project-commands.md +10 -0
- package/dist/templates/profiles/cli/docs/claude-agent/readiness.md +6 -0
- package/dist/templates/profiles/cli/docs/readme/for-coding-agents.md +9 -0
- package/dist/templates/profiles/cli/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/cli/docs/readme/port-shared-services-cli-profile.md +25 -0
- package/dist/templates/profiles/cli/docs/readme/quick-start.md +24 -0
- package/dist/templates/profiles/cli/docs/readme/verification-contract.md +22 -0
- package/dist/templates/profiles/cli/docs/readme/what-s-in-here.md +27 -0
- package/dist/templates/profiles/cli/profile.manifest.json +56 -1
- package/dist/templates/profiles/default/docs/claude-agent/definition-of-done.md +24 -0
- package/dist/templates/profiles/default/docs/claude-agent/do-not.md +10 -0
- package/dist/templates/profiles/default/docs/claude-agent/environment.md +19 -0
- package/dist/templates/profiles/default/docs/claude-agent/project-commands.md +10 -0
- package/dist/templates/profiles/default/docs/claude-agent/readiness.md +12 -0
- package/dist/templates/profiles/default/docs/readme/architecture.md +11 -0
- package/dist/templates/profiles/default/docs/readme/for-coding-agents.md +9 -0
- package/dist/templates/profiles/default/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/default/docs/readme/port-shared-services.md +41 -0
- package/dist/templates/profiles/default/docs/readme/quick-start.md +24 -0
- package/dist/templates/profiles/default/docs/readme/readiness-layers.md +16 -0
- package/dist/templates/profiles/default/docs/readme/verification-contract.md +17 -0
- package/dist/templates/profiles/default/docs/readme/what-s-in-here.md +28 -0
- package/dist/templates/profiles/default/profile.manifest.json +62 -1
- package/dist/templates/profiles/ios/docs/claude-agent/definition-of-done.md +23 -0
- package/dist/templates/profiles/ios/docs/claude-agent/do-not.md +6 -0
- package/dist/templates/profiles/ios/docs/claude-agent/environment.md +14 -0
- package/dist/templates/profiles/ios/docs/claude-agent/intro.md +3 -0
- package/dist/templates/profiles/ios/docs/claude-agent/project-commands.md +21 -0
- package/dist/templates/profiles/ios/docs/claude-agent/readiness.md +6 -0
- package/dist/templates/profiles/ios/docs/claude-agent/user-flow-validation-rocketsim.md +11 -0
- package/dist/templates/profiles/ios/docs/readme/configuration.md +7 -0
- package/dist/templates/profiles/ios/docs/readme/intro.md +7 -0
- package/dist/templates/profiles/ios/docs/readme/port-shared-services-ios-profile.md +25 -0
- package/dist/templates/profiles/ios/docs/readme/quick-start.md +22 -0
- package/dist/templates/profiles/ios/docs/readme/simulators.md +45 -0
- package/dist/templates/profiles/ios/docs/readme/user-flow-validation.md +9 -0
- package/dist/templates/profiles/ios/docs/readme/verification-contract.md +13 -0
- package/dist/templates/profiles/ios/docs/readme/what-s-in-here.md +27 -0
- package/dist/templates/profiles/ios/profile.manifest.json +59 -3
- package/dist/templates/runtime-bundles/pm2-runtime/attach.sh +8 -15
- package/dist/templates/runtime-bundles/pm2-runtime/env.template +1 -1
- package/dist/templates/runtime-bundles/pm2-runtime/stages/api-health.sh +9 -0
- package/dist/templates/runtime-bundles/shared-kernel/STAGES.md +32 -18
- package/dist/templates/runtime-bundles/shared-kernel/agent-cli.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/launch.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/lib/verify-runner.mjs +129 -0
- package/dist/templates/runtime-bundles/shared-kernel/preflight.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/setup-infra.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/stages/README.sh +1 -1
- package/dist/templates/runtime-bundles/shared-kernel/stages/readiness.sh +14 -0
- package/dist/templates/runtime-bundles/shared-kernel/teardown.sh +35 -0
- package/dist/templates/runtime-bundles/shared-kernel/verify.sh +35 -0
- package/dist/templates/shared-docs/claude-agent/intro.md +3 -0
- package/dist/templates/shared-docs/readme/maintaining-this-harness.md +14 -0
- package/dist/templates/shared-docs/readme/run-history.md +5 -0
- package/dist/templates/shared-docs/readme/session-lifecycle.md +20 -0
- package/package.json +1 -1
- package/dist/templates/har-boilerplate/CLAUDE.agent.md +0 -83
- package/dist/templates/har-boilerplate/README.md +0 -199
- package/dist/templates/har-boilerplate/STAGES.md +0 -99
- package/dist/templates/har-boilerplate/agent-cli.sh +0 -225
- package/dist/templates/har-boilerplate/agent-slot.sh +0 -850
- package/dist/templates/har-boilerplate/attach.sh +0 -22
- package/dist/templates/har-boilerplate/ecosystem.agent.template.cjs +0 -52
- package/dist/templates/har-boilerplate/env.template +0 -40
- package/dist/templates/har-boilerplate/launch.sh +0 -323
- package/dist/templates/har-boilerplate/preflight.sh +0 -32
- package/dist/templates/har-boilerplate/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate/setup-infra.sh +0 -178
- package/dist/templates/har-boilerplate/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate/teardown.sh +0 -87
- package/dist/templates/har-boilerplate/verify.sh +0 -249
- package/dist/templates/har-boilerplate-cli/README.md +0 -157
- package/dist/templates/har-boilerplate-cli/STAGES.md +0 -99
- package/dist/templates/har-boilerplate-cli/agent-cli.sh +0 -160
- package/dist/templates/har-boilerplate-cli/agent-slot.sh +0 -832
- package/dist/templates/har-boilerplate-cli/launch.sh +0 -216
- package/dist/templates/har-boilerplate-cli/preflight.sh +0 -28
- package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate-cli/setup-infra.sh +0 -178
- package/dist/templates/har-boilerplate-cli/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate-cli/teardown.sh +0 -66
- package/dist/templates/har-boilerplate-cli/verify.sh +0 -210
- package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +0 -63
- package/dist/templates/har-boilerplate-ios/CLAUDE.agent.md +0 -90
- package/dist/templates/har-boilerplate-ios/README.md +0 -173
- package/dist/templates/har-boilerplate-ios/STAGES.md +0 -99
- package/dist/templates/har-boilerplate-ios/agent-cli.sh +0 -149
- package/dist/templates/har-boilerplate-ios/agent-slot.sh +0 -479
- package/dist/templates/har-boilerplate-ios/launch.sh +0 -206
- package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +0 -766
- package/dist/templates/har-boilerplate-ios/setup-infra.sh +0 -112
- package/dist/templates/har-boilerplate-ios/simulator.sh +0 -492
- package/dist/templates/har-boilerplate-ios/stages/README.sh +0 -11
- package/dist/templates/har-boilerplate-ios/teardown.sh +0 -68
- package/dist/templates/har-boilerplate-ios/verify.sh +0 -185
- package/dist/templates/runtime-bundles/pm2-runtime/README.md +0 -4
- package/dist/templates/runtime-bundles/shared-kernel/README.md +0 -3
- package/dist/templates/runtime-bundles/shared-kernel/provision-toolchain.sh +0 -766
- package/dist/templates/runtime-bundles/xcode-sim/README.md +0 -4
- package/dist/templates/runtime-bundles/xcode-sim/simulator.sh +0 -492
|
@@ -1,766 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Provision the project toolchain and append resolved paths to .env.agent.<id>.
|
|
3
|
-
# Called from launch.sh after the agent env file is created.
|
|
4
|
-
#
|
|
5
|
-
# Configure in harness.env:
|
|
6
|
-
# HARNESS_ECOSYSTEM — auto (default) | node | python | go | rust | java | ruby | ios | none
|
|
7
|
-
# HARNESS_INSTALL_CMD — optional override (eval in HAR_WORK_DIR)
|
|
8
|
-
# Ecosystem-specific optional overrides:
|
|
9
|
-
# HARNESS_PYTHON_VENV_DIR — Python venv path relative to HAR_WORK_DIR (default: .har/venv)
|
|
10
|
-
#
|
|
11
|
-
# Required env from caller: HAR_WORK_DIR, HAR_ENV_FILE
|
|
12
|
-
# Optional: HAR_WORKTREE_DIR, HAR_REL_PREFIX, HAR_AGENT_ID (for logging)
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
: "${HAR_WORK_DIR:?HAR_WORK_DIR is required}"
|
|
16
|
-
: "${HAR_ENV_FILE:?HAR_ENV_FILE is required}"
|
|
17
|
-
|
|
18
|
-
HAR_WORKTREE_DIR="${HAR_WORKTREE_DIR:-}"
|
|
19
|
-
HAR_REL_PREFIX="${HAR_REL_PREFIX:-}"
|
|
20
|
-
HAR_AGENT_ID="${HAR_AGENT_ID:-}"
|
|
21
|
-
|
|
22
|
-
pt_log() {
|
|
23
|
-
if [ -n "$HAR_AGENT_ID" ]; then
|
|
24
|
-
echo "==> [agent-${HAR_AGENT_ID}] toolchain: $*" >&2
|
|
25
|
-
else
|
|
26
|
-
echo "==> [provision-toolchain] $*" >&2
|
|
27
|
-
fi
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
# ── Node package manager helpers ──────────────────────────────────────────────
|
|
31
|
-
# Mirrored verbatim in harness.env and provision-toolchain.sh so a sourcing
|
|
32
|
-
# script and the provisioning subprocess resolve the same tool.
|
|
33
|
-
|
|
34
|
-
# Package managers HAR can drive, in fallback preference order.
|
|
35
|
-
HAR_NODE_PACKAGE_MANAGERS="npm bun pnpm yarn"
|
|
36
|
-
|
|
37
|
-
# Package manager the repo declares: an explicit HARNESS_NODE_PACKAGE_MANAGER
|
|
38
|
-
# wins, then package.json "packageManager", then the lockfile. Empty when the
|
|
39
|
-
# repo says nothing.
|
|
40
|
-
har_node_declared_package_manager() {
|
|
41
|
-
local dir="${1:-.}"
|
|
42
|
-
|
|
43
|
-
if [ -n "${HARNESS_NODE_PACKAGE_MANAGER:-}" ]; then
|
|
44
|
-
echo "$HARNESS_NODE_PACKAGE_MANAGER"
|
|
45
|
-
return
|
|
46
|
-
fi
|
|
47
|
-
if [ -f "$dir/package.json" ]; then
|
|
48
|
-
local field
|
|
49
|
-
field="$(sed -n 's/.*"packageManager"[[:space:]]*:[[:space:]]*"\([a-z]*\)@.*/\1/p' "$dir/package.json" | head -1)"
|
|
50
|
-
if [ -n "$field" ]; then
|
|
51
|
-
echo "$field"
|
|
52
|
-
return
|
|
53
|
-
fi
|
|
54
|
-
fi
|
|
55
|
-
if [ -f "$dir/bun.lock" ] || [ -f "$dir/bun.lockb" ]; then echo bun; return; fi
|
|
56
|
-
if [ -f "$dir/pnpm-lock.yaml" ]; then echo pnpm; return; fi
|
|
57
|
-
if [ -f "$dir/yarn.lock" ]; then echo yarn; return; fi
|
|
58
|
-
if [ -f "$dir/package-lock.json" ]; then echo npm; return; fi
|
|
59
|
-
echo ""
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
# Package manager to actually run. A manager the repo declares but this machine
|
|
63
|
-
# lacks falls back to one that is installed, so a repo pinned to npm still
|
|
64
|
-
# provisions on a bun-only machine (and the reverse).
|
|
65
|
-
har_node_package_manager() {
|
|
66
|
-
local dir="${1:-.}"
|
|
67
|
-
local declared
|
|
68
|
-
declared="$(har_node_declared_package_manager "$dir")"
|
|
69
|
-
|
|
70
|
-
if [ -n "$declared" ] && command -v "$declared" >/dev/null 2>&1; then
|
|
71
|
-
echo "$declared"
|
|
72
|
-
return
|
|
73
|
-
fi
|
|
74
|
-
|
|
75
|
-
local candidate
|
|
76
|
-
for candidate in $HAR_NODE_PACKAGE_MANAGERS; do
|
|
77
|
-
if command -v "$candidate" >/dev/null 2>&1; then
|
|
78
|
-
echo "$candidate"
|
|
79
|
-
return
|
|
80
|
-
fi
|
|
81
|
-
done
|
|
82
|
-
|
|
83
|
-
echo "${declared:-npm}"
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
# Lockfile a manager writes, so a substitute install can clean up after itself.
|
|
87
|
-
har_node_lockfile() {
|
|
88
|
-
case "$1" in
|
|
89
|
-
bun) echo "bun.lock" ;;
|
|
90
|
-
npm) echo "package-lock.json" ;;
|
|
91
|
-
pnpm) echo "pnpm-lock.yaml" ;;
|
|
92
|
-
yarn) echo "yarn.lock" ;;
|
|
93
|
-
*) echo "" ;;
|
|
94
|
-
esac
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
# Install dependencies in a directory. When a substitute manager stands in for
|
|
98
|
-
# the one the repo declares, any lockfile it creates is removed afterwards:
|
|
99
|
-
# provisioning must not migrate the repo to a different package manager.
|
|
100
|
-
# (bun writes bun.lock even under --no-save, so the flags alone are not enough.)
|
|
101
|
-
har_node_install() {
|
|
102
|
-
local dir="$1"
|
|
103
|
-
local manager="$2"
|
|
104
|
-
local declared="${3:-}"
|
|
105
|
-
local substituting=false
|
|
106
|
-
local lockfile=""
|
|
107
|
-
local had_lockfile=false
|
|
108
|
-
|
|
109
|
-
if [ -n "$declared" ] && [ "$declared" != "$manager" ]; then
|
|
110
|
-
substituting=true
|
|
111
|
-
lockfile="$(har_node_lockfile "$manager")"
|
|
112
|
-
if [ -n "$lockfile" ] && [ -e "$dir/$lockfile" ]; then
|
|
113
|
-
had_lockfile=true
|
|
114
|
-
fi
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
local code=0
|
|
118
|
-
(cd "$dir" && "$manager" install --silent) || code=$?
|
|
119
|
-
|
|
120
|
-
if [ "$substituting" = true ] && [ "$had_lockfile" = false ] && [ -n "$lockfile" ]; then
|
|
121
|
-
rm -f "$dir/$lockfile"
|
|
122
|
-
[ "$manager" = "bun" ] && rm -f "$dir/bun.lockb"
|
|
123
|
-
fi
|
|
124
|
-
return $code
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
# Package runner (npx equivalent) for one-off CLIs such as pm2, including the
|
|
128
|
-
# flag that keeps it non-interactive. Takes a manager name, or none to resolve
|
|
129
|
-
# from the environment and PATH.
|
|
130
|
-
har_pkg_exec() {
|
|
131
|
-
case "${1:-${HARNESS_NODE_PACKAGE_MANAGER:-}}" in
|
|
132
|
-
bun) echo "bunx"; return ;;
|
|
133
|
-
pnpm) echo "pnpm dlx"; return ;;
|
|
134
|
-
yarn) echo "yarn dlx"; return ;;
|
|
135
|
-
npm) echo "npx --yes"; return ;;
|
|
136
|
-
esac
|
|
137
|
-
if command -v npx >/dev/null 2>&1; then echo "npx --yes"; return; fi
|
|
138
|
-
if command -v bunx >/dev/null 2>&1; then echo "bunx"; return; fi
|
|
139
|
-
if command -v pnpm >/dev/null 2>&1; then echo "pnpm dlx"; return; fi
|
|
140
|
-
echo "npx --yes"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
append_env() {
|
|
144
|
-
local key="$1"
|
|
145
|
-
local value="$2"
|
|
146
|
-
# %q, not a raw value: an unquoted value with spaces (an Xcode scheme, a
|
|
147
|
-
# simulator name, a path under /Applications) breaks `source .env.agent.<id>`.
|
|
148
|
-
printf '%s=%q\n' "$key" "$value" >> "$HAR_ENV_FILE"
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
append_path_prefix() {
|
|
152
|
-
local prefix="$1"
|
|
153
|
-
[ -n "$prefix" ] && [ -d "$prefix" ] || return 0
|
|
154
|
-
append_env "PATH" "${prefix}:${PATH:-$PATH}"
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
detect_ecosystem() {
|
|
158
|
-
local dir="$1"
|
|
159
|
-
local configured="${HARNESS_ECOSYSTEM:-auto}"
|
|
160
|
-
if [ -n "$configured" ] && [ "$configured" != "auto" ]; then
|
|
161
|
-
echo "$configured"
|
|
162
|
-
return
|
|
163
|
-
fi
|
|
164
|
-
if [ -f "$dir/package.json" ]; then echo node; return; fi
|
|
165
|
-
if [ -f "$dir/pyproject.toml" ] || [ -f "$dir/setup.py" ] || [ -f "$dir/setup.cfg" ] \
|
|
166
|
-
|| [ -f "$dir/requirements.txt" ] || [ -f "$dir/Pipfile" ]; then
|
|
167
|
-
echo python
|
|
168
|
-
return
|
|
169
|
-
fi
|
|
170
|
-
if [ -f "$dir/go.mod" ]; then echo go; return; fi
|
|
171
|
-
if [ -f "$dir/Cargo.toml" ]; then echo rust; return; fi
|
|
172
|
-
if [ -f "$dir/pom.xml" ] || [ -f "$dir/build.gradle" ] || [ -f "$dir/build.gradle.kts" ]; then
|
|
173
|
-
echo java
|
|
174
|
-
return
|
|
175
|
-
fi
|
|
176
|
-
if [ -f "$dir/Gemfile" ]; then echo ruby; return; fi
|
|
177
|
-
if [ -n "${HARNESS_XCODE_SCHEME:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ] \
|
|
178
|
-
|| [ -n "${HARNESS_XCODE_WORKSPACE:-}" ]; then
|
|
179
|
-
echo ios
|
|
180
|
-
return
|
|
181
|
-
fi
|
|
182
|
-
echo none
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
run_install_cmd() {
|
|
186
|
-
local dir="$1"
|
|
187
|
-
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
188
|
-
pt_log "Running HARNESS_INSTALL_CMD..."
|
|
189
|
-
(cd "$dir" && eval "$HARNESS_INSTALL_CMD")
|
|
190
|
-
return
|
|
191
|
-
fi
|
|
192
|
-
return 1
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
provision_node() {
|
|
196
|
-
local dir="$1"
|
|
197
|
-
local node_bin="node"
|
|
198
|
-
local pkg_manager declared_manager
|
|
199
|
-
declared_manager="$(har_node_declared_package_manager "$dir")"
|
|
200
|
-
pkg_manager="$(har_node_package_manager "$dir")"
|
|
201
|
-
|
|
202
|
-
if [ -n "$declared_manager" ] && [ "$declared_manager" != "$pkg_manager" ]; then
|
|
203
|
-
pt_log "Repo declares ${declared_manager}, which is not on PATH — installing with ${pkg_manager} and leaving the lockfile untouched."
|
|
204
|
-
fi
|
|
205
|
-
|
|
206
|
-
if ! run_install_cmd "$dir"; then
|
|
207
|
-
pt_log "Installing Node dependencies with ${pkg_manager}..."
|
|
208
|
-
har_node_install "$dir" "$pkg_manager" "$declared_manager"
|
|
209
|
-
fi
|
|
210
|
-
|
|
211
|
-
if command -v node >/dev/null 2>&1; then
|
|
212
|
-
node_bin="$(command -v node)"
|
|
213
|
-
elif [ "$pkg_manager" = "bun" ]; then
|
|
214
|
-
# bun-only machine: bun runs the `node -e` snippets verify.sh relies on.
|
|
215
|
-
node_bin="$(command -v bun)"
|
|
216
|
-
fi
|
|
217
|
-
|
|
218
|
-
local npm_bin="$pkg_manager"
|
|
219
|
-
if command -v "$pkg_manager" >/dev/null 2>&1; then
|
|
220
|
-
npm_bin="$(command -v "$pkg_manager")"
|
|
221
|
-
fi
|
|
222
|
-
|
|
223
|
-
append_env "HARNESS_ECOSYSTEM" "node"
|
|
224
|
-
append_env "NODE_BIN" "$node_bin"
|
|
225
|
-
append_env "NPM_BIN" "$npm_bin"
|
|
226
|
-
append_env "HARNESS_NODE_PACKAGE_MANAGER" "$pkg_manager"
|
|
227
|
-
append_env "HARNESS_PKG_EXEC" "$(har_pkg_exec "$pkg_manager")"
|
|
228
|
-
append_path_prefix "$dir/node_modules/.bin"
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
# ── Python interpreter helpers ────────────────────────────────────────────────
|
|
232
|
-
# Resolve the project Python (requires-python, .python-version, uv) instead of
|
|
233
|
-
# blindly using PATH python3.
|
|
234
|
-
|
|
235
|
-
har_python_version_from_bin() {
|
|
236
|
-
local bin="$1"
|
|
237
|
-
"$bin" -c 'import sys; print(".".join(map(str, sys.version_info[:3])))' 2>/dev/null \
|
|
238
|
-
| tr -d '[:space:]'
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
har_python_version_to_sortable() {
|
|
242
|
-
local v="${1#python}"
|
|
243
|
-
v="${v#v}"
|
|
244
|
-
local major=0 minor=0 patch=0
|
|
245
|
-
IFS='.' read -r major minor patch _ <<< "$v"
|
|
246
|
-
major=${major:-0}
|
|
247
|
-
minor=${minor:-0}
|
|
248
|
-
patch=${patch:-0}
|
|
249
|
-
printf '%03d%03d%03d' "$major" "$minor" "$patch"
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
har_python_version_ge() {
|
|
253
|
-
local a b
|
|
254
|
-
a="$(har_python_version_to_sortable "$1")"
|
|
255
|
-
b="$(har_python_version_to_sortable "$2")"
|
|
256
|
-
[ "$a" -ge "$b" ]
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
har_python_requires_minimum() {
|
|
260
|
-
local spec="$1"
|
|
261
|
-
local ver=""
|
|
262
|
-
|
|
263
|
-
[ -n "$spec" ] || return 1
|
|
264
|
-
|
|
265
|
-
ver="$(printf '%s' "$spec" | sed -n \
|
|
266
|
-
-e 's/.*>=\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' \
|
|
267
|
-
-e 's/.*~=\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' \
|
|
268
|
-
-e 's/.*==\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p' \
|
|
269
|
-
| head -1)"
|
|
270
|
-
|
|
271
|
-
if [ -z "$ver" ]; then
|
|
272
|
-
ver="$(printf '%s' "$spec" | sed -n 's/^\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/p')"
|
|
273
|
-
fi
|
|
274
|
-
|
|
275
|
-
[ -n "$ver" ] && echo "$ver"
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
har_python_read_dot_version() {
|
|
279
|
-
local dir="$1"
|
|
280
|
-
[ -f "$dir/.python-version" ] || return 1
|
|
281
|
-
head -1 "$dir/.python-version" | tr -d '[:space:]'
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
har_python_read_requires_spec() {
|
|
285
|
-
local dir="$1"
|
|
286
|
-
local spec=""
|
|
287
|
-
|
|
288
|
-
if [ -f "$dir/pyproject.toml" ]; then
|
|
289
|
-
spec="$(sed -n 's/^[[:space:]]*requires-python[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
290
|
-
"$dir/pyproject.toml" | head -1)"
|
|
291
|
-
fi
|
|
292
|
-
if [ -z "$spec" ] && [ -f "$dir/setup.cfg" ]; then
|
|
293
|
-
spec="$(sed -n '/^\[options\]/,/^\[/ s/^python_requires[[:space:]]*=[[:space:]]*\(.*\)/\1/p' \
|
|
294
|
-
"$dir/setup.cfg" | head -1 | tr -d ' "')"
|
|
295
|
-
fi
|
|
296
|
-
[ -n "$spec" ] && echo "$spec"
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
har_python_project_minimum() {
|
|
300
|
-
local dir="$1"
|
|
301
|
-
local req_min="" dot_ver="" higher=""
|
|
302
|
-
|
|
303
|
-
req_min="$(har_python_requires_minimum "$(har_python_read_requires_spec "$dir" || true)" || true)"
|
|
304
|
-
dot_ver="$(har_python_read_dot_version "$dir" || true)"
|
|
305
|
-
if [ -n "$dot_ver" ]; then
|
|
306
|
-
dot_ver="$(printf '%s' "$dot_ver" | sed 's/^v//; s/^\([0-9][0-9]*\.[0-9][0-9]*\).*/\1/')"
|
|
307
|
-
fi
|
|
308
|
-
|
|
309
|
-
if [ -n "$req_min" ] && [ -n "$dot_ver" ]; then
|
|
310
|
-
if har_python_version_ge "$dot_ver" "$req_min"; then
|
|
311
|
-
higher="$dot_ver"
|
|
312
|
-
else
|
|
313
|
-
higher="$req_min"
|
|
314
|
-
fi
|
|
315
|
-
elif [ -n "$req_min" ]; then
|
|
316
|
-
higher="$req_min"
|
|
317
|
-
elif [ -n "$dot_ver" ]; then
|
|
318
|
-
higher="$dot_ver"
|
|
319
|
-
fi
|
|
320
|
-
|
|
321
|
-
[ -n "$higher" ] && echo "$higher"
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
har_python_is_uv_project() {
|
|
325
|
-
local dir="$1"
|
|
326
|
-
[ -f "$dir/uv.lock" ] && return 0
|
|
327
|
-
[ -f "$dir/pyproject.toml" ] && grep -q '^\[tool\.uv\]' "$dir/pyproject.toml" 2>/dev/null
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
har_python_uv_find() {
|
|
331
|
-
local dir="$1"
|
|
332
|
-
local request="${2:-}"
|
|
333
|
-
|
|
334
|
-
command -v uv >/dev/null 2>&1 || return 1
|
|
335
|
-
if [ -n "$request" ]; then
|
|
336
|
-
(cd "$dir" && uv python find "$request" 2>/dev/null)
|
|
337
|
-
else
|
|
338
|
-
(cd "$dir" && uv python find 2>/dev/null)
|
|
339
|
-
fi
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
har_python_resolve_interpreter() {
|
|
343
|
-
local dir="$1"
|
|
344
|
-
local minimum="${2:-}"
|
|
345
|
-
local found=""
|
|
346
|
-
|
|
347
|
-
if har_python_is_uv_project "$dir"; then
|
|
348
|
-
found="$(har_python_uv_find "$dir" "$minimum" || true)"
|
|
349
|
-
if [ -n "$found" ] && [ -x "$found" ]; then
|
|
350
|
-
echo "$found"
|
|
351
|
-
return 0
|
|
352
|
-
fi
|
|
353
|
-
fi
|
|
354
|
-
|
|
355
|
-
if [ -f "$dir/.python-version" ]; then
|
|
356
|
-
found="$(har_python_uv_find "$dir" "$(har_python_read_dot_version "$dir")" || true)"
|
|
357
|
-
if [ -n "$found" ] && [ -x "$found" ]; then
|
|
358
|
-
echo "$found"
|
|
359
|
-
return 0
|
|
360
|
-
fi
|
|
361
|
-
if command -v pyenv >/dev/null 2>&1; then
|
|
362
|
-
found="$(cd "$dir" && pyenv which python 2>/dev/null || true)"
|
|
363
|
-
if [ -n "$found" ] && [ -x "$found" ]; then
|
|
364
|
-
echo "$found"
|
|
365
|
-
return 0
|
|
366
|
-
fi
|
|
367
|
-
fi
|
|
368
|
-
fi
|
|
369
|
-
|
|
370
|
-
if [ -n "$minimum" ]; then
|
|
371
|
-
found="$(har_python_uv_find "$dir" "$minimum" || true)"
|
|
372
|
-
if [ -n "$found" ] && [ -x "$found" ]; then
|
|
373
|
-
echo "$found"
|
|
374
|
-
return 0
|
|
375
|
-
fi
|
|
376
|
-
fi
|
|
377
|
-
|
|
378
|
-
if command -v python3 >/dev/null 2>&1; then
|
|
379
|
-
local sys_py sys_ver=""
|
|
380
|
-
sys_py="$(command -v python3)"
|
|
381
|
-
if [ -z "$minimum" ]; then
|
|
382
|
-
echo "$sys_py"
|
|
383
|
-
return 0
|
|
384
|
-
fi
|
|
385
|
-
sys_ver="$(har_python_version_from_bin "$sys_py")"
|
|
386
|
-
if [ -n "$sys_ver" ] && har_python_version_ge "$sys_ver" "$minimum"; then
|
|
387
|
-
echo "$sys_py"
|
|
388
|
-
return 0
|
|
389
|
-
fi
|
|
390
|
-
echo "$sys_py"
|
|
391
|
-
return 0
|
|
392
|
-
fi
|
|
393
|
-
|
|
394
|
-
return 1
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
har_python_warn_if_below_minimum() {
|
|
398
|
-
local bin="$1"
|
|
399
|
-
local minimum="$2"
|
|
400
|
-
local actual=""
|
|
401
|
-
|
|
402
|
-
[ -n "$minimum" ] || return 0
|
|
403
|
-
actual="$(har_python_version_from_bin "$bin")"
|
|
404
|
-
[ -n "$actual" ] || return 0
|
|
405
|
-
if ! har_python_version_ge "$actual" "$minimum"; then
|
|
406
|
-
pt_log "WARNING: resolved Python ${actual} is older than required ${minimum} (requires-python / .python-version)"
|
|
407
|
-
fi
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
har_python_create_venv() {
|
|
411
|
-
local dir="$1"
|
|
412
|
-
local venv_dir="$2"
|
|
413
|
-
local interpreter="$3"
|
|
414
|
-
local venv_rel="${venv_dir#"$dir"/}"
|
|
415
|
-
|
|
416
|
-
if har_python_is_uv_project "$dir" && command -v uv >/dev/null 2>&1; then
|
|
417
|
-
pt_log "Creating Python venv with uv at ${venv_rel}..."
|
|
418
|
-
if (cd "$dir" && uv venv --python "$interpreter" "$venv_dir" 2>/dev/null) \
|
|
419
|
-
|| (cd "$dir" && uv venv "$venv_dir" 2>/dev/null); then
|
|
420
|
-
return 0
|
|
421
|
-
fi
|
|
422
|
-
pt_log "uv venv failed — falling back to ${interpreter} -m venv"
|
|
423
|
-
fi
|
|
424
|
-
|
|
425
|
-
pt_log "Creating Python venv at ${venv_rel}..."
|
|
426
|
-
"$interpreter" -m venv "$venv_dir"
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
har_python_install_deps() {
|
|
430
|
-
local dir="$1"
|
|
431
|
-
local venv_dir="$2"
|
|
432
|
-
|
|
433
|
-
if har_python_is_uv_project "$dir" && command -v uv >/dev/null 2>&1; then
|
|
434
|
-
pt_log "Syncing Python dependencies with uv..."
|
|
435
|
-
if (cd "$dir" && UV_PROJECT_ENVIRONMENT="$venv_dir" uv sync --quiet 2>/dev/null); then
|
|
436
|
-
return 0
|
|
437
|
-
fi
|
|
438
|
-
if (cd "$dir" && uv sync --quiet 2>/dev/null); then
|
|
439
|
-
return 0
|
|
440
|
-
fi
|
|
441
|
-
pt_log "uv sync failed — falling back to pip"
|
|
442
|
-
return 1
|
|
443
|
-
fi
|
|
444
|
-
return 1
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
provision_python() {
|
|
448
|
-
local dir="$1"
|
|
449
|
-
local venv_rel="${HARNESS_PYTHON_VENV_DIR:-.har/venv}"
|
|
450
|
-
local venv_dir="$dir/$venv_rel"
|
|
451
|
-
local python_bin=""
|
|
452
|
-
local interpreter=""
|
|
453
|
-
local project_min=""
|
|
454
|
-
|
|
455
|
-
project_min="$(har_python_project_minimum "$dir" || true)"
|
|
456
|
-
interpreter="$(har_python_resolve_interpreter "$dir" "$project_min" || true)"
|
|
457
|
-
|
|
458
|
-
if [ -z "$interpreter" ] || ! command -v "$interpreter" >/dev/null 2>&1; then
|
|
459
|
-
pt_log "No suitable Python interpreter found — skipping venv provisioning"
|
|
460
|
-
append_env "HARNESS_ECOSYSTEM" "python"
|
|
461
|
-
append_env "PYTHON_BIN" "${PYTHON_BIN:-python3}"
|
|
462
|
-
return
|
|
463
|
-
fi
|
|
464
|
-
|
|
465
|
-
if [ -n "$project_min" ]; then
|
|
466
|
-
har_python_warn_if_below_minimum "$interpreter" "$project_min"
|
|
467
|
-
fi
|
|
468
|
-
|
|
469
|
-
if [ -d "$venv_dir" ] && [ -x "$venv_dir/bin/python" ] && [ -n "$project_min" ]; then
|
|
470
|
-
local venv_ver=""
|
|
471
|
-
venv_ver="$(har_python_version_from_bin "$venv_dir/bin/python")"
|
|
472
|
-
if [ -n "$venv_ver" ] && ! har_python_version_ge "$venv_ver" "$project_min"; then
|
|
473
|
-
pt_log "Existing venv Python ${venv_ver} is older than required ${project_min} — recreating..."
|
|
474
|
-
rm -rf "$venv_dir"
|
|
475
|
-
fi
|
|
476
|
-
fi
|
|
477
|
-
|
|
478
|
-
if [ ! -d "$venv_dir" ]; then
|
|
479
|
-
if ! har_python_create_venv "$dir" "$venv_dir" "$interpreter"; then
|
|
480
|
-
rm -rf "$venv_dir"
|
|
481
|
-
pt_log "venv creation failed (on Debian/Ubuntu install python3-venv) — using resolved interpreter"
|
|
482
|
-
append_env "HARNESS_ECOSYSTEM" "python"
|
|
483
|
-
append_env "PYTHON_BIN" "$interpreter"
|
|
484
|
-
return
|
|
485
|
-
fi
|
|
486
|
-
fi
|
|
487
|
-
|
|
488
|
-
if [ ! -x "$venv_dir/bin/python" ]; then
|
|
489
|
-
pt_log "Python venv at $venv_rel is missing or broken — using resolved interpreter"
|
|
490
|
-
append_env "HARNESS_ECOSYSTEM" "python"
|
|
491
|
-
append_env "PYTHON_BIN" "$interpreter"
|
|
492
|
-
return
|
|
493
|
-
fi
|
|
494
|
-
|
|
495
|
-
python_bin="$venv_dir/bin/python"
|
|
496
|
-
if [ -n "$project_min" ]; then
|
|
497
|
-
har_python_warn_if_below_minimum "$python_bin" "$project_min"
|
|
498
|
-
fi
|
|
499
|
-
|
|
500
|
-
# shellcheck disable=SC1091
|
|
501
|
-
source "$venv_dir/bin/activate"
|
|
502
|
-
|
|
503
|
-
if ! run_install_cmd "$dir"; then
|
|
504
|
-
if ! har_python_install_deps "$dir" "$venv_dir"; then
|
|
505
|
-
pt_log "Installing Python dependencies..."
|
|
506
|
-
if [ -f "$dir/pyproject.toml" ]; then
|
|
507
|
-
(cd "$dir" && pip install -q -e ".[dev]" 2>/dev/null) || (cd "$dir" && pip install -q -e .)
|
|
508
|
-
elif [ -f "$dir/requirements.txt" ]; then
|
|
509
|
-
(cd "$dir" && pip install -q -r requirements.txt)
|
|
510
|
-
elif [ -f "$dir/setup.py" ] || [ -f "$dir/setup.cfg" ]; then
|
|
511
|
-
(cd "$dir" && pip install -q -e .)
|
|
512
|
-
elif [ -f "$dir/Pipfile" ] && command -v pipenv >/dev/null 2>&1; then
|
|
513
|
-
(cd "$dir" && pipenv install --dev)
|
|
514
|
-
python_bin="$(cd "$dir" && pipenv --py)"
|
|
515
|
-
fi
|
|
516
|
-
fi
|
|
517
|
-
fi
|
|
518
|
-
|
|
519
|
-
append_env "HARNESS_ECOSYSTEM" "python"
|
|
520
|
-
append_env "PYTHON_BIN" "$python_bin"
|
|
521
|
-
append_env "VIRTUAL_ENV" "$venv_dir"
|
|
522
|
-
append_path_prefix "$venv_dir/bin"
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
provision_go() {
|
|
526
|
-
local dir="$1"
|
|
527
|
-
if ! run_install_cmd "$dir"; then
|
|
528
|
-
if command -v go >/dev/null 2>&1; then
|
|
529
|
-
pt_log "Downloading Go modules..."
|
|
530
|
-
(cd "$dir" && go mod download)
|
|
531
|
-
else
|
|
532
|
-
pt_log "go not found on PATH — record paths only"
|
|
533
|
-
fi
|
|
534
|
-
fi
|
|
535
|
-
append_env "HARNESS_ECOSYSTEM" "go"
|
|
536
|
-
append_env "GO_BIN" "$(command -v go 2>/dev/null || echo go)"
|
|
537
|
-
if [ -n "${GOPATH:-}" ]; then append_env "GOPATH" "$GOPATH"; fi
|
|
538
|
-
if [ -n "${GOROOT:-}" ]; then append_env "GOROOT" "$GOROOT"; fi
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
provision_rust() {
|
|
542
|
-
local dir="$1"
|
|
543
|
-
if ! run_install_cmd "$dir"; then
|
|
544
|
-
if command -v cargo >/dev/null 2>&1; then
|
|
545
|
-
pt_log "Fetching Rust dependencies..."
|
|
546
|
-
(cd "$dir" && cargo fetch)
|
|
547
|
-
else
|
|
548
|
-
pt_log "cargo not found on PATH — record paths only"
|
|
549
|
-
fi
|
|
550
|
-
fi
|
|
551
|
-
append_env "HARNESS_ECOSYSTEM" "rust"
|
|
552
|
-
append_env "CARGO_BIN" "$(command -v cargo 2>/dev/null || echo cargo)"
|
|
553
|
-
append_env "RUSTC_BIN" "$(command -v rustc 2>/dev/null || echo rustc)"
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
provision_java() {
|
|
557
|
-
local dir="$1"
|
|
558
|
-
run_install_cmd "$dir" || true
|
|
559
|
-
append_env "HARNESS_ECOSYSTEM" "java"
|
|
560
|
-
if [ -n "${JAVA_HOME:-}" ]; then
|
|
561
|
-
append_env "JAVA_HOME" "$JAVA_HOME"
|
|
562
|
-
append_path_prefix "$JAVA_HOME/bin"
|
|
563
|
-
fi
|
|
564
|
-
if command -v mvn >/dev/null 2>&1; then
|
|
565
|
-
append_env "MVN_BIN" "$(command -v mvn)"
|
|
566
|
-
elif [ -f "$dir/gradlew" ]; then
|
|
567
|
-
append_env "GRADLE_BIN" "$dir/gradlew"
|
|
568
|
-
elif command -v gradle >/dev/null 2>&1; then
|
|
569
|
-
append_env "GRADLE_BIN" "$(command -v gradle)"
|
|
570
|
-
fi
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
provision_ruby() {
|
|
574
|
-
local dir="$1"
|
|
575
|
-
if ! run_install_cmd "$dir"; then
|
|
576
|
-
if command -v bundle >/dev/null 2>&1; then
|
|
577
|
-
pt_log "Installing Ruby gems..."
|
|
578
|
-
(cd "$dir" && bundle install --quiet)
|
|
579
|
-
else
|
|
580
|
-
pt_log "bundle not found on PATH — record paths only"
|
|
581
|
-
fi
|
|
582
|
-
fi
|
|
583
|
-
append_env "HARNESS_ECOSYSTEM" "ruby"
|
|
584
|
-
append_env "RUBY_BIN" "$(command -v ruby 2>/dev/null || echo ruby)"
|
|
585
|
-
append_env "BUNDLE_BIN" "$(command -v bundle 2>/dev/null || echo bundle)"
|
|
586
|
-
append_path_prefix "$dir/vendor/bundle/bin"
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
# ── iOS Xcode project helpers ─────────────────────────────────────────────────
|
|
590
|
-
# Tuist, XcodeGen and CocoaPods treat the .xcodeproj / .xcworkspace as a build
|
|
591
|
-
# product rather than a tracked file, so a fresh worktree has nothing for
|
|
592
|
-
# xcodebuild to open. Generate it here — and fail naming the missing generator,
|
|
593
|
-
# instead of letting xcodebuild report an opaque "scheme not found" later.
|
|
594
|
-
|
|
595
|
-
# First project file of a kind in the work dir. Runs from inside the dir so a dot
|
|
596
|
-
# in the worktree path itself cannot trip the dotfile filter, and skips both the
|
|
597
|
-
# project.xcworkspace every .xcodeproj carries inside it and whatever CocoaPods
|
|
598
|
-
# generates under Pods/.
|
|
599
|
-
har_ios_find_project_file() {
|
|
600
|
-
local dir="$1"
|
|
601
|
-
local pattern="$2"
|
|
602
|
-
local match=""
|
|
603
|
-
match="$(cd "$dir" 2>/dev/null && find . -maxdepth 2 -name "$pattern" \
|
|
604
|
-
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1)" || true
|
|
605
|
-
[ -n "$match" ] || return 1
|
|
606
|
-
echo "${match#./}"
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
# True when this worktree already has something xcodebuild can open. Adapt-time
|
|
610
|
-
# HARNESS_XCODE_WORKSPACE / HARNESS_XCODE_PROJECT decide it when set: they name
|
|
611
|
-
# the generated file, so a missing one means the generator still has to run.
|
|
612
|
-
har_ios_has_project() {
|
|
613
|
-
local dir="$1"
|
|
614
|
-
|
|
615
|
-
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ]; then
|
|
616
|
-
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] && [ -e "$dir/$HARNESS_XCODE_WORKSPACE" ]; then
|
|
617
|
-
return 0
|
|
618
|
-
fi
|
|
619
|
-
if [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$dir/$HARNESS_XCODE_PROJECT" ]; then
|
|
620
|
-
return 0
|
|
621
|
-
fi
|
|
622
|
-
return 1
|
|
623
|
-
fi
|
|
624
|
-
|
|
625
|
-
if har_ios_find_project_file "$dir" '*.xcworkspace' >/dev/null; then return 0; fi
|
|
626
|
-
if har_ios_find_project_file "$dir" '*.xcodeproj' >/dev/null; then return 0; fi
|
|
627
|
-
return 1
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
# Generator this repo declares, or empty. A Podfile counts: `pod install` is what
|
|
631
|
-
# writes the .xcworkspace for a CocoaPods project.
|
|
632
|
-
har_ios_project_generator() {
|
|
633
|
-
local dir="$1"
|
|
634
|
-
if [ -f "$dir/Project.swift" ] || [ -f "$dir/Workspace.swift" ]; then echo tuist; return; fi
|
|
635
|
-
if [ -f "$dir/project.yml" ] || [ -f "$dir/project.yaml" ]; then echo xcodegen; return; fi
|
|
636
|
-
if [ -f "$dir/Podfile" ]; then echo pod; return; fi
|
|
637
|
-
echo ""
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
har_ios_generate_project() {
|
|
641
|
-
local dir="$1"
|
|
642
|
-
local generator=""
|
|
643
|
-
|
|
644
|
-
if har_ios_has_project "$dir"; then
|
|
645
|
-
return 0
|
|
646
|
-
fi
|
|
647
|
-
|
|
648
|
-
generator="$(har_ios_project_generator "$dir")"
|
|
649
|
-
if [ -z "$generator" ]; then
|
|
650
|
-
pt_log "No .xcodeproj/.xcworkspace found and no generator manifest (Project.swift, project.yml, Podfile) — set HARNESS_XCODE_PROJECT/HARNESS_XCODE_WORKSPACE or HARNESS_INSTALL_CMD in harness.env"
|
|
651
|
-
return 0
|
|
652
|
-
fi
|
|
653
|
-
|
|
654
|
-
if ! command -v "$generator" >/dev/null 2>&1; then
|
|
655
|
-
local label="$generator"
|
|
656
|
-
[ "$generator" = "pod" ] && label="CocoaPods (pod)"
|
|
657
|
-
pt_log "ERROR: this repo generates its Xcode project with ${label}, which is not on PATH."
|
|
658
|
-
pt_log " Install ${label}, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
659
|
-
return 1
|
|
660
|
-
fi
|
|
661
|
-
|
|
662
|
-
case "$generator" in
|
|
663
|
-
tuist)
|
|
664
|
-
pt_log "Generating the Xcode project with tuist..."
|
|
665
|
-
if ! (cd "$dir" && tuist generate --no-open); then
|
|
666
|
-
pt_log "tuist generate --no-open failed — retrying without the flag"
|
|
667
|
-
(cd "$dir" && tuist generate)
|
|
668
|
-
fi
|
|
669
|
-
;;
|
|
670
|
-
xcodegen)
|
|
671
|
-
pt_log "Generating the Xcode project with xcodegen..."
|
|
672
|
-
(cd "$dir" && xcodegen generate)
|
|
673
|
-
;;
|
|
674
|
-
pod)
|
|
675
|
-
# har_ios_pod_install writes the workspace right after this.
|
|
676
|
-
:
|
|
677
|
-
;;
|
|
678
|
-
esac
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
# CocoaPods dependencies. Independent of project generation: a tracked
|
|
682
|
-
# .xcworkspace still cannot build when Pods/ is missing in a fresh worktree.
|
|
683
|
-
har_ios_pod_install() {
|
|
684
|
-
local dir="$1"
|
|
685
|
-
|
|
686
|
-
[ -f "$dir/Podfile" ] || return 0
|
|
687
|
-
[ -d "$dir/Pods" ] && return 0
|
|
688
|
-
|
|
689
|
-
if ! command -v pod >/dev/null 2>&1; then
|
|
690
|
-
pt_log "ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH."
|
|
691
|
-
pt_log " Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
692
|
-
return 1
|
|
693
|
-
fi
|
|
694
|
-
|
|
695
|
-
pt_log "Installing CocoaPods dependencies..."
|
|
696
|
-
(cd "$dir" && pod install)
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
provision_ios() {
|
|
700
|
-
local dir="$1"
|
|
701
|
-
|
|
702
|
-
# An explicit HARNESS_INSTALL_CMD owns provisioning outright: the default
|
|
703
|
-
# generators stay out of the way, and a failing override fails the launch
|
|
704
|
-
# rather than being papered over.
|
|
705
|
-
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
706
|
-
run_install_cmd "$dir"
|
|
707
|
-
else
|
|
708
|
-
har_ios_generate_project "$dir"
|
|
709
|
-
har_ios_pod_install "$dir"
|
|
710
|
-
fi
|
|
711
|
-
|
|
712
|
-
append_env "HARNESS_ECOSYSTEM" "ios"
|
|
713
|
-
append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
|
|
714
|
-
if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
|
|
715
|
-
append_env "HARNESS_XCODE_SCHEME" "$HARNESS_XCODE_SCHEME"
|
|
716
|
-
fi
|
|
717
|
-
# The simulator is not recorded here: launch.sh writes the device reserved for
|
|
718
|
-
# this slot, and harness.env already carries the shared one.
|
|
719
|
-
if [ -n "${HARNESS_BUNDLE_ID:-}" ]; then
|
|
720
|
-
append_env "HARNESS_BUNDLE_ID" "$HARNESS_BUNDLE_ID"
|
|
721
|
-
fi
|
|
722
|
-
if [ -n "${DEVELOPER_DIR:-}" ]; then
|
|
723
|
-
append_env "DEVELOPER_DIR" "$DEVELOPER_DIR"
|
|
724
|
-
fi
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
provision_monorepo_root() {
|
|
728
|
-
[ -n "$HAR_REL_PREFIX" ] || return 0
|
|
729
|
-
[ -n "$HAR_WORKTREE_DIR" ] || return 0
|
|
730
|
-
[ -f "$HAR_WORKTREE_DIR/package.json" ] || return 0
|
|
731
|
-
[ -d "$HAR_WORKTREE_DIR/node_modules" ] && return 0
|
|
732
|
-
local pkg_manager
|
|
733
|
-
pkg_manager="$(har_node_package_manager "$HAR_WORKTREE_DIR")"
|
|
734
|
-
pt_log "Installing monorepo root dependencies in $HAR_WORKTREE_DIR with ${pkg_manager}..."
|
|
735
|
-
har_node_install "$HAR_WORKTREE_DIR" "$pkg_manager" \
|
|
736
|
-
"$(har_node_declared_package_manager "$HAR_WORKTREE_DIR")"
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
provision_ecosystem() {
|
|
740
|
-
local dir="$1"
|
|
741
|
-
local ecosystem
|
|
742
|
-
ecosystem="$(detect_ecosystem "$dir")"
|
|
743
|
-
pt_log "Toolchain ecosystem: ${ecosystem} (work dir: ${dir})"
|
|
744
|
-
|
|
745
|
-
case "$ecosystem" in
|
|
746
|
-
node) provision_node "$dir" ;;
|
|
747
|
-
python) provision_python "$dir" ;;
|
|
748
|
-
go) provision_go "$dir" ;;
|
|
749
|
-
rust) provision_rust "$dir" ;;
|
|
750
|
-
java) provision_java "$dir" ;;
|
|
751
|
-
ruby) provision_ruby "$dir" ;;
|
|
752
|
-
ios) provision_ios "$dir" ;;
|
|
753
|
-
none)
|
|
754
|
-
if run_install_cmd "$dir"; then
|
|
755
|
-
append_env "HARNESS_ECOSYSTEM" "custom"
|
|
756
|
-
else
|
|
757
|
-
pt_log "No ecosystem manifest detected — set HARNESS_ECOSYSTEM or HARNESS_INSTALL_CMD in harness.env"
|
|
758
|
-
append_env "HARNESS_ECOSYSTEM" "none"
|
|
759
|
-
fi
|
|
760
|
-
;;
|
|
761
|
-
esac
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
append_env "HARNESS_TOOLCHAIN_PROVISIONED" "true"
|
|
765
|
-
provision_ecosystem "$HAR_WORK_DIR"
|
|
766
|
-
provision_monorepo_root
|