@@ -278,27 +278,62 @@ See $workspacesDocUrl for more information.
278
278
return p.join (root, path);
279
279
}
280
280
281
- return Ignore .listFiles (
281
+ /// Throws if [path] is a link that cannot resolve.
282
+ ///
283
+ /// Circular links will fail to resolve at some depth defined by the os.
284
+ void verifyLink (String path) {
285
+ final link = Link (path);
286
+ if (link.existsSync ()) {
287
+ try {
288
+ link.resolveSymbolicLinksSync ();
289
+ } on FileSystemException catch (e) {
290
+ if (! link.existsSync ()) {
291
+ return ;
292
+ }
293
+ throw DataException (
294
+ 'Could not resolve symbolic link $path . $e ' ,
295
+ );
296
+ }
297
+ }
298
+ }
299
+
300
+ /// We check each directory that it doesn't symlink-resolve to the
301
+ /// symlink-resolution of any parent directory of itself. This avoids
302
+ /// cycles.
303
+ ///
304
+ /// Cache the symlink resolutions here.
305
+ final symlinkResolvedDirs = < String , String > {};
306
+ String resolveDirSymlinks (String path) {
307
+ return symlinkResolvedDirs[path] ?? =
308
+ Directory (path).resolveSymbolicLinksSync ();
309
+ }
310
+
311
+ final result = Ignore .listFiles (
282
312
beneath: beneath,
283
313
listDir: (dir) {
284
- var contents = Directory (resolve (dir)).listSync ();
314
+ final resolvedDir = p.normalize (resolve (dir));
315
+ verifyLink (resolvedDir);
316
+
317
+ {
318
+ final canonicalized = p.canonicalize (resolvedDir);
319
+ final symlinkResolvedDir = resolveDirSymlinks (canonicalized);
320
+ for (final parent in parentDirs (p.dirname (canonicalized))) {
321
+ final symlinkResolvedParent = resolveDirSymlinks (parent);
322
+ if (p.equals (symlinkResolvedDir, symlinkResolvedParent)) {
323
+ dataError ('''
324
+ Pub does not support symlink cycles.
325
+
326
+ $symlinkResolvedDir => ${p .canonicalize (symlinkResolvedParent )}
327
+ ''' );
328
+ }
329
+ }
330
+ }
331
+ var contents = Directory (resolvedDir).listSync (followLinks: false );
332
+
285
333
if (! recursive) {
286
334
contents = contents.where ((entity) => entity is ! Directory ).toList ();
287
335
}
288
336
return contents.map ((entity) {
289
- if (linkExists (entity.path)) {
290
- final target = Link (entity.path).targetSync ();
291
- if (dirExists (entity.path)) {
292
- throw DataException (
293
- '''Pub does not support publishing packages with directory symlinks: `${entity .path }`.''' ,
294
- );
295
- }
296
- if (! fileExists (entity.path)) {
297
- throw DataException (
298
- '''Pub does not support publishing packages with non-resolving symlink: `${entity .path }` => `$target `.''' ,
299
- );
300
- }
301
- }
302
337
final relative = p.relative (entity.path, from: root);
303
338
if (Platform .isWindows) {
304
339
return p.posix.joinAll (p.split (relative));
@@ -367,6 +402,10 @@ See $workspacesDocUrl for more information.
367
402
isDir: (dir) => dirExists (resolve (dir)),
368
403
includeDirs: includeDirs,
369
404
).map (resolve).toList ();
405
+ for (final f in result) {
406
+ verifyLink (f);
407
+ }
408
+ return result;
370
409
}
371
410
372
411
/// Applies [transform] to each package in the workspace and returns a derived
0 commit comments