summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/just.1.md6
-rw-r--r--src/buildtool/common/cli.hpp5
-rw-r--r--src/buildtool/computed_roots/evaluate.cpp1
-rw-r--r--src/buildtool/graph_traverser/graph_traverser.hpp52
-rw-r--r--test/end-to-end/cli/build-p.sh3
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