Implement `gn edit "move attr attr value(s)"` Change-Id: Iadb0b09205bdf7bde614fe7fcd37ae8b6a6a6964 Reviewed-on: https://gn-review.googlesource.com/c/gn/+/25460 Reviewed-by: Takuto Ikuta <tikuta@google.com> Commit-Queue: Matt Stark <msta@google.com>
diff --git a/docs/reference.md b/docs/reference.md index 33e1c6d..26ab83c 100644 --- a/docs/reference.md +++ b/docs/reference.md
@@ -741,6 +741,13 @@ Example: gn edit "delete" //src/tools:old_target + move <from_attribute> <to_attribute> <value(s)> + Moves <value(s)> from the list <from_attribute> to <to_attribute>. + If <to_attribute> does not exist, it is created. + + Example: + gn edit "move deps public_deps //base" //src/tools:* + remove <attribute> Removes <attribute> entirely.
diff --git a/src/gn/edit_command.cc b/src/gn/edit_command.cc index ff4d127..8f02524 100644 --- a/src/gn/edit_command.cc +++ b/src/gn/edit_command.cc
@@ -48,6 +48,13 @@ " Example:\n" " gn edit \"delete\" //src/tools:old_target\n" "\n" + " move <from_attribute> <to_attribute> <value(s)>\n" + " Moves <value(s)> from the list <from_attribute> to <to_attribute>.\n" + " If <to_attribute> does not exist, it is created.\n" + "\n" + " Example:\n" + " gn edit \"move deps public_deps //base\" //src/tools:*\n" + "\n" " remove <attribute>\n" " Removes <attribute> entirely.\n" "\n"
diff --git a/src/gn/edit_command_unittest.cc b/src/gn/edit_command_unittest.cc index 0ec3cfc..e6a0e2c 100644 --- a/src/gn/edit_command_unittest.cc +++ b/src/gn/edit_command_unittest.cc
@@ -261,6 +261,35 @@ EditState({Label(SourceDir("//"), "bar")}))); } +TEST_F(EditCommandTest, MoveSubcommand) { + EXPECT_SUCCESS( + DoEdit("move deps public_deps //a //b //nonexistent", {"//:foo"}, + R"( +executable("foo") { + deps = [ + "//a", + "//b", + "//c", + ] + public_deps = [ "//d" ] +} +)"), + Edited(R"( +executable("foo") { + deps = [ "//c" ] + public_deps = [ + "//a", + "//b", + "//d", + ] +} +)", + EditState{{}, + {Err(Location(), + "Target \"//:foo\" does not contain the value " + "\"//nonexistent\" in attribute \"deps\".")}})); +} + TEST_F(EditCommandTest, RemoveAttributeSubcommand) { EXPECT_SUCCESS(DoEdit("remove testonly", R"(
diff --git a/src/gn/edit_subcommands.cc b/src/gn/edit_subcommands.cc index 9be56c8..34455f1 100644 --- a/src/gn/edit_subcommands.cc +++ b/src/gn/edit_subcommands.cc
@@ -184,6 +184,27 @@ }); } +EditCommand MoveCommand(std::string from_attribute, + std::string to_attribute, + std::vector<Value> values) { + return EditTargetCommand([from_attribute = std::move(from_attribute), + to_attribute = std::move(to_attribute), + values = std::move(values)]( + BuildFile& build_file, const EditTarget& target, + EditState& state) -> Err { + std::vector<Value> moved_values; + for (const auto& value : values) { + if (RemoveFromTarget(target, from_attribute, value, state)) { + moved_values.push_back(value); + } + } + if (!moved_values.empty()) { + AddToTarget(build_file, target, to_attribute, moved_values); + } + return Ok(); + }); +} + EditCommand RemoveAttributeCommand(std::string attribute) { return EditTargetCommand([attribute = std::move(attribute)]( BuildFile& build_file, const EditTarget& target, @@ -256,6 +277,14 @@ return Err(Location(), "Invalid delete command.", "Usage: delete"); } return DeleteCommand(); + } else if (args[0] == "move") { + if (args.size() < 4) { + return Err(Location(), "Invalid move command.", + "Usage: move <from_attribute> <to_attribute> <value(s)>"); + } + ASSIGN_OR_RETURN(std::vector<Value> values, + ParseValues(base::make_span(args).subspan(3))); + return MoveCommand(args[1], args[2], std::move(values)); } else if (args[0] == "remove") { if (args.size() < 2) { return Err(Location(), "Invalid remove command.",