locateMaven function

Future<String> locateMaven({
  1. String? explicit,
  2. Map<String, String>? environment,
})

The mvn to run: explicit and nothing else when given; otherwise $MAVEN_HOME/$M2_HOME, the usual install locations, then the PATH. Throws MavenNotFound.

Implementation

Future<String> locateMaven({
  String? explicit,
  Map<String, String>? environment,
}) async {
  if (explicit != null && explicit.trim().isNotEmpty) {
    // Asked for one in particular: never quietly run another.
    if (File(explicit.trim()).existsSync()) return explicit.trim();
    throw MavenNotFound([explicit.trim()]);
  }

  final env = environment ?? Platform.environment;
  final executable = Platform.isWindows ? 'mvn.cmd' : 'mvn';
  final home = env['MAVEN_HOME'] ?? env['M2_HOME'];
  final candidates = [
    if (home != null && home.trim().isNotEmpty)
      joinPath([home.trim(), 'bin', executable]),
    if (!Platform.isWindows) ...[
      '/opt/homebrew/bin/mvn',
      '/usr/local/bin/mvn',
      '/usr/bin/mvn',
    ],
  ];
  for (final candidate in candidates) {
    if (File(candidate).existsSync()) return candidate;
  }

  try {
    // On Windows, `where mvn` lists Maven's extension-less shell script first;
    // the `.cmd` is the one that runs.
    final which = await Process.run(Platform.isWindows ? 'where' : 'which', [
      executable,
    ]);
    if (which.exitCode == 0) {
      final found = (which.stdout as String).trim().split('\n').first.trim();
      if (found.isNotEmpty && File(found).existsSync()) return found;
    }
  } on ProcessException {
    // No `which`.
  }
  throw MavenNotFound(candidates);
}