blob: ed1429463dbe1902611cfc1d1367bad299cd249b [file] [log] [blame]
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:io';
/// Calculates the amount of formatting changes in a given directory of code.
///
/// This should be run with a path to a directory. That directory should
/// contain a Git repo. The committed state of the repo should be the formatted
/// output before the change in question. Then the result of the new formatting
/// should be unstaged changes.
///
/// Uses `git diff --shortstat` to calculate the number of changed lines.
///
/// Counts the number of lines of Dart code by reading the files.
void main(List<String> arguments) {
if (arguments.length != 1) {
print('Usage: change_metrics.dart <dir>');
exit(1);
}
var directory = arguments[0];
var totalLines = 0;
var totalFiles = 0;
print('Counting lines...');
for (var entry in Directory(directory).listSync(recursive: true)) {
if (entry is File && entry.path.endsWith('.dart')) {
try {
var lines = entry.readAsLinesSync();
totalFiles++;
totalLines += lines.length;
} catch (error) {
print('Could not read ${entry.path}:\n$error');
}
}
}
print('Getting diff stats...');
var result = Process.runSync('git', ['diff', '--shortstat'],
// Make sure the user's local Git config doesn't affect the output.
environment: {
'GIT_CONFIG_NOGLOBAL': 'true',
'GIT_CONFIG_NOSYSTEM': 'true',
},
workingDirectory: directory);
if (result.exitCode != 0) {
print('Git failure:\n${result.stdout}\n${result.stderr}');
exit(1);
}
var stdout = result.stdout as String;
var insertions = _parseGitStdout(stdout, r'(\d+) insertions');
var deletions = _parseGitStdout(stdout, r'(\d+) deletions');
var changes = insertions + deletions;
print('$totalLines lines in $totalFiles files');
print('$insertions insertions + $deletions deletions = $changes changes');
var linesPerChange = totalLines / changes;
print('1 changed line for every ${linesPerChange.toStringAsFixed(2)} '
'lines of code');
var changesPerLine = 1000.0 * changes / totalLines;
print('${changesPerLine.toStringAsFixed(4)} '
'changed lines for every 1,000 lines of code');
}
int _parseGitStdout(String stdout, String pattern) {
var match = RegExp(pattern).firstMatch(stdout);
if (match == null) {
print('Could not parse Git output:\n$stdout');
exit(1);
}
return int.parse(match[1]!);
}