Resolve symlinks when publishing from Git repos.
"git ls-files" doesn't natively resolve symlinks, so this adds some
logic to do so manually. This brings the behavior of uploading from a
Git repo in line with non-Git uploading.
We still don't have a multipart parser in Dart, so we unfortunately have
to way of writing automated tests that the tarballs are created as
expected. I did verify this behavior locally, though.
Closes #1400
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//1862833002 .
diff --git a/lib/src/package.dart b/lib/src/package.dart
index 2ba4c3e..e82f4da 100644
--- a/lib/src/package.dart
+++ b/lib/src/package.dart
@@ -252,9 +252,14 @@
files = files.map((file) {
if (Platform.operatingSystem != 'windows') return "$dir/$file";
return "$dir\\${file.replaceAll("/", "\\")}";
- }).where((file) {
- // Filter out broken symlinks, since git doesn't do so automatically.
- return fileExists(file);
+ }).expand((file) {
+ if (fileExists(file)) return [file];
+ if (!dirExists(file)) return [];
+
+ // `git ls-files` only returns files, except in the case of a symlink to
+ // a directory. So if we're here, [file] refers to a valid symlink to a
+ // directory.
+ return recursive ? _listSymlinkedDir(file) : [file];
});
} else {
files = listDir(beneath, recursive: recursive, includeDirs: false,
@@ -279,6 +284,38 @@
}).toList();
}
+ /// List all files recursively beneath [link], which should be a symlink to a
+ /// directory.
+ ///
+ /// This is used by [list] when listing a Git repository, since `git ls-files`
+ /// can't natively follow symlinks.
+ Iterable<String> _listSymlinkedDir(String link) {
+ assert(linkExists(link));
+ assert(dirExists(link));
+ assert(p.isWithin(dir, link));
+
+ var target = new Directory(link).resolveSymbolicLinksSync();
+
+ List<String> targetFiles;
+ if (p.isWithin(dir, target)) {
+ // If the link points within this repo, use git to list the target
+ // location so we respect .gitignore.
+ targetFiles = listFiles(
+ beneath: p.relative(target, from: dir),
+ recursive: true,
+ useGitIgnore: true);
+ } else {
+ // If the link points outside this repo, just use the default listing
+ // logic.
+ targetFiles = listDir(target, recursive: true, includeDirs: false,
+ whitelist: _WHITELISTED_FILES);
+ }
+
+ // Re-write the paths so they're underneath the symlink.
+ return targetFiles.map((targetFile) =>
+ p.join(link, p.relative(targetFile, from: target)));
+ }
+
/// Returns a debug string for the package.
String toString() => '$name $version ($dir)';
}