[ CLI ] Fix snapshot detection logic for google3

google3 makes heavy use of symlinks, with no guarantee that the relative
location of files with respect to each other will be maintained after
the symlinks are resolved. This causes issues when trying to locate the
DartDev snapshot using the VM executables resolved path as a base.

This change updates the DartDev snapshot detection logic to first try to
find the snapshot using the resolved executable path before falling back
to using the unresolved path used to launch the VM (e.g., the path
specified by argv[0]).

TEST=pkg/dartdev/test/

Change-Id: I19a41c440ac82cbc671dafb3bda23a31fb4cdc0c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370000
Reviewed-by: Derek Xu <derekx@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
This commit is contained in:
Ben Konyi
2024-06-06 19:10:19 +00:00
committed by Commit Queue
parent cf0646d4c3
commit 8e00ebc689
5 changed files with 74 additions and 34 deletions
+29 -14
View File
@@ -30,7 +30,7 @@ class Sdk {
// Assume that we want to use the same Dart executable that we used to spawn
// DartDev. We should be able to run programs with out/ReleaseX64/dart even
// if the SDK isn't completely built.
String get dart => Platform.resolvedExecutable;
String get dart => Platform.executable;
String get dartAotRuntime => _runFromBuildRoot
? path.absolute(
@@ -149,22 +149,37 @@ class Sdk {
static Sdk _createSingleton() {
// Find SDK path.
(String, bool)? trySDKPath(String executablePath) {
// The common case, and how cli_util.dart computes the Dart SDK directory,
// [path.dirname] called twice on Platform.executable. We confirm by
// asserting that the directory `./bin/snapshots/` exists in this directory:
var sdkPath = path.absolute(path.dirname(path.dirname(executablePath)));
var snapshotsDir = path.join(sdkPath, 'bin', 'snapshots');
var runFromBuildRoot = false;
if (!Directory(snapshotsDir).existsSync()) {
// This is the less common case where the user is in
// the checked out Dart SDK, and is executing `dart` via:
// ./out/ReleaseX64/dart ... or in google3.
sdkPath = path.absolute(path.dirname(executablePath));
snapshotsDir = sdkPath;
runFromBuildRoot = true;
}
// The common case, and how cli_util.dart computes the Dart SDK directory,
// [path.dirname] called twice on Platform.resolvedExecutable. We confirm by
// asserting that the directory `./bin/snapshots/` exists in this directory:
var sdkPath =
path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable)));
var snapshotsDir = path.join(sdkPath, 'bin', 'snapshots');
var runFromBuildRoot = false;
if (!Directory(snapshotsDir).existsSync()) {
// This is the less common case where the user is in
// the checked out Dart SDK, and is executing `dart` via:
// ./out/ReleaseX64/dart ... or in google3.
sdkPath = path.absolute(path.dirname(Platform.resolvedExecutable));
runFromBuildRoot = true;
// Try to locate the DartDev snapshot to determine if we're able to find
// the SDK snapshots with this SDK path. This is meant to handle
// non-standard SDK layouts that can involve symlinks (e.g., Brew
// installations, google3 tests, etc).
if (!File(path.join(snapshotsDir, 'dartdev.dart.snapshot'))
.existsSync()) {
return null;
}
return (sdkPath, runFromBuildRoot);
}
final (sdkPath, runFromBuildRoot) =
trySDKPath(Platform.resolvedExecutable) ??
trySDKPath(Platform.executable)!;
// Defer to [Runtime] for the version.
var version = Runtime.runtime.version;
+28 -16
View File
@@ -80,25 +80,37 @@ bool DartDevIsolate::ShouldParseCommand(const char* script_uri) {
}
CStringUniquePtr DartDevIsolate::TryResolveArtifactPath(const char* filename) {
// |dir_prefix| includes the last path separator.
auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();
auto try_resolve_path = [&](CStringUniquePtr dir_prefix) {
// First assume we're in dart-sdk/bin.
char* snapshot_path =
Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename);
if (File::Exists(nullptr, snapshot_path)) {
return CStringUniquePtr(snapshot_path);
}
free(snapshot_path);
// First assume we're in dart-sdk/bin.
char* snapshot_path =
Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename);
if (File::Exists(nullptr, snapshot_path)) {
return CStringUniquePtr(snapshot_path);
}
free(snapshot_path);
// If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
// directories. Try to use a snapshot from a previously built SDK.
snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename);
if (File::Exists(nullptr, snapshot_path)) {
return CStringUniquePtr(snapshot_path);
}
free(snapshot_path);
return CStringUniquePtr(nullptr);
};
// If we're not in dart-sdk/bin, we might be in one of the $SDK/out/*
// directories. Try to use a snapshot from a previously built SDK.
snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename);
if (File::Exists(nullptr, snapshot_path)) {
return CStringUniquePtr(snapshot_path);
// Try to find the artifact using the resolved EXE path first. This can fail
// if the Dart SDK file structure is faked using symlinks and the actual
// artifacts are spread across directories on the file system (e.g., some
// google3 execution environments).
auto result =
try_resolve_path(EXEUtils::GetDirectoryPrefixFromResolvedExeName());
if (result == nullptr) {
result =
try_resolve_path(EXEUtils::GetDirectoryPrefixFromUnresolvedExeName());
}
free(snapshot_path);
return CStringUniquePtr(nullptr);
return result;
}
CStringUniquePtr DartDevIsolate::TryResolveDartDevSnapshotPath() {
+1 -1
View File
@@ -101,7 +101,7 @@ void DFE::InitKernelServiceAndPlatformDills() {
}
// |dir_prefix| includes the last path separator.
auto dir_prefix = EXEUtils::GetDirectoryPrefixFromExeName();
auto dir_prefix = EXEUtils::GetDirectoryPrefixFromResolvedExeName();
// Look for the frontend snapshot next to the executable.
frontend_filename_ =
+7 -1
View File
@@ -65,7 +65,7 @@ static const char* GetFileNameFromPath(const char* path) {
return path;
}
CStringUniquePtr EXEUtils::GetDirectoryPrefixFromExeName() {
CStringUniquePtr EXEUtils::GetDirectoryPrefixFromResolvedExeName() {
const char* name = nullptr;
const int kTargetSize = PATH_MAX;
char target[kTargetSize];
@@ -119,6 +119,12 @@ CStringUniquePtr EXEUtils::GetDirectoryPrefixFromExeName() {
return CStringUniquePtr(result == nullptr ? Utils::StrDup("") : result);
}
CStringUniquePtr EXEUtils::GetDirectoryPrefixFromUnresolvedExeName() {
const char* exe = Platform::GetExecutableName();
return CStringUniquePtr(exe == nullptr ? nullptr
: GetDirectoryFromPath(exe, nullptr));
}
#if !defined(DART_HOST_OS_WINDOWS)
void EXEUtils::LoadDartProfilerSymbols(const char* argv0) {
char* path = reinterpret_cast<char*>(malloc(PATH_MAX + 5));
+9 -2
View File
@@ -17,8 +17,15 @@ namespace bin {
class EXEUtils {
public:
// Returns the path to the directory the current executable resides in.
static CStringUniquePtr GetDirectoryPrefixFromExeName();
// Returns the resolved path to the directory the current executable resides
// in.
static CStringUniquePtr GetDirectoryPrefixFromResolvedExeName();
// Returns the path to the directory the current executable resides
// in without following symlinks.
//
// Returns null if Platform::GetExecutableName() returns null.
static CStringUniquePtr GetDirectoryPrefixFromUnresolvedExeName();
#if !defined(DART_HOST_OS_WINDOWS)
// Loads a compact symbolization table from "$exepath.sym" that is used by the