Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[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

Merged
merged 26 commits into from
Jul 29, 2022

Conversation

Jasguerrero
Copy link
Contributor

@Jasguerrero Jasguerrero commented Jun 3, 2022

Fixes #53833

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • All existing and new tests are passing.

@flutter-dashboard flutter-dashboard bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Jun 3, 2022
@Jasguerrero Jasguerrero changed the title joinCaches function [flutter_tool] join flutter specific with home cache Jun 6, 2022
@Jasguerrero Jasguerrero changed the title [flutter_tool] join flutter specific with home cache [flutter_tools] join flutter specific with home cache Jun 6, 2022
@Jasguerrero Jasguerrero marked this pull request as ready for review June 6, 2022 20:38
@@ -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);
Copy link
Member

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.

@jonasfj
Copy link
Member

jonasfj commented Jun 7, 2022

Isn't there also an opportunity to cleanup:

if [[ -d "$FLUTTER_ROOT/.pub-cache" ]]; then
export PUB_CACHE="${PUB_CACHE:-"$FLUTTER_ROOT/.pub-cache"}"
fi

(and similar thing in the .bat variant)

_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.');
Copy link
Contributor

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);
Copy link
Contributor

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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());
Copy link
Contributor

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);
Copy link
Contributor

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);
Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

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
Copy link
Contributor Author

@Jasguerrero Jasguerrero Jun 10, 2022

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:

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,
Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^

Copy link
Contributor

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,
Copy link
Contributor

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

Copy link
Contributor

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,
Copy link
Contributor

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) {
Copy link
Contributor

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
Copy link
Contributor Author

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'));
Copy link
Contributor

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?

Copy link
Contributor Author

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()) {
Copy link
Contributor

@christopherfujino christopherfujino Jun 10, 2022

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -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'));
Copy link
Contributor

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'] ?? '';
Copy link
Contributor

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?

Copy link
Contributor Author

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']!)

Copy link
Contributor

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// 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).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// 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);
Copy link
Contributor

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);
Copy link
Contributor

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()) {
Copy link
Contributor

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'));
}
}

Copy link
Contributor

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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point

Copy link
Contributor

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?

@Jasguerrero Jasguerrero reopened this Jul 29, 2022
@Jasguerrero Jasguerrero added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 29, 2022
@auto-submit auto-submit bot merged commit 6048e07 into flutter:master Jul 29, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Jul 30, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jul 30, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Jul 30, 2022
camsim99 pushed a commit to camsim99/flutter that referenced this pull request Aug 10, 2022
@Jasguerrero Jasguerrero deleted the flutter_pub_cache branch September 28, 2022 23:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autosubmit Merge PR when tree becomes green via auto submit App tool Affects the "flutter" command-line tool. See also t: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Flutter-specific pub cache causes issues
3 participants