Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/devtools_shared/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
-->

# 13.1.0
* The `LocalFileSystem` extension APIs are deprecated in favor of a new
`FileSystemExtension` extension, which is based on the `FileSystem` class
from the `file` package. In detail:
* `fileSystem` is a new top-level constant which represents the local (real)
file system.
* `LocalFileSystem.devToolsDir()` is replaced by a static getter,
`FileSystemExtension.devToolsDir`.
* `LocalFileSystem.maybeMoveLegacyDevToolsStore()` is replaced by an instance
method, `FileSystemExtension.maybeMoveLegacyDevToolsStore()`.
* `LocalFileSystem.devToolsStoreLocation()` is replaced by a static getter,
`FileSystemExtension.devToolsStoreLocation`.
* `LocalFileSystem.ensureDevToolsDirectory()` will be removed.
* `LocalFileSystem.devToolsFileFromPath()` is replaced by an instance method,
`FileSystemExtension.devToolsFileFromPath()`.
* `LocalFileSystem.devToolsFileAsJson()` is replaced by an instance method,
`FileSystemExtension.devToolsFileAsJson()`.
* `LocalFileSystem.flutterStoreExists()` is replaced by an instance getter,
`FileSystemExtension.flutterStoreExists`.

# 13.0.2
* Validate the `devtoolsOptionsUri` query parameter in the extension enabled
state handler so it must be a `file:` URI named `devtools_options.yaml`,
Expand Down
118 changes: 107 additions & 11 deletions packages/devtools_shared/lib/src/server/file_system.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,60 @@
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.

import 'dart:convert';
import 'dart:io';
import 'dart:io' as io show Platform, File, Directory;

import 'package:file/file.dart' as file;
import 'package:file/local.dart' as file;
import 'package:path/path.dart' as path;

import 'devtools_store.dart';

/// The real, local file system, which can be avoided in tests.
const file.FileSystem fileSystem = file.LocalFileSystem();

/// A namespace local file system utlities.
extension LocalFileSystem on Never {
static String _userHomeDir() {
final envKey = Platform.operatingSystem == 'windows' ? 'APPDATA' : 'HOME';
return Platform.environment[envKey] ?? '.';
final envKey = io.Platform.operatingSystem == 'windows'
? 'APPDATA'
: 'HOME';
return io.Platform.environment[envKey] ?? '.';
}

/// Returns the path to the DevTools storage directory.
@Deprecated("Replaced by 'FileSystemExtension.devToolsDir'")
static String devToolsDir() {
return path.join(_userHomeDir(), '.flutter-devtools');
}

/// Moves the .devtools file to ~/.flutter-devtools/.devtools if the .devtools
/// file exists in the user's home directory.
@Deprecated("Replaced by 'FileSystemExtension.maybeMoveLegacyDevToolsStore'")
static void maybeMoveLegacyDevToolsStore() {
final file = File(path.join(_userHomeDir(), DevToolsUsage.storeName));
final file = io.File(path.join(_userHomeDir(), DevToolsUsage.storeName));
if (file.existsSync()) {
ensureDevToolsDirectory();
file.copySync(devToolsStoreLocation());
file.deleteSync();
}
}

@Deprecated("Replaced by 'FileSystemExtension.devToolsStoreLocation'")
static String devToolsStoreLocation() {
return path.join(devToolsDir(), DevToolsUsage.storeName);
}

/// Creates the ~/.flutter-devtools directory if it does not already exist.
@Deprecated('To be removed')
static void ensureDevToolsDirectory() {
Directory(devToolsDir()).createSync();
io.Directory(devToolsDir()).createSync();
}
Comment thread
srawlins marked this conversation as resolved.

/// Returns a DevTools file from the given path.
///
/// Only files within ~/.flutter-devtools/ can be accessed.
static File? devToolsFileFromPath(String pathFromDevToolsDir) {
@Deprecated("Replaced by 'FileSystemExtension.devToolsFileFromPath'")
static io.File? devToolsFileFromPath(String pathFromDevToolsDir) {
Comment thread
srawlins marked this conversation as resolved.
if (pathFromDevToolsDir.contains('..') ||
path.isAbsolute(pathFromDevToolsDir)) {
// The passed in path should not be able to walk up the directory tree
Expand All @@ -57,7 +69,7 @@ extension LocalFileSystem on Never {

ensureDevToolsDirectory();
final devToolsDirPath = devToolsDir();
final file = File(path.join(devToolsDirPath, pathFromDevToolsDir));
final file = io.File(path.join(devToolsDirPath, pathFromDevToolsDir));
// Defense in depth: ensure the resolved path is actually contained within
// the DevTools directory.
if (!path.isWithin(devToolsDirPath, file.path)) {
Expand All @@ -72,6 +84,7 @@ extension LocalFileSystem on Never {
/// Returns a DevTools file from the given path as encoded json.
///
/// Only files within ~/.flutter-devtools/ can be accessed.
@Deprecated("Replaced by 'FileSystemExtension.devToolsFileAsJson'")
static String? devToolsFileAsJson(String pathFromDevToolsDir) {
final file = devToolsFileFromPath(pathFromDevToolsDir);
if (file == null) return null;
Expand All @@ -86,8 +99,90 @@ extension LocalFileSystem on Never {
}

/// Whether the flutter store file exists.
@Deprecated("Replaced by 'FileSystemExtension.flutterStoreExists'")
static bool flutterStoreExists() {
final flutterStore = File(path.join(_userHomeDir(), '.flutter'));
final flutterStore = io.File(path.join(_userHomeDir(), '.flutter'));
return flutterStore.existsSync();
}
Comment thread
srawlins marked this conversation as resolved.
}

extension FileSystemExtension on file.FileSystem {
static String get _userHomeDir {
final envKey = io.Platform.operatingSystem == 'windows'
? 'APPDATA'
: 'HOME';
return io.Platform.environment[envKey] ?? '.';
}

/// The path to the DevTools storage directory.
static String get devToolsDir {
return path.join(_userHomeDir, '.flutter-devtools');
}

/// Moves the `.devtools` file to `~/.flutter-devtools/.devtools` if the
/// `.devtools` file exists in the user's home directory.
void maybeMoveLegacyDevToolsStore() {
final storeFile = this.file(
path.join(_userHomeDir, DevToolsUsage.storeName),
);
if (storeFile.existsSync()) {
_ensureDevToolsDirectory();
storeFile.copySync(devToolsStoreLocation);
storeFile.deleteSync();
}
}

static String get devToolsStoreLocation {
return path.join(devToolsDir, DevToolsUsage.storeName);
}

/// Creates the `~/.flutter-devtools` directory if it does not already exist.
void _ensureDevToolsDirectory() {
directory(devToolsDir).createSync();
}
Comment thread
srawlins marked this conversation as resolved.

/// Returns a DevTools file from the given path.
///
/// Only files within ~/.flutter-devtools/ can be accessed.
file.File? devToolsFileFromPath(String relativePath) {
if (relativePath.contains('..') || path.isAbsolute(relativePath)) {
// The passed in path should not be able to walk up the directory tree
// outside of the `~/.flutter-devtools/` directory. It must also not be an
// absolute path: `path.join()` discards the base directory when its
// second argument is absolute, which would otherwise allow reading an
// arbitrary file on disk (e.g. an absolute path to a credentials `.json`
// file).
return null;
}

_ensureDevToolsDirectory();
final targetFile = this.file(path.join(devToolsDir, relativePath));
// Defense in depth: ensure the resolved path is actually contained within
// the DevTools directory.
if (!path.isWithin(devToolsDir, targetFile.path)) return null;
if (!targetFile.existsSync()) return null;
return targetFile;
}

/// Returns a DevTools file from the given path as encoded JSON.
///
/// Only files within `~/.flutter-devtools/` can be accessed.
String? devToolsFileAsJson(String relativePath) {
final targetFile = devToolsFileFromPath(relativePath);
if (targetFile == null) return null;

final fileName = path.basename(targetFile.path);
if (!fileName.endsWith('.json')) return null;

final content = targetFile.readAsStringSync();
final json = jsonDecode(content) as Map;
json['lastModifiedTime'] = targetFile.lastModifiedSync().toString();
return jsonEncode(json);
}

/// Whether the flutter store file exists.
bool get flutterStoreExists {
final flutterStore = this.file(path.join(_userHomeDir, '.flutter'));
return flutterStore.existsSync();
}
}
Expand All @@ -96,14 +191,15 @@ class IOPersistentProperties {
IOPersistentProperties(this.name, {String? documentDirPath}) {
final fileName = name.replaceAll(' ', '_');
documentDirPath ??= LocalFileSystem._userHomeDir();
_file = File(path.join(documentDirPath, fileName));
_file = io.File(path.join(documentDirPath, fileName));
if (!_file.existsSync()) {
_file.createSync(recursive: true);
}
syncSettings();
}

IOPersistentProperties.fromFile(File file) : name = path.basename(file.path) {
IOPersistentProperties.fromFile(io.File file)
: name = path.basename(file.path) {
_file = file;
if (!_file.existsSync()) {
_file.createSync(recursive: true);
Expand All @@ -113,7 +209,7 @@ class IOPersistentProperties {

final String name;

late File _file;
late io.File _file;

late Map<String, Object?> _map;

Expand Down
3 changes: 2 additions & 1 deletion packages/devtools_shared/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
name: devtools_shared
description: Package of shared Dart structures between devtools_app, dds, and other tools.

version: 13.0.2
version: 13.1.0

repository: https://github.com/flutter/devtools/tree/master/packages/devtools_shared

Expand All @@ -18,6 +18,7 @@ dependencies:
collection: ^1.15.0
dtd: ^4.0.0
extension_discovery: ^2.1.0
file: ^7.0.0
meta: ^1.9.1
path: ^1.8.0
shelf: ^1.1.0
Expand Down
4 changes: 2 additions & 2 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -555,10 +555,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: c82594181e3312f3d0695fc95aaaf7758d75b8d4ae2bbecf223b9fd5109a059d
sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9"
url: "https://pub.dev"
source: hosted
version: "1.18.3"
version: "1.19.0"
mime:
dependency: transitive
description:
Expand Down