Commit 852bc07c authored by Brett Wilson's avatar Brett Wilson

Recursively load mojo packages

Adds simple manifest file parsing to the package downloader, and recursively schedule loading dependencies of a package.

R=ben@chromium.org

Review URL: https://codereview.chromium.org/600683002

Cr-Commit-Position: refs/heads/master@{#296471}
parent b58d114a
...@@ -36,14 +36,12 @@ ...@@ -36,14 +36,12 @@
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
namespace base { namespace base {
class Value; class Value;
namespace internal { namespace internal {
class JSONParser; class JSONParser;
} }
}
namespace base {
enum JSONParserOptions { enum JSONParserOptions {
// Parses the input strictly according to RFC 4627, except for where noted // Parses the input strictly according to RFC 4627, except for where noted
......
...@@ -6,6 +6,8 @@ shared_library("package_manager") { ...@@ -6,6 +6,8 @@ shared_library("package_manager") {
output_name = "mojo_package_manager" output_name = "mojo_package_manager"
sources = [ sources = [
"manifest.cc",
"manifest.h",
"package_fetcher.cc", "package_fetcher.cc",
"package_fetcher.h", "package_fetcher.h",
"package_manager.cc", "package_manager.cc",
......
// Copyright 2014 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.
#include "mojo/tools/package_manager/manifest.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "url/gurl.h"
namespace mojo {
Manifest::Manifest() {
}
Manifest::~Manifest() {
}
bool Manifest::Parse(const std::string& str, std::string* err_msg) {
int err_code = base::JSONReader::JSON_NO_ERROR;
scoped_ptr<base::Value> root(base::JSONReader::ReadAndReturnError(
str,
base::JSON_ALLOW_TRAILING_COMMAS,
&err_code, err_msg));
if (err_code != base::JSONReader::JSON_NO_ERROR)
return false;
const base::DictionaryValue* root_dict;
if (!root->GetAsDictionary(&root_dict)) {
*err_msg = "Manifest is not a dictionary.";
return false;
}
if (!PopulateDeps(root_dict, err_msg))
return false;
return true;
}
bool Manifest::ParseFromFile(const base::FilePath& file_name,
std::string* err_msg) {
std::string data;
if (!base::ReadFileToString(file_name, &data)) {
*err_msg = "Couldn't read manifest file " + file_name.AsUTF8Unsafe();
return false;
}
return Parse(data, err_msg);
}
bool Manifest::PopulateDeps(const base::DictionaryValue* root,
std::string* err_msg) {
const base::Value* deps_value;
if (!root->Get("deps", &deps_value))
return true; // No deps, that's OK.
const base::ListValue* deps;
if (!deps_value->GetAsList(&deps)) {
*err_msg = "Deps is not a list. Should be \"deps\": [ \"...\", \"...\" ]";
return false;
}
deps_.reserve(deps->GetSize());
for (size_t i = 0; i < deps->GetSize(); i++) {
std::string cur_dep;
if (!deps->GetString(i, &cur_dep)) {
*err_msg = "Dependency list item wasn't a string.";
return false;
}
GURL cur_url(cur_dep);
if (!cur_url.is_valid()) {
*err_msg = "Dependency entry isn't a valid URL: " + cur_dep;
return false;
}
deps_.push_back(cur_url);
}
return true;
}
} // namespace mojo
// Copyright 2014 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 MOJO_TOOLS_PACKAGE_MANAGER_MANIFEST_H_
#define MOJO_TOOLS_PACKAGE_MANAGER_MANIFEST_H_
#include <string>
#include <vector>
#include "mojo/public/cpp/system/macros.h"
class GURL;
namespace base {
class DictionaryValue;
class FilePath;
}
namespace mojo {
class Manifest {
public:
Manifest();
~Manifest();
// Parses the manifest from raw data. Returns true on success. On failure,
// populates the "err_msg" string with an error.
bool Parse(const std::string& str, std::string* err_msg);
// Like Parse but reads the data from a file.
bool ParseFromFile(const base::FilePath& file_name, std::string* err_msg);
const std::vector<GURL>& deps() const { return deps_; }
private:
bool PopulateDeps(const base::DictionaryValue* root, std::string* err_msg);
std::vector<GURL> deps_;
MOJO_DISALLOW_COPY_AND_ASSIGN(Manifest);
};
} // namespace mojo
#endif // MOJO_TOOLS_PACKAGE_MANAGER_MANIFEST_H_
...@@ -5,12 +5,21 @@ ...@@ -5,12 +5,21 @@
#include "mojo/tools/package_manager/package_manager_application.h" #include "mojo/tools/package_manager/package_manager_application.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "mojo/tools/package_manager/manifest.h"
#include "mojo/tools/package_manager/unpacker.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "mojo/public/cpp/application/application_impl.h" #include "mojo/public/cpp/application/application_impl.h"
namespace mojo { namespace mojo {
namespace {
const base::FilePath::CharType kManifestFileName[] =
FILE_PATH_LITERAL("manifest.json");
} // namespace
PackageManagerApplication::PendingLoad::PendingLoad() { PackageManagerApplication::PendingLoad::PendingLoad() {
} }
...@@ -21,7 +30,6 @@ PackageManagerApplication::PackageManagerApplication() { ...@@ -21,7 +30,6 @@ PackageManagerApplication::PackageManagerApplication() {
} }
PackageManagerApplication::~PackageManagerApplication() { PackageManagerApplication::~PackageManagerApplication() {
printf("APPLICATION EXITING\n");
STLDeleteContainerPairSecondPointers(pending_.begin(), pending_.end()); STLDeleteContainerPairSecondPointers(pending_.begin(), pending_.end());
} }
...@@ -42,15 +50,28 @@ void PackageManagerApplication::Initialize(ApplicationImpl* app) { ...@@ -42,15 +50,28 @@ void PackageManagerApplication::Initialize(ApplicationImpl* app) {
return; return;
} }
StartLoad(url);
}
void PackageManagerApplication::StartLoad(const GURL& url) {
if (completed_.find(url) != completed_.end() ||
pending_.find(url) != pending_.end())
return; // Already loaded or are loading this one.
PendingLoad* load = new PendingLoad; PendingLoad* load = new PendingLoad;
load->fetcher.reset(new mojo::PackageFetcher( load->fetcher.reset(new mojo::PackageFetcher(
network_service_.get(), this, url)); network_service_.get(), this, url));
pending_[url] = load; pending_[url] = load;
} }
void PackageManagerApplication::LoadDeps(const Manifest& manifest) {
for (size_t i = 0; i < manifest.deps().size(); i++)
StartLoad(manifest.deps()[i]);
}
void PackageManagerApplication::PendingLoadComplete(const GURL& url) { void PackageManagerApplication::PendingLoadComplete(const GURL& url) {
pending_.erase(pending_.find(url)); pending_.erase(pending_.find(url));
completed_.insert(url);
if (pending_.empty()) if (pending_.empty())
base::MessageLoop::current()->Quit(); base::MessageLoop::current()->Quit();
} }
...@@ -58,16 +79,30 @@ void PackageManagerApplication::PendingLoadComplete(const GURL& url) { ...@@ -58,16 +79,30 @@ void PackageManagerApplication::PendingLoadComplete(const GURL& url) {
void PackageManagerApplication::FetchSucceeded( void PackageManagerApplication::FetchSucceeded(
const GURL& url, const GURL& url,
const base::FilePath& name) { const base::FilePath& name) {
PendingLoad* load = pending_.find(url)->second; Unpacker unpacker;
if (!unpacker.Unpack(name)) {
if (!load->unpacker.Unpack(name)) {
base::DeleteFile(name, false); base::DeleteFile(name, false);
printf("Failed to unpack\n"); printf("Failed to unpack\n");
PendingLoadComplete(url); PendingLoadComplete(url);
return; return;
} }
// The downloaded .zip file is no longer necessary.
base::DeleteFile(name, false); base::DeleteFile(name, false);
// Load the manifest.
base::FilePath manifest_path = unpacker.dir().Append(kManifestFileName);
Manifest manifest;
std::string err_msg;
if (!manifest.ParseFromFile(manifest_path, &err_msg)) {
printf("%s\n", err_msg.c_str());
PendingLoadComplete(url);
return;
}
// Enqueue loads for any deps.
LoadDeps(manifest);
printf("Loaded %s\n", url.spec().c_str());
PendingLoadComplete(url); PendingLoadComplete(url);
} }
......
...@@ -6,16 +6,18 @@ ...@@ -6,16 +6,18 @@
#define MOJO_PACKAGE_MANAGER_PACKAGE_MANAGER_APPLICATION_H_ #define MOJO_PACKAGE_MANAGER_PACKAGE_MANAGER_APPLICATION_H_
#include <map> #include <map>
#include <set>
#include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_delegate.h"
#include "mojo/public/cpp/application/interface_factory.h" #include "mojo/public/cpp/application/interface_factory.h"
#include "mojo/public/cpp/system/macros.h" #include "mojo/public/cpp/system/macros.h"
#include "mojo/services/public/interfaces/network/network_service.mojom.h" #include "mojo/services/public/interfaces/network/network_service.mojom.h"
#include "mojo/tools/package_manager/package_fetcher.h" #include "mojo/tools/package_manager/package_fetcher.h"
#include "mojo/tools/package_manager/unpacker.h"
namespace mojo { namespace mojo {
class Manifest;
class PackageManagerApplication class PackageManagerApplication
: public ApplicationDelegate, : public ApplicationDelegate,
public PackageFetcherDelegate { public PackageFetcherDelegate {
...@@ -29,10 +31,13 @@ class PackageManagerApplication ...@@ -29,10 +31,13 @@ class PackageManagerApplication
~PendingLoad(); ~PendingLoad();
scoped_ptr<PackageFetcher> fetcher; scoped_ptr<PackageFetcher> fetcher;
Unpacker unpacker;
}; };
typedef std::map<GURL, PendingLoad*> PendingLoadMap; typedef std::map<GURL, PendingLoad*> PendingLoadMap;
void StartLoad(const GURL& url);
void LoadDeps(const Manifest& manifest);
// Deletes the pending load entry for the given URL and possibly exits the // Deletes the pending load entry for the given URL and possibly exits the
// message loop if all loads are done. // message loop if all loads are done.
void PendingLoadComplete(const GURL& url); void PendingLoadComplete(const GURL& url);
...@@ -48,6 +53,7 @@ class PackageManagerApplication ...@@ -48,6 +53,7 @@ class PackageManagerApplication
mojo::NetworkServicePtr network_service_; mojo::NetworkServicePtr network_service_;
PendingLoadMap pending_; // Owning pointers. PendingLoadMap pending_; // Owning pointers.
std::set<GURL> completed_;
MOJO_DISALLOW_COPY_AND_ASSIGN(PackageManagerApplication); MOJO_DISALLOW_COPY_AND_ASSIGN(PackageManagerApplication);
}; };
......
...@@ -14,10 +14,8 @@ Unpacker::Unpacker() { ...@@ -14,10 +14,8 @@ Unpacker::Unpacker() {
} }
Unpacker::~Unpacker() { Unpacker::~Unpacker() {
if (!dir_.empty()) { if (!dir_.empty())
printf("Deleting %s\n", dir_.value().c_str()); DeleteFile(dir_, true);
//DeleteFile(dir_, true);
}
} }
bool Unpacker::Unpack(const base::FilePath& zip_file) { bool Unpacker::Unpack(const base::FilePath& zip_file) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment