@@ -11,8 +11,8 @@ import 'package:pub/src/system_cache.dart';
1111import 'package:test/test.dart' ;
1212
1313import 'descriptor.dart' as d;
14+ import 'link_descriptor.dart' ;
1415import 'test_pub.dart' ;
15- import 'validator/utils.dart' ;
1616
1717late String root;
1818Entrypoint ? entrypoint;
@@ -58,12 +58,9 @@ void main() {
5858 d.file ('file2.txt' , 'contents' ),
5959 d.dir ('subdir' , [
6060 d.dir ('a' , [d.file ('file' )]),
61+ link ('symlink' , 'a' , forceDirectory: true ),
6162 ]),
6263 ]).create ();
63- createDirectorySymlink (
64- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
65- 'a' ,
66- );
6764
6865 createEntrypoint ();
6966
@@ -84,12 +81,9 @@ void main() {
8481 d.dir ('subdir' , [
8582 d.file ('.pubignore' , 'symlink' ),
8683 d.dir ('a' , [d.file ('file' )]),
84+ link ('symlink' , 'a' , forceDirectory: true ),
8785 ]),
8886 ]).create ();
89- createDirectorySymlink (
90- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
91- 'a' ,
92- );
9387
9488 createEntrypoint ();
9589
@@ -109,12 +103,9 @@ void main() {
109103 d.dir ('subdir' , [
110104 d.file ('.pubignore' , 'symlink' ),
111105 d.dir ('a' , [d.file ('file' )]),
106+ link ('symlink' , 'b' , forceDirectory: true ),
112107 ]),
113108 ]).create ();
114- createDirectorySymlink (
115- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
116- 'b' ,
117- );
118109
119110 createEntrypoint ();
120111
@@ -134,12 +125,9 @@ void main() {
134125 d.file ('file2.txt' , 'contents' ),
135126 d.dir ('subdir' , [
136127 d.dir ('a' , [d.file ('file' )]),
128+ link ('symlink' , '..' , forceDirectory: true ),
137129 ]),
138130 ]).create ();
139- createDirectorySymlink (
140- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
141- '..' ,
142- );
143131
144132 createEntrypoint ();
145133
@@ -164,12 +152,9 @@ void main() {
164152 d.file ('file2.txt' , 'contents' ),
165153 d.dir ('subdir' , [
166154 d.dir ('a' , [d.file ('file' )]),
155+ link ('symlink' , 'symlink' , forceDirectory: true ),
167156 ]),
168157 ]).create ();
169- createDirectorySymlink (
170- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
171- 'symlink' ,
172- );
173158
174159 createEntrypoint ();
175160
@@ -191,29 +176,94 @@ void main() {
191176 d.file ('file1.txt' , 'contents' ),
192177 d.file ('file2.txt' , 'contents' ),
193178 d.dir ('subdir' , [
194- d.dir ('a' , [d.file ('file' )]),
195- d.dir ('b' ),
196- d.dir ('c' ),
179+ d.dir ('a' , [
180+ d.file ('file' ),
181+ link ('symlink1' , p.join ('..' , 'b' ), forceDirectory: true ),
182+ ]),
183+ d.dir ('b' , [
184+ link ('symlink2' , p.join ('..' , 'c' ), forceDirectory: true ),
185+ ]),
186+ d.dir ('c' , [
187+ link ('symlink3' , p.join ('..' , 'a' ), forceDirectory: true ),
188+ ]),
189+ link ('symlink' , 'a' , forceDirectory: true ),
197190 ]),
198191 ]).create ();
199- createDirectorySymlink (
200- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
201- 'a' ,
202- );
203- createDirectorySymlink (
204- p.join (d.sandbox, appPath, 'subdir' , 'a' , 'symlink1' ),
205- p.join ('..' , 'b' ),
192+
193+ createEntrypoint ();
194+
195+ expect (
196+ () => entrypoint! .workspaceRoot.listFiles (),
197+ throwsA (
198+ isA <DataException >().having (
199+ (e) => e.message,
200+ 'message' ,
201+ contains ('Pub does not support symlink cycles.' ),
202+ ),
203+ ),
206204 );
207- createDirectorySymlink (
208- p.join (d.sandbox, appPath, 'subdir' , 'b' , 'symlink2' ),
209- p.join ('..' , 'c' ),
205+ });
206+
207+ test ('throws on link to loop' , () async {
208+ await d.dir (appPath, [
209+ d.pubspec ({'name' : 'myapp' }),
210+ link ('symlink' , p.join (d.sandbox, 'loop' ), forceDirectory: true ),
211+ ]).create ();
212+ await link ('loop' , 'loop' , forceDirectory: true ).create ();
213+
214+ createEntrypoint ();
215+
216+ expect (
217+ () => entrypoint! .workspaceRoot.listFiles (),
218+ throwsA (
219+ isA <DataException >().having (
220+ (e) => e.message,
221+ 'message' ,
222+ contains ('Could not resolve symbolic link' ),
223+ ),
224+ ),
210225 );
211- createDirectorySymlink (
212- p.join (d.sandbox, appPath, 'subdir' , 'c' , 'symlink3' ),
213- p.join ('..' , 'a' ),
226+ });
227+
228+ test ('throws on link to loop back to parent directory' , () async {
229+ await d.dir ('src' , [
230+ d.dir (appPath, [
231+ d.pubspec ({'name' : 'myapp' }),
232+ link ('symlink' , p.join (d.sandbox, 'source' ), forceDirectory: true ),
233+ ]),
234+ ]).create ();
235+ await link ('source' , p.join (d.sandbox, 'src' ), forceDirectory: true )
236+ .create ();
237+
238+ createEntrypoint (p.join ('src' , appPath));
239+
240+ expect (
241+ () => entrypoint! .workspaceRoot.listFiles (),
242+ throwsA (
243+ isA <DataException >().having (
244+ (e) => e.message,
245+ 'message' ,
246+ contains ('Pub does not support symlink cycles.' ),
247+ ),
248+ ),
214249 );
250+ });
215251
216- createEntrypoint ();
252+ test ('throws on link to subdirectory of loop back to parent directory' ,
253+ () async {
254+ await d.dir ('src' , [
255+ d.dir (appPath, [
256+ d.pubspec ({'name' : 'myapp' }),
257+ link ('symlink' , p.join (d.sandbox, 'source' ), forceDirectory: true ),
258+ ]),
259+ ]).create ();
260+ await link (
261+ 'source' ,
262+ p.join (d.sandbox, 'src' ),
263+ forceDirectory: true ,
264+ ).create ();
265+
266+ createEntrypoint (p.join ('source' , appPath));
217267
218268 expect (
219269 () => entrypoint! .workspaceRoot.listFiles (),
@@ -227,6 +277,25 @@ void main() {
227277 );
228278 });
229279
280+ test ('Does not throw when publishing via symlink' , () async {
281+ await d.dir ('src' , [
282+ d.dir (appPath, [
283+ d.pubspec ({'name' : 'myapp' }),
284+ ]),
285+ ]).create ();
286+ await link (
287+ 'source' ,
288+ p.join (d.sandbox, 'src' ),
289+ forceDirectory: true ,
290+ ).create ();
291+
292+ createEntrypoint (p.join ('source' , appPath));
293+
294+ expect (entrypoint! .workspaceRoot.listFiles (), {
295+ p.join (root, 'pubspec.yaml' ),
296+ });
297+ });
298+
230299 test ('not throws on ignored link' , () async {
231300 await d.dir (appPath, [
232301 d.pubspec ({'name' : 'myapp' }),
@@ -235,12 +304,9 @@ void main() {
235304 d.dir ('subdir' , [
236305 d.file ('.pubignore' , 'symlink' ),
237306 d.dir ('a' , [d.file ('file' )]),
307+ link ('symlink' , '..' , forceDirectory: true ),
238308 ]),
239309 ]).create ();
240- createDirectorySymlink (
241- p.join (d.sandbox, appPath, 'subdir' , 'symlink' ),
242- '..' ,
243- );
244310
245311 createEntrypoint ();
246312
@@ -259,20 +325,11 @@ void main() {
259325 d.file ('file2.txt' , 'contents' ),
260326 d.dir ('subdir' , [
261327 d.dir ('a' , [d.file ('file' )]),
328+ link ('symlink1' , 'a' , forceDirectory: true ),
329+ link ('symlink2' , 'a' , forceDirectory: true ),
262330 ]),
331+ link ('symlink3' , p.join ('subdir' , 'a' )),
263332 ]).create ();
264- createDirectorySymlink (
265- p.join (d.sandbox, appPath, 'subdir' , 'symlink1' ),
266- 'a' ,
267- );
268- createDirectorySymlink (
269- p.join (d.sandbox, appPath, 'subdir' , 'symlink2' ),
270- 'a' ,
271- );
272- createDirectorySymlink (
273- p.join (d.sandbox, appPath, 'symlink3' ),
274- p.join ('subdir' , 'a' ),
275- );
276333
277334 createEntrypoint ();
278335
@@ -299,8 +356,8 @@ void main() {
299356 ]),
300357 ]).create ();
301358
302- final root = p. join (d.sandbox, 'symlink' );
303- createDirectorySymlink ( root, appPath );
359+ await link ( 'symlink' , appPath). create ( );
360+ root = p. join (d.sandbox, 'symlink' );
304361
305362 final entrypoint = Entrypoint (
306363 p.join (d.sandbox, 'symlink' ),
0 commit comments