mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 06:20:13 +00:00
Switch Workspace to Packages.
PackageMapUriResolver is still based on Map. Change-Id: I7d68f9dbc7d970b22c8e1a01d8e816b3e5723f34 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/244047 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
d2c7d93fbf
commit
359e597cec
19 changed files with 308 additions and 139 deletions
|
@ -29,9 +29,9 @@ class TransformSetManager {
|
|||
if (package == null) {
|
||||
return transformSets;
|
||||
}
|
||||
var packageMap = package.packagesAvailableTo(libraryPath);
|
||||
for (var entry in packageMap.entries) {
|
||||
var directory = entry.value[0];
|
||||
var packages = package.packagesAvailableTo(libraryPath);
|
||||
for (var package in packages.packages) {
|
||||
var directory = package.libFolder;
|
||||
var file = directory.getChildAssumingFile(dataFileName);
|
||||
var transformSet = _loadTransformSet(file);
|
||||
if (transformSet != null) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:analysis_server/src/plugin/notification_manager.dart';
|
|||
import 'package:analysis_server/src/plugin/plugin_manager.dart';
|
||||
import 'package:analyzer/file_system/physical_file_system.dart';
|
||||
import 'package:analyzer/instrumentation/instrumentation.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/util/file_paths.dart' as file_paths;
|
||||
|
@ -962,7 +963,7 @@ mixin _ContextRoot on ResourceProviderMixin {
|
|||
return ContextRootImpl(
|
||||
resourceProvider,
|
||||
resourceProvider.getFolder(root),
|
||||
BasicWorkspace.find(resourceProvider, {}, root),
|
||||
BasicWorkspace.find(resourceProvider, Packages.empty, root),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -372,12 +372,6 @@ class ContextLocatorImpl implements ContextLocator {
|
|||
packages = Packages.empty;
|
||||
}
|
||||
|
||||
// TODO(scheglov) Can we use Packages instead?
|
||||
var packageMap = <String, List<Folder>>{};
|
||||
for (var package in packages.packages) {
|
||||
packageMap[package.name] = [package.libFolder];
|
||||
}
|
||||
|
||||
var rootPath = folder.path;
|
||||
|
||||
Workspace? workspace;
|
||||
|
@ -385,9 +379,9 @@ class ContextLocatorImpl implements ContextLocator {
|
|||
lookForBuildFileSubstitutes: false);
|
||||
workspace ??= GnWorkspace.find(resourceProvider, rootPath);
|
||||
workspace ??=
|
||||
PackageBuildWorkspace.find(resourceProvider, packageMap, rootPath);
|
||||
workspace ??= PubWorkspace.find(resourceProvider, packageMap, rootPath);
|
||||
workspace ??= BasicWorkspace.find(resourceProvider, packageMap, rootPath);
|
||||
PackageBuildWorkspace.find(resourceProvider, packages, rootPath);
|
||||
workspace ??= PubWorkspace.find(resourceProvider, packages, rootPath);
|
||||
workspace ??= BasicWorkspace.find(resourceProvider, packages, rootPath);
|
||||
return workspace;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ class BasicWorkspace extends SimpleWorkspace {
|
|||
|
||||
BasicWorkspace._(
|
||||
ResourceProvider provider,
|
||||
Map<String, List<Folder>> packageMap,
|
||||
Packages packages,
|
||||
String root,
|
||||
) : super(provider, packageMap, root) {
|
||||
) : super(provider, packages, root) {
|
||||
_theOnlyPackage = BasicWorkspacePackage(root, this);
|
||||
}
|
||||
|
||||
|
@ -42,14 +42,14 @@ class BasicWorkspace extends SimpleWorkspace {
|
|||
/// (or [path]'s parent if [path] points to a file).
|
||||
static BasicWorkspace find(
|
||||
ResourceProvider provider,
|
||||
Map<String, List<Folder>> packageMap,
|
||||
Packages packages,
|
||||
String path,
|
||||
) {
|
||||
Resource resource = provider.getResource(path);
|
||||
if (resource is File) {
|
||||
path = resource.parent.path;
|
||||
}
|
||||
return BasicWorkspace._(provider, packageMap, path);
|
||||
return BasicWorkspace._(provider, packages, path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,8 +79,7 @@ class BasicWorkspacePackage extends WorkspacePackage {
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
|
||||
workspace.packageMap;
|
||||
Packages packagesAvailableTo(String libraryPath) => workspace.packages;
|
||||
|
||||
@override
|
||||
bool sourceIsInPublicApi(Source source) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:async';
|
|||
import 'dart:collection';
|
||||
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/summary/package_bundle_reader.dart';
|
||||
|
@ -661,8 +662,7 @@ class BazelWorkspacePackage extends WorkspacePackage {
|
|||
@override
|
||||
// TODO(brianwilkerson) Implement this by looking in the BUILD file for 'deps'
|
||||
// lists.
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
|
||||
<String, List<Folder>>{};
|
||||
Packages packagesAvailableTo(String libraryPath) => Packages.empty;
|
||||
|
||||
@override
|
||||
bool sourceIsInPublicApi(Source source) {
|
||||
|
|
|
@ -10,7 +10,6 @@ import 'package:analyzer/src/source/package_map_resolver.dart';
|
|||
import 'package:analyzer/src/summary/package_bundle_reader.dart';
|
||||
import 'package:analyzer/src/workspace/workspace.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
/// Information about a Gn workspace.
|
||||
|
@ -31,17 +30,23 @@ class GnWorkspace extends Workspace {
|
|||
@override
|
||||
final String root;
|
||||
|
||||
/// The map from a package name to the list of its `lib/` folders.
|
||||
final Map<String, List<Folder>> _packageMap;
|
||||
/// Information about packages available in the workspace.
|
||||
final Packages packages;
|
||||
|
||||
GnWorkspace._(this.provider, this.root, this._packageMap);
|
||||
GnWorkspace._(this.provider, this.root, this.packages);
|
||||
|
||||
@visibleForTesting
|
||||
Map<String, List<Folder>> get packageMap => _packageMap;
|
||||
/// TODO(scheglov) Finish switching to [packages].
|
||||
Map<String, List<Folder>> get packageMap {
|
||||
var packageMap = <String, List<Folder>>{};
|
||||
for (var package in packages.packages) {
|
||||
packageMap[package.name] = [package.libFolder];
|
||||
}
|
||||
return packageMap;
|
||||
}
|
||||
|
||||
@override
|
||||
UriResolver get packageUriResolver =>
|
||||
PackageMapUriResolver(provider, _packageMap);
|
||||
PackageMapUriResolver(provider, packageMap);
|
||||
|
||||
@override
|
||||
SourceFactory createSourceFactory(
|
||||
|
@ -113,15 +118,15 @@ class GnWorkspace extends Workspace {
|
|||
return null;
|
||||
}
|
||||
|
||||
var packageMap = <String, List<Folder>>{};
|
||||
var packageMap = <String, Package>{};
|
||||
for (var packagesFile in packagesFiles) {
|
||||
var packages = parsePackagesFile(provider, packagesFile);
|
||||
for (var package in packages.packages) {
|
||||
packageMap[package.name] = [package.libFolder];
|
||||
packageMap[package.name] = package;
|
||||
}
|
||||
}
|
||||
|
||||
return GnWorkspace._(provider, root, packageMap);
|
||||
return GnWorkspace._(provider, root, Packages(packageMap));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -229,8 +234,7 @@ class GnWorkspacePackage extends WorkspacePackage {
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
|
||||
workspace.packageMap;
|
||||
Packages packagesAvailableTo(String libraryPath) => workspace.packages;
|
||||
|
||||
@override
|
||||
bool sourceIsInPublicApi(Source source) {
|
||||
|
|
|
@ -56,6 +56,7 @@ class PackageBuildPackageUriResolver extends UriResolver {
|
|||
: _workspace = workspace,
|
||||
_context = workspace.provider.pathContext;
|
||||
|
||||
/// TODO(scheglov) Finish switching to [Packages].
|
||||
Map<String, List<Folder>> get packageMap => _workspace.packageMap;
|
||||
|
||||
@override
|
||||
|
@ -142,9 +143,8 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
/// We read it once, so that all usages return consistent results.
|
||||
final String? _pubspecContent;
|
||||
|
||||
/// The map from a package name to the list of its `lib/` folders.
|
||||
@override
|
||||
final Map<String, List<Folder>> packageMap;
|
||||
final Packages packages;
|
||||
|
||||
/// The resource provider used to access the file system.
|
||||
@override
|
||||
|
@ -172,7 +172,7 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
|
||||
PackageBuildWorkspace._(
|
||||
this.provider,
|
||||
this.packageMap,
|
||||
this.packages,
|
||||
this.root,
|
||||
this.projectPackageName,
|
||||
this.generatedRootPath,
|
||||
|
@ -188,6 +188,16 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
return _fileContentOrNull(_pubspecFile) == _pubspecContent;
|
||||
}
|
||||
|
||||
/// TODO(scheglov) Finish switching to [packages].
|
||||
@override
|
||||
Map<String, List<Folder>> get packageMap {
|
||||
var packageMap = <String, List<Folder>>{};
|
||||
for (var package in packages.packages) {
|
||||
packageMap[package.name] = [package.libFolder];
|
||||
}
|
||||
return packageMap;
|
||||
}
|
||||
|
||||
@override
|
||||
UriResolver get packageUriResolver => PackageBuildPackageUriResolver(
|
||||
this, PackageMapUriResolver(provider, packageMap));
|
||||
|
@ -200,7 +210,7 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
/// use [builtPackageSourcePath]. For `bin/`, `web/`, etc, it must be relative
|
||||
/// to the project root.
|
||||
File? builtFile(String builtPath, String packageName) {
|
||||
if (!packageMap.containsKey(packageName)) {
|
||||
if (packages[packageName] == null) {
|
||||
return null;
|
||||
}
|
||||
path.Context context = provider.pathContext;
|
||||
|
@ -289,8 +299,8 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
/// Find the package:build workspace that contains the given [filePath].
|
||||
///
|
||||
/// Return `null` if the filePath is not in a package:build workspace.
|
||||
static PackageBuildWorkspace? find(ResourceProvider provider,
|
||||
Map<String, List<Folder>> packageMap, String filePath) {
|
||||
static PackageBuildWorkspace? find(
|
||||
ResourceProvider provider, Packages packages, String filePath) {
|
||||
var startFolder = provider.getFolder(filePath);
|
||||
for (var folder in startFolder.withAncestors) {
|
||||
final File pubspec = folder.getChildAssumingFile(file_paths.pubspecYaml);
|
||||
|
@ -309,7 +319,7 @@ class PackageBuildWorkspace extends Workspace implements PubWorkspace {
|
|||
.joinAll([folder.path, ..._generatedPathParts]);
|
||||
final generatedThisPath =
|
||||
provider.pathContext.join(generatedRootPath, packageName);
|
||||
return PackageBuildWorkspace._(provider, packageMap, folder.path,
|
||||
return PackageBuildWorkspace._(provider, packages, folder.path,
|
||||
packageName, generatedRootPath, generatedThisPath, pubspec);
|
||||
} catch (_) {
|
||||
return null;
|
||||
|
@ -377,8 +387,7 @@ class PackageBuildWorkspacePackage extends WorkspacePackage
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) =>
|
||||
workspace.packageMap;
|
||||
Packages packagesAvailableTo(String libraryPath) => workspace.packages;
|
||||
|
||||
@override
|
||||
bool sourceIsInPublicApi(Source source) {
|
||||
|
|
|
@ -28,12 +28,12 @@ class PubWorkspace extends SimpleWorkspace {
|
|||
|
||||
PubWorkspace._(
|
||||
ResourceProvider provider,
|
||||
Map<String, List<Folder>> packageMap,
|
||||
Packages packages,
|
||||
String root,
|
||||
File pubspecFile,
|
||||
) : _pubspecFile = pubspecFile,
|
||||
_pubspecContent = _fileContentOrNull(pubspecFile),
|
||||
super(provider, packageMap, root) {
|
||||
super(provider, packages, root) {
|
||||
_theOnlyPackage = PubWorkspacePackage(root, this);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ class PubWorkspace extends SimpleWorkspace {
|
|||
/// Find the pub workspace that contains the given [filePath].
|
||||
static PubWorkspace? find(
|
||||
ResourceProvider provider,
|
||||
Map<String, List<Folder>> packageMap,
|
||||
Packages packages,
|
||||
String filePath,
|
||||
) {
|
||||
var start = provider.getFolder(filePath);
|
||||
|
@ -69,7 +69,7 @@ class PubWorkspace extends SimpleWorkspace {
|
|||
var pubspec = current.getChildAssumingFile(file_paths.pubspecYaml);
|
||||
if (pubspec.exists) {
|
||||
var root = current.path;
|
||||
return PubWorkspace._(provider, packageMap, root, pubspec);
|
||||
return PubWorkspace._(provider, packages, root, pubspec);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -128,10 +128,10 @@ class PubWorkspacePackage extends WorkspacePackage {
|
|||
}
|
||||
|
||||
@override
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath) {
|
||||
Packages packagesAvailableTo(String libraryPath) {
|
||||
// TODO(brianwilkerson) Consider differentiating based on whether the
|
||||
// [libraryPath] is inside the `lib` directory.
|
||||
return workspace.packageMap;
|
||||
return workspace.packages;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/source/package_map_resolver.dart';
|
||||
|
@ -15,13 +16,23 @@ abstract class SimpleWorkspace extends Workspace {
|
|||
/// The [ResourceProvider] by which paths are converted into [Resource]s.
|
||||
final ResourceProvider provider;
|
||||
|
||||
final Map<String, List<Folder>> packageMap;
|
||||
/// Information about packages available in the workspace.
|
||||
final Packages packages;
|
||||
|
||||
/// The absolute workspace root path.
|
||||
@override
|
||||
final String root;
|
||||
|
||||
SimpleWorkspace(this.provider, this.packageMap, this.root);
|
||||
SimpleWorkspace(this.provider, this.packages, this.root);
|
||||
|
||||
/// TODO(scheglov) Finish switching to [packages].
|
||||
Map<String, List<Folder>> get packageMap {
|
||||
var packageMap = <String, List<Folder>>{};
|
||||
for (var package in packages.packages) {
|
||||
packageMap[package.name] = [package.libFolder];
|
||||
}
|
||||
return packageMap;
|
||||
}
|
||||
|
||||
@override
|
||||
UriResolver get packageUriResolver =>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// 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 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/generated/sdk.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/summary/api_signature.dart';
|
||||
|
@ -92,7 +92,7 @@ abstract class WorkspacePackage {
|
|||
/// Return a map from the names of packages to the absolute and normalized
|
||||
/// path of the root of those packages for all of the packages that could
|
||||
/// validly be imported by the library with the given [libraryPath].
|
||||
Map<String, List<Folder>> packagesAvailableTo(String libraryPath);
|
||||
Packages packagesAvailableTo(String libraryPath);
|
||||
|
||||
/// Return whether [source] is located in this package's public API.
|
||||
bool sourceIsInPublicApi(Source source);
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:analyzer/dart/analysis/analysis_context.dart';
|
|||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/dart/analysis/declared_variables.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/context/source.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_builder.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_locator.dart';
|
||||
|
@ -54,7 +55,8 @@ class ContextBuilderImplTest with ResourceProviderMixin {
|
|||
|
||||
var folder = newFolder('/home/test');
|
||||
contextBuilder = ContextBuilderImpl(resourceProvider: resourceProvider);
|
||||
var workspace = BasicWorkspace.find(resourceProvider, {}, folder.path);
|
||||
var workspace =
|
||||
BasicWorkspace.find(resourceProvider, Packages.empty, folder.path);
|
||||
contextRoot = ContextRootImpl(resourceProvider, folder, workspace);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:analyzer/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/workspace/basic.dart';
|
||||
|
@ -29,7 +30,7 @@ class ContextRootTest with ResourceProviderMixin {
|
|||
void setUp() {
|
||||
rootPath = convertPath('/test/root');
|
||||
rootFolder = newFolder(rootPath);
|
||||
workspace = BasicWorkspace.find(resourceProvider, {}, rootPath);
|
||||
workspace = BasicWorkspace.find(resourceProvider, Packages.empty, rootPath);
|
||||
contextRoot = ContextRootImpl(resourceProvider, rootFolder, workspace);
|
||||
contextRoot.included.add(rootFolder);
|
||||
}
|
||||
|
@ -247,7 +248,8 @@ class ContextRootTest with ResourceProviderMixin {
|
|||
ContextRootImpl _createContextRoot(String posixPath) {
|
||||
var rootPath = convertPath(posixPath);
|
||||
var rootFolder = newFolder(rootPath);
|
||||
var workspace = BasicWorkspace.find(resourceProvider, {}, rootPath);
|
||||
var workspace =
|
||||
BasicWorkspace.find(resourceProvider, Packages.empty, rootPath);
|
||||
var contextRoot = ContextRootImpl(resourceProvider, rootFolder, workspace);
|
||||
contextRoot.included.add(rootFolder);
|
||||
return contextRoot;
|
||||
|
|
|
@ -146,9 +146,24 @@ class FileSystemStateTest with ResourceProviderMixin {
|
|||
'bbb': [getFolder('/bbb/lib')],
|
||||
};
|
||||
|
||||
var packages = Packages({
|
||||
'aaa': Package(
|
||||
name: 'aaa',
|
||||
rootFolder: newFolder('/packages/aaa'),
|
||||
libFolder: newFolder('/packages/aaa/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
'bbb': Package(
|
||||
name: 'bbb',
|
||||
rootFolder: newFolder('/packages/bbb'),
|
||||
libFolder: newFolder('/packages/bbb/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
});
|
||||
|
||||
var workspace = BasicWorkspace.find(
|
||||
resourceProvider,
|
||||
packageMap,
|
||||
packages,
|
||||
convertPath('/test'),
|
||||
);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
import 'package:analyzer/dart/analysis/analysis_context.dart';
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/dart/analysis/context_root.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver.dart';
|
||||
import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
|
||||
|
@ -49,7 +50,7 @@ class DriverBasedUriConverterTest with ResourceProviderMixin {
|
|||
]);
|
||||
|
||||
var contextRoot = ContextRootImpl(resourceProvider, barFolder,
|
||||
BasicWorkspace.find(resourceProvider, {}, barFolder.path));
|
||||
BasicWorkspace.find(resourceProvider, Packages.empty, barFolder.path));
|
||||
|
||||
MockAnalysisDriver driver = MockAnalysisDriver();
|
||||
driver.resourceProvider = resourceProvider;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// 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 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/workspace/basic.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -21,13 +22,25 @@ main() {
|
|||
class BasicWorkspacePackageTest extends WorkspacePackageTest {
|
||||
setUp() {
|
||||
newFolder('/workspace');
|
||||
|
||||
workspace = BasicWorkspace.find(
|
||||
resourceProvider,
|
||||
{
|
||||
'p1': [getFolder('/.pubcache/p1/lib')],
|
||||
'workspace': [getFolder('/workspace/lib')]
|
||||
},
|
||||
convertPath('/workspace'));
|
||||
resourceProvider,
|
||||
Packages({
|
||||
'p1': Package(
|
||||
name: 'p1',
|
||||
rootFolder: getFolder('/.pubcache/p1'),
|
||||
libFolder: getFolder('/.pubcache/p1/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
'workspace': Package(
|
||||
name: 'workspace',
|
||||
rootFolder: getFolder('/workspace'),
|
||||
libFolder: getFolder('/workspace/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
}),
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace.isBazel, isFalse);
|
||||
}
|
||||
|
||||
|
@ -78,8 +91,11 @@ class BasicWorkspacePackageTest extends WorkspacePackageTest {
|
|||
void test_packagesAvailableTo() {
|
||||
var libraryPath = convertPath('/workspace/lib/test.dart');
|
||||
var package = findPackage(libraryPath)!;
|
||||
var packageMap = package.packagesAvailableTo(libraryPath);
|
||||
expect(packageMap.keys, unorderedEquals(['p1', 'workspace']));
|
||||
var packages = package.packagesAvailableTo(libraryPath);
|
||||
expect(
|
||||
packages.packages.map((e) => e.name),
|
||||
unorderedEquals(['p1', 'workspace']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,8 +106,8 @@ class BasicWorkspaceTest with ResourceProviderMixin {
|
|||
}
|
||||
|
||||
void test_find_directory() {
|
||||
BasicWorkspace workspace =
|
||||
BasicWorkspace.find(resourceProvider, {}, convertPath('/workspace'));
|
||||
BasicWorkspace workspace = BasicWorkspace.find(
|
||||
resourceProvider, Packages.empty, convertPath('/workspace'));
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.isBazel, isFalse);
|
||||
}
|
||||
|
@ -99,13 +115,13 @@ class BasicWorkspaceTest with ResourceProviderMixin {
|
|||
void test_find_fail_notAbsolute() {
|
||||
expect(
|
||||
() => BasicWorkspace.find(
|
||||
resourceProvider, {}, convertPath('not_absolute')),
|
||||
resourceProvider, Packages.empty, convertPath('not_absolute')),
|
||||
throwsA(TypeMatcher<ArgumentError>()));
|
||||
}
|
||||
|
||||
void test_find_file() {
|
||||
BasicWorkspace workspace = BasicWorkspace.find(
|
||||
resourceProvider, {}, convertPath('/workspace/project/lib/lib1.dart'));
|
||||
BasicWorkspace workspace = BasicWorkspace.find(resourceProvider,
|
||||
Packages.empty, convertPath('/workspace/project/lib/lib1.dart'));
|
||||
expect(workspace.root, convertPath('/workspace/project/lib'));
|
||||
expect(workspace.isBazel, isFalse);
|
||||
}
|
||||
|
|
|
@ -883,9 +883,9 @@ class BazelWorkspacePackageTest with ResourceProviderMixin {
|
|||
|
||||
void test_packagesAvailableTo() {
|
||||
_setUpPackage();
|
||||
var packageMap = package
|
||||
?.packagesAvailableTo(convertPath('/ws/some/code/lib/code.dart'));
|
||||
expect(packageMap, isEmpty);
|
||||
var path = convertPath('/ws/some/code/lib/code.dart');
|
||||
var packages = package?.packagesAvailableTo(path);
|
||||
expect(packages?.packages, isEmpty);
|
||||
}
|
||||
|
||||
/// Create new files and directories from [paths].
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
// 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 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/workspace/gn.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -97,8 +99,11 @@ class GnWorkspacePackageTest with ResourceProviderMixin {
|
|||
newFile('/ws/some/code/BUILD.gn', '');
|
||||
var libraryPath = newFile('/ws/some/code/lib/code.dart', '').path;
|
||||
var package = workspace.findPackageFor(libraryPath)!;
|
||||
var packageMap = package.packagesAvailableTo(libraryPath);
|
||||
expect(packageMap.keys, unorderedEquals(['p1', 'workspace']));
|
||||
var packages = package.packagesAvailableTo(libraryPath);
|
||||
expect(
|
||||
packages.packages.map((e) => e.name),
|
||||
unorderedEquals(['p1', 'workspace']),
|
||||
);
|
||||
}
|
||||
|
||||
GnWorkspace _buildStandardGnWorkspace() {
|
||||
|
@ -194,9 +199,15 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 1);
|
||||
expect(workspace.packageMap['flutter']![0].path,
|
||||
convertPath("$packageLocation/lib"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'flutter',
|
||||
rootFolder: getFolder(packageLocation),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_packages_absoluteBuildDir() {
|
||||
|
@ -223,9 +234,15 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 1);
|
||||
expect(workspace.packageMap['flutter']![0].path,
|
||||
convertPath("$packageLocation/lib"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'flutter',
|
||||
rootFolder: getFolder(packageLocation),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_packages_fallbackBuildDir() {
|
||||
|
@ -250,9 +267,15 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 1);
|
||||
expect(workspace.packageMap['flutter']![0].path,
|
||||
convertPath("$packageLocation/lib"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'flutter',
|
||||
rootFolder: getFolder(packageLocation),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_packages_fallbackBuildDirWithUselessConfig() {
|
||||
|
@ -278,9 +301,15 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 1);
|
||||
expect(workspace.packageMap['flutter']![0].path,
|
||||
convertPath("$packageLocation/lib"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'flutter',
|
||||
rootFolder: getFolder(packageLocation),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_packages_multipleCandidates() {
|
||||
|
@ -323,9 +352,16 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 1);
|
||||
expect(workspace.packageMap['rettulf']![0].path,
|
||||
convertPath("$otherPackageLocation/lib2"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'rettulf',
|
||||
rootFolder: getFolder(otherPackageLocation),
|
||||
libFolder: getFolder('$otherPackageLocation/lib2'),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
void test_packages_multipleFiles() {
|
||||
|
@ -368,10 +404,48 @@ class GnWorkspaceTest with ResourceProviderMixin {
|
|||
var workspace = GnWorkspace.find(
|
||||
resourceProvider, convertPath('/workspace/some/code'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
expect(workspace.packageMap.length, 2);
|
||||
expect(workspace.packageMap['flutter']![0].path,
|
||||
convertPath("$packageOneLocation/one/lib"));
|
||||
expect(workspace.packageMap['rettulf']![0].path,
|
||||
convertPath("$packageTwoLocation/two/lib"));
|
||||
expect(
|
||||
workspace.packages.packages,
|
||||
unorderedEquals([
|
||||
_PackageMatcher(
|
||||
name: 'flutter',
|
||||
rootFolder: getFolder(packageOneLocation),
|
||||
libFolder: getFolder('$packageOneLocation/one/lib'),
|
||||
),
|
||||
_PackageMatcher(
|
||||
name: 'rettulf',
|
||||
rootFolder: getFolder(packageTwoLocation),
|
||||
libFolder: getFolder('$packageTwoLocation/two/lib'),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PackageMatcher extends Matcher {
|
||||
final String name;
|
||||
final Folder rootFolder;
|
||||
final Folder libFolder;
|
||||
|
||||
_PackageMatcher({
|
||||
required this.name,
|
||||
required this.rootFolder,
|
||||
Folder? libFolder,
|
||||
}) : libFolder = libFolder ?? rootFolder.getChildAssumingFolder('lib');
|
||||
|
||||
@override
|
||||
Description describe(Description description) => description
|
||||
.add('Package(name:')
|
||||
.addDescriptionOf(name)
|
||||
.add(', rootFolder:')
|
||||
.addDescriptionOf(rootFolder.path)
|
||||
.add(')');
|
||||
|
||||
@override
|
||||
bool matches(Object? item, Map matchState) {
|
||||
return item is Package &&
|
||||
item.name == name &&
|
||||
item.rootFolder == rootFolder &&
|
||||
item.libFolder == libFolder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/file_system/file_system.dart';
|
||||
import 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/generated/source.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/workspace/package_build.dart';
|
||||
|
@ -52,9 +53,14 @@ class PackageBuildFileUriResolverTest with ResourceProviderMixin {
|
|||
|
||||
workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{
|
||||
'project': [getFolder('/workspace')]
|
||||
},
|
||||
Packages({
|
||||
'project': Package(
|
||||
name: 'project',
|
||||
rootFolder: getFolder('/workspace'),
|
||||
libFolder: getFolder('/workspace'),
|
||||
languageVersion: null,
|
||||
),
|
||||
}),
|
||||
convertPath('/workspace'),
|
||||
)!;
|
||||
resolver = PackageBuildFileUriResolver(workspace);
|
||||
|
@ -191,9 +197,14 @@ class PackageBuildPackageUriResolverTest with ResourceProviderMixin {
|
|||
}
|
||||
workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{
|
||||
'project': [getFolder('/workspace')]
|
||||
},
|
||||
Packages({
|
||||
'project': Package(
|
||||
name: 'project',
|
||||
rootFolder: getFolder('/workspace'),
|
||||
libFolder: getFolder('/workspace'),
|
||||
languageVersion: null,
|
||||
),
|
||||
}),
|
||||
convertPath(workspacePath),
|
||||
)!;
|
||||
packageUriResolver = MockUriResolver();
|
||||
|
@ -240,10 +251,20 @@ class PackageBuildWorkspacePackageTest with ResourceProviderMixin {
|
|||
|
||||
myWorkspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{
|
||||
'my': [getFolder(myPackageLibPath)],
|
||||
'foo': [getFolder(fooPackageLibPath)],
|
||||
},
|
||||
Packages({
|
||||
'my': Package(
|
||||
name: 'my',
|
||||
rootFolder: getFolder(myPackageRootPath),
|
||||
libFolder: getFolder(myPackageLibPath),
|
||||
languageVersion: null,
|
||||
),
|
||||
'foo': Package(
|
||||
name: 'foo',
|
||||
rootFolder: getFolder(fooPackageRootPath),
|
||||
libFolder: getFolder(fooPackageLibPath),
|
||||
languageVersion: null,
|
||||
),
|
||||
}),
|
||||
convertPath(myPackageRootPath),
|
||||
)!;
|
||||
|
||||
|
@ -423,7 +444,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
() {
|
||||
return PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('not_absolute'),
|
||||
);
|
||||
},
|
||||
|
@ -440,7 +461,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace/aaa/lib'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -451,7 +472,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
)!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
|
@ -465,7 +486,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace/opened/up/a/child/dir'),
|
||||
)!;
|
||||
expect(workspace.root, convertPath('/workspace/opened/up/a/child/dir'));
|
||||
|
@ -479,7 +500,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace/opened/up/a/child/dir'),
|
||||
)!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
|
@ -492,7 +513,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -502,7 +523,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newFolder('/workspace/.dart_tool/build/generated/project/lib');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -514,7 +535,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -525,7 +546,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'not: yaml: here! 1111');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -539,7 +560,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace/aaa/lib'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -549,7 +570,7 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
{},
|
||||
Packages.empty,
|
||||
convertPath('/workspace'),
|
||||
);
|
||||
expect(workspace, isNull);
|
||||
|
@ -649,14 +670,19 @@ class PackageBuildWorkspaceTest with ResourceProviderMixin {
|
|||
|
||||
PackageBuildWorkspace _createWorkspace(
|
||||
String root, List<String> packageNames) {
|
||||
var packageMap = <String, Package>{};
|
||||
for (var name in packageNames) {
|
||||
packageMap[name] = Package(
|
||||
name: name,
|
||||
rootFolder: getFolder('/packages/$name'),
|
||||
libFolder: getFolder('/packages/$name/lib'),
|
||||
languageVersion: null,
|
||||
);
|
||||
}
|
||||
|
||||
return PackageBuildWorkspace.find(
|
||||
resourceProvider,
|
||||
Map.fromIterables(
|
||||
packageNames,
|
||||
packageNames.map(
|
||||
(name) => [getFolder('/packages/$name/lib')],
|
||||
),
|
||||
),
|
||||
Packages(packageMap),
|
||||
convertPath(root),
|
||||
)!;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// 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 'package:analyzer/src/context/packages.dart';
|
||||
import 'package:analyzer/src/test_utilities/resource_provider_mixin.dart';
|
||||
import 'package:analyzer/src/workspace/pub.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
@ -22,12 +23,23 @@ class PubWorkspacePackageTest extends WorkspacePackageTest {
|
|||
setUp() {
|
||||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
workspace = PubWorkspace.find(
|
||||
resourceProvider,
|
||||
{
|
||||
'p1': [getFolder('/.pubcache/p1/lib')],
|
||||
'workspace': [getFolder('/workspace/lib')]
|
||||
},
|
||||
convertPath('/workspace'))!;
|
||||
resourceProvider,
|
||||
Packages({
|
||||
'p1': Package(
|
||||
name: 'p1',
|
||||
rootFolder: getFolder('/.pubcache/p1'),
|
||||
libFolder: getFolder('/.pubcache/p1/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
'workspace': Package(
|
||||
name: 'workspace',
|
||||
rootFolder: getFolder('/workspace'),
|
||||
libFolder: getFolder('/workspace/lib'),
|
||||
languageVersion: null,
|
||||
),
|
||||
}),
|
||||
convertPath('/workspace'),
|
||||
)!;
|
||||
expect(workspace.isBazel, isFalse);
|
||||
}
|
||||
|
||||
|
@ -77,8 +89,11 @@ class PubWorkspacePackageTest extends WorkspacePackageTest {
|
|||
void test_packagesAvailableTo() {
|
||||
var libraryPath = convertPath('/workspace/lib/test.dart');
|
||||
var package = findPackage(libraryPath)!;
|
||||
var packageMap = package.packagesAvailableTo(libraryPath);
|
||||
expect(packageMap.keys, unorderedEquals(['p1', 'workspace']));
|
||||
var packages = package.packagesAvailableTo(libraryPath);
|
||||
expect(
|
||||
packages.packages.map((e) => e.name),
|
||||
unorderedEquals(['p1', 'workspace']),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,8 +101,8 @@ class PubWorkspacePackageTest extends WorkspacePackageTest {
|
|||
class PubWorkspaceTest with ResourceProviderMixin {
|
||||
void test_find_directory() {
|
||||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace =
|
||||
PubWorkspace.find(resourceProvider, {}, convertPath('/workspace'))!;
|
||||
var workspace = PubWorkspace.find(
|
||||
resourceProvider, Packages.empty, convertPath('/workspace'))!;
|
||||
expect(workspace.isBazel, isFalse);
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
}
|
||||
|
@ -95,27 +110,27 @@ class PubWorkspaceTest with ResourceProviderMixin {
|
|||
void test_find_fail_notAbsolute() {
|
||||
expect(
|
||||
() => PubWorkspace.find(
|
||||
resourceProvider, {}, convertPath('not_absolute')),
|
||||
resourceProvider, Packages.empty, convertPath('not_absolute')),
|
||||
throwsA(TypeMatcher<ArgumentError>()));
|
||||
}
|
||||
|
||||
void test_find_file() {
|
||||
newPubspecYamlFile('/workspace', 'name: project');
|
||||
var workspace = PubWorkspace.find(
|
||||
resourceProvider, {}, convertPath('/workspace/lib/lib1.dart'))!;
|
||||
var workspace = PubWorkspace.find(resourceProvider, Packages.empty,
|
||||
convertPath('/workspace/lib/lib1.dart'))!;
|
||||
expect(workspace.root, convertPath('/workspace'));
|
||||
}
|
||||
|
||||
void test_find_missingPubspec() {
|
||||
var workspace = PubWorkspace.find(
|
||||
resourceProvider, {}, convertPath('/workspace/lib/lib1.dart'));
|
||||
var workspace = PubWorkspace.find(resourceProvider, Packages.empty,
|
||||
convertPath('/workspace/lib/lib1.dart'));
|
||||
expect(workspace, isNull);
|
||||
}
|
||||
|
||||
void test_isConsistentWithFileSystem() {
|
||||
newPubspecYamlFile('/workspace', 'name: my');
|
||||
var workspace =
|
||||
PubWorkspace.find(resourceProvider, {}, convertPath('/workspace'))!;
|
||||
var workspace = PubWorkspace.find(
|
||||
resourceProvider, Packages.empty, convertPath('/workspace'))!;
|
||||
expect(workspace.isConsistentWithFileSystem, isTrue);
|
||||
|
||||
newPubspecYamlFile('/workspace', 'name: my2');
|
||||
|
|
Loading…
Reference in a new issue