xref: /aosp_15_r20/external/perfetto/src/tools/proto_merger/main.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker /*
2*6dbdd20aSAndroid Build Coastguard Worker  * Copyright (C) 2021 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker  *
4*6dbdd20aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker  *
8*6dbdd20aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker  *
10*6dbdd20aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker  * limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker  */
16*6dbdd20aSAndroid Build Coastguard Worker 
17*6dbdd20aSAndroid Build Coastguard Worker #include <stdio.h>
18*6dbdd20aSAndroid Build Coastguard Worker #include <string>
19*6dbdd20aSAndroid Build Coastguard Worker 
20*6dbdd20aSAndroid Build Coastguard Worker #include <google/protobuf/compiler/importer.h>
21*6dbdd20aSAndroid Build Coastguard Worker #include <google/protobuf/io/zero_copy_stream_impl.h>
22*6dbdd20aSAndroid Build Coastguard Worker 
23*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/base/logging.h"
24*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/file_utils.h"
25*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/getopt.h"
26*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/scoped_file.h"
27*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/string_utils.h"
28*6dbdd20aSAndroid Build Coastguard Worker #include "perfetto/ext/base/version.h"
29*6dbdd20aSAndroid Build Coastguard Worker #include "src/tools/proto_merger/allowlist.h"
30*6dbdd20aSAndroid Build Coastguard Worker #include "src/tools/proto_merger/proto_file.h"
31*6dbdd20aSAndroid Build Coastguard Worker #include "src/tools/proto_merger/proto_file_serializer.h"
32*6dbdd20aSAndroid Build Coastguard Worker #include "src/tools/proto_merger/proto_merger.h"
33*6dbdd20aSAndroid Build Coastguard Worker 
34*6dbdd20aSAndroid Build Coastguard Worker namespace perfetto {
35*6dbdd20aSAndroid Build Coastguard Worker namespace proto_merger {
36*6dbdd20aSAndroid Build Coastguard Worker namespace {
37*6dbdd20aSAndroid Build Coastguard Worker 
38*6dbdd20aSAndroid Build Coastguard Worker class MultiFileErrorCollectorImpl
39*6dbdd20aSAndroid Build Coastguard Worker     : public google::protobuf::compiler::MultiFileErrorCollector {
40*6dbdd20aSAndroid Build Coastguard Worker  public:
41*6dbdd20aSAndroid Build Coastguard Worker   ~MultiFileErrorCollectorImpl() override;
42*6dbdd20aSAndroid Build Coastguard Worker   void AddError(const std::string&, int, int, const std::string&) override;
43*6dbdd20aSAndroid Build Coastguard Worker   void AddWarning(const std::string&, int, int, const std::string&) override;
44*6dbdd20aSAndroid Build Coastguard Worker };
45*6dbdd20aSAndroid Build Coastguard Worker 
46*6dbdd20aSAndroid Build Coastguard Worker MultiFileErrorCollectorImpl::~MultiFileErrorCollectorImpl() = default;
47*6dbdd20aSAndroid Build Coastguard Worker 
AddError(const std::string & filename,int line,int column,const std::string & message)48*6dbdd20aSAndroid Build Coastguard Worker void MultiFileErrorCollectorImpl::AddError(const std::string& filename,
49*6dbdd20aSAndroid Build Coastguard Worker                                            int line,
50*6dbdd20aSAndroid Build Coastguard Worker                                            int column,
51*6dbdd20aSAndroid Build Coastguard Worker                                            const std::string& message) {
52*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_ELOG("Error %s %d:%d: %s", filename.c_str(), line, column,
53*6dbdd20aSAndroid Build Coastguard Worker                 message.c_str());
54*6dbdd20aSAndroid Build Coastguard Worker }
55*6dbdd20aSAndroid Build Coastguard Worker 
AddWarning(const std::string & filename,int line,int column,const std::string & message)56*6dbdd20aSAndroid Build Coastguard Worker void MultiFileErrorCollectorImpl::AddWarning(const std::string& filename,
57*6dbdd20aSAndroid Build Coastguard Worker                                              int line,
58*6dbdd20aSAndroid Build Coastguard Worker                                              int column,
59*6dbdd20aSAndroid Build Coastguard Worker                                              const std::string& message) {
60*6dbdd20aSAndroid Build Coastguard Worker   PERFETTO_ELOG("Warning %s %d:%d: %s", filename.c_str(), line, column,
61*6dbdd20aSAndroid Build Coastguard Worker                 message.c_str());
62*6dbdd20aSAndroid Build Coastguard Worker }
63*6dbdd20aSAndroid Build Coastguard Worker 
64*6dbdd20aSAndroid Build Coastguard Worker struct ImportResult {
65*6dbdd20aSAndroid Build Coastguard Worker   std::unique_ptr<google::protobuf::compiler::Importer> importer;
66*6dbdd20aSAndroid Build Coastguard Worker   const google::protobuf::FileDescriptor* file_descriptor;
67*6dbdd20aSAndroid Build Coastguard Worker };
68*6dbdd20aSAndroid Build Coastguard Worker 
ImportProto(const std::string & proto_file,const std::string & proto_dir_path)69*6dbdd20aSAndroid Build Coastguard Worker ImportResult ImportProto(const std::string& proto_file,
70*6dbdd20aSAndroid Build Coastguard Worker                          const std::string& proto_dir_path) {
71*6dbdd20aSAndroid Build Coastguard Worker   MultiFileErrorCollectorImpl mfe;
72*6dbdd20aSAndroid Build Coastguard Worker 
73*6dbdd20aSAndroid Build Coastguard Worker   google::protobuf::compiler::DiskSourceTree dst;
74*6dbdd20aSAndroid Build Coastguard Worker   dst.MapPath("", proto_dir_path);
75*6dbdd20aSAndroid Build Coastguard Worker 
76*6dbdd20aSAndroid Build Coastguard Worker   ImportResult result;
77*6dbdd20aSAndroid Build Coastguard Worker   result.importer.reset(new google::protobuf::compiler::Importer(&dst, &mfe));
78*6dbdd20aSAndroid Build Coastguard Worker   result.file_descriptor = result.importer->Import(proto_file);
79*6dbdd20aSAndroid Build Coastguard Worker   return result;
80*6dbdd20aSAndroid Build Coastguard Worker }
81*6dbdd20aSAndroid Build Coastguard Worker 
82*6dbdd20aSAndroid Build Coastguard Worker const char kUsage[] =
83*6dbdd20aSAndroid Build Coastguard Worker     R"(Usage: proto_merger [-i input proto] [-I import dir]
84*6dbdd20aSAndroid Build Coastguard Worker 
85*6dbdd20aSAndroid Build Coastguard Worker -i, --input:                 Path to the input .proto file (relative to
86*6dbdd20aSAndroid Build Coastguard Worker                               --input-include directory). The contents of this
87*6dbdd20aSAndroid Build Coastguard Worker                               file will be updated using the upstream proto.
88*6dbdd20aSAndroid Build Coastguard Worker -I, --input-include:         Root directory from which includes for --input
89*6dbdd20aSAndroid Build Coastguard Worker                               proto should be searched.
90*6dbdd20aSAndroid Build Coastguard Worker -u, --upstream:              Path to the upstream .proto file; the contents of
91*6dbdd20aSAndroid Build Coastguard Worker                               this file will be used to update
92*6dbdd20aSAndroid Build Coastguard Worker                               the input proto.
93*6dbdd20aSAndroid Build Coastguard Worker -U, --upstream-include:      Root directory from which includes for --upstream
94*6dbdd20aSAndroid Build Coastguard Worker                               proto should be searched.
95*6dbdd20aSAndroid Build Coastguard Worker -a, --allowlist:             Allowlist file which is used to add new fields in
96*6dbdd20aSAndroid Build Coastguard Worker                               the upstream proto to the input proto.
97*6dbdd20aSAndroid Build Coastguard Worker -r, --upstream-root-message: Root message in the upstream proto for which new
98*6dbdd20aSAndroid Build Coastguard Worker                               fields from the allowlist will be allowed.
99*6dbdd20aSAndroid Build Coastguard Worker -o, --output:                Output path for writing the merged proto file.
100*6dbdd20aSAndroid Build Coastguard Worker 
101*6dbdd20aSAndroid Build Coastguard Worker Example usage:
102*6dbdd20aSAndroid Build Coastguard Worker 
103*6dbdd20aSAndroid Build Coastguard Worker # Updating logs proto from Perfetto repo (must be run in G3):
104*6dbdd20aSAndroid Build Coastguard Worker   proto_merger \
105*6dbdd20aSAndroid Build Coastguard Worker     -u third_party/perfetto/protos/perfetto/trace/perfetto_trace.proto \
106*6dbdd20aSAndroid Build Coastguard Worker     -U . \
107*6dbdd20aSAndroid Build Coastguard Worker     -i <path to logs proto>/perfetto_log.proto \
108*6dbdd20aSAndroid Build Coastguard Worker     -I . \
109*6dbdd20aSAndroid Build Coastguard Worker     --allowlist /tmp/allowlist.txt \
110*6dbdd20aSAndroid Build Coastguard Worker     -r perfetto.protos.Trace \
111*6dbdd20aSAndroid Build Coastguard Worker     --output /tmp/output.proto
112*6dbdd20aSAndroid Build Coastguard Worker )";
113*6dbdd20aSAndroid Build Coastguard Worker 
Main(int argc,char ** argv)114*6dbdd20aSAndroid Build Coastguard Worker int Main(int argc, char** argv) {
115*6dbdd20aSAndroid Build Coastguard Worker   static const option long_options[] = {
116*6dbdd20aSAndroid Build Coastguard Worker       {"help", no_argument, nullptr, 'h'},
117*6dbdd20aSAndroid Build Coastguard Worker       {"version", no_argument, nullptr, 'v'},
118*6dbdd20aSAndroid Build Coastguard Worker       {"input", required_argument, nullptr, 'i'},
119*6dbdd20aSAndroid Build Coastguard Worker       {"input-include", required_argument, nullptr, 'I'},
120*6dbdd20aSAndroid Build Coastguard Worker       {"upstream", required_argument, nullptr, 'u'},
121*6dbdd20aSAndroid Build Coastguard Worker       {"upstream-include", required_argument, nullptr, 'U'},
122*6dbdd20aSAndroid Build Coastguard Worker       {"allowlist", required_argument, nullptr, 'a'},
123*6dbdd20aSAndroid Build Coastguard Worker       {"upstream-root-message", required_argument, nullptr, 'r'},
124*6dbdd20aSAndroid Build Coastguard Worker       {"output", required_argument, nullptr, 'o'},
125*6dbdd20aSAndroid Build Coastguard Worker       {nullptr, 0, nullptr, 0}};
126*6dbdd20aSAndroid Build Coastguard Worker 
127*6dbdd20aSAndroid Build Coastguard Worker   std::string input;
128*6dbdd20aSAndroid Build Coastguard Worker   std::string input_include;
129*6dbdd20aSAndroid Build Coastguard Worker   std::string upstream;
130*6dbdd20aSAndroid Build Coastguard Worker   std::string upstream_include;
131*6dbdd20aSAndroid Build Coastguard Worker   std::string allowlist;
132*6dbdd20aSAndroid Build Coastguard Worker   std::string upstream_root_message;
133*6dbdd20aSAndroid Build Coastguard Worker   std::string output;
134*6dbdd20aSAndroid Build Coastguard Worker 
135*6dbdd20aSAndroid Build Coastguard Worker   for (;;) {
136*6dbdd20aSAndroid Build Coastguard Worker     int option =
137*6dbdd20aSAndroid Build Coastguard Worker         getopt_long(argc, argv, "hvi:I:u:U:a:r:o:", long_options, nullptr);
138*6dbdd20aSAndroid Build Coastguard Worker 
139*6dbdd20aSAndroid Build Coastguard Worker     if (option == -1)
140*6dbdd20aSAndroid Build Coastguard Worker       break;  // EOF.
141*6dbdd20aSAndroid Build Coastguard Worker 
142*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'v') {
143*6dbdd20aSAndroid Build Coastguard Worker       printf("%s\n", base::GetVersionString());
144*6dbdd20aSAndroid Build Coastguard Worker       return 0;
145*6dbdd20aSAndroid Build Coastguard Worker     }
146*6dbdd20aSAndroid Build Coastguard Worker 
147*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'i') {
148*6dbdd20aSAndroid Build Coastguard Worker       input = optarg;
149*6dbdd20aSAndroid Build Coastguard Worker       continue;
150*6dbdd20aSAndroid Build Coastguard Worker     }
151*6dbdd20aSAndroid Build Coastguard Worker 
152*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'I') {
153*6dbdd20aSAndroid Build Coastguard Worker       input_include = optarg;
154*6dbdd20aSAndroid Build Coastguard Worker       continue;
155*6dbdd20aSAndroid Build Coastguard Worker     }
156*6dbdd20aSAndroid Build Coastguard Worker 
157*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'u') {
158*6dbdd20aSAndroid Build Coastguard Worker       upstream = optarg;
159*6dbdd20aSAndroid Build Coastguard Worker       continue;
160*6dbdd20aSAndroid Build Coastguard Worker     }
161*6dbdd20aSAndroid Build Coastguard Worker 
162*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'U') {
163*6dbdd20aSAndroid Build Coastguard Worker       upstream_include = optarg;
164*6dbdd20aSAndroid Build Coastguard Worker       continue;
165*6dbdd20aSAndroid Build Coastguard Worker     }
166*6dbdd20aSAndroid Build Coastguard Worker 
167*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'a') {
168*6dbdd20aSAndroid Build Coastguard Worker       allowlist = optarg;
169*6dbdd20aSAndroid Build Coastguard Worker       continue;
170*6dbdd20aSAndroid Build Coastguard Worker     }
171*6dbdd20aSAndroid Build Coastguard Worker 
172*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'r') {
173*6dbdd20aSAndroid Build Coastguard Worker       upstream_root_message = optarg;
174*6dbdd20aSAndroid Build Coastguard Worker       continue;
175*6dbdd20aSAndroid Build Coastguard Worker     }
176*6dbdd20aSAndroid Build Coastguard Worker 
177*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'o') {
178*6dbdd20aSAndroid Build Coastguard Worker       output = optarg;
179*6dbdd20aSAndroid Build Coastguard Worker       continue;
180*6dbdd20aSAndroid Build Coastguard Worker     }
181*6dbdd20aSAndroid Build Coastguard Worker 
182*6dbdd20aSAndroid Build Coastguard Worker     if (option == 'h') {
183*6dbdd20aSAndroid Build Coastguard Worker       fprintf(stdout, kUsage);
184*6dbdd20aSAndroid Build Coastguard Worker       return 0;
185*6dbdd20aSAndroid Build Coastguard Worker     }
186*6dbdd20aSAndroid Build Coastguard Worker 
187*6dbdd20aSAndroid Build Coastguard Worker     fprintf(stderr, kUsage);
188*6dbdd20aSAndroid Build Coastguard Worker     return 1;
189*6dbdd20aSAndroid Build Coastguard Worker   }
190*6dbdd20aSAndroid Build Coastguard Worker 
191*6dbdd20aSAndroid Build Coastguard Worker   if (input.empty()) {
192*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Input proto (--input) should be specified");
193*6dbdd20aSAndroid Build Coastguard Worker     return 1;
194*6dbdd20aSAndroid Build Coastguard Worker   }
195*6dbdd20aSAndroid Build Coastguard Worker 
196*6dbdd20aSAndroid Build Coastguard Worker   if (input_include.empty()) {
197*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG(
198*6dbdd20aSAndroid Build Coastguard Worker         "Input include directory (--input-include) should be specified");
199*6dbdd20aSAndroid Build Coastguard Worker     return 1;
200*6dbdd20aSAndroid Build Coastguard Worker   }
201*6dbdd20aSAndroid Build Coastguard Worker 
202*6dbdd20aSAndroid Build Coastguard Worker   if (upstream.empty()) {
203*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Upstream proto (--upstream) should be specified");
204*6dbdd20aSAndroid Build Coastguard Worker     return 1;
205*6dbdd20aSAndroid Build Coastguard Worker   }
206*6dbdd20aSAndroid Build Coastguard Worker 
207*6dbdd20aSAndroid Build Coastguard Worker   if (upstream_include.empty()) {
208*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG(
209*6dbdd20aSAndroid Build Coastguard Worker         "Upstream include directory (--upstream-include) should be specified");
210*6dbdd20aSAndroid Build Coastguard Worker     return 1;
211*6dbdd20aSAndroid Build Coastguard Worker   }
212*6dbdd20aSAndroid Build Coastguard Worker 
213*6dbdd20aSAndroid Build Coastguard Worker   if (output.empty()) {
214*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Output file (--output) should be specified");
215*6dbdd20aSAndroid Build Coastguard Worker     return 1;
216*6dbdd20aSAndroid Build Coastguard Worker   }
217*6dbdd20aSAndroid Build Coastguard Worker 
218*6dbdd20aSAndroid Build Coastguard Worker   if (!allowlist.empty() && upstream_root_message.empty()) {
219*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG(
220*6dbdd20aSAndroid Build Coastguard Worker         "Need to specifiy upstream root message (--upstream-root-message) when "
221*6dbdd20aSAndroid Build Coastguard Worker         "specifying allowlist");
222*6dbdd20aSAndroid Build Coastguard Worker     return 1;
223*6dbdd20aSAndroid Build Coastguard Worker   }
224*6dbdd20aSAndroid Build Coastguard Worker 
225*6dbdd20aSAndroid Build Coastguard Worker   std::string input_contents;
226*6dbdd20aSAndroid Build Coastguard Worker   if (!base::ReadFile(input_include + "/" + input, &input_contents)) {
227*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Failed to read input");
228*6dbdd20aSAndroid Build Coastguard Worker     return 1;
229*6dbdd20aSAndroid Build Coastguard Worker   }
230*6dbdd20aSAndroid Build Coastguard Worker 
231*6dbdd20aSAndroid Build Coastguard Worker   static constexpr char kPremable[] =
232*6dbdd20aSAndroid Build Coastguard Worker       "// --- PREAMBLE ENDS HERE - EVERYTHING BELOW AUTOGENERATED ---\n";
233*6dbdd20aSAndroid Build Coastguard Worker   size_t input_premable_idx = input_contents.find(kPremable);
234*6dbdd20aSAndroid Build Coastguard Worker   std::string input_preamble =
235*6dbdd20aSAndroid Build Coastguard Worker       input_premable_idx == std::string::npos
236*6dbdd20aSAndroid Build Coastguard Worker           ? ""
237*6dbdd20aSAndroid Build Coastguard Worker           : input_contents.substr(0, input_premable_idx + strlen(kPremable));
238*6dbdd20aSAndroid Build Coastguard Worker 
239*6dbdd20aSAndroid Build Coastguard Worker   ImportResult input_proto = ImportProto(input, input_include);
240*6dbdd20aSAndroid Build Coastguard Worker   ProtoFile input_file = ProtoFileFromDescriptor(std::move(input_preamble),
241*6dbdd20aSAndroid Build Coastguard Worker                                                  *input_proto.file_descriptor);
242*6dbdd20aSAndroid Build Coastguard Worker 
243*6dbdd20aSAndroid Build Coastguard Worker   ImportResult upstream_proto = ImportProto(upstream, upstream_include);
244*6dbdd20aSAndroid Build Coastguard Worker   ProtoFile upstream_file =
245*6dbdd20aSAndroid Build Coastguard Worker       ProtoFileFromDescriptor("", *upstream_proto.file_descriptor);
246*6dbdd20aSAndroid Build Coastguard Worker 
247*6dbdd20aSAndroid Build Coastguard Worker   Allowlist allowed;
248*6dbdd20aSAndroid Build Coastguard Worker   if (!allowlist.empty()) {
249*6dbdd20aSAndroid Build Coastguard Worker     std::string allowlist_contents;
250*6dbdd20aSAndroid Build Coastguard Worker     if (!base::ReadFile(allowlist, &allowlist_contents)) {
251*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_ELOG("Failed to read allowlist");
252*6dbdd20aSAndroid Build Coastguard Worker       return 1;
253*6dbdd20aSAndroid Build Coastguard Worker     }
254*6dbdd20aSAndroid Build Coastguard Worker 
255*6dbdd20aSAndroid Build Coastguard Worker     auto* desc = upstream_proto.importer->pool()->FindMessageTypeByName(
256*6dbdd20aSAndroid Build Coastguard Worker         upstream_root_message);
257*6dbdd20aSAndroid Build Coastguard Worker     if (!desc) {
258*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_ELOG(
259*6dbdd20aSAndroid Build Coastguard Worker           "Failed to find root message descriptor in upstream proto file");
260*6dbdd20aSAndroid Build Coastguard Worker       return 1;
261*6dbdd20aSAndroid Build Coastguard Worker     }
262*6dbdd20aSAndroid Build Coastguard Worker 
263*6dbdd20aSAndroid Build Coastguard Worker     auto field_list = base::SplitString(allowlist_contents, "\n");
264*6dbdd20aSAndroid Build Coastguard Worker     base::Status status = AllowlistFromFieldList(*desc, field_list, allowed);
265*6dbdd20aSAndroid Build Coastguard Worker     if (!status.ok()) {
266*6dbdd20aSAndroid Build Coastguard Worker       PERFETTO_ELOG("Failed creating allowlist: %s", status.c_message());
267*6dbdd20aSAndroid Build Coastguard Worker       return 1;
268*6dbdd20aSAndroid Build Coastguard Worker     }
269*6dbdd20aSAndroid Build Coastguard Worker   }
270*6dbdd20aSAndroid Build Coastguard Worker 
271*6dbdd20aSAndroid Build Coastguard Worker   ProtoFile merged;
272*6dbdd20aSAndroid Build Coastguard Worker   base::Status status =
273*6dbdd20aSAndroid Build Coastguard Worker       MergeProtoFiles(input_file, upstream_file, allowed, merged);
274*6dbdd20aSAndroid Build Coastguard Worker   if (!status.ok()) {
275*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Failed merging protos: %s", status.c_message());
276*6dbdd20aSAndroid Build Coastguard Worker     return 1;
277*6dbdd20aSAndroid Build Coastguard Worker   }
278*6dbdd20aSAndroid Build Coastguard Worker 
279*6dbdd20aSAndroid Build Coastguard Worker   base::ScopedFile output_file(
280*6dbdd20aSAndroid Build Coastguard Worker       base::OpenFile(output, O_CREAT | O_WRONLY | O_TRUNC, 0664));
281*6dbdd20aSAndroid Build Coastguard Worker   if (!output_file) {
282*6dbdd20aSAndroid Build Coastguard Worker     PERFETTO_ELOG("Failed opening output file: %s", output.c_str());
283*6dbdd20aSAndroid Build Coastguard Worker     return 1;
284*6dbdd20aSAndroid Build Coastguard Worker   }
285*6dbdd20aSAndroid Build Coastguard Worker   std::string out = ProtoFileToDotProto(merged);
286*6dbdd20aSAndroid Build Coastguard Worker   base::WriteAll(*output_file, out.c_str(), out.size());
287*6dbdd20aSAndroid Build Coastguard Worker 
288*6dbdd20aSAndroid Build Coastguard Worker   return 0;
289*6dbdd20aSAndroid Build Coastguard Worker }
290*6dbdd20aSAndroid Build Coastguard Worker 
291*6dbdd20aSAndroid Build Coastguard Worker }  // namespace
292*6dbdd20aSAndroid Build Coastguard Worker }  // namespace proto_merger
293*6dbdd20aSAndroid Build Coastguard Worker }  // namespace perfetto
294*6dbdd20aSAndroid Build Coastguard Worker 
main(int argc,char ** argv)295*6dbdd20aSAndroid Build Coastguard Worker int main(int argc, char** argv) {
296*6dbdd20aSAndroid Build Coastguard Worker   return perfetto::proto_merger::Main(argc, argv);
297*6dbdd20aSAndroid Build Coastguard Worker }
298