Commit a13b5a0f authored by huangs's avatar huangs Committed by Commit Bot

[Zucchini] Add command line processing framework with stubs.

This CL adds main_utils.*, which has the framework to dispatch Zucchini
commands and print help messages. This is used by the Zucchini main
program, and is not part of Zucchini library.
- Add ::Command: A struct containing command name (e.g., "-gen",
  "-apply"), help message, and a base::Callback containing code for
  the main command. This allows Zucchini command dispatch without bulky
  bulky class hierarchy and superfluous instantialization.
- Add ::CommandRegistry: A class to manage ::Command instances and
  dispatch commands, or print help messages.
- Add ::ResourceUsageTracker: A class instantiated in main() to track
  resource usage for valid command invocations, and and print them at
  end. Specifically:
  - Zucchini.PeakPagefileUsage (KiB)
  - Zucchini.PeakWorkingSetSize (KiB)
  - Zucchini.TotalTime (s)
  Also add "-quiet" switch to disable this.
- Add stubs for Zucchini-gen and Zucchini-apply, to be populated later.
- Starting to use LOG(INFO) to display output. This requires updating
  PRESUBMIT.py to add Zucchini as an exception.

Bug: 729154
Change-Id: Id5263435100dc73b2d8917ca2bcd04245ed41934
Reviewed-on: https://chromium-review.googlesource.com/567492
Commit-Queue: Samuel Huang <huangs@chromium.org>
Reviewed-by: default avatarDirk Pranke <dpranke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#486762}
parent a308bcc8
...@@ -1149,6 +1149,7 @@ def _CheckSpamLogging(input_api, output_api): ...@@ -1149,6 +1149,7 @@ def _CheckSpamLogging(input_api, output_api):
r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]" r"^chrome[\\\/]browser[\\\/]ui[\\\/]startup[\\\/]"
r"startup_browser_creator\.cc$", r"startup_browser_creator\.cc$",
r"^chrome[\\\/]installer[\\\/]setup[\\\/].*", r"^chrome[\\\/]installer[\\\/]setup[\\\/].*",
r"^chrome[\\\/]installer[\\\/]zucchini[\\\/].*",
r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" + r"chrome[\\\/]browser[\\\/]diagnostics[\\\/]" +
r"diagnostics_writer\.cc$", r"diagnostics_writer\.cc$",
r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$", r"^chrome_elf[\\\/]dll_hash[\\\/]dll_hash_main\.cc$",
......
...@@ -15,6 +15,8 @@ static_library("zucchini_lib") { ...@@ -15,6 +15,8 @@ static_library("zucchini_lib") {
"image_utils.h", "image_utils.h",
"io_utils.cc", "io_utils.cc",
"io_utils.h", "io_utils.h",
"main_utils.cc",
"main_utils.h",
"suffix_array.h", "suffix_array.h",
"typed_value.h", "typed_value.h",
] ]
...@@ -30,6 +32,8 @@ executable("zucchini") { ...@@ -30,6 +32,8 @@ executable("zucchini") {
] ]
deps = [ deps = [
":zucchini_lib",
"//base",
"//build/config:exe_and_shlib_deps", "//build/config:exe_and_shlib_deps",
] ]
......
// 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 <iostream>
#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<base::FilePath>* 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<base::ProcessMetrics> 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<base::FilePath> 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 <old_file> <new_file> <patch_file>", 3,
base::Bind([](const base::CommandLine& command_line,
const std::vector<base::FilePath>& fnames) -> void {
// TODO(etiennep): Implement.
})};
Command kCommandApply = {
"apply", "-apply <old_file> <patch_file> <new_file>", 3,
base::Bind([](const base::CommandLine& command_line,
const std::vector<base::FilePath>& fnames) -> void {
// TODO(etiennep): Implement.
})};
// 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 <memory>
#include <vector>
#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<void(const base::CommandLine&,
const std::vector<base::FilePath>&)>;
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<const Command*> 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_
...@@ -2,6 +2,37 @@ ...@@ -2,6 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // 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[]) { 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; return 0;
} }
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