-
Notifications
You must be signed in to change notification settings - Fork 28.7k
[flutter_tools] join flutter specific with home cache #105343
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@@ -484,8 +504,9 @@ class _DefaultPub implements Pub { | |||
|
|||
final String cachePath = _fileSystem.path.join(Cache.flutterRoot!, '.pub-cache'); | |||
if (_fileSystem.directory(cachePath).existsSync()) { | |||
_logger.printTrace('Using $cachePath for the pub cache.'); | |||
return cachePath; | |||
joinCaches(_fileSystem, '${_platform.environment['Home']}/.pub_cache', cachePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logic for finding the default PUB_CACHE
is here:
https://github.com/dart-lang/pub/blob/73ea9a98b5bef9cd2b1ca4d1eba8b6d20e1ad3d0/lib/src/system_cache.dart#L40-L60
There is occasionally some discussion around moving to a more XDG compliant location. But that's not happening right now. Feel free to file a PR against pub
with a //NOTE: ....
saying that when changing this we should also patch flutter_tools
.
Isn't there also an opportunity to cleanup: flutter/bin/internal/shared.sh Lines 152 to 154 in be0c1bd
(and similar thing in the |
_logger.printTrace('Using $cachePath for the pub cache.'); | ||
return cachePath; | ||
joinCaches(_fileSystem, '${_platform.environment['Home']}/.pub_cache', cachePath); | ||
//_logger.printTrace('Using $cachePath for the pub cache.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
commented out code
@@ -484,8 +504,9 @@ class _DefaultPub implements Pub { | |||
|
|||
final String cachePath = _fileSystem.path.join(Cache.flutterRoot!, '.pub-cache'); | |||
if (_fileSystem.directory(cachePath).existsSync()) { | |||
_logger.printTrace('Using $cachePath for the pub cache.'); | |||
return cachePath; | |||
joinCaches(_fileSystem, '${_platform.environment['Home']}/.pub_cache', cachePath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't hard code '/'
as this will be wrong on Windows. You can copy the rest of this file, where _fileSystem.path.join(...)
is called.
Also, will detecting the home directory work this way on Windows?
@@ -35,6 +36,25 @@ const int _kPubExitCodeUnavailable = 69; | |||
|
|||
typedef MessageFilter = String? Function(String message); | |||
|
|||
/// targetPath is the directory in which the content of the extraPath will be moved in | |||
void joinCaches(FileSystem fileSystem, String targetPath, String extraPath) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void joinCaches(FileSystem fileSystem, String targetPath, String extraPath) { | |
void joinCaches({ | |
required FileSystem fileSystem, | |
required String destinationPath, | |
required String sourcePath, | |
) { |
for (final FileSystemEntity entity in extraDirectory.listSync()) { | ||
final File file = fileSystem.file(entity.path); | ||
if (file.existsSync()) { | ||
targetDirectory.childFile(entity.basename).writeAsBytesSync(file.readAsBytesSync()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
readAsBytesSync -> writeAsBytesSync will pull the entire file into memory before writing it again; this will use a lot of resources and be slow; use https://api.dart.dev/stable/2.17.3/dart-io/File/renameSync.html (per that dartdoc, if the source and destination paths are on different filesystems, that may fail, so maybe copy + delete would be safer?)
final Directory extraDirectory = fileSystem.directory(extraPath); | ||
|
||
for (final FileSystemEntity entity in extraDirectory.listSync()) { | ||
final File file = fileSystem.file(entity.path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A FileSystemEntity
doesn't have to be a file, I think instead you need to check if entity is File
@@ -48,19 +48,43 @@ void joinCaches({ | |||
final String newPath = fileSystem.path.join(targetDirectory.path, entity.basename); | |||
if (entity is File) { | |||
final File file = fileSystem.file(entity.path); | |||
file.renameSync(newPath); | |||
file.copySync(newPath); | |||
file.deleteSync(recursive: true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can probably just recursively delete the entire local cache at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't want to face the issue of running out of memory. But if we don't think that will happen a lot I can delete this line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(doing many little deletes will be much slower than a single file system call)
@@ -477,17 +529,39 @@ class _DefaultPub implements Pub { | |||
return values.join(':'); | |||
} | |||
|
|||
String? _getRootPubCacheIfAvailable() { | |||
/// There is 3 ways to get the cache path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't there also an opportunity to cleanup:
flutter/bin/internal/shared.sh
Lines 152 to 154 in be0c1bd
if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}" fi (and similar thing in the
.bat
variant)
@jonasfj
As I mention in this comment we are not actually deleting the FLUTTER_ROOT/.pub-cache always, we are just doing that when FLUTTER_ROOT/.pub-cache and HOME/.pub-cache are available in the users environment so I don't think deleting the PUB-CACHE variable will be correct
final Directory newDirectory = targetDirectory.childDirectory(entity.basename); | ||
newDirectory.createSync(); | ||
joinCaches( | ||
fileSystem: fileSystem, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: de-dent once and add a trailing comma to line 62
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You added the comma, but not the de-dent
final Directory globalDirectory = _fileSystem.directory(_fileSystem.path.join(homeDirectory, '.pub-cache')); | ||
|
||
if (needsToJoinCache( | ||
fileSystem: _fileSystem, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: de-dent once and add a trailing comma to line 555
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here, and lines 564, 567, 571-573, please de-dent once and add trailing commas where there aren't one already
newDirectory.createSync(); | ||
joinCaches( | ||
fileSystem: fileSystem, | ||
targetPath: newDirectory.path, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you update the parameter names for joinCaches
to be globalCachePath
and localCachePath
. Also change the local variables here to match.
@@ -48,19 +48,43 @@ void joinCaches({ | |||
final String newPath = fileSystem.path.join(targetDirectory.path, entity.basename); | |||
if (entity is File) { | |||
final File file = fileSystem.file(entity.path); | |||
file.renameSync(newPath); | |||
file.copySync(newPath); | |||
file.deleteSync(recursive: true); | |||
} | |||
else if (entity is Directory) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: this else if
should be on the previous line, after the close curly brace
final String localCachePath = _fileSystem.path.join(Cache.flutterRoot!, '.pub-cache'); | ||
final Directory globalDirectory; | ||
if (_platform.isWindows) { | ||
// %LOCALAPPDATA% is preferred as the cache location over %APPDATA%, because the latter is synchronised between |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jonasfj I copy paste this comment from the dart-lang repo. Also can you double check on this logic for windows? Thanks.
required String localCachePath, | ||
required String globalCachePath | ||
}) { | ||
final Directory globalDirectory = fileSystem.directory(fileSystem.path.join(globalCachePath, '.pub-cache')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a surprising API to me. would it make sense to require the caller to pass a path already including .pub-cache
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this needs to change after my last commit. Sorry will update it
final Directory globalDirectory = fileSystem.directory(fileSystem.path.join(globalCachePath, '.pub-cache')); | ||
final Directory localDirectory = fileSystem.directory(fileSystem.path.join(localCachePath, '.pub-cache')); | ||
|
||
if (globalDirectory.existsSync() && localDirectory.existsSync()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can make this code simpler by skipping this check, and instead going directly down to pub.dartlang.org
dir and checking that those exist.
@@ -505,12 +529,16 @@ class _DefaultPub implements Pub { | |||
return values.join(':'); | |||
} | |||
|
|||
String? _getRootPubCacheIfAvailable() { | |||
/// There is 3 ways to get the cache path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same notes about dartdocs should start with a high level summary: https://dart.dev/guides/language/effective-dart/documentation#do-start-doc-comments-with-a-single-sentence-summary
@@ -519,12 +547,20 @@ class _DefaultPub implements Pub { | |||
homeDirectory = _platform.environment['Home'] ?? ''; | |||
} | |||
|
|||
if (_fileSystem.directory(cachePath).existsSync()) { | |||
final Directory globalDirectory = _fileSystem.directory(_fileSystem.path.join(homeDirectory, '.pub-cache')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this indented wrong?
} | ||
} | ||
else { | ||
final String homeDirectory = _platform.environment['HOME'] ?? ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think ''
is a valid path, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not. What should happens when _platform.environment['HOME'] (or 'LOCALAPPDATA'/'APPDATA') is null? Is it ok to fail? (_platform.environment['HOME']!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, it is valid to not have a home directory. Maybe globalDirectory
should be nullable, and in this case it would be null. And then later you treat a null
globalDirectory
the same as if it didn't exist.
@@ -477,17 +522,58 @@ class _DefaultPub implements Pub { | |||
return values.join(':'); | |||
} | |||
|
|||
String? _getRootPubCacheIfAvailable() { | |||
/// There is 3 ways to get the pub cache location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// There is 3 ways to get the pub cache location | |
/// There are 3 ways for the tool to find a pub cache location: |
/// There is 3 ways to get the pub cache location | ||
/// | ||
/// 1) Provide the _kPubCacheEnvironmentKey. | ||
/// 2) localPath (flutterRoot) but not globalPath ($HOME) .pubCache in which case we use the available (and vice versa). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// 2) localPath (flutterRoot) but not globalPath ($HOME) .pubCache in which case we use the available (and vice versa). | |
/// 2) There is a local cache (in the Flutter SDK) but not a global one (in the user's home directory). |
/// | ||
/// 1) Provide the _kPubCacheEnvironmentKey. | ||
/// 2) localPath (flutterRoot) but not globalPath ($HOME) .pubCache in which case we use the available (and vice versa). | ||
/// 3) If both local and global are available joinCaches is called and local deleted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// 3) If both local and global are available joinCaches is called and local deleted | |
/// 3) If both local and global are available then merge the local into global and return the global. |
final File file = fileSystem.file(entity.path); | ||
file.copySync(newPath); | ||
} else if (entity is Directory) { | ||
final Directory currentDirectory = fileSystem.directory(entity.path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't you just use entity
itself?
for (final FileSystemEntity entity in localDirectory.listSync()) { | ||
final String newPath = fileSystem.path.join(globalDirectory.path, entity.basename); | ||
if (entity is File) { | ||
final File file = fileSystem.file(entity.path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can just use entity
as a file in this block, because of type promotion
file.copySync(newPath); | ||
} else if (entity is Directory) { | ||
final Directory currentDirectory = fileSystem.directory(entity.path); | ||
if (!currentDirectory.existsSync()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this can ever not exist--feel free to explain if i'm reading this wrong.
} else { | ||
final String homeDirectoryPath = _platform.environment['HOME']!; | ||
globalDirectory = _fileSystem.directory(_fileSystem.path.join(homeDirectoryPath, '.pub-cache')); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to check if globalDirectory
exists, and if not, return the local cache path
@@ -501,7 +598,7 @@ class _DefaultPub implements Pub { | |||
'FLUTTER_ROOT': flutterRootOverride ?? Cache.flutterRoot!, | |||
_kPubEnvironmentKey: await _getPubEnvironmentValue(context), | |||
}; | |||
final String? pubCache = _getRootPubCacheIfAvailable(); | |||
final String? pubCache = _getLocalPubCacheIfAvailable(); | |||
if (pubCache != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make pubCache
non-nullable, and always tell pub where we know the pub cache is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem comes if the localPubCache and the globalPubCache are both empty we still need to depend on pub's logic to create the global and skip setting the PUB_CACHE
environment variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we rename the function _getPubCacheIfAvailable()
and have it return the global cache if we have one?
Fixes #53833
Pre-launch Checklist
///
).