forked from dart-lang/dartdoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathio_utils.dart
126 lines (104 loc) · 3.91 KB
/
io_utils.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2014, 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.
/// This is a helper library to make working with io easier.
library dartdoc.io_utils;
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart' as path;
/// Return a resolved path including the home directory in place of tilde
/// references.
String resolveTildePath(String originalPath) {
if (originalPath == null || !originalPath.startsWith('~/')) {
return originalPath;
}
String homeDir;
if (Platform.isWindows) {
homeDir = path.absolute(Platform.environment['USERPROFILE']);
} else {
homeDir = path.absolute(Platform.environment['HOME']);
}
return path.join(homeDir, originalPath.substring(2));
}
/// Lists the contents of [dir].
///
/// If [recursive] is `true`, lists subdirectory contents (defaults to `false`).
///
/// Excludes files and directories beginning with `.`
///
/// The returned paths are guaranteed to begin with [dir].
Iterable<String> listDir(String dir,
{bool recursive = false,
Iterable<FileSystemEntity> Function(Directory dir) listDir}) {
listDir ??= (Directory dir) => dir.listSync();
return _doList(dir, <String>{}, recursive, listDir);
}
Iterable<String> _doList(
String dir,
Set<String> listedDirectories,
bool recurse,
Iterable<FileSystemEntity> Function(Directory dir) listDir) sync* {
// Avoid recursive symlinks.
var resolvedPath = Directory(dir).resolveSymbolicLinksSync();
if (!listedDirectories.contains(resolvedPath)) {
listedDirectories = Set<String>.from(listedDirectories);
listedDirectories.add(resolvedPath);
for (var entity in listDir(Directory(dir))) {
// Skip hidden files and directories
if (path.basename(entity.path).startsWith('.')) {
continue;
}
yield entity.path;
if (entity is Directory) {
if (recurse) {
yield* _doList(entity.path, listedDirectories, recurse, listDir);
}
}
}
}
}
/// Converts `.` and `:` into `-`, adding a ".html" extension.
///
/// For example:
///
/// * dart.dartdoc => dart_dartdoc.html
/// * dart:core => dart_core.html
String getFileNameFor(String name) =>
'${name.replaceAll(_libraryNameRegExp, '-')}.html';
final _libraryNameRegExp = RegExp('[.:]');
@Deprecated('Public variable intended to be private; will be removed as early '
'as Dartdoc 1.0.0')
RegExp get libraryNameRegexp => _libraryNameRegExp;
@Deprecated('Public variable intended to be private; will be removed as early '
'as Dartdoc 1.0.0')
final RegExp partOfRegexp = RegExp('part of ');
@Deprecated('Public variable intended to be private; will be removed as early '
'as Dartdoc 1.0.0')
final RegExp newLinePartOfRegexp = RegExp('\npart of ');
/// Best used with Future<void>.
class MultiFutureTracker<T> {
/// Approximate maximum number of simultaneous active Futures.
final int parallel;
final Set<Future<T>> _trackedFutures = {};
MultiFutureTracker(this.parallel);
/// Wait until fewer or equal to this many Futures are outstanding.
Future<void> _waitUntil(int max) async {
while (_trackedFutures.length > max) {
await Future.any(_trackedFutures);
}
}
/// Generates a [Future] from the given closure and adds it to the queue,
/// once the queue is sufficiently empty. The returned future completes
/// when the generated [Future] has been added to the queue.
Future<void> addFutureFromClosure(Future<T> Function() closure) async {
while (_trackedFutures.length > parallel - 1) {
await Future.any(_trackedFutures);
}
Future<void> future = closure();
_trackedFutures.add(future);
// ignore: unawaited_futures
future.then((f) => _trackedFutures.remove(future));
}
/// Wait until all futures added so far have completed.
Future<void> wait() async => await _waitUntil(0);
}