diff --git a/sky/engine/tonic/parsers/BUILD.gn b/sky/engine/tonic/parsers/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..1a5772367cec075d64ab09f34e6f00e8fa75aef1 --- /dev/null +++ b/sky/engine/tonic/parsers/BUILD.gn @@ -0,0 +1,10 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +source_set("parsers") { + sources = [ + "packages_map.cc", + "packages_map.h", + ] +} diff --git a/sky/engine/tonic/parsers/packages_map.cc b/sky/engine/tonic/parsers/packages_map.cc new file mode 100644 index 0000000000000000000000000000000000000000..44ced264271b15e08097a3ee99ce8d7666ccb7f9 --- /dev/null +++ b/sky/engine/tonic/parsers/packages_map.cc @@ -0,0 +1,89 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Spec: https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md + +#include "sky/engine/tonic/parsers/packages_map.h" + +#include + +namespace tonic { +namespace { + +bool isLineBreak(char c) { + return c == '\r' || c == '\n'; +} + +} // namespace + +PackagesMap::PackagesMap() { +} + +PackagesMap::~PackagesMap() { +} + +bool PackagesMap::Parse(const std::string& source, std::string* error) { + map_.clear(); + const auto end = source.end(); + for (auto it = source.begin(); it != end; ++it) { + const char c = *it; + + // Skip blank lines. + if (isLineBreak(c)) + continue; + + // Skip comments. + if (c == '#') { + while (it != end && !isLineBreak(*it)) + ++it; + continue; + } + + if (c == ':') { + map_.clear(); + *error = "Packages file contains a line that begins with ':'."; + return false; + } + + auto package_name_begin = it; + auto package_name_end = end; + bool found_separator = false; + for ( ; it != end; ++it) { + const char c = *it; + if (c == ':' && !found_separator) { + found_separator = true; + package_name_end = it; + continue; + } + if (isLineBreak(c)) + break; + } + + if (!found_separator) { + map_.clear(); + *error = "Packages file contains non-comment line that lacks a ':'."; + return false; + } + + std::string package_name(package_name_begin, package_name_end); + std::string package_path(package_name_end + 1, it); + + auto result = map_.emplace(package_name, package_path); + if (!result.second) { + map_.clear(); + *error = std::string( + "Packages file contains multiple entries for package '") + + package_name + "'."; + return false; + } + } + + return true; +} + +std::string PackagesMap::Resolve(const std::string& package_name) { + return map_[package_name]; +} + +} // namespace tonic diff --git a/sky/engine/tonic/parsers/packages_map.h b/sky/engine/tonic/parsers/packages_map.h new file mode 100644 index 0000000000000000000000000000000000000000..66aa3cad0ddff0122092aa8fbbaee33c4bfc2bb1 --- /dev/null +++ b/sky/engine/tonic/parsers/packages_map.h @@ -0,0 +1,27 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKY_ENGINE_TONIC_PARSERS_PACKAGES_MAP_H_ +#define SKY_ENGINE_TONIC_PARSERS_PACKAGES_MAP_H_ + +#include +#include + +namespace tonic { + +class PackagesMap { + public: + PackagesMap(); + ~PackagesMap(); + + bool Parse(const std::string& source, std::string* error); + std::string Resolve(const std::string& package_name); + + private: + std::unordered_map map_; +}; + +} // namespace tonic + +#endif // SKY_ENGINE_TONIC_PARSERS_PACKAGES_MAP_H_ diff --git a/sky/tools/sky_snapshot/BUILD.gn b/sky/tools/sky_snapshot/BUILD.gn index 81d20a68f62bdc76187abf0b8931972c2bcd2551..b87eb314dca3d546cfd282312ce05ea5398c4578 100644 --- a/sky/tools/sky_snapshot/BUILD.gn +++ b/sky/tools/sky_snapshot/BUILD.gn @@ -21,6 +21,7 @@ executable("sky_snapshot") { "//dart/runtime/vm:libdart_platform", "//dart/runtime:libdart", "//sky/engine/bindings:snapshot_cc", + "//sky/engine/tonic/parsers", "//third_party/zlib", ] diff --git a/sky/tools/sky_snapshot/loader.cc b/sky/tools/sky_snapshot/loader.cc index ba19fa67c8e47e51a67510fd533580a70cdedf05..5d03b3bc72e964e359d4258ebb1c28ff4f819123 100644 --- a/sky/tools/sky_snapshot/loader.cc +++ b/sky/tools/sky_snapshot/loader.cc @@ -12,6 +12,7 @@ #include "sky/tools/sky_snapshot/logging.h" #include "sky/tools/sky_snapshot/scope.h" #include "sky/tools/sky_snapshot/switches.h" +#include "sky/engine/tonic/parsers/packages_map.h" namespace { @@ -34,7 +35,9 @@ base::FilePath SimplifyPath(const base::FilePath& path) { class Loader { public: - Loader(const base::FilePath& package_root); + Loader(); + + void LoadPackagesMap(const base::FilePath& packages); const std::set& dependencies() const { return dependencies_; } @@ -44,20 +47,60 @@ class Loader { Dart_Handle Import(Dart_Handle url); Dart_Handle Source(Dart_Handle library, Dart_Handle url); + void set_package_root(const base::FilePath& package_root) { + package_root_ = package_root; + } + private: std::set dependencies_; + base::FilePath packages_; base::FilePath package_root_; + std::unique_ptr packages_map_; DISALLOW_COPY_AND_ASSIGN(Loader); }; -Loader::Loader(const base::FilePath& package_root) - : package_root_(package_root) { +Loader::Loader() { +} + +void Loader::LoadPackagesMap(const base::FilePath& packages) { + packages_ = base::MakeAbsoluteFilePath(packages); + dependencies_.insert(packages_.AsUTF8Unsafe()); + std::string packages_source; + if (!base::ReadFileToString(packages, &packages_source)) { + fprintf(stderr, "error: Unable to load .packages file '%s'.\n", + packages.AsUTF8Unsafe().c_str()); + exit(1); + } + packages_map_.reset(new tonic::PackagesMap()); + std::string error; + if (!packages_map_->Parse(packages_source, &error)) { + fprintf(stderr, "error: Unable to parse .packages file '%s'.\n%s\n", + packages.AsUTF8Unsafe().c_str(), error.c_str()); + exit(1); + } } std::string Loader::CanonicalizePackageURL(std::string url) { DCHECK(base::StartsWithASCII(url, "package:", true)); base::ReplaceFirstSubstringAfterOffset(&url, 0, "package:", ""); + if (packages_map_) { + size_t slash = url.find('/'); + if (slash == std::string::npos) + return std::string(); + std::string package = url.substr(0, slash); + std::string library_path = url.substr(slash + 1); + std::string package_path = packages_map_->Resolve(package); + if (package_path.empty()) + return std::string(); + if (base::StartsWithASCII(package_path, "file://", true)) { + base::ReplaceFirstSubstringAfterOffset(&package_path, 0, "file://", ""); + return package_path + library_path; + } else { + auto path = packages_.DirName().Append(package_path).Append(library_path); + return SimplifyPath(path).AsUTF8Unsafe(); + } + } return package_root_.Append(url).AsUTF8Unsafe(); } @@ -103,10 +146,18 @@ Loader* g_loader = nullptr; Loader& GetLoader() { if (!g_loader) { base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); - CHECK(command_line.HasSwitch(switches::kPackageRoot)) - << "Need --package-root"; - g_loader = - new Loader(command_line.GetSwitchValuePath(switches::kPackageRoot)); + g_loader = new Loader(); + if (command_line.HasSwitch(switches::kPackages)) { + g_loader->LoadPackagesMap( + command_line.GetSwitchValuePath(switches::kPackages)); + + } else if (command_line.HasSwitch(switches::kPackageRoot)) { + g_loader->set_package_root( + command_line.GetSwitchValuePath(switches::kPackageRoot)); + } else { + fprintf(stderr, "error: Need either --packages or --package-root.\n"); + exit(1); + } } return *g_loader; } diff --git a/sky/tools/sky_snapshot/main.cc b/sky/tools/sky_snapshot/main.cc index 8db8a56833b38fad17c5e088d1f9a3eb4bf02258..0ee81d2e66fd243f8e61141a8c71948d62c7127e 100644 --- a/sky/tools/sky_snapshot/main.cc +++ b/sky/tools/sky_snapshot/main.cc @@ -19,10 +19,15 @@ #include "sky/tools/sky_snapshot/vm.h" void Usage() { - std::cerr << "Usage: sky_snapshot" - << " --" << switches::kPackageRoot << " --" << switches::kSnapshot - << " --" << switches::kDepfile << " --" << switches::kBuildOutput - << " " << std::endl; + std::cerr << R"USAGE(usage: sky_snapshot --packages=PACKAGES --snapshot=SNAPSHOT_BLOB + [ --depfile=DEPS_FILE ] [ --build-output=BUILD_OUTPUT ] [ --help ] + + * PACKAGES is the '.packages' file that defines where to find Dart packages. + * SNAPSHOT_BLOB is the file to write the snapshot into. + * DEPS_FILE is an optional '.d' file to depedendency information into. + * BUILD_OUTPUT optionally overrides the target name used in the DEPS_FILE. + (The default is SNAPSHOT_BLOB.) +)USAGE"; } void WriteSnapshot(base::FilePath path) { @@ -68,6 +73,11 @@ int main(int argc, const char* argv[]) { return 0; } + if (!command_line.HasSwitch(switches::kSnapshot)) { + fprintf(stderr, "error: Need --snapshot.\n"); + exit(1); + } + InitDartVM(); Dart_Isolate isolate = CreateDartIsolate(); CHECK(isolate); @@ -81,7 +91,7 @@ int main(int argc, const char* argv[]) { CHECK(!LogIfError(Dart_FinalizeLoading(true))); - CHECK(command_line.HasSwitch(switches::kSnapshot)) << "Need --snapshot"; + CHECK(command_line.HasSwitch(switches::kSnapshot)); WriteSnapshot(command_line.GetSwitchValuePath(switches::kSnapshot)); if (command_line.HasSwitch(switches::kDepfile)) { diff --git a/sky/tools/sky_snapshot/switches.cc b/sky/tools/sky_snapshot/switches.cc index b2d67e48761acaa36859a5ad948114ae0c4d266c..9e95187d7510ec5fb291f5210a1bfb8e57c043f0 100644 --- a/sky/tools/sky_snapshot/switches.cc +++ b/sky/tools/sky_snapshot/switches.cc @@ -9,6 +9,7 @@ namespace switches { const char kBuildOutput[] = "build-output"; const char kDepfile[] = "depfile"; const char kHelp[] = "help"; +const char kPackages[] = "packages"; const char kPackageRoot[] = "package-root"; const char kSnapshot[] = "snapshot"; diff --git a/sky/tools/sky_snapshot/switches.h b/sky/tools/sky_snapshot/switches.h index 121a6168c29f9ee0cf1ae1755df19db91b957bf5..ee67ca33ab3594bd24d64e04cf41fb5c910922d0 100644 --- a/sky/tools/sky_snapshot/switches.h +++ b/sky/tools/sky_snapshot/switches.h @@ -10,6 +10,7 @@ namespace switches { extern const char kBuildOutput[]; extern const char kDepfile[]; extern const char kHelp[]; +extern const char kPackages[]; extern const char kPackageRoot[]; extern const char kSnapshot[];