Purge invalid git repositories from cache before cloning (#2159)
* Purge invalid git repository from cache before cloning.
* Test cases for invalid git repositories
diff --git a/lib/src/source/git.dart b/lib/src/source/git.dart
index 6a7234c..60225b3 100644
--- a/lib/src/source/git.dart
+++ b/lib/src/source/git.dart
@@ -380,6 +380,8 @@
var path = _repoCachePath(ref);
if (_updatedRepos.contains(path)) return;
+ _cleanInvalidGitRepoCache(path);
+
if (!entryExists(path)) await _createRepoCache(ref);
// Try to list the revision. If it doesn't exist, git will fail and we'll
@@ -397,6 +399,8 @@
var path = _repoCachePath(ref);
if (_updatedRepos.contains(path)) return;
+ _cleanInvalidGitRepoCache(path);
+
if (!entryExists(path)) {
await _createRepoCache(ref);
} else {
@@ -411,7 +415,12 @@
var path = _repoCachePath(ref);
assert(!_updatedRepos.contains(path));
- await _clone(ref.description['url'], path, mirror: true);
+ try {
+ await _clone(ref.description['url'], path, mirror: true);
+ } catch (_) {
+ _cleanInvalidGitRepoCache(path);
+ rethrow;
+ }
_updatedRepos.add(path);
}
@@ -426,6 +435,19 @@
_updatedRepos.add(path);
}
+ /// Clean-up [dirPath] if it's an invalid git repository
+ void _cleanInvalidGitRepoCache(String dirPath) {
+ if (dirExists(dirPath)) {
+ var processResult = runProcessSync(
+ git.command, ['rev-parse', '--is-inside-git-dir'],
+ workingDir: dirPath);
+ var result = processResult.stdout?.join('\n');
+ if (processResult.exitCode != 0 || result != 'true') {
+ deleteEntry(dirPath);
+ }
+ }
+ }
+
/// Updates the package list file in [revisionCachePath] to include [path], if
/// necessary.
void _updatePackageList(String revisionCachePath, String path) {
diff --git a/test/get/git/clean_invalid_git_repo_cache_test.dart b/test/get/git/clean_invalid_git_repo_cache_test.dart
new file mode 100644
index 0000000..e7ff16b
--- /dev/null
+++ b/test/get/git/clean_invalid_git_repo_cache_test.dart
@@ -0,0 +1,108 @@
+// Copyright (c) 2012, 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';
+
+import 'package:path/path.dart' as path;
+import 'package:test/test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+/// Invalidates a git clone in the pub-cache, by recreating it as empty-directory.
+void _invalidateGitCache(String repo) {
+ final cacheDir =
+ path.join(d.sandbox, path.joinAll([cachePath, 'git', 'cache']));
+ final Directory fooCacheDir =
+ Directory(cacheDir).listSync().firstWhere((entity) {
+ if (entity is Directory &&
+ entity.path.split(Platform.pathSeparator).last.startsWith(repo))
+ return true;
+ return false;
+ });
+
+ fooCacheDir.deleteSync(recursive: true);
+ fooCacheDir.createSync();
+}
+
+main() {
+ test('Clean-up invalid git repo cache', () async {
+ ensureGit();
+
+ await d.git(
+ 'foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]).create();
+
+ await d.appDir({
+ "foo": {"git": "../foo.git"}
+ }).create();
+
+ await pubGet();
+
+ await d.dir(cachePath, [
+ d.dir('git', [
+ d.dir('cache', [d.gitPackageRepoCacheDir('foo')]),
+ d.gitPackageRevisionCacheDir('foo')
+ ])
+ ]).validate();
+
+ _invalidateGitCache('foo');
+
+ await pubGet();
+ });
+
+ test('Clean-up invalid git repo cache at a specific branch', () async {
+ ensureGit();
+
+ var repo =
+ d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]);
+ await repo.create();
+ await repo.runGit(["branch", "old"]);
+
+ await d.appDir({
+ "foo": {
+ "git": {"url": "../foo.git", "ref": "old"}
+ }
+ }).create();
+
+ await pubGet();
+
+ await d.dir(cachePath, [
+ d.dir('git', [
+ d.dir('cache', [d.gitPackageRepoCacheDir('foo')]),
+ d.gitPackageRevisionCacheDir('foo')
+ ])
+ ]).validate();
+
+ _invalidateGitCache('foo');
+
+ await pubGet();
+ });
+
+ test('Clean-up invalid git repo cache at a specific commit', () async {
+ ensureGit();
+
+ var repo =
+ d.git('foo.git', [d.libDir('foo'), d.libPubspec('foo', '1.0.0')]);
+ await repo.create();
+ var commit = await repo.revParse('HEAD');
+
+ await d.appDir({
+ "foo": {
+ "git": {"url": "../foo.git", "ref": commit}
+ }
+ }).create();
+
+ await pubGet();
+
+ await d.dir(cachePath, [
+ d.dir('git', [
+ d.dir('cache', [d.gitPackageRepoCacheDir('foo')]),
+ d.gitPackageRevisionCacheDir('foo')
+ ])
+ ]).validate();
+
+ _invalidateGitCache('foo');
+
+ await pubGet();
+ });
+}