Description: Add --trust_install_base option
 This will allow Bazel client to run individually without the appended
 zip archive, which is a requirement for Debian installation.
Author: Yun Peng <pcloudy@google.com>
Origin: upstream, https://github.com/meteorcloudy/bazel/commit/798831be403175a7a262a3fa3875c550dcc89aed
Forwarded: not-needed
Last-Update: 2020-08-10

--- a/src/main/cpp/blaze.cc
+++ b/src/main/cpp/blaze.cc
@@ -1011,6 +1011,10 @@
           << "install base directory '" << install_base
           << "' could not be created. It exists but is not a directory.";
     }
+    // If --trust_install_base is true, we skip the following checks.
+    if (startup_options.trust_install_base) {
+      return DurationMillis();
+    }
     blaze_util::Path install_dir(install_base);
     // Check that all files are present and have timestamps from BlessFiles().
     std::unique_ptr<blaze_util::IFileMtime> mtime(
@@ -1202,7 +1206,10 @@
     // find install bases that haven't been used for a long time
     std::unique_ptr<blaze_util::IFileMtime> mtime(
         blaze_util::CreateFileMtime());
-    if (!mtime->SetToNow(blaze_util::Path(startup_options.install_base))) {
+    // We skip touching the install base if --trust_install_base is enabled,
+    // because the provided install base might not be writable.
+    if (!startup_options.trust_install_base &&
+        !mtime->SetToNow(blaze_util::Path(startup_options.install_base))) {
       string err = GetLastErrorString();
       BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
           << "failed to set timestamp on '" << startup_options.install_base
@@ -1490,9 +1497,21 @@
   return custom_exit_code;
 }
 
-void PrintVersionInfo(const string &self_path, const string &product_name) {
+void PrintVersionInfo(const string &self_path,
+                      const string &product_name,
+                      const StartupOptions &startup_options) {
   string build_label;
-  ExtractBuildLabel(self_path, &build_label);
+  if (startup_options.trust_install_base) {
+    blaze_util::Path install_base(startup_options.install_base);
+    string build_label_path = install_base.GetRelative("build-label.txt").AsNativePath();
+    if (!blaze_util::ReadFile(build_label_path, &build_label)) {
+      BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
+        << "Cannot read build-label.txt file from install base: "
+        << build_label_path;
+    }
+  } else {
+    ExtractBuildLabel(self_path, &build_label);
+  }
   printf("%s %s\n", product_name.c_str(), build_label.c_str());
 }
 
@@ -1586,11 +1605,6 @@
 
   const string self_path = GetSelfPath(argv[0]);
 
-  if (argc == 2 && strcmp(argv[1], "--version") == 0) {
-    PrintVersionInfo(self_path, option_processor->GetLowercaseProductName());
-    return blaze_exit_code::SUCCESS;
-  }
-
   string cwd = GetCanonicalCwd();
   LoggingInfo logging_info(CheckAndGetBinaryPath(cwd, argv[0]), start_time);
 
@@ -1621,11 +1635,23 @@
   StartupOptions *startup_options = option_processor->GetParsedStartupOptions();
   startup_options->MaybeLogStartupOptionWarnings();
 
+  // Check --install_base is provided when --trust_install_base is enabled
+  if (startup_options->trust_install_base && startup_options->install_base.empty()) {
+    BAZEL_DIE(blaze_exit_code::BAD_ARGV)
+        << "--trust_install_base requires --install_base to be provided";
+  }
+
   SetDebugLog(startup_options->client_debug);
+
   // If client_debug was false, this is ignored, so it's accurate.
   BAZEL_LOG(INFO) << "Debug logging requested, sending all client log "
                      "statements to stderr";
 
+  if (startup_options->version) {
+    PrintVersionInfo(self_path, option_processor->GetLowercaseProductName(), *startup_options);
+    return blaze_exit_code::SUCCESS;
+  }
+
   if (startup_options->unlimit_coredumps) {
     UnlimitCoredumps();
   }
@@ -1641,7 +1667,28 @@
 
   vector<string> archive_contents;
   string install_md5;
-  DetermineArchiveContents(self_path, &archive_contents, &install_md5);
+  if (startup_options->trust_install_base) {
+    blaze_util::Path install_base(startup_options->install_base);
+
+    // Read install_md5 value from <install_base>/install_base_key
+    string install_key_path = install_base.GetRelative("install_base_key").AsNativePath();
+    if (!blaze_util::ReadFile(install_key_path, &install_md5)) {
+      BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR)
+        << "Cannot read install_base_key file from install base: "
+        << install_key_path;
+    }
+
+    // Read all archive content entries
+    blaze_util::GetAllFilesUnder(startup_options->install_base, &archive_contents);
+    std::size_t pos = install_base.AsNativePath().length() + 1;
+    for (int i = 0; i < archive_contents.size(); i++) {
+      blaze_util::Path entry(archive_contents[i]);
+      archive_contents[i] = entry.AsNativePath().substr(pos);
+    }
+    std::sort(archive_contents.begin(), archive_contents.end());
+  } else {
+    DetermineArchiveContents(self_path, &archive_contents, &install_md5);
+  }
 
   UpdateConfiguration(install_md5, workspace,
                       IsServerMode(option_processor->GetCommand()),
--- a/src/main/cpp/startup_options.cc
+++ b/src/main/cpp/startup_options.cc
@@ -97,7 +97,9 @@
 #endif
       unlimit_coredumps(false),
       incompatible_enable_execution_transition(false),
-      windows_enable_symlinks(false) {
+      windows_enable_symlinks(false),
+      version(false),
+      trust_install_base(false) {
   if (blaze::IsRunningWithinTest()) {
     output_root = blaze_util::MakeAbsolute(blaze::GetPathEnv("TEST_TMPDIR"));
     max_idle_secs = 15;
@@ -149,6 +151,10 @@
   RegisterNullaryStartupFlag("write_command_log", &write_command_log);
   RegisterNullaryStartupFlag("windows_enable_symlinks",
                              &windows_enable_symlinks);
+  RegisterNullaryStartupFlag("version",
+                             &version);
+  RegisterNullaryStartupFlag("trust_install_base",
+                             &trust_install_base);
   RegisterUnaryStartupFlag("command_port");
   RegisterUnaryStartupFlag("connect_timeout_secs");
   RegisterUnaryStartupFlag("local_startup_timeout_secs");
--- a/src/main/cpp/startup_options.h
+++ b/src/main/cpp/startup_options.h
@@ -280,6 +280,15 @@
   // developer mode to be enabled.
   bool windows_enable_symlinks;
 
+  // Whether to print version info and exit.
+  bool version;
+
+  // Whether to trust the install base directory provided by --install_base
+  // and skip all the checks. This will allow running the Bazel client without
+  // appending the zip archive when a install base is available, eg. for Debian
+  // installation.
+  bool trust_install_base;
+
  protected:
   // Constructor for subclasses only so that site-specific extensions of this
   // class can override the product name.  The product_name must be the
