initializeSidekick function

SidekickCommandRunner initializeSidekick({
  1. @Deprecated('Not used anymore') String? name,
  2. String? description,
  3. String? mainProjectPath,
  4. String? flutterSdkPath,
  5. String? dartSdkPath,
})

Initializes sidekick, call this at the very start of your CLI program

All paths are resolved relative to the location of the SidekickContext.entryPoint, or absolute.

Set flutterSdkPath when you bind a Flutter SDK to this project. This SDK enables the flutter and dart commands. dartSdkPath is inherited from flutterSdkPath. Set it only for pure Dart projects. The paths can either be absolute or relative to the projectRoot (where the entryPoint is located). I.e. when the entrypoint is in /Users/foo/project-x/ set dartSdkPath = 'third_party/dart-sdk' to use the Dart SDK in /Users/foo/project-x/third_party/dart-sdk.

mainProjectPath should be set when you have a package that you consider the main package of the whole repository. When your repository contains only one Flutter package in projectRoot set mainProjectPath = '.'. In a multi package repository you might use the same when the main package is in projectRoot, or mainProjectPath = 'packages/my_app' when it is in a subfolder.

Implementation

SidekickCommandRunner initializeSidekick({
  @Deprecated('Not used anymore') String? name,
  String? description,
  String? mainProjectPath,
  String? flutterSdkPath,
  String? dartSdkPath,
}) {
  final repoRoot = SidekickContext.repository;
  final projectRoot = SidekickContext.projectRoot;

  /// Migrates a [path] relative to the [SidekickContext.repository] (as it
  /// was default before sidekick 1.0.0) to a path relative to the
  /// [SidekickContext.projectRoot]
  ///
  /// This usually works because the projectRoot is usually also the repository
  /// root.
  /// If the Directory is found in only one resolved location that one is used
  /// and warning to migrate to paths relative to the projectRoot is printed.
  /// If the Directory is found in both locations the one relative to the
  /// projectRoot is returned.
  Directory? resolveDirectoryBackwardsCompatible(
    String parameterName,
    String? path,
  ) {
    if (path == null) return null;
    final fromRepoRoot =
        repoRoot == null ? null : _resolveSdkPath(path, repoRoot);
    final fromProjectRoot = _resolveSdkPath(path, projectRoot);

    if (fromRepoRoot == null && fromProjectRoot == null) {
      throw "Could not find directory $parameterName at '$path'. The resolved path is: ${projectRoot.directory(path).path}";
    }

    if (fromProjectRoot != null && fromRepoRoot == fromProjectRoot) {
      if (fromProjectRoot.isAbsolute) {
        // identical absolute paths, all good
        return fromProjectRoot;
      }
    }

    if (fromProjectRoot != null && fromRepoRoot == null) {
      // path has been migrated, all good
      return fromProjectRoot;
    }

    if (fromRepoRoot != null && fromProjectRoot == null) {
      // Found deprecated path relative to repo root. This is fully working
      // when inside a git repo.
      // Show a warning to migrate the path so it will work when not in a git
      // repo
      final correctPath = relative(
        fromRepoRoot.path,
        from: SidekickContext.projectRoot.path,
      );
      printerr(
        red('$parameterName is defined relative to your git repository. '
            'Please migrate it to be relative to the ${SidekickContext.cliName} entryPoint at ${SidekickContext.projectRoot}.\n'),
      );
      printerr(
        "Please use the following path:\n"
        "final runner = initializeSidekick(\n"
        "  //...\n"
        "  $parameterName: '$correctPath'\n"
        ");",
      );
      return fromRepoRoot;
    }
    printerr('Found $parameterName at both: ${fromRepoRoot!.path} and '
        '${fromProjectRoot!.path}. Using the latter which is relative '
        'to the ${SidekickContext.cliName} entryPoint');
    return fromProjectRoot;
  }

  DartPackage? mainProject;
  Directory? flutterSdk;
  Directory? dartSdk;

  if (repoRoot == null) {
    // Not in a git repo. This is not a breaking change. Sidekick did not
    // support project without a git repo, before the migration
    if (mainProjectPath != null) {
      mainProject =
          DartPackage.fromDirectory(projectRoot.directory(mainProjectPath));
    }
    flutterSdk = _resolveSdkPath(flutterSdkPath, projectRoot);
    dartSdk = _resolveSdkPath(dartSdkPath, projectRoot);
  } else if (canonicalize(repoRoot.path) == canonicalize(projectRoot.path)) {
    // EntryPoint is in root of repository, we can safely migrate
    if (mainProjectPath != null) {
      mainProject =
          DartPackage.fromDirectory(projectRoot.directory(mainProjectPath));
    }
    flutterSdk = _resolveSdkPath(flutterSdkPath, projectRoot);
    dartSdk = _resolveSdkPath(dartSdkPath, projectRoot);
  } else {
    // Detected that repoRoot and projectRoot differ
    // This is where shit hits the fan. Users have to migrate their paths from
    // relative to repo-root to relative to project-root

    try {
      flutterSdk =
          resolveDirectoryBackwardsCompatible('flutterSdkPath', flutterSdkPath);
    } catch (e, stack) {
      throw SdkNotFoundException(
        flutterSdkPath!,
        repoRoot,
        cause: e,
        causeStackTrace: stack,
      );
    }
    try {
      dartSdk = resolveDirectoryBackwardsCompatible('dartSdkPath', dartSdkPath);
    } catch (e, stack) {
      throw SdkNotFoundException(
        dartSdkPath!,
        repoRoot,
        cause: e,
        causeStackTrace: stack,
      );
    }

    final mainProjectDir =
        resolveDirectoryBackwardsCompatible('mainProjectPath', mainProjectPath);
    if (mainProjectDir != null) {
      mainProject = DartPackage.fromDirectory(mainProjectDir);
    }
  }

  if (flutterSdkPath != null && dartSdkPath != null) {
    printerr("It's unnecessary to set both `flutterSdkPath` and `dartSdkPath`, "
        "because `dartSdkPath` is inherited from `flutterSdkPath. "
        "Set `dartSdkPath` only for pure dart projects.");
  }

  if (flutterSdkPath != null && flutterSdk?.existsSync() != true) {
    throw SdkNotFoundException(flutterSdkPath, projectRoot);
  }
  if (dartSdkPath != null && dartSdk?.existsSync() != true) {
    throw SdkNotFoundException(dartSdkPath, projectRoot);
  }
  if (mainProjectPath != null && mainProject?.root.existsSync() != true) {
    throw "mainProjectPath $mainProjectPath couldn't be resolved";
  }

  final runner = SidekickCommandRunner._(
    description: description ??
        'A sidekick CLI to equip Dart/Flutter projects with custom tasks',
    mainProject: mainProject,
    flutterSdk: flutterSdk,
    dartSdk: dartSdk,
  );
  return runner;
}