diff options
-rw-r--r-- | share/man/just.1.md | 6 | ||||
-rw-r--r-- | src/buildtool/common/cli.hpp | 5 | ||||
-rw-r--r-- | src/buildtool/computed_roots/evaluate.cpp | 1 | ||||
-rw-r--r-- | src/buildtool/graph_traverser/graph_traverser.hpp | 52 | ||||
-rw-r--r-- | test/end-to-end/cli/build-p.sh | 3 |
5 files changed, 63 insertions, 4 deletions
diff --git a/share/man/just.1.md b/share/man/just.1.md index e56547a8..6c5927f0 100644 --- a/share/man/just.1.md +++ b/share/man/just.1.md @@ -494,6 +494,12 @@ Supported by: analyse|build|install. After building, print the specified artifact to stdout. Supported by: build|install|rebuild|traverse. +**`-p`**, **`--print-unique-artifact`** +After building, print the unique artifact to stdout, if any. If +the option **`-P`** is given or the number of artifacts is not +precisely one, this option has no effect. +Supported by: build|install|rebuild|traverse. + **`-s`**, **`--show-runfiles`** Do not omit runfiles in build report. Supported by: build|install|rebuild|traverse. diff --git a/src/buildtool/common/cli.hpp b/src/buildtool/common/cli.hpp index 3c7ac45e..c6771cb3 100644 --- a/src/buildtool/common/cli.hpp +++ b/src/buildtool/common/cli.hpp @@ -114,6 +114,7 @@ struct BuildArguments { std::size_t build_jobs{}; std::optional<std::string> dump_artifacts{std::nullopt}; std::optional<std::string> print_to_stdout{std::nullopt}; + bool print_unique{false}; bool show_runfiles{false}; }; @@ -533,6 +534,10 @@ static inline auto SetupExtendedBuildArguments( clargs->print_to_stdout, "After building, print the specified artifact to stdout.") ->type_name("LOGICAL_PATH"); + + app->add_flag("-p,--print-unique-artifact", + clargs->print_unique, + "Print the unique artifact, if any, to stdout."); } static inline auto SetupTCArguments(gsl::not_null<CLI::App*> const& app, diff --git a/src/buildtool/computed_roots/evaluate.cpp b/src/buildtool/computed_roots/evaluate.cpp index 6c05aadb..ed1df8de 100644 --- a/src/buildtool/computed_roots/evaluate.cpp +++ b/src/buildtool/computed_roots/evaluate.cpp @@ -317,6 +317,7 @@ void ComputeAndFill( StageArguments{.output_dir = root_dir, .remember = true}; root_build_args.rebuild = std::nullopt; root_build_args.build.print_to_stdout = std::nullopt; + root_build_args.build.print_unique = false; root_build_args.build.dump_artifacts = std::nullopt; root_build_args.build.show_runfiles = false; auto root_exec_context = ExecutionContext{context->repo_config, diff --git a/src/buildtool/graph_traverser/graph_traverser.hpp b/src/buildtool/graph_traverser/graph_traverser.hpp index 51069c0b..3203f9c7 100644 --- a/src/buildtool/graph_traverser/graph_traverser.hpp +++ b/src/buildtool/graph_traverser/graph_traverser.hpp @@ -158,7 +158,13 @@ class GraphTraverser { rel_paths, artifact_nodes, runfile_descriptions); - MaybePrintToStdout(rel_paths, artifact_nodes); + MaybePrintToStdout( + rel_paths, + artifact_nodes, + artifact_descriptions.size() == 1 + ? std::optional<std::string>{artifact_descriptions.begin() + ->first} + : std::nullopt); return BuildResult{.output_paths = std::move(rel_paths), .extra_infos = std::move(infos), .failed_artifacts = failed_artifacts}; @@ -182,7 +188,13 @@ class GraphTraverser { artifact_nodes, runfile_descriptions); - MaybePrintToStdout(rel_paths, artifact_nodes); + MaybePrintToStdout( + rel_paths, + artifact_nodes, + artifact_descriptions.size() == 1 + ? std::optional<std::string>{artifact_descriptions.begin() + ->first} + : std::nullopt); return BuildResult{.output_paths = *output_paths, .extra_infos = std::move(infos), @@ -671,8 +683,8 @@ class GraphTraverser { void MaybePrintToStdout( std::vector<std::filesystem::path> const& paths, - std::vector<DependencyGraph::ArtifactNode const*> const& artifacts) - const { + std::vector<DependencyGraph::ArtifactNode const*> const& artifacts, + std::optional<std::string> const& unique_artifact) const { if (clargs_.build.print_to_stdout) { auto const& remote = *context_.apis->remote; for (std::size_t i = 0; i < paths.size(); i++) { @@ -751,6 +763,38 @@ class GraphTraverser { "{} not a logical path of the specified target", *(clargs_.build.print_to_stdout)); } + else if (clargs_.build.print_unique) { + if (unique_artifact) { + auto const& remote = *context_.apis->remote; + std::optional<Artifact::ObjectInfo> info = std::nullopt; + for (std::size_t i = 0; i < paths.size(); i++) { + if (paths[i] == unique_artifact) { + info = artifacts[i]->Content().Info(); + } + } + if (info) { + if (not remote.RetrieveToFds({*info}, + {dup(fileno(stdout))}, + /*raw_tree=*/false, + &*context_.apis->local)) { + Logger::Log(logger_, + LogLevel::Error, + "Failed to retrieve {}", + *unique_artifact); + } + } + else { + Logger::Log(logger_, + LogLevel::Error, + "Failed to obtain object information for {}", + *unique_artifact); + } + return; + } + Logger::Log(logger_, + LogLevel::Info, + "Target does not have precisely one artifact."); + } } }; diff --git a/test/end-to-end/cli/build-p.sh b/test/end-to-end/cli/build-p.sh index 9a829fe7..0da9179a 100644 --- a/test/end-to-end/cli/build-p.sh +++ b/test/end-to-end/cli/build-p.sh @@ -44,6 +44,9 @@ cat out.json # Requesting foo/bar gives a human-readable description of the tree "${JUST}" build -L '["env", "PATH='"${PATH}"'"]' --local-build-root "${BUILDROOT}" -P foo/bar | grep baz +# ... and so does asking for the unique artifact +"${JUST}" build -L '["env", "PATH='"${PATH}"'"]' --local-build-root "${BUILDROOT}" -p | grep baz + # going deepter into the tree we stil can get human-readable tree descriptions "${JUST}" build -L '["env", "PATH='"${PATH}"'"]' --local-build-root "${BUILDROOT}" -P foo/bar/baz/greeting | grep hello.txt |