blob: 02304ecfb2a2cfb5167139d71e19b1cf79b6b380 [file] [log] [blame]
// Copyright 2020 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 <map>
#include <set>
#include <string>
#include <vector>
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/hash/hash.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "url/gurl.h"
namespace {
// Print the command line help.
void PrintHelp() {
LOG(ERROR) << "schema_org_name_generator <schema-file> ... <schema-file>"
<< " <output-file>";
}
} // namespace
int main(int argc, char* argv[]) {
base::CommandLine::Init(argc, argv);
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
logging::LoggingSettings settings;
settings.logging_dest =
logging::LOG_TO_SYSTEM_DEBUG_LOG | logging::LOG_TO_STDERR;
logging::InitLogging(settings);
#if defined(OS_WIN)
std::vector<std::string> args;
base::CommandLine::StringVector wide_args = command_line.GetArgs();
for (const auto& arg : wide_args) {
args.push_back(base::UTF16ToUTF8(arg));
}
#else
base::CommandLine::StringVector args = command_line.GetArgs();
#endif
if (args.size() < 2U) {
PrintHelp();
return 1;
}
// Read all the args and convert to file paths.
std::vector<base::FilePath> paths;
for (auto& arg : args) {
paths.push_back(base::FilePath::FromUTF8Unsafe(arg));
}
// Check we have at least two paths.
if (paths.size() < 2U) {
PrintHelp();
return 1;
}
// Get the last path which is the output file.
base::FilePath output_path = paths.back();
paths.pop_back();
base::DictionaryValue output_map;
std::set<std::string> names_to_generate;
for (auto& path : paths) {
path = base::MakeAbsoluteFilePath(path);
if (!base::PathExists(path)) {
LOG(ERROR) << "Input JSON file doesn't exist.";
return 1;
}
std::string json_input;
if (!base::ReadFileToString(path, &json_input)) {
LOG(ERROR) << "Could not read input JSON file.";
return 1;
}
auto value = base::JSONReader::Read(json_input);
base::DictionaryValue* dict_value = nullptr;
if (!value.has_value() || !value->GetAsDictionary(&dict_value)) {
LOG(ERROR) << "Could not parse the input JSON file";
return 1;
}
const base::ListValue* graph = nullptr;
if (!dict_value->GetList("@graph", &graph)) {
LOG(ERROR) << "Could not parse the @graph in the input JSON";
return 1;
}
for (size_t i = 0; i < graph->GetSize(); ++i) {
const base::DictionaryValue* parsed = nullptr;
if (!graph->GetDictionary(i, &parsed)) {
LOG(ERROR) << "Could not parse entry " << i << " in the input JSON";
return 1;
}
std::string id;
if (!parsed->GetString("@id", &id)) {
LOG(ERROR) << "Could not extract the id from the entry";
return 1;
}
if (id.empty()) {
LOG(ERROR) << "ID was empty";
return 1;
}
names_to_generate.insert(id);
names_to_generate.insert(GURL(id).path().substr(1));
}
}
std::set<unsigned> generated_hashes;
for (auto& name : names_to_generate) {
auto hash = base::PersistentHash(name);
if (base::Contains(generated_hashes, hash)) {
LOG(ERROR) << "Hash collision: " << name;
return 1;
}
output_map.SetStringKey(name, base::StringPrintf("0x%x", hash));
generated_hashes.insert(hash);
}
std::string output;
if (!base::JSONWriter::Write(output_map, &output)) {
LOG(ERROR) << "Failed to convert output to JSON.";
return 1;
}
if (base::WriteFile(output_path, output.c_str(),
static_cast<uint32_t>(output.size())) <= 0) {
LOG(ERROR) << "Failed to write output.";
return 1;
}
return 0;
}