resolveClassPath function

ResolvedClassPath resolveClassPath(
  1. JavaRuntimeSpec spec, {
  2. List<String>? explicit,
  3. String? cacheDirOverride,
  4. Map<String, String>? environment,
  5. String? projectDir,
})

Finds spec's class path.

In order, the first that gives one wins:

  1. explicit, when not empty;
  2. JavaRuntimeSpec.classPathEnv — a separated list, or a file with one entry per line;
  3. the runtime directory under cacheDirOverride, or under the cache base (JavaRuntimeSpec.cacheBaseDir);
  4. without an override: also the operating system's default cache, when JavaRuntimeSpec.cacheDirEnv pointed somewhere else, and the project's .dart_tool/ (JavaRuntimeSpec.devRuntimeDir).

A runtime directory counts only when its manifest.json names this JavaRuntimeSpec.runtimeId (or it has none), does not record a failed verification, and every entry of its classpath.txt exists: a half-provisioned or rejected cache has to fail here, not with a NoClassDefFoundError later. An explicit or environment class path with a missing entry fails too. Every entry comes back absolute; relative ones are taken against the current directory, the runtime directory, or the list file they are in.

Throws JavaRuntimeNotProvisioned — with the setup command and every place searched — when nothing is found.

Implementation

ResolvedClassPath resolveClassPath(
  JavaRuntimeSpec spec, {
  List<String>? explicit,
  String? cacheDirOverride,
  Map<String, String>? environment,
  String? projectDir,
}) {
  final env = environment ?? Platform.environment;
  final searched = <String>[];

  if (explicit != null && explicit.isNotEmpty) {
    return ResolvedClassPath(
      entries: _existing(
        spec,
        _entriesOf(explicit, relativeTo: Directory.current.path),
        'the explicit class path',
      ),
      source: ClassPathSource.explicit,
    );
  }

  final fromEnv = spec.classPathEnv == null ? null : env[spec.classPathEnv];
  if (fromEnv != null && fromEnv.trim().isNotEmpty) {
    searched.add('\$${spec.classPathEnv}=${fromEnv.trim()}');
    final entries = _parseClassPathValue(fromEnv.trim());
    if (entries.isNotEmpty) {
      return ResolvedClassPath(
        entries: _existing(spec, entries, '\$${spec.classPathEnv}'),
        source: ClassPathSource.environment,
      );
    }
  }

  final dev = spec.devRuntimeDir(projectDir: projectDir);
  final candidates = <(Directory, ClassPathSource)>[
    (
      spec.runtimeDir(override: cacheDirOverride, environment: env),
      ClassPathSource.cache,
    ),
    if (cacheDirOverride == null) ...[
      if (spec.cacheDirEnv != null && env[spec.cacheDirEnv] != null)
        (
          Directory(
            joinPath([
              spec.defaultCacheBasePath(environment: env),
              spec.runtimeId,
            ]),
          ),
          ClassPathSource.cache,
        ),
      if (dev != null) (dev, ClassPathSource.dev),
    ],
  ];

  for (final (dir, source) in candidates) {
    searched.add(dir.path);
    final entries = readRuntimeClassPath(spec, dir);
    if (entries != null && entries.isNotEmpty) {
      return ResolvedClassPath(
        entries: entries,
        source: source,
        runtimeDir: dir,
      );
    }
  }

  throw JavaRuntimeNotProvisioned(
    'no class path found for ${spec.name} runtime ${spec.runtimeId}',
    command: spec.setupCommand,
    searched: searched,
  );
}