xgem-cli 2.0.0-alpha.2 → 2.0.0-alpha.4
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/lib/doctor.sh +9 -1
- package/lib/flutter.sh +8 -3
- package/lib/git.sh +25 -6
- package/lib/ios.sh +51 -34
- package/lib/version.sh +1 -1
- package/lib-win/git.js +27 -7
- package/package.json +1 -1
package/lib/doctor.sh
CHANGED
|
@@ -86,7 +86,7 @@ doctor_print_ios() {
|
|
|
86
86
|
echo "Deployment target [$cfg]: ${t:-unknown}"
|
|
87
87
|
done
|
|
88
88
|
|
|
89
|
-
local required
|
|
89
|
+
local required generated
|
|
90
90
|
required=$(ios_required_spm_deployment_target "$project_dir" 2>/dev/null)
|
|
91
91
|
if [ -n "$required" ]; then
|
|
92
92
|
echo "Required by resolved SwiftPM plugins: $required"
|
|
@@ -94,6 +94,14 @@ doctor_print_ios() {
|
|
|
94
94
|
echo "Required by resolved SwiftPM plugins: unable to determine (run 'flutter pub get' first, or no SPM plugins declare an explicit floor)"
|
|
95
95
|
fi
|
|
96
96
|
|
|
97
|
+
if [ "$uses_spm" = "yes" ]; then
|
|
98
|
+
generated=$(ios_generated_package_target "$project_dir" 2>/dev/null)
|
|
99
|
+
echo "FlutterGeneratedPluginSwiftPackage declares: ${generated:-unknown}"
|
|
100
|
+
if [ -n "$required" ] && [ -n "$generated" ] && _ios_ver_lt "$generated" "$required"; then
|
|
101
|
+
log_warn "This is stale — it declares iOS $generated but plugins need $required. This can happen even when your app's own deployment target is already high enough; 'xgem run flutter build' will detect and fix this."
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
97
105
|
if [ "$uses_spm" = "yes" ]; then
|
|
98
106
|
ios_known_issue_check
|
|
99
107
|
fi
|
package/lib/flutter.sh
CHANGED
|
@@ -66,14 +66,19 @@ _flutter_build_ios() {
|
|
|
66
66
|
|
|
67
67
|
require_cmd xcodebuild "iOS builds require Xcode's command-line tools."
|
|
68
68
|
|
|
69
|
+
# Must run pub get BEFORE reconciling: the required-deployment-target
|
|
70
|
+
# check reads .dart_tool/package_config.json, and that file only
|
|
71
|
+
# reflects the plugin versions actually in use after a fresh pub get.
|
|
72
|
+
# Reconciling against a stale package_config.json can silently pass a
|
|
73
|
+
# check that the real, just-resolved dependency graph would fail.
|
|
74
|
+
log_info "Regenerating dependencies..."
|
|
75
|
+
flutter pub get
|
|
76
|
+
|
|
69
77
|
log_info "Reconciling iOS deployment target against resolved SwiftPM plugins..."
|
|
70
78
|
if ! ios_reconcile_deployment_target "."; then
|
|
71
79
|
die "iOS deployment target could not be reconciled; aborting before build."
|
|
72
80
|
fi
|
|
73
81
|
|
|
74
|
-
log_info "Regenerating dependencies..."
|
|
75
|
-
flutter pub get
|
|
76
|
-
|
|
77
82
|
if ios_project_uses_pods "."; then
|
|
78
83
|
log_info "CocoaPods detected - installing pods..."
|
|
79
84
|
( cd ios || exit 1; pod install )
|
package/lib/git.sh
CHANGED
|
@@ -24,9 +24,13 @@ cmd_git_cmt() {
|
|
|
24
24
|
die "Invalid choice. Operation aborted."
|
|
25
25
|
fi
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
if git diff --cached --quiet; then
|
|
28
|
+
log_warn "Nothing staged to commit — checking whether there's anything already committed to sync."
|
|
29
|
+
else
|
|
30
|
+
log_info "Committing changes..."
|
|
31
|
+
if ! git commit -m "$commit_msg"; then
|
|
32
|
+
die "Commit failed. Aborting before pull/push."
|
|
33
|
+
fi
|
|
30
34
|
fi
|
|
31
35
|
|
|
32
36
|
local current_branch remote_name
|
|
@@ -38,14 +42,29 @@ cmd_git_cmt() {
|
|
|
38
42
|
fi
|
|
39
43
|
|
|
40
44
|
if [ -z "$remote_name" ]; then
|
|
41
|
-
log_warn "
|
|
45
|
+
log_warn "No remote configured — sync was skipped."
|
|
46
|
+
return 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
local ahead_count
|
|
50
|
+
ahead_count=$(git rev-list --count "$remote_name/$current_branch..$current_branch" 2>/dev/null)
|
|
51
|
+
if [ "$ahead_count" = "0" ]; then
|
|
52
|
+
log_success "Already up to date with '$remote_name/$current_branch' — nothing to push."
|
|
42
53
|
return 0
|
|
43
54
|
fi
|
|
44
55
|
|
|
45
56
|
log_info "Pulling updates from remote '$remote_name' on '$current_branch' via rebase..."
|
|
46
57
|
if ! git pull --rebase "$remote_name" "$current_branch"; then
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
local git_dir
|
|
59
|
+
git_dir=$(git rev-parse --git-dir 2>/dev/null)
|
|
60
|
+
if [ -d "$git_dir/rebase-merge" ] || [ -d "$git_dir/rebase-apply" ]; then
|
|
61
|
+
log_error "MERGE CONFLICT DETECTED!"
|
|
62
|
+
log_warn "Execution paused. Resolve conflicts to proceed."
|
|
63
|
+
else
|
|
64
|
+
log_error "Could not sync with '$remote_name' — this looks like a connection problem, not a merge conflict (see the git error above)."
|
|
65
|
+
log_warn "Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push $remote_name $current_branch"
|
|
66
|
+
exit 1
|
|
67
|
+
fi
|
|
49
68
|
local open_editor
|
|
50
69
|
read -r -p "Do you want to open VS Code to resolve this now? (y/n): " open_editor
|
|
51
70
|
[[ "$open_editor" == "y" || "$open_editor" == "Y" ]] && code .
|
package/lib/ios.sh
CHANGED
|
@@ -206,13 +206,23 @@ ios_regenerate_generated_package() {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
ios_known_issue_check() {
|
|
209
|
-
log_warn "Known upstream issue (flutter/flutter#186804, #189422, #162072): FlutterGeneratedPluginSwiftPackage's deployment target can desync from your app's IPHONEOS_DEPLOYMENT_TARGET. Currently open — xgem detects and works around it automatically below."
|
|
209
|
+
log_warn "Known upstream issue (flutter/flutter#186804, #189422, #162072): FlutterGeneratedPluginSwiftPackage's deployment target can desync from your app's IPHONEOS_DEPLOYMENT_TARGET — independently, even when the app's own target is already high enough. Currently open — xgem detects and works around it automatically below."
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# _ios_ver_lt a b -> true if a < b, numeric comparison (not string equality,
|
|
213
|
+
# since "15" and "15.0" are the same version but different strings).
|
|
214
|
+
_ios_ver_lt() {
|
|
215
|
+
awk -v a="$1" -v b="$2" 'BEGIN{exit !(a<b)}'
|
|
210
216
|
}
|
|
211
217
|
|
|
212
218
|
# ios_reconcile_deployment_target [project_dir]
|
|
213
|
-
# The core "self-healing" step
|
|
214
|
-
#
|
|
215
|
-
#
|
|
219
|
+
# The core "self-healing" step. Checks TWO independent things against the
|
|
220
|
+
# required version — the app's own pbxproj target, AND
|
|
221
|
+
# FlutterGeneratedPluginSwiftPackage's own declared platform — because the
|
|
222
|
+
# upstream bug is exactly that these two can desync from each other. A
|
|
223
|
+
# project whose pbxproj is already at (say) 15.6 can still have a generated
|
|
224
|
+
# package stuck at 13.0; checking only the pbxproj target (as an earlier
|
|
225
|
+
# version of this function did) misses that case entirely.
|
|
216
226
|
# Returns 0 if no action was needed or the fix succeeded; 1 if it couldn't
|
|
217
227
|
# reconcile and the caller should stop before attempting a build.
|
|
218
228
|
ios_reconcile_deployment_target() {
|
|
@@ -220,46 +230,53 @@ ios_reconcile_deployment_target() {
|
|
|
220
230
|
|
|
221
231
|
ios_project_uses_spm "$project_dir" || { log_debug "Project does not use SwiftPM; skipping deployment-target reconciliation."; return 0; }
|
|
222
232
|
|
|
223
|
-
local required
|
|
233
|
+
local required
|
|
224
234
|
required=$(ios_required_spm_deployment_target "$project_dir")
|
|
225
|
-
current=$(ios_deployment_target_for_config "Release" "$project_dir")
|
|
226
|
-
|
|
227
235
|
if [ -z "$required" ]; then
|
|
228
236
|
log_debug "Could not determine a required deployment target from resolved SPM plugins; skipping reconciliation."
|
|
229
237
|
return 0
|
|
230
238
|
fi
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
|
|
240
|
+
ios_known_issue_check
|
|
241
|
+
|
|
242
|
+
local current generated
|
|
243
|
+
current=$(ios_deployment_target_for_config "Release" "$project_dir")
|
|
244
|
+
generated=$(ios_generated_package_target "$project_dir")
|
|
245
|
+
|
|
246
|
+
local pbxproj_needs_bump=0 generated_needs_fix=0
|
|
247
|
+
[ -n "$current" ] && _ios_ver_lt "$current" "$required" && pbxproj_needs_bump=1
|
|
248
|
+
if [ -z "$generated" ] || _ios_ver_lt "$generated" "$required"; then
|
|
249
|
+
generated_needs_fix=1
|
|
250
|
+
fi
|
|
251
|
+
|
|
252
|
+
if [ "$pbxproj_needs_bump" = 0 ] && [ "$generated_needs_fix" = 0 ]; then
|
|
253
|
+
log_debug "Deployment target ($current) and generated package ($generated) already satisfy SwiftPM requirement ($required)."
|
|
233
254
|
return 0
|
|
234
255
|
fi
|
|
235
256
|
|
|
236
|
-
|
|
257
|
+
log_warn "Resolved SwiftPM plugins require iOS $required."
|
|
258
|
+
[ "$pbxproj_needs_bump" = 1 ] && echo " - project.pbxproj currently targets iOS $current"
|
|
259
|
+
[ "$generated_needs_fix" = 1 ] && echo " - FlutterGeneratedPluginSwiftPackage currently declares iOS ${generated:-unknown}"
|
|
260
|
+
echo "Plan:"
|
|
261
|
+
[ "$pbxproj_needs_bump" = 1 ] && echo " 1. Set IPHONEOS_DEPLOYMENT_TARGET = $required across every build configuration in project.pbxproj"
|
|
262
|
+
echo " 2. Clear ios/Flutter/ephemeral and re-run 'flutter pub get' to regenerate FlutterGeneratedPluginSwiftPackage"
|
|
263
|
+
echo " 3. Verify the regenerated package declares iOS $required; if it still doesn't (known upstream bug), patch it directly"
|
|
264
|
+
|
|
265
|
+
if ! confirm "Apply this fix?"; then
|
|
266
|
+
log_warn "Skipped. The build will likely fail SwiftPM resolution until this is reconciled manually."
|
|
267
|
+
return 1
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
[ "$pbxproj_needs_bump" = 1 ] && ios_pbxproj_patch_deployment_target "$required" "$project_dir"
|
|
271
|
+
ios_regenerate_generated_package "$project_dir"
|
|
237
272
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
echo " 2. Clear ios/Flutter/ephemeral and re-run 'flutter pub get' to regenerate FlutterGeneratedPluginSwiftPackage"
|
|
243
|
-
echo " 3. Verify the regenerated package declares iOS $required; if it still doesn't (known upstream bug), patch it directly"
|
|
244
|
-
|
|
245
|
-
if ! confirm "Apply this fix?"; then
|
|
246
|
-
log_warn "Skipped. The build will likely fail SwiftPM resolution until the deployment target is reconciled manually."
|
|
247
|
-
return 1
|
|
248
|
-
fi
|
|
249
|
-
|
|
250
|
-
ios_pbxproj_patch_deployment_target "$required" "$project_dir"
|
|
251
|
-
ios_regenerate_generated_package "$project_dir"
|
|
252
|
-
|
|
253
|
-
local regenerated
|
|
254
|
-
regenerated=$(ios_generated_package_target "$project_dir")
|
|
255
|
-
if [ "$regenerated" = "$required" ]; then
|
|
256
|
-
log_success "Generated package now correctly declares iOS $regenerated."
|
|
257
|
-
else
|
|
258
|
-
log_warn "Generated package declares '${regenerated:-unknown}' after regeneration, not $required."
|
|
259
|
-
ios_patch_generated_package_target "$required" "$project_dir"
|
|
260
|
-
fi
|
|
273
|
+
local regenerated
|
|
274
|
+
regenerated=$(ios_generated_package_target "$project_dir")
|
|
275
|
+
if [ -n "$regenerated" ] && ! _ios_ver_lt "$regenerated" "$required"; then
|
|
276
|
+
log_success "Generated package now correctly declares iOS $regenerated."
|
|
261
277
|
else
|
|
262
|
-
|
|
278
|
+
log_warn "Generated package declares '${regenerated:-unknown}' after regeneration, still below $required."
|
|
279
|
+
ios_patch_generated_package_target "$required" "$project_dir"
|
|
263
280
|
fi
|
|
264
281
|
|
|
265
282
|
return 0
|
package/lib/version.sh
CHANGED
package/lib-win/git.js
CHANGED
|
@@ -41,25 +41,45 @@ async function cmdCmt(commitMsg) {
|
|
|
41
41
|
die('Invalid choice. Operation aborted.');
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
const hasStaged = spawnSync('git', ['diff', '--cached', '--quiet']).status !== 0;
|
|
45
|
+
if (!hasStaged) {
|
|
46
|
+
logWarn("Nothing staged to commit — checking whether there's anything already committed to sync.");
|
|
47
|
+
} else {
|
|
48
|
+
logInfo('Committing changes...');
|
|
49
|
+
const commitResult = git(['commit', '-m', commitMsg]);
|
|
50
|
+
if (commitResult.status !== 0) {
|
|
51
|
+
die('Commit failed. Aborting before pull/push.');
|
|
52
|
+
}
|
|
48
53
|
}
|
|
49
54
|
|
|
50
55
|
const currentBranch = gitCapture(['branch', '--show-current']);
|
|
51
56
|
const remoteName = remoteExists('origin') ? 'origin' : gitCapture(['remote']).split(/\r?\n/)[0];
|
|
52
57
|
|
|
53
58
|
if (!remoteName) {
|
|
54
|
-
logWarn('
|
|
59
|
+
logWarn('No remote configured — sync was skipped.');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const aheadCount = gitCapture(['rev-list', '--count', `${remoteName}/${currentBranch}..${currentBranch}`]);
|
|
64
|
+
if (aheadCount === '0') {
|
|
65
|
+
logSuccess(`Already up to date with '${remoteName}/${currentBranch}' — nothing to push.`);
|
|
55
66
|
return;
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
logInfo(`Pulling updates from remote '${remoteName}' on '${currentBranch}' via rebase...`);
|
|
59
70
|
const pullResult = git(['pull', '--rebase', remoteName, currentBranch]);
|
|
60
71
|
if (pullResult.status !== 0) {
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
const gitDir = gitCapture(['rev-parse', '--git-dir']);
|
|
73
|
+
const path = require('node:path');
|
|
74
|
+
const fs = require('node:fs');
|
|
75
|
+
const inConflict = fs.existsSync(path.join(gitDir, 'rebase-merge')) || fs.existsSync(path.join(gitDir, 'rebase-apply'));
|
|
76
|
+
if (inConflict) {
|
|
77
|
+
logError('MERGE CONFLICT DETECTED!');
|
|
78
|
+
logWarn('Execution paused. Resolve conflicts to proceed.');
|
|
79
|
+
} else {
|
|
80
|
+
logError(`Could not sync with '${remoteName}' — this looks like a connection problem, not a merge conflict (see the git error above).`);
|
|
81
|
+
logWarn(`Your commit is safe locally. Re-run 'xgem git cmt' once connectivity is restored, or push manually: git push ${remoteName} ${currentBranch}`);
|
|
82
|
+
}
|
|
63
83
|
process.exit(1);
|
|
64
84
|
}
|
|
65
85
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xgem-cli",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.4",
|
|
4
4
|
"description": "Framework-aware automation CLI: scaffolds and runs clean/build/dev scripts per project type, an environment doctor, a SwiftPM-aware iOS build engine, and a git workflow helper. Runs natively on macOS, Linux, and Windows.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"xgem": "bin/xgem.js"
|