forked from dart-lang/dartdoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflutter_repo.dart
126 lines (108 loc) · 4.52 KB
/
flutter_repo.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) 2023, 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.
import 'dart:async';
import 'dart:io';
import 'package:dartdoc/src/io_utils.dart';
import 'package:path/path.dart' as path;
import 'io_utils.dart' as io_utils;
import 'subprocess_launcher.dart';
/// A class representing a Flutter SDK repository.
class FlutterRepo {
final String repoPath;
final Map<String, String> env;
final String cacheDart;
final SubprocessLauncher launcher;
FlutterRepo._(this.repoPath, this.env, this.cacheDart, this.launcher);
String get dartCmd => path.joinAll([repoPath, 'bin', 'dart']);
String get flutterCmd => path.joinAll([repoPath, 'bin', 'flutter']);
Future<void> init() async {
Directory(repoPath).createSync(recursive: true);
await launcher.runStreamed(
'git', ['clone', 'https://github.com/flutter/flutter.git', '.'],
workingDirectory: repoPath);
await launcher.runStreamed(
flutterCmd,
['--version'],
workingDirectory: repoPath,
);
await launcher.runStreamed(
flutterCmd,
['update-packages'],
workingDirectory: repoPath,
);
}
factory FlutterRepo.fromPath(String flutterPath, Map<String, String> env,
[String? label]) {
var cacheDart =
path.join(flutterPath, 'bin', 'cache', 'dart-sdk', 'bin', 'dart');
var flutterBinPath = path.join(path.canonicalize(flutterPath), 'bin');
var existingPathVariable = env['PATH'] ?? Platform.environment['PATH'];
env['PATH'] = '$flutterBinPath:$existingPathVariable';
env['FLUTTER_ROOT'] = flutterPath;
var launcher =
SubprocessLauncher('flutter${label == null ? "" : "-$label"}', env);
return FlutterRepo._(flutterPath, env, cacheDart, launcher);
}
/// Copies an existing, initialized flutter repo to [flutterPath].
static Future<FlutterRepo> copyFromExistingFlutterRepo(
FlutterRepo originalRepo, String flutterPath, Map<String, String> env,
[String? label]) async {
io_utils.copy(Directory(originalRepo.repoPath), Directory(flutterPath));
return FlutterRepo.fromPath(flutterPath, env, label);
}
/// Doesn't actually copy the existing repo; use for read-only operations
/// only.
static Future<FlutterRepo> fromExistingFlutterRepo(FlutterRepo originalRepo,
[String? label]) async {
return FlutterRepo.fromPath(originalRepo.repoPath, {}, label);
}
}
Directory cleanFlutterDir = Directory(path.join(
path.context.resolveTildePath('~/.dartdoc_grinder'), 'cleanFlutter'));
/// Global so that the lock is retained for the life of the process.
Future<void>? _lockFuture;
Completer<FlutterRepo>? _cleanFlutterRepo;
/// Returns true if we need to replace the existing flutter. We never release
/// this lock until the program exits to prevent edge case runs from
/// spontaneously deciding to download a new Flutter SDK in the middle of a run.
// TODO(srawlins): The above comment is outdated.
Future<FlutterRepo> get cleanFlutterRepo async {
var repoCompleter = _cleanFlutterRepo;
if (repoCompleter != null) {
return repoCompleter.future;
}
// No await is allowed between check of `_cleanFlutterRepo` and its
// assignment, to prevent reentering this function.
repoCompleter = Completer();
_cleanFlutterRepo = repoCompleter;
// Figure out where the repository is supposed to be and lock updates for it.
await cleanFlutterDir.parent.create(recursive: true);
assert(_lockFuture == null);
_lockFuture = File(path.join(cleanFlutterDir.parent.path, 'lock'))
.openSync(mode: FileMode.write)
.lock();
await _lockFuture;
var lastSynced = File(path.join(cleanFlutterDir.parent.path, 'lastSynced'));
var newRepo = FlutterRepo.fromPath(cleanFlutterDir.path, {}, 'clean');
// We have a repository, but is it up to date?
DateTime? lastSyncedTime;
if (lastSynced.existsSync()) {
lastSyncedTime = DateTime.fromMillisecondsSinceEpoch(
int.parse(lastSynced.readAsStringSync()));
}
if (lastSyncedTime == null ||
DateTime.now().difference(lastSyncedTime) > Duration(hours: 24)) {
// Rebuild the repository.
if (cleanFlutterDir.existsSync()) {
cleanFlutterDir.deleteSync(recursive: true);
}
cleanFlutterDir.createSync(recursive: true);
await newRepo.init();
await lastSynced
.writeAsString(DateTime.now().millisecondsSinceEpoch.toString());
}
repoCompleter.complete(newRepo);
_cleanFlutterRepo = repoCompleter;
return repoCompleter.future;
}