Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / tools / gn / command_refs.cc
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <set>
6
7 #include "base/command_line.h"
8 #include "tools/gn/commands.h"
9 #include "tools/gn/filesystem_utils.h"
10 #include "tools/gn/input_file.h"
11 #include "tools/gn/item.h"
12 #include "tools/gn/pattern.h"
13 #include "tools/gn/setup.h"
14 #include "tools/gn/standard_out.h"
15 #include "tools/gn/target.h"
16
17 namespace commands {
18
19 namespace {
20
21 // Returns the file path generating this record.
22 base::FilePath FilePathForRecord(const BuilderRecord* record) {
23   if (!record->item())
24     return base::FilePath(FILE_PATH_LITERAL("=UNRESOLVED DEPENDENCY="));
25   return record->item()->defined_from()->GetRange().begin().file()
26       ->physical_name();
27 }
28
29 }  // namespace
30
31 const char kRefs[] = "refs";
32 const char kRefs_HelpShort[] =
33     "refs: Find stuff referencing a target, directory, or config.";
34 const char kRefs_Help[] =
35     "gn refs <label_pattern> [--files]\n"
36     "\n"
37     "  Finds code referencing a given label. The label can be a\n"
38     "  target or config name. Unlike most other commands, unresolved\n"
39     "  dependencies will be tolerated. This allows you to use this command\n"
40     "  to find references to targets you're in the process of moving.\n"
41     "\n"
42     "  By default, the mapping from source item to dest item (where the\n"
43     "  pattern matches the dest item). See \"gn help pattern\" for\n"
44     "  information on pattern-matching rules.\n"
45     "\n"
46     "Option:\n"
47     "  --files\n"
48     "      Output unique filenames referencing a matched target or config.\n"
49     "\n"
50     "Examples:\n"
51     "  gn refs \"//tools/gn/*\"\n"
52     "      Find all targets depending on any target or config in the\n"
53     "      \"tools/gn\" directory.\n"
54     "\n"
55     "  gn refs //tools/gn:gn\n"
56     "      Find all targets depending on the given exact target name.\n"
57     "\n"
58     "  gn refs \"*gtk*\" --files\n"
59     "      Find all unique buildfiles with a dependency on a target that has\n"
60     "      the substring \"gtk\" in the name.\n";
61
62 int RunRefs(const std::vector<std::string>& args) {
63   if (args.size() != 1 && args.size() != 2) {
64     Err(Location(), "You're holding it wrong.",
65         "Usage: \"gn refs <label_pattern>\"").PrintToStdout();
66     return 1;
67   }
68
69   Pattern pattern(args[0]);
70   // Check for common errors on input.
71   if (args[0].find('*') == std::string::npos) {
72     // We need to begin with a "//" and have a colon if there's no "*" or it
73     // will be impossible to match anything.
74     if (args[0].size() < 2 ||
75         (args[0][0] != '/' && args[0][1] != '/') ||
76         args[0].find(':') == std::string::npos) {
77       OutputString("Assuming \"*" + args[0] +
78                        "*\". See \"gn help refs\" for more information.\n",
79                    DECORATION_YELLOW);
80       pattern = Pattern("*" + args[0] + "*");
81     }
82   }
83
84   Setup* setup = new Setup;
85   setup->set_check_for_bad_items(false);
86   // TODO(brettw) bug 343726: Use a temporary directory instead of this
87   // default one to avoid messing up any build that's in there.
88   if (!setup->DoSetup("//out/Default/") || !setup->Run())
89     return 1;
90
91   std::vector<const BuilderRecord*> records = setup->builder()->GetAllRecords();
92
93   const CommandLine* cmdline = CommandLine::ForCurrentProcess();
94
95   bool file_output = cmdline->HasSwitch("files");
96   std::set<std::string> unique_output;
97
98   for (size_t record_index = 0; record_index < records.size(); record_index++) {
99     const BuilderRecord* record = records[record_index];
100     const BuilderRecord::BuilderRecordSet& deps = record->all_deps();
101     for (BuilderRecord::BuilderRecordSet::const_iterator d = deps.begin();
102          d != deps.end(); ++d) {
103       std::string label = (*d)->label().GetUserVisibleName(false);
104       if (pattern.MatchesString(label)) {
105         // Got a match.
106         if (file_output) {
107           unique_output.insert(FilePathToUTF8(FilePathForRecord(record)));
108           break;  // Found a match for this target's file, don't need more.
109         } else {
110           // We can get dupes when there are differnet toolchains involved,
111           // so we want to send all output through the de-duper.
112           unique_output.insert(
113               record->item()->label().GetUserVisibleName(false) + " -> " +
114               label);
115         }
116       }
117     }
118   }
119
120   for (std::set<std::string>::iterator i = unique_output.begin();
121        i != unique_output.end(); ++i)
122     OutputString(*i + "\n");
123
124   return 0;
125 }
126
127 }  // namespace commands