diff --git a/PRESUBMIT.py b/PRESUBMIT.py index 8cb86fe1622e0d..fc07745f03e6be 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py @@ -1149,6 +1149,7 @@ def _CheckSpamLogging(input_api, output_api): r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]" r"startup_browser_creator\.cc$", r"^chrome[\\\/]installer[\\\/]setup[\\\/].*", + r"^chrome[\\\/]installer[\\\/]zucchini[\\\/].*", r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" + r"diagnostics_writer\.cc$", r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$", diff --git a/chrome/installer/zucchini/BUILD.gn b/chrome/installer/zucchini/BUILD.gn index 24459660d9d9eb..97ea2b42ee5f5a 100644 --- a/chrome/installer/zucchini/BUILD.gn +++ b/chrome/installer/zucchini/BUILD.gn @@ -15,6 +15,8 @@ static_library("zucchini_lib") { "image_utils.h", "io_utils.cc", "io_utils.h", + "main_utils.cc", + "main_utils.h", "suffix_array.h", "typed_value.h", ] @@ -30,6 +32,8 @@ executable("zucchini") { ] deps = [ + ":zucchini_lib", + "//base", "//build/config:exe_and_shlib_deps", ] diff --git a/chrome/installer/zucchini/main_utils.cc b/chrome/installer/zucchini/main_utils.cc new file mode 100644 index 00000000000000..96d477de1fb319 --- /dev/null +++ b/chrome/installer/zucchini/main_utils.cc @@ -0,0 +1,131 @@ +// Copyright 2017 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 "chrome/installer/zucchini/main_utils.h" + +#include + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/process/process_metrics.h" +#include "build/build_config.h" +#include "chrome/installer/zucchini/io_utils.h" + +namespace { + +// Translates |command_line| arguments to a vector of base::FilePath and returns +// the result via |fnames|. Expects exactly |expected_count|. +bool CheckAndGetFilePathParams(const base::CommandLine& command_line, + size_t expected_count, + std::vector* fnames) { + const base::CommandLine::StringVector& args = command_line.GetArgs(); + if (args.size() != expected_count) + return false; + + fnames->clear(); + for (size_t i = 0; i < args.size(); ++i) + fnames->push_back(base::FilePath(args[i])); + return true; +} + +} // namespace + +/******** ResourceUsageTracker ********/ + +ResourceUsageTracker::ResourceUsageTracker() : start_time_(base::Time::Now()) {} + +ResourceUsageTracker::~ResourceUsageTracker() { + base::Time end_time = base::Time::Now(); + +#if !defined(OS_MACOSX) + std::unique_ptr process_metrics( + base::ProcessMetrics::CreateProcessMetrics( + base::GetCurrentProcessHandle())); + + LOG(INFO) << "Zucchini.PeakPagefileUsage " + << process_metrics->GetPeakPagefileUsage() / 1024 << " KiB"; + LOG(INFO) << "Zucchini.PeakWorkingSetSize " + << process_metrics->GetPeakWorkingSetSize() / 1024 << " KiB"; +#endif // !defined(OS_MACOSX) + + LOG(INFO) << "Zucchini.TotalTime " << (end_time - start_time_).InSecondsF() + << " s"; +} + +/******** Command ********/ + +Command::Command(const char* name_in, + const char* usage_in, + int num_args_in, + Command::Fun fun_in) + : name(name_in), usage(usage_in), num_args(num_args_in), fun(fun_in) {} + +Command::Command(const Command&) = default; + +Command::~Command() = default; + +/******** CommandRegistry ********/ + +CommandRegistry::CommandRegistry() = default; + +CommandRegistry::~CommandRegistry() = default; + +void CommandRegistry::Register(const Command* command) { + commands_.push_back(command); +} + +void CommandRegistry::RunOrExit(const base::CommandLine& command_line) { + const Command* command_use = nullptr; + for (const Command* command : commands_) { + if (command_line.HasSwitch(command->name)) { + if (command_use) { // Too many commands found. + command_use = nullptr; // Set to null to flag error. + break; + } + command_use = command; + } + } + + // If we don't have exactly one matching command, print error and exit. + if (!command_use) { + std::cerr << "Must have exactly one of:\n ["; + zucchini::PrefixSep sep(", "); + for (const Command* command : commands_) + std::cerr << sep << "-" << command->name; + std::cerr << "]" << std::endl; + PrintUsageAndExit(); + } + + std::vector fnames; + if (CheckAndGetFilePathParams(command_line, command_use->num_args, &fnames)) { + command_use->fun.Run(command_line, fnames); + } else { + std::cerr << command_use->usage << std::endl; + PrintUsageAndExit(); + } +} + +void CommandRegistry::PrintUsageAndExit() { + std::cerr << "Usage:" << std::endl; + for (const Command* command : commands_) + std::cerr << " zucchini " << command->usage << std::endl; + exit(1); +} + +/******** Command Definitions ********/ + +Command kCommandGen = { + "gen", "-gen ", 3, + base::Bind([](const base::CommandLine& command_line, + const std::vector& fnames) -> void { + // TODO(etiennep): Implement. + })}; + +Command kCommandApply = { + "apply", "-apply ", 3, + base::Bind([](const base::CommandLine& command_line, + const std::vector& fnames) -> void { + // TODO(etiennep): Implement. + })}; diff --git a/chrome/installer/zucchini/main_utils.h b/chrome/installer/zucchini/main_utils.h new file mode 100644 index 00000000000000..17a2b5103e40b3 --- /dev/null +++ b/chrome/installer/zucchini/main_utils.h @@ -0,0 +1,86 @@ +// Copyright 2017 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 CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ +#define CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ + +#include +#include + +#include "base/callback.h" +#include "base/macros.h" +#include "base/time/time.h" + +namespace base { + +class CommandLine; +class FilePath; + +} // namespace base + +// Class to track and print system resource usage. Should be instantiated early +// in program flow to better track start time. +class ResourceUsageTracker { + public: + ResourceUsageTracker(); + ~ResourceUsageTracker(); + + private: + base::Time start_time_; + + DISALLOW_COPY_AND_ASSIGN(ResourceUsageTracker); +}; + +// Specs for a Zucchini command. +struct Command { + using Fun = base::Callback&)>; + + Command(const char* name_in, + const char* usage_in, + int num_args_in, + Fun fun_in); + explicit Command(const Command&); + ~Command(); + + // Unique name of command. |-name| is used to select from command line. + const char* name; + + // Usage help text of command. + const char* usage; + + // Number of arguments (assumed to be filenames) used by the command. + const int num_args; + + // Main code for the command. + Fun fun; +}; + +// Registry of Commands to select the command to run and to handle errors. +class CommandRegistry { + public: + CommandRegistry(); + ~CommandRegistry(); + + void Register(const Command* command); + + // Uses |command_line| to find a Command instance. If a unique command is + // found, then runs it. Otherwise prints error and exits. + void RunOrExit(const base::CommandLine& command_line); + + private: + void PrintUsageAndExit(); + + std::vector commands_; + + DISALLOW_COPY_AND_ASSIGN(CommandRegistry); +}; + +// Command: Patch generation. +extern Command kCommandGen; + +// Command: Patch application. +extern Command kCommandApply; + +#endif // CHROME_INSTALLER_ZUCCHINI_MAIN_UTILS_H_ diff --git a/chrome/installer/zucchini/zucchini_main.cc b/chrome/installer/zucchini/zucchini_main.cc index 3663e67ee6b3ab..face7b45389a83 100644 --- a/chrome/installer/zucchini/zucchini_main.cc +++ b/chrome/installer/zucchini/zucchini_main.cc @@ -2,6 +2,37 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/command_line.h" +#include "base/logging.h" +#include "chrome/installer/zucchini/main_utils.h" + +namespace { + +void InitLogging() { + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; + settings.log_file = nullptr; + settings.lock_log = logging::DONT_LOCK_LOG_FILE; + settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE; + bool logging_res = logging::InitLogging(settings); + CHECK(logging_res); +} + +} // namespace + int main(int argc, const char* argv[]) { + ResourceUsageTracker tracker; + base::CommandLine::Init(argc, argv); + InitLogging(); + + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + // Instantiate Command registry and register Zucchini features. + CommandRegistry registry; + registry.Register(&kCommandGen); + registry.Register(&kCommandApply); + + registry.RunOrExit(command_line); return 0; }