@@ -4979,13 +4979,17 @@ alias DirIterator = _DirIterator!dip1000Enabled;
4979
4979
operating system / filesystem, and may not follow any particular sorting.
4980
4980
4981
4981
Params:
4982
+ Path = Type of the directory path.
4983
+ Can be either a `string` or a `DirEntry`.
4984
+
4982
4985
useDIP1000 = used to instantiate this function separately for code with
4983
4986
and without -preview=dip1000 compiler switch, because it
4984
4987
affects the ABI of this function. Set automatically -
4985
4988
don't touch.
4986
4989
4987
4990
path = The directory to iterate over.
4988
- If empty, the current directory will be iterated.
4991
+ If an empty string (or data that implicitly converts to one) is
4992
+ provided, the current directory will be iterated.
4989
4993
4990
4994
pattern = Optional string with wildcards, such as $(RED
4991
4995
"*.d"). When present, it is used to filter the
@@ -5073,8 +5077,11 @@ scan("");
5073
5077
5074
5078
// For some reason, doing the same alias-to-a-template trick as with DirIterator
5075
5079
// does not work here.
5076
- auto dirEntries (bool useDIP1000 = dip1000Enabled)
5077
- (string path, SpanMode mode, bool followSymlink = true )
5080
+ // The template constraint is necessary to prevent this overload from matching
5081
+ // `DirEntry`. Said type has an `alias this` member of type `string`.
5082
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5083
+ (const Path path, SpanMode mode, bool followSymlink = true )
5084
+ if (is (Path == string ))
5078
5085
{
5079
5086
return _DirIterator! useDIP1000(path, mode, followSymlink);
5080
5087
}
@@ -5175,46 +5182,11 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
5175
5182
dirEntries(" " , SpanMode.shallow).walkLength();
5176
5183
}
5177
5184
5178
- // https://github.com/dlang/phobos/issues/9584
5179
- @safe unittest
5180
- {
5181
- import std.path : absolutePath, buildPath;
5182
-
5183
- string root = deleteme();
5184
- mkdirRecurse(root);
5185
- scope (exit) rmdirRecurse(root);
5186
-
5187
- mkdirRecurse(root.buildPath(" 1" , " 2" ));
5188
- mkdirRecurse(root.buildPath(" 3" , " 4" ));
5189
- mkdirRecurse(root.buildPath(" 3" , " 5" , " 6" ));
5190
-
5191
- const origWD = getcwd();
5192
- chdir(root);
5193
- scope (exit) chdir (origWD);
5194
-
5195
- /*
5196
- This wouldn't work if `entry` were a `string` – for obvious reasons:
5197
- One cannot (reliably) iterate nested directory trees using relative path strings
5198
- while changing directories in between.
5199
-
5200
- The expected error would be something along the lines of:
5201
- > Failed to stat file `./3/5': No such file or directory
5202
-
5203
- See <https://github.com/dlang/phobos/issues/9584> for further details.
5204
- */
5205
- foreach (DirEntry entry; " ." .dirEntries(SpanMode.shallow))
5206
- {
5207
- if (entry.isDir)
5208
- foreach (DirEntry subEntry; entry.dirEntries(SpanMode.shallow))
5209
- if (subEntry.isDir)
5210
- chdir(subEntry.absolutePath); // ←
5211
- }
5212
- }
5213
-
5214
5185
// / Ditto
5215
- auto dirEntries (bool useDIP1000 = dip1000Enabled)
5216
- (string path, string pattern, SpanMode mode,
5186
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5187
+ (const Path path, string pattern, SpanMode mode,
5217
5188
bool followSymlink = true )
5189
+ if (is (Path == string )) // necessary, see comment on previous overload for details
5218
5190
{
5219
5191
import std.algorithm.iteration : filter;
5220
5192
import std.path : globMatch, baseName;
@@ -5334,6 +5306,114 @@ auto dirEntries(bool useDIP1000 = dip1000Enabled)
5334
5306
assertThrown! Exception (dirEntries(" 237f5babd6de21f40915826699582e36" , " *.bin" , SpanMode.depth));
5335
5307
}
5336
5308
5309
+ @safe unittest
5310
+ {
5311
+ // This is why all the template constraints on `dirEntries` are necessary.
5312
+ static assert (isImplicitlyConvertible! (DirEntry , string ));
5313
+ }
5314
+
5315
+ // / Ditto
5316
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5317
+ (Path path, SpanMode mode, bool followSymlink = true )
5318
+ if (isImplicitlyConvertible! (Path, string ) && ! is (Path == string ) && ! is (Path == DirEntry ))
5319
+ {
5320
+ return dirEntries! (string , useDIP1000)(path, mode, followSymlink);
5321
+ }
5322
+
5323
+ // / Ditto
5324
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5325
+ (Path path, string pattern, SpanMode mode,
5326
+ bool followSymlink = true )
5327
+ if (isImplicitlyConvertible! (Path, string ) && ! is (Path == string ) && ! is (Path == DirEntry ))
5328
+ {
5329
+ return dirEntries! (string , useDIP1000)(
5330
+ path, pattern, mode,
5331
+ followSymlink
5332
+ );
5333
+ }
5334
+
5335
+ @safe unittest
5336
+ {
5337
+ static struct Wrapper
5338
+ {
5339
+ string data;
5340
+ alias data this ;
5341
+ }
5342
+
5343
+ string root = deleteme();
5344
+ mkdirRecurse(root);
5345
+ scope (exit) rmdirRecurse(root);
5346
+
5347
+ auto wrapped = Wrapper(root);
5348
+ foreach (entry; dirEntries (wrapped, SpanMode.shallow)) {}
5349
+ }
5350
+
5351
+ // / Ditto
5352
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5353
+ (Path path, SpanMode mode, bool followSymlink = true )
5354
+ if (is (Path == DirEntry ))
5355
+ {
5356
+ return dirEntries! (string , useDIP1000)(path.nameWithPrefix, mode, followSymlink);
5357
+ }
5358
+
5359
+ // / Ditto
5360
+ auto dirEntries (Path, bool useDIP1000 = dip1000Enabled)
5361
+ (Path path, string pattern, SpanMode mode,
5362
+ bool followSymlink = true )
5363
+ if (is (Path == DirEntry ))
5364
+ {
5365
+ return dirEntries! (string , useDIP1000)(
5366
+ path.nameWithPrefix, pattern, mode,
5367
+ followSymlink
5368
+ );
5369
+ }
5370
+
5371
+ // https://github.com/dlang/phobos/issues/9584
5372
+ @safe unittest
5373
+ {
5374
+ import std.path : absolutePath, buildPath;
5375
+
5376
+ string root = deleteme();
5377
+ mkdirRecurse(root);
5378
+ scope (exit) rmdirRecurse(root);
5379
+
5380
+ mkdirRecurse(root.buildPath(" 1" , " 2" ));
5381
+ mkdirRecurse(root.buildPath(" 3" , " 4" ));
5382
+ mkdirRecurse(root.buildPath(" 3" , " 5" , " 6" ));
5383
+
5384
+ const origWD = getcwd();
5385
+
5386
+ /*
5387
+ This wouldn't work if `entry` were a `string` – for fair reasons:
5388
+ One cannot (reliably) iterate nested directory trees using relative path strings
5389
+ while changing directories in between.
5390
+
5391
+ The expected error would be something along the lines of:
5392
+ > Failed to stat file `./3/5': No such file or directory
5393
+
5394
+ See <https://github.com/dlang/phobos/issues/9584> for further details.
5395
+ */
5396
+ chdir(root);
5397
+ scope (exit) chdir (origWD);
5398
+ foreach (DirEntry entry; " ." .dirEntries(SpanMode.shallow))
5399
+ {
5400
+ if (entry.isDir)
5401
+ foreach (DirEntry subEntry; entry.dirEntries(SpanMode.shallow))
5402
+ if (subEntry.isDir)
5403
+ chdir(subEntry.absolutePath); // ←
5404
+ }
5405
+
5406
+ chdir(root);
5407
+ scope (exit) chdir (origWD);
5408
+ foreach (DirEntry entry; " ." .dirEntries(" *" , SpanMode.shallow))
5409
+ {
5410
+ if (entry.isDir)
5411
+ foreach (DirEntry subEntry; entry.dirEntries(" *" , SpanMode.shallow))
5412
+ if (subEntry.isDir)
5413
+ chdir(subEntry.absolutePath); // ←
5414
+ }
5415
+ }
5416
+
5337
5417
/**
5338
5418
* Reads a file line by line and parses the line into a single value or a
5339
5419
* $(REF Tuple, std,typecons) of values depending on the length of `Types`.
0 commit comments