[metadata] Walk function
Implements the main call to the walk metadata function, iterating
through specified targets to extract metadata.
Change-Id: If1058d635a5f1d3d2f9d0237826631f289dc0ddd
Reviewed-on: https://gn-review.googlesource.com/c/3360
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 f17a648..82c15d1 100755
--- a/build/gen.py
+++ b/build/gen.py
@@ -470,6 +470,7 @@
'tools/gn/loader.cc',
'tools/gn/location.cc',
'tools/gn/metadata.cc',
+ 'tools/gn/metadata_walk.cc',
'tools/gn/ninja_action_target_writer.cc',
'tools/gn/ninja_binary_target_writer.cc',
'tools/gn/ninja_build_writer.cc',
@@ -570,6 +571,7 @@
'tools/gn/label_unittest.cc',
'tools/gn/loader_unittest.cc',
'tools/gn/metadata_unittest.cc',
+ 'tools/gn/metadata_walk_unittest.cc',
'tools/gn/ninja_action_target_writer_unittest.cc',
'tools/gn/ninja_binary_target_writer_unittest.cc',
'tools/gn/ninja_build_writer_unittest.cc',
diff --git a/tools/gn/metadata_walk.cc b/tools/gn/metadata_walk.cc
new file mode 100644
index 0000000..6ce9b88
--- /dev/null
+++ b/tools/gn/metadata_walk.cc
@@ -0,0 +1,24 @@
+// 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_walk.h"
+
+std::vector<Value> WalkMetadata(
+ const UniqueVector<const Target*>& targets_to_walk,
+ const std::vector<std::string>& keys_to_extract,
+ const std::vector<std::string>& keys_to_walk,
+ bool rebase_files,
+ std::set<const Target*>* targets_walked,
+ Err* err) {
+ std::vector<Value> result;
+ for (const auto* target : targets_to_walk) {
+ auto pair = targets_walked->insert(target);
+ if (pair.second) {
+ if (!target->GetMetadata(keys_to_extract, keys_to_walk, rebase_files,
+ &result, targets_walked, err))
+ return std::vector<Value>();
+ }
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/tools/gn/metadata_walk.h b/tools/gn/metadata_walk.h
new file mode 100644
index 0000000..4601a3f
--- /dev/null
+++ b/tools/gn/metadata_walk.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef TOOLS_GN_METADATAWALK_H_
+#define TOOLS_GN_METADATAWALK_H_
+
+#include "tools/gn/build_settings.h"
+#include "tools/gn/target.h"
+#include "tools/gn/unique_vector.h"
+#include "tools/gn/value.h"
+
+// Function to collect metadata from resolved targets listed in targets_walked.
+// Intended to be called after all targets are resolved.
+//
+// This populates targets_walked with all targets touched by this walk, and
+// returns the list of metadata values.
+std::vector<Value> WalkMetadata(
+ const UniqueVector<const Target*>& targets_to_walk,
+ const std::vector<std::string>& keys_to_extract,
+ const std::vector<std::string>& keys_to_walk,
+ bool rebase_files,
+ std::set<const Target*>* targets_walked,
+ Err* err);
+
+#endif // TOOLS_GN_METADATAWALK_H_
diff --git a/tools/gn/metadata_walk_unittest.cc b/tools/gn/metadata_walk_unittest.cc
new file mode 100644
index 0000000..4855131
--- /dev/null
+++ b/tools/gn/metadata_walk_unittest.cc
@@ -0,0 +1,211 @@
+// 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_walk.h"
+
+#include "tools/gn/metadata.h"
+#include "tools/gn/target.h"
+#include "tools/gn/test_with_scope.h"
+#include "tools/gn/unique_vector.h"
+#include "util/test/test.h"
+
+TEST(MetadataWalkTest, CollectNoRecurse) {
+ TestWithScope setup;
+
+ TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
+ Value a_expected(nullptr, Value::LIST);
+ a_expected.list_value().push_back(Value(nullptr, "foo"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_expected));
+
+ Value b_expected(nullptr, Value::LIST);
+ b_expected.list_value().push_back(Value(nullptr, true));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("b", b_expected));
+
+ one.metadata().set_source_dir(SourceDir("/usr/home/files/"));
+
+ TestTarget two(setup, "//foo:two", Target::SOURCE_SET);
+ Value a_2_expected(nullptr, Value::LIST);
+ a_2_expected.list_value().push_back(Value(nullptr, "bar"));
+ two.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_2_expected));
+
+ Value b_2_expected(nullptr, Value::LIST);
+ b_2_expected.list_value().push_back(Value(nullptr, false));
+ two.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("b", b_2_expected));
+
+ two.metadata().set_source_dir(SourceDir("/usr/home/files/inner"));
+
+ UniqueVector<const Target*> targets;
+ targets.push_back(&one);
+ targets.push_back(&two);
+
+ std::vector<std::string> data_keys;
+ data_keys.push_back("a");
+ data_keys.push_back("b");
+
+ std::vector<std::string> walk_keys;
+
+ Err err;
+ std::set<const Target*> targets_walked;
+ std::vector<Value> result =
+ WalkMetadata(targets, data_keys, walk_keys, false, &targets_walked, &err);
+ EXPECT_FALSE(err.has_error());
+
+ std::vector<Value> expected;
+ expected.push_back(Value(nullptr, "foo"));
+ expected.push_back(Value(nullptr, true));
+ expected.push_back(Value(nullptr, "bar"));
+ expected.push_back(Value(nullptr, false));
+ EXPECT_EQ(result, expected);
+
+ std::set<const Target*> expected_walked_targets;
+ expected_walked_targets.insert(&one);
+ expected_walked_targets.insert(&two);
+ EXPECT_EQ(targets_walked, expected_walked_targets);
+}
+
+TEST(MetadataWalkTest, CollectWithRecurse) {
+ TestWithScope setup;
+
+ TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
+ Value a_expected(nullptr, Value::LIST);
+ a_expected.list_value().push_back(Value(nullptr, "foo"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_expected));
+
+ Value b_expected(nullptr, Value::LIST);
+ b_expected.list_value().push_back(Value(nullptr, true));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("b", b_expected));
+
+ TestTarget two(setup, "//foo:two", Target::SOURCE_SET);
+ Value a_2_expected(nullptr, Value::LIST);
+ a_2_expected.list_value().push_back(Value(nullptr, "bar"));
+ two.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_2_expected));
+
+ one.public_deps().push_back(LabelTargetPair(&two));
+
+ UniqueVector<const Target*> targets;
+ targets.push_back(&one);
+
+ std::vector<std::string> data_keys;
+ data_keys.push_back("a");
+ data_keys.push_back("b");
+
+ std::vector<std::string> walk_keys;
+
+ Err err;
+ std::set<const Target*> targets_walked;
+ std::vector<Value> result =
+ WalkMetadata(targets, data_keys, walk_keys, false, &targets_walked, &err);
+ EXPECT_FALSE(err.has_error());
+
+ std::vector<Value> expected;
+ expected.push_back(Value(nullptr, "foo"));
+ expected.push_back(Value(nullptr, true));
+ expected.push_back(Value(nullptr, "bar"));
+ EXPECT_EQ(result, expected);
+
+ std::set<const Target*> expected_walked_targets;
+ expected_walked_targets.insert(&one);
+ expected_walked_targets.insert(&two);
+ EXPECT_EQ(targets_walked, expected_walked_targets);
+}
+
+TEST(MetadataWalkTest, CollectWithBarrier) {
+ TestWithScope setup;
+
+ TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
+ Value a_expected(nullptr, Value::LIST);
+ a_expected.list_value().push_back(Value(nullptr, "foo"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_expected));
+
+ Value walk_expected(nullptr, Value::LIST);
+ walk_expected.list_value().push_back(
+ Value(nullptr, "//foo:two(//toolchain:default)"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("walk", walk_expected));
+
+ TestTarget two(setup, "//foo:two", Target::SOURCE_SET);
+ Value a_2_expected(nullptr, Value::LIST);
+ a_2_expected.list_value().push_back(Value(nullptr, "bar"));
+ two.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_2_expected));
+
+ TestTarget three(setup, "//foo:three", Target::SOURCE_SET);
+ Value a_3_expected(nullptr, Value::LIST);
+ a_3_expected.list_value().push_back(Value(nullptr, "baz"));
+ three.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_3_expected));
+
+ one.public_deps().push_back(LabelTargetPair(&two));
+ one.public_deps().push_back(LabelTargetPair(&three));
+
+ UniqueVector<const Target*> targets;
+ targets.push_back(&one);
+
+ std::vector<std::string> data_keys;
+ data_keys.push_back("a");
+
+ std::vector<std::string> walk_keys;
+ walk_keys.push_back("walk");
+
+ Err err;
+ std::set<const Target*> targets_walked;
+ std::vector<Value> result =
+ WalkMetadata(targets, data_keys, walk_keys, false, &targets_walked, &err);
+ EXPECT_FALSE(err.has_error()) << err.message();
+
+ std::vector<Value> expected;
+ expected.push_back(Value(nullptr, "foo"));
+ expected.push_back(Value(nullptr, "bar"));
+ EXPECT_EQ(result, expected) << result.size();
+
+ std::set<const Target*> expected_walked_targets;
+ expected_walked_targets.insert(&one);
+ expected_walked_targets.insert(&two);
+ EXPECT_EQ(targets_walked, expected_walked_targets);
+}
+
+TEST(MetadataWalkTest, CollectWithError) {
+ TestWithScope setup;
+
+ TestTarget one(setup, "//foo:one", Target::SOURCE_SET);
+ Value a_expected(nullptr, Value::LIST);
+ a_expected.list_value().push_back(Value(nullptr, "foo"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("a", a_expected));
+
+ Value walk_expected(nullptr, Value::LIST);
+ walk_expected.list_value().push_back(Value(nullptr, "//foo:missing"));
+ one.metadata().contents().insert(
+ std::pair<base::StringPiece, Value>("walk", walk_expected));
+
+ UniqueVector<const Target*> targets;
+ targets.push_back(&one);
+
+ std::vector<std::string> data_keys;
+ data_keys.push_back("a");
+
+ std::vector<std::string> walk_keys;
+ walk_keys.push_back("walk");
+
+ Err err;
+ std::set<const Target*> targets_walked;
+ std::vector<Value> result =
+ WalkMetadata(targets, data_keys, walk_keys, false, &targets_walked, &err);
+ EXPECT_TRUE(result.empty());
+ EXPECT_TRUE(err.has_error());
+ EXPECT_EQ(err.message(),
+ "I was expecting //foo:missing to be a dependency of "
+ "//foo:one(//toolchain:default). "
+ "Make sure it's included in the deps or data_deps, and that you've "
+ "specified the appropriate toolchain.")
+ << err.message();
+}