[metadata] Adding basic metadata walking Adds walk logic to the metadata field and the target. Change-Id: I5946bd44c1b99f94e3be4a05547a7bdd2f14245b Reviewed-on: https://gn-review.googlesource.com/c/3340 Commit-Queue: Julie Hockett <juliehockett@google.com> Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/build/gen.py b/build/gen.py index e32a609..f17a648 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -469,6 +469,7 @@ 'tools/gn/lib_file.cc', 'tools/gn/loader.cc', 'tools/gn/location.cc', + 'tools/gn/metadata.cc', 'tools/gn/ninja_action_target_writer.cc', 'tools/gn/ninja_binary_target_writer.cc', 'tools/gn/ninja_build_writer.cc',
diff --git a/tools/gn/metadata.cc b/tools/gn/metadata.cc new file mode 100644 index 0000000..605294b --- /dev/null +++ b/tools/gn/metadata.cc
@@ -0,0 +1,67 @@ +// Copyright 2018 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 "tools/gn/metadata.h" + +bool Metadata::WalkStep(const BuildSettings* settings, + const std::vector<std::string>& keys_to_extract, + const std::vector<std::string>& keys_to_walk, + bool rebase_files, + std::vector<Value>* next_walk_keys, + std::vector<Value>* result, + Err* err) const { + // If there's no metadata, there's nothing to find, so quick exit. + if (contents_.empty()) { + next_walk_keys->emplace_back(nullptr, ""); + return true; + } + + // Pull the data from each specified key. + for (const auto& key : keys_to_extract) { + auto iter = contents_.find(key); + if (iter == contents_.end()) + continue; + assert(iter->second.type() == Value::LIST); + + if (rebase_files) { + for (const auto& val : iter->second.list_value()) { + if (!val.VerifyTypeIs(Value::STRING, err)) + return false; + // TODO(juliehockett): Do we want to consider absolute paths here? In + // which case we'd need to propagate the root_path_utf8 from + // build_settings as well. + std::string filename = source_dir_.ResolveRelativeAs( + /*as_file = */ true, val, err, settings->root_path_utf8()); + if (err->has_error()) + return false; + result->emplace_back(val.origin(), std::move(filename)); + } + } else { + result->insert(result->end(), iter->second.list_value().begin(), + iter->second.list_value().end()); + } + } + + // Get the targets to look at next. If no keys_to_walk are present, we push + // the empty string to the list so that the target knows to include its deps + // and data_deps. The values used here must be lists of strings. + bool found_walk_key = false; + for (const auto& key : keys_to_walk) { + auto iter = contents_.find(key); + if (iter != contents_.end()) { + found_walk_key = true; + assert(iter->second.type() == Value::LIST); + for (const auto& val : iter->second.list_value()) { + if (!val.VerifyTypeIs(Value::STRING, err)) + return false; + next_walk_keys->emplace_back(val); + } + } + } + + if (!found_walk_key) + next_walk_keys->emplace_back(nullptr, ""); + + return true; +}
diff --git a/tools/gn/metadata.h b/tools/gn/metadata.h index fe66ff6..235542b 100644 --- a/tools/gn/metadata.h +++ b/tools/gn/metadata.h
@@ -7,6 +7,7 @@ #include <memory> +#include "tools/gn/build_settings.h" #include "tools/gn/scope.h" #include "tools/gn/source_dir.h" @@ -44,6 +45,19 @@ SourceDir& source_dir() { return source_dir_; } void set_source_dir(const SourceDir& d) { source_dir_ = d; } + // Collect the specified metadata from this instance. + // + // Calling this will populate `next_walk_keys` with the values of targets to + // be walked next (with the empty string "" indicating that the target should + // walk all of its deps and data_deps). + bool WalkStep(const BuildSettings* settings, + const std::vector<std::string>& keys_to_extract, + const std::vector<std::string>& keys_to_walk, + bool rebase_files, + std::vector<Value>* next_walk_keys, + std::vector<Value>* result, + Err* err) const; + private: const ParseNode* origin_; Contents contents_;
diff --git a/tools/gn/metadata_unittest.cc b/tools/gn/metadata_unittest.cc index cb94911..2fcebfa 100644 --- a/tools/gn/metadata_unittest.cc +++ b/tools/gn/metadata_unittest.cc
@@ -30,3 +30,175 @@ ASSERT_EQ(a_actual->second, a_expected); ASSERT_EQ(b_actual->second, b_expected); } + +TEST(MetadataTest, Walk) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + Value a_expected(nullptr, Value::LIST); + a_expected.list_value().push_back(Value(nullptr, "foo.cpp")); + a_expected.list_value().push_back(Value(nullptr, "bar.h")); + + metadata.contents().insert( + std::pair<base::StringPiece, Value>("a", a_expected)); + + std::vector<std::string> data_keys; + data_keys.emplace_back("a"); + std::vector<std::string> walk_keys; + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + std::vector<Value> expected; + expected.emplace_back(Value(nullptr, "foo.cpp")); + expected.emplace_back(Value(nullptr, "bar.h")); + + std::vector<Value> expected_walk_keys; + expected_walk_keys.emplace_back(nullptr, ""); + + Err err; + EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, false, &next_walk_keys, &results, + &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(next_walk_keys, expected_walk_keys); + EXPECT_EQ(results, expected); +} + +TEST(MetadataTest, WalkWithRebase) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + Value a_expected(nullptr, Value::LIST); + a_expected.list_value().push_back(Value(nullptr, "foo.cpp")); + a_expected.list_value().push_back(Value(nullptr, "foo/bar.h")); + + metadata.contents().insert( + std::pair<base::StringPiece, Value>("a", a_expected)); + + std::vector<std::string> data_keys; + data_keys.emplace_back("a"); + std::vector<std::string> walk_keys; + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + std::vector<Value> expected; + expected.emplace_back(Value(nullptr, "/usr/home/files/foo.cpp")); + expected.emplace_back(Value(nullptr, "/usr/home/files/foo/bar.h")); + + std::vector<Value> expected_walk_keys; + expected_walk_keys.emplace_back(nullptr, ""); + + Err err; + EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, true, &next_walk_keys, &results, + &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(next_walk_keys, expected_walk_keys); + EXPECT_EQ(results, expected); +} + +TEST(MetadataTest, WalkWithRebaseError) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + Value a_expected(nullptr, Value::LIST); + a_expected.list_value().push_back(Value(nullptr, "foo.cpp")); + a_expected.list_value().push_back(Value(nullptr, true)); + + metadata.contents().insert( + std::pair<base::StringPiece, Value>("a", a_expected)); + + std::vector<std::string> data_keys; + data_keys.emplace_back("a"); + std::vector<std::string> walk_keys; + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + Err err; + EXPECT_FALSE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, true, &next_walk_keys, &results, + &err)); + EXPECT_TRUE(err.has_error()); +} + +TEST(MetadataTest, WalkKeysToWalk) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + Value a_expected(nullptr, Value::LIST); + a_expected.list_value().push_back(Value(nullptr, "//target")); + + metadata.contents().insert( + std::pair<base::StringPiece, Value>("a", a_expected)); + + std::vector<std::string> data_keys; + std::vector<std::string> walk_keys; + walk_keys.emplace_back("a"); + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + std::vector<Value> expected_walk_keys; + expected_walk_keys.emplace_back(nullptr, "//target"); + + Err err; + EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, true, &next_walk_keys, &results, + &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(next_walk_keys, expected_walk_keys); + EXPECT_TRUE(results.empty()); +} + +TEST(MetadataTest, WalkNoContents) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + std::vector<std::string> data_keys; + std::vector<std::string> walk_keys; + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + std::vector<Value> expected_walk_keys; + expected_walk_keys.emplace_back(nullptr, ""); + + Err err; + EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, true, &next_walk_keys, &results, + &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(next_walk_keys, expected_walk_keys); + EXPECT_TRUE(results.empty()); +} + +TEST(MetadataTest, WalkNoKeysWithContents) { + TestWithScope setup; + Metadata metadata; + metadata.set_source_dir(SourceDir("/usr/home/files/")); + + Value a_expected(nullptr, Value::LIST); + a_expected.list_value().push_back(Value(nullptr, "//target")); + + metadata.contents().insert( + std::pair<base::StringPiece, Value>("a", a_expected)); + + std::vector<std::string> data_keys; + std::vector<std::string> walk_keys; + std::vector<Value> next_walk_keys; + std::vector<Value> results; + + std::vector<Value> expected_walk_keys; + expected_walk_keys.emplace_back(nullptr, ""); + + Err err; + EXPECT_TRUE(metadata.WalkStep(setup.settings()->build_settings(), data_keys, + walk_keys, true, &next_walk_keys, &results, + &err)); + EXPECT_FALSE(err.has_error()); + EXPECT_EQ(next_walk_keys, expected_walk_keys); + EXPECT_TRUE(results.empty()); +}