summaryrefslogtreecommitdiff
path: root/chromium/tools/gn/command_analyze.cc
blob: 9aa698b3c152273397e9366817401df63b304898 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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;
  }

  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