Add sources.py `prune` subcommand to prune unrequired sources

This command should make it easier to prune unrequired sources after
copying a new version of libunwindstack and required subfolders into the
src/ directory.

After writing this command, I then ran it, which removed parseint.h.
This file was required by logging.cpp, which was in my original local
compiling version of libunwindstack but was later removed from the
library via a patch.

Bug: 991960
Change-Id: I422caf2c386aadbd046caced3d1dfef6a389e74d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/third_party/libunwindstack/+/1900012
Reviewed-by: Mike Wittman <wittman@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index e812729..399c3cb 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 source_set("libunwindstack") {
-  visibility = [
-    "//base",
-  ]
+  visibility = [ "//base" ]
   include_dirs = [
     "//third_party/libunwindstack/src/android-base/include",
     "//third_party/libunwindstack/src/compat",
@@ -14,68 +12,68 @@
     "//third_party/libunwindstack/src/libprocinfo/include",
     "//third_party/libunwindstack/src/libunwindstack/include",
   ]
+
   # TODO(charliea): After we write the Android unwinder implementation, move
   # header files that don't need to be public to sources.
   public = [
-   "src/libunwindstack/include/unwindstack/DexFiles.h",
-   "src/libunwindstack/include/unwindstack/DwarfError.h",
-   "src/libunwindstack/include/unwindstack/DwarfLocation.h",
-   "src/libunwindstack/include/unwindstack/DwarfMemory.h",
-   "src/libunwindstack/include/unwindstack/DwarfSection.h",
-   "src/libunwindstack/include/unwindstack/DwarfStructs.h",
-   "src/libunwindstack/include/unwindstack/Elf.h",
-   "src/libunwindstack/include/unwindstack/ElfInterface.h",
-   "src/libunwindstack/include/unwindstack/Error.h",
-   "src/libunwindstack/include/unwindstack/Global.h",
-   "src/libunwindstack/include/unwindstack/JitDebug.h",
-   "src/libunwindstack/include/unwindstack/LocalUnwinder.h",
-   "src/libunwindstack/include/unwindstack/Log.h",
-   "src/libunwindstack/include/unwindstack/Log.h",
-   "src/libunwindstack/include/unwindstack/MachineArm.h",
-   "src/libunwindstack/include/unwindstack/MachineArm64.h",
-   "src/libunwindstack/include/unwindstack/MachineMips.h",
-   "src/libunwindstack/include/unwindstack/MachineMips64.h",
-   "src/libunwindstack/include/unwindstack/MachineX86.h",
-   "src/libunwindstack/include/unwindstack/MachineX86_64.h",
-   "src/libunwindstack/include/unwindstack/MapInfo.h",
-   "src/libunwindstack/include/unwindstack/MapInfo.h",
-   "src/libunwindstack/include/unwindstack/Maps.h",
-   "src/libunwindstack/include/unwindstack/Maps.h",
-   "src/libunwindstack/include/unwindstack/Memory.h",
-   "src/libunwindstack/include/unwindstack/Regs.h",
-   "src/libunwindstack/include/unwindstack/Regs.h",
-   "src/libunwindstack/include/unwindstack/RegsArm.h",
-   "src/libunwindstack/include/unwindstack/RegsArm64.h",
-   "src/libunwindstack/include/unwindstack/RegsGetLocal.h",
-   "src/libunwindstack/include/unwindstack/RegsMips.h",
-   "src/libunwindstack/include/unwindstack/RegsMips64.h",
-   "src/libunwindstack/include/unwindstack/RegsX86.h",
-   "src/libunwindstack/include/unwindstack/RegsX86_64.h",
-   "src/libunwindstack/include/unwindstack/UcontextArm.h",
-   "src/libunwindstack/include/unwindstack/UcontextArm64.h",
-   "src/libunwindstack/include/unwindstack/UcontextMips.h",
-   "src/libunwindstack/include/unwindstack/UcontextMips64.h",
-   "src/libunwindstack/include/unwindstack/UcontextX86.h",
-   "src/libunwindstack/include/unwindstack/UcontextX86_64.h",
-   "src/libunwindstack/include/unwindstack/Unwinder.h",
-   "src/libunwindstack/include/unwindstack/UserArm.h",
-   "src/libunwindstack/include/unwindstack/UserArm.h",
-   "src/libunwindstack/include/unwindstack/UserArm64.h",
-   "src/libunwindstack/include/unwindstack/UserArm64.h",
-   "src/libunwindstack/include/unwindstack/UserMips.h",
-   "src/libunwindstack/include/unwindstack/UserMips.h",
-   "src/libunwindstack/include/unwindstack/UserMips64.h",
-   "src/libunwindstack/include/unwindstack/UserMips64.h",
-   "src/libunwindstack/include/unwindstack/UserX86.h",
-   "src/libunwindstack/include/unwindstack/UserX86.h",
-   "src/libunwindstack/include/unwindstack/UserX86_64.h",
+    "src/libunwindstack/include/unwindstack/DexFiles.h",
+    "src/libunwindstack/include/unwindstack/DwarfError.h",
+    "src/libunwindstack/include/unwindstack/DwarfLocation.h",
+    "src/libunwindstack/include/unwindstack/DwarfMemory.h",
+    "src/libunwindstack/include/unwindstack/DwarfSection.h",
+    "src/libunwindstack/include/unwindstack/DwarfStructs.h",
+    "src/libunwindstack/include/unwindstack/Elf.h",
+    "src/libunwindstack/include/unwindstack/ElfInterface.h",
+    "src/libunwindstack/include/unwindstack/Error.h",
+    "src/libunwindstack/include/unwindstack/Global.h",
+    "src/libunwindstack/include/unwindstack/JitDebug.h",
+    "src/libunwindstack/include/unwindstack/LocalUnwinder.h",
+    "src/libunwindstack/include/unwindstack/Log.h",
+    "src/libunwindstack/include/unwindstack/Log.h",
+    "src/libunwindstack/include/unwindstack/MachineArm.h",
+    "src/libunwindstack/include/unwindstack/MachineArm64.h",
+    "src/libunwindstack/include/unwindstack/MachineMips.h",
+    "src/libunwindstack/include/unwindstack/MachineMips64.h",
+    "src/libunwindstack/include/unwindstack/MachineX86.h",
+    "src/libunwindstack/include/unwindstack/MachineX86_64.h",
+    "src/libunwindstack/include/unwindstack/MapInfo.h",
+    "src/libunwindstack/include/unwindstack/MapInfo.h",
+    "src/libunwindstack/include/unwindstack/Maps.h",
+    "src/libunwindstack/include/unwindstack/Maps.h",
+    "src/libunwindstack/include/unwindstack/Memory.h",
+    "src/libunwindstack/include/unwindstack/Regs.h",
+    "src/libunwindstack/include/unwindstack/Regs.h",
+    "src/libunwindstack/include/unwindstack/RegsArm.h",
+    "src/libunwindstack/include/unwindstack/RegsArm64.h",
+    "src/libunwindstack/include/unwindstack/RegsGetLocal.h",
+    "src/libunwindstack/include/unwindstack/RegsMips.h",
+    "src/libunwindstack/include/unwindstack/RegsMips64.h",
+    "src/libunwindstack/include/unwindstack/RegsX86.h",
+    "src/libunwindstack/include/unwindstack/RegsX86_64.h",
+    "src/libunwindstack/include/unwindstack/UcontextArm.h",
+    "src/libunwindstack/include/unwindstack/UcontextArm64.h",
+    "src/libunwindstack/include/unwindstack/UcontextMips.h",
+    "src/libunwindstack/include/unwindstack/UcontextMips64.h",
+    "src/libunwindstack/include/unwindstack/UcontextX86.h",
+    "src/libunwindstack/include/unwindstack/UcontextX86_64.h",
+    "src/libunwindstack/include/unwindstack/Unwinder.h",
+    "src/libunwindstack/include/unwindstack/UserArm.h",
+    "src/libunwindstack/include/unwindstack/UserArm.h",
+    "src/libunwindstack/include/unwindstack/UserArm64.h",
+    "src/libunwindstack/include/unwindstack/UserArm64.h",
+    "src/libunwindstack/include/unwindstack/UserMips.h",
+    "src/libunwindstack/include/unwindstack/UserMips.h",
+    "src/libunwindstack/include/unwindstack/UserMips64.h",
+    "src/libunwindstack/include/unwindstack/UserMips64.h",
+    "src/libunwindstack/include/unwindstack/UserX86.h",
+    "src/libunwindstack/include/unwindstack/UserX86.h",
+    "src/libunwindstack/include/unwindstack/UserX86_64.h",
   ]
   sources = [
     "src/android-base/file.cpp",
     "src/android-base/include/android-base/file.h",
     "src/android-base/include/android-base/macros.h",
     "src/android-base/include/android-base/off64_t.h",
-    "src/android-base/include/android-base/parseint.h",
     "src/android-base/include/android-base/stringprintf.h",
     "src/android-base/include/android-base/stringprintf.h",
     "src/android-base/include/android-base/strings.h",
diff --git a/src/android-base/include/android-base/parseint.h b/src/android-base/include/android-base/parseint.h
deleted file mode 100644
index be8b97b..0000000
--- a/src/android-base/include/android-base/parseint.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <limits>
-#include <string>
-#include <type_traits>
-
-namespace android {
-namespace base {
-
-// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value if it is specified. Optionally allows the caller to define
-// a 'max' beyond which otherwise valid values will be rejected. Returns boolean
-// success; 'out' is untouched if parsing fails.
-template <typename T>
-bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
-               bool allow_suffixes = false) {
-  static_assert(std::is_unsigned<T>::value, "ParseUint can only be used with unsigned types");
-  while (isspace(*s)) {
-    s++;
-  }
-
-  if (s[0] == '-') {
-    errno = EINVAL;
-    return false;
-  }
-
-  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
-  errno = 0;
-  char* end;
-  unsigned long long int result = strtoull(s, &end, base);
-  if (errno != 0) return false;
-  if (end == s) {
-    errno = EINVAL;
-    return false;
-  }
-  if (*end != '\0') {
-    const char* suffixes = "bkmgtpe";
-    const char* suffix;
-    if ((!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) ||
-        __builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) {
-      errno = EINVAL;
-      return false;
-    }
-  }
-  if (max < result) {
-    errno = ERANGE;
-    return false;
-  }
-  if (out != nullptr) {
-    *out = static_cast<T>(result);
-  }
-  return true;
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseUint(const std::string& s, T* out, T max = std::numeric_limits<T>::max(),
-               bool allow_suffixes = false) {
-  return ParseUint(s.c_str(), out, max, allow_suffixes);
-}
-
-template <typename T>
-bool ParseByteCount(const char* s, T* out, T max = std::numeric_limits<T>::max()) {
-  return ParseUint(s, out, max, true);
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseByteCount(const std::string& s, T* out, T max = std::numeric_limits<T>::max()) {
-  return ParseByteCount(s.c_str(), out, max);
-}
-
-// Parses the signed decimal or hexadecimal integer in the string 's' and sets
-// 'out' to that value if it is specified. Optionally allows the caller to define
-// a 'min' and 'max' beyond which otherwise valid values will be rejected. Returns
-// boolean success; 'out' is untouched if parsing fails.
-template <typename T>
-bool ParseInt(const char* s, T* out,
-              T min = std::numeric_limits<T>::min(),
-              T max = std::numeric_limits<T>::max()) {
-  static_assert(std::is_signed<T>::value, "ParseInt can only be used with signed types");
-  while (isspace(*s)) {
-    s++;
-  }
-
-  int base = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
-  errno = 0;
-  char* end;
-  long long int result = strtoll(s, &end, base);
-  if (errno != 0) {
-    return false;
-  }
-  if (s == end || *end != '\0') {
-    errno = EINVAL;
-    return false;
-  }
-  if (result < min || max < result) {
-    errno = ERANGE;
-    return false;
-  }
-  if (out != nullptr) {
-    *out = static_cast<T>(result);
-  }
-  return true;
-}
-
-// TODO: string_view
-template <typename T>
-bool ParseInt(const std::string& s, T* out,
-              T min = std::numeric_limits<T>::min(),
-              T max = std::numeric_limits<T>::max()) {
-  return ParseInt(s.c_str(), out, min, max);
-}
-
-}  // namespace base
-}  // namespace android
diff --git a/tools/sources.py b/tools/sources.py
index 81545a5..2e7e9e4 100755
--- a/tools/sources.py
+++ b/tools/sources.py
@@ -2,7 +2,7 @@
 # Copyright 2019 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.
-'''A tool that helps ease libunwindstack updates by listing the
+'''A tool that helps ease libunwindstack updates by managing the
 platform/system/core source files that are actually needed for libunwindstack to
 compile.
 
@@ -18,10 +18,14 @@
 import subprocess
 import sys
 
+_LIBUNWINDSTACK_ROOT = os.path.abspath(
+    os.path.join(os.path.dirname(__file__), os.pardir))
+_LIBUNWINDSTACK_SRC_ROOT = os.path.join(_LIBUNWINDSTACK_ROOT, 'src')
+
 
 def GenerateDepFiles(ninja_build_dir):
-  """Generates the dependency files that tell us which sources are used to
-  compile libunwindstack."""
+  '''Generates the dependency files that tell us which sources are used to
+  compile libunwindstack.'''
   # We need to clean the build directory for two reasons:
   #
   # 1) This eliminates the risk that there are stale depfiles from previous
@@ -47,10 +51,10 @@
                         stderr=sys.stderr)
 
 
-def ExtractSources(ninja_build_dir):
-  """Assuming that the .o.d depfiles have already been generated by a build,
+def ExtractRequiredSources(ninja_build_dir):
+  '''Assuming that the .o.d depfiles have already been generated by a build,
   parses the depfiles and returns a list of the C++ files in libunwindstack/src/
-  that are needed to compile libunwindstack."""
+  that are needed to compile libunwindstack.'''
   aggregate_deps_process = subprocess.Popen([
       'find', '{}/obj/third_party/libunwindstack/'.format(ninja_build_dir),
       '-name', '*.o.d'
@@ -77,7 +81,7 @@
   # We're looking explicitly for the platform/system/core C++ source code
   # dependencies, so we use a regexp to extract these and ignore other
   # dependencies (e.g. src/third_party/lzma_sdk/) and .o target names.
-  rel_sources = re.findall(r"third_party/libunwindstack/(src/\S+)", sources)
+  rel_sources = re.findall(r'third_party/libunwindstack/(src/\S+)', sources)
   return sorted(set(rel_sources))
 
 
@@ -88,10 +92,31 @@
   print(']')
 
 
+def PruneUnrequiredSources(required_sources):
+  required_abs_sources = [
+      os.path.join(_LIBUNWINDSTACK_ROOT, src) for src in required_sources
+  ]
+  current_sources = []
+
+  for subdir, _, files in os.walk(_LIBUNWINDSTACK_SRC_ROOT):
+    for f in files:
+      current_sources.append(os.path.join(subdir, f))
+
+  sources_to_remove = sorted(set(current_sources) - set(required_abs_sources))
+  print('Removed the following sources:')
+  for source in sources_to_remove:
+    os.remove(source)
+    print('{}'.format(source))
+
+
 def Main():
   parser = argparse.ArgumentParser(description=__doc__)
+  subparsers = parser.add_subparsers(dest='subcommand')
+  print_parser = subparsers.add_parser(
+      'print', help='Print the list of required sources to STDOUT.')
+  prune_parser = subparsers.add_parser(
+      'prune', help='Prune unrequired sources from the src/ directory.')
 
-  # TODO(charliea): Add a command to prune unnecessary deps.
   parser.add_argument(
       'ninja_build_dir',
       help='Change to DIR before compiling (ninja build directory)')
@@ -104,9 +129,13 @@
         'Ninja build directory {} does not exist.'.format(ninja_build_dir))
 
   GenerateDepFiles(ninja_build_dir)
-  sources = ExtractSources(ninja_build_dir)
+  required_sources = ExtractRequiredSources(ninja_build_dir)
 
-  PrintGnFormattedSources(sources)
+  if args.subcommand == 'print':
+    PrintGnFormattedSources(required_sources)
+  elif args.subcommand == 'prune':
+    PruneUnrequiredSources(required_sources)
+
   return 0