<commit_before>import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:git/git.dart';
import 'package:io/ansi.dart' as ansi;
import 'package:path/path.dart' as p;

import 'build_runner.dart';
import 'helpers.dart';
import 'options.dart';
import 'peanut_exception.dart';
import 'utils.dart';
import 'version.dart';
import 'webdev.dart';

export 'options.dart';
export 'utils.dart' show printError;
export 'webdev.dart' show PackageException;

Future<void> run({Options options, String workingDir}) async {
  options ??= const Options();
  workingDir ??= p.current;

  final isGitDir = await GitDir.isGitDir(workingDir);

  if (!isGitDir) {
    throw PeanutException('Not a git directory: $workingDir');
  }

  final gitDir = await GitDir.fromExisting(workingDir, allowSubdirectory: true);

  // current branch cannot be targetBranch
  final currentBranch = await gitDir.getCurrentBranch();

  if (currentBranch.branchName == options.branch) {
    throw PeanutException(
        'Cannot update the current branch "${options.branch}".');
  }

  if (options.directories.isEmpty) {
    throw PeanutException('At least one directory must be provided.');
  }

  // key: package dir; value: all dirs to build within that package
  final targetDirs = targetDirectories(workingDir, options.directories);

  for (var dir in options.directories) {
    final fullPath = pkgNormalize(workingDir, dir);

    if (p.equals(workingDir, dir)) {
      throw PeanutException(
          '"$dir" is the same as the working directory, which is not allowed.');
    }

    if (!p.isWithin(workingDir, fullPath)) {
      throw PeanutException(
          '"$dir" is not in the working directory "$workingDir".');
    }
  }

  for (var entry in targetDirs.entries) {
    final entryDir = pkgNormalize(workingDir, entry.key);
    try {
      await checkPubspecLock(entryDir);
    } on FileSystemException catch (e) {
      throw PeanutException('${e.message} ${e.path}');
    }

    for (var dir in entry.value) {
      final buildDirPath = p.join(entryDir, dir);
      if (FileSystemEntity.typeSync(buildDirPath) ==
          FileSystemEntityType.notFound) {
        stderr.writeln(
          ansi.yellow.wrap(
            'The `$buildDirPath` directory does not exist. This may cause the '
            'build to fail. Try setting the `directory` flag.',
          ),
        );
      }
    }
  }

  final secondsSinceEpoch = DateTime.now().toUtc().millisecondsSinceEpoch;

  var message = options.message;

  if (message == defaultMessage) {
    message = 'Built ${options.directories.join(', ')}';
    if (options.directories.length > 1 && message.length > 72) {
      message = '''
Built ${options.directories.length} directories

Directories:
  ${options.directories.join('\n  ')}
''';
    }
  }

  final outputDirMap = outputDirectoryMap(targetDirs);

  // create a temp dir to dump 'pub build' output to
  final tempDir =
      await Directory.systemTemp.createTemp('peanut.$secondsSinceEpoch.');

  try {
    for (var sourcePkg in targetDirs.entries) {
      final targets = Map<String, String>.fromEntries(outputDirMap.entries
          .where((e) => p.isWithin(sourcePkg.key, e.key))
          .map((e) => MapEntry(
              p.split(e.key).last, pkgNormalize(tempDir.path, e.value))));

      final pkgPath = sourcePkg.key == '.' ? workingDir : sourcePkg.key;

      print('');
      print(ansi.styleBold.wrap('''
Package:     $pkgPath
Directories: ${sourcePkg.value.join(', ')}'''));

      await runBuildRunner(<commit_msg>Print (x of y) count details where there is more than one package<commit_after>import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:git/git.dart';
import 'package:io/ansi.dart' as ansi;
import 'package:path/path.dart' as p;

import 'build_runner.dart';
import 'helpers.dart';
import 'options.dart';
import 'peanut_exception.dart';
import 'utils.dart';
import 'version.dart';
import 'webdev.dart';

export 'options.dart';
export 'utils.dart' show printError;
export 'webdev.dart' show PackageException;

Future<void> run({Options options, String workingDir}) async {
  options ??= const Options();
  workingDir ??= p.current;

  final isGitDir = await GitDir.isGitDir(workingDir);

  if (!isGitDir) {
    throw PeanutException('Not a git directory: $workingDir');
  }

  final gitDir = await GitDir.fromExisting(workingDir, allowSubdirectory: true);

  // current branch cannot be targetBranch
  final currentBranch = await gitDir.getCurrentBranch();

  if (currentBranch.branchName == options.branch) {
    throw PeanutException(
        'Cannot update the current branch "${options.branch}".');
  }

  if (options.directories.isEmpty) {
    throw PeanutException('At least one directory must be provided.');
  }

  // key: package dir; value: all dirs to build within that package
  final targetDirs = targetDirectories(workingDir, options.directories);

  for (var dir in options.directories) {
    final fullPath = pkgNormalize(workingDir, dir);

    if (p.equals(workingDir, dir)) {
      throw PeanutException(
          '"$dir" is the same as the working directory, which is not allowed.');
    }

    if (!p.isWithin(workingDir, fullPath)) {
      throw PeanutException(
          '"$dir" is not in the working directory "$workingDir".');
    }
  }

  for (var entry in targetDirs.entries) {
    final entryDir = pkgNormalize(workingDir, entry.key);
    try {
      await checkPubspecLock(entryDir);
    } on FileSystemException catch (e) {
      throw PeanutException('${e.message} ${e.path}');
    }

    for (var dir in entry.value) {
      final buildDirPath = p.join(entryDir, dir);
      if (FileSystemEntity.typeSync(buildDirPath) ==
          FileSystemEntityType.notFound) {
        stderr.writeln(
          ansi.yellow.wrap(
            'The `$buildDirPath` directory does not exist. This may cause the '
            'build to fail. Try setting the `directory` flag.',
          ),
        );
      }
    }
  }

  final secondsSinceEpoch = DateTime.now().toUtc().millisecondsSinceEpoch;

  var message = options.message;

  if (message == defaultMessage) {
    message = 'Built ${options.directories.join(', ')}';
    if (options.directories.length > 1 && message.length > 72) {
      message = '''
Built ${options.directories.length} directories

Directories:
  ${options.directories.join('\n  ')}
''';
    }
  }

  final outputDirMap = outputDirectoryMap(targetDirs);

  // create a temp dir to dump 'pub build' output to
  final tempDir =
      await Directory.systemTemp.createTemp('peanut.$secondsSinceEpoch.');

  try {
    final entriesList = targetDirs.entries.toList(growable: false);
    for (var i = 0; i < entriesList.length; i++) {
      final sourcePkg = entriesList[i];
      final targets = Map<String, String>.fromEntries(outputDirMap.entries
          .where((e) => p.isWithin(sourcePkg.key, e.key))
          .map((e) => MapEntry(
              p.split(e.key).last, pkgNormalize(tempDir.path, e.value))));

      final pkgPath = sourcePkg.key == '.' ? workingDir : sourcePkg.key;

      final countDetails =
          targetDirs.length == 1 ? '' : ' (${i + 1} of ${entriesList.length})';

      print('');
      print(ansi.styleBold.wrap('''
Package:     $pkgPath$countDetails
Directories: ${sourcePkg.value.join(', ')}'''));

      await runBuildRunner(
{'fraction_non_alphanumeric': 0.1326530612244898, 'fraction_numerical': 0.0012244897959183673, 'mean_word_length': 3.360023724792408, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4641612', 'n_tokens_mistral': 2328, 'n_tokens_neox': 2262, 'n_words': 582}