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