| // 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 |