[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());
+}