| // Copyright (c) 2013 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 <algorithm> | 
 | #include <iterator> | 
 | #include <set> | 
 | #include <vector> | 
 |  | 
 | #include "base/files/file_path.h" | 
 | #include "base/files/file_util.h" | 
 | #include "tools/gn/analyzer.h" | 
 | #include "tools/gn/commands.h" | 
 | #include "tools/gn/filesystem_utils.h" | 
 | #include "tools/gn/location.h" | 
 | #include "tools/gn/setup.h" | 
 |  | 
 | namespace commands { | 
 |  | 
 | const char kAnalyze[] = "analyze"; | 
 | const char kAnalyze_HelpShort[] = | 
 |     "analyze: Analyze which targets are affected by a list of files."; | 
 | const char kAnalyze_Help[] = | 
 |     R"(gn analyze <out_dir> <input_path> <output_path> | 
 |  | 
 |   Analyze which targets are affected by a list of files. | 
 |  | 
 |   This command takes three arguments: | 
 |  | 
 |   out_dir is the path to the build directory. | 
 |  | 
 |   input_path is a path to a file containing a JSON object with three fields: | 
 |  | 
 |    - "files": A list of the filenames to check. | 
 |  | 
 |    - "test_targets": A list of the labels for targets that are needed to run | 
 |      the tests we wish to run. | 
 |  | 
 |    - "additional_compile_targets": A list of the labels for targets that we | 
 |      wish to rebuild, but aren't necessarily needed for testing. The important | 
 |      difference between this field and "test_targets" is that if an item in | 
 |      the additional_compile_targets list refers to a group, then any | 
 |      dependencies of that group will be returned if they are out of date, but | 
 |      the group itself does not need to be. If the dependencies themselves are | 
 |      groups, the same filtering is repeated. This filtering can be used to | 
 |      avoid rebuilding dependencies of a group that are unaffected by the input | 
 |      files. The list may also contain the string "all" to refer to a | 
 |      pseudo-group that contains every root target in the build graph. | 
 |  | 
 |      This filtering behavior is also known as "pruning" the list of compile | 
 |      targets. | 
 |  | 
 |   output_path is a path indicating where the results of the command are to be | 
 |   written. The results will be a file containing a JSON object with one or more | 
 |   of following fields: | 
 |  | 
 |    - "compile_targets": A list of the labels derived from the input | 
 |      compile_targets list that are affected by the input files. Due to the way | 
 |      the filtering works for compile targets as described above, this list may | 
 |      contain targets that do not appear in the input list. | 
 |  | 
 |    - "test_targets": A list of the labels from the input test_targets list that | 
 |      are affected by the input files. This list will be a proper subset of the | 
 |      input list. | 
 |  | 
 |    - "invalid_targets": A list of any names from the input that do not exist in | 
 |      the build graph. If this list is non-empty, the "error" field will also be | 
 |      set to "Invalid targets". | 
 |  | 
 |    - "status": A string containing one of three values: | 
 |  | 
 |        - "Found dependency" | 
 |        - "No dependency" | 
 |        - "Found dependency (all) " | 
 |  | 
 |      In the first case, the lists returned in compile_targets and test_targets | 
 |      should be passed to ninja to build. In the second case, nothing was | 
 |      affected and no build is necessary. In the third case, GN could not | 
 |      determine the correct answer and returned the input as the output in order | 
 |      to be safe. | 
 |  | 
 |    - "error": This will only be present if an error occurred, and will contain | 
 |      a string describing the error. This includes cases where the input file is | 
 |      not in the right format, or contains invalid targets. | 
 |  | 
 |   The command returns 1 if it is unable to read the input file or write the | 
 |   output file, or if there is something wrong with the build such that gen | 
 |   would also fail, and 0 otherwise. In particular, it returns 0 even if the | 
 |   "error" key is non-empty and a non-fatal error occurred. In other words, it | 
 |   tries really hard to always write something to the output JSON and convey | 
 |   errors that way rather than via return codes. | 
 | )"; | 
 |  | 
 | int RunAnalyze(const std::vector<std::string>& args) { | 
 |   if (args.size() != 3) { | 
 |     Err(Location(), "You're holding it wrong.", | 
 |         "Usage: \"gn analyze <out_dir> <input_path> <output_path>") | 
 |         .PrintToStdout(); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   std::string input; | 
 |   bool ret = base::ReadFileToString(UTF8ToFilePath(args[1]), &input); | 
 |   if (!ret) { | 
 |     Err(Location(), "Input file " + args[1] + " not found.").PrintToStdout(); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   // Deliberately leaked to avoid expensive process teardown. | 
 |   Setup* setup = new Setup; | 
 |   if (!setup->DoSetup(args[0], false) || !setup->Run()) | 
 |     return 1; | 
 |  | 
 |   Err err; | 
 |   Analyzer analyzer( | 
 |       setup->builder(), setup->build_settings().build_config_file(), | 
 |       setup->GetDotFile(), | 
 |       setup->build_settings().build_args().build_args_dependency_files()); | 
 |   std::string output = analyzer.Analyze(input, &err); | 
 |   if (err.has_error()) { | 
 |     err.PrintToStdout(); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   WriteFile(UTF8ToFilePath(args[2]), output, &err); | 
 |   if (err.has_error()) { | 
 |     err.PrintToStdout(); | 
 |     return 1; | 
 |   } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | }  // namespace commands |