Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: tools/gn/json_project_writer.cc

Issue 2064533002: [GN] Add JSON project writer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase, fix build, fix variable names Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016 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 "tools/gn/json_project_writer.h"
6
7 #include <iostream>
8
9 #include "base/command_line.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "tools/gn/builder.h"
14 #include "tools/gn/commands.h"
15 #include "tools/gn/deps_iterator.h"
16 #include "tools/gn/desc_builder.h"
17 #include "tools/gn/exec_process.h"
18 #include "tools/gn/filesystem_utils.h"
19 #include "tools/gn/settings.h"
20
21 namespace {
22
23 void add_target_dependencies(const Target* target,
brettw 2016/07/06 22:19:26 These local functions should use CamelCase like "A
matt.k 2016/07/08 00:39:07 Done.
24 std::set<const Target*>* deps) {
25 for (const auto& pair : target->GetDeps(Target::DEPS_LINKED)) {
26 if (deps->find(pair.ptr) == deps->end()) {
27 deps->insert(pair.ptr);
28 add_target_dependencies(pair.ptr, deps);
29 }
30 }
31 }
32
33 // Filters targets according to filter string; Will also recursively
34 // add dependent targets.
35 bool filter_targets(const BuildSettings* build_settings,
36 std::vector<const Target*>& all_targets,
37 std::vector<const Target*>* targets,
38 const std::string& dir_filter_string,
39 Err* err) {
40 if (dir_filter_string.empty()) {
41 *targets = all_targets;
42 } else {
43 targets->reserve(all_targets.size());
44 std::vector<LabelPattern> filters;
45 if (!commands::FilterPatternsFromString(build_settings, dir_filter_string,
46 &filters, err)) {
47 return false;
48 }
49 commands::FilterTargetsByPatterns(all_targets, filters, targets);
50
51 std::set<const Target*> target_set(targets->begin(), targets->end());
52 for (const auto* target : *targets)
53 add_target_dependencies(target, &target_set);
54
55 targets->clear();
56 targets->insert(targets->end(), target_set.begin(), target_set.end());
57 }
58
59 // Sort the list of targets per-label to get a consistent ordering of them
60 // in the generated Xcode project (and thus stability of the file generated).
brettw 2016/07/06 22:19:26 This is a general file and probably shouldn't refe
matt.k 2016/07/08 00:39:08 Done.
61 std::sort(targets->begin(), targets->end(),
62 [](const Target* a, const Target* b) {
63 return a->label().name() < b->label().name();
64 });
65
66 return true;
67 }
68
69 std::string render_json(const BuildSettings* build_settings,
70 const Builder* builder,
71 std::vector<const Target*>& all_targets) {
72 Label default_toolchain_label;
73
74 auto targets = base::WrapUnique(new base::DictionaryValue());
75 for (const auto* target : all_targets) {
76 if (default_toolchain_label.is_null())
77 default_toolchain_label = target->settings()->default_toolchain_label();
78 auto description =
79 DescBuilder::DescriptionForTarget(target, "", false, false, false);
80 // outputs need to be asked for separately
brettw 2016/07/06 22:19:26 Can you make this a sentence with a capital and pe
matt.k 2016/07/08 00:39:08 Done.
81 auto outputs = DescBuilder::DescriptionForTarget(target, "source_outputs",
82 false, false, false);
83 description->MergeDictionary(outputs.get());
84 targets->Set(target->label().GetUserVisibleName(default_toolchain_label),
85 std::move(description));
86 }
87
88 auto settings = base::WrapUnique(new base::DictionaryValue());
89 settings->SetString("root_path", build_settings->root_path_utf8());
90 settings->SetString("build_dir", build_settings->build_dir().value());
91 settings->SetString("default_toolchain",
92 default_toolchain_label.GetUserVisibleName(false));
93
94 auto output = base::WrapUnique(new base::DictionaryValue());
95 output->Set("targets", std::move(targets));
96 output->Set("build_settings", std::move(settings));
97
98 std::string s;
99 base::JSONWriter::WriteWithOptions(
100 *output.get(), base::JSONWriter::OPTIONS_PRETTY_PRINT, &s);
101 return s;
102 }
103
104 bool invoke_python(const BuildSettings* build_settings,
105 const base::FilePath& python_script_path,
106 const std::string& python_script_extra_args,
107 const base::FilePath& output_path,
108 bool quiet,
109 Err* err) {
110 const base::FilePath& python_path = build_settings->python_path();
111 base::CommandLine cmdline(python_path);
112 cmdline.AppendArg("--");
113 cmdline.AppendArgPath(python_script_path);
114 cmdline.AppendArgPath(output_path);
115 if (!python_script_extra_args.empty()) {
116 cmdline.AppendArg(python_script_extra_args);
117 }
118 base::FilePath startup_dir =
119 build_settings->GetFullPath(build_settings->build_dir());
120
121 std::string output;
122 std::string stderr_output;
123
124 int exit_code = 0;
125 if (!internal::ExecProcess(cmdline, startup_dir, &output, &stderr_output,
126 &exit_code)) {
127 *err =
128 Err(Location(), "Could not execute python.",
129 "I was trying to execute \"" + FilePathToUTF8(python_path) + "\".");
130 return false;
131 }
132
133 if (!quiet) {
134 std::cout << output;
135 std::cerr << stderr_output;
136 }
137
138 if (exit_code != 0) {
139 *err = Err(Location(), "Python has quit with exit code " +
140 base::IntToString(exit_code) + ".");
141 return false;
142 }
143
144 return true;
145 }
146
147 } // namespace
148
149 bool JSONProjectWriter::RunAndWriteFiles(
150 const BuildSettings* build_settings,
151 const Builder* builder,
152 const std::string& file_name,
153 const std::string& exec_script,
154 const std::string& exec_script_extra_args,
155 const std::string& dir_filter_string,
156 bool quiet,
157 Err* err) {
158 SourceFile output_file = build_settings->build_dir().ResolveRelativeFile(
159 Value(nullptr, file_name), err);
160 if (output_file.is_null()) {
161 return false;
162 }
163
164 base::FilePath output_path = build_settings->GetFullPath(output_file);
165
166 std::vector<const Target*> all_targets = builder->GetAllResolvedTargets();
167 std::vector<const Target*> targets;
168 if (!filter_targets(build_settings, all_targets, &targets, dir_filter_string,
169 err)) {
170 return false;
171 }
172
173 std::string json = render_json(build_settings, builder, targets);
174 if (!ContentsEqual(output_path, json)) {
175 if (!WriteFileIfChanged(output_path, json, err)) {
176 return false;
177 }
178
179 if (!exec_script.empty()) {
180 SourceFile script_file;
181 if (exec_script[0] != '/') {
182 // relative path, assume the base is in build_dir
brettw 2016/07/06 22:19:26 Same "complete sentence" comment from above.
matt.k 2016/07/08 00:39:07 Done.
183 script_file = build_settings->build_dir().ResolveRelativeFile(
184 Value(nullptr, exec_script), err);
185 if (script_file.is_null()) {
186 return false;
187 }
188 } else {
189 script_file = SourceFile(exec_script);
190 }
191 base::FilePath script_path = build_settings->GetFullPath(script_file);
192 return invoke_python(build_settings, script_path, exec_script_extra_args,
193 output_path, quiet, err);
194 }
195 }
196
197 return true;
198 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698