diff --git a/src/nw_package.cc b/src/nw_package.cc index 2f91d09050..a3fa05fb18 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -26,22 +26,17 @@ #include "base/logging.h" #include "base/scoped_temp_dir.h" #include "base/string_util.h" +#include "base/string16.h" #include "base/threading/thread_restrictions.h" #include "base/values.h" -#include "common/zip.h" #include "content/nw/src/common/shell_switches.h" +#include "content/nw/src/common/zip.h" +#include "googleurl/src/gurl.h" -#if defined(OS_WIN) -#include "base/string16.h" -#endif +namespace nw { namespace { -FilePath package_root; - -// Don't bother with lifetime since it's used through out the program -base::DictionaryValue* g_manifest = NULL; - bool MakePathAbsolute(FilePath* file_path) { DCHECK(file_path); @@ -62,41 +57,41 @@ bool MakePathAbsolute(FilePath* file_path) { return true; } -void ManifestConvertRelativePaths( - FilePath path, - base::DictionaryValue* manifest) { - if (manifest->HasKey(switches::kmMain)) { -#if defined(OS_WIN) - string16 out; -#else - std::string out; -#endif - if (!manifest->GetString(switches::kmMain, &out)) { - manifest->Remove(switches::kmMain, NULL); - LOG(WARNING) << "'main' field in manifest must be a string."; - return; - } - - // Don't append path if there is already a prefix -#if defined(OS_WIN) - if (MatchPattern(out, L"*://*")) { -#else - if (MatchPattern(out, "*://*")) { -#endif - return; - } - +FilePath GetPathFromCommandLine(bool* self_extract) { + FilePath path; + CommandLine* command_line = CommandLine::ForCurrentProcess(); + const CommandLine::StringVector& args = command_line->GetArgs(); - FilePath main_path = path.Append(out); -#if defined(OS_WIN) - string16 url(L"file://"); + if (args.size() == 0) { + *self_extract = true; +#if defined(OS_MACOSX) + // Find if we have node-webkit.app/Resources/app.nw. + path = path.DirName().DirName().Append("Resources").Append("app.nw"); #else - std::string url("file://"); + // See itself as a package (allowing standalone). + path = FilePath(command_line->GetProgram()); #endif - manifest->SetString(switches::kmMain, url + main_path.value()); } else { - LOG(WARNING) << "'main' field in manifest should be specifed."; + *self_extract = false; + // Get first argument. + path = FilePath(args[0]); } + + return path; +} + +void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) { + std::string old; + if (!manifest->GetString(switches::kmMain, &old)) + return; + + // Don't append path if there is already a prefix + if (MatchPattern(old, "*://*")) + return; + + FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old)); + manifest->SetString(switches::kmMain, + std::string("file://") + main_path.AsUTF8Unsafe()); } bool ExtractPackage(const FilePath& zip_file, FilePath* where) { @@ -121,155 +116,141 @@ bool ExtractPackage(const FilePath& zip_file, FilePath* where) { return zip::Unzip(zip_file, *where); } -bool InitPackage() { - FilePath path; - bool is_self_extract = false; +} // namespace + +Package::Package() + : path_(GetPathFromCommandLine(&self_extract_)) { + if (!InitFromPath()) + InitWithDefault(); +} + +Package::Package(FilePath path) + : path_(path), + self_extract_(false) { + if (!InitFromPath()) + InitWithDefault(); +} +Package::~Package() { +} + +GURL Package::GetStartupURL() { + std::string url; + // Specify URL in --url CommandLine* command_line = CommandLine::ForCurrentProcess(); - const CommandLine::StringVector& args = command_line->GetArgs(); + if (command_line->HasSwitch(switches::kUrl)) { + url = command_line->GetSwitchValueASCII(switches::kUrl); + GURL gurl(url); + if (!gurl.has_scheme()) + return GURL(std::string("http://") + url); - if (args.size() == 0) { - // See itself as a package (allowing standalone) - path = FilePath(command_line->GetProgram()); - is_self_extract = true; -#if defined(OS_MACOSX) - // Find if we have node-webkit.app/Resources/app.nw - path = path.DirName().DirName().Append("Resources").Append("app.nw"); -#endif - } else { - // Get first argument - path = FilePath(args[0]); - if (!file_util::PathExists(path)) { - LOG(WARNING) << "Package does not exist."; - return false; - } + return gurl; } - // Convert to absoulute path - if (!MakePathAbsolute(&path)) { - DLOG(ERROR) << "Cannot make absolute path from " << path.value(); - } + // Read from manifest + if (root()->GetString(switches::kmMain, &url)) + return GURL(url); + else + return GURL("nw:blank"); +} - // If it's a file then try to extract from it - if (!file_util::DirectoryExists(path)) { - DLOG(INFO) << "Extracting packaging..."; - FilePath zip_file(path); - if (!ExtractPackage(zip_file, &path)) { - if (!is_self_extract) - LOG(ERROR) << "Unable to extract package."; - return false; - } - } +bool Package::GetUseNode() { + bool use_node = true; + root()->GetBoolean(switches::kmNodejs, &use_node); + return use_node; +} - // Set the directory of app as our working directory - package_root = path; - file_util::SetCurrentDirectory(path); +base::DictionaryValue* Package::window() { + base::DictionaryValue* window; + root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window); + return window; +} -#if defined(OS_WIN) - FilePath manifest_path = path.Append(L"package.json"); -#else - FilePath manifest_path = path.Append("package.json"); -#endif +bool Package::InitFromPath() { + base::ThreadRestrictions::SetIOAllowed(true); + + if (!ExtractPath(&path_)) + return false; + + file_util::SetCurrentDirectory(path_); + + // path_/package.json + FilePath manifest_path = path_.AppendASCII("package.json"); if (!file_util::PathExists(manifest_path)) { - LOG(ERROR) << "No 'package.json' in package."; + if (!self_extract()) + LOG(ERROR) << "No 'package.json' in package."; return false; } - // Parse file + // Parse file. std::string error; JSONFileValueSerializer serializer(manifest_path); scoped_ptr root(serializer.Deserialize(NULL, &error)); if (!root.get()) { - if (error.empty()) { + if (error.empty()) LOG(ERROR) << "It's not able to read the manifest file."; - } else { + else LOG(ERROR) << "Manifest parsing error: " << error; - } return false; - } - - if (!root->IsType(Value::TYPE_DICTIONARY)) { + } else if (!root->IsType(Value::TYPE_DICTIONARY)) { LOG(ERROR) << "Manifest file is invalid, we need a dictionary type"; return false; } // Save result in global - g_manifest = static_cast(root.release()); - // And save the root path - g_manifest->SetString(switches::kmRoot, path.value()); + root_.reset(static_cast(root.release())); // Check fields - const char* required_fields[] = { switches::kmMain, switches::kmName }; - for (unsigned i = 0; i < arraysize(required_fields); i++) { - if (!g_manifest->HasKey(required_fields[i])) { + const char* required_fields[] = { + switches::kmMain, + switches::kmName + }; + for (unsigned i = 0; i < arraysize(required_fields); i++) + if (!root_->HasKey(required_fields[i])) { LOG(ERROR) << "'" << required_fields[i] << "' field is required."; return false; } - } - ManifestConvertRelativePaths(path, g_manifest); + // Force window field no empty + if (!root_->HasKey(switches::kmWindow)) + root_->Set(switches::kmWindow, new base::DictionaryValue()); + + RelativePathToURI(path_, this->root()); return true; } -} // namespace - -namespace nw { +void Package::InitWithDefault() { + root_.reset(new base::DictionaryValue()); + root()->SetString(switches::kmName, "node-webkit"); + root()->SetString(switches::kmMain, "nw:blank"); + base::DictionaryValue* window = new base::DictionaryValue(); + root()->Set(switches::kmWindow, window); -base::DictionaryValue* GetManifest() { - return g_manifest; + // Hide toolbar is specifed in the command line + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar)) + window->SetBoolean(switches::kmToolbar, false); } -GURL GetStartupURL() { - std::string url; - // Specify URL in --url - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kUrl)) { - url = command_line->GetSwitchValueASCII(switches::kUrl); - GURL gurl(url); - if (!gurl.has_scheme()) - return GURL(std::string("http://") + url); - - return gurl; +bool Package::ExtractPath(FilePath* path) { + // Convert to absoulute path. + if (!MakePathAbsolute(&path_)) { + LOG(ERROR) << "Cannot make absolute path from " << path_.value(); + return false; } - // Read from manifest - base::DictionaryValue* manifest = nw::GetManifest(); - manifest->GetString(switches::kmMain, &url); - - if (url.empty()) - url = "nw:blank"; - - return GURL(url); -} - -bool GetUseNode() { - bool use_node = true; - GetManifest()->GetBoolean(switches::kmNodejs, &use_node); - return use_node; -} - -FilePath GetPackageRoot() { - return package_root; -} - -void InitPackageForceNoEmpty() { - base::ThreadRestrictions::SetIOAllowed(true); - - InitPackage(); - - if (g_manifest == NULL) { - g_manifest = new base::DictionaryValue(); - g_manifest->SetString(switches::kmName, "node-webkit"); + // If it's a file then try to extract from it. + if (!file_util::DirectoryExists(path_)) { + DLOG(INFO) << "Extracting packaging..."; + FilePath extracted_path; + if (ExtractPackage(path_, &extracted_path)) { + path_ = extracted_path; + } else if (!self_extract()) { + LOG(ERROR) << "Unable to extract package."; + return false; + } } - if (!g_manifest->HasKey(switches::kmWindow)) { - base::DictionaryValue* window = new base::DictionaryValue(); - g_manifest->Set(switches::kmWindow, window); - - // Hide toolbar is specifed in the command line - if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar)) - window->SetBoolean(switches::kmToolbar, false); - } + return true; } } // namespace nw diff --git a/src/nw_package.h b/src/nw_package.h index 7328a2e2ab..df023fae91 100644 --- a/src/nw_package.h +++ b/src/nw_package.h @@ -21,9 +21,13 @@ #ifndef CONTENT_NW_SRC_NW_PACKAGE_H #define CONTENT_NW_SRC_NW_PACKAGE_H -#include "googleurl/src/gurl.h" +#include "base/basictypes.h" +#include "base/file_path.h" +#include "base/memory/scoped_ptr.h" -class FilePath; +#include + +class GURL; namespace base { class DictionaryValue; @@ -31,20 +35,45 @@ namespace base { namespace nw { -// Return the global manifest file -base::DictionaryValue* GetManifest(); +class Package { + public: + // Init package from command line parameters. + Package(); + + // Init package from specifed path. + Package(FilePath path); + ~Package(); + + // Get startup url. + GURL GetStartupURL(); + + // Return if we enable node.js. + bool GetUseNode(); + + // Root path of package. + FilePath path() const { return path_; } + + // If the package is extracting itself. + bool self_extract() const { return self_extract_; } + + // Manifest root. + base::DictionaryValue* root() { return root_.get(); } -// Return the startup url from mainfest file or command line -GURL GetStartupURL(); + // Window field of manifest. + base::DictionaryValue* window(); -// Return if we enable node.js -bool GetUseNode(); + private: + bool InitFromPath(); + void InitWithDefault(); + bool ExtractPath(FilePath* path); -// Return root path of package -FilePath GetPackageRoot(); + FilePath path_; + bool self_extract_; + bool initialized_; + scoped_ptr root_; -// Extract app package and initialize manifest file -void InitPackageForceNoEmpty(); + DISALLOW_COPY_AND_ASSIGN(Package); +}; } // namespae nw diff --git a/src/shell.cc b/src/shell.cc index 4f6e238a08..3f84ede4c1 100644 --- a/src/shell.cc +++ b/src/shell.cc @@ -124,6 +124,12 @@ Shell* Shell::CreateShell(WebContents* web_contents, return shell; } +nw::Package* Shell::GetPackage() { + ShellContentBrowserClient* browser_client = + static_cast(GetContentClient()->browser()); + return browser_client->shell_browser_main_parts()->package(); +} + void Shell::CloseAllWindows() { AutoReset auto_reset(&quit_message_loop_, false); std::vector open_windows(windows_); @@ -154,8 +160,7 @@ Shell* Shell::CreateNewWindow(BrowserContext* browser_context, base_web_contents); // Create with package's manifest - base::DictionaryValue *manifest = NULL; - nw::GetManifest()->GetDictionary(switches::kmWindow, &manifest); + base::DictionaryValue *manifest = GetPackage()->window(); manifest->SetBoolean(switches::kDeveloper, CommandLine::ForCurrentProcess()->HasSwitch(switches::kDeveloper)); @@ -288,8 +293,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, const GURL& target_url, WebContents* new_contents) { // Create with package's manifest - base::DictionaryValue *manifest = NULL; - nw::GetManifest()->GetDictionary(switches::kmWindow, &manifest); + base::DictionaryValue *manifest = GetPackage()->window(); manifest->SetBoolean(switches::kDeveloper, CommandLine::ForCurrentProcess()->HasSwitch(switches::kDeveloper)); diff --git a/src/shell.h b/src/shell.h index ad28193764..b968f3e19f 100644 --- a/src/shell.h +++ b/src/shell.h @@ -44,7 +44,12 @@ namespace base { class DictionaryValue; } +namespace nw { +class Package; +} + class GURL; + namespace content { class BrowserContext; @@ -101,6 +106,8 @@ class Shell : public WebContentsDelegate, // Closes all windows and exits. static void PlatformExit(); + static nw::Package* GetPackage(); + WebContents* web_contents() const { return web_contents_.get(); } gfx::NativeWindow window() { return window_; } diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index 3ed47107ec..14fc8ceabc 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -45,8 +45,10 @@ namespace content { -ShellBrowserContext::ShellBrowserContext(bool off_the_record) - : off_the_record_(off_the_record) { +ShellBrowserContext::ShellBrowserContext(bool off_the_record, + nw::Package* package) + : off_the_record_(off_the_record), + package_(package) { InitWhileIOAllowed(); } @@ -68,7 +70,6 @@ void ShellBrowserContext::InitWhileIOAllowed() { path_ = cmd_line->GetSwitchValuePath(switches::kContentShellDataPath); return; } - base::DictionaryValue *manifest = nw::GetManifest(); FilePath::StringType name( #if defined(OS_WIN) L"node-webkit" @@ -76,7 +77,7 @@ void ShellBrowserContext::InitWhileIOAllowed() { "node-webkit" #endif ); - manifest->GetString(switches::kmName, &name); + package_->root()->GetString(switches::kmName, &name); #if defined(OS_WIN) CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path_)); path_ = path_.Append(name); diff --git a/src/shell_browser_context.h b/src/shell_browser_context.h index 1ef50d61b3..db9862701c 100644 --- a/src/shell_browser_context.h +++ b/src/shell_browser_context.h @@ -12,6 +12,10 @@ #include "base/scoped_temp_dir.h" #include "content/public/browser/browser_context.h" +namespace nw { +class Package; +} + namespace content { class DownloadManagerDelegate; @@ -20,7 +24,8 @@ class ShellDownloadManagerDelegate; class ShellBrowserContext : public BrowserContext { public: - explicit ShellBrowserContext(bool off_the_record); + explicit ShellBrowserContext(bool off_the_record, + nw::Package* package); virtual ~ShellBrowserContext(); // BrowserContext implementation. @@ -52,6 +57,7 @@ class ShellBrowserContext : public BrowserContext { void InitWhileIOAllowed(); bool off_the_record_; + nw::Package* package_; ScopedTempDir testing_path_; FilePath path_; scoped_ptr resource_context_; diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index 899a0ce649..b72f20a4df 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -95,10 +95,11 @@ void ShellBrowserMainParts::PostMainMessageLoopRun() { } void ShellBrowserMainParts::Init() { - nw::InitPackageForceNoEmpty(); + package_.reset(new nw::Package()); - browser_context_.reset(new ShellBrowserContext(false)); - off_the_record_browser_context_.reset(new ShellBrowserContext(true)); + browser_context_.reset(new ShellBrowserContext(false, package())); + off_the_record_browser_context_.reset( + new ShellBrowserContext(true, package())); Shell::PlatformInitialize(); net::NetModule::SetResourceProvider(PlatformResourceProvider); @@ -122,7 +123,7 @@ void ShellBrowserMainParts::Init() { port, browser_context_->GetRequestContext()); Shell::CreateNewWindow(browser_context_.get(), - nw::GetStartupURL(), + package()->GetStartupURL(), NULL, MSG_ROUTING_NONE, NULL); diff --git a/src/shell_browser_main_parts.h b/src/shell_browser_main_parts.h index 34bdba6e6c..c03609ff88 100644 --- a/src/shell_browser_main_parts.h +++ b/src/shell_browser_main_parts.h @@ -13,6 +13,10 @@ namespace base { class Thread; } +namespace nw { +class Package; +} + namespace content { class ShellBrowserContext; @@ -39,10 +43,12 @@ class ShellBrowserMainParts : public BrowserMainParts { ShellBrowserContext* off_the_record_browser_context() { return off_the_record_browser_context_.get(); } + nw::Package* package() { return package_.get(); } private: scoped_ptr browser_context_; scoped_ptr off_the_record_browser_context_; + scoped_ptr package_; // For running content_browsertests. const MainFunctionParams& parameters_; diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index fd26e17d72..9c8f51d485 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -67,13 +67,14 @@ std::string ShellContentBrowserClient::GetApplicationLocale() { void ShellContentBrowserClient::AppendExtraCommandLineSwitches( CommandLine* command_line, int child_process_id) { - if (nw::GetManifest() && nw::GetUseNode()) { + nw::Package* package = shell_browser_main_parts()->package(); + if (package && package->GetUseNode()) { // Allow node.js command_line->AppendSwitch(switches::kmNodejs); // Set cwd command_line->AppendSwitchPath(switches::kWorkingDirectory, - nw::GetPackageRoot()); + package->path()); } } diff --git a/src/shell_mac.mm b/src/shell_mac.mm index 1c9d887ab4..cc5d413468 100644 --- a/src/shell_mac.mm +++ b/src/shell_mac.mm @@ -385,7 +385,7 @@ void MakeShellButton(NSRect* rect, } // Replace all node-webkit stuff to app's name - base::DictionaryValue* manifest = nw::GetManifest(); + base::DictionaryValue* manifest = GetPackage()->root(); std::string name; if (manifest->GetString(switches::kmName, &name) && name != "node-webkit") {