handleUpdateRuns function
Handle oracular update runs [--port NNNN] [--output-dir <path>].
Adds (or refreshes) IntelliJ / Android Studio run configurations for an Oracular project, in two flavors:
-
Deploy Allat the project root —oracular deploy all. Always emitted (template-agnostic). Lives in<output-dir>/.idea/runConfigurations/Deploy_All.run.xml. -
Serve/Build/Killall :PORTfor every Jaspr web package found underoutput-dir. Lives in<package>/.idea/runConfigurations/. Skipped if no Jaspr packages are detected.
Why this command exists: a project scaffolded by Oracular < 3.4.0
won't have these configs, and the wizard's full rebuild
(oracular rebuild) is too heavy-handed when the user only wants
the IDE wiring back. This command is the fast, surgical update.
Detection strategy for Jaspr packages (in order):
- Load
<output-dir>/config/setup_config.envif it exists. If the saved template is a Jaspr template, use SetupConfig.webPackageName as the canonical target — even if other Jaspr-like packages coexist in the tree. - Otherwise (no setup_config.env, or non-Jaspr template), scan
output-dirone level deep for any folder whosepubspec.yamldeclares ajaspr:dependency. Each matching folder becomes a target. - As a last resort, if
output-diritself is a Jaspr package, treat it as the single target.
All configs are idempotent on re-run.
Implementation
Future<void> handleUpdateRuns(Map<String, dynamic> args) async {
// darted_cli has an internal bug: it strips hyphens from arg names
// when parsing input, but then re-builds `--<name>` to match against
// the original input — dropping any arg whose name contains a hyphen.
// Workaround: name our flags without hyphens (`dir` instead of
// `output-dir`) and accept multiple aliases below for robustness.
final String? rawDir = (args['dir'] as String?) ??
(args['d'] as String?) ??
(args['output-dir'] as String?) ??
(args['outputdir'] as String?);
final String outputDir = (rawDir != null && rawDir.trim().isNotEmpty)
? rawDir.trim()
: Directory.current.path;
final int port = _parsePort(args['port'] ?? args['p']);
print('');
UserPrompt.printDivider(title: 'Update IntelliJ run configurations');
// ── Step 1: project-root "Deploy All" config ──────────────────────────
//
// Template-agnostic — emit unconditionally for any directory the user
// points us at. Even if the dir isn't an Oracular project, the user
// may want a `oracular deploy all` button (e.g., they're about to run
// `oracular create`).
int deployWrittenCount = 0;
try {
final List<String> deployWritten =
await IntellijRunConfigGenerator.generateDeploy(
projectDir: outputDir,
);
deployWrittenCount = deployWritten.length;
if (deployWritten.isNotEmpty) {
info(
' ./ + ${p.basename(deployWritten.first)} '
'(oracular deploy all)',
);
}
} catch (e) {
warn('Failed to write project-level Deploy All config: $e');
}
// ── Step 2: per-Jaspr-package Serve / Build / Killall configs ─────────
final List<_JasprTarget> targets = await _resolveTargets(outputDir);
if (targets.isEmpty) {
if (deployWrittenCount == 0) {
// Neither Deploy nor Jaspr configs were emitted — nothing to do.
// This is genuinely unexpected because the Deploy generator is
// unconditional, so log a hint rather than a hard failure.
error(
'No run configs emitted for $outputDir.',
);
return;
}
print('');
success(
'Wrote project-level "Deploy All" run config '
'(no Jaspr packages found — Serve/Build/Killall skipped).',
);
print('');
UserPrompt.printList(<String>[
'Open the project in IntelliJ / Android Studio.',
'You should see "Deploy All" in the run configurations dropdown',
'(top-right corner). Click ▶ to run `oracular deploy all`.',
]);
return;
}
info(
'Found ${targets.length} Jaspr package'
'${targets.length == 1 ? '' : 's'} — writing Serve/Build/Killall '
'configs (port: $port)...',
);
int totalWritten = 0;
int totalPruned = 0;
for (final _JasprTarget target in targets) {
info(' ${target.relativePath}/');
final List<String> deleted =
await IntellijRunConfigGenerator.pruneStaleKillallConfigs(
packageDir: target.absolutePath,
currentPort: port,
);
if (deleted.isNotEmpty) {
verbose(
' Pruned ${deleted.length} stale Killall config(s) for '
'previous port(s).',
);
totalPruned += deleted.length;
}
final List<String> written = await IntellijRunConfigGenerator.generate(
packageDir: target.absolutePath,
port: port,
);
for (final String f in written) {
verbose(' + ${p.basename(f)}');
}
totalWritten += written.length;
}
print('');
success(
'Updated ${totalWritten + deployWrittenCount} run config'
'${(totalWritten + deployWrittenCount) == 1 ? '' : 's'} '
'($deployWrittenCount project-level Deploy + $totalWritten Jaspr '
'across ${targets.length} package'
'${targets.length == 1 ? '' : 's'})'
'${totalPruned > 0 ? ' (pruned $totalPruned stale)' : ''}.',
);
print('');
UserPrompt.printList(<String>[
'Open the project in IntelliJ / Android Studio.',
'You should see "Deploy All" plus "Serve", "Build", and ',
'"Killall :$port" in the run configurations dropdown (top-right).',
'Re-run with --port NNNN to change the Jaspr port; the killall',
'config will auto-prune the previous port file.',
]);
}