From 14387a181daf538a3bcbda2179a430078d9d930b Mon Sep 17 00:00:00 2001 From: pebers Date: Tue, 2 Feb 2016 14:47:04 +0000 Subject: [PATCH] Initial commit of Please. --- .gitignore | 27 + .plzconfig | 61 + BUILD | 27 + ChangeLog | 507 ++ README.md | 72 + VERSION | 1 + bootstrap.sh | 77 + docs/advanced.html | 148 + docs/basics.html | 95 + docs/intermediate.html | 186 + docs/quickstart.html | 40 + docs/styles.css | 3 + install.sh | 35 + package/BUILD | 81 + package/init.sh | 64 + src/BUILD_ | 21 + src/build/BUILD | 27 + src/build/build_step.go | 387 ++ src/build/cc/BUILD | 100 + src/build/cc/__init__.py | 0 src/build/cc/clang/BUILD | 79 + src/build/cc/clang/embed_file_test.cc | 25 + src/build/cc/clang/embedded_file_1.txt | 1 + src/build/cc/clang/embedded_file_2.txt | 1 + src/build/cc/clang/embedded_files.cc | 16 + src/build/cc/clang/embedded_files.h | 16 + src/build/cc/clang/shared_object_test.py | 20 + src/build/cc/clang/so_test.cc | 30 + src/build/cc/clang/test_binary.cc | 18 + src/build/cc/embed_file_test.cc | 25 + src/build/cc/embedded_file_1.txt | 1 + src/build/cc/embedded_file_2.txt | 1 + src/build/cc/embedded_files.cc | 16 + src/build/cc/embedded_files.h | 16 + src/build/cc/fst_lib.cc | 12 + src/build/cc/fst_lib.h | 15 + src/build/cc/fst_test.cc | 12 + src/build/cc/shared_object_test.py | 20 + src/build/cc/so_test.cc | 67 + src/build/cc/test_binary.cc | 18 + src/build/command_replacements.go | 188 + src/build/command_replacements_test.go | 159 + src/build/incrementality.go | 423 ++ src/build/incrementality_test.go | 80 + src/build/java/BUILD | 46 + src/build/java/jarcat.go | 113 + .../java/net/thoughtmachine/please/test/BUILD | 62 + .../test/PleaseCoverageClassLoaderTest.java | 25 + .../PleaseTestRunnerParameterizedTest.java | 41 + .../please/test/PleaseTestRunnerTest.java | 24 + .../please/test/ResourcesRootTest.java | 24 + .../please/test/TestCoverage.java | 206 + .../please/test/TestCoverageTest.java | 34 + .../please/test/TestListener.java | 162 + .../thoughtmachine/please/test/TestMain.java | 201 + .../please/test/TestResult.java | 33 + .../please/test/test_data/logback-test.xml | 10 + src/build/java/please_maven.go | 234 + src/build/java/test_data/test.zip | Bin 0 -> 6415 bytes src/build/java/zip_writer.go | 242 + src/build/java/zip_writer_test.go | 58 + src/build/python/BUILD | 96 + src/build/python/custom_interpreter_test.py | 15 + src/build/python/data_dep.py | 11 + src/build/python/data_dep_test.py | 22 + src/build/python/pex.py | 168 + src/build/python/pex_import_test.py | 21 + src/build/python/pex_main.py | 72 + src/build/python/pex_test.py | 24 + src/build/python/test_main.py | 99 + src/build/python/zip_unsafe_test.py | 16 + src/cache/BUILD | 42 + src/cache/cache.go | 141 + src/cache/dir_cache.go | 146 + src/cache/http_cache.go | 172 + src/cache/http_cache_test.go | 61 + src/cache/proto/BUILD | 6 + src/cache/proto/rpc_cache.proto | 78 + src/cache/rpc_cache.go | 177 + src/cache/rpc_cache_stub.go | 13 + src/cache/rpc_cache_test.go | 88 + src/cache/server/BUILD | 67 + src/cache/server/cache.go | 268 + src/cache/server/cache_test.go | 31 + src/cache/server/http_server.go | 126 + src/cache/server/http_server_main.go | 33 + src/cache/server/http_server_test.go | 170 + src/cache/server/rpc_server.go | 75 + src/cache/server/rpc_server_main.go | 28 + src/cache/server/rpc_server_test.go | 10 + .../pkg/name/label/name/dGVzdF9rZXk/testfile | 1 + .../pkg/name/label/name/dGVzdF9rZXk/testfile | 1 + .../test_data/plz-out/gen/pkg/name/testfile2 | 2 + .../test_data/plz-out/gen/pkg/name/testfile3 | 1 + src/cache/tools/BUILD | 30 + src/cache/tools/cache_cleaner.go | 116 + src/cache/tools/cache_cleaner_test.go | 49 + src/clean/BUILD | 10 + src/clean/clean.go | 110 + src/core/BUILD | 68 + src/core/build_env.go | 66 + src/core/build_env_test.go | 26 + src/core/build_label.go | 234 + src/core/build_target.go | 636 ++ src/core/build_target_test.go | 160 + src/core/config.go | 251 + src/core/config_test.go | 41 + src/core/file_label.go | 53 + src/core/graph.go | 211 + src/core/label_parse_test.go | 102 + src/core/lock.go | 74 + src/core/state.go | 362 ++ src/core/state_test.go | 65 + src/core/test_data/failing.plzconfig | 7 + src/core/test_data/slices.plzconfig | 2 + src/core/test_data/working.plzconfig | 7 + src/core/utils.go | 421 ++ src/core/utils_test.go | 33 + src/misc/BUILD | 30 + src/misc/get_plz.sh | 32 + src/misc/plz_complete.sh | 31 + src/misc/plz_complete.zsh | 35 + src/misc/plz_diff_graphs.go | 128 + src/misc/plz_diff_graphs_main.go | 61 + src/misc/plz_diff_graphs_test.go | 90 + src/misc/test_data/after.json | 5415 +++++++++++++++++ src/misc/test_data/before.json | 5322 ++++++++++++++++ src/misc/test_data/changed_hash.json | 5322 ++++++++++++++++ src/misc/test_data/labels.json | 5325 ++++++++++++++++ src/misc/test_data/labels2.json | 5328 ++++++++++++++++ src/misc/test_data/removed_package.json | 5287 ++++++++++++++++ src/output/BUILD | 69 + src/output/flags.go | 70 + src/output/interactive_display.go | 193 + src/output/interactive_display_test.go | 65 + src/output/logging.go | 187 + src/output/shell_output.go | 478 ++ src/output/shell_output_test.go | 54 + src/output/trace.go | 82 + src/parse/BUILD | 106 + src/parse/additional_output_test.go | 15 + src/parse/glob_test.go | 32 + src/parse/interpreter.c | 59 + src/parse/interpreter.go | 713 +++ src/parse/interpreter.h | 78 + src/parse/interpreter_test.go | 95 + src/parse/parse_step.go | 391 ++ src/parse/parse_step_test.go | 195 + src/parse/require_provide_test.py | 19 + src/parse/rules/cc_rules.py | 408 ++ src/parse/rules/go_rules.py | 267 + src/parse/rules/java_rules.py | 326 + src/parse/rules/misc_rules.py | 395 ++ src/parse/rules/please_parser.py | 447 ++ src/parse/rules/proto_rules.py | 220 + src/parse/rules/python_rules.py | 369 ++ src/parse/rules/sh_rules.py | 84 + src/parse/test_data/TEST_BUILD | 1 + src/parse/test_data/test.txt | 0 src/parse/test_data/test_subfolder1/a.txt | 0 src/parse/test_data/test_subfolder2/BUILD | 2 + src/parse/test_data/test_subfolder2/b.txt | 0 src/parse/test_data/test_subfolder3/test.py | 0 .../test_data/test_subfolder4/TEST_BUILD | 0 src/parse/test_data/test_subfolder4/test.py | 0 src/please.go | 551 ++ src/query/BUILD | 30 + src/query/affected_targets.go | 85 + src/query/alltargets.go | 11 + src/query/completions.go | 75 + src/query/deps.go | 17 + src/query/graph.go | 113 + src/query/graph_test.go | 62 + src/query/inputs.go | 17 + src/query/outputs.go | 14 + src/query/print.go | 174 + src/query/print_test.go | 66 + src/query/query_step.go | 24 + src/query/somepath.go | 30 + src/run/BUILD | 10 + src/run/run_step.go | 36 + src/test/BUILD | 74 + src/test/container.go | 115 + src/test/container_args_test.go | 11 + src/test/container_test.go | 27 + src/test/coverage.go | 161 + src/test/coverage_test.go | 158 + src/test/data_files_test.sh | 6 + src/test/flakiness_test.py | 13 + src/test/go_coverage.go | 47 + src/test/go_results.go | 67 + src/test/results.go | 57 + src/test/results_test.go | 150 + src/test/test_data/container_data.txt | 1 + src/test/test_data/go_coverage.txt | 360 ++ src/test/test_data/go_coverage_2.txt | 40 + src/test/test_data/go_coverage_3.txt | 42 + src/test/test_data/go_multiple_failure.txt | 8 + src/test/test_data/go_test_failure.txt | 11 + src/test/test_data/go_test_ignore_logs.txt | 14 + src/test/test_data/go_test_pass.txt | 9 + src/test/test_data/go_test_skip.txt | 11 + src/test/test_data/go_test_suite.txt | 19 + src/test/test_data/go_test_unknown_test.txt | 6 + src/test/test_data/junit.xml | 7 + src/test/test_data/karma-junit.xml | 21 + src/test/test_data/python-coverage.xml | 56 + src/test/test_data/unittest.xml | 9 + src/test/test_data/xmlrunner-junit.xml | 17 + src/test/test_step.go | 340 ++ src/test/xml_coverage.go | 65 + src/test/xml_results.go | 147 + src/update/BUILD | 9 + src/update/update.go | 174 + src/utils/BUILD | 10 + src/utils/utils.go | 54 + test/BUILD | 289 + test/IndividualTestRun.java | 20 + test/NoTestRun.java | 10 + test/affectedtests_test.go | 9 + test/basic_completions.txt | 4 + test/build_defs/BUILD | 5 + test/build_defs/plz_e2e_test.build_defs | 38 + test/cc_rules/BUILD | 54 + test/cc_rules/cc_multisrc_test.cc | 11 + test/cc_rules/cc_query_somepath_test_1.txt | 3 + test/cc_rules/cc_query_somepath_test_2.txt | 1 + test/cc_rules/deps_test.cc | 18 + test/cc_rules/lib1.cc | 9 + test/cc_rules/lib1.h | 10 + test/cc_rules/lib2.cc | 9 + test/cc_rules/lib2.h | 10 + test/cc_rules/multisrc.h | 7 + test/cc_rules/multisrc_1.cc | 5 + test/cc_rules/multisrc_2.cc | 5 + test/completions/BUILD | 22 + test/coverage_output_test.py | 12 + test/extra_test_output_test.py | 11 + test/go_rules/BUILD | 25 + test/go_rules/go_rules_test_bin.go | 13 + test/go_rules/go_rules_test_lib.go | 8 + test/go_rules/test/BUILD | 8 + test/go_rules/test/test.go | 6 + test/individual_test_run.py | 13 + test/moar/BUILD | 30 + test/num_runs_test.go | 10 + test/proto_rules/BUILD | 14 + test/proto_rules/specific_out_test.py | 18 + test/proto_rules/test.proto | 7 + test/query_affectedtests_test.txt | 1 + test/query_output_test.txt | 1 + test/query_somepath_nopath_test.txt | 1 + test/query_somepath_test.txt | 4 + test/run_completions.txt | 1 + test/test_completions.txt | 1 + test/test_output_test_1.txt | 9 + test/test_output_test_2.xml | 8 + third_party/go/BUILD | 103 + third_party/go/gcfg_dynamic_fields.patch | 24 + third_party/go/src/zip/BUILD | 9 + third_party/go/src/zip/reader.go | 453 ++ third_party/go/src/zip/register.go | 110 + third_party/go/src/zip/struct.go | 315 + third_party/go/src/zip/writer.go | 381 ++ third_party/java/BUILD | 94 + third_party/python/BUILD | 112 + third_party/python/coverage_pex.patch | 11 + third_party/python/dont_recompress.patch | 10 + third_party/python/never_cache_pex.patch | 21 + 269 files changed, 53988 insertions(+) create mode 100644 .gitignore create mode 100644 .plzconfig create mode 100644 BUILD create mode 100644 ChangeLog create mode 100644 README.md create mode 100644 VERSION create mode 100755 bootstrap.sh create mode 100644 docs/advanced.html create mode 100644 docs/basics.html create mode 100644 docs/intermediate.html create mode 100644 docs/quickstart.html create mode 100644 docs/styles.css create mode 100755 install.sh create mode 100644 package/BUILD create mode 100755 package/init.sh create mode 100644 src/BUILD_ create mode 100644 src/build/BUILD create mode 100644 src/build/build_step.go create mode 100644 src/build/cc/BUILD create mode 100644 src/build/cc/__init__.py create mode 100644 src/build/cc/clang/BUILD create mode 100644 src/build/cc/clang/embed_file_test.cc create mode 100644 src/build/cc/clang/embedded_file_1.txt create mode 100644 src/build/cc/clang/embedded_file_2.txt create mode 100644 src/build/cc/clang/embedded_files.cc create mode 100644 src/build/cc/clang/embedded_files.h create mode 100644 src/build/cc/clang/shared_object_test.py create mode 100644 src/build/cc/clang/so_test.cc create mode 100644 src/build/cc/clang/test_binary.cc create mode 100644 src/build/cc/embed_file_test.cc create mode 100644 src/build/cc/embedded_file_1.txt create mode 100644 src/build/cc/embedded_file_2.txt create mode 100644 src/build/cc/embedded_files.cc create mode 100644 src/build/cc/embedded_files.h create mode 100644 src/build/cc/fst_lib.cc create mode 100644 src/build/cc/fst_lib.h create mode 100644 src/build/cc/fst_test.cc create mode 100644 src/build/cc/shared_object_test.py create mode 100644 src/build/cc/so_test.cc create mode 100644 src/build/cc/test_binary.cc create mode 100644 src/build/command_replacements.go create mode 100644 src/build/command_replacements_test.go create mode 100644 src/build/incrementality.go create mode 100644 src/build/incrementality_test.go create mode 100644 src/build/java/BUILD create mode 100644 src/build/java/jarcat.go create mode 100644 src/build/java/net/thoughtmachine/please/test/BUILD create mode 100644 src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java create mode 100644 src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java create mode 100644 src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java create mode 100644 src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java create mode 100644 src/build/java/net/thoughtmachine/please/test/TestCoverage.java create mode 100644 src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java create mode 100644 src/build/java/net/thoughtmachine/please/test/TestListener.java create mode 100644 src/build/java/net/thoughtmachine/please/test/TestMain.java create mode 100644 src/build/java/net/thoughtmachine/please/test/TestResult.java create mode 100644 src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml create mode 100644 src/build/java/please_maven.go create mode 100644 src/build/java/test_data/test.zip create mode 100644 src/build/java/zip_writer.go create mode 100644 src/build/java/zip_writer_test.go create mode 100644 src/build/python/BUILD create mode 100644 src/build/python/custom_interpreter_test.py create mode 100644 src/build/python/data_dep.py create mode 100644 src/build/python/data_dep_test.py create mode 100755 src/build/python/pex.py create mode 100644 src/build/python/pex_import_test.py create mode 100644 src/build/python/pex_main.py create mode 100644 src/build/python/pex_test.py create mode 100644 src/build/python/test_main.py create mode 100644 src/build/python/zip_unsafe_test.py create mode 100644 src/cache/BUILD create mode 100644 src/cache/cache.go create mode 100644 src/cache/dir_cache.go create mode 100644 src/cache/http_cache.go create mode 100644 src/cache/http_cache_test.go create mode 100644 src/cache/proto/BUILD create mode 100644 src/cache/proto/rpc_cache.proto create mode 100644 src/cache/rpc_cache.go create mode 100644 src/cache/rpc_cache_stub.go create mode 100644 src/cache/rpc_cache_test.go create mode 100644 src/cache/server/BUILD create mode 100644 src/cache/server/cache.go create mode 100644 src/cache/server/cache_test.go create mode 100644 src/cache/server/http_server.go create mode 100644 src/cache/server/http_server_main.go create mode 100644 src/cache/server/http_server_test.go create mode 100644 src/cache/server/rpc_server.go create mode 100644 src/cache/server/rpc_server_main.go create mode 100644 src/cache/server/rpc_server_test.go create mode 100644 src/cache/test_data/darwin_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile create mode 100644 src/cache/test_data/linux_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile create mode 100644 src/cache/test_data/plz-out/gen/pkg/name/testfile2 create mode 100644 src/cache/test_data/plz-out/gen/pkg/name/testfile3 create mode 100644 src/cache/tools/BUILD create mode 100644 src/cache/tools/cache_cleaner.go create mode 100644 src/cache/tools/cache_cleaner_test.go create mode 100644 src/clean/BUILD create mode 100644 src/clean/clean.go create mode 100644 src/core/BUILD create mode 100644 src/core/build_env.go create mode 100644 src/core/build_env_test.go create mode 100644 src/core/build_label.go create mode 100644 src/core/build_target.go create mode 100644 src/core/build_target_test.go create mode 100644 src/core/config.go create mode 100644 src/core/config_test.go create mode 100644 src/core/file_label.go create mode 100644 src/core/graph.go create mode 100644 src/core/label_parse_test.go create mode 100644 src/core/lock.go create mode 100644 src/core/state.go create mode 100644 src/core/state_test.go create mode 100644 src/core/test_data/failing.plzconfig create mode 100644 src/core/test_data/slices.plzconfig create mode 100644 src/core/test_data/working.plzconfig create mode 100644 src/core/utils.go create mode 100644 src/core/utils_test.go create mode 100644 src/misc/BUILD create mode 100755 src/misc/get_plz.sh create mode 100644 src/misc/plz_complete.sh create mode 100644 src/misc/plz_complete.zsh create mode 100644 src/misc/plz_diff_graphs.go create mode 100644 src/misc/plz_diff_graphs_main.go create mode 100644 src/misc/plz_diff_graphs_test.go create mode 100644 src/misc/test_data/after.json create mode 100644 src/misc/test_data/before.json create mode 100644 src/misc/test_data/changed_hash.json create mode 100644 src/misc/test_data/labels.json create mode 100644 src/misc/test_data/labels2.json create mode 100644 src/misc/test_data/removed_package.json create mode 100644 src/output/BUILD create mode 100644 src/output/flags.go create mode 100644 src/output/interactive_display.go create mode 100644 src/output/interactive_display_test.go create mode 100644 src/output/logging.go create mode 100644 src/output/shell_output.go create mode 100644 src/output/shell_output_test.go create mode 100644 src/output/trace.go create mode 100644 src/parse/BUILD create mode 100644 src/parse/additional_output_test.go create mode 100644 src/parse/glob_test.go create mode 100644 src/parse/interpreter.c create mode 100644 src/parse/interpreter.go create mode 100644 src/parse/interpreter.h create mode 100644 src/parse/interpreter_test.go create mode 100644 src/parse/parse_step.go create mode 100644 src/parse/parse_step_test.go create mode 100644 src/parse/require_provide_test.py create mode 100644 src/parse/rules/cc_rules.py create mode 100644 src/parse/rules/go_rules.py create mode 100644 src/parse/rules/java_rules.py create mode 100644 src/parse/rules/misc_rules.py create mode 100644 src/parse/rules/please_parser.py create mode 100644 src/parse/rules/proto_rules.py create mode 100644 src/parse/rules/python_rules.py create mode 100644 src/parse/rules/sh_rules.py create mode 100644 src/parse/test_data/TEST_BUILD create mode 100644 src/parse/test_data/test.txt create mode 100644 src/parse/test_data/test_subfolder1/a.txt create mode 100644 src/parse/test_data/test_subfolder2/BUILD create mode 100644 src/parse/test_data/test_subfolder2/b.txt create mode 100644 src/parse/test_data/test_subfolder3/test.py create mode 100644 src/parse/test_data/test_subfolder4/TEST_BUILD create mode 100644 src/parse/test_data/test_subfolder4/test.py create mode 100644 src/please.go create mode 100644 src/query/BUILD create mode 100644 src/query/affected_targets.go create mode 100644 src/query/alltargets.go create mode 100644 src/query/completions.go create mode 100644 src/query/deps.go create mode 100644 src/query/graph.go create mode 100644 src/query/graph_test.go create mode 100644 src/query/inputs.go create mode 100644 src/query/outputs.go create mode 100644 src/query/print.go create mode 100644 src/query/print_test.go create mode 100644 src/query/query_step.go create mode 100644 src/query/somepath.go create mode 100644 src/run/BUILD create mode 100644 src/run/run_step.go create mode 100644 src/test/BUILD create mode 100644 src/test/container.go create mode 100644 src/test/container_args_test.go create mode 100644 src/test/container_test.go create mode 100644 src/test/coverage.go create mode 100644 src/test/coverage_test.go create mode 100755 src/test/data_files_test.sh create mode 100644 src/test/flakiness_test.py create mode 100644 src/test/go_coverage.go create mode 100644 src/test/go_results.go create mode 100644 src/test/results.go create mode 100644 src/test/results_test.go create mode 100644 src/test/test_data/container_data.txt create mode 100644 src/test/test_data/go_coverage.txt create mode 100644 src/test/test_data/go_coverage_2.txt create mode 100644 src/test/test_data/go_coverage_3.txt create mode 100644 src/test/test_data/go_multiple_failure.txt create mode 100644 src/test/test_data/go_test_failure.txt create mode 100644 src/test/test_data/go_test_ignore_logs.txt create mode 100644 src/test/test_data/go_test_pass.txt create mode 100644 src/test/test_data/go_test_skip.txt create mode 100644 src/test/test_data/go_test_suite.txt create mode 100644 src/test/test_data/go_test_unknown_test.txt create mode 100644 src/test/test_data/junit.xml create mode 100644 src/test/test_data/karma-junit.xml create mode 100644 src/test/test_data/python-coverage.xml create mode 100644 src/test/test_data/unittest.xml create mode 100644 src/test/test_data/xmlrunner-junit.xml create mode 100644 src/test/test_step.go create mode 100644 src/test/xml_coverage.go create mode 100644 src/test/xml_results.go create mode 100644 src/update/BUILD create mode 100644 src/update/update.go create mode 100644 src/utils/BUILD create mode 100644 src/utils/utils.go create mode 100644 test/BUILD create mode 100644 test/IndividualTestRun.java create mode 100644 test/NoTestRun.java create mode 100644 test/affectedtests_test.go create mode 100644 test/basic_completions.txt create mode 100644 test/build_defs/BUILD create mode 100644 test/build_defs/plz_e2e_test.build_defs create mode 100644 test/cc_rules/BUILD create mode 100644 test/cc_rules/cc_multisrc_test.cc create mode 100644 test/cc_rules/cc_query_somepath_test_1.txt create mode 100644 test/cc_rules/cc_query_somepath_test_2.txt create mode 100644 test/cc_rules/deps_test.cc create mode 100644 test/cc_rules/lib1.cc create mode 100644 test/cc_rules/lib1.h create mode 100644 test/cc_rules/lib2.cc create mode 100644 test/cc_rules/lib2.h create mode 100644 test/cc_rules/multisrc.h create mode 100644 test/cc_rules/multisrc_1.cc create mode 100644 test/cc_rules/multisrc_2.cc create mode 100644 test/completions/BUILD create mode 100644 test/coverage_output_test.py create mode 100644 test/extra_test_output_test.py create mode 100644 test/go_rules/BUILD create mode 100644 test/go_rules/go_rules_test_bin.go create mode 100644 test/go_rules/go_rules_test_lib.go create mode 100644 test/go_rules/test/BUILD create mode 100644 test/go_rules/test/test.go create mode 100644 test/individual_test_run.py create mode 100644 test/moar/BUILD create mode 100644 test/num_runs_test.go create mode 100644 test/proto_rules/BUILD create mode 100644 test/proto_rules/specific_out_test.py create mode 100644 test/proto_rules/test.proto create mode 100644 test/query_affectedtests_test.txt create mode 100644 test/query_output_test.txt create mode 100644 test/query_somepath_nopath_test.txt create mode 100644 test/query_somepath_test.txt create mode 100644 test/run_completions.txt create mode 100644 test/test_completions.txt create mode 100644 test/test_output_test_1.txt create mode 100644 test/test_output_test_2.xml create mode 100644 third_party/go/BUILD create mode 100644 third_party/go/gcfg_dynamic_fields.patch create mode 100644 third_party/go/src/zip/BUILD create mode 100644 third_party/go/src/zip/reader.go create mode 100644 third_party/go/src/zip/register.go create mode 100644 third_party/go/src/zip/struct.go create mode 100644 third_party/go/src/zip/writer.go create mode 100644 third_party/java/BUILD create mode 100644 third_party/python/BUILD create mode 100644 third_party/python/coverage_pex.patch create mode 100644 third_party/python/dont_recompress.patch create mode 100644 third_party/python/never_cache_pex.patch diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..2f80725aac --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Output binary from 'go build' +/please +/src/please +# Install directories for third-party Go packages +/pkg +/bin +/src/github.com +/src/golang.org +/src/code.google.com +/src/gopkg.in +/src/google.golang.org +# Generated by go-bindata +/src/parse/builtin_rules.go +# Local config file +.plzconfig.local + +/plz-out +/.plz-cache +/.plz-http-cache +/plz-cache +*.pyc +*.o +*.a +__pycache__ + +.idea +*.iml diff --git a/.plzconfig b/.plzconfig new file mode 100644 index 0000000000..beeef945af --- /dev/null +++ b/.plzconfig @@ -0,0 +1,61 @@ +; We obviously can't rely on anyone having our pex tool already available, +; so in this repo we have to build one without it which we can use to +; compile other python_binary rules within the Please repo itself. +; +; Other projects using Please wouldn't normally need to do anything like this. +[python] +pextool = //src/build/python:bootstrap_pexer +defaultpiprepo = https://s3-eu-west-1.amazonaws.com/py-wheels/index.html + +; This is a hack to handle peasant operating systems with case-insensitive file systems. +; I don't want to rename my package so we have one slightly differently named build file +; in this project. +[please] +buildfilename = BUILD +buildfilename = BUILD_ + +[go] +version = 1.5.3 +; We're going to distribute the binaries and they're quite a bit smaller after this. +; Could disable if people strongly preferred this to be distributed as well. +strip = true + +[cpp] +defaultcflags = --std=c++11 +defaultnamespace = thought_machine + +[java] +jarcattool = //src/build/java:jarcat +junitrunner = //src/build/java:junit_runner +pleasemaventool = //src/build/java:please_maven +defaulttestpackage = net.thoughtmachine +; We want the default to remain at java 8 because obviously it's significantly better, +; but the builtin packages here support java 7 fine so it's nice not to require more. +sourcelevel = 7 +targetlevel = 7 + +[proto] +pythonpackage = third_party.python.google.protobuf +; TODO(pebers): Remove these once we rationalise our package names +grpcpythonplugin = `which grpc_python_plugin` +grpcjavaplugin = `which grpc_java_plugin` +protocgoplugin = //third_party/go:protoc-gen-go + +[docker] +allowlocalfallback = false + +[cache] +dir = .plz-cache +; Too hard to make this guy work during initial bootstrap. +dircachecleaner = + +[licences] +accept = MIT +accept = BSD +accept = BSD License +accept = Simplified BSD +accept = BSD 3-Clause +accept = New BSD License +accept = Apache 2.0 +accept = Apache License, Version 2.0 +accept = PSF \ No newline at end of file diff --git a/BUILD b/BUILD new file mode 100644 index 0000000000..05636904f6 --- /dev/null +++ b/BUILD @@ -0,0 +1,27 @@ +filegroup( + name = 'please', + srcs = ['//src:please'], +) + +filegroup( + name = 'all_tools', + srcs = [ + '//src/build/python:please_pex', + '//src/build/java:junit_runner', + '//src/cache/tools:cache_cleaner', + '//src/cache/server:http_cache_server_bin', + '//src/cache/server:rpc_cache_server_bin', + '//src/build/java:jarcat', + '//src/build/java:please_maven', + '//src/misc:plz_diff_graphs', + ], + deps = [ + '//:please', + ], +) + +filegroup( + name = 'version', + srcs = ['VERSION'], + visibility = ['PUBLIC'], +) diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..30aedb3a04 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,507 @@ +Version 1.4.9 +------------- + + * 'plz clean' now backgrounds itself when possible, in which case the user can + continue with other tasks with no delay. + * Added licenses() builtin function for Bazel compatibility; it roughly parallels + theirs in setting the default licence for all targets in a BUILD file. Implicitly + we can also now use package(default_licences = [...]) which is equivalent. + * + is now allowed in names of build rules. + * Fixed .deb package to include plz_diff_graphs. + + +Version 1.4.8 +------------- + + * Fixed a bug where Please would sometimes panic during coverage display. + * 'plz query graph' now includes all transitive dependencies of requested targets + as well as the targets themselves. + + +Version 1.4.7 +------------- + + * Quoting of expansions in shell commands now only happens when needed. + * $PKG variable is available to test commands as well. + * $ROOT_DIR variable is no longer available to any commands. + + +Version 1.4.6 +------------- + + * Added a 'tools' attribute on genrules which refers to things used to build a rule + which aren't copied into the temp directory. + * Fixed bug where filegroup() didn't correctly honour the binary flag. + + +Version 1.4.5 +------------- + + * Fix debs to have .jar suffix correctly. + * cc_library now correctly supports multiple srcs. As a result it produces a single .a + always instead of .o files. 'archive' attribute is now deprecated. + + +Version 1.4.4 +------------- + + * Make timeout for retrieving Dockerised test results configurable, and default to + a higher value. + * Remove results file before running plz test or plz cover. + * Add configurable extensions which can be excluded from coverage. + + +Version 1.4.3 +------------- + + * Adds support for nested tests in golang (e.g. test suites). + + +Version 1.4.2 +------------- + + * Add a test failure when the test returns nonzero but produces a valid output + file with no errors, so we always show at least one in the summary. + * Add a cc_static_library rule which archives a transitive set of C++ rules. + Essentially it's the static counterpart to cc_shared_object. + * 'plz op' repeats the previous operation. + * Non-zip-safe pexes are now always extracted at startup, even if pex thinks + it doesn't need to. Fixes a bug where incrementality wasn't always correct + because we modify the .pex file after pex has built it. + * New flags --colour and --nocolour allow one to force coloured output on/off. + + +Version 1.4.1 +------------- + + * Temporary directories are now cleaned after successfully building or testing. + * Minor updates to interactive console display. + * Fixes to make cgo_library more robust. + * Small fix to cc_embed_binary which no longer requires passing deps if the src + is generated via a genrule. + + +Version 1.4.0 +------------- + + * java_binary and java_test now generate a self-executable .jar file and no + wrapper script, so the _name#jar sub-rule is no longer generated. + * A number of deprecated arguments have been removed; for example + source_under_test, headers / exported_headers, etc. + * Added a global config parameter to allow enabling/disabling PyPI globally. + * Slightly stricter type checking of arguments to build_rule + * All output of build steps now prints to stderr instead of stdout + (plz query still prints to stdout but plz test / plz build don't) + * Config hashes are now much more granular; only things that affect something + global are used in the calculation of the config hash. Changes to tools etc + are assumed to be handled by the rule hash of any rule using that tool. + * Test container settings in the global config only affect containerised + test rules and only at test time. + * Added a nonce field to the config which we'll use to invalidate the config + hash when necessary. This might happen at any minor release but should + be rare that we'll have to change it. + * Interactive display should be a bit nicer on some non-vsynced terminals + (xterm? not entirely sure what the conditions here were). + * 'query graph' now accepts a list of targets to filter to. + * Support for building with python3. + * Initial support for aliases in config file; the implementation is a little + agricultural but they seem to work so far, within their limits. + * Fix a bunch of small bugs too numerous to mention here. + + +Version 1.3.9 +------------- + + * go_get now takes a `revision` argument which allows pinning libraries to a + particular git revision. `install` now has no effect on it. + * Adding new targets to a package in post build functions now takes effect + immediately, rather than waiting until the end of that post build function. + Fixes some subtle race conditions around dependencies. + + +Version 1.3.8 +------------- + + * Fixed several (benign) race conditions in the interactive display in the interest + of having it run cleanly under go's race detector. + * Bunch of small cleanups suggested by gometalint. + * Add fpm_package and fpm_deb rules and use those to build packages instead of + top-level script. + * Fix for test result hashes; make them the same length as others so the cache cleaner + finds them ok. + * Fixed a hash calculation bug that would sometimes silently fail when the sources of a rule + included a symlink to a directory. + + +Version 1.3.7 +------------- + + * Rules that specify a source dependency on a single output of another rule are now + honoured correctly when being built into a larger rule (eg. a python_library into + a python_binary, as happens often with protos). + * Added option to proto config to rewrite package of Python proto modules. + + +Version 1.3.6 +------------ + + * please_maven now correctly fetches all transitive dependencies, not just one level. + * Added org.ow2.asm:asm-debug-all as a dependency for the test runner which was missing. + * 'plz query graph' now outputs labels in the graph dump. + * plz_diff_graphs can now include/exclude based on labels. + + +Version 1.3.5 +------------- + + * Fixed a couple of subtle internal race conditions. Suspect that most but not all + cases were benign, and it's nicer to have them gone, albeit at the cost of more + lock contention - not that it seems to matter particularly. + * More robust Python licence detection. + + +Version 1.3.4 +------------- + + * More informative error messages when parsing fails due to not finding a package. + * Defaults for repeated entries in the config files now only take effect if nothing else + is specified (ie. the entries in the config replace instead of appending). This + was always the intended behaviour although it's technically breaking. + * Added 'plz query graph' command that produces a (currently fairly minimal) JSON + representation of the graph that other tools could consume. + * Added a tool to diff two graphs produced by new 'query graph' command. + + +Version 1.3.3 +------------- + + * Fix to filegroup rules at the top level of the repo. + * Fix some hash instability in at least some rules. + + +Version 1.3.2 +------------- + + * Support for autodetecting licenses for packages found in a maven_jars rule. + Still pretty experimental since it's surprisingly hard to handle all the maven output + (maybe having someone write this who knew more about Maven would have been an idea...) + * Fix a parse bug where we need to transitively pass the requirement to build a target + that's needed for parse. + * Correct bug in output where it would sometimes crash in rare circumstances (attempting + to print build output of a target that wasn't built due to 'manual' label or similar) + + +Version 1.3.1 +------------- + + * Added possibility for targets to depend on a single output of another rule, + using the format //package:target:output_file. This isn't accepted as a command + line input and is still a little experimental. Proto rules have been changed to + use it instead of generating #only sub-rules. + * Changed detection of multiple rules outputting the same file to parse-time detection + instead of unreliable build-time detection (this requires the proto changes above). + * The exec statement is now banned from the build language. + * When multiple caches are configured, artifacts fetched from a lower-priority cache + are stored into a higher-priority cache (eg. RPC cache -> dir cache). + * Support for associating licences with build targets. Can specify which to accept + and reject in the config. + + +Version 1.3 +----------- + + * Add support to go_binary for stripping symbols. + * Added self-cleaning to HTTP cache + * Added RPC cache implementation. + * Fixed "source file not found" error in some (fairly complex) cases + (I think, this one has been a long battle...) + * Changed jarcat to proper logging & go-flags library + * Implement file copying to dir cache via copy+rename to avoid errors when files + are half-written. + * Building with PyPy 4.0 + * Redid locking around parsing, should allow for better parallelism there + (although I think PyPy is still limited by its GIL). + * Introduced new builtin build function subinclude() which is similar to include_defs + but can be visibility controlled and consumes a real build label instead of basically + a file path. Will eventually remove include_defs since it can't be visibility controlled. + * python_binary rules can be depended on by python_library rules and imported as though + they were a python_library. + + +Version 1.2.7 +------------- + + * Tag test results files with their runtime hash so they are correctly re-run + when runtime data files change + * Small fix to cc_shared_object which was incorrectly marked as binary. + + +Version 1.2.6 +------------- + + * Propagate require / provide through exported_deps when producing sources. + * Add zip_safe as a flag on python_library and pip_library. python_binary and + python_test will pick this up if it's in their transitive dependencies and + mark the pex appropriately. + * Add a flag to control level of messages logged to file output separate from + normal verbosity. + + +Version 1.2.5 +------------- + + * Import ban in Python changed to work by inspecting the AST instead of hacking + __builtins__. Removed some hacky global state changes as a result and added + caching of bytecode which seems quite a bit faster for parsing. + * Add flag to print commands as they're run (CEO request). + * Use directories under /tmp for containerised tests rather than top-level ones + so they can be run as non-root users within the container. + + +Version 1.2.4 +------------- + + * Add detection of multiple rules outputting the same files. This is trickier + then one might think due to things like filegroup() and python_library() + repeating their outputs again so must be done at build time (not parse time). + * Make output trace file configurable. + * Delete test results file at plz startup. + * Disallow : or / in an incoming target name. + * Small cleanup which results in Java source / target levels now being strings. + + +Version 1.2.3 +------------- + + * Small bugfix: named sources that are build labels now automatically add the + dependency in the same way that anonymous sources do. + * Fix a case where post-build rules weren't always linking up deps properly. + * Rename split_path_ext to just splitext, it's more natural. + + +Version 1.2.2 +------------- + + * Small bugfix: always attempt to kill container, even if we can't retrieve results. + * Add basename, dirname, split_path and split_path_ext as global utility functions. + + +Version 1.2.1 +------------- + + * Docker change: rather than attempting to run as the current user which often + has weird effects because they're not known within the container, run as root and + extract the files afterwards with 'docker cp' to avoid root ownership. + * Added timeout and container arguments to sh_test which were missing + * Small improvement to 'plz query print' to not repeat things that are implied + (requires -> labels, exported_deps -> deps). + * Strip all leading underscores for dependent rule names in interactive display + * Remove PY_PKG variable, just replace it in bash + * OP has merged my go-flags patch upstream, it's no longer needed + * Allow specifying the output name of a go_library rule + * Add labels arg to filegroup + + +Version 1.2 +----------- + + * Support for acquiring the transitive set of labels a rule & its dependencies possess. + Useful for implementing properties that affect the final target, eg. cc_library + linker flags being applied to the final cc_binary. + * cc rules: change 'headers' and 'exported_headers' to just 'hdrs', which are always + exported because that's generally what you want. Will consider adding 'private_headers' + or similar later if there's a need but for now I'd prefer the default to be obvious. + * Incremental pex compilation; every python_library rule generates a little .zip file + of just its stuff which get merged together in the final rule. Quite fiddly to get + right but the speedup is dramatic. + * Some rewriting of Go rules to make them more robust for complex libraries & go_get. + * Added an exclusive file lock to two plz processes running in the same repo will + not run simultaneously (unless you pass --nolock). + + +Version 1.1.4 +------------- + + * Added jvm_args parameters to java_test and java_binary so it's possible to + customise JVM startup. + + +Version 1.1.3 +------------- + + * `plz update` now ignores the selfupdate field in config and always updates. + * Added new subcommand, `plz query output` to get the outputs of a rule. + + +Version 1.1.2 +------------- + + * Fix passing relative targets on command line; was accidentally broken by parsing + build labels earlier on in the initialisation process. + * Refactor of the underlying zip writer stuff in jarcat. Doesn't make much difference + yet but is a step towards some future work. + * Add a count of number of targets done / total which better approximates progress. + + +Version 1.1.1 +------------- + + * Upgrade to go 1.5, at last fixed the PyPy issue with a couple of lines of Go. + Note that this is a breaking change for developers (but invisible to users of plz, + so we're doing it at a minor version). + * Share env-building code between build & test, and log more for tests. + * Fixes to http cache. + * New command, 'query affectedtargets', which is similar to 'query affectedtests' but + finds all targets, not just tests. 'query affectedtargets --tests' obsoletes + 'query affectedtests' which will be removed at plz 1.2. + + +Version 1.1 +----------- + + * Major version bump because numbers were getting too big. + * HTTP cache ready for early adopter testing + * Can set containerisation settings on a per-target basis and control the user Docker + runs as within the container. + * Changed $(location ...) style substitutions to use relative instead of absolute paths + so they can be shared via the HTTP cache. + + +Version 1.0.13 +-------------- + + * Expand ~ to home path when building targets. + + +Version 1.0.12 +-------------- + + * Initial implementation of HTTP cache, not yet ready to use. + * Add a little more logging when targets fail to build, which we've seen a few times. + * Some suggestions from go vet, one of which may improve locking potentially + * Ensure rule outputs are added uniquely. + + +Version 1.0.11 +-------------- + + * Fix for cases where sometimes parse errors would not be reported. + Turned out to be related to disallowing imports, so we attempt to + allow them during compilation (but not execution) of code. + * Update of go rules to be more correct and hopefully streamlined around go_get. + + +Version 1.0.10 +-------------- + + * Added RunArgs to [docker] section of config file to allow passing it + arbitrary extra arguments. + * Rewrite of parts of the Go rules to more correctly support targets + in subdirectories. + * add_out() function introduced to build language which can be used + to annotate a target with additional outputs, particularly during + post-build function. Still slightly experimental. + + +Version 1.0.9 +------------- + + * 'query completions' can now be filtered to particular targets, so it will + only complete binaries for 'plz run' and tests for 'plz test' or 'plz cover'. + * Update by downloading tarballs instead of individual binaries. This deprecates + the --extra_tools flag but we will keep it for compatibility for a while. + * Fix for query affectedtests so it correctly excludes manual tests. + + +Version 1.0.8 +------------- + + * Bugfix, 'query affectedtests' not always reading from stdin properly. + + +Version 1.0.7 +------------- + + * Bugfix, previous version mistakenly changed 'query input' to 'query inputs'. + + +Version 1.0.6 +------------- + + * Remove SRCDIR variable and built-in supporting code. No longer needed + for compatibility and the symlink causes problems for some rules because + it introduces a diamond into the folder structure. + * Remove __import__ builtin from parser so build scripts can no longer + import external modules. + * Added a test_only attribute for library rules that ensures they can only be + used by tests or other test_only rules. + * python3 compatibility fix in test_main.py + * Added a package() function that can be used to set various global config + things (probably most usefully, default_visibility). + * Flag parsing refactor; should mostly be invisible externally except that + `plz clean cache` is now `plz clean --cache`. + * Selective test running, eg. `plz test //test:my_test my_test_function` + * --num_runs flag to force a test to run multiple times. + * Some refactoring & bugfixes to require/provide. + + +Version 1.0.5 +------------- + + * Fix crash in output code when window is very small vertically. + * Support for Go 1.5. Seeing some issues that may be caused by it so + not upgrading just yet. + * Populate Java test class names correctly. + * Display elapsed time for each test. + * Fix for require / provide stuff still building unnecessary targets + (they weren't depended on, but still got built). + * Fix caching targets when run with plz cover. + * Support for pseudo-targets like :all and ... with plz clean. + + +Version 1.0.4 +------------- + + * Fix crash when running tests with --no_cache. + * Nothing else, quick release to fix crasher. + + +Version 1.0.3 +------------- + + * Test results are now cached & retrieved as other build artifacts. + * Hashes are verified after retrieving from cache + * Targets retrieved from cache are marked as unchanged when appropriate + * Added a join_path builtin to the build language. + * Remove all outputs after a build fails. + * Attempt to import Python test modules ourselves before relying on unittest's + detection, which produces misleading error messages if an ImportError is + thrown while attempting to load the test. + * Display depending target when we encounter a missing dependency. + * If build fails due to an apparent dependency cycle, attempt to detect and + print the cycle. + + +Version 1.0.2 +------------- + + * Generate a python_library rule behind a python_binary to symlink + the main .py file into plz-out. Fixes certain run issues. + * Set ROOT_DIR variable while running tests. + + +Version 1.0.1 +------------- + + * Support for skipping tests in go_test + * Limit length of printed lines in interactive shell mode so + output doesn't go berserk when window is too narrow. + (it's still not great at being resized down but at least it + stabilises after the window is reduced). + * Fall back to attempting to copy files if hardlink fails. + + +Version 1.0 +----------- + + * f1rst post!!!1!one diff --git a/README.md b/README.md new file mode 100644 index 0000000000..c097586676 --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +Please is a gentleman's build tool. + +It's heavily inspired by Blaze/Bazel and Buck and follows a lot of +similar concepts, but aims to be lighter weight and more flexible +in its build rules. + +See http://please.build for more information. +TODO(all): Set up the website. + + +Getting Started +=============== + +To get started with Please, run ./bootstrap.sh in the repo root. +This will set up the minimal environment needed to build Please, +build it once manually and then rebuild it again using itself. +You'll need to have Go 1.5 and PyPy installed to use Please. +If you're using Ubuntu, run sudo apt-get install golang to install +Go. +Unfortunately at the time of writing the Ubuntu PyPy packages don't +include any shared libraries. We've stashed a .deb at +https://s3-eu-west-1.amazonaws.com/please-build/pypy_4.0.0_amd64.deb +which contains what you need. +To build on OSX, you'll need Homebrew installed. After that it's +rather easier; simply 'brew install pypy' and 'brew install go' +and you should be good to go (heh). + +You'll need to have dependencies for the various helper programs +of Please installed in order to build it. At the moment the minimal +set are Python (which you'll likely have anyway) and Java 7 or above. +Optional dependencies include unittest++ +(sudo apt-get install libunittest++-dev), clang, gold and docker - none +of those are required to build components so their tests will be excluded +if they aren't available. + + +TODOs / Future development +========================== + +At time of writing, Please has passed 8000 lines of Go, and 1000 lines +of Python for the built-in rules. I'm reasonably happy with those (albeit +it's a little more than I originally planned on...) but always keen to +do a little gentle refactoring. +Hopefully it's going to stay at about the same size, at least as an +order of magnitude. + +More tests would be nice. I've been a bit slack, mostly because a lot +of parts of Please are a pain to test because it has so much filesystem +interaction. + +Real multithreaded parsing: since we moved to PyPy we can now parse on any +thread (the original implementation used CPython and couldn't). +Unfortunately it's still limited by the GIL, it would be cool if we could +parse on many threads truly simultaneously. I'm keeping a surreptitious +eye on the pypy-stm branch for this but it's probably a long way off still. + +Customise the build language more; currently it's straight Python with +many of the builtins and a small number of statements banned. Would be cool +to have a more heavily customised dialect to help encourage correctness; +an obvious candidate here would be enforcing ordering on all dicts to +avoid indeterminacy of rules that iterate them, or the (admittedly minor) +performance penalty of sorting them before iteration. + +Deprecate include_defs in favour of subinclude since it can't be +controlled by visibility attributes. Want to be sure subinclude doesn't +compromise significantly on efficiency before we do though. + +Make `plz clean` move the directories and background itself rather than +hanging around in the foreground incessantly. + +Remove temporary directories after targets build successfully. Maybe +control this by a flag or something. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000000..4ea2b1f403 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.4.9 diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000000..7a4c6c3573 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +set -eu + +# Fetch the Go dependencies manually +echo "Installing Go dependencies..." +export GOPATH="${PWD}" +go get github.com/op/go-logging +go get golang.org/x/crypto/ssh/terminal +go get golang.org/x/tools/cover +go get gopkg.in/gcfg.v1 +go get github.com/jteeuwen/go-bindata/... +go get github.com/jessevdk/go-flags +go get github.com/dustin/go-humanize +go get github.com/golang/lint/golint +go get google.golang.org/grpc +go get github.com/kardianos/osext +go get github.com/Songmu/prompter + +# Clean out any old artifacts generated by the builtin rules. +rm -rf src/parse/rules/__pycache__/ src/parse/rules/*.a src/parse/rules/*.pyc +# Invoke this tool to embed the Python scripts. +bin/go-bindata -o src/parse/builtin_rules.go -pkg parse -prefix src/parse/rules/ -ignore BUILD src/parse/rules/ + +# Now invoke Go to run Please to build itself. +echo "Building Please..." +rm -rf plz-out +go run -race src/please.go --plain_output build //src:please //src/build/python:bootstrap_pexer //src/build/java:jarcat //src/build/java:please_maven --log_file plz-out/log/build.log --log_file_level 4 +# Let's prove it works by rebuilding itself with itself. +echo "Rebuilding Please with itself..." +plz-out/bin/src/please --plain_output build //:all_tools //package:tarballs --log_file plz-out/log/build.log --log_file_level 4 + +if [ $# -gt 0 ] && [ "$1" == "--skip_tests" ]; then + exit 0 +fi + +# Run the tests to make sure they still work +echo "Running tests..." + +# Run the set of tests that will work on this machine. +# We assume the user has Java and Python installed or the build will have already failed, +# but some other parts are optional until one actually tries to use the rule. +EXCLUDES="" + +HAVE_UNITTEST=false +for path in `echo | cpp -xc++ -Wp,-v 2>&1 | grep "^ "`; do + if [ -f "${path}/unittest++/UnitTest++.h" ]; then + HAVE_UNITTEST=true + fi +done +if ! $HAVE_UNITTEST ; then + echo "UnitTest++.h not found, excluding C++ tests" + EXCLUDES="${EXCLUDES} --exclude=cc" +fi +if ! hash docker 2>/dev/null ; then + echo "Docker not found, excluding containerised tests" + EXCLUDES="${EXCLUDES} --exclude=container" +fi +if ! hash python3 2>/dev/null ; then + echo "python3 not found, excluding python3 tests" + EXCLUDES="${EXCLUDES} --exclude=py3" +fi +if ! hash clang++ 2>/dev/null ; then + echo "Clang not found, excluding Clang tests" + EXCLUDES="${EXCLUDES} --exclude=clang" +fi +if ! hash gold 2>/dev/null ; then + echo "Gold not found, excluding Gold tests" + EXCLUDES="${EXCLUDES} --exclude=gold" +fi +# Strictly some of these need the library but not the command line tools. +# Pretty sure nobody in the world would be in a situation to care about that distinction though. +if ! hash fstproject 2>/dev/null ; then + echo "libfst not found, excluding relevant tests" + EXCLUDES="${EXCLUDES} --exclude=fst" +fi +plz-out/bin/src/please test ... $EXCLUDES --log_file plz-out/log/build.log --log_file_level 4 diff --git a/docs/advanced.html b/docs/advanced.html new file mode 100644 index 0000000000..322fc4df8e --- /dev/null +++ b/docs/advanced.html @@ -0,0 +1,148 @@ + + + + Advanced Please + + + +

Advanced Please

+ +

So after reading the rest of it, you're wondering what else it can do?

+

This section covers the more esoteric bits of Please functionality. If you're familiar with Blaze or Buck, + these probably still won't be familiar :)

+ +

Pre- and post-build actions

+ +

It's possible in Please to define callbacks in Python that are invoked either immediately before or immediately after + the target is built. These allow modifying aspects of the target or the wider build graph which can potentially + be a powerful tool to handle things that are otherwise awkward or impossible.

+ +

Note that these functions are only evaluated at build time, so their results will not be visible to plz query + and they can be a little hard to debug if you get things wrong. They should hence be used judiciously.

+ +

Pre-build function

+ +

The pre-build function is defined on a build_rule as simply pre_build = lambda name: do_stuff(name).

+ +

As you can see, it's invoked with one argument, the name of the rule about to be built. It's up to you what you do in + the function, although in practice the only really useful thing at present is to inspect the rule's transitive labels and + adjust its build command accordingly. This is done via calling get_labels(name, prefix) where name + is the name of the current rule and prefix is a prefix the labels you're interested in will have (for + convenience, it's stripped from the returned values). Having got these, one can then call set_command(name, cmd) + to alter the command for your rule.

+ +

The built-in C++ rules for Please (src/parse/rules/cc_rules.py) are a reasonably good example of how to use this.

+ +

Post-build function

+ +

The post-build function is somewhat more powerful and useful than the pre-build function, and hence it appeared in the + API several months sooner. It is defined similarly (post_build = lambda name, output: do_stuff(output)) but + takes an extra output which is the standard output of the build rule after successful invocation.

+ +

The power of this is that you can run a build rule to do arbitrary operations and then alter the build graph based + on that; currently you can add outputs to the rule, define new rules and add dependencies to a rule. These lead to + two motivating examples which both occur in built-in rules:

+ +

First, collecting additional output files. This happens with Java protobuf outputs where the output files are not obvious + until the .proto file is parsed, because their location is defined by the option java_package stanza. The + first iteration of proto_library required these to be explicitly defined but that rapidly became tedious; + the nicer solution is detecting it this way. The build rule simply invokes find to locate all the .java files + it produces and the post-build function receives those and runs add_out(name, java_file) for each.

+ +

Second, we wanted to be able to fetch third-party dependencies without having to expand a transitive dependency tree + into separate maven_jar rules by hand. maven_jars does this by hitting up Maven to get the + dependencies then generating a new build rule for each.

+ +

Require / Provide

+ +

This is a generalised mechanism for rules to provide specialised dependencies to other rules. The most obvious example + is again proto_library, also illustrating how it's a harder rule to write well than you'd think.

+ +

The problem with proto_library is that we ideally want to maintain the illusion that there's one rule + by the name given in the BUILD file and have all other rules depend only on that, but of course it generates outputs + for multiple languages and it's pretty suboptimal to have your python_library have to wait for the + C++ and Java generated code to compile.

+ +

This is solved by the proto_library rule declaring the following property: +


+	provides = {
+	    'py': ':python_dependency',
+	    'java': ':java_dependency',
+            'cc': ':cc_dependency',
+        }
+      
+ And then the python_library rule is annotated with +

+	  requires = ['py']
+      
+ Individually neither has any effect, but when a rule with a particular require depends on another with + a matching provide, its dependency is matched directly to the one specified by the providing rule. This + means that it can skip other dependencies that it doesn't care about and be matched only to the ones it does.

+ +

The consequence of this - skipping the actual declared dependency - can be a bit nonobvious so again should be + invoked sparingly. Typically the rule declaring provides should be a no-op collecting rule such as + filegroup and the various provided rules shouldn't normally be needed together. Different languages + are the most common example here (and indeed this feature was nearly named language at one point).

+ +

The requires stanza is also responsible for colouring the interactive build output. Currently the available + colours are hardcoded but one of these days they might become configurable.

+ +

Hash verification

+ +

Please can natively verify hashes of packages. Some of the built-in rules for fetching things from third-party + repos have this option, and you can add it to your own genrules. For example, one of the Python libraries we use: + +

+        pip_library(
+            name = 'coverage',
+            version = '4.0a6',
+            hashes = [
+                'sha1: 39bc6df0d3f7c0633fed8336324e1a7caab58dfa',
+                'sha1: 115cc5c535340856c390d6739c34b7a545349145',
+            ],
+            patch = 'coverage_pex.patch',
+        )
+      
+ + This declares that the calculated sha1 hash of the package must match one of the given set, and it's a failure + if not. +

+ +

Currently the only real way to calculate one of these hashes is to run the rule, let it fail and find the + actual hash, then enter that. At some point in the future we'd like to provide better tooling around this + (eg. automatically updating the build file with a particular hash).

+ +

The reason for allowing multiple is for rules that generate different outputs on different architectures; + this is common for Python libraries which have a compiled component, for example.

+ +

For testing purposes you can run Please with the --nohash_verification flag which will reduce hash + verification failures to a warning message only.

+ +

Note that when using this you must be careful that the outputs of your rule are really deterministic. This is + generally true for remote_file calls, but obviously only if the server returns the same thing + every time for that URL. Some care should be taken with pip_library since the outputs of a + 'pip install' are not bit-for-bit identical if compiled locally, only if you downloaded a precompiled wheel.

+ +

Licence validation

+ +

Please can attempt to autodetect licences from third-party packages and inform you if they're not ones you'd + accept. You mark licences in the .plzconfig file like so: +

+        [licences]
+        accept = MIT
+        accept = BSD
+        reject = MS-EULA
+      
+ By default, with no [licences] section, Please won't perform any licence checking. Once you've added some any + package with a licence must have a matching accepted licence in the config. +

+ +

Currently we can autodetect licences from pip_library rules, you can also set them manually via + the licences attribute on a rule.

+ +

It bears mentioning that this is done as a best-effort - since licences and their locations are not standardised + in pip (and many other places) we can't always be fully confident about this, so it can't be a full substitute for + validating licences yourself.

+ + + diff --git a/docs/basics.html b/docs/basics.html new file mode 100644 index 0000000000..c5ef4b415b --- /dev/null +++ b/docs/basics.html @@ -0,0 +1,95 @@ + + + + Please basics + + + +

Please basics

+ +

If you're familiar with Blaze / Bazel, Buck or Pants you will probably find Please very familiar. + Otherwise, don't worry, it's not very complicated...

+ +

BUILD files

+

Please targets are defined in files named BUILD. These are analogous to Makefiles in that they define + buildable targets for that directory. Fortunately, they do so in a rather nicer syntax.
+ We refer to a directory containing a BUILD file as a package. +

+ +

Build targets

+

Each BUILD file can contain a number of build targets. These are units of buildable code + which can be reused by other build targets. An example is probably worth 1000 words at this point: +


+	  python_library(
+	      name = 'my_library',
+	      srcs = ['file1.py', 'file2.py'],
+	  )
+
+	  python_binary(
+	      name = 'my_binary',
+	      main = 'my_main.py',
+	      deps = [':my_library'],
+	  )
+
+	  python_test(
+	      name = 'my_library_test',
+	      srcs = ['my_library_test.py'],
+	      deps = [':my_library'],
+	  )
+      
+ This snippet defines three build rules: + + This illustrates the core points of Please; every rule clearly defines its inputs - its own sources and its dependencies - + and since these are known Please can be aggressive about parallelising, caching and reusing build artifacts. +

+ +

Okay, great, so how do I actually use them?

+ +

Let's assume the build rules given above are defined in a file in your repo named package/BUILD. You can do the following: +

+

+ +

Build labels

+ +

That brings us to the topic of build labels, which are identifiers of build targets. As you've just seen, + these are of the form //package:target, where package is the path from the repo root to that package, + and target is the name of the target within that package.
+ This is the most common form to identify targets absolutely, but there is also a convenient shorthand where we omit + the part before the colon (as you saw earlier as well) to refer to a target within the current package.

+ +

The convention is to use lower_case_with_underscored for both package names and target names.
+ This is not just for looks; in many languages (eg. Python, Java) the file path appears within the source files, + and so it's important to choose something that's a valid lexical identifier.

+ +

There are also some special pseudo-labels: +

+ Build targets can't use these as dependencies; these are primarily for using on the command + line or in the visibility specification for a target. +

+ +

What now?

+ +

Jump in and get started! See the please lexicon if you want to see the set of built-in + build rules for other languages.

+ +

If that all sounds a bit easy so far, try the intermediate topics and start + learning how to program the system and create your own build rules.

+ + + diff --git a/docs/intermediate.html b/docs/intermediate.html new file mode 100644 index 0000000000..aa7e9f3860 --- /dev/null +++ b/docs/intermediate.html @@ -0,0 +1,186 @@ + + + + Intermediate Please + + + +

Intermediate Please

+ +

Okay, you've read the basics, so what's next?

+ +

BUILD file format

+

We didn't talk much about the actual format of BUILD files last time, but an astute observer may + have noticed that the rule invocations look rather like Python. This is not coincidence; BUILD files + are interpreted as a (slightly) restricted subset of Python.

+ +

So what can you do with them? Well, let's say you want to translate your documentation to a bunch of languages: +


+	  for language in ['en_NZ', 'en_GB', 'it_IT', 'es_MX', 'el_GR']:
+	      genrule(
+	          name = 'txt_documentation_' + language,
+	          srcs = ['docs.txt'],
+	          outs = ['docs_%s.txt' % language],
+	          cmd = 'cat $SRC | $(exe //tools:translate_tool) --language %s > $OUT' % language,
+	      )
+
+	      genrule(
+	          name = 'documentation_' + language,
+	          srcs = [':txt_documentation_' + language],
+                  outs = ['docs_%s.html' % language],
+                  cmd = '$(exe //tools:html_doc_tool) --src $SRC --out $OUT',
+	          visibility = ['PUBLIC'],
+          )
+      
+ + Obviously this would be a bit repetitive if you redefined the rules separately for each language. Instead, we can take + advantage of the build language to genericise them across languages; for each language we translate it and then + format it as HTML. +

+ +

Custom build rules

+ +

While the above is perfectly readable, having to define two rules each time is a bit tedious; + maybe we'd rather define one rule to perform the translation & HTML conversion in one pass. + + docs/documentation_rules.build_defs:
+


+	  def create_html_docs(name, language, srcs, visibility=None):
+	      """Converts documentation to the given language and then to HTML."""
+	      genrule(
+	          name = '_%s_%s#translate' % (name, language),
+	          srcs=srcs,
+                  outs = ['_%s_%s_translated.txt' % (name, language),
+	          cmd = 'cat $SRC | $(exe //tools:translate_tool) --language %s > $OUT' % language,
+	      )
+	      genrule(
+	          name = '%s_%s' % (name, language),
+	          srcs = [':_%s_%s#translate' % (name, language)],
+                  outs = ['%s_%s.html' % (name, language)],
+                  cmd = '$(exe //tools:html_doc_tool) --src $SRC --out $OUT',
+	          visibility = ['PUBLIC'],
+              )
+      
+ docs/BUILD:
+

+	  include_defs('//docs/documentation_rules.build_defs')
+	  for language in ['en_NZ', 'en_GB', 'it_IT', 'es_MX', 'el_GR']:
+	      create_html_docs(
+	          name = 'docs',
+	          language = language,
+	          srcs = ['docs.txt'],
+                  visibility = ['PUBLIC'],
+              )
+      
+

+ +

This example is getting a little strained, but serves to illustrate how you can create something that acts + like a single build rule, but internally creates multiple steps to produce the final result. Since the BUILD + files are essentially Python it's as simple as defining a function.

+ +

Note the microformat of defining 'internal' private rules with a leading underscore and trailing hashtag; + in the interactive build mode those will be omitted to make it appear to users as though they're building + the rule they defined by name, even though internally it's split into multiple rules.

+ +

Transitive dependencies

+ +

Writing some rules requires that the transitive set of dependencies are available when they're built.

+ +

For example, consider cc_binary; all your cc_library rules have created a bunch of .o files, + but each of those only has its own set of symbols. The final binary rule must link all of them together to produce + a working executable.

+ +

Fortunately, this is pretty easy in Please. You can apply needs_transitive_dependencies = True to a + genrule to make them all available at build time. This is easy to do but of course shouldn't be taken + lightly since it will slow the rule down (needs more time to prepare sources) and may harm incrementality.
+ The typical pattern is that _library rules don't need this but _binary and _test + rules do, although this is somewhat dependent on the language.

+ +

gentest

+ +

gentest is similar to genrule but defines a target that runs an arbitrary test. The + test_cmd attribute defines the command to run; this is often simply $(exe :rule_name) + to run its own output.

+ +

The protocol for tests to follow is pretty simple; the test command should return zero on success or nonzero + for failure (Unix FTW). The test should also write either a file called test.results or multiple files + into a directory named the same; these are parsed as one of the formats Please understands (currently either + xUnit XML or Go's test output format). Optionally a test can be marked with no_test_output = True + to indicate that it writes no files, in which case its return value is the only indicator of success.

+ +

Labels

+ +

Rules, particularly the various _test rules can have an optional set of labels associated with + them. These are essentially just a set of tags that can be used to filter them when run via plz test, + for example plz test ... --include py will run all your tests labelled with 'py', + and plz test ... --exclude slow will run all your tests except those labelled with 'slow'.

+ +

The syntax looks like: +

+        go_test(
+            name = 'my_test',
+            srcs = ['my_test.go'],
+            labels = ['slow', 'integration'],
+        )
+      
+

+ +

There is one special label, manual which always excludes tests from autodetection when being run with + plz test //mypackage:all or plz test //mypackage/.... This is often useful to disable tests + from general usage if needed (for example, if a test starts failing, you can disable it while investigating).

+ +

Flaky tests

+ +

Tests can be marked as flaky which causes them to be automatically re-run several times. They are considered + to pass if any one run passes.

+ +

The syntax looks like: +

+        go_test(
+            name = 'my_test',
+            srcs = ['my_test.go'],
+            flaky = True,
+        )
+      
+ By default they are run three times, you can alter this on a per-test basis by passing an integer instead of a boolean. +

+ +

The --max_flakes flag can be used to cap the number of re-runs allowed on a single invocation.

+ +

Containerised tests

+ +

Tests can also be marked as containerised so they are isolated within a container for the duration of their run. + One main advantage of this is for integration tests that need to open ports and start servers, which are then insulated + from port clashes against one another.

+ +

Within the container the test will have access only to the data it's declared it needs at runtime, so you will have + to be correct about declaring all such dependencies (but of course one would do that anyway...).

+ +

The syntax looks like: +

+        go_test(
+            name = 'my_test',
+            srcs = ['my_test.go'],
+            container = True,
+        )
+      
+

+ +

Currently we support Docker as a container format, we plan to support rkt containers in a future release.

+ +

build_rule

+ +

build_rule is the fundamental unit all other build rules are built from. We discussed genrule + just now which is very similar; build_rule allows control over more esoteric features of the system.
+ See the entry in the build lexicon for more details.

+ +

The difference between genrule and build_rule from a user's perspective is pretty arbitrary; + conventionally we use genrule in build files for defining arbitrary build transformations and + build_rule for defining other rules, but there's no particularly principled reason for this.

+ +

What else?

+ +

If you're still curious about what more can be done, try the advanced stuff.

+ + + diff --git a/docs/quickstart.html b/docs/quickstart.html new file mode 100644 index 0000000000..a7d617d6e2 --- /dev/null +++ b/docs/quickstart.html @@ -0,0 +1,40 @@ + + + + Please quickstart + + + +

Please quickstart

+ +

System requirements

+

Please supports Linux and OSX at the moment. We're internally using Ubuntu Trusty and Yosemite but it should + work on other reasonably recent distros.

+ +

Installing

+

curl https://s3-eu-west-1.amazonaws.com/please-build/get_plz.sh | bash

+

This will download and install the latest version of Please on your system.

+

You'll also need PyPy installed, including the .so which is not present in many packaged versions of it.
+ We have a .deb compatible with Ubuntu 14.04 which you can fetch from + https://s3-eu-west-1.amazonaws.com/please-build/pypy_4.0.0_amd64.deb. + brew install pypy should work on OSX though. +

+ +

Shell completion

+

There are a couple of shell completion scripts available:

+ +

Bash: https://s3-eu-west-1.amazonaws.com/please-build/plz_complete.sh
+ Download it and source it from your .bashrc.

+ +

zsh: https://s3-eu-west-1.amazonaws.com/please-build/plz_complete.zsh
+ Download, rename to _plz and put it somewhere in your $fpath, + e.g. /usr/local/share/zsh/site-functions

+ +

Getting started

+

Run plz init at the root of your repo to create the .plzconfig file. + There are many options that can be configured in this file but you can worry about them + later - the defaults should be fine to begin with.
+ You're ready to go now - carry on to Please Basics. +

+ + diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 0000000000..f6a647e577 --- /dev/null +++ b/docs/styles.css @@ -0,0 +1,3 @@ +body { + font-family: sans-serif; +} \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100755 index 0000000000..41c7312f27 --- /dev/null +++ b/install.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# +# Installs Please and its relevant binaries into /opt/please. +# You must run ./bootstrap.sh before running this. + +set -eu + +[[ -w /opt && -w /usr/local ]] || sudo sh -c "mkdir -p /opt && chown -R $USER /opt /usr/local" + +if [ ! -f plz-out/bin/src/please ]; then + echo "It looks like Please hasn't been built yet." + echo "Try running ./bootstrap.sh first." +else + if [ ! -d /opt/please ]; then + sudo mkdir -p /opt/please + sudo chown `whoami` /opt/please + fi + rm -f /opt/please/please /opt/please/please_pex /opt/please/junit_runner.jar /opt/please/jarcat /opt/please/please_maven /opt/please/cache_cleaner + cp plz-out/bin/src/please /opt/please/please + chmod 0775 /opt/please/please + cp plz-out/bin/src/build/python/please_pex.pex /opt/please/please_pex + chmod 0775 /opt/please/please_pex + cp plz-out/bin/src/build/java/junit_runner.jar /opt/please/junit_runner.jar + chmod 0775 /opt/please/junit_runner.jar + cp plz-out/bin/src/build/java/jarcat /opt/please/jarcat + chmod 0775 /opt/please/jarcat + cp plz-out/bin/src/build/java/please_maven /opt/please/please_maven + chmod 0775 /opt/please/please_maven + cp plz-out/bin/src/cache/tools/cache_cleaner /opt/please/cache_cleaner + chmod 0775 /opt/please/cache_cleaner + cp plz-out/bin/src/misc/plz_diff_graphs /opt/please/please_diff_graphs + chmod 0775 /opt/please/please_diff_graphs + ln -sf /opt/please/please /usr/local/bin/plz + echo "Please installed" +fi diff --git a/package/BUILD b/package/BUILD new file mode 100644 index 0000000000..37255124d7 --- /dev/null +++ b/package/BUILD @@ -0,0 +1,81 @@ +fpm_deb( + name = 'please', + version = CONFIG.PLZ_VERSION, + files = { + '/opt/please/please': '//src:please', + '/opt/please/please_pex': '//src/build/python:please_pex', + '/opt/please/please_maven': '//src/build/java:please_maven', + '/opt/please/junit_runner.jar': '//src/build/java:junit_runner', + '/opt/please/cache_cleaner': '//src/cache/tools:cache_cleaner', + '/opt/please/jarcat': '//src/build/java:jarcat', + '/opt/please/please_diff_graphs': '//src/misc:plz_diff_graphs', + }, + links = { + '/usr/bin/plz': '/opt/please/please', + '/usr/bin/plz_diff_graphs': '/opt/please/please_diff_graphs', + }, + labels = ['manual'], +) + +fpm_deb( + name = 'plz_rpc_cache_server', + package_name = 'plz-rpc-cache-server', + version = CONFIG.PLZ_VERSION, + files = { + '/usr/bin/plz_rpc_cache_server': '//src/cache/server:rpc_cache_server_bin', + '/etc/init.d/plz-rpc-cache': 'init.sh', + }, + options = '--deb-init etc/init.d/plz-rpc-cache -x etc/init.d/plz-rpc-cache', + labels = ['manual'], +) + +fpm_deb( + name = 'plz_http_cache_server', + package_name = 'plz-http-cache-server', + version = CONFIG.PLZ_VERSION, + files = { + '/usr/bin/plz_http_cache_server': '//src/cache/server:http_cache_server_bin', + '/etc/init.d/plz-http-cache': 'init.sh', + }, + options = '--deb-init etc/init.d/plz-http-cache -x etc/init.d/plz-http-cache', + labels = ['manual'], +) + +# Remove the .pex suffix from this guy +genrule( + name = 'please_pex', + srcs = ['//src/build/python:please_pex'], + outs = ['please_pex'], + cmd = 'cp $SRC $OUT', + binary = True, +) + +tarball( + name = 'please_tarball', + srcs = [ + '//src:please', + ':please_pex', + '//src/build/java:junit_runner', + '//src/cache/tools:cache_cleaner', + '//src/build/java:jarcat', + '//src/build/java:please_maven', + '//src/misc:plz_diff_graphs', + ], + subdir = 'please', + out = 'please.tar.gz', +) + +tarball( + name = 'servers_tarball', + srcs = [ + '//src/cache/server:http_cache_server_bin', + '//src/cache/server:rpc_cache_server_bin', + ], + subdir = 'please', + out = 'please_servers.tar.gz', +) + +filegroup( + name = 'tarballs', + deps = [':please_tarball', ':servers_tarball'], +) diff --git a/package/init.sh b/package/init.sh new file mode 100755 index 0000000000..5d77e497e1 --- /dev/null +++ b/package/init.sh @@ -0,0 +1,64 @@ +#! /bin/bash + +BASE=$(basename $0) +NAME=${BASE//-/_} +BIN=/usr/bin/${NAME}_server + +# TODO(pebers): Make this stuff configurable sensibly +export VERBOSITY=2 +export PORT=7677 +export DIR=/var/cache/plz_rpc +export LOW_WATER_MARK=45G +export HIGH_WATER_MARK=50G +export CLEAN_FREQUENCY=10 + +PIDFILE=/var/run/${NAME}.pid + +start() { + echo "starting plz rpc cache" + start-stop-daemon --pidfile $PIDFILE --start --exec $BIN -- -v $VERBOSITY -p $PORT -d $DIR -l $LOW_WATER_MARK -i $HIGH_WATER_MARK -f $CLEAN_FREQUENCY +} + +stop() { + echo "stopping teamcity-server" + start-stop-daemon --pidfile $PIDFILE --stop $BIN +} + +status() { + ps aux | grep $BIN | grep -v grep > /dev/null 2>&1 + out=$? + if [ $out -eq 0 ] + then + echo 'Running!' + else + echo 'Not Running!' + fi + exit $out +} + +# Carry out specific functions when asked to by the system +case "$1" in + start) + start + RETVAL=$? + ;; + stop) + stop + RETVAL=$? + ;; + restart) + start + stop + RETVAL=$? + ;; + status) + status + RETVAL=$? + ;; + *) + echo "Usage: $0 {start|stop|restart}" + exit 1 + ;; +esac + +exit $RETVAL diff --git a/src/BUILD_ b/src/BUILD_ new file mode 100644 index 0000000000..4d61a5e17a --- /dev/null +++ b/src/BUILD_ @@ -0,0 +1,21 @@ +go_binary( + name = 'please', + deps = [ + '//src/build', + '//src/cache', + '//src/clean', + '//src/core', + '//src/output', + '//src/parse', + '//src/query', + '//src/run', + '//src/test', + '//src/update', + '//src/utils', + '//third_party/go:go-flags', + '//third_party/go:logging', + '//third_party/go:osext', + '//third_party/go:terminal', + ], + visibility = ['PUBLIC'], +) diff --git a/src/build/BUILD b/src/build/BUILD new file mode 100644 index 0000000000..8bde2a4a9b --- /dev/null +++ b/src/build/BUILD @@ -0,0 +1,27 @@ +go_library( + name = 'build', + srcs = glob(['*.go'], excludes=['*_test.go']), + deps = [ + '//src/core', + '//src/parse', + '//src/cache', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'command_replacements_test', + srcs = ['command_replacements_test.go'], + deps = [ + ':build' + ] +) + +go_test( + name = 'incrementality_test', + srcs = ['incrementality_test.go'], + deps = [ + ':build', + ], +) diff --git a/src/build/build_step.go b/src/build/build_step.go new file mode 100644 index 0000000000..34b9552a2e --- /dev/null +++ b/src/build/build_step.go @@ -0,0 +1,387 @@ +// The build package houses the core functionality for actually building targets. +package build + +import ( + "bytes" + "crypto/sha1" + "encoding/hex" + "fmt" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + + "github.com/op/go-logging" + + "core" + "parse" +) + +var log = logging.MustGetLogger("build") + +func Build(tid int, state *core.BuildState, label core.BuildLabel) { + target := state.Graph.TargetOrDie(label) + target.SetState(core.Building) + if err := buildTarget(tid, state, target); err != nil { + state.LogBuildError(tid, label, core.TargetBuildFailed, err, "Build failed: %s", err) + if err := removeOutputs(target); err != nil { + log.Error("Failed to remove outputs for %s: %s", target.Label, err) + } + target.SetState(core.Failed) + return + } + + // Add any of the reverse deps that are now fully built to the queue. + for _, reverseDep := range state.Graph.ReverseDependencies(target) { + if reverseDep.State() == core.Active && state.Graph.AllDepsBuilt(reverseDep) && reverseDep.SyncUpdateState(core.Active, core.Pending) { + state.AddPendingBuild(reverseDep.Label) + } + } + if target.IsTest && state.NeedTests { + state.AddPendingTest(target.Label) + } + parse.UndeferAnyParses(state, target) +} + +// Builds a single target +func buildTarget(tid int, state *core.BuildState, target *core.BuildTarget) (err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("%s", r) + } + }() + + if err := target.CheckDependencyVisibility(); err != nil { + return err + } + // We can't do this check until build time, until then we don't know what all the outputs + // will be (eg. for filegroups that collect outputs of other rules). + if err := target.CheckDuplicateOutputs(); err != nil { + return err + } + state.LogBuildResult(tid, target.Label, core.TargetBuilding, "Preparing...") + // This must run before we can leave this function successfully by any path. + if target.PreBuildFunction != 0 { + if err := parse.RunPreBuildFunction(tid, state, target); err != nil { + return err + } + } + if !needsBuilding(state, target, false) { + log.Debug("Not rebuilding %s, nothing's changed", target.Label) + runPostBuildFunctionIfNeeded(tid, state, target) + // If a post-build function ran it may modify the rule definition. In that case we + // need to check again whether the rule needs building. + if target.PostBuildFunction == 0 || !needsBuilding(state, target, true) { + target.SetState(core.Unchanged) + state.LogBuildResult(tid, target.Label, core.TargetCached, "Unchanged") + return nil // Nothing needs to be done. + } else { + log.Debug("Rebuilding %s after post-build function", target.Label) + } + } + if err := prepareDirectories(target); err != nil { + return fmt.Errorf("Error preparing directories for %s: %s", target.Label, err) + } + + retrieveArtifacts := func() bool { + if _, retrieved := retrieveFromCache(state, target); retrieved { + log.Debug("Retrieved artifacts for %s from cache", target.Label) + if calculateAndCheckRuleHash(state, target) { + target.SetState(core.Built) + } else { + target.SetState(core.Unchanged) + } + checkLicences(state, target) + state.LogBuildResult(tid, target.Label, core.TargetCached, "Cached") + return true // got from cache + } + return false + } + + cacheKey := mustTargetHash(state, target) + if state.Cache != nil && !target.SkipCache { + // Note that ordering here is quite sensitive since the post-build function can modify + // what we would retrieve from the cache. + state.LogBuildResult(tid, target.Label, core.TargetBuilding, "Checking cache...") + if target.PostBuildFunction != 0 { + log.Debug("Checking for post-build output file for %s in cache...", target.Label) + if (*state.Cache).RetrieveExtra(target, cacheKey, core.PostBuildOutputFileName(target)) { + runPostBuildFunctionIfNeeded(tid, state, target) + if retrieveArtifacts() { + return nil + } + } + } else if retrieveArtifacts() { + return nil + } + } + if err := prepareSources(state.Graph, target, target, map[core.BuildLabel]bool{}); err != nil { + return fmt.Errorf("Error preparing sources for %s: %s", target.Label, err) + } + state.LogBuildResult(tid, target.Label, core.TargetBuilding, target.BuildingDescription) + replacedCmd := replaceSequences(target) + cmd := exec.Command("bash", "-c", replacedCmd) + cmd.Dir = target.TmpDir() + cmd.Env = core.BuildEnvironment(state, target, false) + log.Debug("Building target %s\nENVIRONMENT:\n%s\n%s", target.Label, strings.Join(cmd.Env, "\n"), replacedCmd) + if state.PrintCommands { + log.Notice("Building %s: %s", target.Label, replacedCmd) + } + out, err := core.ExecWithTimeout(cmd, target.BuildTimeout, state.Config.Build.Timeout) + if err != nil { + if state.Verbosity >= 4 { + return fmt.Errorf("Error building target %s: %s\nENVIRONMENT:\n%s\n%s\n%s", + target.Label, err, strings.Join(cmd.Env, "\n"), target.Command, out) + } else { + return fmt.Errorf("Error building target %s: %s\n%s", target.Label, err, out) + } + } + if target.PostBuildFunction != 0 { + if err := parse.RunPostBuildFunction(tid, state, target, string(out)); err != nil { + return err + } + storePostBuildOutput(state, target, out) + } + checkLicences(state, target) + state.LogBuildResult(tid, target.Label, core.TargetBuilding, "Collecting outputs...") + outputsChanged, err := moveOutputs(state, target) + if err != nil { + return fmt.Errorf("Error moving outputs for target %s: %s", target.Label, err) + } else if outputsChanged { + target.SetState(core.Built) + } else { + target.SetState(core.Unchanged) + } + if state.Cache != nil && !target.SkipCache { + state.LogBuildResult(tid, target.Label, core.TargetBuilding, "Storing...") + (*state.Cache).Store(target, mustTargetHash(state, target)) + if target.PostBuildFunction != 0 { + // NB. Important this is stored with the earlier hash - if we calculate the hash + // now, it might be different, and we could of course never retrieve it again. + (*state.Cache).StoreExtra(target, cacheKey, core.PostBuildOutputFileName(target)) + } + } + // Clean up the temporary directory once it's done. + if state.CleanWorkdirs { + if err := os.RemoveAll(target.TmpDir()); err != nil { + log.Warning("Failed to remove temporary directory for %s: %s", target.Label, err) + } + } + state.LogBuildResult(tid, target.Label, core.TargetBuilt, "Built") + return nil +} + +// Prepares the output directories for a target +func prepareDirectories(target *core.BuildTarget) error { + if err := prepareDirectory(target.TmpDir(), true); err != nil { + return err + } + if err := prepareDirectory(target.OutDir(), false); err != nil { + return err + } + // Nicety for the build rules: create any directories that it's + // declared it'll create files in. + for _, out := range target.Outputs() { + if dir := path.Dir(out); dir != "." { + outPath := path.Join(target.TmpDir(), dir) + if !core.PathExists(outPath) { + if err := os.MkdirAll(outPath, core.DirPermissions); err != nil { + return err + } + } + } + } + return nil +} + +func prepareDirectory(directory string, remove bool) error { + if remove && core.PathExists(directory) { + if err := os.RemoveAll(directory); err != nil { + return err + } + } + return os.MkdirAll(directory, core.DirPermissions) // drwxrwxr-x +} + +// Symlinks the source files of this rule into its temp directory. +func prepareSources(graph *core.BuildGraph, target *core.BuildTarget, dependency *core.BuildTarget, done map[core.BuildLabel]bool) error { + for source := range core.IterSources(graph, target, true) { + if err := core.PrepareSourcePair(source); err != nil { + return err + } + } + return nil +} + +func moveOutputs(state *core.BuildState, target *core.BuildTarget) (bool, error) { + // Before we write any outputs, we must remove the old hash file to avoid it being + // left in an inconsistent state. + if err := os.Remove(ruleHashFileName(target)); err != nil && !os.IsNotExist(err) { + return true, err + } + for _, output := range target.Outputs() { + tmpOutput := path.Join(target.TmpDir(), output) + realOutput := path.Join(target.OutDir(), output) + if !core.PathExists(tmpOutput) { + return true, fmt.Errorf("Rule %s failed to create output %s", target.Label, tmpOutput) + } + // If output is a symlink, dereference it. Otherwise, for efficiency, + // we can just move it without a full copy (saves copying large .jar files etc). + dereferencedPath, err := filepath.EvalSymlinks(tmpOutput) + if err != nil { + return true, err + } + // hash the file + newHash, err := pathHash(dereferencedPath) + if err != nil { + return true, err + } + // The tmp output can be a symlink back to the real one; this is allowed for rules like + // filegroups that attempt to link outputs of other rules. In that case we can't + // remove the original because that'd break the link, but by definition we don't need + // to actually do anything more. + // TODO(pebers): The logic here is quite tortured, consider a (very careful) rewrite. + dereferencedOutput, _ := filepath.EvalSymlinks(realOutput) + if absOutput, _ := filepath.Abs(realOutput); dereferencedPath == absOutput || realOutput == dereferencedPath || dereferencedOutput == dereferencedPath { + continue + } + if core.PathExists(realOutput) { + oldHash, err := pathHash(realOutput) + if err != nil { + return true, err + } else if bytes.Equal(oldHash, newHash) { + // We already have the same file in the current location. Don't bother moving it. + continue + } + } + if err := os.RemoveAll(realOutput); err != nil { + return true, err + } + movePathHash(dereferencedPath, realOutput) + // Check if we need a directory for this output. + dir := path.Dir(realOutput) + if !core.PathExists(dir) { + if err := os.MkdirAll(dir, core.DirPermissions); err != nil { + return true, err + } + } + // If the output file is in plz-out/tmp we can just move it to save time, otherwise we need + // to copy so we don't move files from other directories. + if strings.HasPrefix(dereferencedPath, target.TmpDir()) { + if err := os.Rename(dereferencedPath, realOutput); err != nil { + return true, err + } + } else { + if err := core.RecursiveCopyFile(dereferencedPath, realOutput, 0, false); err != nil { + return true, err + } + } + if target.IsBinary { + if err := os.Chmod(realOutput, 0775); err != nil { + return true, err + } + } + } + return calculateAndCheckRuleHash(state, target), nil +} + +// Removes all generated outputs for a rule. +func removeOutputs(target *core.BuildTarget) error { + if err := os.Remove(ruleHashFileName(target)); err != nil && !os.IsNotExist(err) { + return err + } + for _, output := range target.Outputs() { + if err := os.RemoveAll(path.Join(target.OutDir(), output)); err != nil { + return err + } + } + return nil +} + +// Checks the hash for a rule and compares it to any previous one. +// Returns true if outputs have changed from what was there previously. +func calculateAndCheckRuleHash(state *core.BuildState, target *core.BuildTarget) bool { + h := sha1.New() + for _, output := range target.Outputs() { + if h2, err := pathHash(path.Join(target.OutDir(), output)); err != nil { + panic(err) + } else { + h.Write(h2) + } + } + hash := h.Sum(nil) + if err := checkRuleHashes(target, hash); err != nil { + if state.VerifyHashes { + panic(err) + } else { + log.Warning("%s", err) + } + } + // TODO(pebers): We should be able to get away without reading & writing this file quite so often... + _, _, oldSourceHash := readRuleHashFile(ruleHashFileName(target), true) + if err := writeRuleHashFile(state, target); err != nil { + panic(fmt.Errorf("Attempting to create hash file: %s", err)) + } + return !bytes.Equal(oldSourceHash, hash) +} + +// Verify the hash of output files for a rule match the ones set on it. +func checkRuleHashes(target *core.BuildTarget, hash []byte) error { + if len(target.Hashes) == 0 { + return nil // nothing to check + } + hashStr := hex.EncodeToString(hash) + const prefix string = "sha1: " + for _, okHash := range target.Hashes { + // Allow hashes to specify the hash type initially. For now we only provide one + // hash type though. + if strings.HasPrefix(okHash, prefix) { + okHash = okHash[len(prefix):] + } + if okHash == hashStr { + return nil + } + } + return fmt.Errorf("Bad output hash for rule %s: was %s, expected one of [%s]", + target.Label, hashStr, strings.Join(target.Hashes, ", ")) +} + +func retrieveFromCache(state *core.BuildState, target *core.BuildTarget) ([]byte, bool) { + hash, err := targetHash(state, target) + if err != nil { + panic(fmt.Sprintf("Failed to calculate source hash for %s: %s", target.Label, err)) + } + return hash, (*state.Cache).Retrieve(target, hash) +} + +// Runs the post-build function for a target if it's got one. +func runPostBuildFunctionIfNeeded(tid int, state *core.BuildState, target *core.BuildTarget) { + if target.PostBuildFunction != 0 { + out := loadPostBuildOutput(state, target) + if err := parse.RunPostBuildFunction(tid, state, target, out); err != nil { + panic(err) + } + } +} + +// checkLicences checks the licences for the target match what we've accepted / rejected in the config +// and panics if they don't match. +func checkLicences(state *core.BuildState, target *core.BuildTarget) { + for _, licence := range target.Licences { + for _, reject := range state.Config.Licences.Reject { + if reject == licence { + panic(fmt.Sprintf("Target %s is licensed %s, which is explicitly rejected for this repository", target.Label, licence)) + } + } + for _, accept := range state.Config.Licences.Accept { + if accept == licence { + log.Info("Licence %s is accepted in this repository", licence) + return // Note licences are assumed to be an 'or', ie. any one of them can be accepted. + } + } + } + if len(target.Licences) > 0 && len(state.Config.Licences.Accept) > 0 { + panic(fmt.Sprintf("None of the licences for %s are accepted in this repository: %s", target.Label, strings.Join(target.Licences, ", "))) + } +} diff --git a/src/build/cc/BUILD b/src/build/cc/BUILD new file mode 100644 index 0000000000..3c761dd1ac --- /dev/null +++ b/src/build/cc/BUILD @@ -0,0 +1,100 @@ +# So far just contains tests for the C++ build rules. + +cc_embed_binary( + name = 'embedded_file_1', + src = 'embedded_file_1.txt', +) + +genrule( + name = 'embedded_file_3_gen', + outs = ['embedded_file_3.txt'], + cmd = 'echo "testing message 3" > $OUT' +) + +cc_embed_binary( + name = 'embedded_file_3', + src = ':embedded_file_3_gen', + deps = [':embedded_file_3_gen'], +) + +cc_test( + name = 'embed_file_test', + srcs = ['embed_file_test.cc'], + deps = [ + ':embedded_file_1', + ':embedded_file_3', + ], +) + +# This is a little chain of tests to exercise the cc_shared_object rule. +cc_library( + name = 'embedded_files', + srcs = ['embedded_files.cc'], + hdrs = ['embedded_files.h'], + deps = [ + ':embedded_file_1', + ':embedded_file_3', + ], +) + +cc_shared_object( + name = 'so_test', + srcs = ['so_test.cc'], + deps = [ + ':embedded_files', + ], + pkg_config_libs = ['python'], +) + +# Used by Python build code as a convenient way of testing itself. +python_library( + name = 'so_test_py', + srcs = ['__init__.py'], + resources = [':so_test'], + visibility = ['//src/build/python/...'], + zip_safe = False, +) + +python_test( + name = 'shared_object_test', + srcs = ['shared_object_test.py'], + deps = [ + ':so_test', + ], + labels = ['cc'], + zip_safe = False, +) + +# Make sure we have at least one working cc_binary rule. +cc_binary( + name = 'test_binary', + srcs = ['test_binary.cc'], + deps = [ + ':embedded_files', + ], +) + +gentest( + name = 'cc_binary_test', + data = [':test_binary'], + test_cmd = '$(exe :test_binary)', + labels = ['cc'], + no_test_output = True, +) + +# These rules implicitly test the way transitive build labels and pre-build functions +# work; these are needed for cc linker rules to apply transitively. +cc_library( + name = 'cc_fst_lib', + srcs = ['fst_lib.cc'], + hdrs = ['fst_lib.h'], + linker_flags = ['-lfst -ldl'], +) + +cc_test( + name = 'cc_fst_test', + srcs = ['fst_test.cc'], + deps = [ + ':cc_fst_lib', + ], +) diff --git a/src/build/cc/__init__.py b/src/build/cc/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/build/cc/clang/BUILD b/src/build/cc/clang/BUILD new file mode 100644 index 0000000000..1582839964 --- /dev/null +++ b/src/build/cc/clang/BUILD @@ -0,0 +1,79 @@ +# Identical set of tests to the main cc ones, but using Clang and Gold instead. +# (Note that this only controls the tools we invoke directly, not what they +# might use underneath - ie. we are not passing -fuse-ld or similar). + +package(cc_tool = 'clang++', ld_tool = 'gold') + +cc_embed_binary( + name = 'embedded_file_1', + src = 'embedded_file_1.txt', +) + +genrule( + name = 'embedded_file_3_gen', + outs = ['embedded_file_3.txt'], + cmd = 'echo "testing message 3" > $OUT' +) + +cc_embed_binary( + name = 'embedded_file_3', + src = ':embedded_file_3_gen', + deps = [':embedded_file_3_gen'], +) + +cc_test( + name = 'embed_file_test', + srcs = ['embed_file_test.cc'], + deps = [ + ':embedded_file_1', + ':embedded_file_3', + ], + labels = ['clang', 'gold'], +) + +# This is a little chain of tests to exercise the cc_shared_object rule. +cc_library( + name = 'embedded_files', + srcs = ['embedded_files.cc'], + hdrs = ['embedded_files.h'], + deps = [ + ':embedded_file_1', + ':embedded_file_3', + ], +) + +cc_shared_object( + name = 'so_test', + srcs = ['so_test.cc'], + deps = [ + ':embedded_files', + ], + pkg_config_libs = ['python'], +) + +python_test( + name = 'shared_object_test', + srcs = ['shared_object_test.py'], + deps = [ + ':so_test', + ], + labels = ['cc', 'clang', 'gold'], + zip_safe = False, +) + +# Make sure we have at least one working cc_binary rule. +cc_binary( + name = 'test_binary', + srcs = ['test_binary.cc'], + deps = [ + ':embedded_files', + ], +) + +gentest( + name = 'cc_binary_test', + data = [':test_binary'], + test_cmd = '$(exe :test_binary)', + labels = ['cc', 'clang', 'gold'], + no_test_output = True, +) diff --git a/src/build/cc/clang/embed_file_test.cc b/src/build/cc/clang/embed_file_test.cc new file mode 100644 index 0000000000..0eff3d6ffd --- /dev/null +++ b/src/build/cc/clang/embed_file_test.cc @@ -0,0 +1,25 @@ +// Basic tests for checking C++ build rules, particularly cc_embed_binary. + +#include +#include +#include "src/build/cc/clang/embedded_file_1.h" +#include "src/build/cc/clang/embedded_file_3.h" + +namespace thought_machine { + +// This is the most basic case. +TEST(EmbeddedFile1) { + CHECK_EQUAL(18, embedded_file_1_size()); + const std::string s = std::string(embedded_file_1_start(), embedded_file_1_size()); + CHECK_EQUAL("testing message 1\n", s); +} + +// This one tests the file coming from a genrule. +TEST(EmbeddedFile3) { + CHECK_EQUAL(18, embedded_file_3_size()); + const std::string s = std::string(embedded_file_3_start(), embedded_file_3_size()); + CHECK_EQUAL("testing message 3\n", s); +} + +// EmbeddedFile2 is just a myth. +} diff --git a/src/build/cc/clang/embedded_file_1.txt b/src/build/cc/clang/embedded_file_1.txt new file mode 100644 index 0000000000..8587c9416c --- /dev/null +++ b/src/build/cc/clang/embedded_file_1.txt @@ -0,0 +1 @@ +testing message 1 diff --git a/src/build/cc/clang/embedded_file_2.txt b/src/build/cc/clang/embedded_file_2.txt new file mode 100644 index 0000000000..2dfc00aaa8 --- /dev/null +++ b/src/build/cc/clang/embedded_file_2.txt @@ -0,0 +1 @@ +testing message 2 diff --git a/src/build/cc/clang/embedded_files.cc b/src/build/cc/clang/embedded_files.cc new file mode 100644 index 0000000000..7072c8dea2 --- /dev/null +++ b/src/build/cc/clang/embedded_files.cc @@ -0,0 +1,16 @@ +#include "src/build/cc/clang/embedded_files.h" + +#include "src/build/cc/clang/embedded_file_1.h" +#include "src/build/cc/clang/embedded_file_3.h" + +namespace thought_machine { + +std::string embedded_file1_contents() { + return std::string(embedded_file_1_start(), embedded_file_1_size()); +} + +std::string embedded_file3_contents() { + return std::string(embedded_file_3_start(), embedded_file_3_size()); +} + +} // namespace thought_machine diff --git a/src/build/cc/clang/embedded_files.h b/src/build/cc/clang/embedded_files.h new file mode 100644 index 0000000000..08f9bdeea6 --- /dev/null +++ b/src/build/cc/clang/embedded_files.h @@ -0,0 +1,16 @@ +// Wrapper library around the embedded files. + +#ifndef _SRC_BUILD_CC_CLANG_EMBEDDED_FILES_H +#define _SRC_BUILD_CC_CLANG_EMBEDDED_FILES_H + +#include + +namespace thought_machine { + +// Returns the contents of the two embedded files. +std::string embedded_file1_contents(); +std::string embedded_file3_contents(); + +} // namespace thought_machine + +#endif // _SRC_BUILD_CC_CLANG_EMBEDDED_FILES_H diff --git a/src/build/cc/clang/shared_object_test.py b/src/build/cc/clang/shared_object_test.py new file mode 100644 index 0000000000..1dab2e39f5 --- /dev/null +++ b/src/build/cc/clang/shared_object_test.py @@ -0,0 +1,20 @@ +"""Unit test to confirm we can load .so Python extensions.""" + +import unittest + +from src.build.cc.clang import so_test + + +class SharedObjectTest(unittest.TestCase): + + def test_file1_contents(self): + contents = so_test.get_embedded_file_1() + self.assertEqual('testing message 1\n', contents) + + def test_file3_contents(self): + contents = so_test.get_embedded_file_3() + self.assertEqual('testing message 3\n', contents) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/build/cc/clang/so_test.cc b/src/build/cc/clang/so_test.cc new file mode 100644 index 0000000000..578e831e06 --- /dev/null +++ b/src/build/cc/clang/so_test.cc @@ -0,0 +1,30 @@ +// Simple Python extension, this happens to be a handy way of testing that +// cc_shared_object actually does something useful. + +#include +#include + +#include "src/build/cc/clang/embedded_files.h" + + +namespace thought_machine { + +PyObject* get_file1(PyObject *self, PyObject *args) { + return PyString_FromString(embedded_file1_contents().c_str()); +} + +PyObject* get_file3(PyObject *self, PyObject *args) { + return PyString_FromString(embedded_file3_contents().c_str()); +} + +static PyMethodDef module_methods[] = { + {"get_embedded_file_1", get_file1, METH_VARARGS, "gets the first embedded file"}, + {"get_embedded_file_3", get_file3, METH_VARARGS, "gets the third embedded file"}, + {NULL, NULL, 0, NULL} +}; + +} // namespace thought_machine + +PyMODINIT_FUNC initso_test() { + Py_InitModule("so_test", thought_machine::module_methods); +} diff --git a/src/build/cc/clang/test_binary.cc b/src/build/cc/clang/test_binary.cc new file mode 100644 index 0000000000..7c9287c126 --- /dev/null +++ b/src/build/cc/clang/test_binary.cc @@ -0,0 +1,18 @@ +// Just a wee binary to test that we can compile one ok. + +#include + +#include "src/build/cc/clang/embedded_files.h" + + +int main(int argc, char** argv) { + using namespace thought_machine; + + if (embedded_file1_contents() != "testing message 1\n") { + return 1; + } else if (embedded_file3_contents() != "testing message 3\n") { + return 3; + } else { + return 0; + } +} diff --git a/src/build/cc/embed_file_test.cc b/src/build/cc/embed_file_test.cc new file mode 100644 index 0000000000..6f09582b5b --- /dev/null +++ b/src/build/cc/embed_file_test.cc @@ -0,0 +1,25 @@ +// Basic tests for checking C++ build rules, particularly cc_embed_binary. + +#include +#include +#include "src/build/cc/embedded_file_1.h" +#include "src/build/cc/embedded_file_3.h" + +namespace thought_machine { + +// This is the most basic case. +TEST(EmbeddedFile1) { + CHECK_EQUAL(18, embedded_file_1_size()); + const std::string s = std::string(embedded_file_1_start(), embedded_file_1_size()); + CHECK_EQUAL("testing message 1\n", s); +} + +// This one tests the file coming from a genrule. +TEST(EmbeddedFile3) { + CHECK_EQUAL(18, embedded_file_3_size()); + const std::string s = std::string(embedded_file_3_start(), embedded_file_3_size()); + CHECK_EQUAL("testing message 3\n", s); +} + +// EmbeddedFile2 is just a myth. +} diff --git a/src/build/cc/embedded_file_1.txt b/src/build/cc/embedded_file_1.txt new file mode 100644 index 0000000000..8587c9416c --- /dev/null +++ b/src/build/cc/embedded_file_1.txt @@ -0,0 +1 @@ +testing message 1 diff --git a/src/build/cc/embedded_file_2.txt b/src/build/cc/embedded_file_2.txt new file mode 100644 index 0000000000..2dfc00aaa8 --- /dev/null +++ b/src/build/cc/embedded_file_2.txt @@ -0,0 +1 @@ +testing message 2 diff --git a/src/build/cc/embedded_files.cc b/src/build/cc/embedded_files.cc new file mode 100644 index 0000000000..fadfd8201f --- /dev/null +++ b/src/build/cc/embedded_files.cc @@ -0,0 +1,16 @@ +#include "src/build/cc/embedded_files.h" + +#include "src/build/cc/embedded_file_1.h" +#include "src/build/cc/embedded_file_3.h" + +namespace thought_machine { + +std::string embedded_file1_contents() { + return std::string(embedded_file_1_start(), embedded_file_1_size()); +} + +std::string embedded_file3_contents() { + return std::string(embedded_file_3_start(), embedded_file_3_size()); +} + +} // namespace thought_machine diff --git a/src/build/cc/embedded_files.h b/src/build/cc/embedded_files.h new file mode 100644 index 0000000000..257d011a84 --- /dev/null +++ b/src/build/cc/embedded_files.h @@ -0,0 +1,16 @@ +// Wrapper library around the embedded files. + +#ifndef _SRC_BUILD_CC_EMBEDDED_FILES_H +#define _SRC_BUILD_CC_EMBEDDED_FILES_H + +#include + +namespace thought_machine { + +// Returns the contents of the two embedded files. +std::string embedded_file1_contents(); +std::string embedded_file3_contents(); + +} // namespace thought_machine + +#endif // _SRC_BUILD_CC_EMBEDDED_FILES_H diff --git a/src/build/cc/fst_lib.cc b/src/build/cc/fst_lib.cc new file mode 100644 index 0000000000..8688122e3f --- /dev/null +++ b/src/build/cc/fst_lib.cc @@ -0,0 +1,12 @@ +#include +#include "src/build/cc/fst_lib.h" + +namespace thought_machine { + +std::string VectorFstType() { + typedef fst::VectorFst VectorFst; + auto transducer = VectorFst(); + return transducer.Type(); +} + +} // namespace thought_machine diff --git a/src/build/cc/fst_lib.h b/src/build/cc/fst_lib.h new file mode 100644 index 0000000000..adc5175440 --- /dev/null +++ b/src/build/cc/fst_lib.h @@ -0,0 +1,15 @@ +// Test library for transitive linker flags. + +#ifndef _SRC_BUILD_CC_FST_LIB_H +#define _SRC_BUILD_CC_FST_LIB_H + +#include + +namespace thought_machine { + +// Returns the type description of a VectorFst. +std::string VectorFstType(); + +} // namespace thought_machine + +#endif // _SRC_BUILD_CC_FST_LIB_H diff --git a/src/build/cc/fst_test.cc b/src/build/cc/fst_test.cc new file mode 100644 index 0000000000..cda9e52895 --- /dev/null +++ b/src/build/cc/fst_test.cc @@ -0,0 +1,12 @@ +// Test for exercising transitive linker rules. + +#include +#include "src/build/cc/fst_lib.h" + +namespace thought_machine { + +TEST(FstTypeIsAsExpected) { + CHECK_EQUAL("vector", VectorFstType()); +} + +} diff --git a/src/build/cc/shared_object_test.py b/src/build/cc/shared_object_test.py new file mode 100644 index 0000000000..ec134b63ae --- /dev/null +++ b/src/build/cc/shared_object_test.py @@ -0,0 +1,20 @@ +"""Unit test to confirm we can load .so Python extensions.""" + +import unittest + +from src.build.cc import so_test + + +class SharedObjectTest(unittest.TestCase): + + def test_file1_contents(self): + contents = so_test.get_embedded_file_1() + self.assertEqual('testing message 1\n', contents) + + def test_file3_contents(self): + contents = so_test.get_embedded_file_3() + self.assertEqual('testing message 3\n', contents) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/build/cc/so_test.cc b/src/build/cc/so_test.cc new file mode 100644 index 0000000000..3f189dc607 --- /dev/null +++ b/src/build/cc/so_test.cc @@ -0,0 +1,67 @@ +// Simple Python extension, this happens to be a handy way of testing that +// cc_shared_object actually does something useful. + +#include +#include + +#include "src/build/cc/embedded_files.h" + + +namespace thought_machine { + +PyObject* get_file1(PyObject *self, PyObject *args) { + return PyUnicode_FromString(embedded_file1_contents().c_str()); +} + +PyObject* get_file3(PyObject *self, PyObject *args) { + return PyUnicode_FromString(embedded_file3_contents().c_str()); +} + +static PyMethodDef so_test_methods[] = { + {"get_embedded_file_1", get_file1, METH_VARARGS, "gets the first embedded file"}, + {"get_embedded_file_3", get_file3, METH_VARARGS, "gets the third embedded file"}, + {NULL, NULL, 0, NULL} +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) + +struct module_state { + PyObject *error; +}; + +static int so_test_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int so_test_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef so_test_def = { + PyModuleDef_HEAD_INIT, + "so_test", + NULL, + sizeof(struct module_state), + so_test_methods, + NULL, + so_test_traverse, + so_test_clear, + NULL +}; + +#endif // PY_MAJOR_VERSION >= 3 + +} // namespace thought_machine + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit_so_test() { + return PyModule_Create(&thought_machine::so_test_def); +} +#else +PyMODINIT_FUNC initso_test() { + Py_InitModule("so_test", thought_machine::so_test_methods); +} +#endif diff --git a/src/build/cc/test_binary.cc b/src/build/cc/test_binary.cc new file mode 100644 index 0000000000..ff3f1d7b41 --- /dev/null +++ b/src/build/cc/test_binary.cc @@ -0,0 +1,18 @@ +// Just a wee binary to test that we can compile one ok. + +#include + +#include "src/build/cc/embedded_files.h" + + +int main(int argc, char** argv) { + using namespace thought_machine; + + if (embedded_file1_contents() != "testing message 1\n") { + return 1; + } else if (embedded_file3_contents() != "testing message 3\n") { + return 3; + } else { + return 0; + } +} diff --git a/src/build/command_replacements.go b/src/build/command_replacements.go new file mode 100644 index 0000000000..8fd08b0ae6 --- /dev/null +++ b/src/build/command_replacements.go @@ -0,0 +1,188 @@ +// Replacement of sequences in genrule commands. +// +// Genrules can contain certain replacement variables which Please substitutes +// with locations of the actual thing before running. +// The following replacements are currently made: +// +// $(location //path/to:target) +// Expands to the output of the given build rule. The rule can only have one +// output (use $locations if there are multiple). +// +// $(locations //path/to:target) +// Expands to all the outputs (space separated) of the given build rule. +// Equivalent to $(location ...) for rules with a single output. +// +// $(exe //path/to:target) +// Expands to a command to run the output of the given target. For example, +// java -jar plz-out/bin/path/to/target.jar. +// The rule must be tagged as 'binary'. +// +// $(dir //path/to:target) +// Expands to the package directory containing the outputs of the given target. +// Useful for rules that have multiple outputs where you only need to know +// what directory they're in. +// +// $(out_location //path/to:target) +// Expands to a path to the output of the given target, with the preceding plz-out/gen +// or plz-out/bin etc. Useful when these things will be run by a user. +// +// $(location_pairs //path/to:target) +// Expands to pairs of absolute and relative paths for all the outputs of +// the given build rule. Relative paths are relative to their package, so a +// rule in package //d/e with outputs = ['a.txt', 'b/c.txt'] would receive +// '/plz-out/gen/d/e/a.txt a.txt /plz-out/gen/d/e/b/c.txt b/c.txt' from this substitution. +// This is a fairly specific one used mostly by filegroups. +// +// In general it's a good idea to use these where possible in genrules rather than +// hardcoding specific paths. + +package build + +import ( + "fmt" + "path" + "path/filepath" + "regexp" + "strings" + + "core" +) + +var locationReplacement = regexp.MustCompile("\\$\\(location ([^\\)]+)\\)") +var locationsReplacement = regexp.MustCompile("\\$\\(locations ([^\\)]+)\\)") +var exeReplacement = regexp.MustCompile("\\$\\(exe ([^\\)]+)\\)") +var outReplacement = regexp.MustCompile("\\$\\(out_location ([^\\)]+)\\)") +var dirReplacement = regexp.MustCompile("\\$\\(dir ([^\\)]+)\\)") +var locationPairsReplacement = regexp.MustCompile("\\$\\(location_pairs ([^\\)]+)\\)") + +// Replace escape sequences in the target's command. +// For example, $(location :blah) -> the output of rule blah. +func replaceSequences(target *core.BuildTarget) string { + return ReplaceSequences(target, target.Command) +} + +// Replace escape sequences in the given string. +func ReplaceSequences(target *core.BuildTarget, command string) string { + return replaceSequencesInternal(target, command, false) +} + +// Replace escape sequences in the given string when running a test. +func ReplaceTestSequences(target *core.BuildTarget, command string) string { + return replaceSequencesInternal(target, command, true) +} + +func replaceSequencesInternal(target *core.BuildTarget, command string, test bool) string { + cmd := locationReplacement.ReplaceAllStringFunc(command, func(in string) string { + return replaceSequence(target, in[11:len(in)-1], false, false, false, false, false, test) + }) + cmd = locationsReplacement.ReplaceAllStringFunc(cmd, func(in string) string { + return replaceSequence(target, in[12:len(in)-1], false, true, false, false, false, test) + }) + cmd = exeReplacement.ReplaceAllStringFunc(cmd, func(in string) string { + return replaceSequence(target, in[6:len(in)-1], true, false, false, false, false, test) + }) + cmd = outReplacement.ReplaceAllStringFunc(cmd, func(in string) string { + return replaceSequence(target, in[15:len(in)-1], false, false, false, false, true, test) + }) + cmd = dirReplacement.ReplaceAllStringFunc(cmd, func(in string) string { + return replaceSequence(target, in[6:len(in)-1], false, true, false, true, false, test) + }) + cmd = locationPairsReplacement.ReplaceAllStringFunc(cmd, func(in string) string { + return replaceSequence(target, in[17:len(in)-1], false, true, true, false, false, test) + }) + // TODO(pebers): We should check for this when doing matches above, but not easy in + // Go since its regular expressions are actually regular and principled. + return strings.Replace(cmd, "\\$", "$", -1) +} + +// Replaces a single escape sequence in a command. +func replaceSequence(target *core.BuildTarget, in string, runnable, multiple, pairs, dir, outPrefix, test bool) string { + if core.LooksLikeABuildLabel(in) { + label, file := core.ParseBuildFileLabel(in, target.Label.PackageName) + return replaceSequenceLabel(target, label, file, in, runnable, multiple, pairs, dir, outPrefix, test, true) + } + for src := range target.AllSources() { + if label := src.Label(); label != nil && src.String() == in { + return replaceSequenceLabel(target, *label, "", in, runnable, multiple, pairs, dir, outPrefix, test, false) + } + } + if pairs { + return quote(path.Join(core.RepoRoot, target.Label.PackageName, in)) + " " + quote(in) + } else { + return quote(path.Join(target.Label.PackageName, in)) + } +} + +func replaceSequenceLabel(target *core.BuildTarget, label core.BuildLabel, file, in string, runnable, multiple, pairs, dir, outPrefix, test, allOutputs bool) string { + // Check this label is a dependency of the target, otherwise it's not allowed. + if label == target.Label { // targets can always use themselves. + return checkAndReplaceSequence(target, target, file, in, runnable, multiple, pairs, dir, outPrefix, test, allOutputs, false) + } + for _, dep := range target.Dependencies { + if dep.Label == label { + return checkAndReplaceSequence(target, dep, file, in, runnable, multiple, pairs, dir, outPrefix, test, allOutputs, target.IsTool(label)) + } + } + panic(fmt.Sprintf("Rule %s can't use %s; doesn't depend on target %s", target.Label, in, label)) +} + +func checkAndReplaceSequence(target, dep *core.BuildTarget, file, in string, runnable, multiple, pairs, dir, outPrefix, test, allOutputs, tool bool) string { + if allOutputs && !multiple && len(dep.Outputs()) != 1 { + // Label must have only one output. + panic(fmt.Sprintf("Rule %s can't use %s; %s has multiple outputs.", target.Label, in, dep.Label)) + } else if runnable && !dep.IsBinary { + panic(fmt.Sprintf("Rule %s can't $(exe %s), it's not executable", target.Label, dep.Label)) + } else if runnable && len(dep.Outputs()) == 0 { + panic(fmt.Sprintf("Rule %s is tagged as binary but produces no output.", dep.Label)) + } + output := "" + for _, out := range dep.Outputs() { + if file != "" && file != out { + continue + } + if allOutputs || out == in { + if pairs { + output += quote(path.Join(core.RepoRoot, dep.OutDir(), out)) + " " + quote(out) + " " + } else if tool { + abs, err := filepath.Abs(handleDir(dep.OutDir(), out, dir)) + if err != nil { + log.Fatalf("Couldn't calculate relative path: %s", err) + } + output += quote(abs) + " " + if dir { + break + } + } else { + output += quote(fileDestination(target, dep, out, dir, outPrefix, test)) + " " + } + } + } + return strings.TrimRight(output, " ") +} + +func fileDestination(target, dep *core.BuildTarget, out string, dir, outPrefix, test bool) string { + if outPrefix { + return handleDir(dep.OutDir(), out, dir) + } + if test && target == dep { + // Slightly fiddly case because tests put binaries in a possibly slightly unusual place. + return "./" + out + } + return handleDir(dep.Label.PackageName, out, dir) +} + +// Encloses the given string in quotes if needed. +func quote(s string) string { + if strings.ContainsAny(s, "|&;()<>") { + return "\"" + s + "\"" + } + return s +} + +// handleDir chooses either the out dir or the actual output location depending on the 'dir' flag. +func handleDir(outDir, output string, dir bool) string { + if dir { + return outDir + } + return path.Join(outDir, output) +} diff --git a/src/build/command_replacements_test.go b/src/build/command_replacements_test.go new file mode 100644 index 0000000000..6a2143969a --- /dev/null +++ b/src/build/command_replacements_test.go @@ -0,0 +1,159 @@ +// Tests the command replacement functionality. + +package build + +import ( + "os" + "path" + "testing" + + "core" +) + +func TestLocation(t *testing.T) { + target2 := makeTarget("//path/to:target2", "", nil) + target1 := makeTarget("//path/to:target1", "ln -s $(location //path/to:target2) ${OUT}", target2) + + expected := "ln -s path/to/target2.py ${OUT}" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestLocations(t *testing.T) { + target2 := makeTarget("//path/to:target2", "", nil) + target2.AddOutput("target2_other.py") + target1 := makeTarget("//path/to:target1", "cat $(locations //path/to:target2) > ${OUT}", target2) + + expected := "cat path/to/target2.py path/to/target2_other.py > ${OUT}" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestExe(t *testing.T) { + target2 := makeTarget("//path/to:target2", "", nil) + target2.IsBinary = true + target1 := makeTarget("//path/to:target1", "$(exe //path/to:target2) -o ${OUT}", target2) + + expected := "path/to/target2.py -o ${OUT}" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestLocationPairs(t *testing.T) { + core.RepoRoot = "/home/user/repo" + target2 := makeTarget("//path/to:target2", "", nil) + target1 := makeTarget("//path/to:target1", "$(location_pairs //path/to:target2)", target2) + expected := "/home/user/repo/plz-out/gen/path/to/target2.py target2.py" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestLocationPairsLocalFile(t *testing.T) { + core.RepoRoot = "/home/user/repo" + target1 := makeTarget("//path/to:target1", "$(location_pairs target1.py)", nil) + expected := "/home/user/repo/path/to/target1.py target1.py" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestPartialOutput(t *testing.T) { + // Second rule uses only one file from first one. + target2 := makeTarget("//path/to:target2", "", nil) + target2.AddOutput("test.py") + target1 := makeTarget("//path/to:target1", "ln -s $(location test.py) ${OUT}", target2) + target1.Sources = append(target1.Sources, core.BuildFileLabel{File: "test.py", BuildLabel: target2.Label}) + + expected := "ln -s path/to/test.py ${OUT}" + cmd := replaceSequences(target1) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestReplacementsForTest(t *testing.T) { + target2 := makeTarget("//path/to:target2", "", nil) + target1 := makeTarget("//path/to:target1", "$(exe //path/to:target1) $(location //path/to:target2)", target2) + target1.IsBinary = true + target1.IsTest = true + + expected := "./target1.py path/to/target2.py" + cmd := ReplaceTestSequences(target1, target1.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestDataReplacementForTest(t *testing.T) { + target := makeTarget("//path/to:target1", "cat $(location test_data.txt)", nil) + target.Data = append(target.Data, core.FileLabel{File: "test_data.txt", Package: "path/to"}) + + expected := "cat path/to/test_data.txt" + cmd := ReplaceTestSequences(target, target.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestAmpersandReplacement(t *testing.T) { + target := makeTarget("//path/to:target1", "cat $(location b&b.txt)", nil) + expected := "cat \"path/to/b&b.txt\"" + cmd := ReplaceSequences(target, target.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestToolReplacement(t *testing.T) { + target2 := makeTarget("//path/to:target2", "blah", nil) + target1 := makeTarget("//path/to:target1", "$(location //path/to:target2)", target2) + target1.Tools = append(target1.Tools, target2.Label) + + expected := quote(path.Join(os.Getenv("TEST_DIR"), "plz-out/gen/path/to/target2.py")) + cmd := ReplaceSequences(target1, target1.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestDirReplacement(t *testing.T) { + target2 := makeTarget("//path/to:target2", "blah", nil) + target1 := makeTarget("//path/to:target1", "$(dir //path/to:target2)", target2) + + expected := "path/to" + cmd := ReplaceSequences(target1, target1.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func TestToolDirReplacement(t *testing.T) { + target2 := makeTarget("//path/to:target2", "blah", nil) + target1 := makeTarget("//path/to:target1", "$(dir //path/to:target2)", target2) + target1.Tools = append(target1.Tools, target2.Label) + + expected := quote(path.Join(os.Getenv("TEST_DIR"), "plz-out/gen/path/to")) + cmd := ReplaceSequences(target1, target1.Command) + if cmd != expected { + t.Errorf("Replacement sequence not as expected; is %s, should be %s", cmd, expected) + } +} + +func makeTarget(name string, command string, dep *core.BuildTarget) *core.BuildTarget { + target := core.NewBuildTarget(core.ParseBuildLabel(name, "")) + target.Command = command + target.AddOutput(target.Label.Name + ".py") + if dep != nil { + target.Dependencies = append(target.Dependencies, dep) + } + return target +} diff --git a/src/build/incrementality.go b/src/build/incrementality.go new file mode 100644 index 0000000000..87f3653a82 --- /dev/null +++ b/src/build/incrementality.go @@ -0,0 +1,423 @@ +// Utilities to help with incremental builds. +// +// There are four things we consider for each rule: +// - the global config, any change to which invalidates artifacts +// (it's too hard to work out which bits affect which rules) +// - the rule definition itself (the command to run, etc) +// - any input files it might have +// - any dependencies. +// +// If all of those are the same as the last time the rule was run, +// we can safely assume that the output will be the same this time +// and so we don't have to re-run it again. + +package build + +import ( + "bytes" + "crypto/sha1" + "encoding/base64" + "encoding/gob" + "fmt" + "hash" + "io" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "sync" + + "core" +) + +const hashLength = sha1.Size + +// Length of the hash file we write +const hashFileLength = 4 * hashLength + +// Used to write something when we need to indicate a boolean in a hash. Can be essentially +// any value as long as they're different from one another. +var boolTrueHashValue = []byte{2} +var boolFalseHashValue = []byte{1} + +// Return true if the rule needs building, false if the existing outputs are OK. +func needsBuilding(state *core.BuildState, target *core.BuildTarget, postBuild bool) bool { + // Check the dependencies first, because they don't need any disk I/O. + if target.NeedsTransitiveDependencies { + if anyDependencyHasChanged(target) { + return true // one of the transitive deps has changed, need to rebuild + } + } else { + for _, dep := range target.Dependencies { + if dep.State() < core.Unchanged { + log.Debug("Need to rebuild %s, %s has changed", target.Label, dep.Label) + return true // dependency has just been rebuilt, do this too. + } + } + } + oldRuleHash, oldConfigHash, oldSourceHash := readRuleHashFile(ruleHashFileName(target), postBuild) + if !bytes.Equal(oldConfigHash, state.Hashes.Config) { + log.Debug("Need to rebuild %s, config has changed (was %s, need %s)", target.Label, b64(oldConfigHash), b64(state.Hashes.Config)) + return true + } + newRuleHash := RuleHash(target, false, postBuild) + if !bytes.Equal(oldRuleHash, newRuleHash) { + log.Debug("Need to rebuild %s, rule has changed (was %s, need %s)", target.Label, b64(oldRuleHash), b64(newRuleHash)) + return true + } + newSourceHash, err := sourceHash(state.Graph, target) + if err != nil || !bytes.Equal(oldSourceHash, newSourceHash) { + log.Debug("Need to rebuild %s, sources have changed (was %s, need %s)", target.Label, b64(oldSourceHash), b64(newSourceHash)) + return true + } + // Check the outputs of this rule exist. This would only happen if the user had + // removed them but it's incredibly aggravating if you remove an output and the + // rule won't rebuild itself. + for _, output := range target.Outputs() { + realOutput := path.Join(target.OutDir(), output) + if !core.PathExists(realOutput) { + log.Debug("Output %s doesn't exist for rule %s; will rebuild.", realOutput, target.Label) + return true + } + } + return false // \o/ +} + +// b64 base64 encodes a string of bytes for printing. +func b64(b []byte) string { + if len(b) == 0 { + return "" + } + return base64.RawStdEncoding.EncodeToString(b) +} + +// Returns true if any transitive dependency of this target has changed. +func anyDependencyHasChanged(target *core.BuildTarget) bool { + done := map[core.BuildLabel]bool{} + var inner func(*core.BuildTarget) bool + inner = func(dependency *core.BuildTarget) bool { + done[dependency.Label] = true + if dependency != target && dependency.State() < core.Unchanged { + return true + } else if !dependency.OutputIsComplete || dependency == target { + for _, dep := range dependency.Dependencies { + if !done[dep.Label] { + if inner(dep) { + log.Debug("Need to rebuild %s, %s has changed", target.Label, dep.Label) + return true + } + } + } + } + return false + } + return inner(target) +} + +// Calculate the hash of all sources of this rule +func sourceHash(graph *core.BuildGraph, target *core.BuildTarget) ([]byte, error) { + h := sha1.New() + for source := range core.IterSources(graph, target, true) { + result, err := pathHash(source.Src) + if err != nil { + return result, err + } + h.Write(result) + } + // Note that really it would be more correct to hash the outputs of these rules + // in the same way we calculate a hash of sources for the rule, but that is + // impractical for some cases (notably npm) where tools can be very large. + // Instead we assume calculating the target hash is sufficient. + for _, tool := range target.Tools { + h.Write(mustTargetHash(core.State, graph.TargetOrDie(tool))) + } + return h.Sum(nil), nil +} + +// Used to memoize the results of pathHash so we don't hash the same files multiple times. +var pathHashMemoizer = map[string][]byte{} +var pathHashMutex sync.RWMutex // Of course it will be accessed concurrently. + +// Calculate the hash of a single path which might be a file or a directory +// This is the memoized form that only hashes each path once. +func pathHash(path string) ([]byte, error) { + pathHashMutex.RLock() + cached, present := pathHashMemoizer[path] + pathHashMutex.RUnlock() + if present { + return cached, nil + } + result, err := pathHashImpl(path) + if err == nil { + pathHashMutex.Lock() + pathHashMemoizer[path] = result + pathHashMutex.Unlock() + } + return result, err +} + +func pathHashImpl(path string) ([]byte, error) { + h := sha1.New() + info, err := os.Lstat(path) + if err == nil && info.Mode()&os.ModeSymlink != 0 { + // Dereference symlink and try again + deref, err := filepath.EvalSymlinks(path) + if err != nil { + return nil, err + } + // Write something indicating this was a link; important so we rebuild correctly + // when eg. a filegroup is changed from link=False to link=True. + // Don't want to hash all file mode bits, the others could change depending on + // whether we retrieved from cache or not so they're probably a bit too fragile. + h.Write(boolTrueHashValue) + d, err := pathHashImpl(deref) + h.Write(d) + return h.Sum(nil), err + } + if err == nil && info.IsDir() { + err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if !info.IsDir() { + return fileHash(&h, path) + } else { + return nil + } + }) + } else { + err = fileHash(&h, path) // let this handle any other errors + } + return h.Sum(nil), err +} + +// Used when we move files from tmp to out and there was one there before; that's +// the only case in which the hash of a filepath could change. +func movePathHash(oldPath, newPath string) { + pathHashMutex.Lock() + pathHashMemoizer[newPath] = pathHashMemoizer[oldPath] + pathHashMutex.Unlock() +} + +// Calculate the hash of a single file +func fileHash(h *hash.Hash, filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(*h, file) + return err +} + +// RuleHash calculates a hash for the relevant bits of this rule that affect its output. +// Optionally it can include parts of the rule that affect runtime (most obviously test-time). +// Note that we have to hash on the declared fields, we obviously can't hash pointers etc. +// incrementality_test will warn if new fields are added to the struct but not here. +func RuleHash(target *core.BuildTarget, runtime, postBuild bool) []byte { + if runtime || (postBuild && target.PostBuildFunction != 0) { + return ruleHash(target, runtime) + } + // Non-post-build hashes get stored on the target itself. + if len(target.RuleHash) != 0 { + return target.RuleHash + } + target.RuleHash = ruleHash(target, false) // This is never a runtime hash. + return target.RuleHash +} + +func ruleHash(target *core.BuildTarget, runtime bool) []byte { + h := sha1.New() + h.Write([]byte(target.Label.String())) + for _, dep := range target.DeclaredDependencies { + h.Write([]byte(dep.String())) + } + for _, vis := range target.Visibility { + h.Write([]byte(vis.String())) // Doesn't strictly affect the output, but best to be safe. + } + for _, hsh := range target.Hashes { + h.Write([]byte(hsh)) + } + for source := range target.AllSources() { + h.Write([]byte(source.String())) + } + for _, out := range target.DeclaredOutputs() { + h.Write([]byte(out)) + } + for _, licence := range target.Licences { + h.Write([]byte(licence)) + } + for _, output := range target.TestOutputs { + h.Write([]byte(output)) + } + for _, label := range target.Labels { + h.Write([]byte(label)) + } + hashBool(h, target.IsBinary) + hashBool(h, target.IsTest) + h.Write([]byte(target.Command)) + + if runtime { + h.Write([]byte(target.TestCommand)) + for _, datum := range target.Data { + h.Write([]byte(datum.String())) + } + hashBool(h, target.Containerise) + if target.ContainerSettings != nil { + e := gob.NewEncoder(h) + if err := e.Encode(target.ContainerSettings); err != nil { + panic(err) + } + } + if target.Containerise { + h.Write(core.State.Hashes.Containerisation) + } + } + + hashBool(h, target.NeedsTransitiveDependencies) + hashBool(h, target.OutputIsComplete) + for _, require := range target.Requires { + h.Write([]byte(require)) + } + // Indeterminate iteration order, yay... + languages := []string{} + for k := range target.Provides { + languages = append(languages, k) + } + sort.Strings(languages) + for _, lang := range languages { + h.Write([]byte(lang)) + h.Write([]byte(target.Provides[lang].String())) + } + // Obviously we don't include the code pointer because it's a pointer. + h.Write(target.PreBuildHash) + h.Write(target.PostBuildHash) + return h.Sum(nil) +} + +func hashBool(writer hash.Hash, b bool) { + if b { + writer.Write(boolTrueHashValue) + } else { + writer.Write(boolFalseHashValue) + } +} + +// readRuleHashFile reads the contents of a rule hash file into separate byte arrays +// Arrays will be empty if there's an error reading the file. +// If postBuild is true then the rule hash will be the post-build one if present. +func readRuleHashFile(filename string, postBuild bool) ([]byte, []byte, []byte) { + contents := make([]byte, hashFileLength, hashFileLength) + file, err := os.Open(filename) + if err != nil { + if !os.IsNotExist(err) { + log.Warning("Failed to read rule hash file %s: %s", filename, err) + } + return []byte{}, []byte{}, []byte{} + } + defer file.Close() + if n, err := file.Read(contents); err != nil { + log.Warning("Error reading rule hash file %s: %s", filename, err) + return []byte{}, []byte{}, []byte{} + } else if n != hashFileLength { + // TODO(pebers): Uncomment once we've all moved to v1.4, until then it will produce + // many annoying pointless warnings. + //log.Warning("Unexpected rule hash file length: expected %d bytes, was %d", hashFileLength, n) + return []byte{}, []byte{}, []byte{} + } + if postBuild { + return contents[hashLength : 2*hashLength], contents[2*hashLength : 3*hashLength], contents[3*hashLength : hashFileLength] + } + return contents[0:hashLength], contents[2*hashLength : 3*hashLength], contents[3*hashLength : hashFileLength] +} + +// Writes the contents of the rule hash file +func writeRuleHashFile(state *core.BuildState, target *core.BuildTarget) error { + hash, err := targetHash(state, target) + if err != nil { + return err + } + file, err := os.Create(ruleHashFileName(target)) + if err != nil { + return err + } + defer file.Close() + n, err := file.Write(hash) + if err != nil { + return err + } else if n != hashFileLength { + return fmt.Errorf("Wrote %d bytes to rule hash file; should be %d", n, hashFileLength) + } + return nil +} + +// Returns the filename we'll store the hashes for this file in. +func ruleHashFileName(target *core.BuildTarget) string { + return path.Join(target.OutDir(), ".rule_hash_"+target.Label.Name) +} + +func postBuildOutputFileName(target *core.BuildTarget) string { + return path.Join(target.OutDir(), core.PostBuildOutputFileName(target)) +} + +// For targets that have post-build functions, we have to store and retrieve the target's +// output to feed to it +func loadPostBuildOutput(state *core.BuildState, target *core.BuildTarget) string { + out, err := ioutil.ReadFile(postBuildOutputFileName(target)) + if err != nil { + panic(err) + } + return string(out) +} + +func storePostBuildOutput(state *core.BuildState, target *core.BuildTarget, out []byte) { + filename := postBuildOutputFileName(target) + if err := os.RemoveAll(filename); err != nil { + panic(err) + } + if err := ioutil.WriteFile(filename, out, 0644); err != nil { + panic(err) + } +} + +// targetHash returns the hash for a target and any error encountered while calculating it. +func targetHash(state *core.BuildState, target *core.BuildTarget) ([]byte, error) { + hash := append(RuleHash(target, false, false), RuleHash(target, false, true)...) + hash = append(hash, state.Hashes.Config...) + hash2, err := sourceHash(state.Graph, target) + if err != nil { + return []byte{}, err + } + return append(hash, hash2...), nil +} + +// mustTargetHash returns the hash for a target and panics if it can't be calculated. +func mustTargetHash(state *core.BuildState, target *core.BuildTarget) []byte { + hash, err := targetHash(state, target) + if err != nil { + panic(err) + } + return hash +} + +// RuntimeHash returns the target hash, source hash, config hash & runtime file hash, +// all rolled into one. Essentially this is one hash needed to determine if the runtime +// state is consistent. +func RuntimeHash(state *core.BuildState, target *core.BuildTarget) ([]byte, error) { + hash := append(RuleHash(target, true, false), RuleHash(target, true, true)...) + hash = append(hash, state.Hashes.Config...) + sh, err := sourceHash(state.Graph, target) + if err != nil { + return []byte{}, err + } + h := sha1.New() + h.Write(sh) + for source := range core.IterRuntimeFiles(state.Graph, target, true) { + result, err := pathHash(source.Src) + if err != nil { + return result, err + } + h.Write(result) + } + return append(hash, h.Sum(nil)...), nil +} diff --git a/src/build/incrementality_test.go b/src/build/incrementality_test.go new file mode 100644 index 0000000000..8a68fb6431 --- /dev/null +++ b/src/build/incrementality_test.go @@ -0,0 +1,80 @@ +// Test to make sure that every field in BuildTarget has been thought of +// in the rule hash calculation. +// Not every field necessarily needs to be hashed there (and indeed not +// all should be), this is just a guard against adding new fields and +// forgetting to update that function. + +package build + +import ( + "reflect" + "testing" + + "core" +) + +var KnownFields = map[string]bool{ + // These fields are explicitly hashed. + "Label": true, + "DeclaredDependencies": true, + "Hashes": true, + "Sources": true, + "NamedSources": true, + "IsBinary": true, + "IsTest": true, + "Command": true, + "TestCommand": true, + "NeedsTransitiveDependencies": true, + "OutputIsComplete": true, + "Requires": true, + "Provides": true, + "PreBuildFunction": true, + "PostBuildFunction": true, + "PreBuildHash": true, + "PostBuildHash": true, + "outputs": true, + "Licences": true, + "Tools": true, + "TestOutputs": true, + + // These only contribute to the runtime hash, not at build time. + "Data": true, + "Containerise": true, + "ContainerSettings": true, + + // These would ideally not contribute to the hash, but we need that at present + // because we don't have a good way to force a recheck of its reverse dependencies. + "Visibility": true, + "TestOnly": true, + "Labels": true, + + // These fields we have thought about and decided that they shouldn't contribute to the + // hash because they don't affect the actual output of the target. + "Flakiness": true, + "NoTestOutput": true, + "SkipCache": true, + "BuildTimeout": true, + "TestTimeout": true, + "state": true, + "Results": true, // Recall that unsuccessful test results aren't cached... + "BuildingDescription": true, + + // Used to save the rule hash rather than actually being hashed itself. + "RuleHash": true, + + // Covered sufficiently by DeclaredDependencies + "ExportedDependencies": true, + "Dependencies": true, + "resolvedDependencies": true, +} + +func TestAllFieldsArePresentAndAccountedFor(t *testing.T) { + target := core.BuildTarget{} + val := reflect.ValueOf(target) + for i := 0; i < val.Type().NumField(); i++ { + field := val.Type().Field(i) + if !KnownFields[field.Name] { + t.Errorf("Unaccounted field in 'query print': %s", field.Name) + } + } +} diff --git a/src/build/java/BUILD b/src/build/java/BUILD new file mode 100644 index 0000000000..d4f6858edc --- /dev/null +++ b/src/build/java/BUILD @@ -0,0 +1,46 @@ +java_binary( + name = 'junit_runner', + main_class = 'net.thoughtmachine.please.test.TestMain', + deps = [ + '//src/build/java/net/thoughtmachine/please/test:junit_runner', + ], + visibility = ['PUBLIC'] +) + +go_library( + name = 'java', + srcs = ['zip_writer.go'], + deps = [ + '//third_party/go:logging', + '//third_party/go/src/zip', + ], +) + +go_binary( + name = 'jarcat', + deps = [ + ':java', + '//src/output', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_binary( + name = 'please_maven', + deps = [ + '//src/output', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'zip_writer_test', + srcs = ['zip_writer_test.go'], + deps = [ + ':java', + '//third_party/go/src/zip', + ], + data = glob(['test_data/*.zip']), +) diff --git a/src/build/java/jarcat.go b/src/build/java/jarcat.go new file mode 100644 index 0000000000..7af38d01e4 --- /dev/null +++ b/src/build/java/jarcat.go @@ -0,0 +1,113 @@ +// Small program to merge lots of .jar files into one. +// Currently walks the entire of the current directory finding all .jar files beneath it +// and merges them all into one. Later we might add additional flags to exclude certain +// files etc. + +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "zip" + + "github.com/op/go-logging" + + "java" + "output" +) + +var log = logging.MustGetLogger("jarcat") + +func combine(out, in, suffix, excludeSuffix, preamble, mainClass, excludeInternalPrefix string, strict, includeOther, addInitPy bool) error { + f, err := os.Create(out) + if err != nil { + return err + } + defer f.Close() + + w := zip.NewWriter(f) + defer w.Close() + defer java.HandleConcatenatedFiles(w) + + if preamble != "" { + if err := w.WritePreamble(preamble + "\n"); err != nil { + return nil + } + } + + excludeInternalPrefixes := strings.Split(excludeInternalPrefix, ",") + if excludeInternalPrefix == "" { + excludeInternalPrefixes = []string{} + } + + var walkFunc func(path string, info os.FileInfo, err error) error + walkFunc = func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if path != in && (info.Mode()&os.ModeSymlink) != 0 { + if resolved, err := filepath.EvalSymlinks(path); err != nil { + return err + } else if stat, err := os.Stat(resolved); err != nil { + return err + } else if stat.IsDir() { + return filepath.Walk(resolved, walkFunc) + } + } + if path != out && !info.IsDir() { + if excludeSuffix == "" || !strings.HasSuffix(path, excludeSuffix) { + if strings.HasSuffix(path, suffix) { + log.Debug("Adding zip file %s", path) + if err := java.AddZipFile(w, path, excludeInternalPrefixes, []string{}, strict); err != nil { + return fmt.Errorf("Error adding %s to zipfile: %s", path, err) + } + } else if includeOther && !java.HasExistingFile(w, path) { + log.Debug("Including existing non-zip file %s", path) + if b, err := ioutil.ReadFile(path); err != nil { + return fmt.Errorf("Error reading %s to zipfile: %s", path, err) + } else if err = java.WriteFile(w, path, b); err != nil { + return err + } + } + } + } + return nil + } + if err := filepath.Walk(in, walkFunc); err != nil { + return err + } + if mainClass != "" { + if err := java.AddManifest(w, mainClass); err != nil { + return err + } + } + if addInitPy { + return java.AddInitPyFiles(w) + } + return nil +} + +var opts struct { + Out string `short:"o" long:"output" description:"Output filename" required:"true"` + In string `short:"i" long:"input" description:"Input directory" required:"true"` + Suffix string `short:"s" long:"suffix" default:".jar" description:"Suffix of files to include"` + ExcludeSuffix string `short:"e" long:"exclude_suffix" default:"src.jar" description:"Suffix of files to exclude"` + ExcludeInternalPrefix string `long:"exclude_internal_prefix" description:"Prefix of files to exclude"` + Preamble string `short:"p" long:"preamble" description:"Leading string to prepend to written zip file"` + MainClass string `short:"m" long:"main_class" description:"Write a Java manifest file containing the given main class."` + Verbosity int `short:"v" long:"verbose" default:"1" description:"Verbosity of output (higher number = more output, default 1 -> warnings and errors only)"` + Strict bool `long:"strict" default:"false" description:"Disallow duplicate files"` + IncludeOther bool `long:"include_other" default:"false" description:"Add files that are not jar files as well"` + AddInitPy bool `long:"add_init_py" default:"false" description:"Adds __init__.py files to all directories"` +} + +func main() { + output.ParseFlagsOrDie("Jarcat", &opts) + output.InitLogging(opts.Verbosity, "", 0) + if err := combine(opts.Out, opts.In, opts.Suffix, opts.ExcludeSuffix, opts.Preamble, opts.MainClass, opts.ExcludeInternalPrefix, opts.Strict, opts.IncludeOther, opts.AddInitPy); err != nil { + log.Fatalf("Error combining zip files: %s\n", err) + } + os.Exit(0) +} diff --git a/src/build/java/net/thoughtmachine/please/test/BUILD b/src/build/java/net/thoughtmachine/please/test/BUILD new file mode 100644 index 0000000000..1292e68245 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/BUILD @@ -0,0 +1,62 @@ +java_library( + name = 'junit_runner', + srcs = glob(['*.java'], excludes=['*Test.java']), + visibility = ['//src/build/java/...'], + exported_deps = [ + '//third_party/java:junit', + '//third_party/java:hamcrest', + '//third_party/java:guava', + '//third_party/java:jacoco', + ], +) + +java_test( + name = 'junit_runner_test', + srcs = ['PleaseTestRunnerTest.java'], + deps = [ + ':junit_runner', + '//third_party/java:junit', + ] +) + +java_test( + name = 'junit_runner_parameterized_test', + srcs = ['PleaseTestRunnerParameterizedTest.java'], + deps = [ + ':junit_runner', + '//third_party/java:junit', + ] +) + +java_test( + name = 'please_coverage_class_loader_test', + srcs = ['PleaseCoverageClassLoaderTest.java'], + deps = [ + ':junit_runner', + '//third_party/java:junit', + ] +) + +java_test( + name = 'resources_root_test', + srcs = ['ResourcesRootTest.java'], + deps = [ + ':junit_runner', + ':logback_test_xml', + '//third_party/java:logback-classic', + ] +) + +java_test( + name = 'test_coverage_test', + srcs = ['TestCoverageTest.java'], + deps = [ + ':junit_runner', + ] +) + +java_library( + name = 'logback_test_xml', + resources = ['test_data/logback-test.xml'], + resources_root = 'test_data', +) diff --git a/src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java b/src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java new file mode 100644 index 0000000000..4e14d1ddf7 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java @@ -0,0 +1,25 @@ +package net.thoughtmachine.please.test; + +import java.lang.Thread; +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + +public class PleaseCoverageClassLoaderTest { + // Tests for class loading logic. + + @Test + public void testForName() throws Exception { + Class cls = Class.forName("net.thoughtmachine.please.test.PleaseCoverageClassLoaderTest"); + assertEquals(this.getClass(), cls); + } + + @Test + public void testContextClassLoader() throws Exception { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class cls = loader.loadClass("net.thoughtmachine.please.test.PleaseCoverageClassLoaderTest"); + assertEquals(this.getClass(), cls); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java b/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java new file mode 100644 index 0000000000..97db849e69 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java @@ -0,0 +1,41 @@ +package net.thoughtmachine.please.test; + +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameter; +import org.junit.runners.Parameterized.Parameters; +import org.junit.Test; + +import static org.junit.Assert.*; + + +@RunWith(Parameterized.class) +public class PleaseTestRunnerParameterizedTest { + // Tests using a custom test runner; Parameterized is an easy example of one. + + private int a; + private int b; + + @Parameters + public static Object[][] data() { + return new Object[][] { { 1, 2 } }; + } + + public PleaseTestRunnerParameterizedTest(int a, int b) { + this.a = a; + this.b = b; + } + + @Test + public void testSuccess() { + assertEquals(1, a); + assertEquals(2, b); + } + + @Ignore + public void testIgnore() { + assertEquals(0, a); + assertEquals(0, b); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java b/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java new file mode 100644 index 0000000000..8352596749 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java @@ -0,0 +1,24 @@ +package net.thoughtmachine.please.test; + +import org.junit.Ignore; +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class PleaseTestRunnerTest { + // Test class for our test runner. The test is of course whether this can be + // invoked by Please with the correct results; testing the components in isolation + // is not extremely easy since they're all designed to be used around the + // JUnit test running process. + + @Test + public void testSuccess() { + assertEquals(42, 6 * 7); + } + + @Ignore + public void testIgnore() { + assertEquals(42, 6 * 9); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java b/src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java new file mode 100644 index 0000000000..27bd11f1d9 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java @@ -0,0 +1,24 @@ +package net.thoughtmachine.please.test; + +import org.junit.Ignore; +import org.junit.Test; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.LoggerContext; +import org.slf4j.LoggerFactory; + +import static org.junit.Assert.assertEquals; + + +public class ResourcesRootTest { + // Test for setting resources_root on a java_library rule. Logback is the motivating case here. + + @Test + public void testAutoConfigurationLevel() throws Exception { + // If logback-test.xml is on the classpath the level will get set to INFO. By default it's DEBUG. + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + Logger logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME); + assertEquals(Level.INFO, logger.getLevel()); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/TestCoverage.java b/src/build/java/net/thoughtmachine/please/test/TestCoverage.java new file mode 100644 index 0000000000..ca72520dd5 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/TestCoverage.java @@ -0,0 +1,206 @@ +package net.thoughtmachine.please.test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.io.IOException; +import java.lang.Thread; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.jacoco.core.analysis.Analyzer; +import org.jacoco.core.analysis.CoverageBuilder; +import org.jacoco.core.analysis.IClassCoverage; +import org.jacoco.core.analysis.ICounter; +import org.jacoco.core.analysis.ILine; +import org.jacoco.core.data.ExecutionDataStore; +import org.jacoco.core.data.SessionInfoStore; +import org.jacoco.core.instr.Instrumenter; +import org.jacoco.core.runtime.IRuntime; +import org.jacoco.core.runtime.LoggerRuntime; +import org.jacoco.core.runtime.RuntimeData; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + + +public class TestCoverage { + // Class handling coverage instrumentation using Jacoco. + // This is very heavily based on the example given with Jacoco. + private static final String OUTPUT_FILE = "test.coverage"; + + public static void RunTestClasses(Set classes, Set allClasses) throws Exception { + IRuntime runtime = new LoggerRuntime(); + Instrumenter instrumenter = new Instrumenter(runtime); + RuntimeData data = new RuntimeData(); + runtime.startup(data); + + // This is a little bit fiddly; we want to instrument all relevant classes and then + // once that's done run just the test classes. + MemoryClassLoader memoryClassLoader = new MemoryClassLoader(instrumenter, allClasses); + // Inject our class loader so anything that tries to dynamically load classes will use it + // instead of the normal one and get the instrumented classes back. + // This probably isn't completely reliable but certainly fixes some problems. + Thread.currentThread().setContextClassLoader(memoryClassLoader); + Set testClassNames = new HashSet<>(); + for (Class cls : allClasses) { + // don't instrument the test runner classes here, nobody else wants to see them. + if (!cls.getPackage().getName().equals("net.thoughtmachine.please.test")) { + memoryClassLoader.loadClass(cls.getName()); + } + } + for (Class testClass : classes) { + TestMain.runClass(memoryClassLoader.loadClass(testClass.getName())); + testClassNames.add(testClass.getName()); + } + + ExecutionDataStore executionData = new ExecutionDataStore(); + SessionInfoStore sessionInfo = new SessionInfoStore(); + data.collect(executionData, sessionInfo, false); + runtime.shutdown(); + + CoverageBuilder coverageBuilder = new CoverageBuilder(); + Analyzer analyzer = new Analyzer(executionData, coverageBuilder); + for (Class testClass : allClasses) { + analyzer.analyzeClass(getTargetClass(testClass, testClass.getName()), testClass.getName()); + } + writeResults(coverageBuilder, testClassNames); + } + + private static InputStream getTargetClass(Class cls, String name) { + final String resource = '/' + name.replace('.', '/') + ".class"; + return cls.getResourceAsStream(resource); + } + + // Loads and instruments classes for coverage. + private static class MemoryClassLoader extends ClassLoader { + private final Instrumenter instrumenter; + private final Map instrumentedClasses = new HashMap<>(); + + public MemoryClassLoader(Instrumenter instrumenter, Set classes) { + this.instrumenter = instrumenter; + for (Class cls : classes) { + instrumentedClasses.put(cls.getName(), null); + } + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + try { + Class cls = instrumentedClasses.get(name); + if (cls != null) { + return cls; + } else if (instrumentedClasses.containsKey(name)) { + byte[] instrumented = instrumenter.instrument(getTargetClass(MemoryClassLoader.class, name), name); + cls = defineClass(name, instrumented, 0, instrumented.length); + instrumentedClasses.put(name, cls); + return cls; + } + return super.loadClass(name, resolve); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + } + + private static void writeResults(CoverageBuilder coverageBuilder, Set testClassNames) throws Exception { + Map sourceMap = readSourceMap(); + DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + doc.setXmlVersion("1.0"); + + Element root = doc.createElement("coverage"); + doc.appendChild(root); + Element packages = doc.createElement("packages"); + root.appendChild(packages); + // TODO(pebers): split up classes properly into separate packages here. + // It won't really make any difference to plz but it'd be nicer. + Element pkg = doc.createElement("package"); + packages.appendChild(pkg); + Element classes = doc.createElement("classes"); + pkg.appendChild(classes); + + for (final IClassCoverage cc : coverageBuilder.getClasses()) { + if (cc.getName().startsWith("net/thoughtmachine/please/test") || testClassNames.contains(cc.getName().replace("/", "."))) { + continue; // keep these out of results + } + + Element cls = doc.createElement("class"); + cls.setAttribute("branch-rate", String.valueOf(cc.getBranchCounter().getCoveredRatio())); + cls.setAttribute("complexity", String.valueOf(cc.getComplexityCounter().getCoveredRatio())); + cls.setAttribute("line-rate", String.valueOf(cc.getLineCounter().getCoveredRatio())); + cls.setAttribute("name", cc.getName()); + String name = sourceMap.get(cc.getPackageName().replace(".", "/") + "/" + cc.getSourceFileName()); + cls.setAttribute("filename", name != null ? name : cc.getName()); + + Element lines = doc.createElement("lines"); + for (int i = cc.getFirstLine(); i <= cc.getLastLine(); ++i) { + if (cc.getLine(i).getStatus() != ICounter.EMPTY) { // assume this means not executable? + Element line = doc.createElement("line"); + line.setAttribute("number", String.valueOf(i)); + line.setAttribute("hits", String.valueOf(cc.getLine(i).getInstructionCounter().getCoveredCount())); + // TODO(pebers): more useful output here. + lines.appendChild(line); + } + } + cls.appendChild(lines); + classes.appendChild(cls); + } + + TestMain.writeXMLDocumentToFile(OUTPUT_FILE, doc); + } + + /** + * Read the sourcemap file that we use to map Java class names back to their path in the repo. + */ + static Map readSourceMap() { + Map sourceMap = new HashMap<>(); + try { + InputStream is = TestCoverage.class.getClassLoader().getResourceAsStream("META-INF/please_sourcemap"); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + for(String line; (line = br.readLine()) != null; ) { + String[] parts = line.trim().split(" "); + if (parts.length == 2) { + sourceMap.put(parts[1], deriveOriginalFilename(parts[0], parts[1])); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + System.out.println("Failed to read sourcemap. Coverage results may be inaccurate."); + } + return sourceMap; + } + + /** + * Derives the original file name from the package and class paths. + * For example, the package might be src/build/java/net/thoughtmachine/please/test and + * the class would be net/thoughtmachine/please/test/TestCoverage; we want to + * produce src/build/java/net/thoughtmachine/please/test/TestCoverage. + */ + static String deriveOriginalFilename(String packageName, String className) { + String packagePath[] = packageName.split("/"); + String classPath[] = className.split("/"); + StringBuilder sb = new StringBuilder(); + for (String s : packagePath) { + if (classPath[0].equals(s)) { + break; + } else if (!s.isEmpty()) { + sb.append(s); + sb.append("/"); + } + } + sb.append(className); + return sb.toString(); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java b/src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java new file mode 100644 index 0000000000..86c47ef50a --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java @@ -0,0 +1,34 @@ +package net.thoughtmachine.please.test; + +import java.util.Map; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + + +public class TestCoverageTest { + // Direct tests for TestCoverage class. + + @Test + public void testDeriveOriginalFilename() { + String filename = TestCoverage.deriveOriginalFilename("src/build/java/net/thoughtmachine/please/test", + "net/thoughtmachine/please/test/TestCoverage"); + assertEquals("src/build/java/net/thoughtmachine/please/test/TestCoverage", filename); + + filename = TestCoverage.deriveOriginalFilename("src/build/java", "net/thoughtmachine/please/test/TestCoverage"); + assertEquals("src/build/java/net/thoughtmachine/please/test/TestCoverage", filename); + + filename = TestCoverage.deriveOriginalFilename("", "net/thoughtmachine/please/test/TestCoverage"); + assertEquals("net/thoughtmachine/please/test/TestCoverage", filename); + } + + @Test + public void testReadSourceMap() { + // Test we can read our own source map. + Map sourceMap = TestCoverage.readSourceMap(); + assertFalse(sourceMap.isEmpty()); + assertEquals(sourceMap.get("net/thoughtmachine/please/test/TestCoverage.java"), "src/build/java/net/thoughtmachine/please/test/TestCoverage.java"); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/TestListener.java b/src/build/java/net/thoughtmachine/please/test/TestListener.java new file mode 100644 index 0000000000..eea29a0d0a --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/TestListener.java @@ -0,0 +1,162 @@ +package net.thoughtmachine.please.test; + +import org.junit.runner.notification.RunListener; +import org.junit.runner.Description; +import org.junit.runner.Request; +import org.junit.runner.Result; +import org.junit.runner.Runner; +import org.junit.runner.notification.Failure; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +class TestListener extends RunListener { + // Listener for JUnit tests. + // Heavily based on Buck's version. + + private List results; + private PrintStream originalOut, originalErr, stdOutStream, stdErrStream; + private ByteArrayOutputStream rawStdOutBytes, rawStdErrBytes; + private Result result; + private RunListener resultListener; + private Failure assumptionFailure; + private static final String ENCODING = "UTF-8"; + + private long startTime = System.currentTimeMillis(); + + public TestListener(List results) { + this.results = results; + } + + @Override + public void testStarted(Description description) throws Exception { + // Create an intermediate stdout/stderr to capture any debugging statements (usually in the + // form of System.out.println) the developer is using to debug the test. + originalOut = System.out; + originalErr = System.err; + rawStdOutBytes = new ByteArrayOutputStream(); + rawStdErrBytes = new ByteArrayOutputStream(); + stdOutStream = new PrintStream(rawStdOutBytes, true, ENCODING); + stdErrStream = new PrintStream(rawStdErrBytes, true, ENCODING); + System.setOut(stdOutStream); + System.setErr(stdErrStream); + + result = new Result(); + resultListener = result.createListener(); + resultListener.testRunStarted(description); + resultListener.testStarted(description); + } + + @Override + public void testFinished(Description description) throws Exception { + // Shutdown single-test result. + resultListener.testFinished(description); + resultListener.testRunFinished(result); + resultListener = null; + + // Restore the original stdout/stderr. + System.setOut(originalOut); + System.setErr(originalErr); + + // Get the stdout/stderr written during the test as strings. + stdOutStream.flush(); + stdErrStream.flush(); + + int numFailures = result.getFailureCount(); + String className = description.getClassName(); + String methodName = description.getMethodName(); + // In practice, I have seen one case of a test having more than one failure: + // com.xtremelabs.robolectric.shadows.H2DatabaseTest#shouldUseH2DatabaseMap() had 2 + // failures. However, I am not sure what to make of it, so we let it through. + if (numFailures < 0) { + throw new IllegalStateException(String.format("Unexpected number of failures while testing %s#%s(): %d (%s)", + className, + methodName, + numFailures, + result.getFailures())); + } + + Failure failure; + String type; + if (assumptionFailure != null) { + failure = assumptionFailure; + type = "ASSUMPTION_VIOLATION"; + // Clear the assumption-failure field before the next test result appears. + assumptionFailure = null; + } else if (numFailures == 0) { + failure = null; + type = "SUCCESS"; + } else { + failure = result.getFailures().get(0); + type = "FAILURE"; + } + + String stdOut = rawStdOutBytes.size() == 0 ? null : rawStdOutBytes.toString(ENCODING); + String stdErr = rawStdErrBytes.size() == 0 ? null : rawStdErrBytes.toString(ENCODING); + + results.add(new TestResult(className, + methodName, + result.getRunTime(), + type, + failure == null ? null : failure.getException(), + stdOut, + stdErr)); + } + + /** + * The regular listener we created from the singular result, in this class, will not by + * default treat assumption failures as regular failures, and will not store them. As a + * consequence, we store them ourselves! + * + * We store the assumption-failure in a temporary field, which we'll make sure we clear each + * time we write results. + */ + @Override + public void testAssumptionFailure(Failure failure) { + assumptionFailure = failure; + if (resultListener != null) { + // Left in only to help catch future bugs -- right now this does nothing. + resultListener.testAssumptionFailure(failure); + } + } + + @Override + public void testFailure(Failure failure) throws Exception { + if (resultListener == null) { + recordUnpairedFailure(failure); + } else { + resultListener.testFailure(failure); + } + } + + @Override + public void testIgnored(Description description) throws Exception { + if (resultListener != null) { + resultListener.testIgnored(description); + } + } + + /** + * It's possible to encounter a Failure before we've started any tests (and therefore before + * testStarted() has been called). The known example is a @BeforeClass that throws an + * exception, but there may be others. + *

+ * Recording these unexpected failures helps us propagate failures back up to the "buck test" + * process. + */ + private void recordUnpairedFailure(Failure failure) { + long runtime = System.currentTimeMillis() - startTime; + Description description = failure.getDescription(); + results.add(new TestResult(description.getClassName(), + description.getMethodName(), + runtime, + "FAILURE", + failure.getException(), + null, + null)); + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/TestMain.java b/src/build/java/net/thoughtmachine/please/test/TestMain.java new file mode 100644 index 0000000000..5d990e09d8 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/TestMain.java @@ -0,0 +1,201 @@ +package net.thoughtmachine.please.test; + +import java.lang.Class; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.ArrayList; +import java.util.List; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.internal.builders.JUnit4Builder; +import org.junit.runner.Description; +import org.junit.runner.JUnitCore; +import org.junit.runner.Computer; +import org.junit.runner.Request; +import org.junit.runner.Runner; +import org.junit.runner.manipulation.Filter; + +import com.google.common.reflect.ClassPath; + + +public class TestMain { + // Main class for JUnit tests which writes output to a directory. + private static int exitCode = 0; + private static final String RESULTS_DIR = "test.results"; + private static String[] program_args; + private static int numTests = 0; + + public static void main(String[] args) throws Exception { + String testPackage = System.getProperty("net.thoughtmachine.please.testpackage"); + if (testPackage == null || testPackage.equals("")) { + throw new RuntimeException("Test package not provided (define with -Dnet.thoughtmachine.please.testpackage)"); + } + program_args = args; + + Set classes = new HashSet<>(); + Set allClasses = new HashSet<>(); + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + for (ClassPath.ClassInfo info : ClassPath.from(loader).getAllClasses()) { + if (info.getName().startsWith(testPackage)) { + Class testClass = info.load(); + allClasses.add(testClass); + if (testClass.getAnnotation(Ignore.class) == null) { + for (Method method : testClass.getMethods()) { + if (method.getAnnotation(Test.class) != null) { + classes.add(testClass); + break; + } + } + } + } + } + if (System.getenv("COVERAGE") != null) { + TestCoverage.RunTestClasses(classes, allClasses); + } else { + for (Class testClass : classes) { + runClass(testClass); + } + } + // Note that it isn't a fatal failure if there aren't any tests, unless the user specified + // test selectors. + if (args.length > 0 && numTests == 0) { + throw new RuntimeException("No tests were run."); + } + System.exit(exitCode); + } + + public static void runClass(Class testClass) throws Exception { + List results = new ArrayList<>(); + JUnitCore core = new JUnitCore(); + core.addListener(new TestListener(results)); + Request request = Request.aClass(testClass); + for (int i = 0; i < program_args.length; ++i) { + request = request.filterWith(Filter.matchMethodDescription(testDescription(testClass, program_args[i]))); + } + core.run(request); + writeResults(testClass.getName(), results); + numTests += results.size(); + } + + // This is again fairly directly lifted from Buck's writing code, because I am in no way + // interested in reinventing XML writing code like this if I can possibly avoid it. + static void writeResults(String testClassName, List results) throws Exception { + DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + doc.setXmlVersion("1.0"); + + Element root = doc.createElement("testcase"); + root.setAttribute("name", testClassName); + doc.appendChild(root); + + for (TestResult result : results) { + Element test = doc.createElement("test"); + + // name attribute + test.setAttribute("name", result.testMethodName); + test.setAttribute("classname", result.testClassName); + + // success attribute + boolean isSuccess = result.isSuccess(); + test.setAttribute("success", Boolean.toString(isSuccess)); + if (!isSuccess) { + exitCode = 1; + } + + // type attribute + test.setAttribute("type", result.type.toString()); + + // time attribute + long runTime = result.runTime; + test.setAttribute("time", String.valueOf(runTime)); + + // Include failure details, if appropriate. + Throwable failure = result.failure; + if (failure != null) { + String message = failure.getMessage(); + test.setAttribute("message", message); + + String stacktrace = stackTraceToString(failure); + test.setAttribute("stacktrace", stacktrace); + } + + // stdout, if non-empty. + if (result.stdOut != null) { + Element stdOutEl = doc.createElement("stdout"); + stdOutEl.appendChild(doc.createTextNode(result.stdOut)); + test.appendChild(stdOutEl); + } + + // stderr, if non-empty. + if (result.stdErr != null) { + Element stdErrEl = doc.createElement("stderr"); + stdErrEl.appendChild(doc.createTextNode(result.stdErr)); + test.appendChild(stdErrEl); + } + + root.appendChild(test); + } + + File dir = new File(RESULTS_DIR); + if (!dir.exists() && !dir.mkdir()) { + throw new IOException("Failed to create output directory: " + RESULTS_DIR); + } + writeXMLDocumentToFile(RESULTS_DIR + "/" + testClassName + ".xml", doc); + } + + public static void writeXMLDocumentToFile(String filename, Document doc) throws Exception { + // Create an XML transformer that pretty-prints with a 2-space indent. + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer trans = transformerFactory.newTransformer(); + trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); + trans.setOutputProperty(OutputKeys.INDENT, "yes"); + trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); + + File outputFile = new File(filename); + OutputStream output = new BufferedOutputStream(new FileOutputStream(outputFile)); + StreamResult streamResult = new StreamResult(output); + DOMSource source = new DOMSource(doc); + trans.transform(source, streamResult); + output.close(); + } + + static String stackTraceToString(Throwable exc) { + StringWriter writer = new StringWriter(); + exc.printStackTrace(new PrintWriter(writer, true)); + return writer.toString(); + } + + /** + * Returns a JUnit Description matching the given argument string. + */ + static Description testDescription(Class testClass, String s) { + int index = s.lastIndexOf('.'); + if (index == -1) { + return Description.createTestDescription(testClass, s); + } else { + return Description.createTestDescription(s.substring(0, index), s.substring(index + 1)); + } + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/TestResult.java b/src/build/java/net/thoughtmachine/please/test/TestResult.java new file mode 100644 index 0000000000..5d98f72762 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/TestResult.java @@ -0,0 +1,33 @@ +package net.thoughtmachine.please.test; + +final class TestResult { + // Result of an individual JUnit test. Heavily based on Buck's version. + + final String testClassName; + final String testMethodName; + final long runTime; + final String type; + final Throwable failure; + final String stdOut; + final String stdErr; + + public TestResult(String testClassName, + String testMethodName, + long runTime, + String type, + Throwable failure, + String stdOut, + String stdErr) { + this.testClassName = testClassName; + this.testMethodName = testMethodName; + this.runTime = runTime; + this.type = type; + this.failure = failure; + this.stdOut = stdOut; + this.stdErr = stdErr; + } + + public boolean isSuccess() { + return type == "SUCCESS"; + } +} diff --git a/src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml b/src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml new file mode 100644 index 0000000000..af4b7e7bc1 --- /dev/null +++ b/src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml @@ -0,0 +1,10 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + diff --git a/src/build/java/please_maven.go b/src/build/java/please_maven.go new file mode 100644 index 0000000000..5ede0f1f73 --- /dev/null +++ b/src/build/java/please_maven.go @@ -0,0 +1,234 @@ +// Tool to locate third-party Java dependencies on Maven Central. +// It doesn't actually fetch them (we just use curl for that) but instead +// is used to identify their transitive dependencies and report those back +// to build other rules from. + +package main + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "net/http" + "os" + "strings" + + "github.com/op/go-logging" + + "output" +) + +var log = logging.MustGetLogger("please_maven") + +type pomXml struct { + GroupId string `xml:"groupId"` + ArtifactId string `xml:"artifactId"` + Version string `xml:"version"` + Dependencies pomDependencies `xml:"dependencies"` + DependencyManagement struct { + Dependencies pomDependencies `xml:"dependencies"` + } `xml:"dependencyManagement"` + Properties struct { + Property []struct { + XMLName xml.Name + Value string `xml:",chardata"` + } `xml:",any"` + } `xml:"properties"` + Licences struct { + Licence []struct { + Name string `xml:"name"` + } `xml:"license"` + } `xml:"licenses"` +} + +type pomDependencies struct { + Dependency []struct { + GroupId string `xml:"groupId"` + ArtifactId string `xml:"artifactId"` + Version string `xml:"version"` + Scope string `xml:"scope"` + // TODO(pebers): Handle exclusions here. + } `xml:"dependency"` +} + +type mavenMetadataXml struct { + Versioning struct { + Latest string `xml:"latest"` + Release string `xml:"release"` + } `xml:"versioning"` +} + +var opts struct { + Repository string `short:"r" long:"repository" description:"Location of Maven repo" default:"https://repo1.maven.org/maven2"` + Verbosity int `short:"v" long:"verbose" default:"1" description:"Verbosity of output (higher number = more output, default 1 -> warnings and errors only)"` + Exclude []string `short:"e" long:"exclude" description:"Artifacts to exclude from download"` + Args struct { + Package []string + } `positional-args:"yes" required:"yes"` +} + +// Replaces a Maven variable in the given string. +func replaceVariables(s string, properties map[string]string) string { + if strings.HasPrefix(s, "${") { + if prop, present := properties[s[2:len(s)-1]]; !present { + fmt.Printf("Failed property lookup %s: %s\n", s, properties) + os.Exit(4) + } else { + return prop + } + } + return s +} + +// parse parses a downloaded pom.xml. This is of course less trivial than you would hope. +func parse(response []byte, group, artifact, version string) *pomXml { + pom := &pomXml{} + if err := xml.Unmarshal(response, pom); err != nil { + log.Fatalf("Error parsing XML response: %s\n", err) + } else if (pom.GroupId != "" && group != pom.GroupId) || + (pom.ArtifactId != "" && artifact != pom.ArtifactId) || + (pom.Version != "" && version != "" && version != pom.Version) { + // These are a bit fiddly since inexplicably the fields are sometimes empty. + log.Fatalf("Bad artifact: expected %s:%s:%s, got %s:%s:%s\n", group, artifact, version, pom.GroupId, pom.ArtifactId, pom.Version) + } + return pom +} + +// process takes a downloaded and parsed pom.xml and prints details of dependencies to fetch. +func process(pom *pomXml, group, artifact, version string) { + // Handle properties nonsense, because of course it doesn't work this out for us... + properties := map[string]string{} + for _, prop := range pom.Properties.Property { + properties[prop.XMLName.Local] = prop.Value + } + // There are also some nonsense properties that aren't described by the above. + properties["project.groupId"] = group + properties["project.version"] = version + // Arbitrarily, some pom files have this different structure with the extra "dependencyManagement" level. + handleDependencies(pom.Dependencies, properties, version) + handleDependencies(pom.DependencyManagement.Dependencies, properties, version) +} + +func fetchLicences(group, artifact, version string) []string { + // Unfortunately we have to make an extra request for the licences. + pom := fetchAndParse(group, artifact, version) + ret := make([]string, len(pom.Licences.Licence), len(pom.Licences.Licence)) + for i, licence := range pom.Licences.Licence { + ret[i] = licence.Name + } + return ret +} + +func handleDependencies(deps pomDependencies, properties map[string]string, version string) { + for _, dep := range deps.Dependency { + // This is a bit of a hack; our build model doesn't distinguish these in the way Maven does. + // TODO(pebers): Consider allowing specifying these to this tool to produce test-only deps. + if dep.Scope == "test" { + continue + } + dep.GroupId = replaceVariables(dep.GroupId, properties) + dep.ArtifactId = replaceVariables(dep.ArtifactId, properties) + dep.Version = replaceVariables(dep.Version, properties) + if isExcluded(dep.ArtifactId) { + continue + } + if dep.Version == "" { + dep.Version = version + } + licences := strings.Join(fetchLicences(dep.GroupId, dep.ArtifactId, dep.Version), "|") + if licences != "" { + fmt.Printf("%s:%s:%s:%s\n", dep.GroupId, dep.ArtifactId, dep.Version, licences) + } else { + fmt.Printf("%s:%s:%s\n", dep.GroupId, dep.ArtifactId, dep.Version) + } + opts.Exclude = append(opts.Exclude, dep.ArtifactId) // Don't do this one again. + // Recurse so we get all transitive dependencies + pom := fetchAndParse(dep.GroupId, dep.ArtifactId, dep.Version) + process(pom, dep.GroupId, dep.ArtifactId, dep.Version) + } +} + +// isExcluded returns true if this artifact should be excluded from the download. +func isExcluded(artifact string) bool { + for _, exclude := range opts.Exclude { + if exclude == artifact { + return true + } + } + return false +} + +func buildPomUrl(group, artifact, version string) string { + if version == "" { + // This is kind of exciting - we just assume the latest version if one isn't available. + // Not sure what we're really meant to do but I'm losing the will to live over all this so #yolo + version = fetchMetadata(group, artifact).Versioning.Release + log.Notice("Version not specified for %s:%s, decided to use %s", group, artifact, version) + } + slashGroup := strings.Replace(group, ".", "/", -1) + return opts.Repository + "/" + slashGroup + "/" + artifact + "/" + version + "/" + artifact + "-" + version + ".pom" +} + +// fetchOrDie fetches a URL and returns the content, dying if it can't be found. +func fetchOrDie(url string) []byte { + log.Debug("Downloading %s...", url) + response, err := http.Get(url) + if err != nil { + log.Fatalf("Error downloading %s: %s\n", url, err) + } else if response.StatusCode < 200 || response.StatusCode > 299 { + log.Fatalf("Error downloading %s: %s\n", url, response.Status) + } + defer response.Body.Close() + content, err := ioutil.ReadAll(response.Body) + if err != nil { + log.Fatalf("Error receiving response from %s: %s\n", url, err) + } + return content +} + +var fetchAndParseMemo = map[string]*pomXml{} + +// fetchAndParse combines fetch() and parse() and memoises the results so we don't repeat requests. +func fetchAndParse(group, artifact, version string) *pomXml { + key := fmt.Sprintf("%s:%s:%s", group, artifact, version) + if ret := fetchAndParseMemo[key]; ret != nil { + return ret + } + url := buildPomUrl(group, artifact, version) + content := fetchOrDie(url) + ret := parse(content, group, artifact, version) + fetchAndParseMemo[key] = ret + return ret +} + +var fetchMetadataMemo = map[string]*mavenMetadataXml{} + +// fetchMetadata finds the latest available version of a package when nothing else is specified. +// Also memoises because why not. +func fetchMetadata(group, artifact string) *mavenMetadataXml { + slashGroup := strings.Replace(group, ".", "/", -1) + url := opts.Repository + "/" + slashGroup + "/" + artifact + "/maven-metadata.xml" + if ret := fetchMetadataMemo[url]; ret != nil { + return ret + } + content := fetchOrDie(url) + ret := &mavenMetadataXml{} + if err := xml.Unmarshal(content, ret); err != nil { + log.Fatalf("Error parsing XML response: %s\n", err) + } + fetchMetadataMemo[url] = ret + return ret +} + +func main() { + output.ParseFlagsOrDie("please_maven", &opts) + output.InitLogging(opts.Verbosity, "", 0) + for _, pkg := range opts.Args.Package { + split := strings.Split(pkg, ":") + if len(split) != 3 { + log.Fatalf("Incorrect usage: argument %s must be in the form group:artifact:version\n", pkg) + } + pom := fetchAndParse(split[0], split[1], split[2]) + process(pom, split[0], split[1], split[2]) + } +} diff --git a/src/build/java/test_data/test.zip b/src/build/java/test_data/test.zip new file mode 100644 index 0000000000000000000000000000000000000000..9624bfbec6c4c6bc1044bf7839a0be6f5a4a4b5e GIT binary patch literal 6415 zcmZ{pRZtvEn}r8wAXu=$-Q7L71s{S22_AyG1PB`3ok0c<{9IslkhqHu*D7ozzJ04Qb!0I&e$0CNvpdrMO{ zcPnR38z-H2Kmbzk+qXLZ#KRjCfPj2}1OWVNYcONYm>8?Y8i0#e?Pv_KiiKmsw@w# z`d9{rdn?~%uP__p>9Vr!+A83?ny}U~5Qftf2xrb#4jQyjlZ@N)mQVfWG}h!3C#}_i zhtY1|zm0`(89n61@7rWGAnBB+tvV^X=}w%~d{cqz)>9jJwqG*r!rdj%V^i>q1 zNV4CVBWU+?Xpj&~nboVK1cmQ}F0c$i49nBswSTRCCuhMiEKC{8Yw}j!m9eT!pNB|X2za1ro^u%f>(g}0h=G37Z*~AB5ZCJ=50s9j*a;5W(#IaPbKhP zb8vjCAS7@<_AZry#$*){s=Lw0M!kx>YstOcaY4+*?1qQzAZ<|>QPR3e>_!UEhZ!`# zzbK@0&Dx{qXaXsHQZ^gT!cbOLX9FUY(Uw7rcF1_Eqs=P_p}iPPFIv;2G8inQEzWkP z6Ne3n+xX?GMZba-(%NkK!qP-I_!O*uvy>Ot^yUY17#?)X9rKkUSA^8S*k)a1D4ftx7XaTK~9S%mmI6sF$6xhEX7|;<%CKr>eyfy;l771^JDZcIb_G=QP-OHtJA_P-wnGxVpsXiAB5Ri zQ%0@D%G4Idzq;mhVC9BGgO`2P@YYnkL*)Xb&y=y(rb)%}y2P3dPy!cOJ;hONpI0vf z`QB3EC#|E&*u7dpm)_)3sY)gj2JI33>E!e!YAAlJOt{0JfO$CdLusH)pPI|((2K_U ziVhl|Q~q^>EDp7YIV#^WLp#u@x2?BO+H?cOYeFsuj8+^~eOtY*?}~hIl%lMCGBrJs z(w?Qm2#GOo<6K8?4qnlHz2kKq!*-mglL3-Fc>3chu2fbIRrep9SPd~a)(jvJT36;mv_h3u9w{uOg#&q?8-?gQ9eiNTd<3KdWTQUiv9#iC((X7?)GLWQuU` z6882;`3Pd)j%na~x{+5A7y0A^NZ+LpGllbdhM>VDY_^WCbqO9F=iTr@LbUCL=Kc8# zUeU|yTv^wa;%h86)JHWxNymQ^uB4J$YyyW@t;0XdM4#>j2qX5up6i1>`lAuSQF??+ z!&Ycxs>2SiI<}4+tqy&Ean_yAyqds_1}iFl<_)a{{9dq{UG^Yu)_oK7G~Fh@7fvc| zAbvcC=FnYBJ+c906<8CHxrvfm3NjHJ8S6#Rl`W{e8Ft6~68>>jw97}H} z$BnIR_VmlGsCm>B5|NGVWjxcx9PRlMSduYqQ-A5&w#!&zpR_G2{i09ll}7VsdKV7g z%OeTA9ZbT&!7+B**!+V%*zMEDk%6puXIuhO`aH(|JpT0YZrOi6uybyaB9V5w+|0X* zS>MMd&i8EgT1~&~*v=XGj;3LMgcq>2Vz1ZCdx3;AQ;=?2!giP+`1?e`(y*APe_8X7 zJ>4Gf`}eFh|$C&GQNR0}K0fwc}(THkuJG5dG|I1d4kfTXMs zTwS^6sCkHh^+=tz-R^}3aPtC6W7&SqE`ph=Ye?f^1OZ7B@b089Nn@t`Az-9I2U;uZ zwr~?;W+w$X|9a(^Ia3C2;o&~;KP?}IoG{VCwpn0zDQ*Ji)|vJMyP|EfA(*}_7?%rG zAJ5uvcvud)%{E`lv&k1G3sPKljTMrD@I*KJKF$H7TE^S~f@d1s?=#thGdI535@x6t zU`pzH0>d#aoX{KHM{6qzHjodqLZup^Zec)Pj!hv!3+Vypz?u(MGt)IgLU<29*`Uv4 zxC6)s>LSJrvI?IO?KtVPgBz}CL(QIsW3>2yhjnm`W*Fy*Gy{xMSG8MEZ*)fjKB;-7 zac)~{V}>c-6DCW!%#D{e8+Z3+FvmQ~kJVv-0A>>umg)!CXoMhh+GF`|0;*Y3ri6K| z-%9VDQH_;vkONx~_wdLV6X_-dbH)w&xf9j>K5aOYH2*x^cVGI|RV}E>fwx`MdWz9d zxs;?-VyEe}oUys- zX^uW@T+d+{7MpqHgtp_@6 zm4U62u!A-_tamDLCES*;UA40A4Oq)`UV<)wkF{J2!Kq!#G1j&mWhOoe$t2u`e zf|a=AsB`_hUUi~16qby_PIK;E)-^UD=QTkDidPzgQ5lWDTgD;c2etg6A)hNhdS+?= z!sS1TXeTBLRVv zINj07`z0BChAyyS+WlCIf_%O`%xykICn7qcYX9b<)k86N<=&1LUa9_l>jA)bv6%;X>1jN$|q&B*Pi(N z0a?BPM&F6pZ>xN6IUJoPd0F&T?>*FDjuYt)N+@cF3Ate>$Hp1!u+CrJ)jmXw_YScdH@Utx?san8* z0AXc5-5B`DaKk{Jj#gl<>8kt2!23u%YUYa!mW_jltD9N3-`zX< zFk4oVck1&CK^V;Tw3T2MyozrODI4&q(nzhZl<4Bqh5yVZp9PZ>imOBylCZ^J>pdX^_!#e=A485bxHwA;*K)#30M-2+cC4YzP$OBk!6 zYwU7YXHr}h<)?UcA={~A2O4Y?c|phU{iO7b>;qD46yMP02)?d~G?dQ^w@0GQ0n)Na zefoG`Zh9bxkfQpYer37qFx1~K%$-*hShwCUzb(jb;fPrN75XMPg>(=PcsM#r8`(UM zO2R;Z?$@%$c-Q>1waj!oL*7p&<5Se@QRS!Z0`b_*rBg0trm=}i^aasH^3Sab8Da$0 zic~Vs!Za`WU-`%8t$KEi>~m=hLIy{*hP#lxxTRtoitbsia)%m>6iQbxC} z$-7A+rCX(wrLQBVOc(kCA8p;&BUMTPIizX4;=R z>u+eP2SYb4*N~3p7>@C`I|HP%-QtCwjCVo=YzfK_B_5R?Qa&K59UPXZpy7gLi!bA# z0(c3op^sSGFG!mIjU`xrvEqkquk<)jnwT=n%~`GiN(n&rivvrCf6lAT|&A|J(ka*&deoEn}epuRx# zdA+U88@GrVev-qaE9Y9ZJtae26w24Wz;y z`(-}tU1uf_hlEKj9=#=EzD=6{zC%Q?wKOckRY^k>V>Pv=C?Ks-rD9lkg`y3+j<%WV zDZe)&*u?(yfiV)pJ0#VdlWd{>6Q~mRI@{{5QgejCDWcX9!h+w3uA-&0SSdASgs7F^$?P?F@AuWFE!tY@t9?3KqD{*{at*2NZ35y$c>; zloZxK-wF=V7(7Npb8P`HeeYdF^>YPrVYV9>c+|7MOszt=9K5t#v_15|9_uTEtkK6F>55YtkztsL72Pa`! zN|C3}0o+cI9uEHlJ?nlM=I>ORmg+*18?h{PMqHt4RDMNb_=4Ky)_Q258t8^HLlkCG z)>l-yL_trCHCAuCK`XLTVuDi{xEKI-|j0Pc4vRkJLUWuj$v!fr`t{7Q<*j}=L8#WS5^ooo3?eQ`06)=HN+XMRQ2^3p&cV(WMbW3TA^N)q zY^(Rr4^3(Fi-8hhmTRk-HBRe|MDD{V23iW{Reh>MYoxU&S7@LaQX#V~j&y>1Qvp*Q z8vKG?CI3AXJ4=ZY-Qgyt-ABXgBo<3f`EUH32Q1ZY!qAO=!v+tav{7NN-o~GVKM9Vc zj;TRR*{+ALWt(5C0A7vkC**Her|`)w!(}d2)B_R31>>)YCPGsT?$pkDUc7Fb6_{ULsXe{D%T5o4Y9ZVQy|_-kITCSk7COG;&=4rmLSqxToftbM`)kw zmU4HN_CUMt7lp{JxF!|!0_H#^uK93!GzKq?16%*#YcjsM*yTh|BeIG~!||?TI6b^VYT*uflPj zn%yic^jqlznIS@7aLpZ6oY1ZqZA2~USen}&N?;tNtsPwN>$TJKb6uO1l6a16TqCJ= zRmGzZg1XdoekZFTEZ?U>=)SuHYK}@DlEggbrCJ4(_N>Q8eY2+-{b|1}Wvv+%*Ic8u z0}d(cThMQf>&t5?L1fb;R{AN;u$eFPkVDzLdK%S}OL1}A`E9EQ%>tpa_Sq=N>qDun z6v|`nX6z-;o4l;nZRC8S4EtGXX$({)VrhTJNbrPyRM6!`ZY2fF84)1qCy%az$J`@)~6%^#4_xn;DZ3ouDXtgE*AQ}TQJjt@vy{Wm?4n6SaSPFS<- zLnjdtVJBQKKaVgCB|S>b3l3BCp}6eOb%kydrw6CDpoK`L$Zjw@jh!djGBynDm8L(& z$!Dn7-Xub2&WLQb`~&tP<2II#O+$x%4^Y@+RSSX1#{iQxgJ1_Hl)4xn_2yFt4i)n% zirx%T95wxjaanv58S((`r?TiXGg9GF=Mx(<_;V=8`&d+2#xfyqW;lX#v{Q};EREE# zWGU(W%P(e4RcedPCO5Aa0V>bIDFOhh75I(<%?k6>7${z0M=pq2Npu_bb;s1XZrh;A zj|%iu5_s5_D3w~LgBwu08aK`f45i-#n7(%}64pKgMUxvMj72vdvQ^Zg>ob}JvQS8Q z#z9Ihje2QuS!4Xn;TT8xpC?q}bnvldJuMW4($lz5K8k7e8B-V=z_UbFB9+xSf}ryHa5h9Y)% znMp2lSezeFK7h!MB`_!b`=&47qS_fA=%nr}lFU*4W|BJI-(633>(;&FM^Ihf^3b*V z@l8ynXBCMcPO?i%)PSL7twNZ9%7l%Agf_qd{mx(uthlzm+iUzmOu>&l0!@uo_jig^ z$EQ4PhOpMH4WFp-S<-L}V*>~Aw^G=mDJAC~8EaEvg%ev%x`&&VRYE@2FFi3|#XEL9 z*j8fPP|BQo-f7sj1VS+!P~2ZoN)v^LW$wNs?!j<9R_Wde$QTBE5UQx@G!1GP!0?1a zQ_vJS^(arf1$PQz)|*8B7`gZIt7!$%bfo*Us2%|lh;6C` zW=HOvDR%{N9!FVf#5SvQB}MAhUHvKnNr87vBJ?d?qA7P;&gM+q2h} z*gJAff0N!Ht&`)$`>8~F>Xu1lX6qFmdTXXVKVPRmCeBSqP0;ltqxE|puR7axETdaA z_4%!j$7$Op(w$fx`VmLcYv*ZA4RuuWOPEkawt3cAPFA zelf3DeUSvwlv85YNZs54pVj>WF!B4r|5WowMlOoA-H7_Xp?kfPwReyMfYp$`T<;3BQNCp%xql z*2_io?8A|!yH zib-Ft!1KrAjc79XW5^4FrV0WgCDQ*V6hMDP0|0>VH}ygP-2P23p!}y^__zQ2|E&Dq lFz`Ps)Bl=_{{s#F*8U$@ps9j_`p+8>|E}`Cr^dgU{sX;77ViK6 literal 0 HcmV?d00001 diff --git a/src/build/java/zip_writer.go b/src/build/java/zip_writer.go new file mode 100644 index 0000000000..e580c42f13 --- /dev/null +++ b/src/build/java/zip_writer.go @@ -0,0 +1,242 @@ +// Contains utility functions for helping combine .jar files. +package java + +import ( + "bytes" + "encoding/binary" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + "zip" + + "github.com/op/go-logging" +) + +var log = logging.MustGetLogger("zip_writer") + +// AddZipFile copies the contents of a zip file into an existing zip writer. +func AddZipFile(w *zip.Writer, path string, exclude []string, whitelist []string, strict bool) error { + r, err := zip.OpenReader(path) + if err != nil { + return err + } + defer r.Close() + + // Reopen file to get a directly readable version without decompression. + r2, err := os.Open(path) + if err != nil { + return err + } + defer r2.Close() + +outer: + for _, f := range r.File { + // This directory is very awkward. We need to merge the contents by concatenating them, + // we can't replace them or leave them out. + if strings.HasPrefix(f.Name, "META-INF/services/") || + strings.HasPrefix(f.Name, "META-INF/spring") || + f.Name == "META-INF/please_sourcemap" { + if err := concatenateFile(w, f); err != nil { + return err + } + continue + } + for _, excl := range exclude { + if strings.HasPrefix(f.Name, excl) { + continue outer + } + } + if existing, present := getExistingFile(w, f.Name); present { + // Allow duplicates of directories. Seemingly the best way to identify them is that + // they end in a trailing slash. + if strings.HasSuffix(f.Name, "/") { + continue + } + // Check if this file is whitelisted. + for _, wl := range whitelist { + if strings.HasPrefix(f.Name, wl) { + continue outer + } + } + // Allow skipping existing files that are exactly the same as the added ones. + // It's unnecessarily awkward to insist on not ever doubling up on a dependency. + if existing.CRC32 == f.CRC32 { + log.Info("Skipping %s / %s: already added (from %s)", path, f.Name, existing.ZipFile) + continue + } + if strict { + return fmt.Errorf("File %s already added to destination zip file (from %s)", f.Name, existing.ZipFile) + } + continue + } + log.Debug("%s: %s", path, f.Name) + // Java tools don't seem to like writing a data descriptor for stored items. + // Unsure if this is a limitation of the format or a problem of those tools. + f.Flags = 0 + addExistingFile(w, f.Name, path, f.CompressedSize64, f.UncompressedSize64, f.CRC32) + + start, err := f.DataOffset() + if err != nil { + return err + } + if _, err := r2.Seek(start, 0); err != nil { + return err + } + if err := addFile(w, &f.FileHeader, r2, f.CRC32); err != nil { + return err + } + } + return nil +} + +// AddInitPyFiles adds an __init__.py file to every directory in the zip file that doesn't already have one. +func AddInitPyFiles(w *zip.Writer) error { + done := map[string]bool{} + m := files[w] + for p := range m { + initPyPath := path.Join(filepath.Dir(p), "__init__.py") + if _, present := m[initPyPath]; !present && !done[initPyPath] { + // Don't write one at the root, it's not necessary. + if initPyPath != "__init__.py" { + done[initPyPath] = true + if err := WriteFile(w, initPyPath, []byte{}); err != nil { + return err + } + } + } + } + return nil +} + +// AddManifest adds a manifest to the given zip writer with a Main-Class entry (and a couple of others) +func AddManifest(w *zip.Writer, mainClass string) error { + manifest := fmt.Sprintf("Manifest-Version: 1.0\nMain-Class: %s\n", mainClass) + return WriteFile(w, "META-INF/MANIFEST.MF", []byte(manifest)) +} + +// Records some information about a file that we use to check if they're exact duplicates. +type fileRecord struct { + ZipFile string + CompressedSize64 uint64 + UncompressedSize64 uint64 + CRC32 uint32 +} + +var files = map[*zip.Writer]map[string]fileRecord{} +var concatenatedFiles = map[string]string{} + +func getExistingFile(w *zip.Writer, name string) (fileRecord, bool) { + if m := files[w]; m != nil { + record, present := m[name] + return record, present + } + return fileRecord{}, false +} + +// HasExistingFile returns true if the writer has already written the given file. +func HasExistingFile(w *zip.Writer, name string) bool { + _, b := getExistingFile(w, name) + return b +} + +func addExistingFile(w *zip.Writer, name, file string, c, u uint64, crc uint32) { + m := files[w] + if m == nil { + m = map[string]fileRecord{} + files[w] = m + } + m[name] = fileRecord{file, c, u, crc} +} + +// Add a file to the zip which is concatenated with any existing content with the same name. +// Writing is deferred since we obviously can't append to it later. +func concatenateFile(w *zip.Writer, f *zip.File) error { + r, err := f.Open() + if err != nil { + return err + } + defer r.Close() + buf := new(bytes.Buffer) + if _, err := io.Copy(buf, r); err != nil { + return err + } + contents := buf.String() + if !strings.HasSuffix(contents, "\n") { + contents += "\n" + } + concatenatedFiles[f.Name] += contents + return nil +} + +// HandleConcatenatedFiles appends concatenated files to the archive's directory for writing. +func HandleConcatenatedFiles(w *zip.Writer) error { + for name, contents := range concatenatedFiles { + if err := WriteFile(w, name, []byte(contents)); err != nil { + return err + } + } + return nil +} + +// Writes a file to the new writer. +func addFile(w *zip.Writer, fh *zip.FileHeader, r io.Reader, crc uint32) error { + fh.Flags = 0 // we're not writing a data descriptor after the file + comp := func(w io.Writer) (io.WriteCloser, error) { return nopCloser{w}, nil } + fw, err := w.CreateHeaderWithCompressor(fh, comp, fixedCrc32{value: crc}) + if err == nil { + _, err = io.CopyN(fw, r, int64(fh.CompressedSize64)) + } + return err +} + +// WriteFile writes a complete file to the writer. +func WriteFile(w *zip.Writer, filename string, data []byte) error { + if fw, err := w.Create(filename); err != nil { + return err + } else if _, err := fw.Write(data); err != nil { + return err + } + return nil +} + +type nopCloser struct { + io.Writer +} + +func (w nopCloser) Close() error { + return nil +} + +// fixedCrc32 implements a Hash32 interface that just writes out a predetermined value. +// this is really cheating of course but serves our purposes here. +type fixedCrc32 struct { + value uint32 +} + +func (crc fixedCrc32) Write(p []byte) (n int, err error) { + return len(p), nil +} + +func (crc fixedCrc32) Sum(b []byte) []byte { + buf := make([]byte, 4) + binary.LittleEndian.PutUint32(buf, crc.value) + return b +} + +func (crc fixedCrc32) Sum32() uint32 { + return crc.value +} + +func (crc fixedCrc32) Reset() { +} + +func (crc fixedCrc32) Size() int { + return 32 +} + +func (crc fixedCrc32) BlockSize() int { + return 32 +} diff --git a/src/build/java/zip_writer_test.go b/src/build/java/zip_writer_test.go new file mode 100644 index 0000000000..f64d5c6ab4 --- /dev/null +++ b/src/build/java/zip_writer_test.go @@ -0,0 +1,58 @@ +package java + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "strings" + "testing" + "zip" +) + +func TestZipWriter(t *testing.T) { + // Have to write an actual file for zip.OpenReader to use later. + f, err := ioutil.TempFile("", "zip_writer_test") + if err != nil { + t.Fatalf("Failed to create temp file: %s", err) + } + filename := f.Name() + defer os.Remove(filename) + w := zip.NewWriter(f) + if err := AddZipFile(w, "src/build/java/test_data/test.zip", []string{}, []string{}, true); err != nil { + t.Fatalf("Failed to add zip file: %s", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Failed to close zip file: %s", err) + } + w.Close() + f.Close() + + r, err := zip.OpenReader(filename) + if err != nil { + t.Fatalf("Failed to reopen zip file: %s", err) + } + defer r.Close() + + files := []struct{ Name, Prefix string }{ + {"build_step.go", "// Implementation of Step interface."}, + {"incrementality.go", "// Utilities to help with incremental builds."}, + } + for i, f := range r.File { + if f.Name != files[i].Name { + t.Errorf("File %d has wrong name: expected %s, was %s", i, files[i].Name, f.Name) + } + fr, err := f.Open() + if err != nil { + t.Errorf("Failed to reopen file %d [%s]: %s", i, f.Name, err) + } else { + buf := new(bytes.Buffer) + if _, err = io.Copy(buf, fr); err != nil { + t.Errorf("Failed to read full contents of file %d [%s]: %s", i, f.Name, err) + } else if !strings.HasPrefix(buf.String(), files[i].Prefix) { + t.Errorf("File %d [%s] didn't start with expected prefix: was %s", buf.String()[:20]) + } + fr.Close() + } + } +} diff --git a/src/build/python/BUILD b/src/build/python/BUILD new file mode 100644 index 0000000000..d0d54fc3a1 --- /dev/null +++ b/src/build/python/BUILD @@ -0,0 +1,96 @@ +python_binary( + name = 'please_pex', + main = 'pex.py', + deps = [ + ':bootstrap_pexer', + ':main_files', + '//third_party/python:pex', + '//third_party/python:pkg_resources', + ], + visibility = ['PUBLIC'], +) + +python_library( + name = 'main_files', + srcs = ['test_main.py', 'pex_main.py'], + deps = [ + '//third_party/python:six', + '//third_party/python:xmlrunner', + '//third_party/python:coverage', + ], +) + +python_test( + name = 'pex_test', + srcs = ['pex_test.py'], + deps = [ + ':bootstrap_pexer' + ] +) + +python_test( + name = 'custom_interpreter_test', + srcs = ['custom_interpreter_test.py'], + deps = [ + ':bootstrap_pexer' + ], + labels = ['manual'], + interpreter = 'pypy' +) + +# This is needed for bootstrapping the build system: we have to be +# able to build a .pex with the pex builder which is itself a pex. +build_rule( + name = 'bootstrap_pexer', + srcs = ['pex.py'], + outs = ['bootstrap_pexer.pex'], + deps = [ + ':main_files', + '//third_party/python:pex', + '//third_party/python:pkg_resources', + ], + cmd = ' && '.join([ + # Have to make sure these exist. + 'touch third_party/__init__.py third_party/python/__init__.py', + 'touch src/__init__.py src/build/__init__.py src/build/python/__init__.py', + 'PYTHONPATH="." python src/build/python/pex.py --src_dir=${TMP_DIR} --out=${OUT} --entry_point=${PKG//\//.}.pex --interpreter ' + CONFIG.DEFAULT_PYTHON_INTERPRETER, + ]), + needs_transitive_deps = True, + binary = True, + output_is_complete = True, + visibility = ['PUBLIC'] +) + +python_test( + name = 'pex_import_test', + srcs = ['pex_import_test.py'], + deps = [ + ':bootstrap_pexer', + '//third_party/python:dateutil', + '//third_party/python:requests', + ], +) + +# Used to test zip-safety flags. +python_test( + name = 'zip_unsafe_test', + srcs = ['zip_unsafe_test.py'], + deps = [ + '//src/build/cc:so_test_py' + ], + labels = ['cc'], # Depends on cc rules to build +) + +# Tests for a subtle case where python_test rules should get a pex when +# specified as data, but not when depending directly. +python_binary( + name = 'data_dep', + main = 'data_dep.py', +) + +python_test( + name = 'data_dep_test', + srcs = ['data_dep_test.py'], + deps = [':data_dep'], + data = [':data_dep'], +) diff --git a/src/build/python/custom_interpreter_test.py b/src/build/python/custom_interpreter_test.py new file mode 100644 index 0000000000..24f0f8db23 --- /dev/null +++ b/src/build/python/custom_interpreter_test.py @@ -0,0 +1,15 @@ +"""Test that our pexer is capable of building .pex files with custom interpreters.""" + +import platform +import unittest + + +class CustomInterpreterTest(unittest.TestCase): + + def testInterpreterIsPyPy(self): + """Test that this is being run with PyPy.""" + self.assertEqual('PyPy', platform.python_implementation()) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/build/python/data_dep.py b/src/build/python/data_dep.py new file mode 100644 index 0000000000..6ec2846917 --- /dev/null +++ b/src/build/python/data_dep.py @@ -0,0 +1,11 @@ +"""Part of a test on deps, data, requires and provides.""" + +from __future__ import print_function + + +def the_answer(): + return 42 + + +if __name__ == '__main__': + print('42') diff --git a/src/build/python/data_dep_test.py b/src/build/python/data_dep_test.py new file mode 100644 index 0000000000..e8dc64bb30 --- /dev/null +++ b/src/build/python/data_dep_test.py @@ -0,0 +1,22 @@ +"""Test on deps, data, requires and provides.""" + +import os +import subprocess +import unittest + + +class DataDepTest(unittest.TestCase): + + def test_direct_dep(self): + """Test that we can import the module directly.""" + from src.build.python import data_dep + self.assertEqual(42, data_dep.the_answer()) + + def test_data_dep(self): + """Test that we can also invoke the .pex directly as a data dependency.""" + output = subprocess.check_output(['src/build/python/data_dep.pex']) + self.assertEqual('42', output.strip().decode('utf-8')) + + +# Deliberately not adding an "if __name__ == '__main__':" stanza since this test +# will only work when invoked through plz so the data dep is in the right place. diff --git a/src/build/python/pex.py b/src/build/python/pex.py new file mode 100755 index 0000000000..08c36184b8 --- /dev/null +++ b/src/build/python/pex.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +"""Pex building script for Please.""" + +import argparse +import json +import os +import pkg_resources +import shutil +import sys +import tempfile + +from third_party.python.pex.pex_builder import PEXBuilder +from third_party.python.pex.interpreter import PythonInterpreter + + +def dereference_symlinks(src): + """ + Resolve all symbolic references that `src` points to. Note that this + is different than `os.path.realpath` as path components leading up to + the final location may still be symbolic links. + """ + while os.path.islink(src): + src = os.path.join(os.path.dirname(src), os.readlink(src)) + return src + + +def write_file(f, contents): + """Writes contents to given file object. + + TODO(pebers): This is mostly an effort to get around various encoding issues. Would be + nice to solve this in a less brutal way but not sure how best to resolve + python2 / python3 / pkg_resources :( + """ + try: + f.write(contents) + except (UnicodeDecodeError, UnicodeEncodeError, TypeError): + try: + f.write(contents.decode('utf-8')) + except (UnicodeDecodeError, UnicodeEncodeError): + f.write(contents.decode('latin_1')) # This is desperate peasantry of course. + + +def add_directory(root_path, path, pex_builder): + """Recursively adds the contents of a directory to the pex.""" + base = os.path.join(root_path, path) + for filename in os.listdir(base): + src = dereference_symlinks(os.path.join(base, filename)) + dst = os.path.join(path, filename) + if os.path.isdir(src): + add_directory(root_path, dst, pex_builder) + elif filename.endswith('.py'): + # Assume this is source code and add as such. + # TODO(pebers): this is possibly a bit simplistic... + pex_builder.add_source(src, dst) + elif not filename.endswith('.pyc'): + pex_builder.add_resource(src, dst) + + +def add_test_files(test_sources, out_dir): + """Add files required for running a test pex.""" + contents = pkg_resources.resource_string('src.build.python', 'test_main.py').decode('utf-8') + remove_ext = lambda x: x[:-3] if x.endswith('.py') else x + test_modules = ','.join(remove_ext(src.replace('/', '.')) for src in test_sources.split(',')) + contents = contents.replace('__TEST_NAMES__', test_modules) + with open(os.path.join(out_dir, 'test_main.py'), 'w') as f: + write_file(f, contents) + # Extract the xmlrunner and coverage files too + extract_directory('third_party.python', 'xmlrunner', out_dir, '.bootstrap/xmlrunner', True) + extract_file('third_party.python', os.path.join(out_dir, '.bootstrap'), 'six.py', True) + extract_directory('third_party.python', 'coverage', out_dir, '.bootstrap/coverage', True) + + +def add_main(module_dir, entry_point, out_dir): + """Add pex_main.py as the entry point to a pex.""" + contents = pkg_resources.resource_string('src.build.python', 'pex_main.py').decode('utf-8') + contents = contents.replace('__MODULE_DIR__', module_dir).replace('__ENTRY_POINT__', entry_point) + with open(os.path.join(out_dir, 'pex_main.py'), 'w') as f: + write_file(f, contents) + return 'pex_main' + + +def extract_directory(in_pkg, in_req, out_dir, out_path, duplicates_allowed=False): + """Extracts a directory from the pex builder and adds it to the staging directory.""" + target_dir = os.path.join(out_dir, out_path) + if os.path.exists(target_dir) and duplicates_allowed: + return + os.makedirs(target_dir) + full_dir = '%s.%s' % (in_pkg, in_req) + for filename in pkg_resources.resource_listdir(in_pkg, in_req): + if not pkg_resources.resource_isdir(full_dir, filename): + extract_file(full_dir, target_dir, filename) + + +def extract_file(in_pkg, out_dir, filename, duplicates_allowed=False): + """Extracts a single file from the pex builder and adds it to the staging directory.""" + target = os.path.join(out_dir, filename) + if os.path.exists(target) and duplicates_allowed: + return + with open(target, 'w') as f: + write_file(f, pkg_resources.resource_string(in_pkg, filename)) + + +def main(args): + # Pex doesn't support relative interpreter paths. + # In python3 we could use shutil.which() to locate it but it's probably better + # to just force the user to specify it. + if not args.interpreter.startswith('/'): + print('--interpreter argument must be an absolute path') + sys.exit(1) + + # Add pkg_resources and the bootstrapper + extract_directory('third_party.python', + 'pex', + args.src_dir, + '.bootstrap/_pex') + extract_file('third_party.python', + os.path.join(args.src_dir, '.bootstrap'), + 'pkg_resources.py') + + # Setup a temp dir that the PEX builder will use as its scratch dir. + tmp_dir = tempfile.mkdtemp() + try: + interpreter = PythonInterpreter.from_binary(args.interpreter) + pex_builder = PEXBuilder(path=tmp_dir, interpreter=interpreter) + pex_builder.info.zip_safe = args.zip_safe + + # Set the entry point. + pex_main = add_main(args.module_dir, args.entry_point, args.src_dir) + if args.test_package: + # Stick with the test main, it knows what to do. + pex_builder.info.entry_point = args.entry_point + else: + # Override the entry point so the module import override works. + pex_builder.info.entry_point = pex_main + + if args.test_package and args.test_srcs: + # Temp hack to make this work from an unexpected module name + sys.path.append(os.path.join(sys.argv[0], 'third_party/python')) + add_test_files(args.test_srcs, args.src_dir) + + # Add everything under the input dir. + add_directory(args.src_dir, '.', pex_builder) + + # This function does some setuptools malarkey which is vexing me, so + # I'm just gonna cheekily disable it for now. + pex_builder._prepare_bootstrap = lambda: None + + # Generate the PEX file. + pex_builder.build(args.out) + + # Always try cleaning up the scratch dir, ignoring failures. + finally: + shutil.rmtree(tmp_dir, True) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--src_dir', required=True) + parser.add_argument('--out', required=True) + parser.add_argument('--entry_point', required=True) + parser.add_argument('--interpreter', default=sys.executable) + parser.add_argument('--test_package') + parser.add_argument('--test_srcs') + parser.add_argument('--module_dir', default='') + parser.add_argument('--zip_safe', dest='zip_safe', action='store_true') + parser.add_argument('--nozip_safe', dest='zip_safe', action='store_false') + parser.set_defaults(zip_safe=True) + main(parser.parse_args()) diff --git a/src/build/python/pex_import_test.py b/src/build/python/pex_import_test.py new file mode 100644 index 0000000000..680da71236 --- /dev/null +++ b/src/build/python/pex_import_test.py @@ -0,0 +1,21 @@ +# Test for importing certain modules with the new incremental pex +# rules. These have proven tricky, seemingly around requests doing +# "from . import utils" etc (which is perfectly fine, and was working +# previously, this just helps investigate & make sure it's fixed). + +import unittest + + +class PexImportTest(unittest.TestCase): + + def test_import_requests(self): + """Test importing Requests.""" + from third_party.python import requests + + def test_import_dateutil(self): + """Test importing dateutil.""" + from third_party.python.dateutil import parser + + +if __name__ == '__main__': + unittest.main() diff --git a/src/build/python/pex_main.py b/src/build/python/pex_main.py new file mode 100644 index 0000000000..4821afba1b --- /dev/null +++ b/src/build/python/pex_main.py @@ -0,0 +1,72 @@ +"""Customised pex entry point which forces imports of third-party components to a given directory.""" + +import os +import pkg_resources +import runpy +import sys + +try: + import builtins # python 3 +except ImportError: + import __builtin__ as builtins # python 2 + + +# These will get templated in by the build rules. +MODULE_DIR = '__MODULE_DIR__' +ENTRY_POINT = '__ENTRY_POINT__' + +ABSOLUTE_IMPORT_ONLY = 0 + + +def override_import(package=MODULE_DIR): + """Overrides builtin __import__ function to forcibly add the given directory. + + Returns an appropriate replacement for the builtin function which imports known + third party modules as eg. 'third_party.python.six' instead of just 'six'. + """ + if not package: + return + original_import = builtins.__import__ + try: + modules = {(x.rpartition('.')[0] or x): p for p in package.split(',') + for x in pkg_resources.resource_listdir(p, '') if not x.startswith('__init__')} + except ImportError: + return # Skip if the module isn't built into this pex + if not modules: + return # nothing to do + + def _override_import(name, globals=None, locals=None, fromlist=None, level=-1): + module_name = name.partition('.')[0] + if module_name in modules: + prefix = modules[module_name] + '.' + fq_name = prefix + name + mod = original_import(fq_name, globals, locals, fromlist, level=ABSOLUTE_IMPORT_ONLY) + if fromlist: + return mod + else: + # Have to be careful to return the correct module here. + # See http://stackoverflow.com/questions/2724260 if you're curious. + module_name = name.partition('.')[0] + mod = sys.modules[prefix + module_name] + sys.modules[name] = sys.modules[prefix + name] + return mod + return original_import(name, globals, locals, fromlist, level) + + builtins.__import__ = _override_import + + +def clean_sys_path(): + """Remove anything from sys.path that isn't either the pex or the main Python install dir. + + NB: *not* site-packages or dist-packages or any of that malarkey, just the place where + we get the actual Python standard library packages from). + """ + sys.path = [x for x in sys.path if 'dist-packages' not in x and + ('.pex' in x or 'please_pex' in x or x.startswith(os.path.split(os.__file__)[0]))] + + +if __name__ == '__main__': + override_import() + clean_sys_path() + # Must run this as __main__ so it executes its own __name__ == '__main__' block. + runpy.run_module(ENTRY_POINT, run_name='__main__') diff --git a/src/build/python/pex_test.py b/src/build/python/pex_test.py new file mode 100644 index 0000000000..935ca66d13 --- /dev/null +++ b/src/build/python/pex_test.py @@ -0,0 +1,24 @@ +"""Simple test that our pexer works correctly for a unit test.""" + +import unittest + + +class PexTest(unittest.TestCase): + + def testSuccess(self): + """Test records a success.""" + self.assertEqual(4, 2**2) + + @unittest.skip("Saving this for when the stars are right") + def testSkipped(self): + """Test skipping a test""" + self.assertEqual(10, 3**3) + + @unittest.expectedFailure + def testSkipped(self): + """Test an expected failure""" + self.assertEqual(132, 4**4) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/build/python/test_main.py b/src/build/python/test_main.py new file mode 100644 index 0000000000..deae01bac0 --- /dev/null +++ b/src/build/python/test_main.py @@ -0,0 +1,99 @@ +"""Customised test runner to output in JUnit-style XML.""" + +import argparse +import os +import unittest +import sys +try: + from builtins import __import__ # python3 +except ImportError: + from __builtin__ import __import__ # python2 + +# This will get templated in by the build rules. +TEST_NAMES = '__TEST_NAMES__'.split(',') + +sys.path.append(os.path.join(sys.argv[0], '.bootstrap')) + +import xmlrunner +import coverage +from coverage import control as coverage_control +from pex_main import clean_sys_path, override_import + + +def list_classes(suite): + for test in suite: + if isinstance(test, unittest.suite.TestSuite): + for cls, name in list_classes(test): + yield cls, name + else: + yield test, test.__class__.__module__ + '.' + test.id() + + +def filter_suite(suite, test_names): + """Reduces a test suite to just the tests matching the given names.""" + new_suite = unittest.suite.TestSuite() + for name in test_names: + new_suite.addTests(cls for cls, class_name in list_classes(suite) if name in class_name) + return new_suite + + +# Fix up paths in coverage output which are absolute; we want paths relative to +# the repository root. Also skip empty __init__.py files. +def _xml_file(self, fr, analysis): + if '.pex' in fr.filename: + fr.filename = fr.filename[fr.filename.index('.pex') + 5:] # +5 to take off .pex/ + if not (fr.filename.endswith('__init__.py') and len(analysis.statements) <= 1): + _original_xml_file(self, fr, analysis) +_original_xml_file = coverage_control.XmlReporter.xml_file +coverage_control.XmlReporter.xml_file = _xml_file + + +def run_tests(test_names): + """Runs tests, returns the number of failures.""" + # unittest's discovery produces very misleading errors in some cases; if it tries to import + # a module which imports other things that then fail, it reports 'module object has no + # attribute ' and swallows the original exception. Try to import them all first + # so we get better error messages. + for test_name in TEST_NAMES: + __import__(test_name) + suite = unittest.defaultTestLoader.loadTestsFromNames(TEST_NAMES) + if test_names: + suite = filter_suite(suite, test_names) + if suite.countTestCases() == 0: + raise Exception('No matching tests found') + runner = xmlrunner.XMLTestRunner(output='test.results') + results = runner.run(suite) + return len(results.errors) + len(results.failures) + + +def main(args): + if args.list_classes: + suite = unittest.defaultTestLoader.loadTestsFromNames(TEST_NAMES) + for _, cls in set(list_classes(suite)): + sys.stdout.write(cls + '\n') + return 0 + elif args.coverage or os.getenv('COVERAGE'): + # It's important that we run coverage while we load the tests otherwise + # we get no coverage for import statements etc. + cov = coverage.coverage() + cov.start() + result = run_tests(args.test_names) + cov.stop() + omissions = ['*/third_party/*', '*/.bootstrap/*', '*/test_main.py'] + # Exclude test code from coverage itself. + omissions.extend('*/%s.py' % module.replace('.', '/') for module in args.test_names) + cov.xml_report(outfile='test.coverage', omit=omissions) + return result + else: + return run_tests(args.test_names) + + +if __name__ == '__main__': + override_import() + clean_sys_path() + parser = argparse.ArgumentParser(description='Arguments for Please Python tests.') + parser.add_argument('--list_classes', type=bool, default=False, help='List all test classes') + parser.add_argument('--coverage', dest='coverage', action='store_true', + help='Write output coverage file') + parser.add_argument('test_names', nargs='*', default=[], help='Tests to run') + sys.exit(main(parser.parse_args())) diff --git a/src/build/python/zip_unsafe_test.py b/src/build/python/zip_unsafe_test.py new file mode 100644 index 0000000000..d45b1924c3 --- /dev/null +++ b/src/build/python/zip_unsafe_test.py @@ -0,0 +1,16 @@ +"""Library to test transitive zip_safe flag.""" + +import unittest + +from src.build.cc import so_test + + +class SharedObjectTest(unittest.TestCase): + + def test_file1_contents(self): + contents = so_test.get_embedded_file_1() + self.assertEqual('testing message 1\n', contents) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/cache/BUILD b/src/cache/BUILD new file mode 100644 index 0000000000..3fbc965b38 --- /dev/null +++ b/src/cache/BUILD @@ -0,0 +1,42 @@ +go_library( + name = 'cache', + srcs = glob(['*.go'], excludes=['*_test.go', 'rpc_cache_stub.go']), + deps = [ + '//src/core', + '//src/cache/proto:rpc_cache', + '//third_party/go:logging', + '//third_party/go:grpc', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'http_cache_test', + srcs = ['http_cache_test.go'], + deps = [ + ':cache', + '//src/cache/server', + '//third_party/go:logging', + # TODO(pebers): should not need this dependency. + '//src/cache/proto:rpc_cache', + ], + data = ['test_data/linux_amd64', 'test_data/darwin_amd64'], + container = True, # Brings up an internal server + tags = ['proto'], # Protos are available so can compile in rpc. +) + +go_test( + name = 'rpc_cache_test', + srcs = ['rpc_cache_test.go'], + deps = [ + ':cache', + '//src/cache/server', + '//src/output', + '//third_party/go:logging', + # TODO(pebers): should not need this dependency. + '//src/cache/proto:rpc_cache', + ], + data = ['test_data/linux_amd64', 'test_data/darwin_amd64', 'test_data/plz-out'], + container = True, # Brings up an internal server + tags = ['proto'], # Protos are available so can compile in rpc. +) diff --git a/src/cache/cache.go b/src/cache/cache.go new file mode 100644 index 0000000000..2d4e988514 --- /dev/null +++ b/src/cache/cache.go @@ -0,0 +1,141 @@ +// Caching support for Please. + +package cache + +import ( + "core" + "github.com/op/go-logging" + "net/http" +) + +var log = logging.MustGetLogger("cache") + +func NewCache(config core.Configuration) *core.Cache { + mplex := new(cacheMultiplexer) + if config.Cache.Dir != "" { + mplex.caches = append(mplex.caches, newDirCache(config)) + } + if config.Cache.RpcUrl != "" { + cache, err := newRpcCache(config) + if err == nil { + mplex.caches = append(mplex.caches, cache) + } else { + log.Warning("RPC cache server could not be reached: %s", err) + } + } + if config.Cache.HttpUrl != "" { + res, err := http.Get(config.Cache.HttpUrl + "/ping") + if err == nil && res.StatusCode == 200 { + mplex.caches = append(mplex.caches, newHttpCache(config)) + } else { + log.Warning("Http cache server could not be reached: %s.\nSkipping http caching...", err) + } + } + if len(mplex.caches) == 0 { + return nil + } else if len(mplex.caches) == 1 { + return &mplex.caches[0] // Skip the extra layer of indirection + } else { + var cache core.Cache = *mplex + return &cache + } +} + +// Multiplexes several caches into one. +// Used when we have several active (eg. http, dir). +type cacheMultiplexer struct { + caches []core.Cache +} + +func (mplex cacheMultiplexer) Store(target *core.BuildTarget, key []byte) { + mplex.storeUntil(target, key, nil) +} + +// storeUntil stores artifacts into higher priority caches than the given one. +// Used after artifact retrieval to ensure we have them in eg. the directory cache after +// downloading from the RPC cache. +// This is a little inefficient since we could write the file to plz-out then copy it to the dir cache, +// but it's hard to fix that without breaking the cache abstraction. +func (mplex cacheMultiplexer) storeUntil(target *core.BuildTarget, key []byte, stopAt core.Cache) { + // Attempt to store on all caches simultaneously. + ch := make(chan bool) + for _, cache := range mplex.caches { + if cache == stopAt { + break + } + go func(cache core.Cache) { + cache.Store(target, key) + ch <- true + }(cache) + } + for _ = range mplex.caches { + <-ch + } +} + +func (mplex cacheMultiplexer) StoreExtra(target *core.BuildTarget, key []byte, file string) { + mplex.storeExtraUntil(target, key, file, nil) +} + +// storeExtraUntil is similar to storeUntil but stores a single file. +func (mplex cacheMultiplexer) storeExtraUntil(target *core.BuildTarget, key []byte, file string, stopAt core.Cache) { + // Attempt to store on all caches simultaneously. + ch := make(chan bool) + for _, cache := range mplex.caches { + if cache == stopAt { + break + } + go func(cache core.Cache) { + cache.StoreExtra(target, key, file) + ch <- true + }(cache) + } + for _ = range mplex.caches { + <-ch + } +} + +func (mplex cacheMultiplexer) Retrieve(target *core.BuildTarget, key []byte) bool { + // Retrieve from caches sequentially; if we did them simultaneously we could + // easily write the same file from two goroutines at once. + for _, cache := range mplex.caches { + if cache.Retrieve(target, key) { + // Store this into other caches + mplex.storeUntil(target, key, cache) + return true + } + } + return false +} + +func (mplex cacheMultiplexer) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool { + // Retrieve from caches sequentially; if we did them simultaneously we could + // easily write the same file from two goroutines at once. + for _, cache := range mplex.caches { + if cache.RetrieveExtra(target, key, file) { + // Store this into other caches + mplex.storeExtraUntil(target, key, file, cache) + return true + } + } + return false +} + +func (mplex cacheMultiplexer) Clean(target *core.BuildTarget) { + for _, cache := range mplex.caches { + cache.Clean(target) + } +} + +// Yields all cacheable artifacts from this target. Useful for cache implementations +// to not have to reinvent logic around post-build functions etc. +func cacheArtifacts(target *core.BuildTarget) <-chan string { + ch := make(chan string, 10) + go func() { + for _, out := range target.Outputs() { + ch <- out + } + close(ch) + }() + return ch +} diff --git a/src/cache/dir_cache.go b/src/cache/dir_cache.go new file mode 100644 index 0000000000..ff8c142f82 --- /dev/null +++ b/src/cache/dir_cache.go @@ -0,0 +1,146 @@ +// Diretory-based cache. + +package cache + +import ( + "encoding/base64" + "fmt" + "os" + "os/exec" + "path" + + "core" +) + +type dirCache struct { + Dir string +} + +func (cache *dirCache) Store(target *core.BuildTarget, key []byte) { + cacheDir := cache.getPath(target, key) + // Clear out anything that might already be there. + if err := os.RemoveAll(cacheDir); err != nil { + log.Warning("Failed to remove existing cache directory %s: %s", cacheDir, err) + return + } + for out := range cacheArtifacts(target) { + cache.StoreExtra(target, key, out) + } +} + +func (cache *dirCache) StoreExtra(target *core.BuildTarget, key []byte, out string) { + cacheDir := cache.getPath(target, key) + log.Debug("Storing %s: %s in dir cache...", target.Label, out) + if dir := path.Dir(out); dir != "." { + if err := os.MkdirAll(path.Join(cacheDir, dir), core.DirPermissions); err != nil { + log.Warning("Failed to create cache directory %s: %s", path.Join(cacheDir, dir), err) + return + } + } + outFile := path.Join(core.RepoRoot, target.OutDir(), out) + cachedFile := path.Join(cacheDir, out) + // Remove anything existing + if err := os.RemoveAll(cachedFile); err != nil { + log.Warning("Failed to remove existing cached file %s: %s", cachedFile, err) + } else if err := os.MkdirAll(cacheDir, core.DirPermissions); err != nil { + log.Warning("Failed to create cache directory %s: %s", cacheDir, err) + return + } else if err := core.RecursiveCopyFile(outFile, cachedFile, fileMode(target), false); err != nil { + // Cannot hardlink files into the cache, must copy them for reals. + log.Warning("Failed to store cache file %s: %s", cachedFile, err) + } +} + +func (cache *dirCache) Retrieve(target *core.BuildTarget, key []byte) bool { + cacheDir := cache.getPath(target, key) + if !core.PathExists(cacheDir) { + log.Debug("%s: %s doesn't exist in dir cache", target.Label, cacheDir) + return false + } + for out := range cacheArtifacts(target) { + if !cache.RetrieveExtra(target, key, out) { + return false + } + } + return true +} + +func (cache *dirCache) RetrieveExtra(target *core.BuildTarget, key []byte, out string) bool { + outDir := path.Join(core.RepoRoot, target.OutDir()) + cacheDir := cache.getPath(target, key) + cachedOut := path.Join(cacheDir, out) + realOut := path.Join(outDir, out) + if !core.PathExists(cachedOut) { + log.Debug("%s: %s doesn't exist in dir cache", target.Label, cachedOut) + return false + } + log.Debug("Retrieving %s: %s from dir cache...", target.Label, cachedOut) + if dir := path.Dir(realOut); dir != "." { + if err := os.MkdirAll(dir, core.DirPermissions); err != nil { + log.Warning("Failed to create output directory %s: %s", dir, err) + return false + } + } + // It seems to be quite important that we unlink the existing file first to avoid ETXTBSY errors + // in cases where we're running an existing binary (as Please does during bootstrap, for example). + if err := os.RemoveAll(realOut); err != nil { + log.Warning("Failed to unlink existing output %s: %s", realOut, err) + return false + } + // Recursively hardlink files back out of the cache + if err := core.RecursiveCopyFile(cachedOut, realOut, fileMode(target), true); err != nil { + log.Warning("Failed to move cached file to output: %s -> %s: %s", cachedOut, realOut, err) + return false + } + log.Debug("Retrieved %s: %s from dir cache", target.Label, cachedOut) + return true +} + +func (cache *dirCache) Clean(target *core.BuildTarget) { + // Remove for all possible keys, so can't get getPath here + if err := os.RemoveAll(path.Join(cache.Dir, target.Label.PackageName, target.Label.Name)); err != nil { + log.Warning("Failed to remove artifacts for %s from dir cache: %s", target.Label, err) + } +} + +func (cache *dirCache) getPath(target *core.BuildTarget, key []byte) string { + // NB. Is very important to use a padded encoding here so lengths are consistent for cache_cleaner. + return path.Join(cache.Dir, target.Label.PackageName, target.Label.Name, base64.URLEncoding.EncodeToString(core.CollapseHash(key))) +} + +func newDirCache(config core.Configuration) *dirCache { + cache := new(dirCache) + // Absolute paths are allowed. Relative paths are interpreted relative to the repo root. + if config.Cache.Dir[0] == '/' { + cache.Dir = config.Cache.Dir + } else { + cache.Dir = path.Join(core.RepoRoot, config.Cache.Dir) + } + // Make directory if it doesn't exist. + if err := os.MkdirAll(cache.Dir, core.DirPermissions); err != nil { + panic(fmt.Sprintf("Failed to create root cache directory %s: %s", cache.Dir, err)) + } + // Fire off the cache cleaner process. + if config.Cache.DirCacheCleaner != "" { + go func() { + log.Info("Running cache cleaner: %s --dir %s --high_water_mark %s --low_water_mark %s", + config.Cache.DirCacheCleaner, cache.Dir, config.Cache.DirCacheHighWaterMark, config.Cache.DirCacheLowWaterMark) + cmd := exec.Command(config.Cache.DirCacheCleaner, + "--dir", cache.Dir, + "--high_water_mark", config.Cache.DirCacheHighWaterMark, + "--low_water_mark", config.Cache.DirCacheLowWaterMark) + if out, err := cmd.CombinedOutput(); err != nil { + log.Error("Cache cleaner error %s.\nFull output: %s", err, out) + } + }() + } + return cache +} + +func fileMode(target *core.BuildTarget) os.FileMode { + if target.IsBinary { + return 0555 + } else { + return 0444 + } +} diff --git a/src/cache/http_cache.go b/src/cache/http_cache.go new file mode 100644 index 0000000000..76528beac6 --- /dev/null +++ b/src/cache/http_cache.go @@ -0,0 +1,172 @@ +// Http-based cache. + +package cache + +import ( + "core" + "encoding/base64" + "io" + "mime" + "mime/multipart" + "net/http" + "os" + "path" + "path/filepath" + "runtime" +) + +type httpCache struct { + Url string + Writeable bool + Timeout int + OSName string +} + +func (cache *httpCache) Store(target *core.BuildTarget, key []byte) { + // TODO(pebers): Change this to upload using multipart, it's quite slow doing every file separately + // for targets with many files. + if cache.Writeable { + for out := range cacheArtifacts(target) { + if info, err := os.Stat(out); err == nil && info.IsDir() { + filepath.Walk(out, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if !info.IsDir() { + cache.StoreExtra(target, key, name) + } + return nil + }) + } else { + cache.StoreExtra(target, key, out) + } + } + } +} + +func (cache *httpCache) StoreExtra(target *core.BuildTarget, key []byte, file string) { + if cache.Writeable { + artifact := path.Join( + cache.OSName, + target.Label.PackageName, + target.Label.Name, + base64.RawURLEncoding.EncodeToString(key), + file, + ) + log.Info("Storing %s: %s in http cache...", target.Label, artifact) + + // NB. Don't need to close this file, http.Post will do it for us. + file, err := os.Open(path.Join(target.OutDir(), file)) + if err != nil { + log.Warning("Failed to read artifact: %s", err) + return + } + response, err := http.Post(cache.Url+"/artifact/"+artifact, "application/octet-stream", file) + if err != nil { + log.Warning("Failed to send artifact to %s: %s", cache.Url+"/artifact/"+artifact, err) + } else if response.StatusCode < 200 || response.StatusCode > 299 { + log.Warning("Failed to send artifact to %s: got response %s", cache.Url+"/artifact/"+artifact, response.Status) + } + response.Body.Close() + } +} + +func (cache *httpCache) Retrieve(target *core.BuildTarget, key []byte) bool { + // We can't tell from outside if this works or not (as we can for the dir cache) + // so we must assume that a target with no artifacts can't be retrieved. It's a weird + // case but a test already exists in the plz test suite so... + retrieved := false + for out := range cacheArtifacts(target) { + if !cache.RetrieveExtra(target, key, out) { + return false + } + retrieved = true + } + return retrieved +} + +func (cache *httpCache) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool { + log.Debug("Retrieving %s:%s from http cache...", target.Label, file) + + artifact := path.Join( + cache.OSName, + target.Label.PackageName, + target.Label.Name, + base64.RawURLEncoding.EncodeToString(key), + file, + ) + + response, err := http.Get(cache.Url + "/artifact/" + artifact) + if err != nil { + return false + } + defer response.Body.Close() + if response.StatusCode == 404 { + return false + } else if response.StatusCode < 200 || response.StatusCode > 299 { + log.Warning("Error %d from http cache", response.StatusCode) + return false + } else if response.Header.Get("Content-Type") == "application/octet-stream" { + // Single artifact + return cache.writeFile(target, file, response.Body) + } else if _, params, err := mime.ParseMediaType(response.Header.Get("Content-Type")); err != nil { + log.Warning("Couldn't parse response: %s", err) + return false + } else { + // Directory, comes back in multipart + mr := multipart.NewReader(response.Body, params["boundary"]) + for { + if part, err := mr.NextPart(); err == io.EOF { + return true + } else if err != nil { + log.Warning("Error reading multipart response: %s", err) + return false + } else if !cache.writeFile(target, part.FileName(), part) { + return false + } + } + } +} + +func (cache *httpCache) writeFile(target *core.BuildTarget, file string, r io.Reader) bool { + outFile := path.Join(target.OutDir(), file) + if err := os.MkdirAll(path.Dir(outFile), core.DirPermissions); err != nil { + log.Error("Failed to create directory: %s", err) + return false + } + f, err := os.OpenFile(outFile, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, fileMode(target)) + if err != nil { + log.Error("Failed to open file: %s", err) + return false + } + defer f.Close() + if _, err := io.Copy(f, r); err != nil { + log.Error("Failed to write file: %s", err) + return false + } + log.Info("Retrieved %s from http cache", target.Label) + return true +} + +func (cache *httpCache) Clean(target *core.BuildTarget) { + var reader io.Reader + artifact := path.Join( + cache.OSName, + target.Label.PackageName, + target.Label.Name, + ) + req, _ := http.NewRequest("DELETE", cache.Url+"/artifact/"+artifact, reader) + response, err := http.DefaultClient.Do(req) + if err != nil { + log.Warning("Failed to remove artifacts for %s from http cache: %s", target.Label, err) + } + response.Body.Close() +} + +func newHttpCache(config core.Configuration) *httpCache { + cache := new(httpCache) + cache.OSName = runtime.GOOS + "_" + runtime.GOARCH + cache.Url = config.Cache.HttpUrl + cache.Writeable = config.Cache.HttpWriteable + cache.Timeout = config.Cache.HttpTimeout + return cache +} diff --git a/src/cache/http_cache_test.go b/src/cache/http_cache_test.go new file mode 100644 index 0000000000..2046de9cc8 --- /dev/null +++ b/src/cache/http_cache_test.go @@ -0,0 +1,61 @@ +package cache + +import ( + "io/ioutil" + "net/http/httptest" + "path" + "path/filepath" + "runtime" + "testing" + + "cache/server" + "core" +) + +var ( + label core.BuildLabel + target *core.BuildTarget + httpcache *httpCache + key []byte + osName string +) + +func init() { + osName = runtime.GOOS + "_" + runtime.GOARCH + label = core.NewBuildLabel("pkg/name", "label/name") + target = core.NewBuildTarget(label) + + key, _ = ioutil.ReadFile("src/cache/test_data/testfile") + testServer := httptest.NewServer(server.BuildRouter()) + + config := core.DefaultConfiguration() + config.Cache.HttpUrl = testServer.URL + config.Cache.HttpWriteable = true + httpcache = newHttpCache(config) + + // Arbitrary large numbers so the cleaner never needs to run. + server.Init("src/cache/test_data", 100000, 100000000, 1000000000) +} + +func TestStore(t *testing.T) { + target.AddOutput("testfile") + httpcache.Store(target, []byte("test_key")) + abs, _ := filepath.Abs(path.Join("src/cache/test_data", osName, "pkg/name", "label/name")) + if !core.PathExists(abs) { + t.Errorf("Test file %s was not stored in cache.", abs) + } +} + +func TestRetrieve(t *testing.T) { + if !httpcache.Retrieve(target, []byte("test_key")) { + t.Error("Artifact expected and not found.") + } +} + +func TestClean(t *testing.T) { + httpcache.Clean(target) + filename := path.Join("src/cache/test_data", osName, "pkg/name/label/name") + if core.PathExists(filename) { + t.Errorf("File %s was not removed from cache.", filename) + } +} diff --git a/src/cache/proto/BUILD b/src/cache/proto/BUILD new file mode 100644 index 0000000000..f0360a58fe --- /dev/null +++ b/src/cache/proto/BUILD @@ -0,0 +1,6 @@ +grpc_library( + name = 'rpc_cache', + srcs = ['rpc_cache.proto'], + visibility = ['//src/cache/...', '//src/cache_server/...'], + languages = ['go'], +) diff --git a/src/cache/proto/rpc_cache.proto b/src/cache/proto/rpc_cache.proto new file mode 100644 index 0000000000..3c26ef3306 --- /dev/null +++ b/src/cache/proto/rpc_cache.proto @@ -0,0 +1,78 @@ +// Defines interface to our RPC cache. + +syntax = "proto3"; + +option java_package = "net.thoughtmachine.please.cache"; + +package proto.rpc_cache; + +service RpcCache { + // Stores an artifact or set of artifacts in the cache. + rpc Store(StoreRequest) returns (StoreResponse); + // Retrieves an artifact or set of artifacts from the cache. + rpc Retrieve(RetrieveRequest) returns (RetrieveResponse); + // Deletes an artifact from the cache. + rpc Delete(DeleteRequest) returns (DeleteResponse); +} + +message Artifact { + // Package of the artifact + string package = 1; + // Target name of the artifact + string target = 2; + // Output file from the target + string file = 3; + // Contents of it + bytes body = 4; +} + +message StoreRequest { + // Sequence of artifacts to store. + repeated Artifact artifacts = 1; + // OS of requestor + string os = 2; + // Architecture of requestor + string arch = 3; + // Hash of rule that generated these artifacts + bytes hash = 4; +} + +message StoreResponse { + // True if store was successful. + bool success = 1; +} + +message RetrieveRequest { + // Artifacts to retrieve. The 'body' field should obviously not be set. + // If the 'file' field is not set then all artifacts are retrieved. + repeated Artifact artifacts = 1; + // OS of requestor + string os = 2; + // Architecture of requestor + string arch = 3; + // Hash of rule that generated these artifacts + bytes hash = 4; +} + +message RetrieveResponse { + // True if retrieve was successful. + bool success = 1; + // Contents of artifacts retrieved + repeated Artifact artifacts = 2; +} + +message DeleteRequest { + // Artifacts to delete. The 'body' field should obviously not be set. + repeated Artifact artifacts = 1; + // OS of requestor + string os = 2; + // Architecture of requestor + string arch = 3; + // True to delete entire cache. 'paths' should be empty if this is set. + bool everything = 4; +} + +message DeleteResponse { + // True if delete was successful. + bool success = 1; +} diff --git a/src/cache/rpc_cache.go b/src/cache/rpc_cache.go new file mode 100644 index 0000000000..8bdda43ec1 --- /dev/null +++ b/src/cache/rpc_cache.go @@ -0,0 +1,177 @@ +// +build proto + +// RPC-based remote cache. Similar to HTTP but likely higher performance. +package cache + +import ( + "bytes" + "core" + "io/ioutil" + "os" + "path" + "path/filepath" + "runtime" + "time" + + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/grpclog" + + pb "cache/proto/rpc_cache" +) + +type rpcCache struct { + connection *grpc.ClientConn + client pb.RpcCacheClient + Writeable bool + OSName string +} + +func (cache *rpcCache) Store(target *core.BuildTarget, key []byte) { + if cache.Writeable { + artifacts := []*pb.Artifact{} + for out := range cacheArtifacts(target) { + artifacts2, err := cache.loadArtifacts(target, out) + if err != nil { + log.Warning("RPC cache failed to load artifact %s: %s", out, err) + return + } + artifacts = append(artifacts, artifacts2...) + } + cache.sendArtifacts(target, key, artifacts) + } +} + +func (cache *rpcCache) StoreExtra(target *core.BuildTarget, key []byte, file string) { + if cache.Writeable { + artifacts, err := cache.loadArtifacts(target, file) + if err != nil { + log.Warning("RPC cache failed to load artifact %s: %s", file, err) + return + } + cache.sendArtifacts(target, key, artifacts) + } +} + +func (cache *rpcCache) loadArtifacts(target *core.BuildTarget, file string) ([]*pb.Artifact, error) { + artifacts := []*pb.Artifact{} + outDir := target.OutDir() + root := path.Join(outDir, file) + err := filepath.Walk(root, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if !info.IsDir() { + content, err := ioutil.ReadFile(name) + if err != nil { + return err + } + artifacts = append(artifacts, &pb.Artifact{ + Package: target.Label.PackageName, + Target: target.Label.Name, + File: name[len(outDir)+1 : len(name)], + Body: content, + }) + } + return nil + }) + return artifacts, err +} + +func (cache *rpcCache) sendArtifacts(target *core.BuildTarget, key []byte, artifacts []*pb.Artifact) { + req := pb.StoreRequest{Artifacts: artifacts, Hash: key, Os: runtime.GOOS, Arch: runtime.GOARCH} + resp, err := cache.client.Store(context.Background(), &req) + if err != nil { + log.Warning("Error communicating with RPC cache server: %s", err) + } else if !resp.Success { + log.Warning("Failed to store artifacts in RPC cache for %s", target.Label) + } +} + +func (cache *rpcCache) Retrieve(target *core.BuildTarget, key []byte) bool { + req := pb.RetrieveRequest{Hash: key, Os: runtime.GOOS, Arch: runtime.GOARCH} + for out := range cacheArtifacts(target) { + artifact := pb.Artifact{Package: target.Label.PackageName, Target: target.Label.Name, File: out} + req.Artifacts = append(req.Artifacts, &artifact) + } + // We can't tell from here if retrieval has been successful for a target with no outputs. + // This is kind of weird but not actually disallowed, and we already have a test case for it, + // so might as well try to get it right here. + if len(req.Artifacts) == 0 { + return false + } + return cache.retrieveArtifacts(target, &req) +} + +func (cache *rpcCache) RetrieveExtra(target *core.BuildTarget, key []byte, file string) bool { + artifact := pb.Artifact{Package: target.Label.PackageName, Target: target.Label.Name, File: file} + artifacts := []*pb.Artifact{&artifact} + req := pb.RetrieveRequest{Hash: key, Os: runtime.GOOS, Arch: runtime.GOARCH, Artifacts: artifacts} + return cache.retrieveArtifacts(target, &req) +} + +func (cache *rpcCache) retrieveArtifacts(target *core.BuildTarget, req *pb.RetrieveRequest) bool { + response, err := cache.client.Retrieve(context.Background(), req) + if err != nil { + log.Warning("Failed to retrieve artifacts for %s", target.Label) + return false + } else if !response.Success { + // Quiet, this is almost certainly just a 'not found' + log.Debug("Couldn't retrieve artifacts for %s", target.Label) + return false + } + for _, artifact := range response.Artifacts { + if !cache.writeFile(target, artifact.File, artifact.Body) { + return false + } + } + return true +} + +func (cache *rpcCache) writeFile(target *core.BuildTarget, file string, body []byte) bool { + out := path.Join(target.OutDir(), file) + if err := core.WriteFile(bytes.NewReader(body), out, fileMode(target)); err != nil { + log.Warning("RPC cache failed to write file %s", err) + return false + } + log.Debug("Retrieved %s from RPC cache", target.Label) + return true +} + +func (cache *rpcCache) Clean(target *core.BuildTarget) { + if cache.Writeable { + req := pb.DeleteRequest{Os: runtime.GOOS, Arch: runtime.GOARCH} + artifact := pb.Artifact{Package: target.Label.PackageName, Target: target.Label.Name} + req.Artifacts = []*pb.Artifact{&artifact} + response, err := cache.client.Delete(context.Background(), &req) + if err != nil || !response.Success { + log.Error("Failed to remove %s from RPC cache", target.Label) + } + } +} + +func newRpcCache(config core.Configuration) (*rpcCache, error) { + // Change grpc to log using our implementation + grpclog.SetLogger(&grpcLogMabob{}) + log.Info("Connecting to RPC cache at %s", config.Cache.RpcUrl) + // TODO(pebers): Add support for communicating over https. + connection, err := grpc.Dial(config.Cache.RpcUrl, + grpc.WithBlock(), grpc.WithInsecure(), grpc.WithTimeout(time.Duration(config.Cache.RpcTimeout)*time.Second)) + if err != nil { + return nil, err + } + return &rpcCache{ + connection: connection, + client: pb.NewRpcCacheClient(connection), + Writeable: config.Cache.RpcWriteable, + }, nil +} + +// grpcLogMabob is an implementation of grpc's logging interface using our backend. +type grpcLogMabob struct{} + +func (g *grpcLogMabob) Fatal(args ...interface{}) { log.Fatal(args...) } +func (g *grpcLogMabob) Fatalf(format string, args ...interface{}) { log.Fatalf(format, args...) } +func (g *grpcLogMabob) Fatalln(args ...interface{}) { log.Fatal(args...) } +func (g *grpcLogMabob) Print(args ...interface{}) { log.Info("%s", args) } +func (g *grpcLogMabob) Printf(format string, args ...interface{}) { log.Info(format, args...) } +func (g *grpcLogMabob) Println(args ...interface{}) { log.Info("%s", args) } diff --git a/src/cache/rpc_cache_stub.go b/src/cache/rpc_cache_stub.go new file mode 100644 index 0000000000..a04fda9f24 --- /dev/null +++ b/src/cache/rpc_cache_stub.go @@ -0,0 +1,13 @@ +// Only used at initial bootstrap or when used with 'go run' so we don't have to worry +// about proto compilation until that's sorted. + +package cache + +import ( + "core" + "fmt" +) + +func newRpcCache(config core.Configuration) (*httpCache, error) { + return nil, fmt.Errorf("Config specifies RPC cache but it is not compiled") +} diff --git a/src/cache/rpc_cache_test.go b/src/cache/rpc_cache_test.go new file mode 100644 index 0000000000..ea52ab87e6 --- /dev/null +++ b/src/cache/rpc_cache_test.go @@ -0,0 +1,88 @@ +package cache + +import ( + "os" + "path" + "runtime" + "testing" + + "cache/server" + "core" + "output" +) + +var ( + label core.BuildLabel + rpccache *rpcCache + osName string +) + +func init() { + runtime.GOMAXPROCS(1) // Don't allow tests to run in parallel, they should work but makes debugging tricky + output.InitLogging(4, "", 0) + osName = runtime.GOOS + "_" + runtime.GOARCH + label = core.NewBuildLabel("pkg/name", "label/name") + + // Move this directory from test_data to somewhere local. + // This is easier than changing our working dir & a better test of some things too. + if err := os.Rename("src/cache/test_data/plz-out", "plz-out"); err != nil { + log.Fatalf("Failed to prepare test directory: %s\n", err) + } + // Arbitrary large numbers so the cleaner never needs to run. + server.Init("src/cache/test_data", 100000, 100000000, 1000000000) + + go server.ServeGrpcForever(7677) + + config := core.DefaultConfiguration() + config.Cache.RpcUrl = "localhost:7677" + config.Cache.RpcWriteable = true + + var err error + rpccache, err = newRpcCache(config) + if err != nil { + log.Fatalf("Failed to create RPC cache: %s", err) + } +} + +func TestStore(t *testing.T) { + target := core.NewBuildTarget(label) + target.AddOutput("testfile2") + rpccache.Store(target, []byte("test_key")) + expectedPath := path.Join("src/cache/test_data", osName, "pkg/name", "label/name", "dGVzdF9rZXk", target.Outputs()[0]) + if !core.PathExists(expectedPath) { + t.Errorf("Test file %s was not stored in cache.", expectedPath) + } +} + +func TestRetrieve(t *testing.T) { + target := core.NewBuildTarget(label) + target.AddOutput("testfile") + if !rpccache.Retrieve(target, []byte("test_key")) { + t.Error("Artifact expected and not found.") + } +} + +func TestStoreAndRetrieve(t *testing.T) { + target := core.NewBuildTarget(label) + target.AddOutput("testfile3") + rpccache.Store(target, []byte("test_key")) + // Remove the file so we can test retrieval correctly + outPath := path.Join(target.OutDir(), target.Outputs()[0]) + if err := os.Remove(outPath); err != nil { + t.Errorf("Failed to remove artifact: %s", err) + } + if !rpccache.Retrieve(target, []byte("test_key")) { + t.Error("Artifact expected and not found.") + } else if !core.PathExists(outPath) { + t.Errorf("Artifact %s doesn't exist after alleged cache retrieval", outPath) + } +} + +func TestClean(t *testing.T) { + target := core.NewBuildTarget(label) + rpccache.Clean(target) + filename := path.Join("src/cache/test_data", osName, "pkg/name/label/name") + if core.PathExists(filename) { + t.Errorf("File %s was not removed from cache.", filename) + } +} diff --git a/src/cache/server/BUILD b/src/cache/server/BUILD new file mode 100644 index 0000000000..22297a6842 --- /dev/null +++ b/src/cache/server/BUILD @@ -0,0 +1,67 @@ +go_library( + name = 'server', + srcs = ['http_server.go', 'rpc_server.go', 'cache.go'], + deps = [ + '//src/cache/proto:rpc_cache', + '//src/core', + '//third_party/go:mux', + '//third_party/go:logging', + '//third_party/go:humanize', + '//third_party/go:grpc', + ], + # Exposed for a test only. + visibility = ['//src/cache/...'], +) + +go_binary( + name = 'http_cache_server_bin', + main = 'http_server_main.go', + deps = [ + ':server', + '//src/output', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_binary( + name = 'rpc_cache_server_bin', + main = 'rpc_server_main.go', + deps = [ + ':server', + '//src/output', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'http_server_test', + srcs = ['http_server_test.go'], + deps = [ + ':server', + # TODO(pebers): should not need this dependency. + '//src/cache/proto:rpc_cache', + ], +) + +go_test( + name = 'rpc_server_test', + srcs = ['rpc_server_test.go'], + deps = [ + ':server', + # TODO(pebers): should not need this dependency. + '//src/cache/proto:rpc_cache', + ], +) + +go_test( + name = 'cache_test', + srcs = ['cache_test.go'], + deps = [ + ':server', + '//third_party/go:testify', + # TODO(pebers): should not need this dependency. + '//src/cache/proto:rpc_cache', + ], +) diff --git a/src/cache/server/cache.go b/src/cache/server/cache.go new file mode 100644 index 0000000000..fd5db8d5c8 --- /dev/null +++ b/src/cache/server/cache.go @@ -0,0 +1,268 @@ +// Package cache_server contains core functionality for our cache servers; storing & retrieving files etc. +package server + +import ( + "bytes" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "strings" + "sync" + "time" + + "core" +) + +// A cachedFile stores metadata about a file stored in our cache. +type cachedFile struct { + // Arbitrates single access to this file + sync.RWMutex + // Time the file was last read + lastReadTime time.Time + // Number of times the file has been read + readCount int + // Size of the file + size int64 +} + +// Handles synchronisation of storing/retrieving artifacts. +var cachedFiles = map[string]*cachedFile{} +var mutex sync.RWMutex +var totalSize int64 + +var cachePath = ".plz-cache" + +// Init initialises the cache and fires off a background cleaner goroutine which runs every +// cleanFrequency seconds. The high and low water marks control a (soft) max size and a (harder) +// minimum size. +// This causes an initial scan of the directory and is needed to retrieve any preexisting artifacts. +// If it's not called the cache will still function but won't know about anything existing beforehand. +func Init(path string, cleanFrequency int, lowWaterMark, highWaterMark int64) { + log.Notice("Initialising cache with settings:\n Path: %s\n Clean frequency: %d\n Low water mark: %d\n High water mark: %d", + path, cleanFrequency, lowWaterMark, highWaterMark) + cachePath = path + scan(path) + go clean(path, cleanFrequency, lowWaterMark, highWaterMark) +} + +// scan scans the directory tree for files. +func scan(path string) { + mutex.Lock() + defer mutex.Unlock() + cachedFiles = map[string]*cachedFile{} + totalSize = 0 + + if !core.PathExists(path) { + if err := os.MkdirAll(path, core.DirPermissions); err != nil { + log.Fatalf("Failed to create cache directory %s: %s", path, err) + } + return + } + + log.Info("Scanning cache directory %s...", path) + filepath.Walk(path, func(name string, info os.FileInfo, err error) error { + if err != nil { + log.Fatalf("%s", err) + } else if !info.IsDir() { // We don't have directory entries. + name = name[len(path)+1 : len(name)] + log.Debug("Found file %s", name) + size := info.Size() + cachedFiles[name] = &cachedFile{ + lastReadTime: time.Now(), + readCount: 0, + size: size, + } + totalSize += size + } + return nil + }) + cachePath = path + log.Info("Scan complete") +} + +// lockFile locks a file for reading or writing. +// It returns a locked mutex corresponding to that file or nil if there is none. +// The caller should .Unlock() the mutex once they're done with it. +func lockFile(path string, write bool, size int64) *cachedFile { + mutex.Lock() + defer mutex.Unlock() + file, present := cachedFiles[path] + if !present { + // If we're writing we insert a new one, if we're reading we don't. + if !write { + return nil + } + file = &cachedFile{ + lastReadTime: time.Now(), + readCount: 0, + size: size, + } + cachedFiles[path] = file + totalSize += size + } + if write { + file.Lock() + } else { + file.RLock() + file.readCount++ + } + return file +} + +// removeFile deletes a file from the cache map. It does not remove the on-disk file. +// Caller should already hold the mutex before calling this +func removeFile(path string, file *cachedFile) { + delete(cachedFiles, path) + totalSize -= file.size +} + +// RetrieveArtifact takes in the artifact path as a parameter and checks in the base server +// file directory to see if the file exists in the given path. If found, the function will +// return whatever's been stored there, which might be a directory and therefore contain +// multiple files to be returned. +func RetrieveArtifact(artPath string) (map[string][]byte, error) { + lock := lockFile(artPath, false, 0) + if lock == nil { + return nil, os.ErrNotExist + } + defer lock.RUnlock() + + fullPath := path.Join(cachePath, artPath) + ret := map[string][]byte{} + if err := filepath.Walk(fullPath, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if !info.IsDir() { + body, err := ioutil.ReadFile(name) + if err != nil { + return err + } + ret[name[len(cachePath)+1:len(name)]] = body + } + return nil + }); err != nil { + return nil, err + } + return ret, nil +} + +// StoreArtifact takes in the artifact content and path as parameters and creates a file with +// the given content in the given path. +// The function will return the first error found in the process, or nil if the process is successful. +func StoreArtifact(artPath string, key []byte) error { + log.Info("Storing artifact %s", artPath) + lock := lockFile(artPath, true, int64(len(key))) + defer lock.Unlock() + + artPath = path.Join(cachePath, artPath) + dirPath := path.Dir(artPath) + if err := os.MkdirAll(dirPath, core.DirPermissions); err != nil { + log.Warning("Couldn't create path %s in http cache: %s", dirPath, err) + return err + } + log.Debug("Writing artifact to %s", artPath) + if err := core.WriteFile(bytes.NewReader(key), artPath, 0); err != nil { + log.Error("Could not create %s artifact: %s", artPath, err) + return err + } + return nil +} + +// DeleteArtifact takes in the artifact path as a parameter and removes the artifact from disk. +// The function will return the first error found in the process, or nil if the process is successful. +func DeleteArtifact(artPath string) error { + // We need to search the entire map for prefixes. Pessimism follows... + mutex.Lock() + for p, file := range cachedFiles { + if strings.HasPrefix(p, artPath) { + file.Lock() + removeFile(path.Join(cachePath, p), file) + file.Unlock() + } + } + mutex.Unlock() + return os.RemoveAll(path.Join(cachePath, artPath)) +} + +// DeleteAllArtifacts will remove all files in the cache directory. +// The function will return the first error found in the process, or nil if the process is successful. +func DeleteAllArtifacts() error { + // Empty entire cache now. + mutex.Lock() + cachedFiles = map[string]*cachedFile{} + mutex.Unlock() + defer scan(cachePath) // Rescan whatever's left afterwards. + + files, err := ioutil.ReadDir(cachePath) + if err != nil && os.IsNotExist(err) { + log.Warning("%s directory does not exist, nothing to delete.", cachePath) + return nil + } else if err != nil { + log.Error("Error reading cache directory: %s", err) + return err + } + for _, file := range files { + p := path.Join(cachePath, file.Name()) + if err := os.RemoveAll(p); err != nil { + log.Error("Failed to remove directory %s: %s", p, err) + return err + } + } + return nil +} + +// clean implements a periodic clean of the cache to remove old artifacts. +func clean(path string, cleanFrequency int, lowWaterMark, highWaterMark int64) { + for _ = range time.NewTicker(time.Duration(cleanFrequency) * time.Second).C { + if totalSize > highWaterMark { + log.Info("Cleaning cache...") + files := filesToClean(lowWaterMark) + log.Info("Identified %d files to clean...", len(files)) + for _, file := range files { + removeFile(file.path, file.file) + if err := os.RemoveAll(file.path); err != nil { + log.Error("Failed to remove artifact: %s", err) + } + } + } + } +} + +// cachedFilePath embeds a cachedFile but with the path too. +type cachedFilePath struct { + file *cachedFile + path string +} + +type cachedFilePaths []cachedFilePath + +func (c cachedFilePaths) Len() int { return len(c) } +func (c cachedFilePaths) Swap(i, j int) { c[i], c[j] = c[j], c[i] } +func (c cachedFilePaths) Less(i, j int) bool { + return c[i].file.lastReadTime.Before(c[j].file.lastReadTime) +} + +// filesToClean returns a list of files that should be cleaned, ie. the least interesting +// artifacts in the cache according to some heuristic. Removing all of them will be +// sufficient to reduce the cache size below lowWaterMark. +func filesToClean(lowWaterMark int64) cachedFilePaths { + mutex.Lock() + ret := make(cachedFilePaths, 0, len(cachedFiles)) + for path, file := range cachedFiles { + ret = append(ret, cachedFilePath{file: file, path: path}) + } + mutex.Unlock() + sort.Sort(&ret) + + sizeToDelete := totalSize - lowWaterMark + var sizeDeleted int64 + for i, file := range ret { + if sizeDeleted >= sizeToDelete { + return ret[0:i] + } + sizeDeleted += file.file.size + } + return ret +} diff --git a/src/cache/server/cache_test.go b/src/cache/server/cache_test.go new file mode 100644 index 0000000000..8b5628b011 --- /dev/null +++ b/src/cache/server/cache_test.go @@ -0,0 +1,31 @@ +// Tests for the core cache functionality +package server + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestFilesToClean(t *testing.T) { + cachedFiles["test/artifact/1"] = &cachedFile{ + lastReadTime: time.Now().AddDate(0, 0, -2), + readCount: 0, + size: 1000, + } + cachedFiles["test/artifact/2"] = &cachedFile{ + lastReadTime: time.Now().AddDate(0, 0, -5), + readCount: 0, + size: 1000, + } + cachedFiles["test/artifact/3"] = &cachedFile{ + lastReadTime: time.Now().AddDate(0, 0, -1), + readCount: 0, + size: 1000, + } + totalSize = 3000 + + paths := filesToClean(1700) + assert.Equal(t, 2, len(paths)) +} diff --git a/src/cache/server/http_server.go b/src/cache/server/http_server.go new file mode 100644 index 0000000000..773d41d007 --- /dev/null +++ b/src/cache/server/http_server.go @@ -0,0 +1,126 @@ +package server + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "mime/multipart" + "net/http" + "os" + "path" + "path/filepath" + "strings" + + "github.com/gorilla/mux" + "github.com/op/go-logging" +) + +var log = logging.MustGetLogger("server") + +// The pingHandler will return a 200 Accepted status +// This handler will handle ping endpoint requests, in order to confirm whether the server can be accessed +func pingHandler(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Server connection established successfully.") +} + +// The getHandler function handles the GET endpoint for the artifact path. +// It calls the RetrieveArtifact function, and then either returns the found artifact, or logs the error +// returned by RetrieveArtifact. +func getHandler(w http.ResponseWriter, r *http.Request) { + log.Debug("GET %s", r.URL.Path) + artifactPath := strings.TrimPrefix(r.URL.Path, "/artifact/") + + art, err := RetrieveArtifact(artifactPath) + if err != nil && os.IsNotExist(err) { + w.WriteHeader(http.StatusNotFound) + log.Debug("%s doesn't exist in http cache", artifactPath) + return + } else if err != nil { + log.Error("Failed to retrieve artifact %s: %s", artifactPath, err) + w.WriteHeader(http.StatusInternalServerError) + return + } + + // In order to handle directories we use multipart encoding. + // Note that we don't bother on the upload because the client knows all the parts and can + // send individually; here they don't know what they'll need to expect. + // We could use it for upload too which might be faster and would be more symmetric, but + // multipart is a bit fiddly so for now we're not bothering. + mw := multipart.NewWriter(w) + defer mw.Close() + w.Header().Set("Content-Type", mw.FormDataContentType()) + for name, body := range art { + if part, err := mw.CreateFormFile(name, name); err != nil { + log.Error("Failed to create form file %s: %s", name, err) + w.WriteHeader(http.StatusInternalServerError) + } else if _, err := io.Copy(part, bytes.NewReader(body)); err != nil { + log.Error("Failed to write form file %s: %s", name, err) + w.WriteHeader(http.StatusInternalServerError) + } + } +} + +// The postHandler function handles the POST endpoint for the artifact path. +// It reads the request body and sends it to the StoreArtifact function, along with the path where it should +// be stored. +// The handler will either return an error or display a message confirming the file has been created. +func postHandler(w http.ResponseWriter, r *http.Request) { + log.Debug("POST %s", r.URL.Path) + artifact, err := ioutil.ReadAll(r.Body) + filePath, fileName := path.Split(strings.TrimPrefix(r.URL.Path, "/artifact")) + if err == nil { + if err := StoreArtifact(strings.TrimPrefix(r.URL.Path, "/artifact"), artifact); err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Error("Failed to store artifact %s: %s", fileName, err) + return + } + absPath, _ := filepath.Abs(filePath) + fmt.Fprintf(w, "%s was created in %s.", fileName, absPath) + log.Notice("%s was stored in the http cache.", fileName) + } else { + w.WriteHeader(http.StatusInternalServerError) + log.Error("Failed to store artifact %s: %s", fileName, err) + } +} + +// The deleteAllHandler function handles the DELETE endpoint for the general server path. +// It calls the DeleteAllArtifacts function. +// The handler will either return an error or display a message confirming the files have been removed. +func deleteAllHandler(w http.ResponseWriter, r *http.Request) { + if err := DeleteAllArtifacts(); err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Error("Failed to clean http cache: %s", err) + return + } else { + log.Notice("The http cache has been cleaned.") + fmt.Fprintf(w, "The http cache has been cleaned.") + } +} + +// The deleteHandler function handles the DELETE endpoint for the artifact path. +// It calls the DeleteArtifact function, sending the path of the artifact as a parameter. +// The handler will either return an error or display a message confirming the artifact has been removed. +func deleteHandler(w http.ResponseWriter, r *http.Request) { + artifactPath := strings.TrimPrefix(r.URL.Path, "/artifact") + if err := DeleteArtifact(artifactPath); err != nil { + w.WriteHeader(http.StatusInternalServerError) + log.Error("Failed to remove %s from http cache: %s", artifactPath, err) + return + } else { + log.Notice("%s was removed from the http cache.", artifactPath) + fmt.Fprintf(w, "%s artifact was removed from cache.", artifactPath) + } +} + +// The BuildRouter function creates a router, sets the base FileServer directory and the Handler Functions +// for each endpoint, and then returns the router. +func BuildRouter() *mux.Router { + r := mux.NewRouter() + r.HandleFunc("/ping", pingHandler).Methods("GET") + r.HandleFunc("/artifact/{os_name}/{artifact:.*}", getHandler).Methods("GET") + r.HandleFunc("/artifact/{os_name}/{artifact:.*}", postHandler).Methods("POST") + r.HandleFunc("/artifact/{artifact:.*}", deleteHandler).Methods("DELETE") + r.HandleFunc("/", deleteAllHandler).Methods("DELETE") + return r +} diff --git a/src/cache/server/http_server_main.go b/src/cache/server/http_server_main.go new file mode 100644 index 0000000000..c78d564c80 --- /dev/null +++ b/src/cache/server/http_server_main.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/op/go-logging" + + "cache/server" + "output" +) + +var log = logging.MustGetLogger("http_cache_server") + +var opts struct { + Verbosity int `short:"v" long:"verbosity" description:"Verbosity of output (higher number = more output, default 2 -> notice, warnings and errors only)" default:"2"` + Port int `short:"p" long:"port" description:"Port to serve on" default:"8080"` + Dir string `short:"d" long:"dir" description:"Directory to write into" default:"plz-http-cache"` + LowWaterMark output.ByteSize `short:"l" long:"low_water_mark" description:"Size of cache to clean down to" default:"18G"` + HighWaterMark output.ByteSize `short:"i" long:"high_water_mark" description:"Max size of cache to clean at" default:"20G"` + CleanFrequency int `short:"f" long:"clean_frequency" description:"Frequency to clean cache at, in seconds" default:"10"` +} + +func main() { + output.ParseFlagsOrDie("Please RPC cache server", &opts) + output.InitLogging(opts.Verbosity, "", 0) + log.Notice("Initialising cache server...") + server.Init(opts.Dir, opts.CleanFrequency, int64(opts.LowWaterMark), int64(opts.HighWaterMark)) + log.Notice("Starting up http cache server on port %d...", opts.Port) + router := server.BuildRouter() + http.Handle("/", router) + http.ListenAndServe(fmt.Sprintf(":%d", opts.Port), router) +} diff --git a/src/cache/server/http_server_test.go b/src/cache/server/http_server_test.go new file mode 100644 index 0000000000..bdf71cc15f --- /dev/null +++ b/src/cache/server/http_server_test.go @@ -0,0 +1,170 @@ +package server + +import ( + "fmt" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + + "core" +) + +var ( + server *httptest.Server + realURL string + fakeURL string + otherRealURL string + extraRealURL string + reader io.Reader +) + +func init() { + server = httptest.NewServer(BuildRouter()) + if !core.PathExists(cachePath + "/darwin_amd64/pack/label/hash/") { + _ = os.MkdirAll(cachePath+"/darwin_amd64/pack/label/hash/", core.DirPermissions) + _, _ = os.Create(cachePath + "/darwin_amd64/pack/label/hash/" + "label.ext") + } + if !core.PathExists(cachePath + "/linux_amd64/otherpack/label/hash/") { + _ = os.MkdirAll(cachePath+"/linux_amd64/otherpack/label/hash/", core.DirPermissions) + _, _ = os.Create(cachePath + "/linux_amd64/otherpack/label/hash/" + "label.ext") + } + if !core.PathExists(cachePath + "/linux_amd64/extrapack/label/hash/") { + _ = os.MkdirAll(cachePath+"/linux_amd64/extrapack/label/hash/", core.DirPermissions) + _, _ = os.Create(cachePath + "/linux_amd64/extrapack/label/hash/" + "label.ext") + } + + // Don't call init to kick off the cleaner goroutine + scan(cachePath) + + realURL = fmt.Sprintf("%s/artifact/darwin_amd64/pack/label/hash/label.ext", server.URL) + otherRealURL = fmt.Sprintf("%s/artifact/linux_amd64/otherpack/label/hash/label.ext", server.URL) + extraRealURL = fmt.Sprintf("%s/artifact/extrapack/label", server.URL) + fakeURL = fmt.Sprintf("%s/artifact/darwin_amd64/somepack/somelabel/somehash/somelabel.ext", server.URL) +} + +func TestOutputFolderExists(t *testing.T) { + if !core.PathExists(cachePath) { + t.Errorf("%s does not exist.", cachePath) + } +} + +func TestRetrieve(t *testing.T) { + artifact, err := RetrieveArtifact("darwin_amd64/pack/label/hash/label.ext") + if err != nil { + t.Error(err) + return + } + if artifact == nil { + t.Error("Expected artifact and found nil.") + } +} + +func TestRetrieveError(t *testing.T) { + artifact, err := RetrieveArtifact(cachePath + "/darwin_amd64/somepack/somelabel/somehash/somelabel.ext") + if artifact != nil { + t.Error("Expected nil and found artifact.") + } + if err == nil { + t.Error("Expected error and found nil.") + } +} + +func TestGetHandler(t *testing.T) { + request, err := http.NewRequest("GET", realURL, reader) + res, err := http.DefaultClient.Do(request) + + if err != nil { + t.Error(err) + } + if res.StatusCode < 200 || res.StatusCode > 299 { + t.Error("Expected response Status Accepted, got:", res.Status) + } +} + +func TestGetHandlerError(t *testing.T) { + request, _ := http.NewRequest("GET", fakeURL, reader) + res, _ := http.DefaultClient.Do(request) + if res.StatusCode != 404 { + t.Error("Expected nil and found artifact.") + } +} + +func TestStore(t *testing.T) { + fileContent := "This is a newly created file." + reader = strings.NewReader(fileContent) + key, err := ioutil.ReadAll(reader) + + err = StoreArtifact("/darwin_amd64/somepack/somelabel/somehash/somelabel.ext", key) + if err != nil { + t.Error(err) + } +} + +func TestPostHandler(t *testing.T) { + fileContent := "This is a newly created file." + reader = strings.NewReader(fileContent) + request, err := http.NewRequest("POST", fakeURL, reader) + res, err := http.DefaultClient.Do(request) + + if err != nil { + t.Error(err) + } + + if res.StatusCode < 200 || res.StatusCode > 299 { + t.Error("Expected response Status Accepted, got:", res.Status) + } +} + +func TestDeleteArtifact(t *testing.T) { + err := DeleteArtifact("/linux_amd64/otherpack/label") + if err != nil { + t.Error(err) + } + absPath, _ := filepath.Abs(cachePath + "/linux_amd64/otherpack/label") + if core.PathExists(absPath) { + t.Errorf("%s was not removed from cache.", absPath) + } +} + +func TestDeleteHandler(t *testing.T) { + request, _ := http.NewRequest("DELETE", extraRealURL, reader) + res, err := http.DefaultClient.Do(request) + if err != nil { + t.Error(err) + } + + if res.StatusCode < 200 || res.StatusCode > 299 { + t.Error("Expected response Status Accepted, got:", res.Status) + } + +} + +func TestDeleteAll(t *testing.T) { + err := DeleteAllArtifacts() + if err != nil { + t.Error(err) + } + absPath, _ := filepath.Abs(cachePath) + if files, _ := ioutil.ReadDir(absPath); len(files) != 0 { + + t.Error(files[0].Name()) + t.Error("The cache was not cleaned.") + } +} + +func TestDeleteAllHandler(t *testing.T) { + request, _ := http.NewRequest("DELETE", server.URL, reader) + res, err := http.DefaultClient.Do(request) + if err != nil { + t.Error(err) + } + + if res.StatusCode < 200 || res.StatusCode > 299 { + t.Error("Expected response Status Accepted, got:", res.Status) + } +} diff --git a/src/cache/server/rpc_server.go b/src/cache/server/rpc_server.go new file mode 100644 index 0000000000..0fd0e5be45 --- /dev/null +++ b/src/cache/server/rpc_server.go @@ -0,0 +1,75 @@ +// Test only at this point to make sure we can build grpc correctly. +// Later this will turn into a proper RPC cache server implementation. +package server + +import ( + "encoding/base64" + "fmt" + "net" + "path" + + "golang.org/x/net/context" + "google.golang.org/grpc" + + pb "cache/proto/rpc_cache" +) + +type RpcCacheServer struct{} + +func (*RpcCacheServer) Store(ctx context.Context, req *pb.StoreRequest) (*pb.StoreResponse, error) { + arch := req.Os + "_" + req.Arch + hash := base64.RawStdEncoding.EncodeToString(req.Hash) + for _, artifact := range req.Artifacts { + path := path.Join(arch, artifact.Package, artifact.Target, hash, artifact.File) + if err := StoreArtifact(path, artifact.Body); err != nil { + return &pb.StoreResponse{Success: false}, nil + } + } + return &pb.StoreResponse{Success: true}, nil +} + +func (*RpcCacheServer) Retrieve(ctx context.Context, req *pb.RetrieveRequest) (*pb.RetrieveResponse, error) { + response := pb.RetrieveResponse{Success: true} + arch := req.Os + "_" + req.Arch + hash := base64.RawStdEncoding.EncodeToString(req.Hash) + for _, artifact := range req.Artifacts { + root := path.Join(arch, artifact.Package, artifact.Target, hash) + fileRoot := path.Join(root, artifact.File) + art, err := RetrieveArtifact(fileRoot) + if err != nil { + log.Debug("Failed to retrieve artifact %s: %s", fileRoot, err) + return &pb.RetrieveResponse{Success: false}, nil + } + for name, body := range art { + response.Artifacts = append(response.Artifacts, &pb.Artifact{ + Package: artifact.Package, + Target: artifact.Target, + File: name[len(root)+1 : len(name)], + Body: body, + }) + } + } + return &response, nil +} + +func (*RpcCacheServer) Delete(ctx context.Context, req *pb.DeleteRequest) (*pb.DeleteResponse, error) { + if req.Everything { + return &pb.DeleteResponse{Success: DeleteAllArtifacts() == nil}, nil + } + success := true + arch := req.Os + "_" + req.Arch + for _, artifact := range req.Artifacts { + success = success && (DeleteArtifact(path.Join(arch, artifact.Package, artifact.Target)) == nil) + } + return &pb.DeleteResponse{Success: success}, nil +} + +func ServeGrpcForever(port int) { + lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + log.Fatalf("Failed to listen on port %d: %v", port, err) + } + s := grpc.NewServer() + pb.RegisterRpcCacheServer(s, &RpcCacheServer{}) + s.Serve(lis) +} diff --git a/src/cache/server/rpc_server_main.go b/src/cache/server/rpc_server_main.go new file mode 100644 index 0000000000..099e736acf --- /dev/null +++ b/src/cache/server/rpc_server_main.go @@ -0,0 +1,28 @@ +package main + +import ( + "github.com/op/go-logging" + + "cache/server" + "output" +) + +var log = logging.MustGetLogger("rpc_cache_server") + +var opts struct { + Verbosity int `short:"v" long:"verbosity" description:"Verbosity of output (higher number = more output, default 2 -> notice, warnings and errors only)" default:"2"` + Port int `short:"p" long:"port" description:"Port to serve on" default:"7677"` + Dir string `short:"d" long:"dir" description:"Directory to write into" default:"plz-rpc-cache"` + LowWaterMark output.ByteSize `short:"l" long:"low_water_mark" description:"Size of cache to clean down to" default:"18G"` + HighWaterMark output.ByteSize `short:"i" long:"high_water_mark" description:"Max size of cache to clean at" default:"20G"` + CleanFrequency int `short:"f" long:"clean_frequency" description:"Frequency to clean cache at, in seconds" default:"10"` +} + +func main() { + output.ParseFlagsOrDie("Please RPC cache server", &opts) + output.InitLogging(opts.Verbosity, "", 0) + log.Notice("Scanning existing cache directory %s...", opts.Dir) + server.Init(opts.Dir, opts.CleanFrequency, int64(opts.LowWaterMark), int64(opts.HighWaterMark)) + log.Notice("Starting up RPC cache server on port %d...", opts.Port) + server.ServeGrpcForever(opts.Port) +} diff --git a/src/cache/server/rpc_server_test.go b/src/cache/server/rpc_server_test.go new file mode 100644 index 0000000000..5846737bd8 --- /dev/null +++ b/src/cache/server/rpc_server_test.go @@ -0,0 +1,10 @@ +// Test for the rpc server. +package server + +import ( + "testing" +) + +func TestRpcServer(t *testing.T) { + // Do nothing, for now we just want to test it builds correctly. +} diff --git a/src/cache/test_data/darwin_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile b/src/cache/test_data/darwin_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile new file mode 100644 index 0000000000..3b30906789 --- /dev/null +++ b/src/cache/test_data/darwin_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile @@ -0,0 +1 @@ +test file for http cache diff --git a/src/cache/test_data/linux_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile b/src/cache/test_data/linux_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile new file mode 100644 index 0000000000..3b30906789 --- /dev/null +++ b/src/cache/test_data/linux_amd64/pkg/name/label/name/dGVzdF9rZXk/testfile @@ -0,0 +1 @@ +test file for http cache diff --git a/src/cache/test_data/plz-out/gen/pkg/name/testfile2 b/src/cache/test_data/plz-out/gen/pkg/name/testfile2 new file mode 100644 index 0000000000..e29b9b7bdf --- /dev/null +++ b/src/cache/test_data/plz-out/gen/pkg/name/testfile2 @@ -0,0 +1,2 @@ +test file to be stored for rpc cache + diff --git a/src/cache/test_data/plz-out/gen/pkg/name/testfile3 b/src/cache/test_data/plz-out/gen/pkg/name/testfile3 new file mode 100644 index 0000000000..193f1d193a --- /dev/null +++ b/src/cache/test_data/plz-out/gen/pkg/name/testfile3 @@ -0,0 +1 @@ +test file to be stored & retrieved for rpc cache diff --git a/src/cache/tools/BUILD b/src/cache/tools/BUILD new file mode 100644 index 0000000000..43d04a3ca3 --- /dev/null +++ b/src/cache/tools/BUILD @@ -0,0 +1,30 @@ +go_binary( + name = 'cache_cleaner', + main = ':cache_cleaner_platform', + deps = [ + '//src/output', + '//third_party/go:logging', + '//third_party/go:humanize', + ], + visibility = ['PUBLIC'], +) + +# Bit of a fiddle to do conditional compilation (weirdly, Go's isn't working for me). +genrule( + name = 'cache_cleaner_platform', + srcs = ['cache_cleaner.go'], + outs = ['cache_cleaner_platform.go'], + cmd = ('cat $SRC | sed -e "s/stat.Atim.Sec/stat.Atimespec.Sec/g" > $OUT' + if CONFIG.OS == 'darwin' else 'cp $SRC $OUT') +) + +go_test( + name = 'cache_cleaner_test', + srcs = ['cache_cleaner_test.go', ':cache_cleaner_platform'], + deps = [ + '//src/output', + '//third_party/go:logging', + '//third_party/go:humanize', + '//third_party/go:testify', + ], +) diff --git a/src/cache/tools/cache_cleaner.go b/src/cache/tools/cache_cleaner.go new file mode 100644 index 0000000000..8b89b97b16 --- /dev/null +++ b/src/cache/tools/cache_cleaner.go @@ -0,0 +1,116 @@ +// Small program to clean directory cache. +// This is actually fairly tricky since Please doesn't have a daemon managing it; +// we don't particularly want that so instead we fire off one of these processes +// at each invocation of 'build' or 'test' to check the cache size and clean out stuff +// if it looks too big. + +package main + +import ( + "os" + "path/filepath" + "sort" + "syscall" + "time" + + "github.com/dustin/go-humanize" + "github.com/op/go-logging" + + "output" +) + +var log = logging.MustGetLogger("cache_cleaner") + +// Period of time in seconds between which two artifacts are considered to have the same atime. +const accessTimeGracePeriod = 600 // Ten minutes + +type CacheEntry struct { + Path string + Size int64 + Atime int64 +} +type CacheEntries []CacheEntry + +func (entries CacheEntries) Len() int { return len(entries) } +func (entries CacheEntries) Swap(i, j int) { entries[i], entries[j] = entries[j], entries[i] } +func (entries CacheEntries) Less(i, j int) bool { + diff := entries[i].Atime - entries[j].Atime + if diff > -accessTimeGracePeriod && diff < accessTimeGracePeriod { + return entries[i].Size > entries[j].Size + } + return entries[i].Atime < entries[j].Atime +} + +func findSize(path string) (int64, error) { + var totalSize int64 = 0 + if err := filepath.Walk(path, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } else { + totalSize += info.Size() + return nil + } + }); err != nil { + return 0, err + } else { + return totalSize, nil + } +} + +func start(directory string, highWaterMark, lowWaterMark int64) { + entries := CacheEntries{} + var totalSize int64 = 0 + if err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if len(info.Name()) == 28 && info.Name()[27] == '=' { + // Directory has the right length. We do this in an attempt to clean only entire + // entries in the cache, not just individual files from them. + // 28 == length of 20-byte sha1 hash, encoded to base64, which always gets a trailing = + // as padding so we can check that to be "sure". + if size, err := findSize(path); err != nil { + return err + } else { + stat := info.Sys().(*syscall.Stat_t) + entries = append(entries, CacheEntry{path, size, stat.Atim.Sec}) + totalSize += size + return filepath.SkipDir + } + } else { + return nil // nothing particularly to do for other entries + } + }); err != nil { + log.Fatalf("error walking cache directory: %s\n", err) + } + log.Notice("Total cache size: %s", humanize.Bytes(uint64(totalSize))) + if totalSize < highWaterMark { + return // Nothing to do, cache is small enough. + } + // OK, we need to slim it down a bit. We implement a simple LRU algorithm. + sort.Sort(entries) + for _, entry := range entries { + log.Notice("Cleaning %s, accessed %s, saves %s", entry.Path, humanize.Time(time.Unix(entry.Atime, 0)), humanize.Bytes(uint64(entry.Size))) + if err := os.RemoveAll(entry.Path); err != nil { + log.Error("Couldn't remove %s: %s", entry.Path, err) + continue + } + totalSize -= entry.Size + if totalSize < lowWaterMark { + break + } + } +} + +var opts struct { + Verbosity int `short:"v" long:"verbosity" description:"Verbosity of output (higher number = more output, default 2 -> notice, warnings and errors only)" default:"2"` + LowWaterMark output.ByteSize `short:"l" long:"low_water_mark" description:"Size of cache to clean down to" default:"8G"` + HighWaterMark output.ByteSize `short:"i" long:"high_water_mark" description:"Max size of cache to clean at" default:"10G"` + Directory string `short:"d" long:"dir" required:"true" description:"Location of cache directory"` +} + +func main() { + output.ParseFlagsOrDie("Please directory cache cleaner", &opts) + output.InitLogging(opts.Verbosity, "", 0) + start(opts.Directory, int64(opts.HighWaterMark), int64(opts.LowWaterMark)) + os.Exit(0) +} diff --git a/src/cache/tools/cache_cleaner_test.go b/src/cache/tools/cache_cleaner_test.go new file mode 100644 index 0000000000..829e0346be --- /dev/null +++ b/src/cache/tools/cache_cleaner_test.go @@ -0,0 +1,49 @@ +package main + +import ( + "sort" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCacheEntriesSortByTime(t *testing.T) { + entries := CacheEntries{ + CacheEntry{Path: "path1", Size: 1000, Atime: 1449488976}, + CacheEntry{Path: "path2", Size: 1000, Atime: 1449688978}, + CacheEntry{Path: "path3", Size: 1000, Atime: 1449588977}, + } + sort.Sort(entries) + // Oldest first. + assert.Equal(t, "path1", entries[0].Path) + assert.Equal(t, "path3", entries[1].Path) + assert.Equal(t, "path2", entries[2].Path) +} + +func TestCacheEntriesSortBySizeAfterTime(t *testing.T) { + entries := CacheEntries{ + CacheEntry{Path: "path1", Size: 10, Atime: 1449488976}, + CacheEntry{Path: "path2", Size: 100000, Atime: 1449488976}, + CacheEntry{Path: "path3", Size: 1000, Atime: 1449488976}, + } + sort.Sort(entries) + // Largest first. + assert.Equal(t, "path2", entries[0].Path) + assert.Equal(t, "path3", entries[1].Path) + assert.Equal(t, "path1", entries[2].Path) +} + +func TestCacheEntriesSortingWithTolerance(t *testing.T) { + entries := CacheEntries{ + CacheEntry{Path: "path1", Size: 10, Atime: 1449488976}, + CacheEntry{Path: "path2", Size: 100000, Atime: 1449488978}, + CacheEntry{Path: "path3", Size: 1000, Atime: 1449488977}, + } + sort.Sort(entries) + // Similar to the previous test, but times aren't exactly the same; we should prefer to + // delete the 100kB file over the 10B one, it being two seconds newer shouldn't be enough + // to save it. + assert.Equal(t, "path2", entries[0].Path) + assert.Equal(t, "path3", entries[1].Path) + assert.Equal(t, "path1", entries[2].Path) +} diff --git a/src/clean/BUILD b/src/clean/BUILD new file mode 100644 index 0000000000..3f4b5b16f2 --- /dev/null +++ b/src/clean/BUILD @@ -0,0 +1,10 @@ +go_library( + name = 'clean', + srcs = glob(['*.go']), + deps = [ + '//src/core', + '//src/test', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) diff --git a/src/clean/clean.go b/src/clean/clean.go new file mode 100644 index 0000000000..979a8a74b6 --- /dev/null +++ b/src/clean/clean.go @@ -0,0 +1,110 @@ +// Code for cleaning Please build artifacts. + +package clean + +import ( + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "syscall" + + "github.com/op/go-logging" + + "core" + "test" +) + +var log = logging.MustGetLogger("clean") + +// Clean cleans the output directory and optionally the cache as well. +// If labels is non-empty then only those specific targets will be wiped, otherwise +// everything will be removed. +func Clean(state *core.BuildState, labels []core.BuildLabel, cleanCache, background bool) { + if len(labels) == 0 { + if background { + if err := maybeFork(core.OutDir, state.Config.Cache.Dir, cleanCache); err != nil { + log.Warning("Couldn't run clean in background; will do it synchronously: %s", err) + } + } + if cleanCache { + clean(state.Config.Cache.Dir) + } + clean(core.OutDir) + } else { + for _, label := range labels { + cleanTarget(state, state.Graph.TargetOrDie(label), cleanCache) + } + } +} + +func cleanTarget(state *core.BuildState, target *core.BuildTarget, cleanCache bool) { + for _, out := range target.Outputs() { + clean(path.Join(target.OutDir(), out)) + } + if target.IsTest { + if err := test.RemoveCachedTestFiles(target); err != nil { + log.Fatalf("Failed to remove file: %s", err) + } + } + if cleanCache && state.Cache != nil { + (*state.Cache).Clean(target) + } +} + +func clean(what string) { + dir := path.Join(core.RepoRoot, what) + if !core.PathExists(dir) { + // Out path doesn't exist. Nothing to do. + log.Info("Path %s not found, nothing to do.", dir) + return + } + log.Info("Cleaning path %s", dir) + if err := os.RemoveAll(dir); err != nil { + log.Fatalf("Failed to clean path %s: %s", dir, err) + } +} + +// maybeFork will fork & detach if background is true. First it will rename the out and +// cache dirs so it's safe to run another plz in this repo, then fork & detach child +// processes to do the actual cleaning. +// The parent will then die quietly and the children will continue to actually remove the +// directories. +func maybeFork(outDir, cacheDir string, cleanCache bool) error { + rm, err := exec.LookPath("rm") + if err != nil { + return err + } + if !core.PathExists(outDir) || !core.PathExists(cacheDir) { + return nil + } + newOutDir, err := moveDir(outDir) + if err != nil { + return err + } + newCacheDir, err := moveDir(cacheDir) + if err != nil { + return err + } + // Note that we can't fork() directly and continue running Go code, but ForkExec() works okay. + _, err = syscall.ForkExec(rm, []string{rm, "-rf", newOutDir, newCacheDir}, nil) + if err == nil { + // Success if we get here. + fmt.Println("Cleaning in background; you may continue to do pleasing things in this repo in the meantime.") + os.Exit(0) + } + return err +} + +// moveDir moves a directory to a new location and returns that new location. +func moveDir(dir string) (string, error) { + name, err := ioutil.TempDir(filepath.Dir(dir), ".plz_clean_") + if err != nil { + return "", err + } + log.Notice("Moving %s to %s", dir, name) + return name, os.Rename(dir, name) +} + diff --git a/src/core/BUILD b/src/core/BUILD new file mode 100644 index 0000000000..c82b29636c --- /dev/null +++ b/src/core/BUILD @@ -0,0 +1,68 @@ +genrule( + name = 'config', + srcs = {'go': ['config.go'], 'version': ['//:version']}, + outs = ['config_versioned.go'], + cmd = 'sed "s//`cat $SRCS_VERSION`/" $SRCS_GO > $OUT', +) + +go_library( + name = 'core', + srcs = glob(['*.go'], excludes=['*_test.go', 'config.go']) + [':config'], + visibility = ['PUBLIC'], + deps = [ + '//third_party/go:gcfg', + '//third_party/go:logging', + ] +) + +go_test( + name = 'config_test', + srcs = ['config_test.go'], + deps = [ + ':core', + '//third_party/go:testify', + ], + data = glob(['test_data/*.plzconfig']), +) + +go_test( + name = 'label_parse_test', + srcs = ['label_parse_test.go'], + deps = [ + ':core', + ], +) + +go_test( + name = 'state_test', + srcs = ['state_test.go'], + deps = [ + ':core', + ], +) + +go_test( + name = 'build_target_test', + srcs = ['build_target_test.go'], + deps = [ + ':core', + '//third_party/go:testify', + ], +) + +go_test( + name = 'build_env_test', + srcs = ['build_env_test.go'], + deps = [ + ':core' + ], +) + +go_test( + name = 'utils_test', + srcs = ['utils_test.go'], + deps = [ + ':core', + '//third_party/go:testify', + ], +) diff --git a/src/core/build_env.go b/src/core/build_env.go new file mode 100644 index 0000000000..3f30f5d674 --- /dev/null +++ b/src/core/build_env.go @@ -0,0 +1,66 @@ +package core + +import ( + "os" + "path" + "regexp" + "runtime" + "strings" +) + +var home = os.Getenv("HOME") +var homeRex = regexp.MustCompile("(?:^|:)(~(?:[/:]|$))") + +// Expand all prefixes of ~ without a user specifier TO $HOME. +// NB: this will break on recursive calls to plz +func expandHomePath(path string) string { + return homeRex.ReplaceAllStringFunc(path, func(subpath string) string { + return strings.Replace(subpath, "~", home, -1) + }) +} + +// BuildEnvironment state target test creates the shell env vars to be passed +// into the exec.Command calls made by plz. Use test=true for plz test targets. +func BuildEnvironment(state *BuildState, target *BuildTarget, test bool) []string { + sources := target.AllSourcePaths(state.Graph) + env := []string{ + "PKG="+target.Label.PackageName, + // Need to know these for certain rules, particularly Go rules. + "ARCH=" + runtime.GOARCH, + "OS=" + runtime.GOOS, + // Need this for certain tools, for example sass + "LANG=" + state.Config.Please.Lang, + // Use a restricted PATH; it'd be easier for the user if we pass it through + // but really external environment variables shouldn't affect this. + // The only concession is that ~ is expanded as the user's home directory + // in PATH entries. + "PATH=" + expandHomePath(strings.Join(state.Config.Build.Path, ":")), + } + if !test { + env = append(env, + "TMP_DIR="+path.Join(RepoRoot, target.TmpDir()), + "SRCS="+strings.Join(sources, " "), + "OUTS="+strings.Join(target.Outputs(), " "), + "NAME="+target.Label.Name, + ) + // The OUT variable is only available on rules that have a single output. + if len(target.Outputs()) == 1 { + env = append(env, "OUT="+path.Join(RepoRoot, target.TmpDir(), target.Outputs()[0])) + } + // The SRC variable is only available on rules that have a single source file. + if len(sources) == 1 { + env = append(env, "SRC="+sources[0]) + } + // Named source groups if the target declared any. + for name, srcs := range target.NamedSources { + paths := target.SourcePaths(state.Graph, srcs) + env = append(env, "SRCS_"+strings.ToUpper(name)+"="+strings.Join(paths, " ")) + } + } else { + env = append(env, "TEST_DIR="+path.Join(RepoRoot, target.TestDir())) + if state.NeedCoverage { + env = append(env, "COVERAGE=true") + } + } + return env +} diff --git a/src/core/build_env_test.go b/src/core/build_env_test.go new file mode 100644 index 0000000000..c77613b66d --- /dev/null +++ b/src/core/build_env_test.go @@ -0,0 +1,26 @@ +package core + +import ( + "os" + "testing" +) + +func TestExpandHomePath(t *testing.T) { + HOME := os.Getenv("HOME") + cases := []struct { + in, want string + }{ + {"", ""}, + {"~", HOME}, + {"~username", "~username"}, + {"~:/bin/~:/usr/local", HOME + ":/bin/~:/usr/local"}, + {"/bin:~/bin:~/script:/usr/local/bin", + "/bin:" + HOME + "/bin:" + HOME + "/script:/usr/local/bin"}, + } + for _, c := range cases { + got := expandHomePath(c.in) + if got != c.want { + t.Errorf("ExpandHomePath(%q) == %q, want %q", c.in, got, c.want) + } + } +} diff --git a/src/core/build_label.go b/src/core/build_label.go new file mode 100644 index 0000000000..d1a9314572 --- /dev/null +++ b/src/core/build_label.go @@ -0,0 +1,234 @@ +package core + +import ( + "path" + "regexp" + "strings" + + "fmt" + "github.com/op/go-logging" +) + +var log = logging.MustGetLogger("core") + +// Representation of an identifier of a build target, eg. //spam/eggs:ham +// corresponds to BuildLabel{PackageName: spam/eggs name: ham} +// BuildLabels are always absolute, so relative identifiers +// like :ham are always parsed into an absolute form. +// There is also implicit expansion of the final element of a target (ala Blaze) +// so //spam/eggs is equivalent to //spam/eggs:eggs +type BuildLabel struct { + PackageName string + Name string +} + +// Build label that represents parsing the entire graph. +// We use this specially in one or two places. +var WholeGraph = []BuildLabel{{PackageName: "", Name: "..."}} + +// Used to indicate that we're going to consume build labels from stdin. +var BuildLabelStdin = BuildLabel{PackageName: "", Name: "_STDIN"} + +// Used to indicate one of the originally requested targets on the command line. +var OriginalTarget = BuildLabel{PackageName: "", Name: "_ORIGINAL"} + +// This is a little strict; doesn't allow for non-ascii names, for example. +var absoluteTarget = regexp.MustCompile("^//([A-Za-z0-9\\._/-]*):([A-Za-z0-9\\._#+-]+)$") +var localTarget = regexp.MustCompile("^:([A-Za-z0-9\\._#+-]+)$") +var implicitTarget = regexp.MustCompile("^//([A-Za-z0-9\\._/-]+/)?([A-Za-z0-9\\._-]+)$") +var subTargets = regexp.MustCompile("^//([A-Za-z0-9\\._/-]+)/(\\.\\.\\.)$") +var rootSubTargets = regexp.MustCompile("^(//)(\\.\\.\\.)$") +var relativeTarget = regexp.MustCompile("^([A-Za-z0-9\\._-][A-Za-z0-9\\._/-]*):([A-Za-z0-9\\._#+-]+)$") +var relativeImplicitTarget = regexp.MustCompile("^([A-Za-z0-9\\._-][A-Za-z0-9\\._-]*/)([A-Za-z0-9\\._-]+)$") +var relativeSubTargets = regexp.MustCompile("^(?:([A-Za-z0-9\\._-][A-Za-z0-9\\._/-]*)/)?(\\.\\.\\.)$") + +func (label BuildLabel) String() string { + if label.Name != "" { + return "//" + label.PackageName + ":" + label.Name + } + return "//" + label.PackageName +} + +func NewBuildLabel(pkgName string, name string) BuildLabel { + if strings.HasSuffix(pkgName, "/") || strings.HasSuffix(pkgName, ":") { + panic("Invalid package name: " + pkgName) + } + return BuildLabel{PackageName: pkgName, Name: name} +} + +// ParseBuildLabel parses a single build label from a string. Panics on failure. +func ParseBuildLabel(target string, currentPath string) BuildLabel { + if label, success := tryParseBuildLabel(target, currentPath); success { + return label + } + panic("Invalid build target label: " + target) +} + +// ParseBuildFileLabel parses a build label with an attached file specification. Panics on failure. +func ParseBuildFileLabel(target string, currentPath string) (BuildLabel, string) { + if strings.Count(target, ":") == 2 { + index := strings.LastIndex(target, ":") + return ParseBuildLabel(target[0:index], currentPath), target[index+1 : len(target)] + } + return ParseBuildLabel(target, currentPath), "" +} + +// tryParseBuildLabel attempts to parse a single build label from a string. Returns a bool indicating success. +func tryParseBuildLabel(target string, currentPath string) (BuildLabel, bool) { + matches := absoluteTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(matches[1], matches[2]), true + } + matches = localTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(currentPath, matches[1]), true + } + matches = subTargets.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(matches[1], matches[2]), true + } + matches = rootSubTargets.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel("", matches[2]), true + } + matches = implicitTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(matches[1]+matches[2], matches[2]), true + } + return BuildLabel{}, false +} + +// As above, but allows parsing of relative labels (eg. src/parse/rules:python_rules) +// which is convenient at the shell prompt +func parseMaybeRelativeBuildLabel(target, subdir string) BuildLabel { + // Try the ones that don't need locating the repo root first. + if !strings.HasPrefix(target, ":") { + if label, success := tryParseBuildLabel(target, ""); success { + return label + } + } + // Now we need to locate the repo root and initial package. + // Deliberately leave this till after the above to facilitate the --repo_root flag. + if subdir == "" { + _, subdir = getRepoRoot(true) + } + matches := relativeTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(path.Join(subdir, matches[1]), matches[2]) + } + matches = relativeSubTargets.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(path.Join(subdir, matches[1]), matches[2]) + } + matches = relativeImplicitTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(path.Join(subdir, matches[1]+matches[2]), matches[2]) + } + matches = localTarget.FindStringSubmatch(target) + if matches != nil { + return NewBuildLabel(subdir, matches[1]) + } + log.Fatalf("Invalid build target label: %s", target) + return BuildLabel{} +} + +// Parse a bunch of build labels. +// Relative labels are allowed since this is generally used at initialisation. +func ParseBuildLabels(targets []string) []BuildLabel { + defer func() { + if r := recover(); r != nil { + log.Fatalf("%s", r) + } + }() + + var ret []BuildLabel + for _, target := range targets { + ret = append(ret, parseMaybeRelativeBuildLabel(target, "")) + } + return ret +} + +// Returns true if the label ends in ..., ie. it includes all subpackages. +func (label BuildLabel) IsAllSubpackages() bool { + return label.Name == "..." +} + +// Returns true if the label is the pseudo-label referring to all targets in this package. +func (label BuildLabel) IsAllTargets() bool { + return label.Name == "all" +} + +func (this BuildLabel) Less(that BuildLabel) bool { + if this.PackageName == that.PackageName { + return this.Name < that.Name + } else { + return this.PackageName < that.PackageName + } +} + +// Implementation of BuildInput interface +func (label BuildLabel) Paths(graph *BuildGraph) []string { + target := graph.Target(label) + if target == nil { + panic(fmt.Sprintf("Couldn't find target %s in build graph", label)) + } + ret := make([]string, len(target.Outputs()), len(target.Outputs())) + for i, output := range target.Outputs() { + ret[i] = path.Join(label.PackageName, output) + } + return ret +} + +func (label BuildLabel) FullPaths(graph *BuildGraph) []string { + target := graph.Target(label) + if target == nil { + panic("Couldn't find target corresponding to build label " + label.String()) + } + ret := make([]string, len(target.Outputs()), len(target.Outputs())) + for i, output := range target.Outputs() { + ret[i] = path.Join(target.OutDir(), output) + } + return ret +} + +func (label BuildLabel) Label() *BuildLabel { + return &label +} + +// Unmarshals a build label from a command line flag. Implementation of flags.Unmarshaler interface. +func (label *BuildLabel) UnmarshalFlag(value string) error { + // This is only allowable here, not in any other usage of build labels. + if value == "-" { + *label = BuildLabelStdin + return nil + } + + defer func() { + if r := recover(); r != nil { + // This has to be fatal because of the way we're using the flags package; + // we lose incoming flags if we return errors. + log.Fatalf("%s", r) + } + }() + *label = parseMaybeRelativeBuildLabel(value, "") + return nil +} + +// Returns true if the string appears to be a build label, false if not. +// Useful for cases like rule sources where sources can be a filename or a label. +func LooksLikeABuildLabel(str string) bool { + return strings.HasPrefix(str, "/") || strings.HasPrefix(str, ":") +} + +// Make slices of these guys sortable. +type BuildLabels []BuildLabel + +func (slice BuildLabels) Len() int { + return len(slice) +} +func (slice BuildLabels) Less(i, j int) bool { + return slice[i].Less(slice[j]) +} +func (slice BuildLabels) Swap(i, j int) { + slice[i], slice[j] = slice[j], slice[i] +} diff --git a/src/core/build_target.go b/src/core/build_target.go new file mode 100644 index 0000000000..6f768be1f5 --- /dev/null +++ b/src/core/build_target.go @@ -0,0 +1,636 @@ +package core + +import ( + "fmt" + "path" + "reflect" + "sort" + "strings" + "sync" + "sync/atomic" +) + +// OutDir is the output directory for everything. +const OutDir string = "plz-out" +const tmpDir string = "plz-out/tmp" +const genDir string = "plz-out/gen" +const binDir string = "plz-out/bin" + +// Representation of a build target and all information about it; +// its name, dependencies, build commands, etc. + +type BuildTarget struct { + // Identifier of this build target + Label BuildLabel + // Dependencies of this target + Dependencies []*BuildTarget + // Label dependencies of this target. + // This is mostly used during the parse phase when we know the set of + // declared labels, but don't necessarily have targets to associate + // with them until we've parsed the relevant build files. + DeclaredDependencies []BuildLabel + // Dependencies that are 'exported' to consuming rules, ie. if something depends + // on this rule, they get the exported dependencies as well. + ExportedDependencies []BuildLabel + // List of build target patterns that can use this build target. + Visibility []BuildLabel + // Source files of this rule. Can refer to build rules themselves. + Sources []BuildInput + // Named source files of this rule; as above but identified by name. + NamedSources map[string][]BuildInput + // Data files of this rule. Similar to sources but used at runtime, typically by tests. + Data []BuildInput + // Output files of this rule. All are paths relative to this package. + outputs []string + // Optional labels applied to this rule. Used for including/excluding rules. + Labels []string + // Shell command to run. + Command string + // Shell command to run for test targets. + TestCommand string + // Represents the state of this build target (see below) + state int32 + // True if this target is a binary (ie. runnable, will appear in plz-out/bin) + IsBinary bool + // True if this target is a test + IsTest bool + // True if we're going to containerise the test. + Containerise bool + // True if the target is a test and has no output file. + // Default is false, meaning all tests must produce test.results as output. + NoTestOutput bool + // True if this target needs access to its transitive dependencies to build. + // This would be false for most 'normal' genrules but true for eg. compiler steps + // that need to build in everything. + NeedsTransitiveDependencies bool + // True if this target blocks recursive exploring for transitive dependencies. + // This is typically false for _library rules which aren't complete, and true + // for _binary rules which normally are, and genrules where you don't care about + // the inputs, only whatever they were turned into. + OutputIsComplete bool + // Containerisation settings that override the defaults. + ContainerSettings *TargetContainerSettings + // Results of test, if it is one + Results TestResults + // Description displayed while the command is building. + // Default is just "Building" but it can be customised. + BuildingDescription string + // Acceptable hashes of the outputs of this rule. If the output doesn't match any of these + // it's an error at build time. Can be used to validate third-party deps. + Hashes []string + // Licences that this target is subject to. + Licences []string + // Python functions to call before / after target is built. Allows deferred manipulation of the + // build graph. + PreBuildFunction, PostBuildFunction uintptr + // Hash of the function's bytecode. Used for incrementality. + // TODO(pebers): unify with RuleHash maybe? seems wasteful to store these separately. + PreBuildHash, PostBuildHash []byte + // Languages this rule requires. These are an arbitrary set and the only meaning is that they + // correspond to entries in Provides; if rules match up then it allows choosing a specific + // dependency (consider eg. code generated from protobufs; this mechanism allows us to expose + // one rule but only compile the appropriate code for each library that consumes it). + Requires []string + // Dependent rules this rule provides for each language. Matches up to Requires as described above. + Provides map[string]BuildLabel + // Stores the hash of this build rule before any post-build function is run. + RuleHash []byte + // Tools that this rule will use, ie. other rules that it may use at build time which are not + // copied into its source directory. + Tools []BuildLabel + // Flakiness of test, ie. number of times we will rerun it before giving up. 0 is the default and + // is interpreted the same way as 1 would be (ie. one run only). + Flakiness int + // Timeouts for build/test actions, in seconds. + BuildTimeout int + TestTimeout int + // Indication that we should skip caching this rule. This shouldn't be used as an out for + // making targets indeterminate, it's a hint for rules like filegroup which simply symlink + // their inputs - so it's faster to relink them than copying their contents. + SkipCache bool + // Indicates that the target can only be depended on by tests or other rules with this set. + // Used to restrict non-deployable code and also affects coverage detection. + TestOnly bool + // Extra output files from the test. + // These are in addition to the usual test.results output file. + TestOutputs []string + // Used internally to track how many dependencies we've resolved, ie. how many declared + // dependencies have been mapped to actual dependencies. Once all are done this target is + // ready to build. + // TODO(pebers): unify this, Dependencies and DeclaredDependencies into one map. + resolvedDependencies map[BuildLabel]bool +} + +type BuildTargetState int32 + +const ( + Inactive BuildTargetState = iota // Target isn't used in current build + Semiactive BuildTargetState = iota // Target would be active if we needed a build + Active BuildTargetState = iota // Target is going to be used in current build + Pending BuildTargetState = iota // Target is ready to be built but not yet started. + Building BuildTargetState = iota // Target is currently being built + Built BuildTargetState = iota // Target has been successfully built + Unchanged BuildTargetState = iota // Target hasn't changed since last build + Failed BuildTargetState = iota // Target failed for some reason +) + +type TestResults struct { + NumTests int // Total number of test cases in the test target. + Passed int // Number of tests that passed outright. + Failed int // Number of tests that failed. + ExpectedFailures int // Number of tests that were expected to fail (counts as a pass, but displayed differently) + Skipped int // Number of tests skipped (also count as passes) + Flakes int // Number of failed attempts to run the test + Failures []TestFailure + Passes []string + Output string // Stdout / stderr from the test. + Cached bool // True if the test results were retrieved from cache + Duration float64 // Length of time this test took, in seconds. +} + +type TestFailure struct { + Name string // Name of failed test + Type string // Type of failure, eg. type of exception raised + Traceback string // Traceback + Stdout string // Standard output during test + Stderr string // Standard error during test +} + +// Aggregates the given results into this one. +func (this *TestResults) Aggregate(that TestResults) { + this.NumTests += that.NumTests + this.Passed += that.Passed + this.Failed += that.Failed + this.ExpectedFailures += that.ExpectedFailures + this.Skipped += that.Skipped + this.Flakes += that.Flakes + this.Failures = append(this.Failures, that.Failures...) + this.Passes = append(this.Passes, that.Passes...) + this.Duration += that.Duration + // Output can't really be aggregated sensibly. +} + +// Inputs to a build can be either a file in the local package or another build rule. +// All users care about is where they find them. +type BuildInput interface { + // Returns a slice of paths to the files of this input. + Paths(graph *BuildGraph) []string + // As above, but includes the leading plz-out/gen directory. + FullPaths(graph *BuildGraph) []string + // Returns the build label associated with this input, or nil if it doesn't have one (eg. it's just a file). + Label() *BuildLabel + // Returns a string representation of this input + String() string +} + +// Settings controlling containerisation for a particular target. +type TargetContainerSettings struct { + // Image to use for this test + DockerImage string + // Username / Uid to run as + DockerUser string + // Extra arguments to pass to 'docker run' + DockerRunArgs string +} + +func NewBuildTarget(label BuildLabel) *BuildTarget { + target := new(BuildTarget) + target.Label = label + target.DeclaredDependencies = []BuildLabel{} + target.state = int32(Inactive) + target.Dependencies = []*BuildTarget{} + target.resolvedDependencies = map[BuildLabel]bool{} + target.IsBinary = false + target.IsTest = false + target.Command = "false" + target.BuildingDescription = "Building..." + return target +} + +// Returns the temporary working directory for this target, eg. +// //mickey/donald:goofy -> plz-out/tmp/mickey/donald/goofy +// Note the extra subdirectory to keep rules separate from one another. +func (target *BuildTarget) TmpDir() string { + return path.Join(tmpDir, target.Label.PackageName, target.Label.Name) +} + +// Returns the output directory for this target, eg. +// //mickey/donald:goofy -> plz-out/gen/mickey/donald (or plz-out/bin if it's a binary) +func (target *BuildTarget) OutDir() string { + if target.IsBinary { + return path.Join(binDir, target.Label.PackageName) + } else { + return path.Join(genDir, target.Label.PackageName) + } +} + +// Returns the test directory for this target, eg. +// //mickey/donald:goofy -> plz-out/tmp/mickey/donald/goofy.test +// This is different to TmpDir so we run tests in a clean environment +// and to facilitate containerising tests. +func (target *BuildTarget) TestDir() string { + return target.TmpDir() + ".test" +} + +// Returns all the source paths for this target +func (target *BuildTarget) AllSourcePaths(graph *BuildGraph) []string { + ret := make([]string, 0, len(target.Sources)) + for source := range target.AllSources() { + for _, file := range source.Paths(graph) { + ret = append(ret, file) + } + } + return ret +} + +// DeclaredOutputs returns the outputs from this target's original declaration. +// Hence it's similar to Outputs() but without the resolving of other rule names. +func (target *BuildTarget) DeclaredOutputs() []string { + return target.outputs +} + +// Outputs returns a slice of all the outputs of this rule. +// Recall that outputs can be defined as the name of another rule to indicate that +// a rule collects and re-outputs them; that is expanded here. +func (target *BuildTarget) Outputs() []string { + ret := []string{} + for _, out := range target.outputs { + if LooksLikeABuildLabel(out) { + label, file := ParseBuildFileLabel(out, target.Label.PackageName) + if file != "" { + ret = append(ret, file) + } else { + ret = append(ret, target.findOutputTarget(label, out)...) + } + } else { + ret = append(ret, out) + } + } + return ret +} + +// findOutputTarget finds, among this target's dependencies, the target that outputs +// the given label, and returns its outputs. +func (target *BuildTarget) findOutputTarget(label BuildLabel, out string) []string { + for _, dep := range target.Dependencies { + if dep.Label == label { + return dep.Outputs() + } + } + panic(fmt.Sprintf("Target %s declares outputs of %s but they're not a resolved dependency of it", target.Label, out)) +} + +// Returns the source paths for a given set of sources. +func (target *BuildTarget) SourcePaths(graph *BuildGraph, sources []BuildInput) []string { + ret := make([]string, 0, len(sources)) + for _, source := range sources { + for _, file := range source.Paths(graph) { + ret = append(ret, file) + } + } + return ret +} + +// allDepsBuilt returns true if all the dependencies of a target are built. +func (target *BuildTarget) allDepsBuilt() bool { + if !target.allDependenciesResolved() { + return false // Target still has some deps pending parse. + } + for _, dep := range target.Dependencies { + if dep.State() < Built { + return false + } + } + return true +} + +// allDependenciesResolved returns true once all the dependencies of a target have been +// parsed and resolved to real targets. +func (target *BuildTarget) allDependenciesResolved() bool { + for _, resolved := range target.resolvedDependencies { + if !resolved { + return false + } + } + return true +} + +// CanSee returns true if target can see the given dependency, or false if not. +func (target *BuildTarget) CanSee(dep *BuildTarget) bool { + // Targets are always visible to other targets in the same directory. + if target.Label.PackageName == dep.Label.PackageName { + return true + } + for _, vis := range dep.Visibility { + if strings.HasPrefix(target.Label.PackageName, vis.PackageName) { + // We're in the same package or a subpackage of this visibility spec + if vis.IsAllSubpackages() { + return true + } else if target.Label.PackageName == vis.PackageName { + if target.Label.Name == vis.Name || vis.IsAllTargets() { + return true + } + } + } + } + return false +} + +// CheckDependencyVisibility checks that all dependencies of this target are visible to it. +// Returns an error if not, or nil if all's well. +func (target *BuildTarget) CheckDependencyVisibility() error { + for _, dep := range target.Dependencies { + if !target.CanSee(dep) { + return fmt.Errorf("Target %s isn't visible to %s", dep.Label, target.Label) + } else if dep.TestOnly && !(target.IsTest || target.TestOnly) { + return fmt.Errorf("Target %s can't depend on %s, it's marked test_only", target.Label, dep.Label) + } + } + return nil +} + +// CheckDuplicateOutputs checks if any of the outputs of this target duplicate one another. +// Returns an error if so, or nil if all's well. +func (target *BuildTarget) CheckDuplicateOutputs() error { + outputs := map[string]struct{}{} + for _, output := range target.Outputs() { + if _, present := outputs[output]; present { + return fmt.Errorf("Target %s declares output file %s multiple times", target.Label, output) + } + outputs[output] = struct{}{} + } + return nil +} + +// HasDependency checks if a target already depends on this label. +func (target *BuildTarget) HasDependency(label BuildLabel) bool { + for _, dep := range target.DeclaredDependencies { + if dep == label { + return true + } + } + return false +} + +// Checks if a target already has an exported dependency on this label. +func (target *BuildTarget) HasExportedDependency(label BuildLabel) bool { + for _, dep := range target.ExportedDependencies { + if dep == label { + return true + } + } + return false +} + +// State returns the target's current state. +func (target *BuildTarget) State() BuildTargetState { + return BuildTargetState(atomic.LoadInt32(&target.state)) +} + +// SetState sets a target's current state. +func (target *BuildTarget) SetState(state BuildTargetState) { + atomic.StoreInt32(&target.state, int32(state)) +} + +// SyncUpdateState oves the target's state from before to after via a lock. +// Returns true if successful, false if not (which implies something else changed the state first). +// The nature of our build graph ensures that most transitions are only attempted by +// one thread simultaneously, but this one can be attempted by several at once +// (eg. if a depends on b and c, which finish building simultaneously, they race to queue a). +func (target *BuildTarget) SyncUpdateState(before, after BuildTargetState) bool { + return atomic.CompareAndSwapInt32(&target.state, int32(before), int32(after)) +} + +// AddLabel adds the given label to this target if it doesn't already have it. +func (target *BuildTarget) AddLabel(label string) { + if !target.HasLabel(label) { + target.Labels = append(target.Labels, label) + } +} + +// HasLabel returns true if target has the given label. +func (target *BuildTarget) HasLabel(label string) bool { + for _, l := range target.Labels { + if l == label { + return true + } + } + return false +} + +// HasAnyLabel returns true if target has any of these labels. +func (target *BuildTarget) HasAnyLabel(labels []string) bool { + for _, label := range labels { + if target.HasLabel(label) { + return true + } + } + return false +} + +// Handles the typical include/exclude logic for a target's labels; returns true if +// target has any include label and not an exclude one. +func (target *BuildTarget) ShouldInclude(include, exclude []string) bool { + return (len(include) == 0 || target.HasAnyLabel(include)) && !target.HasAnyLabel(exclude) && !target.HasLabel("manual") +} + +func (target *BuildTarget) AddProvide(language string, label BuildLabel) { + if label == target.Label { + target.addProvide(language, target.Label) + return + } + for _, dep := range target.DeclaredDependencies { + if dep == label { + target.addProvide(language, label) + return + } + } + panic(fmt.Sprintf("Target %s must depend on %s in order to provide it", target.Label, label)) +} + +func (target *BuildTarget) addProvide(language string, label BuildLabel) { + if target.Provides == nil { + target.Provides = map[string]BuildLabel{language: label} + } else { + target.Provides[language] = label + } +} + +// Returns the build label that we'd provide for the given target. +func (target *BuildTarget) ProvideFor(other *BuildTarget) []BuildLabel { + ret := []BuildLabel{} + if target.Provides != nil { + // Never do this if the other target has a data dependency on us. + for _, data := range other.Data { + if label := data.Label(); label != nil && *label == target.Label { + return []BuildLabel{target.Label} + } + } + for _, require := range other.Requires { + if label, present := target.Provides[require]; present { + ret = append(ret, label) + } + } + if len(ret) > 0 { + return ret + } + } + return []BuildLabel{target.Label} +} + +func (target *BuildTarget) AddNamedSource(name string, source BuildInput) { + if target.NamedSources == nil { + target.NamedSources = map[string][]BuildInput{} + } + target.NamedSources[name] = append(target.NamedSources[name], source) +} + +func (target *BuildTarget) AllSources() <-chan BuildInput { + ch := make(chan BuildInput, 10) + go func() { + for _, source := range target.Sources { + ch <- source + } + if target.NamedSources != nil { + keys := make([]string, 0, len(target.NamedSources)) + for k := range target.NamedSources { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + for _, source := range target.NamedSources[k] { + ch <- source + } + } + } + close(ch) + }() + return ch +} + +func (target *BuildTarget) AddDependency(dep BuildLabel) { + if dep == target.Label { + log.Fatalf("Attempted to add %s as a dependency of itself.\n", dep) + } + if !target.HasDependency(dep) { + target.DeclaredDependencies = append(target.DeclaredDependencies, dep) + target.resolvedDependencies[dep] = false + } +} + +func (target *BuildTarget) AddExportedDependency(dep BuildLabel) { + if !target.HasExportedDependency(dep) { + target.ExportedDependencies = append(target.ExportedDependencies, dep) + } +} + +// IsTool returns true if the given build label is a dependency of this target. +func (target *BuildTarget) IsTool(tool BuildLabel) bool { + for _, t := range target.Tools { + if t == tool { + return true + } + } + return false +} + +// AddOutput adds a new output to the target if it's not already there. +func (target *BuildTarget) AddOutput(output string) { + for _, out := range target.outputs { + if out == output { + return + } + } + target.outputs = append(target.outputs, output) +} + +// AddLicence adds a licence to the target if it's not already there. +func (target *BuildTarget) AddLicence(licence string) { + licence = strings.TrimSpace(licence) + for _, l := range target.Licences { + if l == licence { + return + } + } + target.Licences = append(target.Licences, licence) +} + +// Sets one of the fields on the container settings by name. +func (target *BuildTarget) SetContainerSetting(name, value string) { + if target.ContainerSettings == nil { + target.ContainerSettings = &TargetContainerSettings{} + } + t := reflect.TypeOf(*target.ContainerSettings) + for i := 0; i < t.NumField(); i++ { + if strings.ToLower(t.Field(i).Name) == name { + v := reflect.ValueOf(target.ContainerSettings) + v.Elem().Field(i).SetString(value) + return + } + } + panic(fmt.Sprintf("Field %s isn't a valid container setting", name)) +} + +// Make slices of these guys sortable. +type BuildTargets []*BuildTarget + +func (slice BuildTargets) Len() int { + return len(slice) +} +func (slice BuildTargets) Less(i, j int) bool { + return slice[i].Label.Less(slice[j].Label) +} +func (slice BuildTargets) Swap(i, j int) { + slice[i], slice[j] = slice[j], slice[i] +} + +// Representation of a package, ie. the part of the system (one or more +// directories) covered by a single build file. +type Package struct { + // Name of the package, ie. //spam/eggs + Name string + // Filename of the build file that defined this package + Filename string + // Subincluded build defs files that this package imported + Subincludes []string + // Targets contained within the package + Targets map[string]*BuildTarget + // Set of output files from rules. + Outputs map[string]*BuildTarget + // Protects access to above + Mutex sync.Mutex +} + +func NewPackage(name string) *Package { + pkg := new(Package) + pkg.Name = name + pkg.Targets = map[string]*BuildTarget{} + pkg.Outputs = map[string]*BuildTarget{} + return pkg +} + +func (pkg *Package) RegisterSubinclude(filename string) { + // Ensure these are unique. + for _, fn := range pkg.Subincludes { + if fn == filename { + return + } + } + pkg.Subincludes = append(pkg.Subincludes, filename) +} + +// RegisterOutput registers a new output file in the map. +// Dies if the file has already been registered. +func (pkg *Package) RegisterOutput(fileName string, target *BuildTarget) { + pkg.Mutex.Lock() + defer pkg.Mutex.Unlock() + originalFileName := fileName + if target.IsBinary { + fileName = ":_bin_" + fileName // Add some arbitrary prefix so they don't clash. + } + if existing, present := pkg.Outputs[fileName]; present && existing != target { + log.Fatalf("Rules %s and %s in %s both attempt to output the same file: %s\n", + existing.Label, target.Label, pkg.Filename, originalFileName) + } + pkg.Outputs[fileName] = target +} diff --git a/src/core/build_target_test.go b/src/core/build_target_test.go new file mode 100644 index 0000000000..e4a35989d7 --- /dev/null +++ b/src/core/build_target_test.go @@ -0,0 +1,160 @@ +// Tests on specific functions in build_target.go +package core + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCanSee(t *testing.T) { + target1 := makeTarget("//src/build/python:lib1", "") + target2 := makeTarget("//src/build/python:lib2", "PUBLIC") + target3 := makeTarget("//src/test/python:lib3", "//src/test/...") + target4 := makeTarget("//src/test/python/moar:lib4", "") + + // target2 is public so anything can import it + assert.True(t, target3.CanSee(target2), "couldn't see public target") + assert.True(t, target4.CanSee(target2), "couldn't see public target") + + // target1 is not public, other things can't import it + assert.False(t, target3.CanSee(target1), "could see private target") + assert.False(t, target4.CanSee(target1), "could see private target") + + // target2 is in the same package as target1 so can implicitly see it + assert.True(t, target2.CanSee(target1), "couldn't see target in the same package") + + // target3 is only visible to a subtree, things outside it can't see it + assert.False(t, target1.CanSee(target3), "could see target with restricted visibility") + assert.False(t, target2.CanSee(target3), "could see target with restricted visibility") + + // Targets in that subtree can though. + assert.True(t, target4.CanSee(target3), "couldn't see target within its visibility spec") +} + +func TestCheckDependencyVisibility(t *testing.T) { + target1 := makeTarget("//src/build/python:lib1", "") + target2 := makeTarget("//src/build/python:lib2", "PUBLIC", target1) + target3 := makeTarget("//src/test/python:lib3", "//src/test/...", target2) + target4 := makeTarget("//src/test/python/moar:lib4", "//src/test/...", target3) + target5 := makeTarget("//third_party/python:mock", "PUBLIC") + target5.TestOnly = true + target6 := makeTarget("//src/test/python:test_lib", "", target5) + target6.TestOnly = true + target7 := makeTarget("//src/test/python:test1", "", target5, target4) + target7.IsTest = true + + // Deps should all be correct at this point + assert.NoError(t, target1.CheckDependencyVisibility()) + assert.NoError(t, target2.CheckDependencyVisibility()) + assert.NoError(t, target3.CheckDependencyVisibility()) + assert.NoError(t, target4.CheckDependencyVisibility()) + assert.NoError(t, target5.CheckDependencyVisibility()) + assert.NoError(t, target6.CheckDependencyVisibility()) + assert.NoError(t, target7.CheckDependencyVisibility()) + + // Now if we add a dep on this mock library, lib2 will fail because it's not a test. + target2.Dependencies = append(target2.Dependencies, target5) + assert.Error(t, target2.CheckDependencyVisibility()) + + // Similarly to above test, if we add a dep on something that can't be seen, we should + // get errors back from this function. + target3.Dependencies = append(target3.Dependencies, target1) + assert.Error(t, target3.CheckDependencyVisibility()) +} + +func TestAddOutput(t *testing.T) { + target := makeTarget("//src/test/python:lib1", "") + target.AddOutput("thingy.py") + target.AddOutput("thingy2.py") + target.AddOutput("thingy.py") + if len(target.Outputs()) != 2 { + t.Errorf("Incorrect output length; should be 2, was %d", len(target.Outputs())) + } +} + +func TestSetContainerSettings(t *testing.T) { + target := makeTarget("//src/test/python:lib1", "") + + target.SetContainerSetting("dockerimage", "tm/special_image:v2") + assert.Equal(t, "tm/special_image:v2", target.ContainerSettings.DockerImage) + + target.SetContainerSetting("dockeruser", "") + assert.Equal(t, "", target.ContainerSettings.DockerUser) + + target.SetContainerSetting("dockerrunargs", "-it") + assert.Equal(t, "-it", target.ContainerSettings.DockerRunArgs) +} + +func TestOutputs(t *testing.T) { + target1 := makeTarget("//src/core:target1", "PUBLIC") + target1.AddOutput("file1.go") + target1.AddOutput("file2.go") + target2 := makeTarget("//src/test:target2", "PUBLIC", target1) + target2.AddOutput("//src/core:target1") + target2.AddOutput("file3.go") + target3 := makeTarget("//src/test:target3", "PUBLIC", target2) + target3.AddOutput(":target2") + target3.AddOutput("file4.go") + + assert.Equal(t, []string{"file1.go", "file2.go"}, target1.Outputs()) + assert.Equal(t, []string{"file1.go", "file2.go", "file3.go"}, target2.Outputs()) + assert.Equal(t, []string{"file1.go", "file2.go", "file3.go", "file4.go"}, target3.Outputs()) +} + +func TestProvideFor(t *testing.T) { + // target1 is provided directly since they have a simple dependency + target1 := makeTarget("//src/core:target1", "PUBLIC") + target2 := makeTarget("//src/core:target2", "PUBLIC", target1) + assert.Equal(t, []BuildLabel{target1.Label}, target1.ProvideFor(target2)) + // Now have target2 provide target1. target3 will get target1 instead. + target2.Provides = map[string]BuildLabel{"whatevs": target1.Label} + target3 := makeTarget("//src/core:target3", "PUBLIC", target2) + target3.Requires = append(target3.Requires, "whatevs") + assert.Equal(t, []BuildLabel{target1.Label}, target2.ProvideFor(target3)) + // Now target4 has a data dependency on target2. It has the same requirement as target3 but + // it gets target2 instead of target1, because that's just how data deps work. + target4 := makeTarget("//src/core:target4", "PUBLIC", target2) + target4.Data = append(target4.Data, target2.Label) + target4.Requires = append(target4.Requires, "whatevs") + assert.Equal(t, []BuildLabel{target2.Label}, target2.ProvideFor(target4)) +} + +func TestCheckDuplicateOutputs(t *testing.T) { + target1 := makeTarget("//src/core:target1", "PUBLIC") + target3 := makeTarget("//src/core:target3", "PUBLIC") + target2 := makeTarget("//src/core:target2", "PUBLIC", target1, target3) + target1.AddOutput("thingy.txt") + target3.AddOutput("thingy.txt") + assert.NoError(t, target1.CheckDuplicateOutputs()) + target2.AddOutput(target1.Label.String()) + target2.AddOutput(target1.Label.String()) + // Not an error yet because AddOutput deduplicates trivially identical outputs. + assert.NoError(t, target2.CheckDuplicateOutputs()) + // Will fail now we add the same output to another target. + target2.AddOutput(target3.Label.String()) + assert.Error(t, target2.CheckDuplicateOutputs()) +} + +func TestLabels(t *testing.T) { + target := makeTarget("//src/core:target1", "PUBLIC") + assert.False(t, target.HasLabel("py")) + assert.False(t, target.HasAnyLabel([]string{"py", "go"})) + target.AddLabel("py") + assert.True(t, target.HasLabel("py")) + assert.True(t, target.HasAnyLabel([]string{"py", "go"})) + target.AddLabel("py") + target.AddLabel("go") + assert.Equal(t, 2, len(target.Labels)) +} + +func makeTarget(label, visibility string, deps ...*BuildTarget) *BuildTarget { + target := NewBuildTarget(ParseBuildLabel(label, "")) + if visibility == "PUBLIC" { + target.Visibility = append(target.Visibility, BuildLabel{PackageName: "", Name: "..."}) + } else if visibility != "" { + target.Visibility = append(target.Visibility, ParseBuildLabel(visibility, "")) + } + target.Dependencies = append(target.Dependencies, deps...) + return target +} diff --git a/src/core/config.go b/src/core/config.go new file mode 100644 index 0000000000..539ac89676 --- /dev/null +++ b/src/core/config.go @@ -0,0 +1,251 @@ +// Utilities for reading the Please config files. + +package core + +import ( + "crypto/sha1" + "encoding/gob" + "fmt" + "os" + + "gopkg.in/gcfg.v1" +) + +// File name for the typical repo config - this is normally checked in +const ConfigFileName string = ".plzconfig" + +// File name for the local repo config - this is not normally checked in and used to +// override settings on the local machine. +const LocalConfigFileName string = ".plzconfig.local" + +// File name for the machine-level config - can use this to override things +// for a particular machine (eg. build machine with different caching behaviour). +const MachineConfigFileName = "/etc/plzconfig" + +const PleaseVersion string = "" + +const TestContainerDocker = "docker" +const TestContainerNone = "none" + +func readConfigFile(config *Configuration, filename string) error { + if err := gcfg.ReadFileInto(config, filename); err != nil && os.IsNotExist(err) { + return nil // It's not an error to not have the file at all. + } else if err != nil { + return err + } + // TODO(pebers): Use gcfg's types thingy to parse this once it's finalised. + if config.Test.DefaultContainer != TestContainerNone && config.Test.DefaultContainer != TestContainerDocker { + return fmt.Errorf("Unknown container type %s", config.Test.DefaultContainer) + } + return nil +} + +// Reads a config file from the given locations, in order. +// Values are filled in by defaults initially and then overridden by each file in turn. +func ReadConfigFiles(filenames []string) (Configuration, error) { + config := DefaultConfiguration() + for _, filename := range filenames { + if err := readConfigFile(&config, filename); err != nil { + return config, err + } + } + // Set default values for slices. These add rather than overwriting so we can't set + // them upfront as we would with other config values. + setDefault(&config.Please.BuildFileName, []string{"BUILD"}) + setDefault(&config.Build.Path, []string{"/usr/local/bin", "/usr/bin", "/bin"}) + setDefault(&config.Please.PyPyLocation, []string{"/usr/lib/libpypy-c.so", "/usr/local/lib/libpypy-c.dylib"}) + setDefault(&config.Cover.FileExtension, []string{".go", ".py", ".java", ".js", ".cc", ".h", ".c"}) + setDefault(&config.Cover.ExcludeExtension, []string{".pb.go", "_pb2.py", ".pb.cc", ".pb.h", "_test.py"}) + setDefault(&config.Proto.Language, []string{"cc", "py", "java", "go"}) + + return config, nil +} + +// setDefault sets a slice of strings in the config if the set one is empty. +func setDefault(conf *[]string, def []string) { + if len(*conf) == 0 { + *conf = def + } +} + +func DefaultConfiguration() Configuration { + config := Configuration{} + config.Please.Version = PleaseVersion + config.Please.Location = "/opt/please" + config.Please.SelfUpdate = true + config.Please.DownloadLocation = "https://s3-eu-west-1.amazonaws.com/please-build" + config.Please.Lang = "en_GB.UTF-8" // Not the language of the UI, the language passed to rules. + config.Please.Nonce = "1402" // Arbitrary nonce to invalidate config when needed. + config.Build.Timeout = 600 // Ten minutes + config.Cache.HttpTimeout = 5 // Five seconds + config.Cache.RpcTimeout = 5 // Five seconds + config.Cache.DirCacheCleaner = "/opt/please/cache_cleaner" + config.Cache.DirCacheHighWaterMark = "10G" + config.Cache.DirCacheLowWaterMark = "8G" + config.Test.Timeout = 600 + config.Test.DefaultContainer = TestContainerDocker + config.Docker.DefaultImage = "ubuntu:trusty" + config.Docker.AllowLocalFallback = true + config.Docker.Timeout = 1200 // Twenty minutes + config.Docker.ResultsTimeout = 20 // Twenty seconds + config.Docker.RemoveTimeout = 20 // Twenty seconds + config.Go.Version = "1.5.1" + config.Python.PipTool = "pip" + config.Python.PexTool = "/opt/please/please_pex" + config.Python.DefaultInterpreter = "/usr/bin/python" + config.Python.UsePyPI = true + config.Java.JavacTool = "javac" + config.Java.JarTool = "jar" + config.Java.JarCatTool = "/opt/please/jarcat" + config.Java.PleaseMavenTool = "/opt/please/please_maven" + config.Java.JUnitRunner = "/opt/please/junit_runner.jar" + config.Java.DefaultTestPackage = "" + config.Java.SourceLevel = "8" + config.Java.TargetLevel = "8" + config.Cpp.CCTool = "g++" + config.Cpp.LdTool = "ld" + config.Cpp.DefaultCflags = "--std=c++11 -O2 -Wall -Wextra -Werror" + config.Cpp.DefaultTestCflags = "--std=c++11 -O2 -Wall -Wextra -Werror" + config.Cpp.DefaultTestLdflags = "-lunittest++" + config.Cpp.DefaultNamespace = "my_namespace" // Rules don't support not having this set. + config.Proto.ProtocTool = "protoc" + config.Proto.ProtocGoPlugin = "`which protoc-gen-go`" // These seem to need absolute paths + config.Proto.GrpcPythonPlugin = "`which protoc-gen-grpc-python`" + config.Proto.GrpcJavaPlugin = "`which protoc-gen-grpc-java`" + config.Proto.ProtocVersion = "3.0.0" + config.Proto.PythonDep = "//third_party/python:protobuf" + config.Proto.JavaDep = "//third_party/java:protobuf" + config.Proto.GoDep = "//third_party/go:protobuf" + config.Proto.GrpcVersion = "0.11.1" + config.Proto.PythonGrpcDep = "//third_party/python:grpc" + config.Proto.JavaGrpcDep = "//third_party/java:grpc-all" + config.Proto.GoGrpcDep = "//third_party/go:grpc" + return config +} + +type Configuration struct { + Please struct { + Version string + Location string + SelfUpdate bool + DownloadLocation string + BuildFileName []string + Lang string + PyPyLocation []string + Nonce string + } + Build struct { + Timeout int + Path []string + } + Cache struct { + Dir string + DirCacheCleaner string + DirCacheHighWaterMark string + DirCacheLowWaterMark string + HttpUrl string + HttpWriteable bool + HttpTimeout int + RpcUrl string + RpcWriteable bool + RpcTimeout int + } + Test struct { + Timeout int + DefaultContainer string + } + Cover struct { + FileExtension []string + ExcludeExtension []string + } + Docker struct { + DefaultImage string + AllowLocalFallback bool + Timeout int + ResultsTimeout int + RemoveTimeout int + RunArgs []string + } + Go struct { + Version string + Strip string + } + Python struct { + PipTool string + PexTool string + DefaultInterpreter string + ModuleDir string + DefaultPipRepo string + UsePyPI bool + } + Java struct { + JavacTool string + JarTool string + JarCatTool string + PleaseMavenTool string + JUnitRunner string + DefaultTestPackage string + SourceLevel string + TargetLevel string + } + Cpp struct { + CCTool string + LdTool string + DefaultCflags string + DefaultTestCflags string + DefaultLdflags string + DefaultTestLdflags string + DefaultNamespace string + } + Proto struct { + ProtocTool string + ProtocGoPlugin string + GrpcPythonPlugin string + GrpcJavaPlugin string + Language []string + ProtocVersion string + PythonDep string + JavaDep string + GoDep string + GrpcVersion string + PythonGrpcDep string + JavaGrpcDep string + GoGrpcDep string + PythonPackage string + } + Licences struct { + Accept []string + Reject []string + } + Aliases map[string]string +} + +func (config *Configuration) Hash() []byte { + h := sha1.New() + // These fields are the ones that need to be in the general hash; other things will be + // picked up by relevant rules (particularly tool paths etc). + // Note that container settings are handled separately. + for _, f := range config.Please.BuildFileName { + h.Write([]byte(f)) + } + h.Write([]byte(config.Please.Lang)) + h.Write([]byte(config.Please.Nonce)) + for _, p := range config.Build.Path { + h.Write([]byte(p)) + } + h.Write([]byte(config.Go.Version)) // Sucks a bit not to invalidate just Go rules but it's hard to detect. + for _, l := range config.Licences.Reject { + h.Write([]byte(l)) + } + return h.Sum(nil) +} + +// ContainerisationHash returns the hash of the containerisation part of the config. +func (config *Configuration) ContainerisationHash() []byte { + h := sha1.New() + encoder := gob.NewEncoder(h) + if err := encoder.Encode(config.Docker); err != nil { + panic(err) + } + return h.Sum(nil) +} diff --git a/src/core/config_test.go b/src/core/config_test.go new file mode 100644 index 0000000000..c461028018 --- /dev/null +++ b/src/core/config_test.go @@ -0,0 +1,41 @@ +package core + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPlzConfigWorking(t *testing.T) { + config, err := ReadConfigFiles([]string{"src/core/test_data/working.plzconfig"}) + assert.NoError(t, err) + assert.Equal(t, "pexmabob", config.Python.PexTool) + assert.Equal(t, "javac", config.Java.JavacTool) + assert.Equal(t, "8", config.Java.SourceLevel) + assert.Equal(t, "7", config.Java.TargetLevel) + assert.Equal(t, "jar", config.Java.JarTool) +} + +func TestPlzConfigFailing(t *testing.T) { + _, err := ReadConfigFiles([]string{"src/core/test_data/failing.plzconfig"}) + assert.Error(t, err) +} + +func TestMultiplePlzConfigFiles(t *testing.T) { + config, err := ReadConfigFiles([]string{ + "src/core/test_data/working.plzconfig", + "src/core/test_data/failing.plzconfig", + }) + assert.Error(t, err) + // Quick check of this - we should have still read the first config file correctly. + assert.Equal(t, "javac", config.Java.JavacTool) +} + +func TestConfigSlicesOverwrite(t *testing.T) { + config, err := ReadConfigFiles([]string{"src/core/test_data/slices.plzconfig"}) + assert.NoError(t, err) + // This should be completely overwritten by the config file + assert.Equal(t, []string{"/sbin"}, config.Build.Path) + // This should still get the defaults. + assert.Equal(t, []string{"BUILD"}, config.Please.BuildFileName) +} diff --git a/src/core/file_label.go b/src/core/file_label.go new file mode 100644 index 0000000000..ee3077d96f --- /dev/null +++ b/src/core/file_label.go @@ -0,0 +1,53 @@ +// Implementation of the BuildInput interface for simple cases of files in the local package. + +package core + +import "fmt" +import "path" + +type FileLabel struct { + // Name of the file + File string + // Name of the package + Package string +} + +func (label FileLabel) Paths(graph *BuildGraph) []string { + return []string{path.Join(label.Package, label.File)} +} + +func (label FileLabel) FullPaths(graph *BuildGraph) []string { + return label.Paths(graph) +} + +func (label FileLabel) Label() *BuildLabel { + return nil +} + +func (label FileLabel) String() string { + return label.File +} + +// Similar to above but used for collecting a single output of another file. +type BuildFileLabel struct { + // Target the label comes from + BuildLabel BuildLabel + // Name of the file + File string +} + +func (label BuildFileLabel) Paths(graph *BuildGraph) []string { + return []string{path.Join(label.BuildLabel.PackageName, label.File)} +} + +func (label BuildFileLabel) FullPaths(graph *BuildGraph) []string { + return []string{path.Join(graph.TargetOrDie(label.BuildLabel).OutDir(), label.File)} +} + +func (label BuildFileLabel) Label() *BuildLabel { + return &label.BuildLabel +} + +func (label BuildFileLabel) String() string { + return fmt.Sprintf("%s:%s", label.BuildLabel, label.File) +} diff --git a/src/core/graph.go b/src/core/graph.go new file mode 100644 index 0000000000..8531dfd2e2 --- /dev/null +++ b/src/core/graph.go @@ -0,0 +1,211 @@ +// Representation of the build graph. +// The graph of build targets forms a DAG which we discover from the top +// down and then build bottom-up. + +package core + +import "sort" +import "sync" + +type BuildGraph struct { + // Map of all currently known targets by their label. + targets map[BuildLabel]*BuildTarget + // Map of all currently known packages. + packages map[string]*Package + // Reverse dependencies that are pending on targets actually being added to the graph. + pendingRevDeps map[BuildLabel]map[BuildLabel]bool + // Actual reverse dependencies + revDeps map[BuildLabel][]*BuildTarget + // Used to arbitrate access to the graph. We parallelise most build operations + // and Go maps aren't natively threadsafe so this is needed. + mutex sync.Mutex +} + +// Adds a new target to the graph. +func (graph *BuildGraph) AddTarget(target *BuildTarget) *BuildTarget { + graph.mutex.Lock() + defer graph.mutex.Unlock() + _, present := graph.targets[target.Label] + if present { + panic("Attempted to re-add existing target to build graph: " + target.Label.String()) + } + graph.targets[target.Label] = target + // Check these reverse deps which may have already been added against this target. + revdeps, present := graph.pendingRevDeps[target.Label] + if present { + for revdep := range revdeps { + graph.linkDependencies(graph.targets[revdep], target) + } + delete(graph.pendingRevDeps, target.Label) // Don't need any more + } + return target +} + +// Adds a new package to the graph with given name. +func (graph *BuildGraph) AddPackage(pkg *Package) { + graph.mutex.Lock() + defer graph.mutex.Unlock() + if _, present := graph.packages[pkg.Name]; present { + panic("Attempt to readd existing package: " + pkg.Name) + } + graph.packages[pkg.Name] = pkg +} + +// Target retrieves a target from the graph by label +func (graph *BuildGraph) Target(label BuildLabel) *BuildTarget { + graph.mutex.Lock() + defer graph.mutex.Unlock() + target, present := graph.targets[label] + if !present { + target = nil // easier than a 'null' BuildTarget. + } + return target +} + +// TargetOrDie retrieves a target from the graph by label. Dies if the target doesn't exist. +func (graph *BuildGraph) TargetOrDie(label BuildLabel) *BuildTarget { + target := graph.Target(label) + if target == nil { + log.Fatalf("Target %s not found in build graph\n", label) + } + return target +} + +// Package retrieves a package from the graph by name +func (graph *BuildGraph) Package(name string) *Package { + graph.mutex.Lock() + defer graph.mutex.Unlock() + pkg, present := graph.packages[name] + if !present { + pkg = nil + } + return pkg +} + +// PackageOrDie retrieves a package by name, and dies if it can't be found. +func (graph *BuildGraph) PackageOrDie(name string) *Package { + pkg := graph.Package(name) + if pkg == nil { + log.Fatalf("Package %s doesn't exist in graph", name) + } + return pkg +} + +func (graph *BuildGraph) Len() int { + graph.mutex.Lock() + defer graph.mutex.Unlock() + return len(graph.targets) +} + +// Returns a sorted slice of all the targets in the graph. +func (graph *BuildGraph) AllTargets() BuildTargets { + graph.mutex.Lock() + defer graph.mutex.Unlock() + targets := make(BuildTargets, 0, len(graph.targets)) + for _, target := range graph.targets { + targets = append(targets, target) + } + sort.Sort(targets) + return targets +} + +// Used for getting a local copy of the package map without having to expose it publicly. +func (graph *BuildGraph) PackageMap() map[string]*Package { + graph.mutex.Lock() + defer graph.mutex.Unlock() + packages := make(map[string]*Package) + for name, pkg := range graph.packages { + packages[name] = pkg + } + return packages +} + +func (graph *BuildGraph) AddDependency(from BuildLabel, to BuildLabel) { + graph.mutex.Lock() + defer graph.mutex.Unlock() + fromTarget := graph.targets[from] + // We might have done this already; do a quick check here first. + if fromTarget.resolvedDependencies[to] { + return + } + toTarget, present := graph.targets[to] + // The dependency may not exist yet if we haven't parsed its package. + // In that case we stash it away for later. + if !present { + graph.addPendingRevDep(from, to) + } else { + graph.linkDependencies(fromTarget, toTarget) + } +} + +func NewGraph() *BuildGraph { + graph := new(BuildGraph) + graph.targets = make(map[BuildLabel]*BuildTarget) + graph.packages = make(map[string]*Package) + graph.pendingRevDeps = make(map[BuildLabel]map[BuildLabel]bool) + graph.revDeps = make(map[BuildLabel][]*BuildTarget) + return graph +} + +// ReverseDependencies returns the set of revdeps on the given target. +func (graph *BuildGraph) ReverseDependencies(target *BuildTarget) []*BuildTarget { + graph.mutex.Lock() + defer graph.mutex.Unlock() + if revdeps, present := graph.revDeps[target.Label]; present { + return revdeps[:] + } + return []*BuildTarget{} +} + +// AllDepsBuilt returns true if all the dependencies of a target are built. +func (graph *BuildGraph) AllDepsBuilt(target *BuildTarget) bool { + graph.mutex.Lock() + defer graph.mutex.Unlock() + return target.allDepsBuilt() +} + +// AllDependenciesResolved returns true once all the dependencies of a target have been +// parsed and resolved to real targets. +func (graph *BuildGraph) AllDependenciesResolved(target *BuildTarget) bool { + graph.mutex.Lock() + defer graph.mutex.Unlock() + return target.allDependenciesResolved() +} + +// linkDependencies adds the dependency of fromTarget on toTarget and the corresponding +// reverse dependency in the other direction. +// This is complicated somewhat by the require/provide mechanism which is resolved at this +// point, but some of the dependencies may not yet exist. +func (graph *BuildGraph) linkDependencies(fromTarget, toTarget *BuildTarget) { + for _, label := range toTarget.ProvideFor(fromTarget) { + target, present := graph.targets[label] + if present { + fromTarget.Dependencies = append(fromTarget.Dependencies, target) + graph.revDeps[label] = append(graph.revDeps[label], fromTarget) + } else { + graph.addPendingRevDep(fromTarget.Label, label) + } + } + fromTarget.resolvedDependencies[toTarget.Label] = true +} + +func (graph *BuildGraph) addPendingRevDep(from, to BuildLabel) { + deps, present := graph.pendingRevDeps[to] + if !present { + deps = map[BuildLabel]bool{} + graph.pendingRevDeps[to] = deps + } + deps[from] = true +} + +// DependentTargets returns the labels that 'from' should actually depend on when it declared a dependency on 'to'. +// This is normally just 'to' but could be otherwise given require/provide shenanigans. +func (graph *BuildGraph) DependentTargets(from, to BuildLabel) []BuildLabel { + fromTarget := graph.Target(from) + if toTarget := graph.Target(to); fromTarget != nil && toTarget != nil { + graph.mutex.Lock() + defer graph.mutex.Unlock() + return toTarget.ProvideFor(fromTarget) + } + return []BuildLabel{to} +} diff --git a/src/core/label_parse_test.go b/src/core/label_parse_test.go new file mode 100644 index 0000000000..50bb3a2893 --- /dev/null +++ b/src/core/label_parse_test.go @@ -0,0 +1,102 @@ +// Tests parsing of build labels. + +package core + +import "testing" + +func assertLabel(t *testing.T, in, pkg, name string) { + assertLabelFunc(t, in, pkg, name, ParseBuildLabel) +} + +func assertRelativeLabel(t *testing.T, in, pkg, name string) { + assertLabelFunc(t, in, pkg, name, parseMaybeRelativeBuildLabel) +} + +func assertLabelFunc(t *testing.T, in, pkg, name string, f func(string, string) BuildLabel) { + defer func() { + if r := recover(); r != nil { + t.Errorf("Failed to parse %s: %s", in, r) + } + }() + label := f(in, "current_package") + if label.PackageName != pkg { + t.Errorf("Incorrect parse of %s: package name should be %s, was %s", in, pkg, label.PackageName) + } + if label.Name != name { + t.Errorf("Incorrect parse of %s: target name should be %s, was %s", in, name, label.Name) + } +} + +func assertNotLabel(t *testing.T, in, reason string) { + var label BuildLabel + defer func() { + if r := recover(); r == nil { + t.Errorf("%s should have failed (%s), instead generated %s", in, reason, label) + } + }() + label = ParseBuildLabel(in, "current_package") +} + +// These labels are accepted anywhere, on the command line or in BUILD files. + +func TestAbsoluteTarget(t *testing.T) { + assertLabel(t, "//path/to:target", "path/to", "target") + assertLabel(t, "//path:target", "path", "target") + assertLabel(t, "//:target", "", "target") + assertNotLabel(t, "//path:to/target", "can't have slashes in target names") + assertNotLabel(t, "//path:to:target", "can't have multiple colons") + assertNotLabel(t, "/path:to/target", "must have two initial slashes") + assertNotLabel(t, "/path/to:", "must pass a target name") +} + +func TestLocalTarget(t *testing.T) { + assertLabel(t, ":target", "current_package", "target") + assertLabel(t, ":thingy_wotsit_123", "current_package", "thingy_wotsit_123") + assertNotLabel(t, ":to/target", "can't have slashes in target names") + assertNotLabel(t, ":to:target", "can't have multiple colons") + assertNotLabel(t, "::to_target", "can't have multiple colons") +} + +func TestImplicitTarget(t *testing.T) { + assertLabel(t, "//path/to", "path/to", "to") + assertLabel(t, "//path", "path", "path") + assertNotLabel(t, "/path", "must have two initial slashes") +} + +func TestSubTargets(t *testing.T) { + assertLabel(t, "//path/to/...", "path/to", "...") + assertLabel(t, "//path/...", "path", "...") + assertLabel(t, "//...", "", "...") + // These three are not passing at the moment. Not completely crucial since the ... will just be + // treated as a package name but would be nice if they were rejected here. + // assertNotLabel(t, "//...:hello", "can't have stuff after the ellipsis") + // assertNotLabel(t, "//...1234", "can't have stuff after the ellipsis") + // assertNotLabel(t, "//.../...", "can't have multiple ellipses") +} + +// The following are only accepted on the command line and converted to absolute +// labels based on the current directory. + +func TestRelativeSubTargets(t *testing.T) { + assertRelativeLabel(t, "...", "current_package", "...") + assertRelativeLabel(t, "path/to/...", "current_package/path/to", "...") + assertNotLabel(t, "...:hello", "can't have stuff after the ellipsis") + assertNotLabel(t, "...1234", "can't have stuff after the ellipsis") + assertNotLabel(t, ".../...", "can't have multiple ellipses") +} + +func TestRelativeTarget(t *testing.T) { + assertRelativeLabel(t, "path/to:thingy", "current_package/path/to", "thingy") + assertRelativeLabel(t, ":thingy", "current_package", "thingy") + assertNotLabel(t, "path/to:", "must have a target name") + assertNotLabel(t, "path/to:thingy/mabob", "can't have a slash in target name") + assertNotLabel(t, "path/to:thingy:mabob", "can only have one colon") +} + +func TestRelativeImplicitTarget(t *testing.T) { + assertRelativeLabel(t, "path/to:thingy", "current_package/path/to", "thingy") + assertRelativeLabel(t, ":thingy", "current_package", "thingy") + assertNotLabel(t, "path/to:", "must have a target name") + assertNotLabel(t, "path/to:thingy/mabob", "can't have a slash in target name") + assertNotLabel(t, "path/to:thingy:mabob", "can only have one colon") +} diff --git a/src/core/lock.go b/src/core/lock.go new file mode 100644 index 0000000000..0f1916fe8f --- /dev/null +++ b/src/core/lock.go @@ -0,0 +1,74 @@ +// Contains utility functions for managing an exclusive lock file. +// Based on flock() underneath so + +package core + +import ( + "io/ioutil" + "os" + "path" + "strings" + "syscall" +) + +const lockFilePath = "plz-out/.lock" + +var lockFile *os.File + +// AcquireRepoLock opens the lock file and acquires the lock. +// Dies if the lock cannot be successfully acquired. +func AcquireRepoLock() { + var err error + // There is of course technically a bit of a race condition between the file & flock operations here, + // but it shouldn't matter much since we're trying to mutually exclude plz processes started by the user + // which (one hopes) they wouldn't normally do simultaneously. + os.MkdirAll(path.Dir(lockFilePath), DirPermissions) + // TODO(pebers): This doesn't seem quite as intended, I think the file still gets truncated sometimes. + // Not sure why since I'm not passing O_TRUNC... + if lockFile, err = os.OpenFile(lockFilePath, os.O_RDWR | os.O_CREATE, 0644); err != nil && !os.IsNotExist(err) { + log.Fatalf("Failed to acquire lock: %s", err) + } else if lockFile, err = os.Create(lockFilePath); err != nil { + log.Fatalf("Failed to create lock: %s", err) + } + // Try a non-blocking acquire first so we can warn the user if we're waiting. + log.Debug("Attempting to acquire lock %s...", lockFilePath) + if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err == nil { + log.Debug("Acquired lock %s", lockFilePath) + } else { + log.Warning("Looks like another plz is already running in this repo. Waiting for it to finish...") + if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX); err != nil { + log.Fatalf("Failed to acquire lock: %s", err) + } + } + + // Record the operation performed. + if _, err = lockFile.Seek(0, os.SEEK_SET); err == nil { + if n, err := lockFile.Write([]byte(strings.Join(os.Args[1:], " ") + "\n")); err == nil { + lockFile.Truncate(int64(n)) + } + } +} + +// ReleaseRepoLock releases the lock and closes the file handle. +// Does not die on errors, at this point it wouldn't really do any good. +func ReleaseRepoLock() { + if lockFile == nil { + log.Error("Lock file not acquired!") + return + } + if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN); err != nil { + log.Error("Failed to release lock: %s", err) // No point making this fatal really + } + if err := lockFile.Close(); err != nil { + log.Error("Failed to close lock file: %s", err) + } +} + +// ReadLastOperationOrDie reads the last operation performed from the lock file. Dies if unsuccessful. +func ReadLastOperationOrDie() []string { + contents, err := ioutil.ReadFile(lockFilePath) + if err != nil || len(contents) == 0 { + log.Fatalf("Sorry OP, can't read previous operation :(") + } + return strings.Split(strings.TrimSpace(string(contents)), " ") +} diff --git a/src/core/state.go b/src/core/state.go new file mode 100644 index 0000000000..f8ec193ddd --- /dev/null +++ b/src/core/state.go @@ -0,0 +1,362 @@ +package core + +import "bytes" +import "fmt" +import "sort" +import "sync" +import "time" + +type BuildLabelPair struct { + Label BuildLabel // Label of target to parse + Dependor BuildLabel // The target that depended on it +} + +// Passed about to track the current state of the build. +type BuildState struct { + Graph *BuildGraph + // Stream of pending packages to parse + pendingParses chan *BuildLabelPair + // Stream of pending targets to build + pendingBuilds chan BuildLabel + // Stream of pending tests to run + pendingTests chan BuildLabel + // Stream of results from the build + Results chan *BuildResult + // Used to signal goroutines to stop once the build is done. + Stop chan bool + // Configuration options + Config Configuration + // Hashes of variouts bits of the configuration, used for incrementality. + Hashes struct { + // Hash of the general config, not including specialised bits. + Config []byte + // Hash of the config relating to containerisation for tests. + Containerisation []byte + } + // Level of verbosity during the build + Verbosity int + // Cache to store / retrieve old build results. + Cache *Cache + // Targets that we were originally requested to build + OriginalTargets []BuildLabel + // Arguments to tests. + TestArgs []string + // True once the main thread has finished finding / loading targets. + TargetsLoaded bool + // True if we require rule hashes to be correctly verified (usually the case). + VerifyHashes bool + // Aggregated coverage for this run + Coverage TestCoverage + // True if tests should calculate coverage metrics + NeedCoverage bool + // True if we intend to build targets. False if we're just parsing + // (although some may be built if they're needed for parse). + NeedBuild bool + // True if we're running tests. False if we're only building or parsing. + NeedTests bool + // Max number of flakes for any test. 0 == defined by test. + MaxFlakes int + // Number of times to run each test target. + NumTestRuns int + // True to print the build / test commands as they're run + PrintCommands bool + // True to clean working directories after successful builds. + CleanWorkdirs bool + // Used to count the number of currently active/pending targets + numActive int + numPending int + numDone int + mutex sync.Mutex +} + +// Singleton instance of one of these. Tried to avoid introducing it but it ended up being +// inevitable to make some of the parsing code work. +var State *BuildState + +func (state *BuildState) AddActiveTarget() { + state.mutex.Lock() + state.numActive++ + state.mutex.Unlock() +} + +func (state *BuildState) AddPendingParse(label, dependor BuildLabel) { + state.mutex.Lock() + state.numActive++ + state.numPending++ + state.mutex.Unlock() + state.pendingParses <- &BuildLabelPair{label, dependor} +} + +func (state *BuildState) AddPendingBuild(label BuildLabel) { + state.addPending(label, state.pendingBuilds) +} + +func (state *BuildState) AddPendingTest(label BuildLabel) { + if state.NeedTests { + state.addPending(label, state.pendingTests) + } +} + +// Used to allow receive-only access to these channels. +// Caller should call ProcessedOne *after* they're done handling the result of one of these. +func (state *BuildState) ReceiveChannels() (<-chan *BuildLabelPair, <-chan BuildLabel, <-chan BuildLabel) { + return state.pendingParses, state.pendingBuilds, state.pendingTests +} + +func (state *BuildState) addPending(label BuildLabel, ch chan<- BuildLabel) { + state.mutex.Lock() + state.numPending++ + state.mutex.Unlock() + ch <- label +} + +func (state *BuildState) ProcessedOne() { + state.mutex.Lock() + state.numDone++ + state.numPending-- + if state.numPending <= 0 { + state.Stop <- true + } + state.mutex.Unlock() +} + +func (state *BuildState) IsOriginalTarget(label BuildLabel) bool { + for _, original := range state.OriginalTargets { + if original == label || (original.IsAllTargets() && original.PackageName == label.PackageName) { + return true + } + } + return false +} + +func (state *BuildState) LogBuildResult(tid int, label BuildLabel, status BuildResultStatus, description string) { + state.Results <- &BuildResult{ + ThreadId: tid, + Time: time.Now(), + Label: label, + Status: status, + Err: nil, + Description: description, + } +} + +func (state *BuildState) LogTestResult(tid int, label BuildLabel, status BuildResultStatus, results TestResults, coverage TestCoverage, err error, format string, args ...interface{}) { + state.Results <- &BuildResult{ + ThreadId: tid, + Time: time.Now(), + Label: label, + Status: status, + Err: err, + Description: fmt.Sprintf(format, args...), + Tests: results, + } + state.mutex.Lock() + defer state.mutex.Unlock() + state.Coverage.Aggregate(coverage) +} + +func (state *BuildState) LogBuildError(tid int, label BuildLabel, status BuildResultStatus, err error, format string, args ...interface{}) { + state.Results <- &BuildResult{ + ThreadId: tid, + Time: time.Now(), + Label: label, + Status: status, + Err: err, + Description: fmt.Sprintf(format, args...), + } +} + +func (state *BuildState) NumActive() int { + state.mutex.Lock() + defer state.mutex.Unlock() + return state.numActive +} + +func (state *BuildState) NumDone() int { + state.mutex.Lock() + defer state.mutex.Unlock() + return state.numDone +} + +// Expands any pseudo-targets (ie. :all, ... has already been resolved to a bunch :all targets) +// from the set of original targets. +func (state *BuildState) ExpandOriginalTargets() []BuildLabel { + ret := []BuildLabel{} + for _, target := range state.OriginalTargets { + if target.IsAllTargets() { + for _, target2 := range state.Graph.PackageOrDie(target.PackageName).Targets { + ret = append(ret, target2.Label) + } + } else { + ret = append(ret, target) + } + } + return ret +} + +func NewBuildState(numThreads int, cache *Cache, verbosity int, config Configuration) *BuildState { + State = &BuildState{ + Graph: NewGraph(), + // Buffer the channels, since they will both send & receive on (potentially) the same threads. + // TODO(pebers): this is rather awkward, they (particularly the parse channel) can block when + // given a sufficiently large set of inputs. I'd prefer not to make the buffers + // massive since they are dominating quite a bit of our memory usage... + pendingParses: make(chan *BuildLabelPair, numThreads*100000), + pendingBuilds: make(chan BuildLabel, numThreads*10000), + pendingTests: make(chan BuildLabel, numThreads*10000), + Results: make(chan *BuildResult, numThreads*10000), + Stop: make(chan bool, numThreads), + Config: config, + Verbosity: verbosity, + Cache: cache, + VerifyHashes: true, + NeedBuild: true, + numActive: 1, // One for the initial target adding on the main thread. + numPending: 1, + Coverage: TestCoverage{Files: map[string][]LineCoverage{}}, + } + State.Hashes.Config = config.Hash() + State.Hashes.Containerisation = config.ContainerisationHash() + return State +} + +type BuildResult struct { + // Thread id (or goroutine id, really) that generated this result. + ThreadId int + // Timestamp of this event + Time time.Time + // Target which has just changed + Label BuildLabel + // Its current status + Status BuildResultStatus + // Error, only populated for failure statuses + Err error + // Description of what's going on right now. + Description string + // Test results + Tests TestResults +} + +func NewBuildError(tid int, label BuildLabel, status BuildResultStatus, err error, description string) BuildResult { + return BuildResult{ + ThreadId: tid, + Time: time.Now(), + Label: label, + Status: status, + Err: err, + Description: description, + } +} + +type BuildResultStatus int + +const ( + PackageParsing BuildResultStatus = iota + PackageParsed BuildResultStatus = iota + ParseFailed BuildResultStatus = iota + TargetBuilding BuildResultStatus = iota + TargetBuilt BuildResultStatus = iota + TargetCached BuildResultStatus = iota + TargetBuildFailed BuildResultStatus = iota + TargetTesting BuildResultStatus = iota + TargetTested BuildResultStatus = iota + TargetTestFailed BuildResultStatus = iota +) + +type Cache interface { + // Stores the results of a single build target. + Store(target *BuildTarget, key []byte) + // Stores an extra file against a build target. + // The file name is relative to the target's out directory. + StoreExtra(target *BuildTarget, key []byte, file string) + // Retrieves the results of a single build target. + // If successful, the outputs will be placed into the output file tree. + Retrieve(target *BuildTarget, key []byte) bool + // Retrieves an extra file previously stored by StoreExtra. + // If successful, the file will be placed into the output file tree. + RetrieveExtra(target *BuildTarget, key []byte, file string) bool + // Cleans any artifacts associated with this target from the cache, for any possible key. + Clean(target *BuildTarget) +} + +// This is a pretty simple coverage format; we record one int for each line +// stating what its coverage is. +type TestCoverage struct { + Tests map[BuildLabel]map[string][]LineCoverage + Files map[string][]LineCoverage +} + +// Aggregates results from that coverage object into this one. +func (this *TestCoverage) Aggregate(that TestCoverage) { + if this.Tests == nil { + this.Tests = map[BuildLabel]map[string][]LineCoverage{} + } + if this.Files == nil { + this.Files = map[string][]LineCoverage{} + } + + // Assume that tests are independent (will currently always be the case). + for label, coverage := range that.Tests { + this.Tests[label] = coverage + } + // Files are more complex since multiple tests can cover the same file. + // We take the best result for each line from each test. + for filename, coverage := range that.Files { + this.Files[filename] = MergeCoverageLines(this.Files[filename], coverage) + } +} + +func MergeCoverageLines(existing, coverage []LineCoverage) []LineCoverage { + ret := make([]LineCoverage, len(existing)) + copy(ret, existing) + for i, line := range coverage { + if i >= len(ret) { + ret = append(ret, line) + } else if coverage[i] > ret[i] { + ret[i] = coverage[i] + } + } + return ret +} + +// Returns an ordered slice of all the files we have coverage information for. +func (this TestCoverage) OrderedFiles() []string { + files := []string{} + for file, _ := range this.Files { + files = append(files, file) + } + sort.Strings(files) + return files +} + +func NewTestCoverage() TestCoverage { + return TestCoverage{ + Tests: map[BuildLabel]map[string][]LineCoverage{}, + Files: map[string][]LineCoverage{}, + } +} + +// Produce a string representation of coverage for serialising to file so we don't +// expose the internal enum values (ordering is important so we may want to insert +// new ones later. This format happens to be the same as the one Phabricator uses, +// which is mildly useful to us since we want to integrate with it anyway. See +// https://secure.phabricator.com/book/phabricator/article/arcanist_coverage/ +// for more detail of how it works. +func TestCoverageString(lines []LineCoverage) string { + var buffer bytes.Buffer + for _, line := range lines { + buffer.WriteRune(lineCoverageOutput[line]) + } + return buffer.String() +} + +type LineCoverage uint8 + +const ( + NotExecutable LineCoverage = iota // Line isn't executable (eg. comment, blank) + Unreachable LineCoverage = iota // Line is executable but we've determined it can't be reached. So far not used. + Uncovered LineCoverage = iota // Line is executable but isn't covered. + Covered LineCoverage = iota // Line is executable and covered. +) + +var lineCoverageOutput = [...]rune{'N', 'X', 'U', 'C'} // Corresponds to ordering of enum. diff --git a/src/core/state_test.go b/src/core/state_test.go new file mode 100644 index 0000000000..56ba47b1f5 --- /dev/null +++ b/src/core/state_test.go @@ -0,0 +1,65 @@ +package core + +import "testing" + +var a = []LineCoverage{NotExecutable, Uncovered, Uncovered, Covered, NotExecutable, Unreachable} +var b = []LineCoverage{Uncovered, Covered, Uncovered, Uncovered, Unreachable, Covered} +var c = []LineCoverage{Covered, NotExecutable, Covered, Uncovered, Covered, NotExecutable} +var empty = []LineCoverage{} + +func assertCoverage(t *testing.T, expected, coverage []LineCoverage) { + if len(coverage) != len(expected) { + t.Errorf("Incorrect length of produced coverage; should be %d, was %d", len(expected), len(coverage)) + } else { + for i, cvr := range coverage { + if expected[i] != cvr { + t.Errorf("Incorrect coverage entry at index %d: should be %d, was %d", i, expected[i], cvr) + } + } + } +} + +func TestMergeCoverageLines1(t *testing.T) { + coverage := MergeCoverageLines(a, b) + expected := []LineCoverage{Uncovered, Covered, Uncovered, Covered, Unreachable, Covered} + assertCoverage(t, expected, coverage) +} + +func TestMergeCoverageLines2(t *testing.T) { + coverage := MergeCoverageLines(a, c) + expected := []LineCoverage{Covered, Uncovered, Covered, Covered, Covered, Unreachable} + assertCoverage(t, expected, coverage) +} + +func TestMergeCoverageLines3(t *testing.T) { + coverage := MergeCoverageLines(b, c) + expected := []LineCoverage{Covered, Covered, Covered, Uncovered, Covered, Covered} + assertCoverage(t, expected, coverage) +} + +func TestMergeCoverageLines4(t *testing.T) { + coverage := MergeCoverageLines(MergeCoverageLines(a, b), c) + expected := []LineCoverage{Covered, Covered, Covered, Covered, Covered, Covered} + assertCoverage(t, expected, coverage) +} + +func TestMergeCoverageLines5(t *testing.T) { + coverage := MergeCoverageLines(MergeCoverageLines(c, a), b) + expected := []LineCoverage{Covered, Covered, Covered, Covered, Covered, Covered} + assertCoverage(t, expected, coverage) +} + +func TestMergeCoverageLines6(t *testing.T) { + coverage := MergeCoverageLines(empty, b) + assertCoverage(t, b, coverage) +} + +func TestMergeCoverageLines7(t *testing.T) { + coverage := MergeCoverageLines(a, empty) + assertCoverage(t, a, coverage) +} + +func TestMergeCoverageLines8(t *testing.T) { + coverage := MergeCoverageLines(empty, empty) + assertCoverage(t, empty, coverage) +} diff --git a/src/core/test_data/failing.plzconfig b/src/core/test_data/failing.plzconfig new file mode 100644 index 0000000000..ccd5a775a6 --- /dev/null +++ b/src/core/test_data/failing.plzconfig @@ -0,0 +1,7 @@ +[python] +pext + +[java] +javactool = javac +sourceversion = 7 +targetversion = 7 \ No newline at end of file diff --git a/src/core/test_data/slices.plzconfig b/src/core/test_data/slices.plzconfig new file mode 100644 index 0000000000..cfc024dd9e --- /dev/null +++ b/src/core/test_data/slices.plzconfig @@ -0,0 +1,2 @@ +[build] +path = /sbin \ No newline at end of file diff --git a/src/core/test_data/working.plzconfig b/src/core/test_data/working.plzconfig new file mode 100644 index 0000000000..2494736997 --- /dev/null +++ b/src/core/test_data/working.plzconfig @@ -0,0 +1,7 @@ +[python] +pextool = pexmabob + +[java] +javactool = javac +sourcelevel = 8 +targetlevel = 7 diff --git a/src/core/utils.go b/src/core/utils.go new file mode 100644 index 0000000000..2c256f1edd --- /dev/null +++ b/src/core/utils.go @@ -0,0 +1,421 @@ +package core + +import ( + "bytes" + "crypto/sha1" + "fmt" + "io" + "io/ioutil" + "os" + "os/exec" + "path" + "path/filepath" + "sort" + "strings" + "time" +) + +// Root of the repository +var RepoRoot string + +// Initial working directory +var initialWorkingDir string + +// Initial subdir of the working directory, ie. what package did we start in. +var initialPackage string + +const DirPermissions = os.ModeDir | 0775 + +// FindRepoRoot returns the root directory of the current repo and sets the initial working dir. +// Dies on failure if 'die' is set. +func FindRepoRoot(die bool) { + initialWorkingDir, _ = os.Getwd() + RepoRoot, initialPackage = getRepoRoot(die) +} + +// getRepoRoot returns the root directory of the current repo and the initial package. +func getRepoRoot(die bool) (string, string) { + dir, err := os.Getwd() + if err != nil { + log.Fatalf("Couldn't determine working directory: %s", err) + } + // Walk up directories looking for a .plzconfig file, which we use to identify the root. + initial := dir + for dir != "" { + if PathExists(path.Join(dir, ConfigFileName)) { + return dir, strings.TrimLeft(initial[len(dir):], "/") + } + dir, _ = path.Split(dir) + dir = strings.TrimRight(dir, "/") + } + if die { + log.Fatalf("Couldn't locate the repo root. Are you sure you're inside a plz repo?") + } + return "", "" +} + +// Returns true if the build was initiated from the repo root. +// Used to provide slightly nicer output in some places. +func StartedAtRepoRoot() bool { + return RepoRoot == initialWorkingDir +} + +func PathExists(filename string) bool { + _, err := os.Stat(filename) + return err == nil +} + +func FileExists(filename string) bool { + info, err := os.Stat(filename) + return err == nil && !info.IsDir() +} + +// CopyFile copies a file from 'from' to 'to', with an attempt to perform a copy & rename +// to avoid chaos if anything goes wrong partway. +func CopyFile(from string, to string, mode os.FileMode) error { + fromFile, err := os.Open(from) + if err != nil { + return err + } + defer fromFile.Close() + return WriteFile(fromFile, to, mode) +} + +// WriteFile writes data from a reader to the file named 'to', with an attempt to perform +// a copy & rename to avoid chaos if anything goes wrong partway. +func WriteFile(fromFile io.Reader, to string, mode os.FileMode) error { + if err := os.RemoveAll(to); err != nil { + return err + } + dir, file := path.Split(to) + if err := os.MkdirAll(dir, DirPermissions); err != nil { + return err + } + tempFile, err := ioutil.TempFile(dir, file) + if err != nil { + return err + } + if _, err := io.Copy(tempFile, fromFile); err != nil { + return err + } + if err := tempFile.Close(); err != nil { + return err + } + // OK, now file is written; adjust permissions appropriately. + if mode == 0 { + mode = 0664 + } + if err := os.Chmod(tempFile.Name(), mode); err != nil { + return err + } + // And move it to its final destination. + return os.Rename(tempFile.Name(), to) +} + +// Copies either a single file or a directory. +// If 'link' is true then we'll attempt to hardlink files instead of copying them +// (on failure we still attempt a copy). +func RecursiveCopyFile(from string, to string, mode os.FileMode, link bool) error { + if info, err := os.Stat(from); err == nil && info.IsDir() { + return filepath.Walk(from, func(name string, info os.FileInfo, err error) error { + dest := path.Join(to, name[len(from):]) + if err != nil { + return err + } else if info.IsDir() { + return os.MkdirAll(dest, DirPermissions) + } else if (info.Mode() & os.ModeSymlink) != 0 { + fi, err := os.Stat(name) + if err != nil { + return err + } + if fi.IsDir() { + return RecursiveCopyFile(name+"/", dest+"/", mode, link) + } else { + return copyOrLinkFile(name, dest, mode, link) + } + } else { + return copyOrLinkFile(name, dest, mode, link) + } + }) + } else { + return copyOrLinkFile(from, to, mode, link) + } +} + +// Either copies or hardlinks a file based on the link argument. +func copyOrLinkFile(from, to string, mode os.FileMode, link bool) error { + if link { + if err := os.Link(from, to); err == nil { + return nil + } + } + return CopyFile(from, to, mode) +} + +// Runs an external command with a timeout. +func ExecWithTimeout(cmd *exec.Cmd, timeout int, defaultTimeout int) ([]byte, error) { + type cmdResult struct { + out []byte + err error + } + if timeout == 0 { + timeout = defaultTimeout + } + done := make(chan cmdResult, 1) + go func() { + out, err := cmd.CombinedOutput() + done <- cmdResult{out, err} + }() + select { + case <-time.After(time.Duration(timeout) * time.Second): + if err := cmd.Process.Kill(); err != nil { + return []byte{}, fmt.Errorf("Process %d could not be killed after exceeding timeout of %d seconds", cmd.Process.Pid, timeout) + } + // Don't do a blocking read here; if the process refuses to die we can hang on it forever. + // TODO(pebers): possibly we need to give it more of a chance to terminate than this. + select { + case result := <-done: + return result.out, fmt.Errorf("Timeout (%d seconds) exceeded", timeout) + default: + return []byte{}, fmt.Errorf("Timeout (%d seconds) exceeded. No process output available.", timeout) + } + case result := <-done: + return result.out, result.err + } +} + +// Returns all the sources for a function, allowing for sources that are other rules +// and rules that require transitive dependencies. +// Yielded values are pairs of the original source location and its temporary location for this rule. +type sourcePair struct{ Src, Tmp string } + +func IterSources(graph *BuildGraph, target *BuildTarget, includeTransitive bool) <-chan sourcePair { + ch := make(chan sourcePair) + done := map[BuildLabel]bool{} + donePaths := map[string]bool{} + tmpDir := target.TmpDir() + var inner func(dependency *BuildTarget) + inner = func(dependency *BuildTarget) { + if target == dependency { + // This is the current build rule, so link its sources. + for source := range dependency.AllSources() { + fullPaths := source.FullPaths(graph) + for i, sourcePath := range source.Paths(graph) { + ch <- sourcePair{fullPaths[i], path.Join(tmpDir, sourcePath)} + donePaths[path.Join(tmpDir, sourcePath)] = true + } + if label := source.Label(); label != nil { + if _, found := source.(BuildFileLabel); found { + done[*label] = true + } + } + } + } else { + // This is a dependency of the rule, so link its outputs. + for _, dep := range dependency.Outputs() { + depPath := path.Join(dependency.OutDir(), dep) + tmpPath := path.Join(tmpDir, dependency.Label.PackageName, dep) + if !donePaths[tmpPath] { + ch <- sourcePair{depPath, tmpPath} + donePaths[tmpPath] = true + } + } + // Mark any label-type outputs as done. + for _, out := range dependency.DeclaredOutputs() { + if LooksLikeABuildLabel(out) { + label, _ := ParseBuildFileLabel(out, target.Label.PackageName) + done[label] = true + } + } + } + done[dependency.Label] = true + if includeTransitive && (target == dependency || (target.NeedsTransitiveDependencies && !dependency.OutputIsComplete)) { + // Need to make sure we iterate these in order for things that care. + deps := make(BuildTargets, len(dependency.Dependencies)) + copy(deps, dependency.Dependencies) + sort.Sort(deps) + for _, dep := range deps { + if !done[dep.Label] && !target.IsTool(dep.Label) { + inner(dep) + } + } + } else if len(dependency.ExportedDependencies) > 0 { + deps := make(BuildLabels, len(dependency.ExportedDependencies)) + copy(deps, dependency.ExportedDependencies) + sort.Sort(deps) + for _, dep := range deps { + for _, dep2 := range recursivelyProvideFor(graph, target, dep) { + if !done[dep2] { + inner(graph.TargetOrDie(dep2)) + } + } + } + } + } + go func() { + inner(target) + close(ch) + }() + return ch +} + +// recursivelyProvideFor recursively applies ProvideFor to a target. +func recursivelyProvideFor(graph *BuildGraph, target *BuildTarget, dep BuildLabel) []BuildLabel { + ret := graph.TargetOrDie(dep).ProvideFor(target) + if len(ret) == 1 && ret[0] == dep { + return ret // Providing itself, don't recurse + } + ret2 := []BuildLabel{} + for _, r := range ret { + ret2 = append(ret2, recursivelyProvideFor(graph, target, r)...) + } + return ret2 +} + +// Yields all the runtime files for a rule (outputs & data files), similar to above. +func IterRuntimeFiles(graph *BuildGraph, target *BuildTarget, absoluteOuts bool) <-chan sourcePair { + done := map[string]bool{} + ch := make(chan sourcePair) + + makeOut := func(out string) string { + if absoluteOuts { + return path.Join(RepoRoot, target.TestDir(), out) + } else { + return out + } + } + + pushOut := func(src, out string) { + out = makeOut(out) + if !done[out] { + ch <- sourcePair{src, out} + done[out] = true + } + } + + var inner func(*BuildTarget) + inner = func(target *BuildTarget) { + for _, out := range target.Outputs() { + pushOut(path.Join(target.OutDir(), out), out) + } + for _, data := range target.Data { + fullPaths := data.FullPaths(graph) + for i, dataPath := range data.Paths(graph) { + pushOut(fullPaths[i], dataPath) + } + if label := data.Label(); label != nil { + for _, dep := range graph.TargetOrDie(*label).ExportedDependencies { + inner(graph.TargetOrDie(dep)) + } + } + } + for _, dep := range target.ExportedDependencies { + inner(graph.TargetOrDie(dep)) + } + } + go func() { + inner(target) + close(ch) + }() + return ch +} + +// Yields all the transitive input files for a rule (sources & data files), similar to above (again). +func IterInputPaths(graph *BuildGraph, target *BuildTarget) <-chan string { + // Use a couple of maps to protect us from dep-graph loops and to stop parsing the same target + // multiple times. We also only want to push files to the channel that it has not already seen. + donePaths := map[string]bool{} + doneTargets := map[*BuildTarget]bool{} + ch := make(chan string) + var inner func(*BuildTarget) + inner = func(target *BuildTarget) { + + if !doneTargets[target] { + // First yield all the sources of the target only ever pushing declared paths to + // the channel to prevent us outputting any intermediate files. + for source := range target.AllSources() { + // If the label is nil add any input paths contained here. + if label := source.Label(); label == nil { + for _, sourcePath := range source.FullPaths(graph) { + if !donePaths[sourcePath] { + ch <- sourcePath + donePaths[sourcePath] = true + } + } + // Otherwise we should recurse for this build label (and gather its sources) + } else { + inner(graph.TargetOrDie(*label)) + } + } + + // Now yield all the data deps of this rule. + for _, data := range target.Data { + // If the label is nil add any input paths contained here. + if label := data.Label(); label == nil { + for _, sourcePath := range data.FullPaths(graph) { + if !donePaths[sourcePath] { + ch <- sourcePath + donePaths[sourcePath] = true + } + } + // Otherwise we should recurse for this build label (and gather its sources) + } else { + inner(graph.TargetOrDie(*label)) + } + } + + // Finally recurse for all the deps of this rule. + for _, dep := range target.Dependencies { + inner(dep) + } + doneTargets[target] = true + } + } + go func() { + inner(target) + close(ch) + }() + return ch +} + +// Symlinks a single source file for a build rule. +func PrepareSource(sourcePath string, tmpPath string) error { + dir := path.Dir(tmpPath) + if !PathExists(dir) { + if err := os.MkdirAll(dir, DirPermissions); err != nil { + return err + } + } + if !PathExists(sourcePath) { + return fmt.Errorf("Source file %s doesn't exist", sourcePath) + } + return RecursiveCopyFile(sourcePath, tmpPath, 0, true) +} + +func PrepareSourcePair(pair sourcePair) error { + return PrepareSource(path.Join(RepoRoot, pair.Src), pair.Tmp) +} + +func PostBuildOutputFileName(target *BuildTarget) string { + return ".build_output_" + target.Label.Name +} + +// CollapseHash combines our usual four-part hash into one by XOR'ing them together. +// This helps keep things short in places where sometimes we get complaints about filenames being too long (?) +// and where we don't especially care about breaking out the individual parts of hashes, which +// is important for many parts of the system. +func CollapseHash(key []byte) []byte { + short := [sha1.Size]byte{} + // We store the rule hash twice, if it's repeated we must make sure not to xor it + // against itself. + if bytes.Equal(key[0:sha1.Size], key[sha1.Size:2*sha1.Size]) { + for i := 0; i < sha1.Size; i++ { + short[i] = key[i] ^ key[i+2*sha1.Size] ^ key[i+3*sha1.Size] + } + } else { + for i := 0; i < sha1.Size; i++ { + short[i] = key[i] ^ key[i+sha1.Size] ^ key[i+2*sha1.Size] ^ key[i+3*sha1.Size] + } + } + return short[:] +} diff --git a/src/core/utils_test.go b/src/core/utils_test.go new file mode 100644 index 0000000000..af4bf6d526 --- /dev/null +++ b/src/core/utils_test.go @@ -0,0 +1,33 @@ +package core + +import ( + "crypto/sha1" + "encoding/base64" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestCollapseHash(t *testing.T) { + // Test that these two come out differently + input1 := [sha1.Size * 4]byte{} + input2 := [sha1.Size * 4]byte{} + for i := 0; i < sha1.Size; i++ { + input1[i] = byte(i) + input2[i] = byte(i * 2) + } + output1 := CollapseHash(input1[:]) + output2 := CollapseHash(input2[:]) + assert.NotEqual(t, output1, output2) +} + +func TestCollapseHash2(t *testing.T) { + // Test of a couple of cases that weren't different... + input1, err1 := base64.URLEncoding.DecodeString("mByUsoTswXV2X_W6FHhBwJUCQM-YHJSyhOzBdXZf9boUeEHAlQJAz-DzaA7MCXxt5_FFws2WO51vKlqt-JThKzdEQn_bghpDDCuKOI9qGNI=") + input2, err2 := base64.URLEncoding.DecodeString("rSH0PS_dftB6KN_Jnu_jszhbxiutIfQ9L91-0Hoo38me7-OzOFvGK-DzaA7MCXxt5_FFws2WO51vKlqt-JThKzdEQn_bghpDDCuKOI9qGNI=") + assert.NoError(t, err1) + assert.NoError(t, err2) + output1 := CollapseHash(input1) + output2 := CollapseHash(input2) + assert.NotEqual(t, output1, output2) +} diff --git a/src/misc/BUILD b/src/misc/BUILD new file mode 100644 index 0000000000..6a1b87dedd --- /dev/null +++ b/src/misc/BUILD @@ -0,0 +1,30 @@ +go_library( + name = 'misc', + srcs = ['plz_diff_graphs.go'], + deps = [ + '//src/core', + '//src/query', + '//third_party/go:logging', + ], +) + +go_binary( + name = 'plz_diff_graphs', + main = 'plz_diff_graphs_main.go', + deps = [ + ':misc', + '//src/output', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'plz_diff_graphs_test', + srcs = ['plz_diff_graphs_test.go'], + deps = [ + ':misc', + '//src/core', + '//third_party/go:testify', + ], + data = glob(['test_data/*.json']), +) diff --git a/src/misc/get_plz.sh b/src/misc/get_plz.sh new file mode 100755 index 0000000000..3b896719de --- /dev/null +++ b/src/misc/get_plz.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Downloads a precompiled copy of Please from our s3 bucket and installs it. +set -eu + +REVISION=`curl -s https://s3-eu-west-1.amazonaws.com/please-build/latest_version` +# Find the os / arch to download. You can do this quite nicely with go env +# but we use this script on machines that don't necessarily have Go itself. +OS=`uname` +if [ "$OS" = "Linux" ]; then + GOOS="linux" +elif [ "$OS" = "Darwin" ]; then + GOOS="darwin" +else + echo "Unknown operating system $OS" + exit 1 +fi + +PLEASE_URL="https://s3-eu-west-1.amazonaws.com/please-build/${GOOS}_amd64/${REVISION}/please.tar.gz" + +if [ ! -d /opt/please ]; then + sudo mkdir -p /opt/please + sudo chown `whoami` /opt/please +fi + +rm -f /opt/please/*[^/] + +curl -sSL "${PLEASE_URL}" | tar -zxpf- -C /opt/ +ln -sf /opt/please/please /usr/local/bin/plz + +echo "Please installed." +plz --help diff --git a/src/misc/plz_complete.sh b/src/misc/plz_complete.sh new file mode 100644 index 0000000000..62cde872c2 --- /dev/null +++ b/src/misc/plz_complete.sh @@ -0,0 +1,31 @@ +# Bash parameter completion for Please. +# +# Note that colons are fairly crucial to us so some fiddling is needed to keep them +# from counting as separators as it normally would. + +_PleaseCompleteMe() { + local cur + COMPREPLY=() + _get_comp_words_by_ref -n "/:" cur + + if [[ "$cur" == -* ]]; then + COMPREPLY=( $( compgen -W "`plz --help 2>&1 | grep -Eo -- '--?[a-z_]+'`" -- $cur ) ) + else + if [[ "$COMP_CWORD" == "1" ]]; then + COMPREPLY=( $( compgen -W "build test cover query clean run update" -- $cur ) ) + else + if [[ "$COMP_CWORD" == "2" && "${COMP_WORDS[1]}" == "query" ]]; then + COMPREPLY=( $( compgen -W "somepath alltargets deps print completions affectedtests input output" -- $cur ) ) + else + local IFS=$'\n' + COMPREPLY=( $( compgen -W "`plz --noupdate -p query completions --cmd ${COMP_WORDS[1]} $cur 2>/dev/null`" -- $cur ) ) + unset IFS + fi + fi + fi + __ltrim_colon_completions "$cur" + return 0 +} + +complete -F _PleaseCompleteMe -o filenames plz +COMP_WORDBREAKS=${COMP_WORDBREAKS//:} diff --git a/src/misc/plz_complete.zsh b/src/misc/plz_complete.zsh new file mode 100644 index 0000000000..24caaf58bc --- /dev/null +++ b/src/misc/plz_complete.zsh @@ -0,0 +1,35 @@ +#compdef plz +#autoload + +#################################################### +# plz zsh completion +# +# rename to _plz and put somewhere in your $fpath +# e.g. /usr/local/share/zsh/site-functions +#################################################### + +local expl +local arguments +local -a _1st_arguments arguments +local options + +_1st_arguments=("${(f)$(plz --help \ + | perl -lnE 'say if (/Available commands/...//)' \ + | grep '^ ' \ + | perl -pE 's/^ +//; s/(?<=[^\s])\s+/:/')}") + +_targets() { + completions=("${(f)$(plz query completions --cmd $words[2,-1])}") + _wanted completions expl "Target" compadd -a completions +} + +if [[ $words[-1] =~ '-' ]]; then + options=("${(f)$(${words[1,-2]} --help \ + | perl -lnE 'if (/ *(-[a-zA-Z]), ([^ =]*)=? *(.+)/) {say "${1}:$3\n${2}:$3"} elsif (/^ *(--[^ =]*)[ =]*(.*)/) {say "${1}[$2]"}')}") + _arguments ${options[@]} '1:' +elif (( CURRENT == 2 )); then + _describe -t commands "plz subcommand" _1st_arguments + return +elif [[ $words[-2] =~ '^[a-z]' && $words[-2] != 'update' ]]; then + _targets +fi diff --git a/src/misc/plz_diff_graphs.go b/src/misc/plz_diff_graphs.go new file mode 100644 index 0000000000..756f4479ba --- /dev/null +++ b/src/misc/plz_diff_graphs.go @@ -0,0 +1,128 @@ +// Package misc contains utility functions, mostly to help the graph differ. +package misc + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "sort" + + "github.com/op/go-logging" + + "core" + "query" +) + +var log = logging.MustGetLogger("misc") + +// ParseGraphOrDie reads a graph file, or dies if anything goes wrong. +func ParseGraphOrDie(filename string) *query.JSONGraph { + graph := query.JSONGraph{} + data, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatalf("Error reading graph: %s", err) + } + if err := json.Unmarshal(data, &graph); err != nil { + log.Fatalf("Error parsing graph: %s", err) + } + return &graph +} + +// DiffGraphs calculates the differences between two graphs. +func DiffGraphs(before, after *query.JSONGraph, changedFiles, include, exclude []string, recurse bool) []core.BuildLabel { + changedFileMap := toMap(changedFiles) + allChanges := map[string]bool{} + for pkgName, afterPkg := range after.Packages { + beforePkg, present := before.Packages[pkgName] + if !present { + // Package didn't exist before, add every target in it. + for targetName := range afterPkg.Targets { + label := core.BuildLabel{PackageName: pkgName, Name: targetName} + allChanges[label.String()] = true + } + continue + } + for targetName, afterTarget := range afterPkg.Targets { + beforeTarget := beforePkg.Targets[targetName] + if targetChanged(&beforeTarget, &afterTarget, pkgName, changedFileMap) { + label := core.BuildLabel{PackageName: pkgName, Name: targetName} + allChanges[label.String()] = true + } + } + } + // Now we have all the targets that are directly changed, we locate all transitive ones + // in a second pass. We can't do this above because we've got no sensible ordering for it. + ret := core.BuildLabels{} + for pkgName, pkg := range after.Packages { + for targetName, target := range pkg.Targets { + if depsChanged(after, allChanges, pkgName, targetName, recurse) && + shouldInclude(&target, include, exclude) { + ret = append(ret, core.BuildLabel{PackageName: pkgName, Name: targetName}) + } + } + } + sort.Sort(ret) + return ret +} + +func targetChanged(before, after *query.JSONTarget, pkgName string, changedFiles map[string]bool) bool { + if before.Hash != after.Hash { + return true + } + // Note that if the set of sources etc has changed, the hash will have changed also, + // so here we're only worrying about the content. + for _, src := range after.Sources { + if _, present := changedFiles[pkgName+"/"+src]; present { + return true + } + } + return false +} + +// depsChanged returns true if any of the transitive dependencies of this target have changed. +// It marks any changes in allChanges for efficiency. +func depsChanged(graph *query.JSONGraph, allChanges map[string]bool, pkgName, targetName string, recurse bool) bool { + label := fmt.Sprintf("//%s:%s", pkgName, targetName) + changed, present := allChanges[label] + if present { + return changed + } + target := graph.Packages[pkgName].Targets[targetName] + if !recurse { + return false + } + for _, dep := range target.Deps { + depLabel := core.ParseBuildLabel(dep, "") + if depsChanged(graph, allChanges, depLabel.PackageName, depLabel.Name, recurse) { + allChanges[label] = true + return true + } + } + allChanges[label] = false + return false +} + +// toMap is a utility function to convert a slice of strings to a map for faster lookup. +func toMap(in []string) map[string]bool { + ret := map[string]bool{} + for _, s := range in { + ret[s] = true + } + return ret +} + +// shouldInclude returns true if the given combination of labels means we should return this target. +func shouldInclude(target *query.JSONTarget, include, exclude []string) bool { + return (len(include) == 0 || hasAnyLabel(target, include)) && !hasAnyLabel(target, exclude) +} + +func hasAnyLabel(target *query.JSONTarget, labels []string) bool { + for _, l1 := range labels { + for _, l2 := range target.Labels { + if l1 == l2 { + return true + } + } + } + return false +} diff --git a/src/misc/plz_diff_graphs_main.go b/src/misc/plz_diff_graphs_main.go new file mode 100644 index 0000000000..762ba6f79c --- /dev/null +++ b/src/misc/plz_diff_graphs_main.go @@ -0,0 +1,61 @@ +// plz_diff_graphs is a small utility to take the JSON representation of two build graphs +// (as output from 'plz query graph') and produce a list of targets that have changed +// between the two. +// +// Note that the 'ordering' of the two graphs matters, hence their labels 'before' and 'after'; +// the operation is non-commutative because targets that are added appear and those deleted do not. +// +// It also accepts a list of filenames that have changed and invalidates targets appropriately. +package main + +import ( + "fmt" + "io/ioutil" + "os" + "strings" + + "misc" + "output" +) + +var opts struct { + Verbosity int `short:"v" long:"verbosity" description:"Verbosity of output (higher number = more output, default 2 -> notice, warnings and errors only)" default:"2"` + Before string `short:"b" long:"before" required:"true" description:"File containing build graph before changes."` + After string `short:"a" long:"after" required:"true" description:"File containing build graph after changes."` + Include []string `short:"i" long:"include" description:"Label of targets to include."` + Exclude []string `short:"e" long:"exclude" description:"Label of targets to exclude." default:"manual"` + NoRecurse bool `long:"norecurse" description:"Don't recurse into dependencies of rules to see if they've changed"` + ChangedFiles struct { + Files []string `positional-arg-name:"files" description:"Files that have changed. - to read from stdin."` + } `positional-args:"true"` +} + +func readStdin() []string { + stdin, err := ioutil.ReadAll(os.Stdin) + if err != nil { + fmt.Printf("%s\n", err) + os.Exit(1) + } + trimmed := strings.TrimSpace(string(stdin)) + if trimmed == "" { + return []string{} + } + ret := strings.Split(trimmed, "\n") + for i, s := range ret { + ret[i] = strings.TrimSpace(s) + } + return ret +} + +func main() { + output.ParseFlagsOrDie("Please graph differ", &opts) + output.InitLogging(opts.Verbosity, "", 0) + before := misc.ParseGraphOrDie(opts.Before) + after := misc.ParseGraphOrDie(opts.After) + if len(opts.ChangedFiles.Files) == 1 && opts.ChangedFiles.Files[0] == "-" { + opts.ChangedFiles.Files = readStdin() + } + for _, label := range misc.DiffGraphs(before, after, opts.ChangedFiles.Files, opts.Include, opts.Exclude, !opts.NoRecurse) { + fmt.Printf("%s\n", label) + } +} diff --git a/src/misc/plz_diff_graphs_test.go b/src/misc/plz_diff_graphs_test.go new file mode 100644 index 0000000000..f17ba9844e --- /dev/null +++ b/src/misc/plz_diff_graphs_test.go @@ -0,0 +1,90 @@ +package misc + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "core" +) + +func TestDiffGraphsSimple(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/after.json", nil, nil, nil) + expected := []core.BuildLabel{ + core.ParseBuildLabel("//src/misc:plz_diff_graphs", ""), + core.ParseBuildLabel("//src/misc:plz_diff_graphs_test", ""), + } + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsRemovedPackage(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/removed_package.json", nil, nil, nil) + expected := []core.BuildLabel{} // Nothing because targets no longer exist + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsRemovedPackage2(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/removed_package.json", "src/misc/test_data/before.json", nil, nil, nil) + expected := []core.BuildLabel{ + core.ParseBuildLabel("//:all_tools", ""), + core.ParseBuildLabel("//src/cache/tools:cache_cleaner", ""), + core.ParseBuildLabel("//src/cache/tools:cache_cleaner_platform", ""), + } + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsChangedHash(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/changed_hash.json", nil, nil, nil) + expected := []core.BuildLabel{ + core.ParseBuildLabel("//:all_tools", ""), + core.ParseBuildLabel("//src/cache/server:http_cache_server_bin", ""), + } + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsChangedFile(t *testing.T) { + changedFile := []string{"src/build/java/net/thoughtmachine/please/test/TestCoverage.java"} + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/before.json", changedFile, nil, nil) + expected := []core.BuildLabel{ + core.ParseBuildLabel("//:all_tools", ""), + core.ParseBuildLabel("//src/build/java:_junit_runner#jar", ""), + core.ParseBuildLabel("//src/build/java:junit_runner", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:junit_runner", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:junit_runner_parameterized_test", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:junit_runner_test", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:please_coverage_class_loader_test", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:resources_root_test", ""), + core.ParseBuildLabel("//src/build/java/net/thoughtmachine/please/test:test_coverage_test", ""), + } + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsExcludeLabels(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/labels.json", nil, nil, []string{"manual"}) + expected := []core.BuildLabel{} + assert.Equal(t, expected, changes) +} + +func TestDiffGraphsIncludeLabels(t *testing.T) { + changes := readAndDiffGraphs("src/misc/test_data/before.json", "src/misc/test_data/labels2.json", nil, []string{"py"}, nil) + expected := []core.BuildLabel{ + core.ParseBuildLabel("//src/build/python:pex_import_test", ""), + } + assert.Equal(t, expected, changes) +} + +func readAndDiffGraphs(before, after string, changedFiles, include, exclude []string) []core.BuildLabel { + beforeGraph := ParseGraphOrDie(before) + afterGraph := ParseGraphOrDie(after) + return DiffGraphs(beforeGraph, afterGraph, changedFiles, include, exclude, true) +} diff --git a/src/misc/test_data/after.json b/src/misc/test_data/after.json new file mode 100644 index 0000000000..0916929c7f --- /dev/null +++ b/src/misc/test_data/after.json @@ -0,0 +1,5415 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "hash": "dSdE9RWGt4flZaVq70NUVaqwHWLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "hash": "vHcsPH1Qh577EiW5UaEruZQRNbHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/tools": { + "targets": { + "cache_cleaner": { + "inputs": [ + "plz-out/gen/src/cache/tools/cache_cleaner_platform.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/tools/cache_cleaner" + ], + "srcs": [ + "//src/cache/tools:cache_cleaner_platform" + ], + "deps": [ + "//src/cache/tools:cache_cleaner_platform", + "//third_party/go:logging", + "//third_party/go:humanize" + ], + "hash": "dd9jwTL1/vS+Y9OnbKq8tUKwL9nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_cleaner_platform": { + "inputs": [ + "src/cache/tools/cache_cleaner.go" + ], + "outs": [ + "src/cache/tools/cache_cleaner_platform.go" + ], + "srcs": [ + "cache_cleaner.go" + ], + "hash": "0jm8MZ88Lage8yS/mXq0tWdq7xfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/misc": { + "targets": { + "plz_diff_graphs": { + "inputs": [ + "src/misc/plz_diff_graphs.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go" + ], + "outs": [ + "src/misc/plz_diff_graphs" + ], + "srcs": [ + "plz_diff_graphs.go" + ], + "deps": [ + "//src/query:query", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "tXf5fz2WoAaw4K8wm+ZYhUdE8zDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_diff_graphs_test": { + "inputs": [ + "src/misc/plz_diff_graphs_test.go", + "plz-out/bin/src/misc/plz_diff_graphs", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/misc/plz_diff_graphs_test" + ], + "srcs": [ + "plz_diff_graphs_test.go" + ], + "deps": [ + "//src/misc:plz_diff_graphs", + "//third_party/go:testify" + ], + "hash": "u7xfOwRvvcN+iSk+uaIk97PY9HzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/misc/test_data/before.json b/src/misc/test_data/before.json new file mode 100644 index 0000000000..35b4b551c4 --- /dev/null +++ b/src/misc/test_data/before.json @@ -0,0 +1,5322 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "hash": "dSdE9RWGt4flZaVq70NUVaqwHWLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "hash": "vHcsPH1Qh577EiW5UaEruZQRNbHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/tools": { + "targets": { + "cache_cleaner": { + "inputs": [ + "plz-out/gen/src/cache/tools/cache_cleaner_platform.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/tools/cache_cleaner" + ], + "srcs": [ + "//src/cache/tools:cache_cleaner_platform" + ], + "deps": [ + "//src/cache/tools:cache_cleaner_platform", + "//third_party/go:logging", + "//third_party/go:humanize" + ], + "hash": "dd9jwTL1/vS+Y9OnbKq8tUKwL9nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_cleaner_platform": { + "inputs": [ + "src/cache/tools/cache_cleaner.go" + ], + "outs": [ + "src/cache/tools/cache_cleaner_platform.go" + ], + "srcs": [ + "cache_cleaner.go" + ], + "hash": "0jm8MZ88Lage8yS/mXq0tWdq7xfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/misc/test_data/changed_hash.json b/src/misc/test_data/changed_hash.json new file mode 100644 index 0000000000..7a661e1cda --- /dev/null +++ b/src/misc/test_data/changed_hash.json @@ -0,0 +1,5322 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "hash": "dSdE9RWGt4flZaVq70NUVaqwHWLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "hash": "vHcsPH1Qh577EiW5UaEruZQRNbHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcfgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/tools": { + "targets": { + "cache_cleaner": { + "inputs": [ + "plz-out/gen/src/cache/tools/cache_cleaner_platform.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/tools/cache_cleaner" + ], + "srcs": [ + "//src/cache/tools:cache_cleaner_platform" + ], + "deps": [ + "//src/cache/tools:cache_cleaner_platform", + "//third_party/go:logging", + "//third_party/go:humanize" + ], + "hash": "dd9jwTL1/vS+Y9OnbKq8tUKwL9nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_cleaner_platform": { + "inputs": [ + "src/cache/tools/cache_cleaner.go" + ], + "outs": [ + "src/cache/tools/cache_cleaner_platform.go" + ], + "srcs": [ + "cache_cleaner.go" + ], + "hash": "0jm8MZ88Lage8yS/mXq0tWdq7xfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/misc/test_data/labels.json b/src/misc/test_data/labels.json new file mode 100644 index 0000000000..52b4757284 --- /dev/null +++ b/src/misc/test_data/labels.json @@ -0,0 +1,5325 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "labels": [ + "manual" + ], + "hash": "wibble", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "hash": "vHcsPH1Qh577EiW5UaEruZQRNbHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/tools": { + "targets": { + "cache_cleaner": { + "inputs": [ + "plz-out/gen/src/cache/tools/cache_cleaner_platform.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/tools/cache_cleaner" + ], + "srcs": [ + "//src/cache/tools:cache_cleaner_platform" + ], + "deps": [ + "//src/cache/tools:cache_cleaner_platform", + "//third_party/go:logging", + "//third_party/go:humanize" + ], + "hash": "dd9jwTL1/vS+Y9OnbKq8tUKwL9nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_cleaner_platform": { + "inputs": [ + "src/cache/tools/cache_cleaner.go" + ], + "outs": [ + "src/cache/tools/cache_cleaner_platform.go" + ], + "srcs": [ + "cache_cleaner.go" + ], + "hash": "0jm8MZ88Lage8yS/mXq0tWdq7xfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/misc/test_data/labels2.json b/src/misc/test_data/labels2.json new file mode 100644 index 0000000000..33d132da7f --- /dev/null +++ b/src/misc/test_data/labels2.json @@ -0,0 +1,5328 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "labels": [ + "go" + ], + "hash": "wibble", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "labels": [ + "py" + ], + "hash": "wibble", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/tools": { + "targets": { + "cache_cleaner": { + "inputs": [ + "plz-out/gen/src/cache/tools/cache_cleaner_platform.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/tools/cache_cleaner" + ], + "srcs": [ + "//src/cache/tools:cache_cleaner_platform" + ], + "deps": [ + "//src/cache/tools:cache_cleaner_platform", + "//third_party/go:logging", + "//third_party/go:humanize" + ], + "hash": "dd9jwTL1/vS+Y9OnbKq8tUKwL9nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_cleaner_platform": { + "inputs": [ + "src/cache/tools/cache_cleaner.go" + ], + "outs": [ + "src/cache/tools/cache_cleaner_platform.go" + ], + "srcs": [ + "cache_cleaner.go" + ], + "hash": "0jm8MZ88Lage8yS/mXq0tWdq7xfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/misc/test_data/removed_package.json b/src/misc/test_data/removed_package.json new file mode 100644 index 0000000000..3d170940ac --- /dev/null +++ b/src/misc/test_data/removed_package.json @@ -0,0 +1,5287 @@ +{ + "packages": { + "": { + "targets": { + "all_tools": { + "inputs": [ + "plz-out/gen/please", + "plz-out/bin/src/build/java/jarcat", + "plz-out/bin/src/build/java/junit_runner", + "plz-out/gen/src/build/java/junit_runner.jar", + "plz-out/bin/src/build/java/please_maven", + "plz-out/bin/src/build/python/please_pex.pex", + "plz-out/bin/src/cache/server/http_cache_server_bin", + "plz-out/bin/src/cache/server/rpc_cache_server_bin", + "plz-out/bin/src/cache/tools/cache_cleaner" + ], + "outs": [ + "please_pex.pex", + "junit_runner", + "cache_cleaner", + "http_cache_server_bin", + "rpc_cache_server_bin", + "jarcat", + "please_maven" + ], + "srcs": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven" + ], + "deps": [ + "//src/build/python:please_pex", + "//src/build/java:junit_runner", + "//src/cache/tools:cache_cleaner", + "//src/cache/server:http_cache_server_bin", + "//src/cache/server:rpc_cache_server_bin", + "//src/build/java:jarcat", + "//src/build/java:please_maven", + "//:please" + ], + "hash": "FvfxcdQY2k+sR4zbqMh3rSZeBBnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "0bwLFmkP4SsGz6JaVZ/su0QkzTLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "version": { + "inputs": [ + "VERSION" + ], + "outs": [ + "VERSION" + ], + "srcs": [ + "VERSION" + ], + "hash": "P0Xa6ZvFT4Omd0K4p10caVx2vxLDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src": { + "targets": { + "please": { + "inputs": [ + "src/please.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/clean/clean.a", + "plz-out/gen/src/clean/clean.go", + "plz-out/gen/src/test/test.a", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal", + "plz-out/gen/src/query/query.a", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/run/run.a", + "plz-out/gen/src/run/run_step.go", + "plz-out/gen/src/update/update.a", + "plz-out/gen/src/update/update.go" + ], + "outs": [ + "src/please" + ], + "srcs": [ + "please.go" + ], + "deps": [ + "//src/build:build", + "//src/cache:cache", + "//src/clean:clean", + "//src/core:core", + "//src/output:output", + "//src/parse:parse", + "//src/query:query", + "//src/run:run", + "//src/test:test", + "//src/update:update", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "BCJyaC1YXKB7Pa9JE/bIgvAWiwrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build": { + "targets": { + "_build#srcs": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging" + ], + "hash": "nyTUOSLSGB7LpQDtUA3xZqYcHPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build": { + "inputs": [ + "src/build/build_step.go", + "src/build/command_replacements.go", + "src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/build/build.a" + ], + "srcs": [ + "build_step.go", + "command_replacements.go", + "incrementality.go" + ], + "deps": [ + "//src/core:core", + "//src/parse:parse", + "//src/cache:cache", + "//third_party/go:logging", + "//src/build:_build#srcs" + ], + "hash": "zkXRXTjBPLzLov7DzNCiEWgBZ/HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "command_replacements_test": { + "inputs": [ + "src/build/command_replacements_test.go", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/build/command_replacements_test" + ], + "srcs": [ + "command_replacements_test.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build" + ], + "hash": "dSdE9RWGt4flZaVq70NUVaqwHWLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/cc": { + "targets": { + "_cc_fst_lib#hdrs": { + "inputs": [ + "src/build/cc/fst_lib.h" + ], + "outs": [ + "src/build/cc/fst_lib.h" + ], + "srcs": [ + "fst_lib.h" + ], + "hash": "ped70h46dNPcOlMKuQQg7MqA1ADDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_lib#o": { + "inputs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/fst_lib.cc" + ], + "outs": [ + "src/build/cc/cc_fst_lib.o" + ], + "hash": "R6RaiagsTi9Df6GoVd0XxCsoEmvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_cc_fst_test#main": { + "outs": [ + "src/build/cc/_cc_fst_test_main.cc" + ], + "hash": "C96HmtnAsF6b6VW1DOlmgL/JZMPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embed_file_test#main": { + "outs": [ + "src/build/cc/_embed_file_test_main.cc" + ], + "hash": "DGRsiS5iAih56+jmZV04OCghOM3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/embedded_file_1.h" + ], + "hash": "WLDG5clUp3YdRiSouqaHHS/GO3XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "MYENTqJlgonUkWzZfS2PKvV1bVLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "f0fRbzhcZrvYQlCux/5SEGFEyfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc:embedded_file_3_gen" + ], + "hash": "T2d78+bz02jQB7bvxbfn5wnDngTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "raM6zG1mwev8xcBQbKGCCbtdKyzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.cc", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embedded_files.o" + ], + "deps": [ + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "obwmLXI23F2ecSp//s2mgj/R4DrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "/zM/4086df3MvjvcI14HZz36LLXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/shared_object_test.py" + ], + "outs": [ + "src/build/cc/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc:_shared_object_test#deps" + ], + "hash": "fi5VlYNxV+uPfhxYGQ8+B5Zd6gTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_so_test_py#zip": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/.so_test_py.pex.zip" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test" + ], + "hash": "dchdgIr4XVoRWfbi11Gy+M+wz3PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:test_binary" + ], + "hash": "gqt0l00AAqqnB7oZKPfrohZXw5DDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_fst_lib": { + "inputs": [ + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/fst_lib.h", + "src/build/cc/cc_fst_lib.o" + ], + "srcs": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "deps": [ + "//src/build/cc:_cc_fst_lib#hdrs", + "//src/build/cc:_cc_fst_lib#o" + ], + "hash": "aPYcQMNxHdxjqq8F4t4m3xIHxC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_fst_test": { + "inputs": [ + "src/build/cc/fst_test.cc", + "plz-out/gen/src/build/cc/_cc_fst_test_main.cc", + "plz-out/gen/src/build/cc/fst_lib.h", + "plz-out/gen/src/build/cc/cc_fst_lib.o" + ], + "outs": [ + "src/build/cc/cc_fst_test" + ], + "srcs": [ + "fst_test.cc", + "//src/build/cc:_cc_fst_test#main" + ], + "deps": [ + "//src/build/cc:_cc_fst_test#main", + "//src/build/cc:cc_fst_lib" + ], + "hash": "bmf4IRiiBQ6hxxP9tW0GqYd9HZjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/embed_file_test.cc", + "plz-out/gen/src/build/cc/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc:_embed_file_test#main", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "n3CQgVBa+B1jdxRpySLqJ18XBcjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/libembedded_file_1.a", + "src/build/cc/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_1#lib", + "//src/build/cc:_embedded_file_1#hdr" + ], + "hash": "Bs9GejH4enOpoLXc3mKpVAJET3zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/libembedded_file_3.a", + "src/build/cc/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc:_embedded_file_3#lib", + "//src/build/cc:_embedded_file_3#hdr" + ], + "hash": "A+3WlrJjUE07cjtvHGl+wuSiTTjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/embedded_file_3.txt" + ], + "hash": "cXZHbTWowgv7Vv9FROMjKOVMQ6HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_files.o" + ], + "outs": [ + "src/build/cc/embedded_files.h", + "src/build/cc/embedded_files.o" + ], + "srcs": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o" + ], + "deps": [ + "//src/build/cc:_embedded_files#hdrs", + "//src/build/cc:_embedded_files#o", + "//src/build/cc:embedded_file_1", + "//src/build/cc:embedded_file_3" + ], + "hash": "qpMr+EShDWDXLZ25G40LAio+QDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc:_shared_object_test#pex" + ], + "hash": "KVJWqND2nlHrzv6Gh+85I6g+y53DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/so_test.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "MGp2BtRU+l/OnwB6eGzK08Kus0DDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "so_test_py": { + "inputs": [ + "src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip", + "plz-out/gen/src/build/cc/so_test.so" + ], + "outs": [ + "src/build/cc/__init__.py", + "src/build/cc/so_test.so" + ], + "srcs": [ + "__init__.py", + "//src/build/cc:so_test" + ], + "deps": [ + "//src/build/cc:so_test", + "//src/build/cc:_so_test_py#zip" + ], + "hash": "IAG0WrZvmcw/9YYf+V6i0o0fVYLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/test_binary.cc", + "plz-out/gen/src/build/cc/embedded_files.h", + "plz-out/gen/src/build/cc/embedded_files.o", + "plz-out/gen/src/build/cc/libembedded_file_1.a", + "plz-out/gen/src/build/cc/embedded_file_1.h", + "plz-out/gen/src/build/cc/libembedded_file_3.a", + "plz-out/gen/src/build/cc/embedded_file_3.h", + "plz-out/gen/src/build/cc/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/test_binary" + ], + "deps": [ + "//src/build/cc:embedded_files" + ], + "hash": "+m6dJCzttDMmhutLk99LRkxz4U/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/cc/clang": { + "targets": { + "_embed_file_test#main": { + "outs": [ + "src/build/cc/clang/_embed_file_test_main.cc" + ], + "hash": "rz6T58bA/bxXypV2CfJcM9E2o7LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#hdr": { + "outs": [ + "src/build/cc/clang/embedded_file_1.h" + ], + "hash": "DJnc1p2XjkHv0Noy3kS9wngmycnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_1#lib": { + "inputs": [ + "src/build/cc/clang/embedded_file_1.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a" + ], + "srcs": [ + "embedded_file_1.txt" + ], + "hash": "dpS6GdNoGD9yiC8p1hrX4O8lwyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#hdr": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/embedded_file_3.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "vxAFszXMUTYfWcCSPaiyAN+xn3LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_file_3#lib": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a" + ], + "srcs": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_3_gen" + ], + "hash": "3S5RS8J2KuJQhFELBB0U3G/+sA/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#hdrs": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h" + ], + "srcs": [ + "embedded_files.h" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "8XrWqiRaf9utGbuDhLoeEFLkAvDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_embedded_files#o": { + "inputs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.cc", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embedded_files.o" + ], + "deps": [ + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "6AtqzOhC0PtYflwCJfY1Jva9lWzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:so_test" + ], + "hash": "zZW5LCZk2Vyk/qdJoat++TWTX1XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_shared_object_test#pex": { + "inputs": [ + "src/build/cc/clang/shared_object_test.py" + ], + "outs": [ + "src/build/cc/clang/.shared_object_test_main.pex.zip" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#deps" + ], + "hash": "0ycGleFxWE/paKcqfOB3nGIY7O3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_binary_test": { + "inputs": [ + "plz-out/bin/src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:test_binary" + ], + "hash": "Uh5UYKhaq78E153whLV4o07ozNbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embed_file_test": { + "inputs": [ + "src/build/cc/clang/embed_file_test.cc", + "plz-out/gen/src/build/cc/clang/_embed_file_test_main.cc", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h" + ], + "outs": [ + "src/build/cc/clang/embed_file_test" + ], + "srcs": [ + "embed_file_test.cc", + "//src/build/cc/clang:_embed_file_test#main" + ], + "deps": [ + "//src/build/cc/clang:_embed_file_test#main", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "dbAf5WQOUG9ML5fkDdNM+ZdfKQHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "embedded_file_1": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_1.a", + "src/build/cc/clang/embedded_file_1.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_1#lib", + "//src/build/cc/clang:_embedded_file_1#hdr" + ], + "hash": "REWAySLABLCZNaDsSlh9sExY9wXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a" + ], + "outs": [ + "src/build/cc/clang/libembedded_file_3.a", + "src/build/cc/clang/embedded_file_3.h" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "deps": [ + "//src/build/cc/clang:_embedded_file_3#lib", + "//src/build/cc/clang:_embedded_file_3#hdr" + ], + "hash": "cDTzt8Cr2nWaCKRk8hU76WB847rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_file_3_gen": { + "outs": [ + "src/build/cc/clang/embedded_file_3.txt" + ], + "hash": "vxYuYojGQi7FsBsWLuNdvVOp8tzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "embedded_files": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o" + ], + "outs": [ + "src/build/cc/clang/embedded_files.h", + "src/build/cc/clang/embedded_files.o" + ], + "srcs": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o" + ], + "deps": [ + "//src/build/cc/clang:_embedded_files#hdrs", + "//src/build/cc/clang:_embedded_files#o", + "//src/build/cc/clang:embedded_file_1", + "//src/build/cc/clang:embedded_file_3" + ], + "hash": "nslqTA4hsbbXwILmDoDiibq3yPDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shared_object_test": { + "inputs": [ + "plz-out/gen/src/build/cc/clang/.shared_object_test_main.pex.zip", + "plz-out/gen/src/build/cc/clang/so_test.so" + ], + "outs": [ + "src/build/cc/clang/shared_object_test.pex" + ], + "deps": [ + "//src/build/cc/clang:_shared_object_test#pex" + ], + "hash": "nWDqSQgHRQ51iGyzCCAMlRmaAxnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "so_test": { + "inputs": [ + "src/build/cc/clang/so_test.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/so_test.so" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "Jem/XhxaqW8qlOlXHl5YFGisDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_binary": { + "inputs": [ + "src/build/cc/clang/test_binary.cc", + "plz-out/gen/src/build/cc/clang/embedded_files.h", + "plz-out/gen/src/build/cc/clang/embedded_files.o", + "plz-out/gen/src/build/cc/clang/libembedded_file_1.a", + "plz-out/gen/src/build/cc/clang/embedded_file_1.h", + "plz-out/gen/src/build/cc/clang/libembedded_file_3.a", + "plz-out/gen/src/build/cc/clang/embedded_file_3.h", + "plz-out/gen/src/build/cc/clang/embedded_file_3.txt" + ], + "outs": [ + "src/build/cc/clang/test_binary" + ], + "deps": [ + "//src/build/cc/clang:embedded_files" + ], + "hash": "4fDaxa2GsXtE9RgugI5cJVysE87DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/build/java": { + "targets": { + "_java#srcs": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/zip_writer.go" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip" + ], + "hash": "yVatULQHy4pfN+KQwG2w6b6f9iDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/junit_runner.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "7HbO6o43gVxpZr+jeI6BKerYx0vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jarcat": { + "inputs": [ + "src/build/java/jarcat.go", + "plz-out/gen/src/build/java/java.a", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/jarcat" + ], + "srcs": [ + "jarcat.go" + ], + "deps": [ + "//src/build/java:java", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "O6uv/5TgAc3yTWfZryu5vvlaLtXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "java": { + "inputs": [ + "src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a" + ], + "outs": [ + "src/build/java/java.a" + ], + "srcs": [ + "zip_writer.go" + ], + "deps": [ + "//third_party/go:logging", + "//third_party/go/src/zip:zip", + "//src/build/java:_java#srcs" + ], + "hash": "YG34g1o4F+4GtH34ApUS+8cqrknDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "plz-out/gen/src/build/java/junit_runner.jar" + ], + "outs": [ + "src/build/java/junit_runner" + ], + "deps": [ + "//src/build/java:_junit_runner#jar" + ], + "hash": "zU9th0oM3ivN+TT5DXbQd8VX60jDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_maven": { + "inputs": [ + "src/build/java/please_maven.go", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/build/java/please_maven" + ], + "srcs": [ + "please_maven.go" + ], + "deps": [ + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "qtY7XyyTVvF4Lmebw3HeD8bhzMvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_writer_test": { + "inputs": [ + "src/build/java/zip_writer_test.go", + "plz-out/gen/src/build/java/zip_writer.go", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/zip/zip.a", + "plz-out/gen/third_party/go/src/zip/reader.go", + "plz-out/gen/third_party/go/src/zip/register.go", + "plz-out/gen/third_party/go/src/zip/struct.go", + "plz-out/gen/third_party/go/src/zip/writer.go" + ], + "outs": [ + "src/build/java/zip_writer_test" + ], + "srcs": [ + "zip_writer_test.go" + ], + "deps": [ + "//src/build/java:java", + "//third_party/go/src/zip:zip" + ], + "hash": "DKibvcCTNn+UcleV3VovNuNMARfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/java/net/thoughtmachine/please/test": { + "targets": { + "_junit_runner_parameterized_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#lib" + ], + "hash": "gwTE4Bako4DIvEEZbbRZX3qAQavDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_parameterized_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerParameterizedTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_parameterized_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerParameterizedTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "Mj1pP1H2I9dLAhIGSQeRoR2+o3bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#lib" + ], + "hash": "rcdEveVCo1Z0TulyDYfzU/0jz1fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_junit_runner_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseTestRunnerTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_junit_runner_test#lib.jar" + ], + "srcs": [ + "PleaseTestRunnerTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "BPJlJ60jBV3ZfyLF33bwuArI7U3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#lib" + ], + "hash": "zs1R3qD0wkKNXZ8IZo3WPNlFTEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_coverage_class_loader_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/PleaseCoverageClassLoaderTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_please_coverage_class_loader_test#lib.jar" + ], + "srcs": [ + "PleaseCoverageClassLoaderTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//third_party/java:junit" + ], + "hash": "twcp9rCV5DEJLEzy98Pa+yS3aOzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#lib" + ], + "hash": "Isv/b725+Mc87nrVL4jXUpvXhSbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_resources_root_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/ResourcesRootTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar", + "plz-out/gen/third_party/java/logback-classic.jar", + "plz-out/gen/third_party/java/logback-classic_src.jar", + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_resources_root_test#lib.jar" + ], + "srcs": [ + "ResourcesRootTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner", + "//src/build/java/net/thoughtmachine/please/test:logback_test_xml", + "//third_party/java:logback-classic" + ], + "hash": "FgZdG90f7mYUfyfz38zZQgmKj6bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#jar": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#lib" + ], + "hash": "xuRiKxSHbX6Z59Ed9ZU7YgGWTz3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test_coverage_test#lib": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverageTest.java", + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/_test_coverage_test#lib.jar" + ], + "srcs": [ + "TestCoverageTest.java", + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:junit_runner" + ], + "hash": "hM2D/2qzSD1ZeY/2zfmVyiQG42XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/TestCoverage.java", + "src/build/java/net/thoughtmachine/please/test/TestListener.java", + "src/build/java/net/thoughtmachine/please/test/TestMain.java", + "src/build/java/net/thoughtmachine/please/test/TestResult.java", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/hamcrest.jar", + "plz-out/gen/third_party/java/hamcrest_src.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner.jar" + ], + "srcs": [ + "TestCoverage.java", + "TestListener.java", + "TestMain.java", + "TestResult.java", + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "deps": [ + "//third_party/java:junit", + "//third_party/java:hamcrest", + "//third_party/java:guava", + "//third_party/java:jacoco" + ], + "hash": "bgvaLY+yEViOxO75Win5SmCepWTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit_runner_parameterized_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_parameterized_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_parameterized_test#jar" + ], + "hash": "gf4Hbz0FaXQNBI/BU2AedIr+cW7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "junit_runner_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/junit_runner_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/junit_runner_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_junit_runner_test#jar" + ], + "hash": "EMVGWhxUhfd4KO1rj7MnM9Ydc47DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "logback_test_xml": { + "inputs": [ + "src/build/java/net/thoughtmachine/please/test/test_data/logback-test.xml" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/logback_test_xml.jar" + ], + "srcs": [ + "test_data/logback-test.xml" + ], + "hash": "q+1Mv8OAX4etMEsH7llKNd7Nn7/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_coverage_class_loader_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/please_coverage_class_loader_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_please_coverage_class_loader_test#jar" + ], + "hash": "1rFf+VyUQi+dByjbudYnQn1F3YDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "resources_root_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/resources_root_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/resources_root_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_resources_root_test#jar" + ], + "hash": "8YofX5EMHdexV+JdpvRyNo5wPBbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_coverage_test": { + "inputs": [ + "plz-out/gen/src/build/java/net/thoughtmachine/please/test/test_coverage_test.jar" + ], + "outs": [ + "src/build/java/net/thoughtmachine/please/test/test_coverage_test" + ], + "deps": [ + "//src/build/java/net/thoughtmachine/please/test:_test_coverage_test#jar" + ], + "hash": "wXOaIJAr2YiLmVla/v5xDphGHbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/build/python": { + "targets": { + "__please_pex_pre#lib#zip": { + "inputs": [ + "src/build/python/pex.py" + ], + "outs": [ + "src/build/python/._please_pex_pre#lib.pex.zip" + ], + "srcs": [ + "pex.py" + ], + "hash": "jxL7Z1H7nG0wAgEoETZToJ32nyLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "/kkuntLm4+2Pwq5wbbOKryNG8SDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_custom_interpreter_test#pex": { + "inputs": [ + "src/build/python/custom_interpreter_test.py" + ], + "outs": [ + "src/build/python/.custom_interpreter_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#deps" + ], + "hash": "GCtC4XP1RBzBAab4snSlq1oMiU7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_main_files#zip": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "outs": [ + "src/build/python/.main_files.pex.zip" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "hash": "YYFcUCNEeJqo8Fv1DpVt0aIPzEXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/requests" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//third_party/python:dateutil", + "//third_party/python:requests" + ], + "hash": "VE1SdR9AsdvJp2iOLE8E/YlR0zHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_import_test#pex": { + "inputs": [ + "src/build/python/pex_import_test.py" + ], + "outs": [ + "src/build/python/.pex_import_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_import_test#deps" + ], + "hash": "b6tVo+4FmPvhcHaiSUiQpkvdBonDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "deps": [ + "//src/build/python:bootstrap_pexer" + ], + "hash": "A6whRNkFmsigpxhhtIINRzcupH/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex_test#pex": { + "inputs": [ + "src/build/python/pex_test.py" + ], + "outs": [ + "src/build/python/.pex_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_pex_test#deps" + ], + "hash": "k/a/Z04jEDMhDXH9Ml5V6/yUjtrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#lib": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "src/build/python/pex.py" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:bootstrap_pexer", + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources", + "//src/build/python:__please_pex_pre#lib#zip" + ], + "hash": "nmK84MMq+kDQtoEAY1GvnG89uSPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_please_pex_pre#pex": { + "outs": [ + "src/build/python/.please_pex_pre_main.pex.zip" + ], + "hash": "92bf/9rPV0ONz7XBfi9r4P+5T8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#deps": { + "inputs": [ + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so" + ], + "deps": [ + "//src/build/cc:so_test_py" + ], + "hash": "Y+VN6xCZvX7So+EPt5WvfLneKt7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_zip_unsafe_test#pex": { + "inputs": [ + "src/build/python/zip_unsafe_test.py" + ], + "outs": [ + "src/build/python/.zip_unsafe_test_main.pex.zip" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#deps" + ], + "hash": "WgUKQK43uTxHtLJ/1Q5AY7dHxrHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "bootstrap_pexer": { + "inputs": [ + "src/build/python/pex.py", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "src/build/python/bootstrap_pexer.pex" + ], + "srcs": [ + "pex.py" + ], + "deps": [ + "//src/build/python:main_files", + "//third_party/python:pex", + "//third_party/python:pkg_resources" + ], + "hash": "TNqPaDFTVf9OrA/VsJHeWE8U8VTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "custom_interpreter_test": { + "inputs": [ + "plz-out/gen/src/build/python/.custom_interpreter_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/custom_interpreter_test.pex" + ], + "deps": [ + "//src/build/python:_custom_interpreter_test#pex" + ], + "hash": "LC576NaRTW4eSDlj/UENHgU4M43DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "main_files": { + "inputs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "src/build/python/test_main.py", + "src/build/python/pex_main.py" + ], + "srcs": [ + "test_main.py", + "pex_main.py" + ], + "deps": [ + "//third_party/python:six", + "//third_party/python:xmlrunner", + "//third_party/python:coverage", + "//src/build/python:_main_files#zip" + ], + "hash": "bqQVTAH9atPmtF8EAdZq73BasEbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex_import_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_import_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "src/build/python/pex_import_test.pex" + ], + "deps": [ + "//src/build/python:_pex_import_test#pex" + ], + "hash": "vHcsPH1Qh577EiW5UaEruZQRNbHDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "pex_test": { + "inputs": [ + "plz-out/gen/src/build/python/.pex_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex" + ], + "outs": [ + "src/build/python/pex_test.pex" + ], + "deps": [ + "//src/build/python:_pex_test#pex" + ], + "hash": "UWTOQb46dbI7Ut6Rpp4Ip4bgRirDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "please_pex": { + "inputs": [ + "plz-out/bin/src/build/python/please_pex_pre.pex" + ], + "outs": [ + "src/build/python/please_pex.pex" + ], + "srcs": [ + "//src/build/python:please_pex_pre" + ], + "deps": [ + "//src/build/python:please_pex_pre" + ], + "hash": "xeSuOYFU9ATYMDO5zGxGyLOBGK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "please_pex_pre": { + "inputs": [ + "plz-out/gen/src/build/python/pex.py", + "plz-out/gen/src/build/python/._please_pex_pre#lib.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/build/python/test_main.py", + "plz-out/gen/src/build/python/pex_main.py", + "plz-out/gen/src/build/python/.main_files.pex.zip", + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip", + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip", + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip", + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip", + "plz-out/gen/src/build/python/.please_pex_pre_main.pex.zip" + ], + "outs": [ + "src/build/python/please_pex_pre.pex" + ], + "deps": [ + "//src/build/python:_please_pex_pre#pex", + "//src/build/python:_please_pex_pre#lib" + ], + "hash": "tx0YrReIxBdBg3FtZDvZP1WHxsrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip_unsafe_test": { + "inputs": [ + "plz-out/gen/src/build/python/.zip_unsafe_test_main.pex.zip", + "plz-out/gen/src/build/cc/__init__.py", + "plz-out/gen/src/build/cc/so_test.so", + "plz-out/gen/src/build/cc/.so_test_py.pex.zip" + ], + "outs": [ + "src/build/python/zip_unsafe_test.pex" + ], + "deps": [ + "//src/build/python:_zip_unsafe_test#pex" + ], + "hash": "X0kRUcXRh5OBVOlPvT7oWOS85PbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache": { + "targets": { + "_cache#srcs": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc" + ], + "hash": "bjjdCr1Q1dcqTDW5YTBzY7po5GbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache": { + "inputs": [ + "src/cache/cache.go", + "src/cache/dir_cache.go", + "src/cache/http_cache.go", + "src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/cache/cache.a" + ], + "srcs": [ + "cache.go", + "dir_cache.go", + "http_cache.go", + "rpc_cache.go" + ], + "deps": [ + "//src/core:core", + "//src/cache/proto:rpc_cache", + "//third_party/go:logging", + "//third_party/go:grpc", + "//src/cache:_cache#srcs" + ], + "hash": "LY4GzZgnGL+X5nvHqLRxofdoh33DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_cache_test": { + "inputs": [ + "src/cache/http_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/http_cache_test" + ], + "srcs": [ + "http_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "erjJlF9VTNOBFcCzHOXAfOplYbDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_test": { + "inputs": [ + "src/cache/rpc_cache_test.go", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/rpc_cache_test" + ], + "srcs": [ + "rpc_cache_test.go" + ], + "deps": [ + "//src/cache:cache", + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging", + "//src/cache/proto:rpc_cache" + ], + "hash": "Npt8Cv1yp0RRUUYvOsldu0h9d0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/cache/proto": { + "targets": { + "__rpc_cache#cc#hdrs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.h" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "0wh+VZDSx6QkkdkbFDTzYAky08fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#cc#o": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/_rpc_cache#cc.o" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "YQ+gKgMiQ0XoGLPPNF4pW1wcZEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#go#srcs": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc" + ], + "hash": "Zoz1N5MeFqvzrYx6qcGWogzld03DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__rpc_cache#py#zip": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/._rpc_cache#py.pex.zip" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "CRIPHmbA7EYv6H4zQR5OfA8UJPzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#cc": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o" + ], + "outs": [ + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/_rpc_cache#cc.o" + ], + "srcs": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o" + ], + "deps": [ + "//src/cache/proto:__rpc_cache#cc#hdrs", + "//src/cache/proto:__rpc_cache#cc#o", + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "E6hEvB6M1q4ol5079r203NFHdFPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "outs": [ + "src/cache/proto/rpc_cache.a" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/go:protobuf", + "//third_party/go:grpc", + "//src/cache/proto:__rpc_cache#go#srcs" + ], + "hash": "lNQKCSxAHHRBwcMkMqEGIOaeVdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#go_src": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "outs": [ + "src/cache/proto/rpc_cache/rpc_cache.pb.go" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache.pb.go" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "Fmp+14zGHjzdJINTW54RgKRRKe/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java": { + "inputs": [ + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar" + ], + "outs": [ + "src/cache/proto/_rpc_cache#java.jar" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#java_only", + "//third_party/java:protobuf", + "//third_party/java:grpc-all" + ], + "hash": "XhltlOhtLrP26/6msoxSX1jA6jnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#java_only": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc" + ], + "hash": "6sN81E7GqUD1hnXBU81UOAMYwufDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#proto": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache.proto" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "yRY793E7bEsPwQSnu7EQW6ETWoXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#protoc": { + "inputs": [ + "src/cache/proto/rpc_cache.proto" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py", + "src/cache/proto/rpc_cache.pb.go", + "src/cache/proto/rpc_cache.pb.h", + "src/cache/proto/rpc_cache.pb.cc" + ], + "srcs": [ + "rpc_cache.proto" + ], + "hash": "sfkb/uW5mQdxohDpyKWm6r26HdPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_rpc_cache#py": { + "inputs": [ + "plz-out/gen/src/cache/proto/._rpc_cache#py.pex.zip", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "src/cache/proto/rpc_cache_pb2.py" + ], + "srcs": [ + "//src/cache/proto:_rpc_cache#protoc:rpc_cache_pb2.py" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#protoc", + "//third_party/python:protobuf", + "//third_party/python:grpc", + "//src/cache/proto:__rpc_cache#py#zip" + ], + "hash": "fE8kCleRv/eNG1exlYSzV/q+n5XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_cache": { + "inputs": [ + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/src/cache/proto/_rpc_cache#cc.o", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/_rpc_cache#java.jar", + "plz-out/gen/third_party/java/grpc-all.jar", + "plz-out/gen/third_party/java/grpc-all_src.jar", + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar", + "plz-out/gen/third_party/java/protobuf.jar", + "plz-out/gen/third_party/java/protobuf_src.jar", + "plz-out/gen/src/cache/proto/rpc_cache.proto" + ], + "deps": [ + "//src/cache/proto:_rpc_cache#proto", + "//src/cache/proto:_rpc_cache#cc", + "//src/cache/proto:_rpc_cache#py", + "//src/cache/proto:_rpc_cache#java", + "//src/cache/proto:_rpc_cache#go", + "//src/cache/proto:_rpc_cache#go_src", + "//src/cache/proto:__rpc_cache#cc#hdrs" + ], + "hash": "2kFQGIa2dRESF8/ttMzZWz/q3KvDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/cache/server": { + "targets": { + "_server#srcs": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc" + ], + "hash": "tcpiTYdaYnYnMR6Exa+xI7RQ8ubDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cache_test": { + "inputs": [ + "src/cache/server/cache_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/cache/server/cache_test" + ], + "srcs": [ + "cache_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//third_party/go:testify", + "//src/cache/proto:rpc_cache" + ], + "hash": "RQoQKkwT+43YbYP4lLDZrHrwb2vDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "http_cache_server_bin": { + "inputs": [ + "src/cache/server/http_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/http_cache_server_bin" + ], + "srcs": [ + "http_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Wqk5vlgnOMUDhMzGpDubAuBcvrrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "http_server_test": { + "inputs": [ + "src/cache/server/http_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/http_server_test" + ], + "srcs": [ + "http_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "yH1rYMNRxx1V6yQBN8Zzoxq1oujDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "rpc_cache_server_bin": { + "inputs": [ + "src/cache/server/rpc_server_main.go", + "plz-out/gen/src/cache/server/server.a", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context", + "plz-out/gen/src/output/output.a", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/cache/server/rpc_cache_server_bin" + ], + "srcs": [ + "rpc_server_main.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/output:output", + "//third_party/go:logging" + ], + "hash": "Faehe0cyUiTWjJEo1npiszoPigTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "rpc_server_test": { + "inputs": [ + "src/cache/server/rpc_server_test.go", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/cache/proto/rpc_cache/rpc_cache.pb.go", + "plz-out/gen/src/cache/server/http_server.go", + "plz-out/gen/src/cache/server/rpc_server.go", + "plz-out/gen/src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux", + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "src/cache/server/rpc_server_test" + ], + "srcs": [ + "rpc_server_test.go" + ], + "deps": [ + "//src/cache/server:server", + "//src/cache/proto:rpc_cache" + ], + "hash": "bU/XSz1sFx1HGkgreeebcTmTTvbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "server": { + "inputs": [ + "src/cache/server/http_server.go", + "src/cache/server/rpc_server.go", + "src/cache/server/cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/gorilla/mux" + ], + "outs": [ + "src/cache/server/server.a" + ], + "srcs": [ + "http_server.go", + "rpc_server.go", + "cache.go" + ], + "deps": [ + "//src/cache/proto:rpc_cache", + "//src/core:core", + "//third_party/go:mux", + "//third_party/go:logging", + "//third_party/go:humanize", + "//third_party/go:grpc", + "//src/cache/server:_server#srcs" + ], + "hash": "yY93VgzORBqk0TSFUOtGkdT3Vx3DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/clean": { + "targets": { + "_clean#srcs": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.go" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging" + ], + "hash": "TX4OirUGW69yUC2oEJ0zwASVq8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "clean": { + "inputs": [ + "src/clean/clean.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/test/test.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/clean/clean.a" + ], + "srcs": [ + "clean.go" + ], + "deps": [ + "//src/core:core", + "//src/test:test", + "//third_party/go:logging", + "//src/clean:_clean#srcs" + ], + "hash": "s2do89NtgjsSD1v9vWEmghchBHfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/core": { + "targets": { + "_core#srcs": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "src/core/config_versioned.go" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging" + ], + "hash": "nRLzKt9OUfD3P9cxM3Xgtm9rwDPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "build_env_test": { + "inputs": [ + "src/core/build_env_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/build_env_test" + ], + "srcs": [ + "build_env_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "UTvGfXJL8zTOuwtxxxhryDoCXsLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_target_test": { + "inputs": [ + "src/core/build_target_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/build_target_test" + ], + "srcs": [ + "build_target_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "S1dwyqmxDb6h5oYqnM3sEaKaFrfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "config": { + "inputs": [ + "src/core/config.go", + "plz-out/gen/VERSION" + ], + "outs": [ + "src/core/config_versioned.go" + ], + "deps": [ + "//:version" + ], + "hash": "oHtpRa4ryppei3GB026MB+rNVpfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "config_test": { + "inputs": [ + "src/core/config_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/core/config_test" + ], + "srcs": [ + "config_test.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "OsrRYmPaXVvhnQXvJoYAgMr5Uv3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "core": { + "inputs": [ + "src/core/build_env.go", + "src/core/build_label.go", + "src/core/build_target.go", + "src/core/file_label.go", + "src/core/graph.go", + "src/core/lock.go", + "src/core/state.go", + "src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/core.a" + ], + "srcs": [ + "build_env.go", + "build_label.go", + "build_target.go", + "file_label.go", + "graph.go", + "lock.go", + "state.go", + "utils.go", + "//src/core:config" + ], + "deps": [ + "//src/core:config", + "//third_party/go:gcfg", + "//third_party/go:logging", + "//src/core:_core#srcs" + ], + "hash": "yuhUzftv7/8qDRcrkV+csb5KscvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "label_parse_test": { + "inputs": [ + "src/core/label_parse_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/label_parse_test" + ], + "srcs": [ + "label_parse_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "lOwgQ+BUXe1Hx+/FGjtQi6ZROTTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "state_test": { + "inputs": [ + "src/core/state_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/core/state_test" + ], + "srcs": [ + "state_test.go" + ], + "deps": [ + "//src/core:core" + ], + "hash": "0RXmTjGRcHthkkio1u6uKvfw6VXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/output": { + "targets": { + "_output#srcs": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "src/output/shell_output_templated.go", + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal" + ], + "hash": "+t+aFCIXd09OrINnMde+77uLHJvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_templated": { + "inputs": [ + "src/output/interactive_display.go" + ], + "outs": [ + "src/output/interactive_display_templated.go" + ], + "srcs": [ + "interactive_display.go" + ], + "hash": "zChxOIWo+e7OFXAf9K3rXkr6HznDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "interactive_display_test": { + "inputs": [ + "src/output/interactive_display_test.go", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/interactive_display_test" + ], + "srcs": [ + "interactive_display_test.go" + ], + "deps": [ + "//src/output:output" + ], + "hash": "aEmiFqMjT+av3JvtKzic6bpifLPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "output": { + "inputs": [ + "src/output/flags.go", + "src/output/logging.go", + "src/output/trace.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/output.a" + ], + "srcs": [ + "flags.go", + "logging.go", + "trace.go", + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated" + ], + "deps": [ + "//src/output:shell_output_templated", + "//src/output:interactive_display_templated", + "//src/core:core", + "//third_party/go:go-flags", + "//third_party/go:humanize", + "//third_party/go:logging", + "//third_party/go:terminal", + "//src/output:_output#srcs" + ], + "hash": "PDjfwYxycbe1gJ6fRHK1mfmwAxrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_templated": { + "inputs": [ + "src/output/shell_output.go" + ], + "outs": [ + "src/output/shell_output_templated.go" + ], + "srcs": [ + "shell_output.go" + ], + "hash": "Fi99GJJVRvCexGrh7nwim4liz2PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "shell_output_test": { + "inputs": [ + "src/output/shell_output_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/output/flags.go", + "plz-out/gen/src/output/logging.go", + "plz-out/gen/src/output/trace.go", + "plz-out/gen/src/output/shell_output_templated.go", + "plz-out/gen/src/output/interactive_display_templated.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/jessevdk/go-flags", + "plz-out/gen/third_party/go/src/github.com/dustin/go-humanize", + "plz-out/gen/third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "outs": [ + "src/output/shell_output_test" + ], + "srcs": [ + "shell_output_test.go" + ], + "deps": [ + "//src/output:output", + "//src/core:core" + ], + "hash": "4vfgC1x2BAQMxOw8oKQN2qLncNnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "src/parse": { + "targets": { + "_gen_output": { + "deps": [ + "//src/parse:_gen_output_name" + ], + "hash": "agrAo8AYx/syCpY8wzhAIbkjw8XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_gen_output_name": { + "hash": "cpxdYZ9AdePv85tuIM9y5fbcOu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_parse#srcs": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "src/parse/builtin_rules.go" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg" + ], + "hash": "JaH7QpXlAW3rfuKgkHTEfgO0vbDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#deps": { + "inputs": [ + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "deps": [ + "//src/parse:test_require", + "//src/build/python:bootstrap_pexer" + ], + "hash": "+XYjUX0H96dytBDr7I9FycncNCPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_require_provide_test#pex": { + "inputs": [ + "src/parse/require_provide_test.py" + ], + "outs": [ + "src/parse/.require_provide_test_main.pex.zip" + ], + "deps": [ + "//src/parse:_require_provide_test#deps" + ], + "hash": "bDELOZHgxb9LeqNaq0qz9AbZkhPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "additional_output_test": { + "inputs": [ + "src/parse/additional_output_test.go" + ], + "outs": [ + "src/parse/additional_output_test" + ], + "srcs": [ + "additional_output_test.go" + ], + "deps": [ + "//src/parse:_gen_output" + ], + "hash": "5ZO6emN7tB9Ff0cuu2KzmKKYXhTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "builtin_rules": { + "inputs": [ + "src/parse/rules/cc_rules.py", + "src/parse/rules/go_rules.py", + "src/parse/rules/java_rules.py", + "src/parse/rules/misc_rules.py", + "src/parse/rules/please_parser.py", + "src/parse/rules/proto_rules.py", + "src/parse/rules/python_rules.py", + "src/parse/rules/sh_rules.py", + "plz-out/bin/third_party/go/bin/go-bindata" + ], + "outs": [ + "src/parse/builtin_rules.go" + ], + "srcs": [ + "rules/cc_rules.py", + "rules/go_rules.py", + "rules/java_rules.py", + "rules/misc_rules.py", + "rules/please_parser.py", + "rules/proto_rules.py", + "rules/python_rules.py", + "rules/sh_rules.py" + ], + "deps": [ + "//third_party/go:go-bindata" + ], + "hash": "K1gSEC3B0aYgtjALmxGQp2TEHO7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "glob_test": { + "inputs": [ + "src/parse/glob_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/glob_test" + ], + "srcs": [ + "glob_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core" + ], + "hash": "XiTkdZIFggY9Ytj5PWH44PcFQMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "interpreter_test": { + "inputs": [ + "src/parse/interpreter_test.go", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/parse/interpreter_test" + ], + "srcs": [ + "interpreter_test.go" + ], + "deps": [ + "//src/parse:parse" + ], + "hash": "AiEkbtnRqXytXF/ugDpma3ctcJfDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "parse": { + "inputs": [ + "src/parse/interpreter.go", + "src/parse/parse_step.go", + "src/parse/interpreter.h", + "src/parse/interpreter.c", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a" + ], + "outs": [ + "src/parse/parse.a" + ], + "srcs": [ + "interpreter.go", + "parse_step.go", + "interpreter.h", + "interpreter.c", + "//src/parse:builtin_rules" + ], + "deps": [ + "//src/parse:builtin_rules", + "//src/core:core", + "//third_party/go:logging", + "//third_party/go:gcfg", + "//src/parse:_parse#srcs" + ], + "hash": "Gdk1iaqCtrQ08q9gK/5siv+68XPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "parse_step_test": { + "inputs": [ + "src/parse/parse_step_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/stretchr/testify" + ], + "outs": [ + "src/parse/parse_step_test" + ], + "srcs": [ + "parse_step_test.go" + ], + "deps": [ + "//src/parse:parse", + "//src/core:core", + "//third_party/go:testify" + ], + "hash": "MtNq6rrLNTcOh0atjyV7eJqVAMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/gen/src/parse/.require_provide_test_main.pex.zip", + "plz-out/bin/src/build/python/bootstrap_pexer.pex", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/require_provide_test.pex" + ], + "deps": [ + "//src/parse:_require_provide_test#pex" + ], + "hash": "bBuQH6xZCwx4YwijuByj7dQR9CjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_require": { + "inputs": [ + "plz-out/gen/src/parse/test_require.go", + "plz-out/gen/src/parse/test_require.py" + ], + "outs": [ + "src/parse/test_require.py", + "src/parse/test_require.go" + ], + "srcs": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "deps": [ + "//src/parse:test_require_py", + "//src/parse:test_require_go" + ], + "hash": "2TaR20doLIMVi/BXfA0fDdbDBLLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "src/parse/test_require.go" + ], + "hash": "nv6e7apHUSR/LhyDvh5ikKB3BijDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "src/parse/test_require.py" + ], + "hash": "PG5oqI211GxyXomxd5eGOIwMH4jDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/parse/test_data/test_subfolder2": { + "targets": {} + }, + "src/query": { + "targets": { + "_query#srcs": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging" + ], + "hash": "SIUajbgHTSMPSSNkVArHDxWjGKLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "print_test": { + "inputs": [ + "src/query/print_test.go", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/query/affected_targets.go", + "plz-out/gen/src/query/alltargets.go", + "plz-out/gen/src/query/completions.go", + "plz-out/gen/src/query/deps.go", + "plz-out/gen/src/query/graph.go", + "plz-out/gen/src/query/inputs.go", + "plz-out/gen/src/query/outputs.go", + "plz-out/gen/src/query/print.go", + "plz-out/gen/src/query/query_step.go", + "plz-out/gen/src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go" + ], + "outs": [ + "src/query/print_test" + ], + "srcs": [ + "print_test.go" + ], + "deps": [ + "//src/query:query", + "//src/core:core" + ], + "hash": "aXQuDkGCtlvTwXBzYLIvo7IRAgbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query": { + "inputs": [ + "src/query/affected_targets.go", + "src/query/alltargets.go", + "src/query/completions.go", + "src/query/deps.go", + "src/query/graph.go", + "src/query/inputs.go", + "src/query/outputs.go", + "src/query/print.go", + "src/query/query_step.go", + "src/query/somepath.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/query/query.a" + ], + "srcs": [ + "affected_targets.go", + "alltargets.go", + "completions.go", + "deps.go", + "graph.go", + "inputs.go", + "outputs.go", + "print.go", + "query_step.go", + "somepath.go" + ], + "deps": [ + "//src/build:build", + "//src/core:core", + "//src/parse:parse", + "//third_party/go:logging", + "//src/query:_query#srcs" + ], + "hash": "5aOQOp2bWw44VC6Iihydl537KmrDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/run": { + "targets": { + "_run#srcs": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run_step.go" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging" + ], + "hash": "SyI7mnv0LYG2ak8LZ4k1WBv8cSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "run": { + "inputs": [ + "src/run/run_step.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/run/run.a" + ], + "srcs": [ + "run_step.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:logging", + "//src/run:_run#srcs" + ], + "hash": "SIJ15+CXnro1nt1oW+UiNlIeq4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/test": { + "targets": { + "_flakiness_test#deps": { + "hash": "EglqRAPfWljkDTRAcJRt0sNVWvjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_flakiness_test#pex": { + "inputs": [ + "src/test/flakiness_test.py" + ], + "outs": [ + "src/test/.flakiness_test_main.pex.zip" + ], + "deps": [ + "//src/test:_flakiness_test#deps" + ], + "hash": "tJRk5LiDw1uphNQ75FesLjDbOx7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_test#srcs": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging" + ], + "hash": "Y3iyGtFFVVbbxDYBAqYvj6F2oqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "container_args_test": { + "inputs": [ + "src/test/container_args_test.go" + ], + "outs": [ + "src/test/container_args_test" + ], + "srcs": [ + "container_args_test.go" + ], + "hash": "unS1CYFasgkTyU5oZlpr2cF0db/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "container_test": { + "inputs": [ + "src/test/container_test.go" + ], + "outs": [ + "src/test/container_test" + ], + "srcs": [ + "container_test.go" + ], + "hash": "HZQr4x9vpH7SPB2umZCujfdNbSLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_test": { + "inputs": [ + "src/test/coverage_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/coverage_test" + ], + "srcs": [ + "coverage_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "22b7lDguXqyw8N7Grnp+H72CgtrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "data_files_test": { + "inputs": [ + "src/test/data_files_test.sh" + ], + "outs": [ + "src/test/data_files_test.sh" + ], + "srcs": [ + "data_files_test.sh" + ], + "hash": "JnfDzOlxUAdgw58EbLhAqbB0Fd7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "flakiness_test": { + "inputs": [ + "plz-out/gen/src/test/.flakiness_test_main.pex.zip" + ], + "outs": [ + "src/test/flakiness_test.pex" + ], + "deps": [ + "//src/test:_flakiness_test#pex" + ], + "hash": "3p6fczN/m3md3ePEhdpf6OBzg1fDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_output_test": { + "hash": "hm3vlAkUKehrTv5LjzCOdiuzzw3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "results_test": { + "inputs": [ + "src/test/results_test.go", + "plz-out/gen/src/test/container.go", + "plz-out/gen/src/test/coverage.go", + "plz-out/gen/src/test/go_coverage.go", + "plz-out/gen/src/test/go_results.go", + "plz-out/gen/src/test/results.go", + "plz-out/gen/src/test/test_step.go", + "plz-out/gen/src/test/xml_coverage.go", + "plz-out/gen/src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/build/build_step.go", + "plz-out/gen/src/build/command_replacements.go", + "plz-out/gen/src/build/incrementality.go", + "plz-out/gen/src/cache/cache.a", + "plz-out/gen/src/cache/cache.go", + "plz-out/gen/src/cache/dir_cache.go", + "plz-out/gen/src/cache/http_cache.go", + "plz-out/gen/src/cache/rpc_cache.go", + "plz-out/gen/src/cache/proto/rpc_cache.a", + "plz-out/gen/src/cache/proto/rpc_cache.pb.go", + "plz-out/gen/src/cache/proto/rpc_cache_pb2.py", + "plz-out/gen/src/cache/proto/rpc_cache.pb.h", + "plz-out/gen/src/cache/proto/rpc_cache.pb.cc", + "plz-out/gen/third_party/go/src/google.golang.org/grpc", + "plz-out/gen/src/core/core.a", + "plz-out/gen/src/core/build_env.go", + "plz-out/gen/src/core/build_label.go", + "plz-out/gen/src/core/build_target.go", + "plz-out/gen/src/core/file_label.go", + "plz-out/gen/src/core/graph.go", + "plz-out/gen/src/core/lock.go", + "plz-out/gen/src/core/state.go", + "plz-out/gen/src/core/utils.go", + "plz-out/gen/src/core/config_versioned.go", + "plz-out/gen/third_party/go/src/gopkg.in/gcfg.v1", + "plz-out/gen/third_party/go/src/github.com/op/go-logging", + "plz-out/gen/src/parse/parse.a", + "plz-out/gen/src/parse/interpreter.go", + "plz-out/gen/src/parse/parse_step.go", + "plz-out/gen/src/parse/interpreter.h", + "plz-out/gen/src/parse/interpreter.c", + "plz-out/gen/src/parse/builtin_rules.go", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover" + ], + "outs": [ + "src/test/results_test" + ], + "srcs": [ + "results_test.go" + ], + "deps": [ + "//src/test:test" + ], + "hash": "BzinVog6R5vU4ZqEZiX5NX85iMTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test": { + "inputs": [ + "src/test/container.go", + "src/test/coverage.go", + "src/test/go_coverage.go", + "src/test/go_results.go", + "src/test/results.go", + "src/test/test_step.go", + "src/test/xml_coverage.go", + "src/test/xml_results.go", + "plz-out/gen/src/build/build.a", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/golang.org/x/tools/cover", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/test/test.a" + ], + "srcs": [ + "container.go", + "coverage.go", + "go_coverage.go", + "go_results.go", + "results.go", + "test_step.go", + "xml_coverage.go", + "xml_results.go" + ], + "deps": [ + "//src/core:core", + "//src/build:build", + "//third_party/go:cover", + "//third_party/go:logging", + "//src/test:_test#srcs" + ], + "hash": "VYjEtYtN3iFQ+Mhx/GlJepHfpgTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "src/update": { + "targets": { + "_update#srcs": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.go" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging" + ], + "hash": "qhdzqNhe3HRVSHNy4SfJFEJjXfXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "update": { + "inputs": [ + "src/update/update.go", + "plz-out/gen/src/core/core.a", + "plz-out/gen/third_party/go/src/github.com/op/go-logging" + ], + "outs": [ + "src/update/update.a" + ], + "srcs": [ + "update.go" + ], + "deps": [ + "//src/core:core", + "//third_party/go:logging", + "//src/update:_update#srcs" + ], + "hash": "JP0kxpG5pJ4pS3zfm7W0pXJZa9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test": { + "targets": { + "__coverage_output_test#deps": { + "hash": "YO5mXYpSNlmzN9pDoOiQe1ZfBvrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__coverage_output_test#deps" + ], + "hash": "QZg5WuvThjUxJB+6I0nCD3EQ2AzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#deps": { + "hash": "/amxz/Q+GbUVK0UqNWQ/tCcSoMXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "__no_coverage_output_test#pex": { + "inputs": [ + "test/coverage_output_test.py" + ], + "outs": [ + "test/._no_coverage_output_test_main.pex.zip" + ], + "deps": [ + "//test:__no_coverage_output_test#deps" + ], + "hash": "HPmoPQnJlaId0hnAODTOExD74UDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_gen": { + "hash": "U2iBQOVfrtWkyk2/rqA4gzo3M4PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_add_out_test": { + "deps": [ + "//test:_add_out_gen" + ], + "hash": "1KfwIZ4S8GRgMYH10LXWBeyqEXnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_manual_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_manual_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "Q6D7hMadyED9V85txXL1e2YUncXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_affectedtests_test": { + "inputs": [ + "test/affectedtests_test.go" + ], + "outs": [ + "test/_affectedtests_test" + ], + "srcs": [ + "affectedtests_test.go" + ], + "hash": "xkp108/MY5Qv9/MUplsM31ozEx/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_coverage_output_test.pex" + ], + "deps": [ + "//test:__coverage_output_test#pex" + ], + "hash": "C0e5YcsASIOO3urvavG7jgViLxzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_individual_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_individual_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/individual_test_run_java.jar" + ], + "deps": [ + "//test:_individual_test_run_java#lib" + ], + "hash": "sYW0v/fGEClx7JebnyaPYX/LHK7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_java#lib": { + "inputs": [ + "test/IndividualTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_individual_test_run_java#lib.jar" + ], + "srcs": [ + "IndividualTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "uxiKyCJzT9L8sJ7Db13hOWa5jZXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#deps": { + "hash": "jic8prVXuAUwiN39mcrLQnUfjrTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_individual_test_run_py#pex": { + "inputs": [ + "test/individual_test_run.py" + ], + "outs": [ + "test/.individual_test_run_py_main.pex.zip" + ], + "deps": [ + "//test:_individual_test_run_py#deps" + ], + "hash": "prI7CVWd3Uu0sesYtE2dZ6c0F4nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_coverage_output_test": { + "inputs": [ + "plz-out/gen/test/._no_coverage_output_test_main.pex.zip" + ], + "outs": [ + "test/_no_coverage_output_test.pex" + ], + "deps": [ + "//test:__no_coverage_output_test#pex" + ], + "hash": "5laA6EdFvPgCE6KAQLmI2VN5djPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "_no_test_run_java#jar": { + "inputs": [ + "plz-out/gen/test/_no_test_run_java#lib.jar", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/no_test_run_java.jar" + ], + "deps": [ + "//test:_no_test_run_java#lib" + ], + "hash": "JPlvbheYSnQH0qX5ejQi+GJy5c7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_no_test_run_java#lib": { + "inputs": [ + "test/NoTestRun.java", + "plz-out/gen/third_party/java/junit.jar", + "plz-out/gen/third_party/java/junit_src.jar" + ], + "outs": [ + "test/_no_test_run_java#lib.jar" + ], + "srcs": [ + "NoTestRun.java", + "//third_party/java:junit" + ], + "deps": [ + "//third_party/java:junit" + ], + "hash": "d0COxoeayYUeWsS9aBUroKRxhKzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_num_runs_test": { + "inputs": [ + "test/num_runs_test.go" + ], + "outs": [ + "test/_num_runs_test" + ], + "srcs": [ + "num_runs_test.go" + ], + "hash": "stmj2KQ+CIFHXtK+Usq5im+FDyjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "add_out_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iDqBXwF211MDjas4+SjWzv2Hu2rDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "basic_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1HxOsHR0WSinLqyYqUTseU4SRiTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "build_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "QDrUOUqIxPkQA86Wge0jFNBauWXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iihTclru0VCXF+vVFeKQVUOYmUbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "HLpODaJWtdP1tHx531A8WLqZZmLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "dep_required_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "czY0RJ9n0wZ1B1XSQ/4m8aL15DrDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "extra_flag_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "fx3BAIRJbHoX3v/n6wkg457j2SPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "failed_dep": { + "hash": "ETYk7G4/kP0ssrhsLG6p6zJI1fvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "individual_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "oVZLJ/mCveUNZI81vguSRhiat9LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_python_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "qDhKqA4tTyisXO20m4t3ByiTGcDDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_java": { + "inputs": [ + "plz-out/gen/test/individual_test_run_java.jar" + ], + "outs": [ + "test/individual_test_run_java" + ], + "deps": [ + "//test:_individual_test_run_java#jar" + ], + "hash": "p+Ma0zOVi97JwWZp3Zp+ayCrG9XDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "individual_test_run_py": { + "inputs": [ + "plz-out/gen/test/.individual_test_run_py_main.pex.zip" + ], + "outs": [ + "test/individual_test_run_py.pex" + ], + "deps": [ + "//test:_individual_test_run_py#pex" + ], + "hash": "mPSuy14tAICsGHKY38iqOg+FB6LDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_coverage_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "MK9QYTJtHzdI+pn4NJIIKw9W28bDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_java_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Br6aD3HR5gzs2YMUI9lGqnF2nhbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "no_test_run_java": { + "inputs": [ + "plz-out/gen/test/no_test_run_java.jar" + ], + "outs": [ + "test/no_test_run_java" + ], + "deps": [ + "//test:_no_test_run_java#jar" + ], + "hash": "gkvCJcr/mSdyYIEOuaG7NBZGdhzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "0KeFJ8uEV9xpkJSNt5lgies0KGvDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "num_runs_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "/XY/HJslUnk1W1FYZmEQhFBdUTXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "plz_e2e_test_build_defs": { + "inputs": [ + "test/plz_e2e_test.build_defs" + ], + "outs": [ + "test/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "/gUkB6W9An34BZlCYuJYZzT2H2TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "plz_run_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "LkhXx+QcHbEZwtkZD6GNBf8De1/DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_stdin_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jOu7+ZnOgZrfN7NO94FEfpDnc5HDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_affectedtests_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "c0sR/1+BgR3xuA3DIXCTCY0L+NTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_alltargets_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "1IVKSFW6IgayB61DXqZBs/LksCnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_output_filegroup": { + "inputs": [ + "plz-out/bin/src/please" + ], + "outs": [ + "test/please" + ], + "srcs": [ + "//src:please" + ], + "deps": [ + "//src:please" + ], + "hash": "dvdir3rPFroX6lMmzbpsKxiBxRTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "query_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "RJ76VbNx43Ap4ILwzDV18DqkTHnDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_nopath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "VEpE0fOB8qyyinS7ejFQuShIGkPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_reverse_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "Msg8eBgHDX0XBVQvTMyMAsI+ovTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "query_somepath_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "jTVz0Pvyur9AEX6S5z9o1H3a/WLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "require_provide_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "30tu12JRyONE8zALs6zzD1ha+K3DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "run_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "5OfqxFMCww7taeOS/NGphxxsTqjDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_caching_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "D9N+TGynizJ7cKc/mw1yIFKs3snDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_completion_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "uFODJU10kGdS0EjfeKlnzHuhD0nDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_nocache_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "ftKfxHLzlWvIKOJ2jgHxoP/zggbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "iX2f+KYe1HwMH7mYMRpgDjiIGTbDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_1": { + "hash": "AthXQHSMeGteyJhmG72kwbrZgqLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "test_output_test_2": { + "hash": "USKlsmDYB2rk/ugs34BSnWek4KzDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/build_defs": { + "targets": { + "plz_e2e_test": { + "inputs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "outs": [ + "test/build_defs/plz_e2e_test.build_defs" + ], + "srcs": [ + "plz_e2e_test.build_defs" + ], + "hash": "1h5rquaK2nONfv1wgxSDO5biMzTDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/cc_rules": { + "targets": { + "_cc_deps_test#main": { + "outs": [ + "test/cc_rules/_cc_deps_test_main.cc" + ], + "hash": "3fMFo+HrUbo9QYbCmKu0XcPlI8TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#hdrs": { + "inputs": [ + "test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib1.h" + ], + "srcs": [ + "lib1.h" + ], + "hash": "wMlCefIBhv0q0yqtTlvTd1I34OPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib1#o": { + "inputs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.cc" + ], + "outs": [ + "test/cc_rules/lib1.o" + ], + "hash": "7xp3cGwQkJOkymq7txLbLXsz6oDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#hdrs": { + "inputs": [ + "test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.h" + ], + "srcs": [ + "lib2.h" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "+pA1CFET1AUy1APs/VaEohyaOx/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_lib2#o": { + "inputs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.cc", + "plz-out/gen/test/cc_rules/lib1.h" + ], + "outs": [ + "test/cc_rules/lib2.o" + ], + "deps": [ + "//test/cc_rules:lib1" + ], + "hash": "5Mbm85Jh9W2kRPJb9z9sI+iTY1TDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "cc_deps_test": { + "inputs": [ + "test/cc_rules/deps_test.cc", + "plz-out/gen/test/cc_rules/_cc_deps_test_main.cc", + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib2.o", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/cc_deps_test" + ], + "srcs": [ + "deps_test.cc", + "//test/cc_rules:_cc_deps_test#main" + ], + "deps": [ + "//test/cc_rules:_cc_deps_test#main", + "//test/cc_rules:lib2" + ], + "hash": "PAha5xLbWNWBXO3V2ztIQGeQEFTDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_1": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "tSfo8lCLF8FL5yKt8rsLqQ72Ei7DcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "cc_query_somepath_test_2": { + "inputs": [ + "plz-out/bin/src/please" + ], + "deps": [ + "//src:please" + ], + "hash": "z6ykpBz9X7UqNfKkjhVjvETlekPDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "lib1": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o" + ], + "outs": [ + "test/cc_rules/lib1.h", + "test/cc_rules/lib1.o" + ], + "srcs": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "deps": [ + "//test/cc_rules:_lib1#hdrs", + "//test/cc_rules:_lib1#o" + ], + "hash": "d9xYaRp2RJdBR24mUHD4kL/KGaPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "lib2": { + "inputs": [ + "plz-out/gen/test/cc_rules/lib2.h", + "plz-out/gen/test/cc_rules/lib1.h", + "plz-out/gen/test/cc_rules/lib1.o", + "plz-out/gen/test/cc_rules/lib2.o" + ], + "outs": [ + "test/cc_rules/lib2.h", + "test/cc_rules/lib2.o" + ], + "srcs": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o" + ], + "deps": [ + "//test/cc_rules:_lib2#hdrs", + "//test/cc_rules:_lib2#o", + "//test/cc_rules:lib1" + ], + "hash": "YI+3HsutPZQT1R9TvaZC01N/4PbDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/completions": { + "targets": { + "binary": { + "outs": [ + "test/completions/bin.sh" + ], + "hash": "h6ha/ix1yO2EBl0ZhaBLPoda4VbDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "library": { + "outs": [ + "test/completions/lib.txt" + ], + "hash": "jwjglHFcm+LiArYyTYMoxle/WNrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "outs": [ + "test/completions/test.sh" + ], + "hash": "4/e4LiFK6NPQJvFPgTdsyjox1rLDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + } + } + }, + "test/go_rules": { + "targets": { + "_go_rules_test_lib#srcs": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.go" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test" + ], + "hash": "uq5luQ9r35Z1K13XCZ252MkBDrDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test": { + "inputs": [ + "plz-out/bin/test/go_rules/go_rules_test_bin" + ], + "deps": [ + "//test/go_rules:go_rules_test_bin" + ], + "hash": "eSzKUMd6VuBQDSMvGMR14WSUEOXDcgEsI2vAKnpbZL6KuEj4oejACQ", + "test": true + }, + "go_rules_test_bin": { + "inputs": [ + "test/go_rules/go_rules_test_bin.go", + "plz-out/gen/test/go_rules/go_rules_test_lib.a", + "plz-out/gen/test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a", + "plz-out/gen/test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/go_rules_test_bin" + ], + "srcs": [ + "go_rules_test_bin.go" + ], + "deps": [ + "//test/go_rules:go_rules_test_lib" + ], + "hash": "bMKbH96VY+xVdr9RwrNxvQwlJ8rDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go_rules_test_lib": { + "inputs": [ + "test/go_rules/go_rules_test_lib.go", + "plz-out/gen/test/go_rules/test/test.a" + ], + "outs": [ + "test/go_rules/go_rules_test_lib.a" + ], + "srcs": [ + "go_rules_test_lib.go" + ], + "deps": [ + "//test/go_rules/test:test", + "//test/go_rules:_go_rules_test_lib#srcs" + ], + "hash": "xZXWRDS7z7whmOEr6Dd3O0HbhlHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/go_rules/test": { + "targets": { + "_test#srcs": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.go" + ], + "srcs": [ + "test.go" + ], + "hash": "UwHtPzCZYxaQivohqCCWEJaYazzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test": { + "inputs": [ + "test/go_rules/test/test.go" + ], + "outs": [ + "test/go_rules/test/test.a" + ], + "srcs": [ + "test.go" + ], + "deps": [ + "//test/go_rules/test:_test#srcs" + ], + "hash": "Ct0p5oyzGd8SheKyELkFVEy4mSHDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "test/moar": { + "targets": { + "require_provide_check": { + "inputs": [ + "plz-out/gen/test/moar/test_require.py" + ], + "deps": [ + "//test/moar:test_require_fg" + ], + "hash": "czu4haSvutKYJHn5m+DW69xMhcHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_fg": { + "inputs": [ + "plz-out/gen/test/moar/test_require.go", + "plz-out/gen/test/moar/test_require.py" + ], + "outs": [ + "test/moar/test_require.py", + "test/moar/test_require.go" + ], + "srcs": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "deps": [ + "//test/moar:test_require_py", + "//test/moar:test_require_go" + ], + "hash": "bUGcDMMoTGDRbOnpu2KwnS0PzqfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_go": { + "outs": [ + "test/moar/test_require.go" + ], + "hash": "yqqcCotfLjmRoYpSRPi1oYN6bUDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "test_require_py": { + "outs": [ + "test/moar/test_require.py" + ], + "hash": "Zigvtx6a4wYzcMXhCnDByw4fe6LDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go": { + "targets": { + "cover": { + "outs": [ + "third_party/go/src/golang.org/x/tools/cover" + ], + "hash": "UiWdL61pVpNxMc8gHU++PhmHHCfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gcfg": { + "outs": [ + "third_party/go/src/gopkg.in/gcfg.v1" + ], + "hash": "lkaHfJVuOgya+FmIpOCe8bFDy87DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-bindata": { + "outs": [ + "third_party/go/bin/go-bindata" + ], + "hash": "qgqNa44iHHc3bQffed25/5SW0lfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "go-flags": { + "outs": [ + "third_party/go/src/github.com/jessevdk/go-flags" + ], + "hash": "Ky+B19RvonVsZKx1EBpkDQNIOgrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "gorilla_context": { + "outs": [ + "third_party/go/src/github.com/gorilla/context" + ], + "hash": "7+svWZoqCEG13glJAiXOxMNkryrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "outs": [ + "third_party/go/src/google.golang.org/grpc" + ], + "hash": "8Vy+D6vjdKM0MHm+9Zl5Ys+W+H3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "humanize": { + "outs": [ + "third_party/go/src/github.com/dustin/go-humanize" + ], + "hash": "1+ORyl7Hvyi3xWV8J4hwSv4dib7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logging": { + "outs": [ + "third_party/go/src/github.com/op/go-logging" + ], + "hash": "rXIiDZyzbaIh0PnS9LQefrRzNMjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "mux": { + "inputs": [ + "plz-out/gen/third_party/go/src/github.com/gorilla/context" + ], + "outs": [ + "third_party/go/src/github.com/gorilla/mux" + ], + "deps": [ + "//third_party/go:gorilla_context" + ], + "hash": "+Gm01eEGAzNV8mFLQfRZE8B5KlXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/go/src/google.golang.org/grpc" + ], + "deps": [ + "//third_party/go:grpc" + ], + "hash": "+/Mb/whZ6LPUUuw1Z7nfFY0ph7XDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "terminal": { + "outs": [ + "third_party/go/src/golang.org/x/crypto/ssh/terminal" + ], + "hash": "FcpaVJ/SEDPy72CSKaVjG9hpL/fDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "testify": { + "outs": [ + "third_party/go/src/github.com/stretchr/testify" + ], + "hash": "nJQvNZW9cHWT1vRoqC5U2gx+5Y/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/go/src/zip": { + "targets": { + "_zip#srcs": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "hash": "MF3fHjSjJkTBSN9EV5MovZnrsyHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "zip": { + "inputs": [ + "third_party/go/src/zip/reader.go", + "third_party/go/src/zip/register.go", + "third_party/go/src/zip/struct.go", + "third_party/go/src/zip/writer.go" + ], + "outs": [ + "third_party/go/src/zip/zip.a" + ], + "srcs": [ + "reader.go", + "register.go", + "struct.go", + "writer.go" + ], + "deps": [ + "//third_party/go/src/zip:_zip#srcs" + ], + "hash": "EHuCQesXI9pmMtGqE6YyJqC/FI/DcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/java": { + "targets": { + "_grpc-all#deps": { + "hash": "GHW2g31ZWQxfsp5i08UtPKwvbITDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_guava#deps": { + "hash": "I+KwVmV8hzyCuIErqHbv12+msC3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_jacoco#deps": { + "hash": "1tlqcXUAPq1QDXPBb+tcWGl2EN7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc-all": { + "inputs": [ + "plz-out/gen/third_party/java/guava.jar", + "plz-out/gen/third_party/java/guava_src.jar" + ], + "outs": [ + "third_party/java/grpc-all.jar", + "third_party/java/grpc-all_src.jar" + ], + "deps": [ + "//third_party/java:guava", + "//third_party/java:_grpc-all#deps" + ], + "hash": "9PDSn2cZp5nWfxw6tILj9hVQcifDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "guava": { + "outs": [ + "third_party/java/guava.jar", + "third_party/java/guava_src.jar" + ], + "deps": [ + "//third_party/java:_guava#deps" + ], + "hash": "k8HlmutD5M/CneKBaWhcEN8keTPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "hamcrest": { + "outs": [ + "third_party/java/hamcrest.jar", + "third_party/java/hamcrest_src.jar" + ], + "hash": "3G4cELL2GGcAoA3NC4nIrn8LYGrDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "jacoco": { + "deps": [ + "//third_party/java:_jacoco#deps" + ], + "hash": "qMc1vbEA3aV1crBRmmmFnSsjsnHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "junit": { + "outs": [ + "third_party/java/junit.jar", + "third_party/java/junit_src.jar" + ], + "hash": "LAShIOoIwd5cY6BLPqpWfCLGS5vDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-classic": { + "inputs": [ + "plz-out/gen/third_party/java/logback-core.jar", + "plz-out/gen/third_party/java/logback-core_src.jar", + "plz-out/gen/third_party/java/slf4j-api.jar", + "plz-out/gen/third_party/java/slf4j-api_src.jar" + ], + "outs": [ + "third_party/java/logback-classic.jar", + "third_party/java/logback-classic_src.jar" + ], + "deps": [ + "//third_party/java:logback-core", + "//third_party/java:slf4j-api" + ], + "hash": "UgfdT4xA/zMsjknEHYc64d0MTEHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "logback-core": { + "outs": [ + "third_party/java/logback-core.jar", + "third_party/java/logback-core_src.jar" + ], + "hash": "0sXW5uIp8z1918q1WCQzAmdX4o/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "outs": [ + "third_party/java/protobuf.jar", + "third_party/java/protobuf_src.jar" + ], + "hash": "x1vvNR7XXQW5teeJWsQpjvqPWu/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "slf4j-api": { + "outs": [ + "third_party/java/slf4j-api.jar", + "third_party/java/slf4j-api_src.jar" + ], + "hash": "BSkx0ofR88El3Ehw22+73FYioKDDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + }, + "third_party/python": { + "targets": { + "_coverage#install": { + "inputs": [ + "third_party/python/coverage_pex.patch" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "coverage_pex.patch" + ], + "hash": "LzngD6PgZinbFWjMfK0GDtGwm8nDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_coverage#zip": { + "inputs": [ + "plz-out/gen/third_party/python/coverage" + ], + "outs": [ + "third_party/python/.coverage.pex.zip" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install" + ], + "hash": "Fgyiyue7XQjoAyWw76tDyikkxA7DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#install": { + "outs": [ + "third_party/python/dateutil" + ], + "hash": "UnXOG8dt1RxBlIAdMdvCDc0ZbjHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_dateutil#zip": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil" + ], + "outs": [ + "third_party/python/.dateutil.pex.zip" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install" + ], + "hash": "59WbSfWDxRV4Gvfj8qBfnreb+WjDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#install": { + "outs": [ + "third_party/python/enum" + ], + "hash": "98lcfb/agadvKuqkqplGnFWXDFnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_enum#zip": { + "inputs": [ + "plz-out/gen/third_party/python/enum" + ], + "outs": [ + "third_party/python/.enum.pex.zip" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install" + ], + "hash": "wh+KEh+sBL3vEkpRdfpopqYov1zDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#install": { + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "hash": "2XsrV4CWO2cmGSKjHlp+UG3rp1bDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_futures#zip": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/.futures.pex.zip" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install" + ], + "hash": "/IWpfNoaCrOGFsTtmSgjveS1bgzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#install": { + "outs": [ + "third_party/python/grpc" + ], + "hash": "jA3IsGVNzSqbY95K2/SDWUbIVNPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_grpc#zip": { + "inputs": [ + "plz-out/gen/third_party/python/grpc" + ], + "outs": [ + "third_party/python/.grpc.pex.zip" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install" + ], + "hash": "kqgcFXFV09Idj1a7N97eWNnwWmTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#install": { + "inputs": [ + "third_party/python/dont_recompress.patch" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "dont_recompress.patch" + ], + "hash": "f5yfP8jTERTv6Zwy6vtPF8UTTU/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pex#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pex" + ], + "outs": [ + "third_party/python/.pex.pex.zip" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install" + ], + "hash": "DaDqXy0V9gW2pjQDVkI2S95wpALDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#install": { + "outs": [ + "third_party/python/pkg_resources.py" + ], + "hash": "OgVx1nXDmDmhdxleLvI/wnqPsDfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_pkg_resources#zip": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py" + ], + "outs": [ + "third_party/python/.pkg_resources.pex.zip" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install" + ], + "hash": "sR2/lL6GhqLmelat3QTP/3Ai0dvDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#install": { + "outs": [ + "third_party/python/google" + ], + "hash": "7OMczFruVZ5xPmDqf37e9k7ZeLDDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_protobuf#zip": { + "inputs": [ + "plz-out/gen/third_party/python/google" + ], + "outs": [ + "third_party/python/.protobuf.pex.zip" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install" + ], + "hash": "ohku8j82xf+tcCsooBWcJW4mTmHDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#install": { + "outs": [ + "third_party/python/requests" + ], + "hash": "a1a9d81liuJCirp6Oi9sLhr8HjTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_requests#zip": { + "inputs": [ + "plz-out/gen/third_party/python/requests" + ], + "outs": [ + "third_party/python/.requests.pex.zip" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install" + ], + "hash": "i5Yg5s1zCM1Qo5ykajAzMMl+pE/DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#install": { + "outs": [ + "third_party/python/six.py" + ], + "hash": "/gMpURXuTkpKvSYPrOGGcxE1SdLDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_six#zip": { + "inputs": [ + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/.six.pex.zip" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install" + ], + "hash": "geXev5UJTauv6H2dEQ+ZGfigl9PDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#install": { + "outs": [ + "third_party/python/xmlrunner" + ], + "hash": "osdyazaQeQ+jklBShMxKcY2jN+LDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "_xmlrunner#zip": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner" + ], + "outs": [ + "third_party/python/.xmlrunner.pex.zip" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install" + ], + "hash": "wpyDPUlEsbjscUGHVLujQJY/1V3DcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "coverage": { + "inputs": [ + "plz-out/gen/third_party/python/coverage", + "plz-out/gen/third_party/python/.coverage.pex.zip" + ], + "outs": [ + "third_party/python/coverage" + ], + "srcs": [ + "//third_party/python:_coverage#install" + ], + "deps": [ + "//third_party/python:_coverage#install", + "//third_party/python:_coverage#zip" + ], + "hash": "S3tnef6VL6F1LenOdmTa/ApdczPDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "dateutil": { + "inputs": [ + "plz-out/gen/third_party/python/dateutil", + "plz-out/gen/third_party/python/.dateutil.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/dateutil" + ], + "srcs": [ + "//third_party/python:_dateutil#install" + ], + "deps": [ + "//third_party/python:_dateutil#install", + "//third_party/python:six", + "//third_party/python:_dateutil#zip" + ], + "hash": "w6UJ7Lk5pssXX4CqZ/FcwAFDRfTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "enum": { + "inputs": [ + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/.enum.pex.zip" + ], + "outs": [ + "third_party/python/enum" + ], + "srcs": [ + "//third_party/python:_enum#install" + ], + "deps": [ + "//third_party/python:_enum#install", + "//third_party/python:_enum#zip" + ], + "hash": "3P0E36Ibun/hmSxYPtafi4u8bZfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "futures": { + "inputs": [ + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent", + "plz-out/gen/third_party/python/.futures.pex.zip" + ], + "outs": [ + "third_party/python/futures", + "third_party/python/concurrent" + ], + "srcs": [ + "//third_party/python:_futures#install" + ], + "deps": [ + "//third_party/python:_futures#install", + "//third_party/python:_futures#zip" + ], + "hash": "0kXMJhIFO99pVX+suv9FBBOo8PzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "grpc": { + "inputs": [ + "plz-out/gen/third_party/python/grpc", + "plz-out/gen/third_party/python/.grpc.pex.zip", + "plz-out/gen/third_party/python/enum", + "plz-out/gen/third_party/python/futures", + "plz-out/gen/third_party/python/concurrent" + ], + "outs": [ + "third_party/python/grpc" + ], + "srcs": [ + "//third_party/python:_grpc#install" + ], + "deps": [ + "//third_party/python:_grpc#install", + "//third_party/python:enum", + "//third_party/python:futures", + "//third_party/python:_grpc#zip" + ], + "hash": "3AxoqkdRhOPPpdl6GoTx28tIVYXDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pex": { + "inputs": [ + "plz-out/gen/third_party/python/pex", + "plz-out/gen/third_party/python/.pex.pex.zip" + ], + "outs": [ + "third_party/python/pex" + ], + "srcs": [ + "//third_party/python:_pex#install" + ], + "deps": [ + "//third_party/python:_pex#install", + "//third_party/python:_pex#zip" + ], + "hash": "kioo+zDIRDIIalaq94ou48MffGzDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "pkg_resources": { + "inputs": [ + "plz-out/gen/third_party/python/pkg_resources.py", + "plz-out/gen/third_party/python/.pkg_resources.pex.zip" + ], + "outs": [ + "third_party/python/pkg_resources.py" + ], + "srcs": [ + "//third_party/python:_pkg_resources#install" + ], + "deps": [ + "//third_party/python:_pkg_resources#install", + "//third_party/python:_pkg_resources#zip" + ], + "hash": "aIAnzkWZu/EHJAXYuerL3zuKL1HDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "protobuf": { + "inputs": [ + "plz-out/gen/third_party/python/google", + "plz-out/gen/third_party/python/.protobuf.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/google" + ], + "srcs": [ + "//third_party/python:_protobuf#install" + ], + "deps": [ + "//third_party/python:_protobuf#install", + "//third_party/python:six", + "//third_party/python:_protobuf#zip" + ], + "hash": "lMJEXoo6weRr/IOc/SefTCAVtjnDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "requests": { + "inputs": [ + "plz-out/gen/third_party/python/requests", + "plz-out/gen/third_party/python/.requests.pex.zip" + ], + "outs": [ + "third_party/python/requests" + ], + "srcs": [ + "//third_party/python:_requests#install" + ], + "deps": [ + "//third_party/python:_requests#install", + "//third_party/python:_requests#zip" + ], + "hash": "NmxOtRUFpvtZV0jftDk+sBoyTXTDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "six": { + "inputs": [ + "plz-out/gen/third_party/python/six.py", + "plz-out/gen/third_party/python/.six.pex.zip" + ], + "outs": [ + "third_party/python/six.py" + ], + "srcs": [ + "//third_party/python:_six#install" + ], + "deps": [ + "//third_party/python:_six#install", + "//third_party/python:_six#zip" + ], + "hash": "fy6uoVz3fA7m76e+9xxyF2fFOQfDcgEsI2vAKnpbZL6KuEj4oejACQ" + }, + "xmlrunner": { + "inputs": [ + "plz-out/gen/third_party/python/xmlrunner", + "plz-out/gen/third_party/python/.xmlrunner.pex.zip", + "plz-out/gen/third_party/python/six.py" + ], + "outs": [ + "third_party/python/xmlrunner" + ], + "srcs": [ + "//third_party/python:_xmlrunner#install" + ], + "deps": [ + "//third_party/python:_xmlrunner#install", + "//third_party/python:six", + "//third_party/python:_xmlrunner#zip" + ], + "hash": "F6pYl9nYTHHcQ5IvoYEReFZ+rLfDcgEsI2vAKnpbZL6KuEj4oejACQ" + } + } + } + } +} diff --git a/src/output/BUILD b/src/output/BUILD new file mode 100644 index 0000000000..de5d65a4fc --- /dev/null +++ b/src/output/BUILD @@ -0,0 +1,69 @@ +# These are the shell command code replacements made in shell_output.go +# Backslashes are deliberately repeated many times to get through all the levels of escaping needed. +REPLACEMENTS = { + 'BOLD': r'\\\\x1b[1m', + 'BOLD_GREY': r'\\\\x1b[30;1m', + 'BOLD_RED': r'\\\\x1b[31;1m', + 'BOLD_GREEN': r'\\\\x1b[32;1m', + 'BOLD_YELLOW': r'\\\\x1b[33;1m', + 'BOLD_BLUE': r'\\\\x1b[34;1m', + 'BOLD_MAGENTA': r'\\\\x1b[35;1m', + 'BOLD_CYAN': r'\\\\x1b[36;1m', + 'BOLD_WHITE': r'\\\\x1b[37;1m', + 'GREY': r'\\\\x1b[30m', + 'RED': r'\\\\x1b[31m', + 'GREEN': r'\\\\x1b[32m', + 'YELLOW': r'\\\\x1b[33m', + 'BLUE': r'\\\\x1b[34m', + 'MAGENTA': r'\\\\x1b[35m', + 'CYAN': r'\\\\x1b[36m', + 'WHITE': r'\\\\x1b[37m', + 'WHITE_ON_RED': r'\\\\x1b[37;41;1m', + 'RED_NO_BG': r'\\\\x1b[31;49;1m', + 'RESET': r'\\\\x1b[0m', + 'ERASE_AFTER': r'\\\\x1b[K', +} + +TEMPLATED_FILES = { + 'shell_output.go': 'shell_output_templated', + 'interactive_display.go': 'interactive_display_templated', +} +TEMPLATED_FILES_DEPS = [':' + x for x in TEMPLATED_FILES.values()] + +for file_name, rule_name in TEMPLATED_FILES.items(): + genrule( + name = rule_name, + srcs = [file_name], + outs = [rule_name + '.go'], + cmd = 'cat $SRC | %s > $OUT' % ' | '.join(r'sed -e "s/\\${%s}/%s/g"' % (k, v) for k, v in REPLACEMENTS.items()) + ) + +go_library( + name = 'output', + srcs = glob(['*.go'], excludes=TEMPLATED_FILES.keys() + ['*_test.go']) + TEMPLATED_FILES_DEPS, + deps = TEMPLATED_FILES_DEPS + [ + '//src/core', + '//third_party/go:go-flags', + '//third_party/go:humanize', + '//third_party/go:logging', + '//third_party/go:terminal', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'interactive_display_test', + srcs = ['interactive_display_test.go'], + deps = [ + ':output', + ], +) + +go_test( + name = 'shell_output_test', + srcs = ['shell_output_test.go'], + deps = [ + ':output', + '//src/core', + ], +) diff --git a/src/output/flags.go b/src/output/flags.go new file mode 100644 index 0000000000..d4303e8f56 --- /dev/null +++ b/src/output/flags.go @@ -0,0 +1,70 @@ +// Contains helper functions related to flag parsing. + +package output + +import ( + "fmt" + "os" + "path" + "reflect" + "strings" + + "github.com/dustin/go-humanize" + "github.com/jessevdk/go-flags" + + "core" +) + +// ParseFlags parses the app's flags and returns the parser, any extra arguments, and any error encountered. +// It may exit if certain options are encountered (eg. --help). +func ParseFlags(appname string, data interface{}, args []string) (*flags.Parser, []string, error) { + parser := flags.NewNamedParser(path.Base(args[0]), flags.HelpFlag|flags.PassDoubleDash) + parser.AddGroup(appname+" options", "", data) + extraArgs, err := parser.ParseArgs(args[1:]) + if err != nil { + if err.(*flags.Error).Type == flags.ErrHelp { + fmt.Printf("%s\n", err) + os.Exit(0) + } else if err.(*flags.Error).Type == flags.ErrUnknownFlag && strings.Contains(err.(*flags.Error).Message, "halp") { + fmt.Printf("Hmmmmm, hows can I halp you?\n") + parser.WriteHelp(os.Stderr) + os.Exit(1) + } else if v := reflect.ValueOf(data).Elem().FieldByName("Version"); v != reflect.ValueOf(nil) && v.Bool() { + fmt.Printf("%s version %s\n", appname, core.PleaseVersion) + os.Exit(0) // Ignore other errors if --version was passed. + } + } + return parser, extraArgs, err +} + +// ParseFlagsOrDie, as the name suggests, parses the app's flags and dies if unsuccessful. +// Also dies if any unexpected arguments are passed. +func ParseFlagsOrDie(appname string, data interface{}) *flags.Parser { + return ParseFlagsFromArgsOrDie(appname, data, os.Args) +} + +// ParseFlagsFromArgsOrDie is similar to ParseFlagsOrDie but allows control over the +// flags passed. +func ParseFlagsFromArgsOrDie(appname string, data interface{}, args []string) *flags.Parser { + parser, extraArgs, err := ParseFlags(appname, data, args) + if err != nil { + parser.WriteHelp(os.Stderr) + fmt.Printf("\n%s\n", err) + os.Exit(1); + } else if len(extraArgs) > 0 { + fmt.Printf("Unknown option %s\n", extraArgs) + parser.WriteHelp(os.Stderr) + os.Exit(1) + } + return parser +} + +// A ByteSize is used for flags that represent some quantity of bytes that can be +// passed as human-readable quantities (eg. "10G"). +type ByteSize int64 + +func (b *ByteSize) UnmarshalFlag(in string) error { + b2, err := humanize.ParseBytes(in) + *b = ByteSize(b2) + return err +} diff --git a/src/output/interactive_display.go b/src/output/interactive_display.go new file mode 100644 index 0000000000..b238522eb5 --- /dev/null +++ b/src/output/interactive_display.go @@ -0,0 +1,193 @@ +package output + +import ( + "bytes" + "container/list" + "fmt" + "os" + "os/signal" + "regexp" + "runtime" + "strings" + "syscall" + "time" + "unsafe" + + "github.com/op/go-logging" + + "core" +) + +func display(state *core.BuildState, buildingTargets *[]buildingTarget, stop <-chan interface{}, done chan<- interface{}) { + backend := logBackend{InteractiveRows: len(*buildingTargets), MaxRecords: 10, LogMessages: list.New(), Formatter: logFormatter()} + go func() { + sig := make(chan os.Signal, 10) + signal.Notify(sig, syscall.SIGWINCH) + for { + <-sig + recalcWindowSize(&backend) + } + }() + recalcWindowSize(&backend) + setLogBackend(logBackendFacade{&backend}) + + printLines(state, *buildingTargets, backend.MaxInteractiveRows, backend.Cols) + outputLines := len(backend.Output) + ticker := time.NewTicker(50 * time.Millisecond) +loop: + for { + select { + case <-stop: + break loop + case <-ticker.C: + moveToFirstLine(*buildingTargets, outputLines, backend.MaxInteractiveRows) + printLines(state, *buildingTargets, backend.MaxInteractiveRows, backend.Cols) + for _, line := range backend.Output { + printf("\x1b[2K%s\n", line) // erase each line as we go + } + outputLines = len(backend.Output) + } + } + ticker.Stop() + // Clear it all out. + moveToFirstLine(*buildingTargets, outputLines, backend.MaxInteractiveRows) + printf("\x1b[0J") // Clear out to end of screen. + setLogBackend(logging.NewLogBackend(os.Stderr, "", 0)) + done <- struct{}{} +} + +// moveToFirstLine resets back to the first line. Not as easy as you might think. +func moveToFirstLine(buildingTargets []buildingTarget, outputLines, maxInteractiveRows int) { + if maxInteractiveRows > len(buildingTargets) { + maxInteractiveRows = len(buildingTargets) + } + printf("\x1b[%dF", maxInteractiveRows+1+outputLines) +} + +func printLines(state *core.BuildState, buildingTargets []buildingTarget, maxLines, cols int) { + now := time.Now() + printf("Building [%d/%d, %3.1fs]:\n", state.NumDone(), state.NumActive(), time.Since(startTime).Seconds()) + for i := 0; i < len(buildingTargets) && i < maxLines; i++ { + buildingTargets[i].Lock() + // Take a local copy of the structure, which isn't *that* big, so we don't need to retain the lock + // while we do potentially blocking things like printing. + target := buildingTargets[i].buildingTargetData + buildingTargets[i].Unlock() + label := displayLabel(target.Label) + if target.Active { + lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_WHITE}%s${ERASE_AFTER}\n", + now.Sub(target.Started).Seconds(), target.Colour, label, target.Description) + } else if time.Since(target.Finished).Seconds() < 0.5 { + // Only display finished targets for half a second after they're done. + duration := target.Finished.Sub(target.Started).Seconds() + if target.Failed { + lprintf(cols, "${BOLD_RED}=> [%4.1fs] ${RESET}%s%s ${BOLD_RED}Failed${ERASE_AFTER}\n", + duration, target.Colour, label) + } else if target.Cached { + lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${BOLD_GREY}%s${ERASE_AFTER}\n", + duration, target.Colour, label, target.Description) + } else { + lprintf(cols, "${BOLD_WHITE}=> [%4.1fs] ${RESET}%s%s ${WHITE}%s${ERASE_AFTER}\n", + duration, target.Colour, label, target.Description) + } + } else { + printf("${BOLD_GREY}=|${ERASE_AFTER}\n") + } + } + printf("${RESET}") +} + +// displayLabel returns the label that we'll display to the user; this is often just the label +// but in some cases rules define extra rules in the form _#thing. For anything matching that +// we strip the leading _ and trailing hashtag to make it look like it's all the same rule. +// Note that this is only a nicety for display, all log messages etc will still display the real names. +func displayLabel(label core.BuildLabel) string { + if len(label.Name) > 0 && label.Name[0] == '_' { + if index := strings.IndexRune(label.Name, '#'); index != -1 { + return core.BuildLabel{PackageName: label.PackageName, Name: strings.TrimLeft(label.Name[1:index], "_")}.String() + } + } + return label.String() +} + +// For calculating the size of the console window; this is pretty important when we're writing +// arbitrary-length log messages around the interactive display. +type winsize struct { + Row uint16 + Col uint16 + Xpixel uint16 + Ypixel uint16 +} + +func windowSize() (int, int) { + ws := new(winsize) + if ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, + uintptr(syscall.Stderr), + uintptr(magicNumber()), + uintptr(unsafe.Pointer(ws)), + ); int(ret) == -1 { + log.Error("error %d getting window size", int(errno)) + return 80, 25 + } else { + return int(ws.Row), int(ws.Col) + } +} + +func magicNumber() int { + // Found these on an internet somewhere. + if runtime.GOOS == "darwin" { + return 1074295912 + } else { + return 0x5413 + } +} + +func recalcWindowSize(backend *logBackend) { + rows, cols := windowSize() + backend.mutex.Lock() + defer backend.mutex.Unlock() + backend.Rows = rows - 4 // Give a little space at the edge for any off-by-ones + backend.Cols = cols + backend.RecalcLines() +} + +// Limited-length printf that respects current window width. +// Output is truncated at the middle to fit within 'cols'. +func lprintf(cols int, format string, args ...interface{}) { + printf(lprintfPrepare(cols, format, args...)) +} + +// Implementation of above. Split out to make testing easier. +var stripAnsi = regexp.MustCompile("\x1b[^m]+m") + +func lprintfPrepare(cols int, format string, args ...interface{}) string { + s := fmt.Sprintf(format, args...) + if len(s) < cols { + return s // it's short enough, nice and simple + } + // Okay, it's too long. Tricky thing: ANSI escape codes don't count for width + // so we need to count without those. Bonus: make an effort to be unicode-aware. + var b bytes.Buffer + written := 0 + inAnsiCode := false + for _, rune := range s { + if inAnsiCode { + b.WriteRune(rune) + if rune == 'm' { + inAnsiCode = false + } + } else if rune == '\x1b' { + b.WriteRune(rune) + inAnsiCode = true + } else if rune == '\n' { + b.WriteRune(rune) + } else if written == cols-3 { + b.WriteString("...") + written += 3 + } else if written < cols-3 { + b.WriteRune(rune) + written++ + } + } + return b.String() +} diff --git a/src/output/interactive_display_test.go b/src/output/interactive_display_test.go new file mode 100644 index 0000000000..cf06ba9f7d --- /dev/null +++ b/src/output/interactive_display_test.go @@ -0,0 +1,65 @@ +package output + +import "strings" +import "testing" + +import "core" + +func TestLimitedPrintfSimple(t *testing.T) { + assertEquals(t, "wibble wobble", lprintfPrepare(20, "wibble wobble")) + assertEquals(t, "wibble wobble", lprintfPrepare(20, "%s %s", "wibble", "wobble")) +} + +func TestLimitedPrintfMore(t *testing.T) { + assertEquals(t, "wibble ...", lprintfPrepare(10, "wibble wobble")) + assertEquals(t, "wibble ...", lprintfPrepare(10, "%s %s", "wibble", "wobble")) +} + +func TestLimitedPrintfAnsi(t *testing.T) { + // Should be unchanged because without escape sequences it's under the limit. + assertEquals(t, "\x1b[30mwibble wobble\x1b[1m", lprintfPrepare(20, "\x1b[30mwibble wobble\x1b[1m")) +} + +func TestLimitedPrintfAnsiNotCountedWhenReducing(t *testing.T) { + assertEquals(t, "\x1b[30mwibble ...\x1b[1m", lprintfPrepare(10, "%s %s", "\x1b[30mwibble", "wobble\x1b[1m")) +} + +func TestNewlinesStillWritte(t *testing.T) { + // Test that newline still gets written (it doesn't count as horizontal space and is Very Important) + assertEquals(t, "\x1b[30mwibble ...\x1b[1m\n", lprintfPrepare(10, "%s %s\n", "\x1b[30mwibble", "wobble\x1b[1m")) +} + +func TestLineWrap(t *testing.T) { + backend := logBackend{Cols: 80, maxLines: 2} + + s := backend.lineWrap(strings.Repeat("a", 40)) + assertEquals(t, strings.Repeat("a", 40), strings.Join(s, "\n")) + + s = backend.lineWrap(strings.Repeat("a", 100)) + assertEquals(t, strings.Repeat("a", 20)+"\n"+strings.Repeat("a", 80), strings.Join(s, "\n")) + + s = backend.lineWrap(strings.Repeat("a", 80)) + assertEquals(t, strings.Repeat("a", 80), strings.Join(s, "\n")) +} + +func assertEquals(t *testing.T, expected, actual string) { + if expected != actual { + t.Errorf("Assertion failed: expected %s, was %s", expected, actual) + } +} + +func TestDisplayLabel(t *testing.T) { + label := core.BuildLabel{PackageName: "src/display", Name: "display"} + assertEquals(t, "//src/display:display", displayLabel(label)) + label = core.BuildLabel{PackageName: "src/display", Name: "_display#lib"} + assertEquals(t, "//src/display:display", displayLabel(label)) + label = core.BuildLabel{PackageName: "src/display", Name: "display#lib"} + assertEquals(t, "//src/display:display#lib", displayLabel(label)) + label = core.BuildLabel{PackageName: "src/display", Name: "_display_lib"} + assertEquals(t, "//src/display:_display_lib", displayLabel(label)) + label = core.BuildLabel{PackageName: "src/display", Name: ""} + assertEquals(t, "//src/display", displayLabel(label)) + // Happens sometimes when you start stacking up labels + label = core.BuildLabel{PackageName: "src/display", Name: "__display#lib#zip"} + assertEquals(t, "//src/display:display", displayLabel(label)) +} diff --git a/src/output/logging.go b/src/output/logging.go new file mode 100644 index 0000000000..472d5b4624 --- /dev/null +++ b/src/output/logging.go @@ -0,0 +1,187 @@ +// Contains various utility functions related to logging. + +package output + +import ( + "bytes" + "container/list" + "fmt" + "io" + "os" + "path" + "regexp" + "strings" + "sync" + + "github.com/op/go-logging" + + "core" +) + +var log = logging.MustGetLogger("output") + +var logLevel = logging.WARNING +var fileLogLevel = logging.WARNING +var fileBackend *logging.LogBackend = nil + +type logFileWriter struct { + file io.Writer +} + +func (writer logFileWriter) Write(p []byte) (n int, err error) { + return writer.file.Write(stripAnsi.ReplaceAllLiteral(p, []byte{})) +} + +// translateLogLevel translates our verbosity flags to logging levels. +func translateLogLevel(verbosity int) logging.Level { + if verbosity <= 0 { + return logging.ERROR + } else if verbosity == 1 { + return logging.WARNING + } else if verbosity == 2 { + return logging.NOTICE + } else if verbosity == 3 { + return logging.INFO + } else { + return logging.DEBUG + } +} + +// InitLogging initialises logging backends. verbosity controls output to shell, +// logFile and logFileLevel what's (optionally) logged to a file as well. +func InitLogging(verbosity int, logFile string, logFileLevel int) { + logLevel = translateLogLevel(verbosity) + fileLogLevel = translateLogLevel(logFileLevel) + logging.SetFormatter(logFormatter()) + setLogBackend(logging.NewLogBackend(os.Stderr, "", 0)) + + if logFile != "" { + if err := os.MkdirAll(path.Dir(logFile), core.DirPermissions); err != nil { + log.Fatalf("Error creating log file directory: %s", err) + } + if file, err := os.Create(logFile); err != nil { + log.Fatalf("Error opening log file: %s", err) + } else { + fileBackend = logging.NewLogBackend(logFileWriter{file: file}, "", 0) + setLogBackend(logging.NewLogBackend(os.Stderr, "", 0)) + } + } +} + +func logFormatter() logging.Formatter { + formatStr := "%{time:15:04:05.000} %{level:7s}: %{message}" + if stdErrIsATerminal { + formatStr = "%{color}" + formatStr + "%{color:reset}" + } + return logging.MustStringFormatter(formatStr) +} + +func setLogBackend(backend logging.Backend) { + backendLeveled := logging.AddModuleLevel(backend) + backendLeveled.SetLevel(logLevel, "") + if fileBackend == nil { + logging.SetBackend(backendLeveled) + } else { + fileBackendLeveled := logging.AddModuleLevel(fileBackend) + fileBackendLeveled.SetLevel(fileLogLevel, "") + logging.SetBackend(backendLeveled, fileBackendLeveled) + } +} + +type logBackendFacade struct { + realBackend *logBackend // To work around the logging interface requiring us to pass by value. +} + +func (backend logBackendFacade) Log(level logging.Level, calldepth int, rec *logging.Record) error { + var b bytes.Buffer + backend.realBackend.Formatter.Format(calldepth, rec, &b) + if rec.Level <= logging.CRITICAL { + fmt.Print(b.String()) // Don't capture critical messages, just die immediately. + os.Exit(1) + } + backend.realBackend.mutex.Lock() + defer backend.realBackend.mutex.Unlock() + backend.realBackend.LogMessages.PushBack(strings.TrimSpace(b.String())) + backend.realBackend.RecalcLines() + return nil +} + +type logBackend struct { + Rows, Cols, MaxRecords, InteractiveRows, MaxInteractiveRows, maxLines int + Output []string + LogMessages *list.List + mutex sync.Mutex // Protects access to LogMessages + Formatter logging.Formatter // TODO(pebers): seems a bit weird that we have to have this here, but it doesn't +} // seem to be possible to retrieve the formatter from outside the package? + +func (backend *logBackend) RecalcLines() { + for backend.LogMessages.Len() >= backend.MaxRecords { + backend.LogMessages.Remove(backend.LogMessages.Front()) + } + backend.maxLines = backend.Rows - backend.InteractiveRows - 1 + if backend.maxLines > 15 { + backend.maxLines = 15 // Cap it here so we don't log too much + } else if backend.maxLines <= 0 { + backend.maxLines = 1 // Set a minimum so we don't have negative indices later. + } + backend.Output = backend.calcOutput() + backend.MaxInteractiveRows = backend.Rows - len(backend.Output) - 1 +} + +func (backend *logBackend) calcOutput() []string { + ret := []string{} + for e := backend.LogMessages.Back(); e != nil; e = e.Prev() { + new := backend.lineWrap(e.Value.(string)) + if len(ret)+len(new) <= backend.maxLines { + ret = append(ret, new...) + } + } + if len(ret) > 0 { + ret = append(ret, "Messages:") + } + return reverse(ret) +} + +// Wraps a string across multiple lines. Returned slice is reversed. +func (backend *logBackend) lineWrap(msg string) []string { + lines := strings.Split(msg, "\n") + wrappedLines := make([]string, 0, len(lines)) + for _, line := range lines { + for i := 0; i < len(line); { + split := i + findSplit(line[i:len(line)], backend.Cols) + wrappedLines = append(wrappedLines, line[i:split]) + i = split + } + } + if len(wrappedLines) > backend.maxLines { + return reverse(wrappedLines[:backend.maxLines]) + } else { + return reverse(wrappedLines) + } +} + +func reverse(s []string) []string { + if len(s) > 1 { + r := []string{} + for i := len(s) - 1; i >= 0; i-- { + r = append(r, s[i]) + } + return r + } else { + return s + } +} + +// Tries to find an appropriate point to word wrap line, taking shell escape codes into account. +// (Note that because the escape codes are not visible, we can run past the max length for one of them) +func findSplit(line string, guess int) int { + if guess >= len(line) { + return len(line) + } + r := regexp.MustCompilePOSIX(fmt.Sprintf(".{%d,%d}(\\x1b[^m]+m)?", guess/2, guess)) + m := r.FindStringIndex(line) + if m != nil { + return m[1] // second element in slice is the end index + } + return guess // Dunno what to do at this point. It's probably unlikely to happen often though. +} diff --git a/src/output/shell_output.go b/src/output/shell_output.go new file mode 100644 index 0000000000..876ad5214b --- /dev/null +++ b/src/output/shell_output.go @@ -0,0 +1,478 @@ +// Package for displaying output on the command line of the current build state. + +package output + +import ( + "fmt" + "os" + "path" + "regexp" + "sort" + "strings" + "sync" + "time" + + "golang.org/x/crypto/ssh/terminal" + + "core" +) + +var startTime = time.Now() +var stdErrIsATerminal = terminal.IsTerminal(int(os.Stderr.Fd())) + +// SetColouredOutput forces on or off coloured output in logging and other console output. +func SetColouredOutput(on bool) { + stdErrIsATerminal = on +} + +// Used to track currently building targets. +type buildingTarget struct { + sync.Mutex + buildingTargetData +} + +type buildingTargetData struct { + Label core.BuildLabel + Started time.Time + Finished time.Time + Description string + Active bool + Failed bool + Cached bool + Err error + Colour string +} + +func MonitorState(state *core.BuildState, numThreads int, plainOutput, keepGoing, shouldBuild, shouldTest bool, done chan<- bool, traceFile string) { + failedTargetMap := map[core.BuildLabel]error{} + buildingTargets := make([]buildingTarget, numThreads, numThreads) + + displayDone := make(chan interface{}) + stop := make(chan interface{}) + if !plainOutput { + go display(state, &buildingTargets, stop, displayDone) + } + aggregatedResults := core.TestResults{} + failedTargets := []core.BuildLabel{} + failedNonTests := []core.BuildLabel{} + for { + result, ok := <-state.Results + if ok { + processResult(state, result, buildingTargets, &aggregatedResults, plainOutput, keepGoing, &failedTargets, &failedNonTests, failedTargetMap, traceFile != "") + } else { + break + } + } + if !plainOutput { + stop <- struct{}{} + <-displayDone + } + if traceFile != "" { + writeTrace(traceFile) + } + duration := time.Since(startTime).Seconds() + // Check all the targets we wanted to build actually have been built. + for _, label := range state.OriginalTargets { + if target := state.Graph.Target(label); target == nil && !label.IsAllTargets() { + log.Fatalf("Target %s doesn't exist in build graph", label) + } else if shouldBuild && target != nil && target.State() < core.Built { + cycle := graphCycleMessage(state.Graph, target) + log.Fatalf("Target %s hasn't built but we have no pending tasks left.\n%s", label, cycle) + } + } + if state.Verbosity > 0 && shouldBuild { + if len(failedNonTests) > 0 { // We didn't get to the tests, something failed in the build step. + printFailedBuildResults(failedNonTests, failedTargetMap, duration) + } else if shouldTest { // Got to the test phase, report their results. + printTestResults(state.Graph, aggregatedResults, failedTargets, duration) + } else { // Must be plz build or similar, report build outputs. + printBuildResults(state, duration) + } + } + done <- len(failedTargetMap) == 0 +} + +func processResult(state *core.BuildState, result *core.BuildResult, buildingTargets []buildingTarget, aggregatedResults *core.TestResults, plainOutput bool, + keepGoing bool, failedTargets, failedNonTests *[]core.BuildLabel, failedTargetMap map[core.BuildLabel]error, shouldTrace bool) { + label := result.Label + active := result.Status == core.PackageParsing || result.Status == core.TargetBuilding || result.Status == core.TargetTesting + failed := result.Status == core.ParseFailed || result.Status == core.TargetBuildFailed || result.Status == core.TargetTestFailed + cached := result.Status == core.TargetCached || result.Tests.Cached + if shouldTrace { + addTrace(result, buildingTargets[result.ThreadId].Label, active) + } + if failed && result.Tests.NumTests == 0 && result.Tests.Failed == 0 { + result.Tests.NumTests = 1 + result.Tests.Failed = 1 // Ensure there's one test failure when there're no results to parse. + } + // Only aggregate test results the first time it finishes. + if buildingTargets[result.ThreadId].Active && !active { + aggregatedResults.Aggregate(result.Tests) + } + updateTarget(state, plainOutput, &buildingTargets[result.ThreadId], label, active, failed, cached, result.Description, result.Err, targetColour(state.Graph.Target(label))) + if failed { + failedTargetMap[label] = result.Err + // Don't stop here after test failure, aggregate them for later. + if !keepGoing && result.Status != core.TargetTestFailed { + // Reset colour so the entire compiler error output doesn't appear purple. + log.Fatalf("%s failed:${RESET}\n%s\n", result.Label, result.Err) + } else if !plainOutput { // plain output will have already logged this + log.Error("%s failed: %s\n", result.Label, result.Err) + } + *failedTargets = append(*failedTargets, label) + if result.Status != core.TargetTestFailed { + *failedNonTests = append(*failedNonTests, label) + } + } +} + +func printTestResults(graph *core.BuildGraph, aggregatedResults core.TestResults, failedTargets []core.BuildLabel, duration float64) { + if len(failedTargets) > 0 { + for _, failed := range failedTargets { + target := graph.TargetOrDie(failed) + if len(target.Results.Failures) == 0 { + printf("${WHITE_ON_RED}Fail:${RED_NO_BG} %s ${WHITE_ON_RED}Failed to run test${RESET}\n", target.Label) + } else { + printf("${WHITE_ON_RED}Fail:${RED_NO_BG} %s ${BOLD_GREEN}%3d passed ${BOLD_YELLOW}%3d skipped ${BOLD_RED}%3d failed ${BOLD_WHITE}Took %3.1fs${RESET}\n", + target.Label, target.Results.Passed, target.Results.Skipped, target.Results.Failed, target.Results.Duration) + for _, failure := range target.Results.Failures { + printf("${BOLD_RED}Failure: %s in %s${RESET}\n", failure.Type, failure.Name) + printf("%s\n", failure.Traceback) + if len(failure.Stdout) > 0 { + printf("${BOLD_RED}Standard output:${RESET}\n%s\n", failure.Stdout) + } + if len(failure.Stderr) > 0 { + printf("${BOLD_RED}Standard error:${RESET}\n%s\n", failure.Stderr) + } + } + } + if len(target.Results.Output) > 0 { + printf("${BOLD_RED}Full output:${RESET}\n%s\n", target.Results.Output) + } + if target.Results.Flakes > 0 { + printf("${BOLD_MAGENTA}Flaky target; made %s before giving up${RESET}\n", pluralise(target.Results.Flakes, "attempt", "attempts")) + } + } + } + // Print individual test results + i := 0 + for _, target := range graph.AllTargets() { + if target.IsTest && target.Results.NumTests > 0 { + if target.Results.Failed > 0 { + printf("${RED}%s${RESET} %s\n", target.Label, testResultMessage(target.Results, failedTargets)) + } else { + printf("${GREEN}%s${RESET} %s\n", target.Label, testResultMessage(target.Results, failedTargets)) + } + i++ + } + } + aggregatedResults.Duration = -0.1 // Exclude this from being displayed later. + printf(fmt.Sprintf("${BOLD_WHITE}%s and %s${BOLD_WHITE}. Total time %0.2fs.${RESET}\n", + pluralise(i, "test target", "test targets"), testResultMessage(aggregatedResults, failedTargets), duration)) +} + +// Produces a string describing the results of one test (or a single aggregation). +func testResultMessage(results core.TestResults, failedTargets []core.BuildLabel) string { + if results.NumTests == 0 { + if len(failedTargets) > 0 { + return "Tests failed" + } else { + return "No tests found" + } + } else { + msg := fmt.Sprintf("%s run", pluralise(results.NumTests, "test", "tests")) + if results.Duration >= 0.0 { + msg += fmt.Sprintf(" in %4.2fs", results.Duration) + } + msg += fmt.Sprintf("; ${BOLD_GREEN}%d passed${RESET}", results.Passed) + if results.Failed > 0 { + msg += fmt.Sprintf(", ${BOLD_RED}%d failed${RESET}", results.Failed) + } + if results.Skipped > 0 { + msg += fmt.Sprintf(", ${BOLD_YELLOW}%d skipped${RESET}", results.Skipped) + } + if results.Flakes > 0 { + msg += fmt.Sprintf(", ${BOLD_MAGENTA}%s${RESET}", pluralise(results.Flakes, "flake", "flakes")) + } + if results.Cached { + msg += " ${GREEN}[cached]${RESET}" + } + return msg + } +} + +func printBuildResults(state *core.BuildState, duration float64) { + // Count incrementality. + totalBuilt := 0 + totalUnchanged := 0 + for _, target := range state.Graph.AllTargets() { + if target.State() == core.Built { + totalBuilt++ + } else if target.State() == core.Unchanged { + totalUnchanged++ + } + } + incrementality := 100.0 * float64(totalUnchanged) / float64(totalBuilt+totalUnchanged) + if totalBuilt+totalUnchanged == 0 { + incrementality = 100 // avoid NaN + } + // Print this stuff so we always see it. + printf("Build finished; total time %0.2fs, incrementality %.1f%%. Outputs:\n", duration, incrementality) + results := []string{} + for _, label := range state.ExpandOriginalTargets() { + target := state.Graph.TargetOrDie(label) + // This is slightly dodgy; really we should check if it was included in the original query + // or not, but we don't have the include/exclude labels here. Instead we assume whether + // it was actually built as a proxy for it. + if target.State() >= core.Built { + results = append(results, buildResult(target)...) + } + } + sort.Strings(results) + for i, result := range results { + if i == 0 || result != results[i-1] { // Don't repeat results. + printf(" %s\n", result) + } + } +} + +func buildResult(target *core.BuildTarget) []string { + results := []string{} + if target != nil { + for _, out := range target.Outputs() { + if core.StartedAtRepoRoot() { + results = append(results, path.Join(target.OutDir(), out)) + } else { + results = append(results, path.Join(core.RepoRoot, target.OutDir(), out)) + } + } + } + return results +} + +func printFailedBuildResults(failedTargets []core.BuildLabel, failedTargetMap map[core.BuildLabel]error, duration float64) { + printf("${WHITE_ON_RED}Build stopped after %0.2fs. Some targets failed:${RESET}\n", duration) + for _, label := range failedTargets { + err, present := failedTargetMap[label] + if present { + printf(" ${BOLD_RED}%s\n${RESET}${RED}%s${RESET}\n", label, err) + } else { + printf(" ${BOLD_RED}%s${RESET}\n", label) + } + } +} + +func updateTarget(state *core.BuildState, plainOutput bool, buildingTarget *buildingTarget, label core.BuildLabel, + active bool, failed bool, cached bool, description string, err error, colour string) { + updateTarget2(buildingTarget, label, active, failed, cached, description, err, colour) + if plainOutput || failed { + if failed { + log.Error("%s: %s", label.String(), description) + } else { + if !active { + active := pluralise(state.NumActive(), "task", "tasks") + log.Notice("[%d/%s] %s: %s [%3.1fs]", state.NumDone(), active, label.String(), description, time.Now().Sub(buildingTarget.Started).Seconds()) + } else { + log.Info("%s: %s", label.String(), description) + } + } + } +} + +func updateTarget2(target *buildingTarget, label core.BuildLabel, active bool, failed bool, cached bool, description string, err error, colour string) { + target.Lock() + defer target.Unlock() + target.Label = label + target.Description = description + if !target.Active { + // Starting to build now. + target.Started = time.Now() + target.Finished = target.Started + } else if !active { + // finished building + target.Finished = time.Now() + } + target.Active = active + target.Failed = failed + target.Cached = cached + target.Err = err + target.Colour = colour +} + +func targetColour(target *core.BuildTarget) string { + if target == nil { + return "${BOLD_CYAN}" // unknown + } else if target.IsBinary { + return "${BOLD}" + targetColour2(target) + } else { + return targetColour2(target) + } +} + +func targetColour2(target *core.BuildTarget) string { + // Quick heuristic on language types. May want to make this configurable. + for _, require := range target.Requires { + if require == "py" { + return "${GREEN}" + } else if require == "java" { + return "${RED}" + } else if require == "go" { + return "${YELLOW}" + } else if require == "js" { + return "${BLUE}" + } + } + if strings.Contains(target.Label.PackageName, "third_party") { + return "${MAGENTA}" + } + return "${WHITE}" +} + +// Used to strip the formatting stuff when running directly through 'go run'. +var stripFormatting = regexp.MustCompile("\\$\\{[^\\}]+\\}") + +// printf is used throughout this package to print something to stderr with some niceties +// around ANSI formatting codes. +func printf(format string, args ...interface{}) { + if "${WHITE}"[0] == '$' || !stdErrIsATerminal { + msg := stripFormatting.ReplaceAllString(fmt.Sprintf(format, args...), "") + fmt.Fprint(os.Stderr, stripAnsi.ReplaceAllString(msg, "")) + } else { + fmt.Fprintf(os.Stderr, format, args...) + } +} + +// Since this is a gentleman's build tool, we'll make an effort to get plurals correct +// in at least this one place. +func pluralise(num int, singular, plural string) string { + if num == 1 { + return fmt.Sprintf("1 %s", singular) + } else { + return fmt.Sprintf("%d %s", num, plural) + } +} + +// Writes out coverage metrics after a test run in a file tree setup. +// Only files that were covered by tests and not excluded are shown. +func PrintCoverage(state *core.BuildState) { + printf("${BOLD_WHITE}Coverage results:${RESET}\n") + totalCovered := 0 + totalTotal := 0 + lastDir := "_" + for _, file := range state.Coverage.OrderedFiles() { + if strings.HasPrefix(file, core.RepoRoot) { + file = file[len(core.RepoRoot):] + } + file = strings.TrimLeft(file, "/") + dir := file[:strings.LastIndex(file, "/")+1] + if dir != lastDir { + printf("${WHITE}%s:${RESET}\n", strings.TrimRight(dir, "/")) + } + lastDir = dir + covered, total := countCoverage(state.Coverage.Files[file]) + printf(" %s\n", coveragePercentage(covered, total, file[len(dir):])) + totalCovered += covered + totalTotal += total + } + printf("${BOLD_WHITE}Total coverage: %s${RESET}\n", coveragePercentage(totalCovered, totalTotal, "")) +} + +// Counts the number of lines covered and the total number coverable in a single file. +func countCoverage(lines []core.LineCoverage) (int, int) { + covered := 0 + total := 0 + for _, line := range lines { + if line == core.Covered { + total++ + covered++ + } else if line != core.NotExecutable { + total++ + } + } + return covered, total +} + +// Returns some appropriate ANSI colour code for a coverage percentage. +func coverageColour(percentage float32) string { + // TODO(pebers): consider making these configurable? + if percentage < 20.0 { + return "${MAGENTA}" + } else if percentage < 60.0 { + return "${BOLD_RED}" + } else if percentage < 80.0 { + return "${BOLD_YELLOW}" + } else { + return "${BOLD_GREEN}" + } +} + +func coveragePercentage(covered, total int, label string) string { + if total == 0 { + return fmt.Sprintf("${BOLD_MAGENTA}%s No data${RESET}", label) + } else { + percentage := 100.0 * float32(covered) / float32(total) + return fmt.Sprintf("%s%s %d/%s, %2.1f%%${RESET}", coverageColour(percentage), label, covered, pluralise(total, "line", "lines"), percentage) + } +} + +// Attempts to detect graph cycles and produces a readable message from it. +func graphCycleMessage(graph *core.BuildGraph, target *core.BuildTarget) string { + if cycle := findGraphCycle(graph, target); len(cycle) > 0 { + msg := "Dependency cycle found:\n" + msg += fmt.Sprintf(" %s\n", cycle[len(cycle)-1].Label) + for i := len(cycle) - 2; i >= 0; i-- { + msg += fmt.Sprintf(" -> %s\n", cycle[i].Label) + } + msg += fmt.Sprintf(" -> %s\n", cycle[len(cycle)-1].Label) + return msg + fmt.Sprintf("Sorry, but you'll have to refactor your build files to avoid this cycle.") + } + return unbuiltTargetsMessage(graph) +} + +// Attempts to detect cycles in the build graph. Returns an empty slice if none is found, +// otherwise returns a slice of labels describing the cycle. +func findGraphCycle(graph *core.BuildGraph, target *core.BuildTarget) []*core.BuildTarget { + index := func(haystack []*core.BuildTarget, needle *core.BuildTarget) int { + for i, straw := range haystack { + if straw == needle { + return i + } + } + return -1 + } + + var detectCycle func(*core.BuildTarget, []*core.BuildTarget) []*core.BuildTarget + detectCycle = func(target *core.BuildTarget, deps []*core.BuildTarget) []*core.BuildTarget { + if i := index(deps, target); i != -1 { + return deps[i:] + } + deps = append(deps, target) + for _, dep := range target.Dependencies { + if cycle := detectCycle(dep, deps); len(cycle) > 0 { + return cycle + } + } + return nil + } + return detectCycle(target, nil) +} + +// Prints all targets in the build graph that are marked to be built but not built yet. +func unbuiltTargetsMessage(graph *core.BuildGraph) string { + msg := "" + for _, target := range graph.AllTargets() { + if target.State() == core.Active { + if graph.AllDepsBuilt(target) { + msg += fmt.Sprintf(" %s (waiting for deps to build)\n", target.Label) + } else { + msg += fmt.Sprintf(" %s\n", target.Label) + } + } else if target.State() == core.Pending { + msg += fmt.Sprintf(" %s (pending build)\n", target.Label) + } + } + if msg != "" { + return "\nThe following targets have not yet built:\n" + msg + } + return "" +} diff --git a/src/output/shell_output_test.go b/src/output/shell_output_test.go new file mode 100644 index 0000000000..018f3ec3e5 --- /dev/null +++ b/src/output/shell_output_test.go @@ -0,0 +1,54 @@ +package output + +import "testing" + +import "core" + +func TestFindGraphCycle(t *testing.T) { + graph := core.NewGraph() + graph.AddTarget(makeTarget("//src/output:target1", "//src/output:target2", "//src/output:target3", "//src/core:target2")) + graph.AddTarget(makeTarget("//src/output:target2", "//src/output:target3", "//src/core:target1")) + graph.AddTarget(makeTarget("//src/output:target3")) + graph.AddTarget(makeTarget("//src/core:target1", "//third_party/go:target2", "//third_party/go:target3", "//src/core:target3")) + graph.AddTarget(makeTarget("//src/core:target2", "//third_party/go:target3", "//src/output:target2")) + graph.AddTarget(makeTarget("//src/core:target3", "//third_party/go:target2", "//src/output:target2")) + graph.AddTarget(makeTarget("//third_party/go:target2", "//third_party/go:target1")) + graph.AddTarget(makeTarget("//third_party/go:target3", "//third_party/go:target1")) + graph.AddTarget(makeTarget("//third_party/go:target1")) + updateDependencies(graph) + + cycle := findGraphCycle(graph, graph.TargetOrDie(core.ParseBuildLabel("//src/output:target1", ""))) + if len(cycle) == 0 { + t.Fatalf("Failed to find cycle") + } else if len(cycle) != 3 { + t.Errorf("Found unexpected cycle of length %d", len(cycle)) + } + assertTarget(t, cycle[0], "//src/output:target2") + assertTarget(t, cycle[1], "//src/core:target1") + assertTarget(t, cycle[2], "//src/core:target3") +} + +// Factory function for build targets +func makeTarget(label string, deps ...string) *core.BuildTarget { + target := core.NewBuildTarget(core.ParseBuildLabel(label, "")) + for _, dep := range deps { + target.AddDependency(core.ParseBuildLabel(dep, "")) + } + return target +} + +// Set dependency pointers on all contents of the graph. +// Has to be done after to test cycles etc. +func updateDependencies(graph *core.BuildGraph) { + for _, target := range graph.AllTargets() { + for _, dep := range target.DeclaredDependencies { + target.Dependencies = append(target.Dependencies, graph.TargetOrDie(dep)) + } + } +} + +func assertTarget(t *testing.T, target *core.BuildTarget, label string) { + if target.Label != core.ParseBuildLabel(label, "") { + t.Errorf("Unexpected target in detected cycle; expected %s, was %s", label, target.Label) + } +} diff --git a/src/output/trace.go b/src/output/trace.go new file mode 100644 index 0000000000..ef76e4d8ff --- /dev/null +++ b/src/output/trace.go @@ -0,0 +1,82 @@ +// For writing out JSON trace files which Chrome can interpret nicely for us. +// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU + +package output + +import "encoding/json" +import "fmt" +import "os" + +import "core" + +var traces = make([]traceEntry, 0, 1000) + +func addTrace(result *core.BuildResult, previous core.BuildLabel, active bool) { + // It's a bit fiddly to keep all the phases in line here. + if result.Label != previous { + traces = append(traces, translateEvent(result, "B")) + } else if !active { + traces = append(traces, translateEvent(result, "E")) + } else { + traces = append(traces, translateEvent(result, "E")) + traces = append(traces, translateEvent(result, "B")) + } +} + +func writeTrace(traceFile string) { + file, err := os.Create(traceFile) + if err != nil { + log.Error("Couldn't create trace file: %s", err) + return + } + defer file.Close() + file.Write(formatTrace()) +} + +func formatTrace() []byte { + var out traceObjectFormat + out.OtherData.Version = "Please v1.2" // TODO(pebers): Get this from somewhere... + out.TraceEvents = traces + data, err := json.Marshal(out) + if err != nil { + log.Error("Error serialising JSON trace data: %s", err) + } + return data +} + +func translateEvent(result *core.BuildResult, phase string) traceEntry { + entry := traceEntry{ + Name: result.Label.String(), + Cat: "Please", // Not sure what would be useful here + Ph: phase, + Pid: 0, // This isn't really important, there's only one process. + Ts: result.Time.UnixNano() / 1000, + } + entry.Tid = fmt.Sprintf("Builder %d", result.ThreadId) + entry.Args.Description = result.Description + if result.Err != nil { + entry.Args.Err = fmt.Sprintf("%s", result.Err) + } + return entry +} + +type traceObjectFormat struct { + TraceEvents []traceEntry `json:"traceEvents"` + OtherData struct { + Version string `json:"version"` + } `json:"otherData"` + // Ignoring other properties for now. +} + +type traceEntry struct { + Name string `json:"name"` + Cat string `json:"cat"` + Ph string `json:"ph"` + Pid int32 `json:"pid"` + Tid string `json:"tid"` + Ts int64 `json:"ts"` + Args struct { + Description string `json:"description"` + Err string `json:"err"` + } `json:"args"` +} diff --git a/src/parse/BUILD b/src/parse/BUILD new file mode 100644 index 0000000000..0eafd1318b --- /dev/null +++ b/src/parse/BUILD @@ -0,0 +1,106 @@ +cgo_library( + name = 'parse', + srcs = glob(['*.go', '*.h', '*.c', 'python_interface.*'], excludes=['builtin_rules.go', 'go_rules_test_*', '*_test.go']) + [':builtin_rules'], + env = {'CGO_LDFLAGS': '-L${TMP_DIR}/${PKG}/rules'}, + deps = [ + ':builtin_rules', + '//src/core', + '//third_party/go:logging', + '//third_party/go:gcfg', + ], + visibility = ['PUBLIC'], +) + +genrule( + name = 'builtin_rules', + srcs = glob(['rules/*.py']), + outs = ['builtin_rules.go'], + # Massive hack since symlinks don't seem to be working with go-bindata here. + # Not sure why, they have a resolved issue for them... + cmd = 'for i in `find -L $PKG -type f`; do cp $i tmp && rm $i && mv tmp $i; done && ' + '$(exe //third_party/go:go-bindata) -o $OUT -nomemcopy -pkg parse -prefix ${PKG}/rules ${PKG}/rules', + deps = [ + '//third_party/go:go-bindata', + ] +) + +go_test( + name = 'glob_test', + srcs = ['glob_test.go'], + deps = [ + ':parse', + '//src/core', + ], + data = glob(['test_data/**/*.txt']), +) + +go_test( + name = 'parse_step_test', + srcs = ['parse_step_test.go'], + deps = [ + ':parse', + '//src/core', + '//third_party/go:testify', + ], +) + +go_test( + name = 'interpreter_test', + srcs = ['interpreter_test.go'], + deps = [ + ':parse', + '//third_party/go:testify', + ], + data = glob(['test_data/**/TEST_BUILD', 'test_data/**/test.py']), +) + +# Simulates a code generating rule to test the require / provide mechanism. +genrule( + name = 'test_require_py', + outs = ['test_require.py'], + cmd = 'touch $OUT', + test_only = True, +) +genrule( + name = 'test_require_go', + outs = ['test_require.go'], + cmd = 'touch $OUT', + test_only = True, +) +filegroup( + name = 'test_require', + srcs = [':test_require_py', ':test_require_go'], + deps = [':test_require_py', ':test_require_go'], + provides = { + 'py': ':test_require_py', + 'go': ':test_require_go', + }, + test_only = True, +) +python_test( + name = 'require_provide_test', + srcs = ['require_provide_test.py'], + deps = [ + ':test_require', + '//src/build/python:bootstrap_pexer', + ], +) + +# Test for adding additional outputs to a target. +genrule( + name = '_gen_output_name', + cmd = 'echo test_additional_output.txt', + post_build = lambda _, output: add_out('_gen_output', ''.join(output).strip()), +) +genrule( + name = '_gen_output', + cmd = 'echo -n "kittens" > $OUT', + deps = [ + ':_gen_output_name', + ], +) +go_test( + name = 'additional_output_test', + srcs = ['additional_output_test.go'], + data = [':_gen_output'], +) diff --git a/src/parse/additional_output_test.go b/src/parse/additional_output_test.go new file mode 100644 index 0000000000..1b554b248f --- /dev/null +++ b/src/parse/additional_output_test.go @@ -0,0 +1,15 @@ +// Test on adding extra output files to a target in a post-build function. +package parse + +import "io/ioutil" +import "testing" + +func TestContentsOfOutputFile(t *testing.T) { + contents, err := ioutil.ReadFile("src/parse/test_additional_output.txt") + if err != nil { + t.Errorf("Failed to read additional output file: %s", err) + } + if string(contents) != "kittens" { + t.Errorf("Unexpected file contents: was '%s', expected 'kittens'", string(contents)) + } +} diff --git a/src/parse/glob_test.go b/src/parse/glob_test.go new file mode 100644 index 0000000000..6921049ac6 --- /dev/null +++ b/src/parse/glob_test.go @@ -0,0 +1,32 @@ +// Tests for our glob functions. + +package parse + +import "testing" + +import "core" + +func TestCanGlobFirstFile(t *testing.T) { + // If this fails then we probably failed to interpret /**/ properly, + // which can resolve to just / - ie. we glob test_data/**/*.txt, + // which should include test_data/test.txt + if !core.FileExists("src/parse/test_data/test.txt") { + t.Errorf("Can't load test_data/test.txt") + } +} + +func TestCanGlobSecondFile(t *testing.T) { + // If this fails then we haven't walked down enough subdirectories + // or something. Shouldn't really be hard - it's a sanity check really + // since it's similar to the third file but without a package boundary. + if !core.FileExists("src/parse/test_data/test_subfolder1/a.txt") { + t.Errorf("Can't load test_data/test_subfolder1/a.txt") + } +} + +func TestCannotGlobThirdFile(t *testing.T) { + // This one we should not be able to glob because it's inside its own subpackage. + if core.FileExists("src/parse/test_data/test_subfolder2/b.txt") { + t.Errorf("Incorrectly loaded test_data/test_subfolder2/b.txt; have globbed it through a package boundary") + } +} diff --git a/src/parse/interpreter.c b/src/parse/interpreter.c new file mode 100644 index 0000000000..fa85bbff28 --- /dev/null +++ b/src/parse/interpreter.c @@ -0,0 +1,59 @@ +#include "interpreter.h" + +#include "_cgo_export.h" + +void PreBuildFunctionSetter(void* callback, char* bytecode, void* target) { + SetPreBuildFunction((size_t)callback, bytecode, target); +} + +void PostBuildFunctionSetter(void* callback, char* bytecode, void* target) { + SetPostBuildFunction((size_t)callback, bytecode, target); +} + +char* ParseFile(ParseFileCallback* func, char* filename, char* package_name, void* package) { + return (*func)(filename, package_name, package); +} + +void SetConfigValue(SetConfigValueCallback* func, char* name, char* value) { + func(name, value); +} + +char* RunPreBuildFunction(PreBuildCallbackRunner* runner, size_t callback, void* package, char* name) { + return runner((void*)callback, package, name); +} + +char* RunPostBuildFunction(PostBuildCallbackRunner* runner, size_t callback, void* package, char* name, char* output) { + return runner((void*)callback, package, name, output); +} + +int InitialiseInterpreter(char* data, void* vcallbacks) { + struct PleaseCallbacks* callbacks = (struct PleaseCallbacks*)vcallbacks; + callbacks->add_target = (AddTargetCallback*)AddTarget; + callbacks->add_src = AddSource; + callbacks->add_data = AddData; + callbacks->add_out = AddOutput; + callbacks->add_dep = AddDep; + callbacks->add_exported_dep = AddExportedDep; + callbacks->add_tool = AddTool; + callbacks->add_vis = AddVis; + callbacks->add_label = AddLabel; + callbacks->add_hash = AddHash; + callbacks->add_licence = AddLicence; + callbacks->add_test_output = AddTestOutput; + callbacks->add_require = AddRequire; + callbacks->add_provide = AddProvide; + callbacks->add_named_src = AddNamedSource; + callbacks->set_container_setting = SetContainerSetting; + callbacks->glob = Glob; + callbacks->get_include_file = GetIncludeFile; + callbacks->get_subinclude_file = GetSubincludeFile; + callbacks->get_labels = GetLabels; + callbacks->set_pre_build_function = PreBuildFunctionSetter; + callbacks->set_post_build_function = PostBuildFunctionSetter; + callbacks->add_dependency = AddDependency; + callbacks->add_output = AddOutputPost; + callbacks->add_licence_post = AddLicencePost; + callbacks->set_command = SetCommand; + callbacks->log = Log; + return pypy_execute_source_ptr(data, callbacks); +} diff --git a/src/parse/interpreter.go b/src/parse/interpreter.go new file mode 100644 index 0000000000..d64f6063cb --- /dev/null +++ b/src/parse/interpreter.go @@ -0,0 +1,713 @@ +// Rule parser using PyPy. To build this you need PyPy installed, but the stock one +// that comes with Ubuntu will not work since it doesn't include shared libraries. +// We have a deb at https://s3-eu-west-1.amazonaws.com/please-build/pypy_4.0.0_amd64.deb +// which contains essentially the contents of a recent PyPy tarball. +// On OSX installing through Homebrew should be fine. +// +// The interface to PyPy is done through cgo and cffi. This means that we need to write very little +// actual C code; nearly all of it is in interpreter.h and is just declarations. What remains in +// interpreter.c is essentially just glue to handle limitations of cgo and the way we're using +// callbacks etc. +// The setup isn't actually extremely complex but some care is needed; it's relatively rare to need +// to modify it (generally only when adding new properties to build targets) but when you do you +// must make sure this file, interpreter.h and rules/please_parser.py all agree about struct +// definitions etc. Bad Things will happen if you do not. + +package parse + +import ( + "core" + "crypto/sha1" + "fmt" + "os" + "path" + "path/filepath" + "regexp" + "runtime" + "sort" + "strings" + "sync" + "unsafe" + + "github.com/op/go-logging" +) + +/* +#cgo CFLAGS: --std=c99 -I/usr/include/pypy -Werror +#cgo LDFLAGS: -lpypy-c +#include "interpreter.h" +*/ +import "C" + +var log = logging.MustGetLogger("parse") + +// Communicated back from PyPy to indicate that a parse has been deferred because +// we need to wait for another target to build. +const pyDeferParse = "_DEFER_" + +var cDeferParse = C.CString(pyDeferParse) + +// Callback state about how we communicate with the interpreter. +type PleaseCallbacks struct { + ParseFile, ParseCode *C.ParseFileCallback + AddTarget, AddSrc, AddData, AddDep, AddExportedDep, AddTool, AddOut, AddVis, AddLabel unsafe.Pointer + AddHash, AddLicence, AddTestOutput, AddRequire, AddProvide, AddNamedSrc, SetContainerSetting unsafe.Pointer + Glob, GetIncludeFile, GetSubincludeFile, GetLabels, SetPreBuildFunction unsafe.Pointer + SetPostBuildFunction, AddDependency, AddOutput, AddLicencePost, SetCommand unsafe.Pointer + SetConfigValue *C.SetConfigValueCallback + PreBuildCallbackRunner *C.PreBuildCallbackRunner + PostBuildCallbackRunner *C.PostBuildCallbackRunner + Log unsafe.Pointer +} + +var callbacks PleaseCallbacks + +// Something of a hack - we need to know these for globbing correctly but don't have +// access to the actual config object inside the glob function. +// Fortunately it doesn't change at runtime so we can stash these away... +var buildFileNames []string + +// To ensure we only initialise once. +var initializeOnce sync.Once + +// Code to initialise the Python interpreter. +func initializeInterpreter(config core.Configuration) { + log.Debug("Initialising interpreter...") + buildFileNames = config.Please.BuildFileName + + // PyPy becomes very unhappy if Go schedules it to a different OS thread during + // its initialisation. Force it to stay on this one thread for now. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + C.rpython_startup_code() + libpypy := locateLibPyPy(config) + defer C.free(unsafe.Pointer(libpypy)) + if result := C.pypy_setup_home(libpypy, 1); result != 0 { + log.Fatalf("Failed to initialise PyPy (error %d)\n", result) + } + C.pypy_init_threads() + + // Load interpreter & set up callbacks for communication + log.Debug("Initialising interpreter environment...") + data := loadAsset("please_parser.py") + defer C.free(unsafe.Pointer(data)) + if result := C.InitialiseInterpreter(data, unsafe.Pointer(&callbacks)); result != 0 { + panic(fmt.Sprintf("Failed to initialise parsing callbacks, error %d", result)) + } + setConfigValue("PLZ_VERSION", config.Please.Version) + setConfigValue("GO_VERSION", config.Go.Version) + setConfigValue("GO_STRIP", config.Go.Strip) + setConfigValue("PIP_TOOL", config.Python.PipTool) + setConfigValue("PEX_TOOL", config.Python.PexTool) + setConfigValue("DEFAULT_PYTHON_INTERPRETER", config.Python.DefaultInterpreter) + setConfigValue("PYTHON_MODULE_DIR", config.Python.ModuleDir) + setConfigValue("PYTHON_DEFAULT_PIP_REPO", config.Python.DefaultPipRepo) + if config.Python.UsePyPI { + setConfigValue("USE_PYPI", "true") + } else { + setConfigValue("USE_PYPI", "") + } + setConfigValue("JAVAC_TOOL", config.Java.JavacTool) + setConfigValue("JAR_TOOL", config.Java.JarTool) + setConfigValue("JARCAT_TOOL", config.Java.JarCatTool) + setConfigValue("JUNIT_RUNNER", config.Java.JUnitRunner) + setConfigValue("DEFAULT_TEST_PACKAGE", config.Java.DefaultTestPackage) + setConfigValue("PLEASE_MAVEN_TOOL", config.Java.PleaseMavenTool) + setConfigValue("JAVA_SOURCE_LEVEL", config.Java.SourceLevel) + setConfigValue("JAVA_TARGET_LEVEL", config.Java.TargetLevel) + setConfigValue("CC_TOOL", config.Cpp.CCTool) + setConfigValue("LD_TOOL", config.Cpp.LdTool) + setConfigValue("DEFAULT_CFLAGS", config.Cpp.DefaultCflags) + setConfigValue("DEFAULT_TEST_CFLAGS", config.Cpp.DefaultTestCflags) + setConfigValue("DEFAULT_LDFLAGS", config.Cpp.DefaultLdflags) + setConfigValue("DEFAULT_TEST_LDFLAGS", config.Cpp.DefaultTestLdflags) + setConfigValue("DEFAULT_NAMESPACE", config.Cpp.DefaultNamespace) + setConfigValue("OS", runtime.GOOS) + setConfigValue("ARCH", runtime.GOARCH) + for _, language := range config.Proto.Language { + setConfigValue("PROTO_LANGUAGES", language) + } + setConfigValue("PROTOC_TOOL", config.Proto.ProtocTool) + setConfigValue("PROTOC_GO_PLUGIN", config.Proto.ProtocGoPlugin) + setConfigValue("GRPC_PYTHON_PLUGIN", config.Proto.GrpcPythonPlugin) + setConfigValue("GRPC_JAVA_PLUGIN", config.Proto.GrpcJavaPlugin) + setConfigValue("PROTOC_VERSION", config.Proto.ProtocVersion) + setConfigValue("PROTO_PYTHON_DEP", config.Proto.PythonDep) + setConfigValue("PROTO_JAVA_DEP", config.Proto.JavaDep) + setConfigValue("PROTO_GO_DEP", config.Proto.GoDep) + setConfigValue("PROTO_PYTHON_PACKAGE", config.Proto.PythonPackage) + setConfigValue("GRPC_VERSION", config.Proto.GrpcVersion) + setConfigValue("GRPC_PYTHON_DEP", config.Proto.PythonGrpcDep) + setConfigValue("GRPC_JAVA_DEP", config.Proto.JavaGrpcDep) + setConfigValue("GRPC_GO_DEP", config.Proto.GoGrpcDep) + + // Load all the builtin rules + log.Debug("Loading builtin build rules...") + loadBuiltinRules("misc_rules.py") + loadBuiltinRules("sh_rules.py") + loadBuiltinRules("python_rules.py") + loadBuiltinRules("java_rules.py") + loadBuiltinRules("cc_rules.py") + loadBuiltinRules("go_rules.py") + loadBuiltinRules("proto_rules.py") + log.Debug("Interpreter ready") +} + +// locateLibPyPy returns a C string corresponding to the location of libpypy. +// It dies if it cannot be located successfully. +func locateLibPyPy(config core.Configuration) *C.char { + // This is something of a hack to handle PyPy's dynamic location of itself. + for _, location := range config.Please.PyPyLocation { + if core.PathExists(location) { + return C.CString(location) + } + } + log.Fatalf("Cannot locate libpypy in any of [%s]\n", strings.Join(config.Please.PyPyLocation, ", ")) + return nil +} + +func setConfigValue(name string, value string) { + cName := C.CString(name) + cValue := C.CString(value) + defer C.free(unsafe.Pointer(cName)) + defer C.free(unsafe.Pointer(cValue)) + C.SetConfigValue(callbacks.SetConfigValue, cName, cValue) +} + +func loadBuiltinRules(path string) { + data := loadAsset(path) + defer C.free(unsafe.Pointer(data)) + cPackageName := C.CString(path) + defer C.free(unsafe.Pointer(cPackageName)) + if result := C.GoString(C.ParseFile(callbacks.ParseCode, data, cPackageName, nil)); result != "" { + panic(fmt.Sprintf("Failed to interpret builtin build rules from %s: %s", path, result)) + } +} + +func loadAsset(path string) *C.char { + data, err := Asset(path) + if err != nil { + panic(fmt.Sprintf("Failed to load builtin build rules from %s", path)) + } + // well this is pretty inefficient... we end up with three copies of the data for no + // really good reason. + return C.CString(string(data)) +} + +// parsePackageFile parses a single BUILD file. +// It returns true if parsing is deferred and waiting on other build actions, false otherwise on success +// and will panic on errors. +func parsePackageFile(state *core.BuildState, filename string, pkg *core.Package) bool { + log.Debug("Parsing package file %s", filename) + initializeOnce.Do(func() { initializeInterpreter(state.Config) }) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + // TODO(pebers): It seems like we should be calling C.pypy_attach_thread here once per OS thread. + // That only seems to introduce problems though and not solve them; not sure if that is + // because we are doing thread-unsafe things in our parser, more go/c/pypy interface + // issues or something more mysterious. Regardless, it would be nice to understand + // more what's going on there and see if we can solve - I'm not sure we really have + // multithreaded parsing without it. + cFilename := C.CString(filename) + cPackageName := C.CString(pkg.Name) + defer C.free(unsafe.Pointer(cFilename)) + defer C.free(unsafe.Pointer(cPackageName)) + if ret := C.GoString(C.ParseFile(callbacks.ParseFile, cFilename, cPackageName, unsafe.Pointer(pkg))); ret != "" && ret != pyDeferParse { + panic(fmt.Sprintf("Failed to parse file %s: %s", filename, ret)) + } else { + return ret == pyDeferParse + } +} + +//export AddTarget +func AddTarget(pkgPtr unsafe.Pointer, cName, cCmd, cTestCmd *C.char, binary bool, test bool, + needsTransitiveDeps, outputIsComplete, containerise, noTestOutput, skipCache, testOnly bool, + flakiness, buildTimeout, testTimeout int, cBuildingDescription *C.char) unsafe.Pointer { + buildingDescription := "" + if cBuildingDescription != nil { + buildingDescription = C.GoString(cBuildingDescription) + } + return addTarget(pkgPtr, C.GoString(cName), C.GoString(cCmd), C.GoString(cTestCmd), + binary, test, needsTransitiveDeps, outputIsComplete, containerise, noTestOutput, + skipCache, testOnly, flakiness, buildTimeout, testTimeout, buildingDescription) +} + +// addTarget adds a new build target to the graph. +// Separated from AddTarget to make it possible to test (since you can't mix cgo and go test). +func addTarget(pkgPtr unsafe.Pointer, name, cmd, testCmd string, binary bool, test bool, + needsTransitiveDeps, outputIsComplete, containerise, noTestOutput, skipCache, testOnly bool, + flakiness, buildTimeout, testTimeout int, buildingDescription string) unsafe.Pointer { + pkg := (*core.Package)(pkgPtr) + target := core.NewBuildTarget(core.NewBuildLabel(pkg.Name, name)) + target.IsBinary = binary + target.IsTest = test + target.NeedsTransitiveDependencies = needsTransitiveDeps + target.OutputIsComplete = outputIsComplete + target.Containerise = containerise + target.NoTestOutput = noTestOutput + target.SkipCache = skipCache + target.TestOnly = testOnly + target.Flakiness = flakiness + target.BuildTimeout = buildTimeout + target.TestTimeout = testTimeout + if containerise { + // Automatically label containerised tests. + target.AddLabel("container") + } + if buildingDescription != "" { + target.BuildingDescription = buildingDescription + } + if binary { + target.AddLabel("bin") + } + target.Command = cmd + target.TestCommand = testCmd + if _, present := pkg.Targets[name]; present { + panic(fmt.Sprintf("Duplicate build target in %s: %s", pkg.Name, name)) + } + if target.TestCommand != "" && !target.IsTest { + panic(fmt.Sprintf("Target %s has been given a test command but isn't a test", target.Label)) + } else if target.IsTest && target.TestCommand == "" { + panic(fmt.Sprintf("Target %s is a test but hasn't been given a test command", target.Label)) + } + pkg.Targets[name] = target + if core.State.Graph.Package(pkg.Name) != nil { + // Package already added, so we're probably in a post-build function. Add target directly to graph now. + log.Debug("Adding new target %s directly to graph", target.Label) + core.State.Graph.AddTarget(target) + } + return unsafe.Pointer(target) +} + +//export SetPreBuildFunction +func SetPreBuildFunction(callback uintptr, cBytecode *C.char, cTarget unsafe.Pointer) { + target := (*core.BuildTarget)(cTarget) + target.PreBuildFunction = callback + hash := sha1.Sum([]byte(C.GoString(cBytecode))) + target.PreBuildHash = hash[:] +} + +//export SetPostBuildFunction +func SetPostBuildFunction(callback uintptr, cBytecode *C.char, cTarget unsafe.Pointer) { + target := (*core.BuildTarget)(cTarget) + target.PostBuildFunction = callback + hash := sha1.Sum([]byte(C.GoString(cBytecode))) + target.PostBuildHash = hash[:] +} + +//export AddDependency +func AddDependency(cPackage unsafe.Pointer, cTarget *C.char, cDep *C.char, exported bool) { + target := getTargetPost(cPackage, cTarget) + dep, _ := core.ParseBuildFileLabel(C.GoString(cDep), target.Label.PackageName) + target.AddDependency(dep) + if exported { + target.AddExportedDependency(dep) + } + core.State.Graph.AddDependency(target.Label, dep) +} + +//export AddOutputPost +func AddOutputPost(cPackage unsafe.Pointer, cTarget *C.char, cOut *C.char) { + target := getTargetPost(cPackage, cTarget) + out := C.GoString(cOut) + pkg := (*core.Package)(cPackage) + pkg.RegisterOutput(out, target) + target.AddOutput(out) +} + +//export AddLicencePost +func AddLicencePost(cPackage unsafe.Pointer, cTarget *C.char, cLicence *C.char) { + target := getTargetPost(cPackage, cTarget) + target.AddLicence(C.GoString(cLicence)) +} + +//export SetCommand +func SetCommand(cPackage unsafe.Pointer, cTarget *C.char, cCommand *C.char) { + target := getTargetPost(cPackage, cTarget) + oldCommand := target.Command + target.Command = C.GoString(cCommand) + log.Debug("Set command for %s to %s (was %s)", target.Label, target.Command, oldCommand) + // It'd be nice if we could ensure here that we're in the pre-build function + // but not the post-build function which is too late to have any effect. + // OTOH while it's ineffective it shouldn't cause any trouble trying it either... +} + +// Called by above to get a target from the current package. +// Panics if the target is not in the current package or has already been built. +func getTargetPost(cPackage unsafe.Pointer, cTarget *C.char) *core.BuildTarget { + pkg := (*core.Package)(cPackage) + name := C.GoString(cTarget) + target, present := pkg.Targets[name] + if !present { + panic(fmt.Sprintf("Unknown build target %s in %s", name, pkg.Name)) + } + // It'd be cheating to try to modify targets that're already built. + // Prohibit this because it'd likely end up with nasty race conditions. + if target.State() >= core.Built { + panic(fmt.Sprintf("Attempted to modify target %s, but it's already built", target.Label)) + } + return target +} + +//export AddSource +func AddSource(cTarget unsafe.Pointer, cSource *C.char) { + target := (*core.BuildTarget)(cTarget) + source := parseSource(C.GoString(cSource), target.Label.PackageName) + target.Sources = append(target.Sources, source) + if label := source.Label(); label != nil { + target.AddDependency(*label) + } +} + +// Parses an incoming source label as either a file or a build label. +// Identifies if the file is owned by this package and dies if not. +func parseSource(src string, packageName string) core.BuildInput { + if core.LooksLikeABuildLabel(src) { + label, file := core.ParseBuildFileLabel(src, packageName) + if file != "" { + return core.BuildFileLabel{BuildLabel: label, File: file} + } + return label + } else if strings.Contains(src, "../") { + panic(fmt.Errorf("'%s' (in package %s) is an invalid path; build target paths can't contain ../", src, packageName)) + } else if src[0] == '/' { + panic(fmt.Errorf("'%s' (in package %s) is an absolute path; that's not allowed.", src, packageName)) + } else if strings.Contains(src, "/") { + // Target is in a subdirectory, check nobody else owns that. + for dir := path.Dir(path.Join(packageName, src)); dir != packageName && dir != "."; dir = path.Dir(dir) { + if isPackage(dir) { + panic(fmt.Errorf("Package %s tries to use file %s, but that belongs to another package (%s).", packageName, src, dir)) + } + } + } + return core.FileLabel{File: src, Package: packageName} +} + +//export AddNamedSource +func AddNamedSource(cTarget unsafe.Pointer, cName *C.char, cSource *C.char) { + target := (*core.BuildTarget)(cTarget) + source := parseSource(C.GoString(cSource), target.Label.PackageName) + target.AddNamedSource(C.GoString(cName), source) + if label := source.Label(); label != nil { + target.AddDependency(*label) + } +} + +//export AddData +func AddData(cTarget unsafe.Pointer, cData *C.char) { + target := (*core.BuildTarget)(cTarget) + data := parseSource(C.GoString(cData), target.Label.PackageName) + target.Data = append(target.Data, data) + if label := data.Label(); label != nil { + target.AddDependency(*label) + } +} + +//export AddOutput +func AddOutput(cTarget unsafe.Pointer, cOutput *C.char) { + target := (*core.BuildTarget)(cTarget) + target.AddOutput(C.GoString(cOutput)) +} + +//export AddDep +func AddDep(cTarget unsafe.Pointer, cDep *C.char) { + target := (*core.BuildTarget)(cTarget) + dep, _ := core.ParseBuildFileLabel(C.GoString(cDep), target.Label.PackageName) + target.AddDependency(dep) +} + +//export AddExportedDep +func AddExportedDep(cTarget unsafe.Pointer, cDep *C.char) { + target := (*core.BuildTarget)(cTarget) + dep, _ := core.ParseBuildFileLabel(C.GoString(cDep), target.Label.PackageName) + target.AddDependency(dep) + target.AddExportedDependency(dep) +} + +//export AddTool +func AddTool(cTarget unsafe.Pointer, cTool *C.char) { + target := (*core.BuildTarget)(cTarget) + tool, _ := core.ParseBuildFileLabel(C.GoString(cTool), target.Label.PackageName) + target.Tools = append(target.Tools, tool) + target.AddDependency(tool) +} + +//export AddVis +func AddVis(cTarget unsafe.Pointer, cVis *C.char) { + target := (*core.BuildTarget)(cTarget) + vis := C.GoString(cVis) + if vis == "PUBLIC" { + target.Visibility = append(target.Visibility, core.NewBuildLabel("", "...")) + } else { + target.Visibility = append(target.Visibility, core.ParseBuildLabel(vis, target.Label.PackageName)) + } +} + +//export AddLabel +func AddLabel(cTarget unsafe.Pointer, cLabel *C.char) { + target := (*core.BuildTarget)(cTarget) + target.AddLabel(C.GoString(cLabel)) +} + +//export AddHash +func AddHash(cTarget unsafe.Pointer, cHash *C.char) { + target := (*core.BuildTarget)(cTarget) + target.Hashes = append(target.Hashes, C.GoString(cHash)) +} + +//export AddLicence +func AddLicence(cTarget unsafe.Pointer, cLicence *C.char) { + target := (*core.BuildTarget)(cTarget) + target.AddLicence(C.GoString(cLicence)) +} + +//export AddTestOutput +func AddTestOutput(cTarget unsafe.Pointer, cTestOutput *C.char) { + target := (*core.BuildTarget)(cTarget) + target.TestOutputs = append(target.TestOutputs, C.GoString(cTestOutput)) +} + +//export AddRequire +func AddRequire(cTarget unsafe.Pointer, cRequire *C.char) { + target := (*core.BuildTarget)(cTarget) + target.Requires = append(target.Requires, C.GoString(cRequire)) + // Requirements are also implicit labels + target.AddLabel(C.GoString(cRequire)) +} + +//export AddProvide +func AddProvide(cTarget unsafe.Pointer, cLanguage *C.char, cDep *C.char) { + target := (*core.BuildTarget)(cTarget) + target.AddProvide(C.GoString(cLanguage), core.ParseBuildLabel(C.GoString(cDep), target.Label.PackageName)) +} + +//export SetContainerSetting +func SetContainerSetting(cTarget unsafe.Pointer, cName, cValue *C.char) { + target := (*core.BuildTarget)(cTarget) + target.SetContainerSetting(strings.Replace(C.GoString(cName), "_", "", -1), C.GoString(cValue)) +} + +//export GetIncludeFile +func GetIncludeFile(cPackage unsafe.Pointer, cLabel *C.char) *C.char { + pkg := (*core.Package)(cPackage) + label := C.GoString(cLabel) + if !strings.HasPrefix(label, "//") { + panic("include_defs argument must be an absolute path (ie. start with //)") + } + relPath := strings.TrimLeft(label, "/") + pkg.RegisterSubinclude(relPath) + return C.CString(path.Join(core.RepoRoot, relPath)) +} + +// GetSubincludeFile is a callback to the interpreter that returns the path it +// should be opening in order to subinclude() a build target. +// For convenience we use in-band signalling for some errors since C can't handle multiple return values :) +// Fatal errors (like incorrect build labels etc) will cause a panic. +//export GetSubincludeFile +func GetSubincludeFile(cPackage unsafe.Pointer, cLabel *C.char) *C.char { + pkg := (*core.Package)(cPackage) + label := core.ParseBuildLabel(C.GoString(cLabel), pkg.Name) + pkgLabel := core.BuildLabel{PackageName: pkg.Name, Name: "all"} + target := core.State.Graph.Target(label) + if target == nil { + // Might not have been parsed yet. Check for that first. + if subincludePackage := core.State.Graph.Package(label.PackageName); subincludePackage == nil { + deferParse(label, pkg) + return cDeferParse // Not an error, they'll just have to wait. + } + panic(fmt.Sprintf("Failed to subinclude %s; package %s has no target by that name", label, label.PackageName)) + } else if tmp := core.NewBuildTarget(pkgLabel); !tmp.CanSee(target) { + panic(fmt.Sprintf("Can't subinclude %s from %s due to visibility constraints", label, pkg.Name)) + } else if len(target.Outputs()) != 1 { + panic(fmt.Sprintf("Can't subinclude %s, subinclude targets must have exactly one output", label)) + } else if target.State() < core.Built { + deferParse(label, pkg) + return cDeferParse // Again, they'll have to wait for this guy to build. + } + // Well if we made it to here it's actually ready to go, so tell them where to get it. + return C.CString(path.Join(target.OutDir(), target.Outputs()[0])) +} + +// runPreBuildFunction runs the pre-build function for a single target. +func runPreBuildFunction(pkg *core.Package, target *core.BuildTarget) error { + cName := C.CString(target.Label.Name) + defer C.free(unsafe.Pointer(cName)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if result := C.GoString(C.RunPreBuildFunction(callbacks.PreBuildCallbackRunner, C.size_t(target.PreBuildFunction), unsafe.Pointer(pkg), cName)); result != "" { + return fmt.Errorf("Failed to run pre-build function for target %s: %s", target.Label.String(), result) + } + return nil +} + +// runPostBuildFunction runs the post-build function for a single target. +func runPostBuildFunction(pkg *core.Package, target *core.BuildTarget, out string) error { + cName := C.CString(target.Label.Name) + cOutput := C.CString(out) + defer C.free(unsafe.Pointer(cName)) + defer C.free(unsafe.Pointer(cOutput)) + runtime.LockOSThread() + defer runtime.UnlockOSThread() + if result := C.GoString(C.RunPostBuildFunction(callbacks.PostBuildCallbackRunner, C.size_t(target.PostBuildFunction), unsafe.Pointer(pkg), cName, cOutput)); result != "" { + return fmt.Errorf("Failed to run post-build function for target %s: %s", target.Label.String(), result) + } + return nil +} + +// Unfortunately there doesn't seem to be any API to do this dynamically :( +var logLevelFuncs = map[logging.Level]func(format string, args ...interface{}){ + logging.CRITICAL: log.Fatalf, + logging.ERROR: log.Error, + logging.WARNING: log.Warning, + logging.NOTICE: log.Notice, + logging.INFO: log.Info, + logging.DEBUG: log.Debug, +} + +//export Log +func Log(level int, cPackage unsafe.Pointer, cMessage *C.char) { + pkg := (*core.Package)(cPackage) + f, present := logLevelFuncs[logging.Level(level)] + if !present { + f = log.Error + } + f("//%s/BUILD: %s", pkg.Name, C.GoString(cMessage)) +} + +//export Glob +func Glob(cPackage *C.char, cIncludes **C.char, numIncludes int, cExcludes **C.char, numExcludes int, includeHidden bool) **C.char { + packageName := C.GoString(cPackage) + filenames := []string{} + for i := 0; i < numIncludes; i++ { + matches, err := glob(packageName, C.GoString(C.getStringFromArray(cIncludes, C.int(i)))) + if err != nil { + panic(err) + } + for _, filename := range matches { + if !includeHidden { + // Exclude hidden & temporary files + _, file := path.Split(filename) + if strings.HasPrefix(file, ".") || (strings.HasPrefix(file, "#") && strings.HasSuffix(file, "#")) { + continue + } + } + if !shouldExcludeMatch(filename, packageName, cExcludes, numExcludes) { + if strings.HasPrefix(filename, packageName) { + filename = filename[len(packageName)+1:] // +1 to strip the slash too + } + filenames = append(filenames, filename) + } + } + } + return stringSliceToCStringArray(filenames) +} + +// stringSliceToCDoubleArray converts a Go slice of strings to a C array of char*'s. +// The returned array is terminated by a null pointer - the Python interpreter code will +// understand how to turn this back into Python strings. +func stringSliceToCStringArray(s []string) **C.char { + ret := C.allocateStringArray(C.int(len(s) + 1)) + for i, x := range s { + C.setStringInArray(ret, C.int(i), C.CString(x)) + } + C.setStringInArray(ret, C.int(len(s)), nil) + return ret +} + +func shouldExcludeMatch(match string, packageName string, cExcludes **C.char, numExcludes int) bool { + for j := 0; j < numExcludes; j++ { + exclPattern := path.Join(packageName, C.GoString(C.getStringFromArray(cExcludes, C.int(j)))) + matches, err := filepath.Match(exclPattern, match) + if err != nil { + panic(err) + } else if matches { + return true + } + } + return false +} + +func glob(rootPath, pattern string) ([]string, error) { + // Go's Glob function doesn't handle Ant-style ** patterns. Do it ourselves if we have to, + // but we prefer not since our solution will have to do a potentially inefficient walk. + if !strings.Contains(pattern, "**") { + return filepath.Glob(path.Join(rootPath, pattern)) + } + + matches := []string{} + // Turn the pattern into a regex. Oh dear... + pattern = strings.Replace(pattern, "*", "[^/]*", -1) // handle single (all) * components + pattern = strings.Replace(pattern, "[^/]*[^/]*", ".*", -1) // handle ** components + pattern = strings.Replace(pattern, "/.*/", "/(?:.*/)?", -1) // allow /**/ to match nothing + regex, err := regexp.Compile(pattern) + if err != nil { + return matches, err + } + + err = filepath.Walk(rootPath, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if info.IsDir() && name != rootPath && isPackage(name) { + return filepath.SkipDir // Can't glob past a package boundary + } else if !info.IsDir() && regex.MatchString(name) { + matches = append(matches, name) + } + return nil + }) + return matches, err +} + +// Memoize this to cut down on filesystem operations +var isPackageMemo = map[string]bool{} +var isPackageMutex sync.Mutex + +func isPackage(name string) bool { + isPackageMutex.Lock() + defer isPackageMutex.Unlock() + if ret, present := isPackageMemo[name]; present { + return ret + } + ret := isPackageInternal(name) + isPackageMemo[name] = ret + return ret +} + +func isPackageInternal(name string) bool { + for _, buildFileName := range buildFileNames { + if core.FileExists(path.Join(name, buildFileName)) { + return true + } + } + return false +} + +//export GetLabels +func GetLabels(cPackage unsafe.Pointer, cTarget *C.char, cPrefix *C.char) **C.char { + target := getTargetPost(cPackage, cTarget) + prefix := C.GoString(cPrefix) + if target.State() != core.Building { + log.Fatalf("get_labels called for %s incorrectly; the only time this is safe to call is from its own pre-build function.", target.Label) + } + labels := map[string]bool{} + var getLabels func(*core.BuildTarget) + getLabels = func(target *core.BuildTarget) { + for _, label := range target.Labels { + if strings.HasPrefix(label, prefix) { + labels[strings.TrimSpace(strings.TrimPrefix(label, prefix))] = true + } + } + for _, dep := range target.Dependencies { + getLabels(dep) + } + } + getLabels(target) + ret := make([]string, len(labels)) + i := 0 + for label := range labels { + ret[i] = label + i++ + } + sort.Strings(ret) + return stringSliceToCStringArray(ret) +} diff --git a/src/parse/interpreter.h b/src/parse/interpreter.h new file mode 100644 index 0000000000..9681223822 --- /dev/null +++ b/src/parse/interpreter.h @@ -0,0 +1,78 @@ +#ifndef _SRC_PARSE_INTERPRETER_H +#define _SRC_PARSE_INTERPRETER_H + +#include +#include +#include + +// Interface code between Python & Go. C is a kind of intermediate translation layer. +// This needs to be consistent with the cffi code in please_parser.py. +typedef unsigned char uint8; +typedef long long int64; +typedef char* (ParseFileCallback)(char*, char*, void*); +typedef void* (AddTargetCallback)(void*, char*, char*, char*, uint8, uint8, uint8, uint8, uint8, uint8, uint8, uint8, uint8, int64, int64, int64, char*); +typedef void (AddStringCallback)(void*, char*); +typedef void (AddTwoStringsCallback)(void*, char*, char*); +typedef void (AddDependencyCallback)(void*, char*, char*, uint8); +typedef void (AddOutputCallback)(void*, char*, char*); +typedef char** (GlobCallback)(char*, char**, long long, char**, long long, uint8); +typedef char* (GetIncludeFileCallback)(void*, char*); +typedef char** (GetLabelsCallback)(void*, char*, char*); +typedef void (SetConfigValueCallback)(char*, char*); +typedef char* (PreBuildCallbackRunner)(void*, void*, char*); +typedef char* (PostBuildCallbackRunner)(void*, void*, char*, char*); +typedef void (SetBuildFunctionCallback)(void*, char*, void*); +typedef void (LogCallback)(int64, void*, char*); +struct PleaseCallbacks { + ParseFileCallback* parse_file; + ParseFileCallback* parse_code; + AddTargetCallback* add_target; + AddStringCallback* add_src; + AddStringCallback* add_data; + AddStringCallback* add_dep; + AddStringCallback* add_exported_dep; + AddStringCallback* add_tool; + AddStringCallback* add_out; + AddStringCallback* add_vis; + AddStringCallback* add_label; + AddStringCallback* add_hash; + AddStringCallback* add_licence; + AddStringCallback* add_test_output; + AddStringCallback* add_require; + AddTwoStringsCallback* add_provide; + AddTwoStringsCallback* add_named_src; + AddTwoStringsCallback* set_container_setting; + GlobCallback* glob; + GetIncludeFileCallback* get_include_file; + GetIncludeFileCallback* get_subinclude_file; + GetLabelsCallback* get_labels; + SetBuildFunctionCallback* set_pre_build_function; + SetBuildFunctionCallback* set_post_build_function; + AddDependencyCallback* add_dependency; + AddOutputCallback* add_output; + AddTwoStringsCallback* add_licence_post; + AddTwoStringsCallback* set_command; + SetConfigValueCallback* set_config_value; + PreBuildCallbackRunner* pre_build_callback_runner; + PostBuildCallbackRunner* post_build_callback_runner; + LogCallback* log; +}; + +// AFAICT there isn't a way to call the function pointers directly. +char* ParseFile(ParseFileCallback* func, char* filename, char* package_name, void* package); +void SetConfigValue(SetConfigValueCallback* func, char* name, char* value); +char* RunPreBuildFunction(PreBuildCallbackRunner* runner, size_t callback, void* package, char* name); +char* RunPostBuildFunction(PostBuildCallbackRunner* runner, size_t callback, void* package, char* name, char* output); +void PreBuildFunctionSetter(void* callback, char* bytecode, void* target); +void PostBuildFunctionSetter(void* callback, char* bytecode, void* target); + +// Helper functions for handling arrays of strings in C; seems to be nigh impossible in native Go. +inline char** allocateStringArray(int len) { return malloc(len * sizeof(char*)); } +inline void setStringInArray(char** arr, int i, char* s) { arr[i] = s; } +inline char* getStringFromArray(char** arr, int i) { return arr[i]; } + +// Initialises interpreter. +// TODO(pebers): Second argument should change to 'struct PleaseCallbacks*' for go1.6. +int InitialiseInterpreter(char* data, void* callbacks); + +#endif // _SRC_PARSE_INTERPRETER_H diff --git a/src/parse/interpreter_test.go b/src/parse/interpreter_test.go new file mode 100644 index 0000000000..4c046a6d2d --- /dev/null +++ b/src/parse/interpreter_test.go @@ -0,0 +1,95 @@ +package parse + +import ( + "os" + "testing" + "unsafe" + + "github.com/stretchr/testify/assert" + + "core" +) + +func TestParseSourceBuildLabel(t *testing.T) { + src := parseSource("//src/parse/test_data/test_subfolder4:test_py", "src/parse") + label := src.Label() + assert.NotNil(t, label) + assert.Equal(t, label.PackageName, "src/parse/test_data/test_subfolder4") + assert.Equal(t, label.Name, "test_py") +} + +func TestParseSourceRelativeBuildLabel(t *testing.T) { + src := parseSource(":builtin_rules", "src/parse") + label := src.Label() + assert.NotNil(t, label) + assert.Equal(t, "src/parse", label.PackageName) + assert.Equal(t, "builtin_rules", label.Name) +} + +// Test parsing from a subdirectory that does not contain a build file. +func TestParseSourceFromSubdirectory(t *testing.T) { + src := parseSource("test_subfolder3/test_py", "src/parse/test_data") + assert.Nil(t, src.Label()) + paths := src.Paths(nil) + assert.Equal(t, 1, len(paths)) + assert.Equal(t, "src/parse/test_data/test_subfolder3/test_py", paths[0]) +} + +func TestParseSourceFromOwnedSubdirectory(t *testing.T) { + assert.Panics(t, func() { parseSource("test_subfolder4/test_py", "src/parse/test_data") }, + "Should panic when parsing from a subdirectory that does contain a build file") +} + +func TestParseSourceWithParentPath(t *testing.T) { + assert.Panics(t, func() { parseSource("test_subfolder4/../test_py", "src/parse/test_data") }, + "Should panic when parsing a path with ../ in it") +} + +func TestParseSourceWithAbsolutePath(t *testing.T) { + assert.Panics(t, func() { parseSource("/test_subfolder4/test_py", "src/parse/test_data") }, + "Should panic trying to parse an absolute path") +} + +func TestAddTarget(t *testing.T) { + pkg := core.NewPackage("src/parse") + addTargetTest1 := func(name string, binary, container, test bool, testCmd string) *core.BuildTarget { + target := addTarget(unsafe.Pointer(pkg), name, "true", testCmd, binary, test, + false, false, container, false, false, false, 0, 0, 0, "Building...") + return (*core.BuildTarget)(target) + } + addTargetTest := func(name string, binary, container bool) *core.BuildTarget { + return addTargetTest1(name, binary, container, false, "") + } + // Test that labels are correctly applied + target1 := addTargetTest("target1", false, false) + assert.False(t, target1.HasLabel("bin")) + assert.False(t, target1.HasLabel("container")) + target2 := addTargetTest("target2", true, false) + assert.True(t, target2.HasLabel("bin")) + assert.False(t, target2.HasLabel("container")) + target3 := addTargetTest("target3", true, true) + assert.True(t, target3.HasLabel("bin")) + assert.True(t, target3.HasLabel("container")) + + assert.Panics(t, func() { addTargetTest("target1", false, false) }, + "Should panic attempting to add a new target with the same name") + assert.Panics(t, func() { addTargetTest1("target4", false, false, true, "") }, + "Should panic attempting to add a test target with no test command") + assert.Panics(t, func() { addTargetTest1("target5", false, false, false, "true") }, + "Should panic attempting to add a non-test target with a test command") + + assert.Nil(t, core.State.Graph.Target(core.ParseBuildLabel("//src/parse:target1", "")), + "Shouldn't have added target to the graph yet") + core.State.Graph.AddPackage(pkg) + addTargetTest("target6", true, false) + target6 := core.State.Graph.Target(core.ParseBuildLabel("//src/parse:target6", "")) + assert.NotNil(t, target6, "Should have been added to the graph since the package is added") + assert.True(t, target6.HasLabel("bin")) +} + +func TestMain(m *testing.M) { + // Need to set this before calling parseSource. It's a bit of a hack but whatevs. + buildFileNames = []string{"TEST_BUILD"} + core.NewBuildState(10, nil, 2, core.DefaultConfiguration()) + os.Exit(m.Run()) +} diff --git a/src/parse/parse_step.go b/src/parse/parse_step.go new file mode 100644 index 0000000000..9c9462830a --- /dev/null +++ b/src/parse/parse_step.go @@ -0,0 +1,391 @@ +// Package responsible for parsing build files and constructing build targets & the graph. +// +// The actual work here is done by an embedded PyPy instance. Various rules are built in to +// the binary itself using go-bindata to embed the .py files; these are always available to +// all programs which is rather nice, but it does mean that must be run before 'go run' etc +// will work as expected. +package parse + +import "core" +import "fmt" +import "os" +import "path" +import "path/filepath" +import "strings" +import "sync" + +// Parses the package corresponding to a single build label. The label can be :all to add all targets in a package. +// It is not an error if the package has already been parsed. +// +// By default, after the package is parsed, any targets that are now needed for the build and ready +// to be built are queued, and any new packages are queued for parsing. When a specific label is requested +// this is straightforward, but when parsing for pseudo-targets like :all and ..., various flags affect it: +// If 'noDeps' is true, then no new packages will be added and no new targets queued. +// 'include' and 'exclude' refer to the labels of targets to be added. If 'include' is non-empty then only +// targets with at least one matching label are added. Any targets with a label in 'exclude' are not added. +func Parse(tid int, state *core.BuildState, label, dependor core.BuildLabel, noDeps bool, include, exclude []string) { + defer func() { + if r := recover(); r != nil { + state.LogBuildError(tid, label, core.ParseFailed, fmt.Errorf("%s", r), "Failed to parse package") + } + }() + // First see if this package already exists; once it's in the graph it will have been parsed. + pkg := state.Graph.Package(label.PackageName) + if pkg != nil { + // Does exist, all we need to do is toggle on this target + activateTarget(state, pkg, label, dependor, noDeps, include, exclude) + return + } + // We use the name here to signal undeferring of a package. If we get that we need to retry the package regardless. + if dependor.Name != "_UNDEFER_" && !firstToParse(label, dependor) { + // Check this again to avoid a potential race + if pkg = state.Graph.Package(label.PackageName); pkg != nil { + activateTarget(state, pkg, label, dependor, noDeps, include, exclude) + } else { + log.Debug("Adding pending parse for %s", label) + } + return + } + // If we get here then it falls to us to parse this package + state.LogBuildResult(tid, label, core.PackageParsing, "Parsing...") + pkg = parsePackage(state, label, dependor) + if pkg == nil { + state.LogBuildResult(tid, label, core.PackageParsed, "Deferred") + return + } + + // Now add any lurking pending targets for this package. + pendingTargetMutex.Lock() + pending := pendingTargets[label.PackageName] // Must be present. + pendingTargets[label.PackageName] = map[string][]core.BuildLabel{} // Empty this to free memory, but leave a sentinel + pendingTargetMutex.Unlock() // Nothing will look up this package in the map again. + for targetName, dependors := range pending { + for _, dependor := range dependors { + lbl := core.BuildLabel{PackageName: label.PackageName, Name: targetName} + activateTarget(state, pkg, lbl, dependor, noDeps, include, exclude) + } + } + state.LogBuildResult(tid, label, core.PackageParsed, "Parsed") +} + +// activateTarget marks a target as active (ie. to be built) and adds its dependencies as pending parses. +func activateTarget(state *core.BuildState, pkg *core.Package, label, dependor core.BuildLabel, noDeps bool, include, exclude []string) { + if !label.IsAllTargets() && state.Graph.Target(label) == nil { + msg := fmt.Sprintf("Parsed build file %s/BUILD but it doesn't contain target %s", label.PackageName, label.Name) + if dependor != core.OriginalTarget { + msg += fmt.Sprintf(" (depended on by %s)", dependor) + } + panic(msg) + } + if noDeps && !dependor.IsAllTargets() { // IsAllTargets indicates requirement for parse + return // Some kinds of query don't need a full recursive parse. + } else if label.IsAllTargets() { + for _, target := range pkg.Targets { + if target.ShouldInclude(include, exclude) { + // Must always do this for coverage because we need to calculate sources of + // non-test targets later on. + if !state.NeedTests || target.IsTest || state.NeedCoverage { + addDep(state, target.Label, dependor, false, dependor.IsAllTargets()) + } + } + } + } else { + for _, l := range state.Graph.DependentTargets(dependor, label) { + // We use :all to indicate a dependency needed for parse. + addDep(state, l, dependor, false, dependor.IsAllTargets()) + } + } +} + +// Used to arbitrate single access to these maps +var pendingTargetMutex sync.Mutex + +// Map of package name -> target name -> label that requested parse +var pendingTargets = map[string]map[string][]core.BuildLabel{} + +// Map of package name -> target name -> package names that're waiting for it +var deferredParses = map[string]map[string][]string{} + +// firstToParse returns true if the caller is the first to parse a given package and hence should +// continue parsing that file. It only returns true once for each package but stores subsequent +// targets in the pendingTargets map. +func firstToParse(label, dependor core.BuildLabel) bool { + pendingTargetMutex.Lock() + defer pendingTargetMutex.Unlock() + if pkg, present := pendingTargets[label.PackageName]; present { + pkg[label.Name] = append(pkg[label.Name], dependor) + return false + } + pendingTargets[label.PackageName] = map[string][]core.BuildLabel{label.Name: []core.BuildLabel{dependor}} + return true +} + +// deferParse defers the parsing of a package until the given label has been built. +func deferParse(label core.BuildLabel, pkg *core.Package) { + pendingTargetMutex.Lock() + defer pendingTargetMutex.Unlock() + log.Debug("Deferring parse of %s", pkg.Name) + if m, present := deferredParses[label.PackageName]; present { + m[label.Name] = append(m[label.Name], pkg.Name) + } else { + deferredParses[label.PackageName] = map[string][]string{label.Name: []string{pkg.Name}} + } + core.State.AddPendingParse(label, core.BuildLabel{PackageName: pkg.Name, Name: "all"}) +} + +// UndeferAnyParses un-defers the parsing of a package if it depended on some subinclude target being built. +func UndeferAnyParses(state *core.BuildState, target *core.BuildTarget) { + pendingTargetMutex.Lock() + defer pendingTargetMutex.Unlock() + if m, present := deferredParses[target.Label.PackageName]; present { + if s, present := m[target.Label.Name]; present { + for _, deferredPackageName := range s { + log.Debug("Undeferring parse of %s", deferredPackageName) + state.AddPendingParse( + core.BuildLabel{PackageName: deferredPackageName, Name: getDependingTarget(deferredPackageName)}, + core.BuildLabel{PackageName: deferredPackageName, Name: "_UNDEFER_"}, + ) + } + delete(m, target.Label.Name) // Don't need this any more + } + } +} + +// getDependingTarget returns the name of any one target in packageName that required parsing. +func getDependingTarget(packageName string) string { + // We need to supply a label in this package that actually needs to be built. + // Fortunately there must be at least one of these in the pending target map... + if m, present := pendingTargets[packageName]; present { + for target := range m { + return target + } + } + // We shouldn't really get here, of course. + log.Error("No pending target entry for %s at deferral. Must assume :all.", packageName) + return "all" +} + +// parsePackage performs the initial parse of a package. +// It's assumed that the caller used firstToParse to ascertain that they only call this once per package. +func parsePackage(state *core.BuildState, label, dependor core.BuildLabel) *core.Package { + packageName := label.PackageName + pkg := core.NewPackage(packageName) + if pkg.Filename = buildFileName(state, packageName); pkg.Filename == "" { + exists := core.PathExists(packageName) + // Handle quite a few cases to provide more obvious error messages. + if dependor != core.OriginalTarget && exists { + panic(fmt.Sprintf("%s depends on %s, but there's no BUILD file in %s/", dependor, label, packageName)) + } else if dependor != core.OriginalTarget { + panic(fmt.Sprintf("%s depends on %s, but the directory %s doesn't exist", dependor, label, packageName)) + } else if exists { + panic(fmt.Sprintf("Can't build %s; there's no BUILD file in %s/", label, packageName)) + } + panic(fmt.Sprintf("Can't build %s; the directory %s doesn't exist", label, packageName)) + } + + if parsePackageFile(state, pkg.Filename, pkg) { + return nil // Indicates deferral + } + + for _, target := range pkg.Targets { + state.Graph.AddTarget(target) + for _, out := range target.DeclaredOutputs() { + pkg.RegisterOutput(out, target) + } + for _, out := range target.TestOutputs { + pkg.RegisterOutput(out, target) + } + } + // Do this in a separate loop so we get intra-package dependencies right now. + for _, target := range pkg.Targets { + for _, dep := range target.DeclaredDependencies { + state.Graph.AddDependency(target.Label, dep) + } + } + state.Graph.AddPackage(pkg) // Calling this means nobody else will add entries to pendingTargets for this package. + createInitPyIfNeeded(pkg, packageName) + return pkg +} + +// Pre-emptively create __init__.py files so we can load generated modules dynamically. +// It's a bit cheeky to do language-specific logic here but it's hard to find another way. +func createInitPyIfNeeded(pkg *core.Package, packagePath string) { + for _, target := range pkg.Targets { + for _, require := range target.Requires { + if require == "py" { + dir := path.Join(core.RepoRoot, "plz-out/gen", packagePath) + for i := 0; i < len(strings.Split(packagePath, "/")); i++ { + initPy := path.Join(dir, "__init__.py") + if !core.PathExists(initPy) { + if err := os.MkdirAll(dir, core.DirPermissions); err != nil { + panic(fmt.Sprintf("Failed to create directory %s: %s", dir, err)) + } else if file, err := os.Create(initPy); err != nil { + panic(fmt.Sprintf("Failed to create file %s: %s", initPy, err)) + } else { + file.Close() + } + } + dir = path.Dir(dir) + } + return + } + } + } +} + +func buildFileName(state *core.BuildState, pkgName string) string { + for _, buildFileName := range state.Config.Please.BuildFileName { + if filename := path.Join(pkgName, buildFileName); core.FileExists(filename) { + return filename + } + } + return "" +} + +// Adds a single target to the build queue. +func addDep(state *core.BuildState, label, dependor core.BuildLabel, rescan, forceBuild bool) { + // Stop at any package that's not loaded yet + if state.Graph.Package(label.PackageName) == nil { + state.AddPendingParse(label, dependor) + return + } + target := state.Graph.Target(label) + if target == nil { + log.Fatalf("Target %s (referenced by %s) doesn't exist\n", label, dependor) + } + if target.State() >= core.Active && !rescan && !forceBuild { + return // Target is already tagged to be built and likely on the queue. + } + // Only do this bit if we actually need to build the targe + if !target.SyncUpdateState(core.Inactive, core.Semiactive) && !rescan && !forceBuild { + return + } + if state.NeedBuild || forceBuild { + if target.SyncUpdateState(core.Semiactive, core.Active) { + state.AddActiveTarget() + if target.IsTest && state.NeedTests { + state.AddActiveTarget() // Tests count twice if we're gonna run them. + } + } + } + // If this target has no deps, add it to the queue now, otherwise handle its deps. + // Only add if we need to build targets (not if we're just parsing) but we might need it to parse... + if target.State() == core.Active && state.Graph.AllDepsBuilt(target) { + if target.SyncUpdateState(core.Active, core.Pending) { + state.AddPendingBuild(label) + } + if !rescan { + return + } + } + for _, dep := range target.DeclaredDependencies { + // Check the require/provide stuff; we may need to add a different target. + if len(target.Requires) > 0 { + if depTarget := state.Graph.Target(dep); depTarget != nil && len(depTarget.Provides) > 0 { + for _, provided := range depTarget.ProvideFor(target) { + addDep(state, provided, label, false, forceBuild) + } + continue + } + } + addDep(state, dep, label, false, forceBuild) + } +} + +// RunPreBuildFunction runs a pre-build callback function registered on a build target via pre_build = <...>. +// +// This is called before the target is built. It doesn't receive any output like the post-build one does but can +// be useful for other things; for example if you want to investigate a target's transitive labels to adjust +// its build command, you have to do that here (because in general the transitive dependencies aren't known +// when the rule is evaluated). +func RunPreBuildFunction(tid int, state *core.BuildState, target *core.BuildTarget) error { + state.LogBuildResult(tid, target.Label, core.PackageParsing, + fmt.Sprintf("Running pre-build function for %s", target.Label)) + pkg := state.Graph.Package(target.Label.PackageName) + if err := runPreBuildFunction(pkg, target); err != nil { + state.LogBuildError(tid, target.Label, core.ParseFailed, err, "Failed pre-build function for %s", target.Label) + return err + } + rescanDeps(state, pkg) + state.LogBuildResult(tid, target.Label, core.TargetBuilding, + fmt.Sprintf("Finished pre-build function for %s", target.Label)) + return nil +} + +// RunPostBuildFunction runs a post-build callback function registered on a build target via post_build = <...>. +// +// This is called after the target has been built and it is given the combined stdout/stderr of +// the build process. This output is passed to the post-build Python function which can then +// generate new targets or add dependencies to existing unbuilt targets. +func RunPostBuildFunction(tid int, state *core.BuildState, target *core.BuildTarget, out string) error { + state.LogBuildResult(tid, target.Label, core.PackageParsing, + fmt.Sprintf("Running post-build function for %s", target.Label)) + pkg := state.Graph.Package(target.Label.PackageName) + log.Debug("Running post-build function for %s. Build output:\n%s\n", target.Label, out) + if err := runPostBuildFunction(pkg, target, out); err != nil { + state.LogBuildError(tid, target.Label, core.ParseFailed, err, "Failed post-build function for %s", target.Label) + return err + } + rescanDeps(state, pkg) + state.LogBuildResult(tid, target.Label, core.TargetBuilding, + fmt.Sprintf("Finished post-build function for %s", target.Label)) + return nil +} + +func rescanDeps(state *core.BuildState, pkg *core.Package) { + // Run over all the targets in this package and ensure that any newly added dependencies enter the build queue. + for _, target := range pkg.Targets { + // TODO(pebers): this is pretty brutal; we're forcing a recheck of all dependencies + // in case we have any new targets. It'd be better to do it only for + // targets that need it but it's not easy to tell we're in a post build + // function at the point we'd need to do that. + if !state.Graph.AllDependenciesResolved(target) { + for _, dep := range target.DeclaredDependencies { + state.Graph.AddDependency(target.Label, dep) + } + } + s := target.State() + if s < core.Built && s > core.Inactive { + addDep(state, target.Label, core.OriginalTarget, true, false) + } + } +} + +// Finds all packages under a particular path. +// Used to implement rules with ... where we need to know all possible packages +// under that location. +func FindAllSubpackages(config core.Configuration, rootPath string, prefix string) <-chan string { + ch := make(chan string) + go func() { + if rootPath == "" { + rootPath = "." + } + if err := filepath.Walk(rootPath, func(name string, info os.FileInfo, err error) error { + if err != nil { + return err // stop on any error + } else if name == "plz-out" || (info.IsDir() && strings.HasPrefix(info.Name(), ".") && name != ".") { + return filepath.SkipDir // Don't walk output or hidden directories + } else if info.IsDir() && !strings.HasPrefix(name, prefix) && !strings.HasPrefix(prefix, name) { + return filepath.SkipDir // Skip any directory without the prefix we're after (but not any directory beneath that) + } else if isABuildFile(info.Name(), config) && !info.IsDir() { + dir, _ := path.Split(name) + ch <- strings.TrimRight(dir, "/") + } + return nil + }); err != nil { + log.Fatalf("Failed to walk tree under %s; %s\n", rootPath, err) + } + close(ch) + }() + return ch +} + +// Returns true if given filename is a build file name. +func isABuildFile(name string, config core.Configuration) bool { + for _, buildFileName := range config.Please.BuildFileName { + if name == buildFileName { + return true + } + } + return false +} diff --git a/src/parse/parse_step_test.go b/src/parse/parse_step_test.go new file mode 100644 index 0000000000..30c2eea003 --- /dev/null +++ b/src/parse/parse_step_test.go @@ -0,0 +1,195 @@ +// Tests for general parse functions. + +package parse + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "core" +) + +var empty = []string{} + +func TestAddDepSimple(t *testing.T) { + // Simple case with only one package parsed and one target added + state := makeState(true, false) + activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty) + assertPendingParses(t, state, "//package2:target1", "//package2:target1") + assertPendingBuilds(t, state) // None until package2 parses + assert.Equal(t, 5, state.NumActive()) +} + +func TestAddDepMultiple(t *testing.T) { + // Similar to above but doing all targets in that package + state := makeState(true, false) + activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty) + activateTarget(state, nil, buildLabel("//package1:target2"), core.OriginalTarget, false, empty, empty) + activateTarget(state, nil, buildLabel("//package1:target3"), core.OriginalTarget, false, empty, empty) + // We get an additional dep on target2, but not another on package2:target1 because target2 + // is already activated since package1:target1 depends on it + assertPendingParses(t, state, "//package2:target1", "//package2:target1", "//package2:target2") + assertPendingBuilds(t, state) // None until package2 parses + assert.Equal(t, 7, state.NumActive()) +} + +func TestAddDepMultiplePackages(t *testing.T) { + // This time we already have package2 parsed + state := makeState(true, true) + activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty) + assertPendingParses(t, state) // None, we have both packages already + assertPendingBuilds(t, state, "//package2:target2") // This is the only candidate target + assert.Equal(t, 6, state.NumActive()) +} + +func TestAddDepNoBuild(t *testing.T) { + // Tag state as not needing build. We shouldn't get any pending builds at this point. + state := makeState(true, true) + state.NeedBuild = false + activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty) + assertPendingParses(t, state) // None, we have both packages already + assertPendingBuilds(t, state) // Nothing because we don't need to build. + assert.Equal(t, 1, state.NumActive()) // Parses only +} + +func TestAddParseDep(t *testing.T) { + // Tag state as not needing build. Any target that needs to be built to complete parse + // should still get queued for build though. Recall that we indicate this with :all... + state := makeState(true, true) + state.NeedBuild = false + activateTarget(state, nil, buildLabel("//package2:target2"), buildLabel("//package3:all"), false, empty, empty) + assertPendingParses(t, state) // None, we have both packages already + assertPendingBuilds(t, state, "//package2:target2") // Queued because it's needed for parse + assert.Equal(t, 2, state.NumActive()) +} + +func TestAddDepRescan(t *testing.T) { + // Simulate a post-build function and rescan. + state := makeState(true, true) + activateTarget(state, nil, buildLabel("//package1:target1"), core.OriginalTarget, false, empty, empty) + assertPendingParses(t, state) // None, we have both packages already + assertPendingBuilds(t, state, "//package2:target2") // This is the only candidate target + assert.Equal(t, 6, state.NumActive()) + + // Add new target & dep to target1 + target4 := makeTarget("//package1:target4") + state.Graph.Package("package1").Targets["target4"] = target4 + state.Graph.AddTarget(target4) + target1 := state.Graph.TargetOrDie(buildLabel("//package1:target1")) + target1.AddDependency(buildLabel("//package1:target4")) + state.Graph.AddDependency(buildLabel("//package1:target1"), buildLabel("//package1:target4")) + + // Fake test: calling this now should have no effect because rescan is not true. + addDep(state, buildLabel("//package1:target1"), core.OriginalTarget, false, false) + assertPendingParses(t, state) + assertPendingBuilds(t, state) // Note that the earlier call to assertPendingBuilds cleared it. + + // Now running this should activate it + rescanDeps(state, state.Graph.Package("package1")) + assertPendingParses(t, state) + assertPendingBuilds(t, state, "//package1:target4") + assert.True(t, state.Graph.AllDependenciesResolved(target1)) +} + +func TestAddParseDepDeferred(t *testing.T) { + // Similar to TestAddParseDep but where we scan the package once and come back later because + // something else asserts a dependency on it. + state := makeState(true, true) + state.NeedBuild = false + assert.Equal(t, 1, state.NumActive()) + activateTarget(state, nil, buildLabel("//package2:target2"), core.OriginalTarget, false, empty, empty) + assertPendingParses(t, state) + assertPendingBuilds(t, state) // Not yet. + + // Now the undefer kicks off... + activateTarget(state, nil, buildLabel("//package2:target2"), buildLabel("//package1:all"), false, empty, empty) + assertPendingParses(t, state) + assertPendingBuilds(t, state, "//package2:target2") // This time! + assert.Equal(t, 2, state.NumActive()) +} + +func makeTarget(label string, deps ...string) *core.BuildTarget { + target := core.NewBuildTarget(core.ParseBuildLabel(label, "")) + for _, dep := range deps { + target.AddDependency(core.ParseBuildLabel(dep, "")) + } + return target +} + +// makeState creates a new build state with optionally one or two packages in it. +// Used in various tests above. +func makeState(withPackage1, withPackage2 bool) *core.BuildState { + state := core.NewBuildState(5, nil, 4, core.DefaultConfiguration()) + if withPackage1 { + pkg := core.NewPackage("package1") + state.Graph.AddPackage(pkg) + pkg.Targets["target1"] = makeTarget("//package1:target1", "//package1:target2", "//package2:target1") + pkg.Targets["target2"] = makeTarget("//package1:target2", "//package2:target1") + pkg.Targets["target3"] = makeTarget("//package1:target3", "//package2:target2") + state.Graph.AddTarget(pkg.Targets["target1"]) + state.Graph.AddTarget(pkg.Targets["target2"]) + state.Graph.AddTarget(pkg.Targets["target3"]) + addDeps(state.Graph, pkg) + } + if withPackage2 { + pkg := core.NewPackage("package2") + state.Graph.AddPackage(pkg) + pkg.Targets["target1"] = makeTarget("//package2:target1", "//package2:target2", "//package1:target3") + pkg.Targets["target2"] = makeTarget("//package2:target2") + state.Graph.AddTarget(pkg.Targets["target1"]) + state.Graph.AddTarget(pkg.Targets["target2"]) + addDeps(state.Graph, pkg) + } + return state +} + +func addDeps(graph *core.BuildGraph, pkg *core.Package) { + for _, target := range pkg.Targets { + for _, dep := range target.DeclaredDependencies { + graph.AddDependency(target.Label, dep) + } + } +} + +func assertPendingParses(t *testing.T, state *core.BuildState, targets ...string) { + pendingParses, _, _ := state.ReceiveChannels() + pending := []core.BuildLabel{} +loop: + for { + select { + case p := <-pendingParses: + pending = append(pending, p.Label) + default: + break loop + } + } + expected := []core.BuildLabel{} + for _, target := range targets { + expected = append(expected, core.ParseBuildLabel(target, "")) + } + assert.Equal(t, expected, pending) +} + +func assertPendingBuilds(t *testing.T, state *core.BuildState, targets ...string) { + _, pendingBuilds, _ := state.ReceiveChannels() + pending := []core.BuildLabel{} +loop: + for { + select { + case p := <-pendingBuilds: + pending = append(pending, p) + default: + break loop + } + } + expected := []core.BuildLabel{} + for _, target := range targets { + expected = append(expected, core.ParseBuildLabel(target, "")) + } + assert.Equal(t, expected, pending) +} + +func buildLabel(bl string) core.BuildLabel { + return core.ParseBuildLabel(bl, "") +} diff --git a/src/parse/require_provide_test.py b/src/parse/require_provide_test.py new file mode 100644 index 0000000000..d45d6ffc3b --- /dev/null +++ b/src/parse/require_provide_test.py @@ -0,0 +1,19 @@ +#!/usr/bin/python + +import pkg_resources +import unittest + + +class RequireProvideTest(unittest.TestCase): + + def test_other_language_not_present(self): + """Test that we don't get the Go file from the dependent rule.""" + self.assertFalse(pkg_resources.resource_exists('src.parse', 'test_require.go')) + + def test_our_language_is_present(self): + """Test that we do get the Python file from the dependent rule.""" + self.assertTrue(pkg_resources.resource_exists('src.parse', 'test_require.py')) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/parse/rules/cc_rules.py b/src/parse/rules/cc_rules.py new file mode 100644 index 0000000000..5f12f0e101 --- /dev/null +++ b/src/parse/rules/cc_rules.py @@ -0,0 +1,408 @@ +"""Rules to build C++ targets (or likely C although we've not tested that extensively). + +In general these have received somewhat less testing than would really be required for +the complex build environment C++ has, so some issues may remain. +""" + + +def cc_library(name, srcs=None, hdrs=None, deps=None, visibility=None, test_only=False, + compiler_flags=None, linker_flags=None, pkg_config_libs=None, archive=False): + """Generate a C++ library target. + + Args: + name (str): Name of the rule + srcs (list): C or C++ source files to compile. + hdrs (list): Header files. These will be made available to dependent rules, so the distinction + between srcs and hdrs is important. + deps (list): Dependent rules. + visibility (list): Visibility declaration for this rule. + test_only (bool): If True, is only available to other test rules. + compiler_flags (list): Flags to pass to the compiler. + linker_flags (list): Flags to pass to the linker; these will not be used here but will be + picked up by a cc_binary or cc_test rule. + pkg_config_libs (list): Libraries to declare a dependency on using pkg-config. Again, the ldflags + will be picked up by cc_binary or cc_test rules. + archive (bool): Deprecated, has no effect. + """ + srcs = srcs or [] + hdrs = hdrs or [] + deps = deps or [] + linker_flags = linker_flags or [] + pkg_config_libs = pkg_config_libs or [] + flags = _build_flags(compiler_flags, [], [], pkg_config_cflags=pkg_config_libs) + + # Collect the headers for other rules + filegroup( + name='_%s#hdrs' % name, + srcs=hdrs, + visibility=visibility, + requires=['cc_hdrs'], + exported_deps=deps, + ) + build_rule( + name='_%s#a' % name, + srcs={'srcs': srcs, 'hdrs': hdrs}, + outs=[name + '.a'], + deps=deps, + visibility=visibility, + cmd='%s -c -I . ${SRCS_SRCS} %s && ar rcs%s $OUT *.o' % (CONFIG.CC_TOOL, flags, _AR_FLAG), + building_description='Compiling...', + requires=['cc', 'cc_hdrs'], + test_only=test_only, + labels=['cc:ld:' + flag for flag in linker_flags] + + ['cc:pc:' + lib for lib in pkg_config_libs], + ) + hdrs_rule = ':_%s#hdrs' % name + a_rule = ':_%s#a' % name + filegroup( + name=name, + srcs=[hdrs_rule, a_rule], + provides={ + 'cc_hdrs': hdrs_rule, + }, + deps=deps + [hdrs_rule, a_rule], + test_only=test_only, + visibility=visibility, + output_is_complete=False, + ) + + +def cc_static_library(name, srcs=None, hdrs=None, compiler_flags=None, linker_flags=None, + deps=None, visibility=None, test_only=False, pkg_config_libs=None): + """Generates a C++ static library (.a). + + This is essentially just a collection of other cc_library rules into a single archive. + Optionally this rule can have sources of its own, but it's quite reasonable just to use + it as a collection of other rules. + + Args: + name (str): Name of the rule + srcs (list): C or C++ source files to compile. + hdrs (list): Header files. + compiler_flags (list): Flags to pass to the compiler. + linker_flags (list): Flags to pass to the linker. + deps (list): Dependent rules. + visibility (list): Visibility declaration for this rule. + test_only (bool): If True, is only available to other test rules. + pkg_config_libs (list): Libraries to declare a dependency on using pkg-config. + """ + deps = deps or [] + provides = None + if srcs: + cc_library( + name = '_%s#lib' % name, + srcs = srcs, + hdrs = hdrs, + compiler_flags = compiler_flags, + linker_flags = linker_flags, + deps = deps, + test_only = test_only, + pkg_config_libs = pkg_config_libs, + ) + deps.append(':_%s#lib' % name) + deps.append(':__%s#lib#hdrs' % name) + provides = { + 'cc_hdrs': ':__%s#lib#hdrs' % name, + 'cc': ':' + name, + } + build_rule( + name = name, + deps = deps, + outs = ['lib%s.a' % name], + cmd = '(find . -name "*.a" | xargs -n 1 ar x) && ar rcs%s $OUT `find . -name "*.o"`' % _AR_FLAG, + needs_transitive_deps = True, + output_is_complete = True, + visibility = visibility, + building_description = 'Archiving...', + provides = provides, + ) + + +def cc_shared_object(name, srcs=None, hdrs=None, compiler_flags=None, linker_flags=None, + deps=None, visibility=None, test_only=False, pkg_config_libs=None): + """Generates a C++ shared object with its dependencies linked in. + + Args: + name (str): Name of the rule + srcs (list): C or C++ source files to compile. + hdrs (list): Header files. These will be made available to dependent rules, so the distinction + between srcs and hdrs is important. + compiler_flags (list): Flags to pass to the compiler. + linker_flags (list): Flags to pass to the linker. + deps (list): Dependent rules. + visibility (list): Visibility declaration for this rule. + test_only (bool): If True, is only available to other test rules. + pkg_config_libs (list): Libraries to declare a dependency on using pkg-config. + """ + deps = deps or [] + srcs = srcs or [] + hdrs = hdrs or [] + flags = _build_flags(compiler_flags, linker_flags, pkg_config_libs, binary=True) + cmd = '%s -o ${OUT} -shared -I . ${SRCS_SRCS} %s' % (CONFIG.CC_TOOL, flags) + build_rule( + name=name, + srcs={'srcs': srcs, 'hdrs': hdrs}, + outs=[name + '.so'], + deps=deps, + visibility=visibility, + cmd=cmd, + building_description='Linking...', + needs_transitive_deps=True, + output_is_complete=True, + requires=['cc'], + pre_build=_apply_transitive_labels(cmd), + ) + + +def cc_binary(name, srcs=None, hdrs=None, compiler_flags=None, + linker_flags=None, deps=None, visibility=None, pkg_config_libs=None): + """Builds a binary from a collection of C++ rules. + + Args: + name (str): Name of the rule + srcs (list): C or C++ source files to compile. + hdrs (list): Header files. + compiler_flags (list): Flags to pass to the compiler. + linker_flags (list): Flags to pass to the linker. + deps (list): Dependent rules. + visibility (list): Visibility declaration for this rule. + pkg_config_libs (list): Libraries to declare a dependency on using pkg-config. + """ + srcs = srcs or [] + hdrs = hdrs or [] + linker_flags = linker_flags or [CONFIG.DEFAULT_LDFLAGS] + flags = _build_flags(compiler_flags, linker_flags, pkg_config_libs, binary=True) + cmd = '%s -o ${OUT} -I . ${SRCS_SRCS} %s' % (CONFIG.CC_TOOL, flags) + build_rule( + name=name, + srcs={'srcs': srcs, 'hdrs': hdrs}, + outs=[name], + deps=deps, + visibility=visibility, + cmd=cmd, + building_description='Linking...', + binary=True, + needs_transitive_deps=True, + output_is_complete=True, + requires=['cc'], + pre_build=_apply_transitive_labels(cmd), + ) + + +def cc_test(name, srcs=None, compiler_flags=None, linker_flags=None, pkg_config_libs=None, + deps=None, data=None, visibility=None, labels=None, flaky=0, test_outputs=None, + timeout=0, container=False): + """Defines a C++ test using UnitTest++. + + We template in a main file so you don't have to supply your own. + (Later we might allow that to be configured to help support other unit test frameworks). + + Args: + name (str): Name of the rule + srcs (list): C or C++ source files to compile. + compiler_flags (list): Flags to pass to the compiler. + linker_flags (list): Flags to pass to the linker. + pkg_config_libs (list): Libraries to declare a dependency on using pkg-config. + deps (list): Dependent rules. + data (list): Runtime data files for this test. + visibility (list): Visibility declaration for this rule. + labels (list): Labels to attach to this test. + flaky (bool | int): If true the test will be marked as flaky and automatically retried. + test_outputs (list): Extra test output files to generate from this test. + timeout (int): Length of time in seconds to allow the test to run for before killing it. + container (bool | dict): If true the test is run in a container (eg. Docker). + """ + srcs = srcs or [] + deps=deps or [] + compiler_flags = compiler_flags or [CONFIG.DEFAULT_TEST_CFLAGS] + linker_flags = linker_flags or [CONFIG.DEFAULT_TEST_LDFLAGS] + flags = _build_flags(compiler_flags, linker_flags, pkg_config_libs, binary=True) + genrule( + name='_%s#main' % name, + outs=['_%s_main.cc' % name], + cmd='echo \'%s\' > $OUT' % _CC_TEST_MAIN_CONTENTS, + test_only=True, + ) + deps.append(':_%s#main' % name) + srcs.append(':_%s#main' % name) + cmd = '%s -o ${OUT} -I . ${SRCS} %s' % (CONFIG.CC_TOOL, flags) + build_rule( + name=name, + srcs=srcs, + outs=[name], + deps=deps, + data=data, + visibility=visibility, + cmd=cmd, + test_cmd='$(exe :%s) > test.results' % name, + building_description='Linking...', + binary=True, + test=True, + needs_transitive_deps=True, + output_is_complete=True, + requires=['cc'], + labels=labels, + pre_build=_apply_transitive_labels(cmd), + flaky=flaky, + test_outputs=test_outputs, + test_timeout=timeout, + container=container, + ) + + +def cc_embed_binary(name, src, deps=None, visibility=None, test_only=False, namespace=None): + """Build rule to embed an arbitrary binary file into a C library. + + You can depend on the output of this as though it were a cc_library rule. + There are five functions available to access the data once compiled, all of which are + prefixed with the file's basename: + filename_start(): returns a const char* pointing to the beginning of the data. + filename_end(): returns a const char* pointing to the end of the data. + filename_size(): returns the length of the data in bytes. + filename_start_nc(): returns a char* pointing to the beginning of the data. + This is a convenience wrapper using const_cast, you should not + mutate the contents of the returned pointer. + filename_end(): returns a char* pointing to the end of the data. + Again, don't mutate the contents of the pointer. + You don't own the contents of any of these pointers so don't try to delete them :) + + NB. Does not work on OSX at present due to missing options in Apple's ld. + + Args: + name (str): Name of the rule. + src (str): Source file to embed. + deps (list): Dependencies. + visibility (list): Rule visibility. + test_only (bool): If True, is only available to test rules. + namespace (str): Allows specifying the namespace the symbols will be available in. + """ + if src.startswith(':') or src.startswith('/'): + deps = (deps or []) + [src] + build_rule( + name='_%s#hdr' % name, + srcs=[], + outs=[name + '.h'], + deps=deps, + cmd='; '.join([ + 'ENCODED_FILENAME=$(location %s)' % src, + 'BINARY_NAME=' + name, + 'NAMESPACE=' + (namespace or CONFIG.DEFAULT_NAMESPACE), + 'echo "%s" | sed -E -e "s/([^/ ])[/\\.-]([^/ ])/\\1_\\2/g" > $OUT' % _CC_HEADER_CONTENTS, + ]), + visibility=visibility, + building_description='Writing header...', + requires=['cc'], + test_only=test_only, + ) + build_rule( + name='_%s#lib' % name, + srcs=[src], + outs=['lib%s.a' % name], + deps=deps, + cmd='%s -r --format binary -o $OUT $SRC' % CONFIG.LD_TOOL, + visibility=visibility, + building_description='Embedding...', + requires=['cc'], + test_only=test_only, + ) + lib_rule = ':_%s#lib' % name + hdr_rule = ':_%s#hdr' % name + filegroup( + name=name, + srcs=[lib_rule, hdr_rule], + visibility=visibility, + test_only=test_only, + provides={ + 'cc_hdrs': hdr_rule, + }, + ) + + +# ar D doesn't exist on OSX :( +_AR_FLAG = '' if CONFIG.OS == 'darwin' else 'D' + + +_CC_HEADER_CONTENTS = """\ +#ifdef __cplusplus +namespace ${NAMESPACE} { +extern \\"C\\" { +#endif // __cplusplus +extern const char _binary_${ENCODED_FILENAME}_start[]; +extern const char _binary_${ENCODED_FILENAME}_end[]; +#ifdef __cplusplus +} +#endif // __cplusplus + +// Nicer aliases. +inline const char* ${BINARY_NAME}_start() { + return _binary_${ENCODED_FILENAME}_start; +} +inline const char* ${BINARY_NAME}_end() { + return _binary_${ENCODED_FILENAME}_end; +} +inline unsigned long ${BINARY_NAME}_size() { + return _binary_${ENCODED_FILENAME}_end - _binary_${ENCODED_FILENAME}_start; +} +inline char* ${BINARY_NAME}_start_nc() { + return (char*)(_binary_${ENCODED_FILENAME}_start); +} +inline char* ${BINARY_NAME}_end_nc() { + return (char*)(_binary_${ENCODED_FILENAME}_end); +} +#ifdef __cplusplus +} // namespace ${NAMESPACE} +#endif // __cplusplus +""" + + +# This is a lightweight way of building the test main, but it's awkward not +# having command line output as well as XML output. +_CC_TEST_MAIN_CONTENTS = """ +#include +#include "unittest++/UnitTest++.h" +#include "unittest++/XmlTestReporter.h" +int main(int, char const *[]) { + std::ofstream f("test.results"); + UnitTest::XmlTestReporter reporter(f); + UnitTest::TestRunner runner(reporter); + return runner.RunTestsIf(UnitTest::Test::GetTestList(), + NULL, + UnitTest::True(), + 0); +} +""" + + +# For nominal Buck compatibility. The cc_ forms are preferred. +cxx_binary = cc_binary +cxx_library = cc_library +cxx_test = cc_test + + +def _build_flags(compiler_flags, linker_flags, pkg_config_libs, pkg_config_cflags=None, binary=False): + """Builds flags that we'll pass to the compiler invocation.""" + compiler_flags = compiler_flags or [CONFIG.DEFAULT_CFLAGS] + compiler_flags.append('-fPIC') + # Linker flags may need this leading -Xlinker mabob. + linker_flags = ['-Xlinker ' + flag for flag in (linker_flags or [])] + pkg_config_cmd = ' '.join('`pkg-config --cflags --libs %s`' % x for x in pkg_config_libs or []) + pkg_config_cmd_2 = ' '.join('`pkg-config --cflags %s`' % x for x in pkg_config_cflags or []) + postamble = '`find . -name "*.o" -or -name "*.a"`' if binary else '' + return ' '.join([' '.join(compiler_flags), ' '.join(linker_flags), + pkg_config_cmd, pkg_config_cmd_2, postamble]) + + +def _apply_transitive_labels(command): + """Acquires the required linker flags from all transitive labels of a rule. + + This is how we handle libraries sensibly for C++ rules; you might write a rule that + depends on some extra library and needs a linker flag. You'd obviously like to specify + that on the cc_library rule and not on all the transitive cc_binary and cc_test targets + that use it. The solution to this is here; we collect the set of linker flags from all + dependencies and apply them to the binary rule that needs them. + """ + return lambda name: set_command(name, ' '.join([ + command, + ' '.join('-Xlinker ' + flag for flag in get_labels(name, 'cc:ld:')), + ' '.join('`pkg-config --libs %s`' % x for x in get_labels(name, 'cc:pc:')), + ])) diff --git a/src/parse/rules/go_rules.py b/src/parse/rules/go_rules.py new file mode 100644 index 0000000000..053cf639a7 --- /dev/null +++ b/src/parse/rules/go_rules.py @@ -0,0 +1,267 @@ +""" Rules to build Go code. + +Go has a strong built-in concept of packages so it's probably a good idea to match Please +rules to Go packages. +""" + +_GO_COMPILE_TOOL = 'compile' if CONFIG.GO_VERSION >= "1.5" else '6g' +_GO_LINK_TOOL = 'link' if CONFIG.GO_VERSION >= "1.5" else '6l' + +# This is the command we use to provide include directories to the Go compiler. +# It's fairly brutal but since our model is that we completely specify all the dependencies +# it's valid to essentially allow it to pick up any of them. +_SRC_DIRS_CMD = 'SRC_DIRS=`find . -type d | grep -v "^\\.$" | sed -E -e "s|^./|-I |g"`; ' + + +def go_library(name, srcs, out=None, deps=None, visibility=None, test_only=False): + """Generates a Go library which can be reused by other rules. + + Args: + name (str): Name of the rule. + srcs (list): Go source files to compile. + out (str): Name of the output library to compile (defaults to name suffixed with .a) + deps (list): Dependencies + visibility (list): Visibility specification + test_only (bool): If True, is only visible to test rules. + """ + # Copies archives up a directory; this is needed in some cases depending on whether + # the library matches the name of the directory it's in or not. + copy_cmd = 'for i in `find . -name "*.a"`; do cp $i $(dirname $(dirname $i)); done' + # Invokes the Go compiler. + compile_cmd = 'go tool %s -trimpath $TMP_DIR -complete $SRC_DIRS -I . -pack -o $OUT $SRCS' % _GO_COMPILE_TOOL + # String it all together. + cmd = '%s %s && %s' % (_SRC_DIRS_CMD, copy_cmd, compile_cmd) + + # go_test and cgo_library need access to the sources as well. + filegroup( + name='_%s#srcs' % name, + srcs=srcs, + deps=deps, + visibility=visibility, + output_is_complete=False, + requires=['go'], + test_only=test_only, + ) + + build_rule( + name=name, + srcs=srcs, + deps=(deps or []) + [':_%s#srcs' % name], + outs=[out or name + '.a'], + cmd=cmd, + visibility=visibility, + building_description="Compiling...", + requires=['go'], + provides={'go_src': ':_%s#srcs' % name}, + test_only=test_only, + ) + + +def cgo_library(name, srcs, env=None, deps=None, visibility=None, test_only=False, package=''): + """Generates a Go library which can be reused by other rules. + + Note that this is a little experimental and hasn't yet received extensive testing. + + It also has a slightly interesting approach in that it recompiles all the input + Go sources. It'd be nicer to use go tool cgo/compile, but it's excruciatingly + hard to mimic what 'go build' does well enough to actually work. + + Args: + name (str): Name of the rule. + srcs (list): Go source files to compile. + env (dict): Dict of environment variables to control the Go build. + deps (list): Dependencies + visibility (list): Visibility specification + test_only (bool): If True, is only visible to test rules. + package (str): Name of the package to output (defaults to same as name). + """ + env = env or {} + package = package or name + # TODO(pebers): Need a sensible way of working out what GOPATH should be. + env.setdefault('GOPATH', '$TMP_DIR:$TMP_DIR/third_party/go') + env_cmd = ' '.join('export %s="%s";' % (k, v) for k, v in sorted(env.items())) + cmd = ' && '.join([ + 'if [ ! -d src ]; then ln -s . src; fi', + 'go install ${PKG#*src/}', + 'mv pkg/${OS}_${ARCH}/${PKG#*src/}.a $OUT', + ]) + + filegroup( + name='_%s#srcs' % name, + srcs=srcs, + deps=deps, + visibility=visibility, + output_is_complete=False, + requires=['go'], + test_only=test_only, + ) + + build_rule( + name=name, + srcs=srcs, + deps=(deps or []) + [':_%s#srcs' % name], + outs=[package + '.a'], + cmd=env_cmd + cmd, + visibility=visibility, + building_description="Compiling...", + requires=['go', 'go_src', 'cc', 'cc_hdrs'], + provides={ + 'go': ':' + name, + 'go_src': ':_%s#srcs' % name, + }, + test_only=test_only, + needs_transitive_deps=True, + ) + + +def go_binary(name, main=None, deps=None, visibility=None, test_only=False, strip=None): + """Compiles a Go binary. + + Args: + name (str): Name of the rule. + main (str): Go source file containing the main function. + deps (list): Dependencies + visibility (list): Visibility specification + test_only (bool): If True, is only visible to test rules. + strip (bool): Controls whether to strip the final binary of symbols or not (ie. -s to go tool link). + By default it's controlled by the config setting, but can be set to True or False to + override on a per-rule basis. + """ + strip = CONFIG.GO_STRIP if strip is None else strip + copy_cmd = 'for i in `find . -name "*.a"`; do cp $i $(dirname $(dirname $i)); done' + compile_cmd = 'go tool %s -trimpath $TMP_DIR -complete $SRC_DIRS -I . -o ${OUT}.6 $SRC' % _GO_COMPILE_TOOL + link_cmd = 'go tool %s %s ${SRC_DIRS//-I/-L} -L . -o ${OUT} ${OUT}.6' % ( + _GO_LINK_TOOL, '-s' if strip else '') + cmd='%s %s && %s && %s' % (_SRC_DIRS_CMD, copy_cmd, compile_cmd, link_cmd) + build_rule( + name=name, + srcs=[main or name + '.go'], + deps=deps, + outs=[name], + cmd=cmd, + building_description="Compiling...", + needs_transitive_deps=True, + binary=True, + output_is_complete=True, + test_only=test_only, + visibility=visibility, + requires=['go'], + ) + + +def go_test(name, srcs, data=None, deps=None, visibility=None, container=False, + timeout=0, flaky=0, test_outputs=None, labels=None, tags=None): + """Defines a Go test rule. + + Note that similarly to cgo_library this requires the test sources in order to + template in the test specifications. We kind of get away with this because Go compilation + is so fast but it would be better not to - on the other hand, this also allows us + to build with coverage tracing which wouldn't be possible otherwise. + + Args: + name (str): Name of the rule. + srcs (list): Go source files to compile. + data (list): Runtime data files for the test. + deps (list): Dependencies + visibility (list): Visibility specification + container (bool | dict): True to run this test in a container. + timeout (int): Timeout in seconds to allow the test to run for. + flaky (int | bool): True to mark the test as flaky, or an integer to specify how many reruns. + test_outputs (list): Extra test output files to generate from this test. + labels (list): Labels for this rule. + tags (list): Tags to pass to go build (see 'go help build' for details). + """ + tag_cmd = '-tags "%s"' % ' '.join(tags) if tags else '' + build_rule( + name=name, + srcs=srcs, + data=data, + deps=deps, + outs=[name], + # TODO(pebers): how not to hardcode third_party/go here? + cmd='export GOPATH=${PWD}:${PWD}/third_party/go; ln -s $TMP_DIR src; go test ${PKG#*src/} %s -c -test.cover -o $OUT' % tag_cmd, + test_cmd='set -o pipefail && $(exe :%s) -test.v -test.coverprofile test.coverage | tee test.results' % name, + visibility=visibility, + container=container, + test_timeout=timeout, + flaky=flaky, + test_outputs=test_outputs, + requires=['go', 'go_src'], + labels=labels, + binary=True, + test=True, + building_description="Compiling...", + needs_transitive_deps=True, + output_is_complete=True, + ) + + +def go_get(name, get=None, outs=None, deps=None, visibility=None, patch=None, + binary=False, test_only=False, install=None, revision=None): + """Defines a dependency on a third-party Go library. + + Args: + name (str): Name of the rule + get (str): Target to get (eg. "github.com/gorilla/mux") + outs (list): Output files from the rule. Default autodetects. + deps (list): Dependencies + visibility (list): Visibility specification + patch (str): Patch file to apply + binary (bool): True if the output of the rule is a binary. + test_only (bool): If true this rule will only be visible to tests. + install (list): Allows specifying extra packages to install. Convenient in some cases where we + want to go get something with an extra subpackage. + revision (str): Git hash to check out before building. Only works for git at present, + not for other version control systems. + """ + post_build = None + if binary and outs and len(outs) != 1: + raise ValueError(name + ': Binary rules can only have a single output') + if not outs: + outs = [('bin/' + name) if binary else ('src/' + get)] + if not binary: + post_build = _extra_outs(get) + cmd = [ + 'export GOPATH=$TMP_DIR:$TMP_DIR/$PKG', + 'rm -rf pkg src', + 'go get -d ' + get, + ] + subdir = 'src/' + (get[:-4] if get.endswith('/...') else get) + if revision: + # Annoyingly -C does not work on git checkout :( + cmd.append('(cd %s && git checkout -q %s)' % (subdir, revision)) + if patch: + cmd.append('patch -s -d %s -p1 < ${TMP_DIR}/$(location %s)' % (subdir, patch)) + cmd.append('go install ' + get) + if install: + cmd.extend('go install %s' % lib for lib in install) + cmd.extend([ + 'find . -name .git | xargs rm -rf', + 'find pkg -name "*.a"', + ]) + build_rule( + name=name, + srcs=[patch] if patch else [], + outs=outs, + deps=deps, + visibility=visibility, + building_description='Fetching...', + cmd=' && '.join(cmd), + binary=binary, + requires=['go'], + test_only=test_only, + post_build=post_build, + ) + + +def _extra_outs(get): + """Attaches extra outputs to go_get rules.""" + def _inner(name, output): + last = '<>' + for archive in sorted(output): + add_out(name, archive) + subpath = archive[archive.find('/', 6) + 1:-2] + if not subpath.startswith(get) and not subpath.startswith(last): + add_out(name, 'src/' + subpath) + last = subpath + return _inner diff --git a/src/parse/rules/java_rules.py b/src/parse/rules/java_rules.py new file mode 100644 index 0000000000..4945226e67 --- /dev/null +++ b/src/parse/rules/java_rules.py @@ -0,0 +1,326 @@ +"""Built-in rules to compile Java code.""" + +# Prefixes of files to exclude when building jars. May need to be configurable. +_JAVA_EXCLUDE_FILES = ','.join(['LICENSE', 'META-INF/', 'NOTICE', 'asm-license.txt']) + +_MAVEN_CENTRAL = "https://repo1.maven.org/maven2" +_maven_packages = defaultdict(dict) + + +def java_library(name, srcs=None, resources=None, resources_root=None, deps=None, + exported_deps=None, visibility=None, source=None, target=None, test_only=False): + """Compiles Java source to a .jar which can be collected by other rules. + + Args: + name (str): Name of the rule + srcs (list): Java source files to compile for this library + resources (list): Resources to include in the .jar file + resources_root (str): Root directory to treat resources relative to; ie. if we are in + //project/main/resources and resources_root is project/main then + the resources in the .jar will be in the subdirectory 'resources'. + deps (list): Dependencies of this rule. + exported_deps (list): Exported dependencies, ie. dependencies that other things depending on this + rule will also receive when they're compiling. This is quite important for + Java; any dependency that forms part of the public API for your classes + should be an exported dependency. + visibility (list): Visibility declaration of this rule. + source (int): Java source level to compile sources as. Defaults to whatever's set in the config, + which itself defaults to 8. + target (int): Java bytecode level to target after compile. Defaults to whatever's set in the + config, which itself defaults to 8. + test_only (bool): If True, this rule can only be depended on by tests. + """ + all_srcs = (srcs or []) + (resources or []) + if srcs: + build_rule( + name=name, + srcs=all_srcs, + deps=deps, + exported_deps=exported_deps, + outs=[name + '.jar'], + visibility=visibility, + cmd=' && '.join([ + 'mkdir _tmp _tmp/META-INF', + '%s -encoding utf8 -source %s -target %s -classpath .:%s -d _tmp -g %s' % ( + CONFIG.JAVAC_TOOL, + source or CONFIG.JAVA_SOURCE_LEVEL, + target or CONFIG.JAVA_TARGET_LEVEL, + r'`find . -name "*.jar" ! -name "*src.jar" | tr \\\\n :`', + ' '.join('$(locations %s)' % src for src in srcs) + ), + 'mv ${PKG}/%s/* _tmp' % resources_root if resources_root else 'true', + 'find _tmp -name "*.class" | sed -e "s|_tmp/|${PKG} |g" -e "s/\\.class/.java/g" > _tmp/META-INF/please_sourcemap', + CONFIG.JAR_TOOL + ' cfM $OUT -C _tmp .', + ]), + building_description="Compiling...", + requires=['java'], + test_only=test_only, + ) + elif resources: + # Can't run javac since there are no java files. + if resources_root: + cmd = 'cd ${PKG}/%s && %s -cfM ${OUT} .' % (resources_root, CONFIG.JAR_TOOL) + else: + cmd = '%s -cfM ${OUT} ${PKG}' % CONFIG.JAR_TOOL + build_rule( + name=name, + srcs=all_srcs, + deps=deps, + exported_deps=exported_deps, + outs=[name + '.jar'], + visibility=visibility, + cmd=cmd, + building_description="Linking...", + requires=['java'], + test_only=test_only, + ) + else: + # If input is only jar files (as maven_jar produces in some cases) we simply collect them + # all up for other rules to use. + filegroup( + name=name, + deps=deps, + exported_deps=exported_deps, + visibility=visibility, + output_is_complete=False, + requires=['java'], + test_only=test_only, + ) + + +def java_binary(name, main_class, deps=None, data=None, visibility=None, jvm_args=None, + self_executable=False): + """Compiles a .jar from a set of Java libraries. + + Args: + name (str): Name of the rule. + main_class (str): Main class to set in the manifest. + deps (list): Dependencies of this rule. + data (list): Runtime data files for this rule. + visibility (list): Visibility declaration of this rule. + jvm_args (str): Arguments to pass to the JVM in the run script. + self_executable (bool): True to make the jar self executable. + """ + if self_executable: + cmd, tools = _java_binary_cmd(main_class, jvm_args) + else: + # This is essentially a hack to get past some Java things (notably Jersey) failing + # in subtle ways when the jar has a preamble (srsly...). + jarcat_tool, tools = _tool_path(CONFIG.JARCAT_TOOL) + cmd = '%s -i . -o ${OUTS} --exclude_internal_prefix "%s" -m "%s"' % ( + jarcat_tool, _JAVA_EXCLUDE_FILES, main_class) + build_rule( + name=name, + deps=deps, + data=data, + outs=[name + '.jar'], + cmd=cmd, + needs_transitive_deps=True, + output_is_complete=True, + binary=True, + building_description="Creating jar...", + requires=['java'], + visibility=visibility, + tools=tools, + ) + + +def java_test(name, srcs, data=None, deps=None, labels=None, visibility=None, + container=False, timeout=0, flaky=0, test_outputs=None, + test_package=CONFIG.DEFAULT_TEST_PACKAGE, jvm_args=''): + """Defines a Java test. + + Args: + name (str): Name of the rule. + srcs (list): Java files containing the tests. + data (list): Runtime data files for this rule. + deps (list): Dependencies of this rule. + labels (list): Labels to attach to this test. + visibility (list): Visibility declaration of this rule. + container (bool | dict): True to run this test within a container (eg. Docker). + timeout (int): Maximum length of time, in seconds, to allow this test to run for. + flaky (int | bool): True to mark this as flaky and automatically rerun. + test_outputs (list): Extra test output files to generate from this test. + test_package (str): Java package to scan for test classes to run. + jvm_args (str): Arguments to pass to the JVM in the run script. + """ + # It's a bit sucky doing this in two separate steps, but it is + # at least easy and reuses the existing code. + java_library( + name='_%s#lib' % name, + srcs=srcs, + deps=deps, + test_only=True, + # Deliberately not visible outside this package. + ) + # As above, would be nicer if we could make the jars self-executing again. + jarcat_tool, tools = _tool_path(CONFIG.JARCAT_TOOL) + junit_runner, tools = _tool_path(CONFIG.JUNIT_RUNNER, tools) + main_class = 'net.thoughtmachine.please.test.TestMain' + cmd = 'ln -s %s . && %s -i . -o ${OUTS} --exclude_internal_prefix "%s" -m "%s"' % ( + junit_runner, jarcat_tool, _JAVA_EXCLUDE_FILES, main_class) + test_cmd = 'java -Dnet.thoughtmachine.please.testpackage=%s %s -jar $(location :%s) ' % ( + test_package, jvm_args, name) + build_rule( + name=name, + cmd=cmd, + test_cmd=test_cmd, + data=data, + outs=[name + '.jar'], + deps=[':_%s#lib' % name], + visibility=visibility, + container=container, + labels=labels, + test_timeout=timeout, + flaky=flaky, + test_outputs=test_outputs, + requires=['java'], + needs_transitive_deps=True, + output_is_complete=True, + test=True, + binary=True, + building_description="Creating jar...", + tools=tools, + ) + + +def maven_jars(name, id, repository=_MAVEN_CENTRAL, exclude=None, hashes=None, + deps=None, visibility=None, filename=None, deps_only=False): + """Fetches a transitive set of dependencies from Maven. + + Requires post build commands to be allowed for this repo. + + Note that this is still fairly experimental; the interface is unlikely to change much + but it still has issues with some Maven packages. + + Args: + name (str): Name of the output rule. + id (str): Maven id of the artifact (eg. org.junit:junit:4.1.0) + repository (str): Maven repo to fetch deps from. + exclude (list): Dependencies to ignore when fetching this one. + hashes (dict): Map of Maven id -> rule hash for each rule produced. + deps (list): Labels of dependencies, as usual. + visibility (list): Visibility label. + filename (str): Filename we attempt to download. Defaults to standard Maven name. + deps_only (bool): If True we fetch only dependent rules, not this one itself. Useful for some that + have a top-level target as a facade which doesn't have actual code. + """ + existing_packages = _maven_packages[get_base_path()] + exclude = exclude or [] + + def create_maven_deps(_, output): + for line in output: + if not line: + continue + try: + group, artifact, version, licences = line.split(':') + except ValueError: + group, artifact, version = line.split(':') + licences = None + if artifact in exclude: + continue + # Deduplicate packages + existing = existing_packages.get(artifact) + if existing: + if existing != line: + raise ValueError('Package version clash in maven_jars: got %s, but already have %s' % (line, existing)) + else: + maven_jar( + name=artifact, + id=line, + repository=repository, + hash=None if hashes is None else hashes.get(id, hashes.get(artifact, '')), + licences=licences.split('|') if licences else None, + # We deliberately don't make this rule visible externally. + ) + add_exported_dep(name, ':' + artifact) + + deps = deps or [] + exclusions = ' '.join('-e ' + excl for excl in exclude) + please_maven_tool, tools = _tool_path(CONFIG.PLEASE_MAVEN_TOOL) + build_rule( + name='_%s#deps' % name, + cmd='%s -r %s %s %s' % (please_maven_tool, repository, id, exclusions), + post_build=create_maven_deps, + building_description='Finding dependencies...', + tools=tools, + + ) + if not deps_only: + maven_jar( + name=name, + id=id, + repository=repository, + hash=None if hashes is None else hashes.get(id, hashes.get(name, '')), + deps = deps + [':_%s#deps' % name], + visibility=visibility, + filename=filename, + ) + else: + build_rule( + name=name, + deps=[':_%s#deps' % name], + exported_deps=deps, + cmd='true', # do nothing! + visibility=visibility, + ) + + +def maven_jar(name, id, repository=_MAVEN_CENTRAL, hash=None, deps=None, + visibility=None, filename=None, sources=True, licences=None): + """Fetches a single Java dependency from Maven. + + Args: + name (str): Name of the output rule. + id (str): Maven id of the artifact (eg. org.junit:junit:4.1.0) + repository (str): Maven repo to fetch deps from. + hash (str): Hash for produced rule. + deps (list): Labels of dependencies, as usual. + visibility (list): Visibility label. + filename (str): Filename we attempt to download. Defaults to standard Maven name. + sources (bool): True to download source jars as well. + licences (list): Licences this package is subject to. + """ + _maven_packages[get_base_path()][name] = id + # TODO(pebers): Handle exclusions, packages with no source available and packages with no version. + try: + group, artifact, version = id.split(':') + except ValueError: + group, artifact, version, licence = id.split(':') + if licence and not licences: + licences = licence.split('|') + filename = filename or '%s-%s.jar' % (artifact, version) + bin_url = '/'.join([ + repository, + group.replace('.', '/'), + artifact, + version, + filename or '%s-%s.jar' % (artifact, version), + ]) + src_url = bin_url.replace('.jar', '-sources.jar') # is this always predictable? + outs = [name + '.jar'] + cmd = 'echo "Fetching %s..." && curl -f %s -o %s' % (bin_url, bin_url, outs[0]) + if sources: + outs.append(name + '_src.jar') + cmd += ' && echo "Fetching %s..." && curl -f %s -o %s' % (src_url, src_url, outs[1]) + build_rule( + name=name, + outs=outs, + cmd=cmd, + hashes=[hash] if hash else None, + licences=licences, + exported_deps=deps, # easiest to assume these are always exported. + visibility=visibility, + building_description='Fetching...', + ) + + +def _java_binary_cmd(main_class, jvm_args, test_package=None): + """Returns the command we use to build a .jar for a java_binary or a java_test.""" + jarcat_tool, tools = _tool_path(CONFIG.JARCAT_TOOL) + junit_runner, toolss = _tool_path(CONFIG.JUNIT_RUNNER, tools) + prop = '-Dnet.thoughtmachine.please.testpackage=' + test_package if test_package else '' + preamble = '#!/bin/sh\nexec java %s %s -jar $0 $@' % (prop, jvm_args or '') + cmd = '%s -i . -o ${OUTS} --exclude_internal_prefix "%s" -p \'%s\' -m "%s"' % ( + jarcat_tool, _JAVA_EXCLUDE_FILES, preamble, main_class) + return ('ln -s %s . && %s' % (junit_runner, cmd) if test_package else cmd), tools diff --git a/src/parse/rules/misc_rules.py b/src/parse/rules/misc_rules.py new file mode 100644 index 0000000000..6b61780c2e --- /dev/null +++ b/src/parse/rules/misc_rules.py @@ -0,0 +1,395 @@ +"""Miscellaneous rules that aren't language-specific.""" + + +def genrule(name, cmd, srcs=None, out=None, outs=None, deps=None, visibility=None, + building_description='Building...', hashes=None, timeout=0, binary=False, + needs_transitive_deps=False, output_is_complete=True, test_only=False, + requires=None, provides=None, pre_build=None, post_build=None, tools=None): + """A general build rule which allows the user to specify a command. + + Args: + name (str): Name of the rule + cmd (str): Command to run. It's subject to various sequence replacements: + $(location //path/to:target) expands to the location of the given build rule, which + must have a single output only. + $(locations //path/to:target) expands to the locations of the outputs of the given + build rule, which can have any number of outputs. + $(exe //path/to:target) expands to a command to run the output of the given target. + The rule must be marked as binary. + $(out_location //path_to:target) expands to the output of the given build rule, with + the preceding plz-out/gen etc. + Also a number of environment variables will be defined: + ARCH: architecture of the system, eg. amd64 + OS: current operating system (linux, darwin, etc). + PATH: usual PATH environment variable as defined in your .plzconfig + TMP_DIR: the temporary directory you're compiling within. + SRCS: the sources of your rule + OUTS: the outputs of your rule + PKG: the path to the package containing this rule + NAME: the name of this build rule + OUT: the output of this rule. Only present when there is only one output. + SRC: the source of this rule. Only present when there is only one source. + SRCS_: Present when you've defined named sources on a rule. Each group + creates one of these these variables with paths to those sources. + srcs (list): Sources of this rule. Can be a list of files or rules, or a dict of names to similar + lists. In the latter case they can be accessed separately which is useful when you + have separate kinds of things in a rule. + outs (list): Outputs of this rule. + out (str): A single output of this rule, as a string. Discouraged in favour of 'outs'. + deps (list): Dependencies of this rule. + tools (list): Tools used to build this rule; similar to srcs but are not copied to the temporary + build directory. Should be accessed via $(exe //path/to:tool) or similar. + visibility (list): Visibility declaration of this rule + building_description (str): Description to display to the user while the rule is building. + hashes (list): List of hashes; if given the outputs must match one of these. They can be + optionally preceded by their method. Currently the only supported method is sha1. + timeout (int): Maximum time in seconds this rule can run for before being killed. + binary (bool): True to mark a rule that produces a runnable output. Its output will be placed into + plz-out/bin instead of plz-out/gen and can be run with 'plz run'. Binary rules + can only have a single output. + needs_transitive_deps (bool): If True, all transitive dependencies of the rule will be made + available to it when it builds (although see below...). By default + rules only get their immediate dependencies. + output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive + dependencies by other rules (ie. it will be available to them, but not + its dependencies as well). + test_only (bool): If True it can only be used by test rules. + requires (list): A list of arbitrary strings that define kinds of output that this rule might want. + See 'provides' for more detail; it's mostly useful to match up rules with multiple + kinds of output with ones that only need one of them, eg. a proto_library with + a python_library that doesn't want the C++ or Java proto outputs. + Entries in 'requires' are also implicitly labels on the rule. + provides (dict): A map of arbitrary strings to dependencies of the rule that provide some specific + type of thing. For example: + provides = {'py': ':python_rule', 'go': ':go_rule'}, + A Python rule would have requires = ['py'] and so if it depended on a rule like + this it would pick up a dependency on :python_rule instead. See the proto rules + for an example of where this is useful. + Note that the keys of provides and entries in requires are arbitrary and + have no effect until a matched pair meet one another. + pre_build (function): A function to be executed immediately before the rule builds. It receives one + argument, the name of the building rule. This is mostly useful to interrogate + the metadata of dependent rules which isn't generally available at parse time; + see the get_labels function for a motivating example. + post_build (function): A function to be executed immediately after the rule builds. It receives two + arguments, the rule name and its command line output. + This is significantly more useful than the pre_build function, it can be used + to dynamically create new rules based on the output of another. + """ + if out and outs: + raise TypeError('Can\'t specify both "out" and "outs".') + build_rule( + name=name, + srcs=srcs, + outs=[out] if out else outs, + cmd=cmd, + deps=deps, + tools=tools, + visibility = visibility, + output_is_complete=output_is_complete, + building_description=building_description, + hashes=hashes, + post_build=post_build, + binary=binary, + build_timeout=timeout, + needs_transitive_deps=needs_transitive_deps, + requires=requires, + provides=provides, + test_only=test_only, + ) + + +def gentest(name, test_cmd, labels=None, cmd=None, srcs=None, outs=None, deps=None, + data=None, visibility=None, timeout=0, needs_transitive_deps=False, flaky=0, + no_test_output=False, output_is_complete=True, requires=None, container=False): + """A rule which creates a test with an arbitrary command. + + The command must return zero on success and nonzero on failure. Test results are written + to test.results (or not if no_test_output is True). + Most arguments are similar to genrule() so we cover them in less detail here. + + Args: + name (str): Name of the rule + test_cmd (str): Command to run for the test. + labels (list): Labels to apply to this test. + cmd (str): Command to run to build the test. + srcs (list): Source files for this rule. + outs (list): Output files of this rule. + deps (list): Dependencies of this rule. + data (list): Runtime data files for the test. + visibility (list): Visibility declaration of this rule. + timeout (int): Length of time in seconds to allow the test to run for before killing it. + needs_transitive_deps (bool): True if building the rule requires all transitive dependencies to + be made available. + flaky (bool | int): If true the test will be marked as flaky and automatically retried. + no_test_output (bool): If true the test is not expected to write any output results, it's only + judged on its return value. + output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive + dependencies by other rules. + requires (list): Kinds of output from other rules that this one requires. + container (bool | dict): If true the test is run in a container (eg. Docker). + """ + build_rule( + name=name, + srcs=srcs, + outs=outs, + deps=deps, + data=data, + test_cmd = test_cmd, + cmd=cmd or 'true', # By default, do nothing + visibility=visibility, + output_is_complete=output_is_complete, + labels=labels, + binary=True, + test=True, + test_timeout=timeout, + needs_transitive_deps=needs_transitive_deps, + requires=requires, + container=container, + no_test_output=no_test_output, + flaky=flaky, + ) + + +def export_file(name, src, visibility=None, binary=False, test_only=False): + """Essentially a single-file alias for filegroup. + + Args: + name (str): Name of the rule + src (str): Source file for the rule + visibility (list): Visibility declaration + binary (bool): True to mark the rule outputs as binary + test_only (bool): If true the exported file can only be used by test targets. + """ + filegroup( + name = name, + srcs = [src], + visibility = visibility, + binary = binary, + test_only = test_only, + ) + + +def filegroup(name, srcs=None, deps=None, exported_deps=None, visibility=None, labels=None, binary=False, + output_is_complete=True, requires=None, provides=None, link=True, test_only=False): + """Defines a collection of files which other rules can depend on. + + Sources can be omitted entirely in which case it acts simply as a rule to collect other rules, + which is often more handy than you might think. + + Args: + name (str): Name of the rule + srcs (list): Source files for the rule. + deps (list): Dependencies of the rule. + exported_deps (list): Dependencies that will become visible to any rules that depend on this rule. + visibility (list): Visibility declaration + labels (list): Labels to apply to this rule + binary (bool): True to mark the rule outputs as binary + output_is_complete (bool): If this is true then the rule blocks downwards searches of transitive + dependencies by other rules. + requires (list): Kinds of output from other rules that this one requires. + provides (dict): Kinds of output that this provides for other rules (see genrule() for a more + in-depth discussion of this). + test_only (bool): If true the exported file can only be used by test targets. + """ + cmd = 'true' # Nothing to do if we only have deps. + if srcs: + not_root = bool(get_base_path()) + locations = ' '.join('$(location_pairs %s)' % src for src in srcs + if not_root or src.startswith(':') or src.startswith('/')) + if locations: + cmd = 'echo %s | xargs -n 2 %s' % (locations, 'ln -s' if link else 'cp -r') + build_rule( + name=name, + srcs=srcs, + deps=deps, + exported_deps=exported_deps, + outs=srcs, + cmd=cmd, + visibility=visibility, + building_description='Symlinking...' if link else 'Copying...', + # This fixes some issues; I think it's reasonable that the outputs of filegroups + # are treated just as files without any transitive deps. + output_is_complete=output_is_complete, + # This just symlinks its inputs so it's faster not to copy to the cache and back, + # especially if the files it's collecting are large. + skip_cache=link, + requires=requires, + provides=provides, + test_only=test_only, + labels=labels, + binary=binary, + ) + + +def remote_file(name, url, hashes, out=None, binary=False, visibility=None, test_only=False): + """Defines a rule to fetch a file over HTTP(S). + + Args: + name (str): Name of the rule + url (str): URL to fetch + hashes (list): List of hashes; the output must match at least one of these. This is required + because the remote file must not change, otherwise it'd introduce fundamental + indeterminacy into the build. + out (str): Output name of the file. Chosen automatically if not given. + binary (bool): True to mark the output as binary and runnable. + visibility (list): Visibility declaration of the rule. + test_only (bool): If true the rule is only visible to test targets. + """ + cmd = 'curl %s -o %s' % (url, out) if out else 'curl %s -O' % url + # TODO(pebers): maybe plz should automatically do this on binary outputs? + if binary: + cmd += ' && chmod +x $OUT' + build_rule( + name=name, + cmd=cmd, + outs=[out or url[url.rfind('/') + 1:]], + binary=binary, + visibility=visibility, + hashes=hashes, + building_description='Fetching...', + ) + + +def fpm_package(name, files, version, package_type, links=None, package_name=None, options='', + srcs=None, deps=None, visibility=None, labels=None): + """Defines a rule to build a package using fpm. + + Args: + name (str): Rule name + files (dict): Dict of locations -> files to include, for example: + { + '/usr/bin/plz': '//src:please', + '/usr/share/plz/junit_runner': '//src/build/java:junit_runner', + '/usr/share/plz/some_file': 'some_file', # file in this package + } + links (dict): Dict of locations -> file to link to, for example: + { + '/usr/bin/plz': '/opt/please', + } + version (str): Version of the package. + package_type (str): Type of package to build (deb, rpm, etc) + package_name (str): Name of package. Defaults to rule name. + options (str): Extra options to pass to fpm. + srcs (list): Extra sources (it's not necessary to mention entries in 'files' here) + deps (list): Dependencies + visibility (list): Visibility specification. + labels (list): Labels associated with this rule. + """ + package_name = package_name or name + cmd = ' && '.join('mkdir -p $(dirname %s) && cp -r ../$(location %s) %s' % + (k.lstrip('/'), v, k.lstrip('/')) for k, v in sorted(files.items())) + if links: + cmd += ' && ' + ' && '.join('mkdir -p $(dirname %s) && ln -s %s %s' % + (k.lstrip('/'), v, k.lstrip('/')) for k, v in sorted(links.items())) + cmd = 'mkdir _tmp && cd _tmp && %s && fpm -s dir -t %s -n "%s" -v "%s" %s -p $OUT .' % ( + cmd, package_type, package_name, version, options) + build_rule( + name=name, + srcs=sorted(files.values()) + (srcs or []), + outs=['%s_%s_%s.deb' % (package_name, version, CONFIG.ARCH)], + cmd=cmd, + deps=deps, + visibility=visibility, + building_description='Packaging...', + requires=['fpm'], + ) + + +def fpm_deb(name, files, version, links=None, package_name=None, options='', + srcs=None, deps=None, visibility=None, labels=None): + """Convenience wrapper around fpm_package that always builds a .deb package. + + Args: + name (str): Rule name + files (dict): Dict of locations -> files to include, for example: + { + '/usr/bin/plz': '//src:please', + '/usr/share/plz/junit_runner': '//src/build/java:junit_runner', + '/usr/share/plz/some_file': 'some_file', # file in this package + } + links (dict): Dict of locations -> file to link to, for example: + { + '/usr/bin/plz': '/opt/please', + } + version (str): Version of the package. + package_name (str): Name of package. Defaults to rule name. + options (str): Extra options to pass to fpm. + srcs (list): Extra sources (it's not necessary to mention entries in 'files' here) + deps (list): Dependencies + visibility (list): Visibility specification. + labels (list): Labels associated with this rule. + """ + fpm_package( + name=name, + files=files, + version=version, + package_type='deb', + links=links, + package_name=package_name, + options=options, + srcs=srcs, + deps=deps, + visibility=visibility, + labels=labels, + ) + + +def tarball(name, srcs, out=None, deps=None, subdir=None, + compression='gzip', visibility=None, labels=None): + """Defines a rule to create a tarball containing outputs of other rules. + + Args: + name: Rule name + srcs: Source files to include in the tarball + out: Name of output tarball (defaults to `name`.tar.gz, but see below re compression) + subdir: Subdirectory to create in (defaults to 'name') + compression: Kind of compression to use. Either one of {gzip, bzip2, xz, lzma} + to filter through known tar methods, an explicit flag, or None for + no compression. + deps: Dependencies + visibility: Visibility specification. + labels: Labels associated with this rule. + """ + subdir = subdir or name + locations = ' '.join('$(location_pairs %s)' % src for src in srcs) + if compression is not None and compression.startswith('-'): + if not out: + raise ValueError('Must pass "out" argument to tarball() if you pass an ' + 'explicit flag for "compression"') + else: + compression, extension = _COMPRESSION.get(compression, ('-a', '')) + build_rule( + name=name, + cmd=' && '.join([ + 'mkdir -p _tmp/' + subdir, + 'cd _tmp/' + subdir, + 'echo %s | xargs -n 2 cp -r' % locations, + 'cd ${TMP_DIR}/_tmp', + 'tar %s -cf $OUT *' % compression, + ]), + srcs=srcs, + outs=[out or name + '.tar' + extension], + deps=deps, + visibility=visibility, + labels=(labels or []) + ['tar'], + ) + + +_COMPRESSION = { + 'gzip': ('-z', '.gz'), + 'bzip2': ('-j', '.bz2'), + 'xz': ('-J', '.xz'), + 'lzma': ('--lzma', '.lzma'), + 'compress': ('-Z', '.Z'), +} + + +def _tool_path(tool, tools=None): + """Returns the invocation of a tool and the list of tools for a rule to depend on. + + Used for tools like pex_tool and jarcat_tool which might be repo rules or just filesystem paths. + """ + if tool.startswith('//'): + return '$(exe %s)' % tool, [tool] + (tools or []) + return tool, tools diff --git a/src/parse/rules/please_parser.py b/src/parse/rules/please_parser.py new file mode 100644 index 0000000000..6d1813d964 --- /dev/null +++ b/src/parse/rules/please_parser.py @@ -0,0 +1,447 @@ +# Wrapper script invoked from Please to parse build files. + +import __builtin__ +import ast +import imp +import os +from cffi import FFI +from collections import defaultdict, Mapping +from contextlib import contextmanager +from types import FunctionType + + +ffi = FFI() + +ffi.cdef(""" +typedef unsigned char uint8; +typedef long long int64; +typedef char* (ParseFileCallback)(const char*, const char*, void*); +typedef void* (AddTargetCallback)(void*, char*, char*, char*, uint8, uint8, uint8, uint8, uint8, uint8, uint8, uint8, int64, int64, int64, char*); +typedef void (AddStringCallback)(void*, char*); +typedef void (AddTwoStringsCallback)(void*, char*, char*); +typedef void (AddDependencyCallback)(void*, char*, char*, uint8); +typedef void (AddOutputCallback)(void*, char*, char*); +typedef char** (GlobCallback)(char*, char**, long long, char**, long long, uint8); +typedef char* (GetIncludeFileCallback)(void*, char*); +typedef char** (GetLabelsCallback)(void*, char*, char*); +typedef void (SetConfigValueCallback)(char*, char*); +typedef char* (PreBuildCallbackRunner)(void*, void*, char*); +typedef char* (PostBuildCallbackRunner)(void*, void*, char*, char*); +// We're not going to call this SetBuildCallbackCallback because we're not peasants. +typedef void (SetBuildFunctionCallback)(void*, char*, void*); +typedef void (LogCallback)(int64, void*, char*); + +typedef struct _PleaseCallbacks { + ParseFileCallback* parse_file; + ParseFileCallback* parse_code; + AddTargetCallback* add_target; + AddStringCallback* add_src; + AddStringCallback* add_data; + AddStringCallback* add_dep; + AddStringCallback* add_exported_dep; + AddStringCallback* add_tool; + AddStringCallback* add_out; + AddStringCallback* add_vis; + AddStringCallback* add_label; + AddStringCallback* add_hash; + AddStringCallback* add_licence; + AddStringCallback* add_test_output; + AddStringCallback* add_require; + AddTwoStringsCallback* add_provide; + AddTwoStringsCallback* add_named_src; + AddTwoStringsCallback* set_container_setting; + GlobCallback* glob; + GetIncludeFileCallback* get_include_file; + GetIncludeFileCallback* get_subinclude_file; + GetLabelsCallback* get_labels; + SetBuildFunctionCallback* set_pre_build_callback; + SetBuildFunctionCallback* set_post_build_callback; + AddDependencyCallback* add_dependency; + AddOutputCallback* add_output; + AddTwoStringsCallback* add_licence_post; + AddTwoStringsCallback* set_command; + SetConfigValueCallback* set_config_value; + PreBuildCallbackRunner* pre_build_callback_runner; + PostBuildCallbackRunner* post_build_callback_runner; + LogCallback* log; +} PleaseCallbacks; +""") + +_please_builtins = imp.new_module('_please_builtins') +_please_globals = _please_builtins.__dict__ +_keepalive_functions = set() +_build_code_cache = {} + +# List of everything we keep in the __builtin__ module. This is a pretty agricultural way +# of restricting what build files can do - no doubt there'd be clever ways of working +# around it - but at least it will give people the sense that they shouldn't use some of these. +# We also implicitly keep all the exception types. +_WHITELISTED_BUILTINS = { + 'None', 'False', 'True', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', + 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'complex', 'delattr', 'dict', 'dir', + 'divmod', 'enumerate', 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', + 'hasattr', 'hash', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', + 'len', 'list', 'locals', 'long', 'map', 'max', 'min', 'next', 'object', 'oct', 'ord', + 'bytearray', 'pow', 'print', 'property', 'range', 'reduce', 'repr', 'reversed', 'round', + 'sequenceiterator', 'set', 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', + 'super', 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip', '__name__', + 'NotImplemented', + 'compile', '__import__', # We disallow importing separately, it's too hard to do here +} + +# Used to indicate that parsing of a target is deferred because it requires another target. +_DEFER_PARSE = '_DEFER_' +_FFI_DEFER_PARSE = ffi.new('char[]', _DEFER_PARSE) + + +@ffi.callback('char* (const char*, const char*, void*)') +def parse_file(c_filename, c_package_name, c_package): + try: + filename = ffi.string(c_filename) + package_name = ffi.string(c_package_name) + builtins = _get_globals(c_package, c_package_name) + _parse_build_code(filename, builtins) + return ffi.cast('char*', 0) + except DeferParse as err: + return _FFI_DEFER_PARSE + except Exception as err: + return ffi.new('char[]', str(err)) + + +@ffi.callback('char* (const char*, const char*, void*)') +def parse_code(c_code, c_filename, _): + try: + code = ffi.string(c_code) + filename = ffi.string(c_filename) + # Note we don't go through _parse_build_code - there's no need to perform the ast + # walk on code that we control internally. This conceptually means that we *could* + # import in those files, but we will not do that because it would be sheer peasantry. + code = _compile(code, filename, 'exec') + exec(code, _please_globals) + return ffi.cast('char*', 0) + except Exception as err: + return ffi.new('char[]', str(err)) + + +def _parse_build_code(filename, globals_dict, cache=False): + """Parses given file and interprets it. Optionally caches code for future reuse.""" + code = _build_code_cache.get(filename) + if not code: + with _open(filename) as f: + tree = ast.parse(f.read(), filename) + for node in ast.iter_child_nodes(tree): + if isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom): + raise SyntaxError('import not allowed') + if isinstance(node, ast.Exec): + raise SyntaxError('exec not allowed') + if isinstance(node, ast.Print): + raise SyntaxError('print not allowed, use log functions instead') + code = _compile(tree, filename, 'exec') + _build_code_cache[filename] = code + exec(code, globals_dict) + + +@ffi.callback('void (const char*, const char*)') +def set_config_value(c_name, c_value): + name = ffi.string(c_name) + value = ffi.string(c_value) + config = _please_globals['CONFIG'] + existing = config.get(name) + # A little gentle hack to make it convenient to set repeated config values; we could + # do it via another callback but we already have so many of them... + if isinstance(existing, list): + existing.append(value) + elif existing: + config[name] = [existing, value] + else: + config[name] = value + + +def include_defs(package, dct, target): + filename = ffi.string(_get_include_file(package, ffi.new('char[]', target))) + _parse_build_code(filename, dct, cache=True) + + +def subinclude(package, dct, target): + """Includes the output of a build target as extra rules in this one.""" + filename = ffi.string(_get_subinclude_file(package, ffi.new('char[]', target))) + if filename == _DEFER_PARSE: + raise DeferParse(filename) + with _open(filename) as f: + code = _compile(f.read(), filename, 'exec') + exec(code, dct) + + +def build_rule(globals_dict, package, name, cmd, test_cmd=None, srcs=None, data=None, outs=None, + deps=None, exported_deps=None, tools=None, labels=None, visibility=None, hashes=None, + binary=False, test=False, test_only=False, building_description='Building...', + needs_transitive_deps=False, output_is_complete=False, container=False, + skip_cache=False, no_test_output=False, flaky=0, build_timeout=0, test_timeout=0, + pre_build=None, post_build=None, requires=None, provides=None, licences=None, + test_outputs=None): + if name == 'all': + raise ValueError('"all" is a reserved build target name.') + if '/' in name or ':' in name: + raise ValueError(': and / are reserved characters in build target names') + if container and not test: + raise ValueError('Only tests can have container=True') + if visibility is None: + visibility = globals_dict['CONFIG'].get('DEFAULT_VISIBILITY') + if licences is None: + licences = globals_dict['CONFIG'].get('DEFAULT_LICENCES') + ffi_string = lambda x: ffi.cast('char*', 0) if x is None else ffi.new('char[]', x) + target = _add_target(package, + ffi_string(name), + ffi_string(cmd), + ffi_string(test_cmd), + binary, + test, + needs_transitive_deps, + output_is_complete, + bool(container), + no_test_output, + skip_cache, + test_only or test, # Tests are implicitly test_only + 3 if flaky is True else flaky, # Default is to rerun three times. + build_timeout, + test_timeout, + ffi_string(building_description)) + if flaky: + labels = labels or [] + if 'flaky' not in labels: + labels.append('flaky') + if isinstance(srcs, Mapping): + for name, src_list in srcs.iteritems(): + if src_list: + for src in src_list: + _add_named_src(target, name, src) + else: + _add_strings(target, _add_src, srcs, 'srcs') + _add_strings(target, _add_data, data, 'data') + _add_strings(target, _add_dep, deps, 'deps') + _add_strings(target, _add_exported_dep, exported_deps, 'exported_deps') + _add_strings(target, _add_tool, tools, 'tools') + _add_strings(target, _add_out, outs, 'outs') + _add_strings(target, _add_vis, visibility, 'visibility') + _add_strings(target, _add_label, labels, 'labels') + _add_strings(target, _add_hash, hashes, 'hashes') + _add_strings(target, _add_licence, licences, 'licences') + _add_strings(target, _add_test_output, test_outputs, 'test_outputs') + _add_strings(target, _add_require, requires, 'requires') + if provides: + if not isinstance(provides, Mapping): + raise ValueError('"provides" argument for rule %s is not a mapping' % name) + for lang, rule in provides.items(): + _add_provide(target, ffi.new('char[]', lang), ffi.new('char[]', rule)) + if pre_build: + # Must manually ensure we keep these objects from being gc'd. + handle = ffi.new_handle(pre_build) + _keepalive_functions.add(pre_build) + _keepalive_functions.add(handle) + _set_pre_build_callback(handle, pre_build.__code__.co_code, target) + if post_build: + handle = ffi.new_handle(post_build) + _keepalive_functions.add(post_build) + _keepalive_functions.add(handle) + _set_post_build_callback(handle, post_build.__code__.co_code, target) + if isinstance(container, dict): + for k, v in container.items(): + _set_container_setting(target, k, v) + + +@ffi.callback('char* (void*, void*, char*)') +def run_pre_build_function(handle, package, name): + try: + callback = ffi.from_handle(handle) + callback(ffi.string(name)) + return ffi.cast('char*', 0) + except DeferParse: + return ffi.new('char[]', "Don't try to subinclude() from inside a pre-build function") + except Exception as err: + return ffi.new('char[]', str(err)) + + +@ffi.callback('char* (void*, void*, char*, char*)') +def run_post_build_function(handle, package, name, output): + try: + callback = ffi.from_handle(handle) + callback(ffi.string(name), ffi.string(output).strip().split('\n')) + return ffi.cast('char*', 0) + except DeferParse: + return ffi.new('char[]', "Don't try to subinclude() from inside a post-build function") + except Exception as err: + return ffi.new('char[]', str(err)) + + +def _add_strings(target, func, lst, name): + if lst: + if isinstance(lst, str): + # We don't want to enforce this is a list (any sequence should be fine) but it's + # easy to use a string by mistake, which tends to cause some weird cffi errors later. + raise ValueError('"%s" argument should be a list of strings, not a string' % name) + for x in lst: + func(target, ffi.new('char[]', x)) + + +def glob(package, includes, excludes=None, hidden=False): + includes_keepalive = [ffi.new('char[]', include) for include in includes] + excludes_keepalive = [ffi.new('char[]', exclude) for exclude in excludes or []] + filenames = _glob(ffi.new('char[]', package), + ffi.new('char*[]', includes_keepalive), + len(includes_keepalive), + ffi.new('char*[]', excludes_keepalive), + len(excludes_keepalive), + hidden) + return [ffi.string(filename) for filename in _null_terminated_array(filenames)] + + +def get_labels(package, target, prefix): + """Gets the transitive set of labels for a rule. Should be called from a pre-build function.""" + labels = _get_labels(package, ffi.new('char[]', target), ffi.new('char[]', prefix)) + return [ffi.string(label) for label in _null_terminated_array(labels)] + + +def has_label(package, target, prefix): + """Returns True if the target has any matching label that would be returned by get_labels.""" + labels = _get_labels(package, ffi.new('char[]', target), ffi.new('char[]', prefix)) + for label in _null_terminated_array(labels): + return True + return False + + +def package(globals_dict, **kwargs): + """Defines settings affecting the current package - for example, default visibility.""" + config = globals_dict['CONFIG'].copy() + for k, v in kwargs.items(): + k = k.upper() + if k in config: + config[k] = v + else: + raise KeyError('error calling package(): %s is not a known config value' % k) + globals_dict['CONFIG'] = config + + +def licenses(globals_dict, licenses): + """Defines default licenses for the package. Provided for Bazel compatibility.""" + package(globals_dict, default_licences=licenses) + + +def _null_terminated_array(arr): + for i in xrange(1000000): + if arr[i] == ffi.NULL: + break + yield arr[i] + + +def _get_globals(c_package, c_package_name): + """Creates a copy of the builtin set of globals to use on interpreting new files. + + Best not to ask about any of this really. If you must know: all Python functions store their + own set of globals internally, which we want to change to point to this local dict so it's + indistinguishable from before. It's not sufficient just to update their __globals__ and you + can't reassign that at runtime, so we create duplicates here. YOLO. + """ + local_globals = {} + for k, v in _please_globals.iteritems(): + if callable(v) and type(v) == FunctionType: + local_globals[k] = FunctionType(v.__code__, local_globals, k, v.__defaults__, v.__closure__) + else: + local_globals[k] = v + # Need to pass some hidden arguments to these guys. + package_name = ffi.string(c_package_name) + local_globals['include_defs'] = lambda target: include_defs(c_package, local_globals, target) + local_globals['subinclude'] = lambda target: subinclude(c_package, local_globals, target) + local_globals['build_rule'] = lambda *args, **kwargs: build_rule(local_globals, c_package, + *args, **kwargs) + local_globals['glob'] = lambda *args, **kwargs: glob(package_name, *args, **kwargs) + local_globals['get_labels'] = lambda name, prefix: get_labels(c_package, name, prefix) + local_globals['has_label'] = lambda name, prefix: has_label(c_package, name, prefix) + local_globals['get_base_path'] = lambda: package_name + local_globals['add_dep'] = lambda target, dep: _add_dependency(c_package, target, dep, False) + local_globals['add_exported_dep'] = lambda target, dep: _add_dependency(c_package, target, dep, True) + local_globals['add_out'] = lambda target, out: _add_output(c_package, target, out) + local_globals['add_licence'] = lambda name, licence: _add_licence_post(c_package, name, licence) + local_globals['set_command'] = lambda name, command: _set_command(c_package, name, command) + local_globals['package'] = lambda **kwargs: package(local_globals, **kwargs) + local_globals['licenses'] = lambda l: licenses(local_globals, l) + # Make these available to other scripts so they can get it without import. + local_globals['join_path'] = os.path.join + local_globals['split_path'] = os.path.split + local_globals['splitext'] = os.path.splitext + local_globals['basename'] = os.path.basename + local_globals['dirname'] = os.path.dirname + # The levels here are internally interpreted to match go-logging's levels. + local_globals['log'] = DotDict({ + 'fatal': lambda message, *args: _log(0, c_package, message % args), + 'error': lambda message, *args: _log(1, c_package, message % args), + 'warning': lambda message, *args: _log(2, c_package, message % args), + 'notice': lambda message, *args: _log(3, c_package, message % args), + 'info': lambda message, *args: _log(4, c_package, message % args), + 'debug': lambda message, *args: _log(5, c_package, message % args), + }) + return local_globals + + +# c_argument is magically created for us by pypy. +callbacks = ffi.cast('PleaseCallbacks*', c_argument) +callbacks.parse_file = parse_file +callbacks.parse_code = parse_code +callbacks.set_config_value = set_config_value +callbacks.pre_build_callback_runner = run_pre_build_function +callbacks.post_build_callback_runner = run_post_build_function +_add_target = ffi.cast('AddTargetCallback*', callbacks.add_target) +_add_src = ffi.cast('AddStringCallback*', callbacks.add_src) +_add_data = ffi.cast('AddStringCallback*', callbacks.add_data) +_add_dep = ffi.cast('AddStringCallback*', callbacks.add_dep) +_add_exported_dep = ffi.cast('AddStringCallback*', callbacks.add_exported_dep) +_add_tool = ffi.cast('AddStringCallback*', callbacks.add_tool) +_add_out = ffi.cast('AddStringCallback*', callbacks.add_out) +_add_vis = ffi.cast('AddStringCallback*', callbacks.add_vis) +_add_label = ffi.cast('AddStringCallback*', callbacks.add_label) +_add_hash = ffi.cast('AddStringCallback*', callbacks.add_hash) +_add_licence = ffi.cast('AddStringCallback*', callbacks.add_licence) +_add_test_output = ffi.cast('AddStringCallback*', callbacks.add_test_output) +_add_require = ffi.cast('AddStringCallback*', callbacks.add_require) +_add_provide = ffi.cast('AddTwoStringsCallback*', callbacks.add_provide) +_add_named_src = ffi.cast('AddTwoStringsCallback*', callbacks.add_named_src) +_set_container_setting = ffi.cast('AddTwoStringsCallback*', callbacks.set_container_setting) +_glob = ffi.cast('GlobCallback*', callbacks.glob) +_get_include_file = ffi.cast('GetIncludeFileCallback*', callbacks.get_include_file) +_get_subinclude_file = ffi.cast('GetIncludeFileCallback*', callbacks.get_subinclude_file) +_get_labels = ffi.cast('GetLabelsCallback*', callbacks.get_labels) +_set_pre_build_callback = ffi.cast('SetBuildFunctionCallback*', callbacks.set_pre_build_callback) +_set_post_build_callback = ffi.cast('SetBuildFunctionCallback*', callbacks.set_post_build_callback) +_add_dependency = ffi.cast('AddDependencyCallback*', callbacks.add_dependency) +_add_output = ffi.cast('AddOutputCallback*', callbacks.add_output) +_add_licence_post = ffi.cast('AddTwoStringsCallback*', callbacks.add_licence_post) +_set_command = ffi.cast('AddTwoStringsCallback*', callbacks.set_command) +_log = ffi.cast('LogCallback*', callbacks.log) + +# Derive to support dot notation. +class DotDict(dict): + def __getattr__(self, attr): + return self[attr] + + def copy(self): + return DotDict(self) + +_please_globals['CONFIG'] = DotDict() +_please_globals['CONFIG']['DEFAULT_VISIBILITY'] = None +_please_globals['CONFIG']['DEFAULT_LICENCES'] = None +_please_globals['defaultdict'] = defaultdict + +# We'll need these guys locally. Unfortunately exec is a statement so we +# can't do it for that. +_compile, _open = compile, open +for k, v in __builtin__.__dict__.items(): # YOLO + try: + if issubclass(v, BaseException): + continue + except: + pass + if k not in _WHITELISTED_BUILTINS: + del __builtin__.__dict__[k] + + +class DeferParse(Exception): + """Raised to include that the parse of a file will be deferred until some build actions are done.""" diff --git a/src/parse/rules/proto_rules.py b/src/parse/rules/proto_rules.py new file mode 100644 index 0000000000..40b5330b33 --- /dev/null +++ b/src/parse/rules/proto_rules.py @@ -0,0 +1,220 @@ +"""Build rules for compiling protocol buffers & gRPC service stubs. + +Note that these are some of the most complex of our built-in build rules, +because of their cross-language nature. Each proto_library rule declares a set of +sub-rules to run protoc & the appropriate java_library, go_library rules etc. Users +shouldn't worry about those sub-rules and just declare a dependency directly on +the proto_library rule to get its appropriate outputs. +""" + +# Languages to generate protos for. +# We maintain this internal mapping to normalize their names to the same ones we use elsewhere. +_PROTO_LANGUAGES = {'cc': 'cpp', 'py': 'python', 'java': 'java', 'go': 'go'} + + +def proto_library(name, srcs, plugins=None, deps=None, visibility=None, + python_deps=None, cc_deps=None, java_deps=None, go_deps=None, + protoc_version=CONFIG.PROTOC_VERSION, languages=None): + """Compile a .proto file to generated code for various languages. + + Args: + name (str): Name of the rule + srcs (list): Input .proto files. + plugins (dict): Plugins to invoke for code generation. + deps (list): Dependencies + visibility (list): Visibility specification for the rule. + python_deps (list): Additional deps to add to the python_library rules + cc_deps (list): Additional deps to add to the cc_library rules + java_deps (list): Additional deps to add to the java_library rules + go_deps (list): Additional deps to add to the go_library rules + protoc_version (str): Version of protoc compiler, used to invalidate build rules when it changes. + languages (list): List of languages to generate rules for, chosen from the set {cc, py, go, java}. + """ + if languages: + for language in languages: + if language not in _PROTO_LANGUAGES: + raise ValueError('Unknown language for proto_library: %s' % language) + else: + languages = CONFIG.PROTO_LANGUAGES + plugins = plugins or {} + plugin_cmds = '' + deps = deps or [] + if 'go' in languages and 'plugin=protoc-gen-go' not in plugins: + plugins['plugin=protoc-gen-go'] = _plugin(CONFIG.PROTOC_GO_PLUGIN, deps) + if plugins: + if isinstance(plugins, dict): + plugins = sorted(plugins.items()) + plugin_cmds = ' '.join('--%s=%s' % (k, v) for k, v in plugins) + python_deps = python_deps or [] + cc_deps = cc_deps or [] + java_deps = java_deps or [] + go_deps = go_deps or [] + python_outs = [src.replace('.proto', '_pb2.py') for src in srcs] if 'py' in languages else [] + go_outs = [src.replace('.proto', '.pb.go') for src in srcs] if 'go' in languages else [] + cc_hdrs = [src.replace('.proto', '.pb.h') for src in srcs] if 'cc' in languages else [] + cc_srcs = [src.replace('.proto', '.pb.cc') for src in srcs] if 'cc' in languages else [] + gen_name = '_%s#protoc' % name + gen_rule = ':' + gen_name + java_only_name = '_%s#java_only' % name + base_path = get_base_path() + labels = ['proto:go-map: %s/%s=%s/%s' % (base_path, src, base_path, name) for src in srcs] + + # Used to collect Java output files; we don't know where they'll end up because their + # location depends on the java_package option defined in the .proto file. + def _annotate_java_outs(rule_name, output): + for out in output: + if out and out.endswith('.java'): + java_file = out.lstrip('./') + add_out(rule_name, java_file) + add_out(java_only_name, ':%s:%s' % (gen_name, java_file)) + + protoc_out_flags = ' '.join('--%s_out=$TMP_DIR' % _PROTO_LANGUAGES[language] + for language in languages) + cmds = [ + '%s %s %s ${SRCS}' % (_plugin(CONFIG.PROTOC_TOOL, deps), protoc_out_flags, plugin_cmds), + 'mv -f ${PKG}/* .', + 'find . -name "*.java" # protoc v%s' % protoc_version, + ] + if CONFIG.PROTO_PYTHON_PACKAGE: + cmds.insert(2, 'sed -i -e "s/from google.protobuf/from %s/g" *.py' % + CONFIG.PROTO_PYTHON_PACKAGE) + cmd = ' && '.join(cmds) + + # Used to update the Go path mapping; by default it doesn't really import in the way we want. + def _go_path_mapping(rule_name): + mapping = ',M'.join(get_labels(rule_name, 'proto:go-map:')) + # Bit of a hack, it's very hard to insert this one generically because of the way the + # go code generator specifies its own plugins. + grpc_plugin = 'plugins=grpc,' if 'grpc' in protoc_version else '' + new_cmd = cmd.replace('go_out=$TMP_DIR', 'go_out=%sM%s:$TMP_DIR' % (grpc_plugin, mapping)) + set_command(rule_name, new_cmd) + + build_rule( + name = gen_name, + srcs = srcs, + outs = python_outs + go_outs + cc_hdrs + cc_srcs, + cmd = cmd, + deps = deps, + requires = ['proto'], + pre_build = _go_path_mapping if 'go' in languages else None, + post_build = _annotate_java_outs if 'java' in languages else None, + labels = labels, + needs_transitive_deps = True, + visibility = visibility, + ) + filegroup( + name = '_%s#proto' % name, + srcs = srcs, + visibility = visibility, + exported_deps = deps, + labels = labels, + requires = ['proto'], + output_is_complete = False, + ) + + if 'cc' in languages: + cc_library( + name = '_%s#cc' % name, + srcs = [':%s:%s' % (gen_name, src) for src in cc_srcs], + hdrs = [':%s:%s' % (gen_name, hdr) for hdr in cc_hdrs], + deps = [gen_rule] + deps + cc_deps, + visibility = visibility, + ) + + if 'py' in languages: + python_library( + name = '_%s#py' % name, + srcs = [':%s:%s' % (gen_name, out) for out in python_outs], + deps = [CONFIG.PROTO_PYTHON_DEP] + deps + python_deps, + visibility = visibility, + ) + + if 'java' in languages: + # Used to reduce to just the Java files. + # Can't avoid this as we do with the other rules since java_library won't generate what we want + # for a rule with no srcs. Also can't use a filegroup directly, it's not quite flexible enough. + build_rule( + name = java_only_name, + srcs = [gen_rule], + cmd = 'echo $(location_pairs %s) | xargs -n 2 ln -s' % gen_rule, + skip_cache = True, + ) + java_library( + name = '_%s#java' % name, + srcs = [':' + java_only_name], + deps = deps, + exported_deps = [CONFIG.PROTO_JAVA_DEP] + java_deps, + visibility = visibility, + ) + + if 'go' in languages: + go_library( + name = '_%s#go' % name, + srcs = [':%s:%s' % (gen_name, out) for out in go_outs], + out = name + '.a', + deps = [CONFIG.PROTO_GO_DEP] + deps + go_deps, + visibility = visibility, + ) + # Needed for things like go_test / cgo_library that need the source in expected places + build_rule( + name = '_%s#go_src' % name, + srcs = [':%s:%s' % (gen_name, out) for out in go_outs], + outs = ['%s/%s' % (name, src.replace('.proto', '.pb.go')) for src in srcs], + cmd = 'cp ${PKG}/*.go %s' % name, + visibility = visibility, + deps = deps, + requires = ['go_src'], + ) + + provides = {x: ':_%s#%s' % (name, x) for x in ['proto'] + list(languages)} + provides['go_src'] = ':_%s#go_src' % name + provides['cc_hdrs'] = ':__%s#cc#hdrs' % name + filegroup( + name = name, + deps = provides.values(), + provides = provides, + visibility = visibility, + ) + + +def grpc_library(name, srcs, deps=None, visibility=None, languages=None): + """Defines a rule for a grpc library. + + Args: + name (str): Name of the rule + srcs (list): Input .proto files. + deps (list): Dependencies (other proto_library rules) + visibility (list): Visibility specification for the rule. + languages (list): List of languages to generate rules for, chosen from the set {cc, py, go, java}. + At present this will not create any service definitions for C++, but 'cc' is + still accepted for forwards compatibility. + """ + # No plugin for Go, that's handled above since it's merged into the go_out argument. + deps = deps or [] + languages = languages or CONFIG.PROTO_LANGUAGES + plugins = {} + if 'py' in languages: + plugins['plugin=protoc-gen-grpc-python'] = _plugin(CONFIG.GRPC_PYTHON_PLUGIN, deps) + plugins['grpc-python_out'] = '$TMP_DIR' + if 'java' in languages: + plugins['plugin=protoc-gen-grpc-java'] = _plugin(CONFIG.GRPC_JAVA_PLUGIN, deps) + plugins['grpc-java_out'] = '$TMP_DIR' + proto_library( + name = name, + srcs = srcs, + plugins=plugins, + deps=deps, + python_deps=[CONFIG.GRPC_PYTHON_DEP] if 'py' in languages else [], + java_deps=[CONFIG.GRPC_JAVA_DEP] if 'java' in languages else [], + go_deps=[CONFIG.GRPC_GO_DEP] if 'go' in languages else [], + visibility=visibility, + protoc_version='%s, grpc v%s' % (CONFIG.PROTOC_VERSION, CONFIG.GRPC_VERSION), + ) + + +def _plugin(plugin, deps): + """Handles plugins that are build labels by annotating them with $(exe ) and adds to deps.""" + if plugin.startswith('//'): + deps.append(plugin) + return '$(exe %s)' % plugin + return plugin diff --git a/src/parse/rules/python_rules.py b/src/parse/rules/python_rules.py new file mode 100644 index 0000000000..b4c3b2080a --- /dev/null +++ b/src/parse/rules/python_rules.py @@ -0,0 +1,369 @@ +""" Rules to build Python code. + +The output artifacts for Python rules are .pex files (see https://github.com/pantsbuild/pex). +Pex is a rather nice system for combining Python code and all needed dependencies +(excluding the actual interpreter and possibly some system level bits) into a single file. + +The process of compiling pex files can be a little slow when including many large files, as +often happens when one's binary includes large compiled dependencies (eg. numpy...). Hence +we have a fairly elaborate optimisation whereby each python_library rule builds a little +zipfile containing just its sources, and all of those are combined at the end to produce +the final .pex. This builds at roughly the same pace for a clean build of a single target, +but is drastically faster for building many targets with similar dependencies or rebuilding +a target which has only had small changes. +""" + + +def python_library(name, srcs=None, resources=None, deps=None, visibility=None, + test_only=False, zip_safe=True, labels=None): + """Generates a Python library target, which collects Python files for use by dependent rules. + + Note that each python_library performs some pre-zipping of its inputs before they're combined + in a python_binary or python_test. Hence while it's of course not required that all dependencies + of those rules are python_library rules, it's often a good idea to wrap any large dependencies + in one to improve incrementality (not necessary for pip_library, of course). + + Args: + name (str): Name of the rule. + srcs (list): Python source files for this rule. + resources (list): Non-Python files that this rule collects which will be included in the final .pex. + The distinction between this and srcs is fairly arbitrary and historical, but + semantically quite nice and parallels python_test. + deps (list): Dependencies of this rule. + visibility (list): Visibility specification. + test_only (bool): If True, can only be depended on by tests. + zip_safe (bool): Should be set to False if this library can't be safely run inside a .pex + (the most obvious reason not is when it contains .so modules). + See python_binary for more information. + labels (list): Labels to apply to this rule. + """ + all_srcs = (srcs or []) + (resources or []) + deps = deps or [] + labels = labels or [] + if not zip_safe: + labels.append('py:zip-unsafe') + if all_srcs: + # Pre-zip the files for later collection by python_binary. + build_rule( + name='_%s#zip' % name, + srcs=all_srcs, + outs=['.%s.pex.zip' % name], + # This is a little heavy-handed but approximates what pex would do (ie. create __init__.py + # files anywhere they don't exist). It's a little more selective but this is much better than + # the alternative. + cmd = 'find ${PKG} -type d | grep -v "${PKG}$" | xargs -I {} touch "{}/__init__.py" && zip -r1 $OUT $(echo "$PKG" | cut -d "/" -f 1)', + building_description='Compressing...', + requires=['py'], + test_only=test_only, + output_is_complete=True, + ) + deps.append(':_%s#zip' % name) + + filegroup( + name=name, + srcs=all_srcs, + deps=deps, + visibility=visibility, + output_is_complete=False, + requires=['py'], + test_only=test_only, + labels=labels, + ) + + +def python_binary(name, main, deps=None, visibility=None, zip_safe=None, + interpreter=CONFIG.DEFAULT_PYTHON_INTERPRETER): + """Generates a Python binary target. + + This compiles all source files together into a single .pex file which can + be easily copied or deployed. The construction of the .pex is done in parts + by the dependent python_library rules, and this rule simply builds the + metadata for it and concatenates them all together. + + Args: + name (str): Name of the rule. + main (str): Python file which is the entry point and __main__ module. + deps (list): Dependencies of this rule. + visibility (list): Visibility specification. + zip_safe (bool): Allows overriding whether the output is marked zip safe or not. + If set to explicitly True or False, the output will be marked + appropriately; by default it will be safe unless any of the + transitive dependencies are themselves marked as not zip-safe. + interpreter (str): The Python interpreter to use. Defaults to the config setting + which is normally just 'python', but could be 'python3' or + 'pypy' or whatever. + """ + main_mod = main[:-3] if main.endswith('.py') else main + pex_tool, tools = _tool_path(CONFIG.PEX_TOOL) + deps = deps or [] + cmd = ' '.join([ + # Ensure they all have an __init__.py + 'find `echo $PKG | cut -d "/" -f 1` -type d | xargs -I {} touch {}/__init__.py && ', + pex_tool, + '--src_dir=${TMP_DIR}', + '--out=${OUT}', + '--entry_point=${PKG//\//.}.' + main_mod, + '--interpreter=' + interpreter, + '--module_dir=' + CONFIG.PYTHON_MODULE_DIR, + ]) + pre_build, cmd = _handle_zip_safe(cmd, zip_safe) + + python_library( + name='_%s#lib' % name, + srcs=[main], + deps=deps, + visibility=visibility, + ) + + # Use the pex tool to compress the entry point & add all the bootstrap helpers etc. + build_rule( + name='_%s#pex' % name, + outs=['.%s_main.pex.zip' % name], # just call it .zip so everything has the same extension + cmd=cmd, + requires=['py'], + pre_build=pre_build, + tools=tools, + ) + # This rule concatenates the .pex with all the other precompiled zip files from dependent rules. + jarcat_tool, tools = _tool_path(CONFIG.JARCAT_TOOL) + build_rule( + name=name, + deps=[':_%s#pex' % name, ':_%s#lib' % name], + outs=['%s.pex' % name], + cmd=' && '.join([ + 'PREAMBLE=`head -n 1 $(location :_%s#pex)`' % name, + '%s -i . -o $OUTS --suffix=.pex.zip --preamble="$PREAMBLE" --include_other --add_init_py --strict' % jarcat_tool, + 'chmod +x $OUTS', + ]), + needs_transitive_deps=True, + binary=True, + output_is_complete=True, + building_description="Creating pex...", + visibility=visibility, + requires=['py'], + tools=tools, + # This makes the python_library rule the dependency for other python_library or + # python_test rules that try to import it. Does mean that they cannot collect a .pex + # by depending directly on the rule, they'll just get the Python files instead. + # This is not a common case anyway; more usually you'd treat that as a runtime data + # file rather than trying to pack into a pex. Can be worked around with an + # intermediary filegroup rule if really needed. + provides={'py': ':_%s#lib' % name}, + ) + + +def python_test(name, srcs, data=None, resources=None, deps=None, labels=None, + visibility=None, container=False, timeout=0, flaky=0, test_outputs=None, + zip_safe=None, interpreter=CONFIG.DEFAULT_PYTHON_INTERPRETER): + """Generates a Python test target. + + This works very similarly to python_binary; it is also a single .pex file + which is run to execute the tests. The tests are run via unittest. + + Args: + name (str): Name of the rule. + srcs (list): Source files for this test. + data (list): Runtime data files for the test. + resources (list): Non-Python files to be included in the pex. Note that the distinction + vs. srcs is important here; srcs are passed to unittest for it to run + and it may or may not be happy if given non-Python files. + deps (list): Dependencies of this rule. + labels (list): Labels for this rule. + visibility (list): Visibility specification. + container (bool | dict): If True, the test will be run in a container (eg. Docker). + timeout (int): Maximum time this test is allowed to run for, in seconds. + flaky (int | bool): True to mark this test as flaky, or an integer for a number of reruns. + test_outputs (list): Extra test output files to generate from this test. + zip_safe (bool): Allows overriding whether the output is marked zip safe or not. + If set to explicitly True or False, the output will be marked + appropriately; by default it will be safe unless any of the + transitive dependencies are themselves marked as not zip-safe. + interpreter (str): The Python interpreter to use. Defaults to the config setting + which is normally just 'python', but could be 'python3' or + 'pypy' or whatever. + """ + deps = deps or [] + pex_tool, tools = _tool_path(CONFIG.PEX_TOOL) + cmd=' '.join([ + # Ensure they all have an __init__.py + 'find `echo $PKG | cut -d "/" -f 1` -type d | xargs -I {} touch {}/__init__.py && ', + pex_tool, + '--src_dir=${TMP_DIR}', + '--out=${OUTS}', + '--entry_point=test_main', + '--test_package=${PKG//\//.}', + '--test_srcs=${SRCS_SRCS// /,}', + '--interpreter=' + interpreter, + '--module_dir=' + CONFIG.PYTHON_MODULE_DIR, + ]) + pre_build, cmd = _handle_zip_safe(cmd, zip_safe) + + # Used to separate dependencies from the pex rule so they aren't recompressed again. + build_rule( + name='_%s#deps' % name, + deps=deps, + cmd='true', + requires=['py'], + test_only=True, + ) + + # Use the pex tool to compress the entry point & add all the bootstrap helpers etc. + build_rule( + name='_%s#pex' % name, + srcs={ + 'srcs': srcs, + 'resources': resources, + }, + outs=['.%s_main.pex.zip' % name], # just call it .zip so everything has the same extension + cmd=cmd, + requires=['py'], + test_only=True, + building_description="Creating pex info...", + pre_build=pre_build, + deps=[':_%s#deps' % name], + tools=tools, + ) + # This rule concatenates the .pex with all the other precompiled zip files from dependent rules. + jarcat_tool, tools = _tool_path(CONFIG.JARCAT_TOOL) + build_rule( + name=name, + deps=[':_%s#pex' % name], + data=data, + outs=['%s.pex' % name], + labels=labels or [], + cmd=' && '.join([ + 'PREAMBLE=`head -n 1 $(location :_%s#pex)`' % name, + '%s -i . -o $OUTS --suffix=.pex.zip --preamble="$PREAMBLE" --include_other --add_init_py --strict' % jarcat_tool, + 'chmod +x $OUTS', + ]), + test_cmd = '$(exe :%s)' % name, + needs_transitive_deps=True, + output_is_complete=True, + binary=True, + test=True, + container=container, + building_description="Building pex...", + visibility=visibility, + test_timeout=timeout, + flaky=flaky, + test_outputs=test_outputs, + requires=['py'], + tools=tools, + ) + + +def pip_library(name, version, hashes, package_name=None, outs=None, test_only=False, + env=None, deps=None, post_install_commands=None, install_subdirectory=False, + repo=None, use_pypi=None, patch=None, visibility=None, zip_safe=True, licences=None): + """Provides a build rule for third-party dependencies to be installed by pip. + + Args: + name (str): Name of the build rule. + version (str): Specific version of the package to install. + hashes (list): List of acceptable hashes for this target. + package_name (str): Name of the pip package to install. Defaults to the same as 'name'. + outs (list): List of output files / directories. Defaults to [name]. + env (dict): Environment variables to provide during pip install, as a dict (or similar). + deps (list): List of rules this library depends on. + post_install_commands (list): Commands run after pip install has completed. + install_subdirectory (bool): Forces the package to install into a subdirectory with this name. + repo (str): Allows specifying a custom repo to fetch from. + use_pypi (bool): If True, will check PyPI as well for packages. + patch (str): A patch file to be applied after install. + visibility (list): Visibility declaration for this rule. + zip_safe (bool): Flag to indicate whether a pex including this rule will be zip-safe. + licences (list): Licences this rule is subject to. Default attempts to detect from package metadata. + """ + package_name = '%s==%s' % (package_name or name, version) + outs = outs or [name] + install_deps = [] + post_install_commands = post_install_commands or [] + post_build = None + use_pypi = CONFIG.USE_PYPI if use_pypi is None else use_pypi + index_flag = '' if use_pypi else '--no-index' + + repo_flag = '' + repo = repo or CONFIG.PYTHON_DEFAULT_PIP_REPO + if repo: + if repo.startswith('//') or repo.startswith(':'): # Looks like a build label, not a URL. + repo_flag = '-f %(location %s)' % repo + deps.append(repo) + else: + repo_flag = '-f ' + repo + + # Environment variables. Must sort in case we were given a dict. + environment = ' '.join('%s=%s' % (k, v) for k, v in sorted((env or {}).items())) + target = name if install_subdirectory else '.' + + cmd = '%s install --no-deps --no-compile --default-timeout=60 --target=%s' % (CONFIG.PIP_TOOL, target) + cmd += ' -b build %s %s %s' % (repo_flag, index_flag, package_name) + cmd += ' && find . -name "*.pyc" -or -name "tests" | xargs rm -rf' + + if not licences: + cmd += ' && find . -name METADATA -or -name PKG-INFO | grep -v "^./build/" | xargs grep -E "License ?:" | grep -v UNKNOWN | cat' + + if install_subdirectory: + cmd += ' && rm -rf %s/*.egg-info %s/*.dist-info' % (name, name) + + if patch: + patches = [patch] if isinstance(patch, str) else patch + cmd += ' && ' + ' && '.join('patch -p0 < $(location %s)' % patch for patch in patches) + + if post_install_commands: + cmd = ' && '.join([cmd] + post_install_commands) + + build_rule( + name = '_%s#install' % name, + cmd = cmd, + outs = outs, + srcs = patches if patch else [], + deps = install_deps, + building_description = 'Fetching...', + hashes = hashes, + requires=['py'], + test_only=test_only, + licences=licences, + post_build=None if licences else _add_licences, + ) + # Get this to do the pex pre-zipping stuff. + python_library( + name = name, + srcs = [':_%s#install' % name], + deps = deps, + visibility = visibility, + test_only=test_only, + zip_safe=zip_safe, + ) + + +def _handle_zip_safe(cmd, zip_safe): + """Handles the zip safe flag. Returns a tuple of (pre-build function, new command).""" + if zip_safe is None: + return lambda name: (set_command(name, cmd + ' --nozip_safe') + if has_label(name, 'py:zip-unsafe') else None), cmd + elif zip_safe: + return None, cmd + else: + return None, cmd + ' --nozip_safe' + + +def _add_licences(name, output): + """Annotates a pip_library rule with detected licences after download.""" + for line in output: + if line.startswith('License: '): + for licence in line[9:].split(' or '): # Some are defined this way (eg. "PSF or ZPL") + add_licence(name, licence) + return + elif line.startswith('Classifier: License'): + # Oddly quite a few packages seem to have UNKNOWN for the licence but this Classifier + # section still seems to know what they are licenced as. + add_licence(name, line.split(' :: ')[-1]) + return + log.warning('No licence found for %s, should add licences = [...] to the rule', + name.lstrip('_').split('#')[0]) + + +# Nod to superficial Bazel compatibility +py_library = python_library +py_binary = python_binary +py_test = python_test diff --git a/src/parse/rules/sh_rules.py b/src/parse/rules/sh_rules.py new file mode 100644 index 0000000000..a63a183e7b --- /dev/null +++ b/src/parse/rules/sh_rules.py @@ -0,0 +1,84 @@ +""" Rules to 'build' shell scripts. + +Note that these do pretty much nothing beyond collecting the files. In future we might +implement something more advanced (ala .sar files or whatever). +""" + +def sh_library(name, src, deps=None, visibility=None, link=True): + """Generates a shell script binary, essentially just the given source. + + Note that these are individually executable so can only have one source file each. + This is a bit tedious and would be nice to improve sometime. + + Args: + name (str): Name of the rule + src (str): Source file for the rule + deps (list): Dependencies of this rule + visibility (list): Visibility declaration of the rule. + link (bool): If True, outputs will be linked in plz-out; if False they'll be copied. + """ + filegroup( + name=name, + srcs=[src], + deps=deps, + visibility=visibility, + link=link, + binary=True, + ) + + +def sh_binary(name, main, deps=None, visibility=None, link=True): + """Generates a shell binary, essentially just the shell script itself. + + Args: + name (str): Name of the rule + main (str): Main script file. + deps (list): Dependencies of this rule + visibility (list): Visibility declaration of the rule. + link (bool): If True, outputs will be linked in plz-out; if False they'll be copied. + """ + filegroup( + name=name, + srcs=[main], + deps=deps, + visibility=visibility, + link=link, + binary=True, + ) + + +def sh_test(name, src=None, args=None, labels=None, data=None, deps=None, + visibility=None, flaky=0, test_outputs=None, timeout=0, container=False): + """Generates a shell test. Note that these aren't packaged in a useful way. + + Args: + name (str): Name of the rule + src (str): Test script file. + args (list): Arguments that will be passed to this test when run. + labels (list): Labels to apply to this test. + data (list): Runtime data for the test. + deps (list): Dependencies of this rule + visibility (list): Visibility declaration of the rule. + timeout (int): Maximum length of time, in seconds, to allow this test to run for. + flaky (int | bool): True to mark this as flaky and automatically rerun. + test_outputs (list): Extra test output files to generate from this test. + container (bool | dict): True to run this test within a container (eg. Docker). + """ + build_rule( + name=name, + srcs=[src or test], + data=data, + deps=deps, + outs=[name + '.sh'], + cmd='ln -s ${SRC} ${OUT}', + test_cmd='$(exe :%s) %s' % (name, ' '.join(args or [])), + visibility=visibility, + labels=labels, + binary=True, + test=True, + no_test_output=True, + flaky=flaky, + test_outputs=test_outputs, + test_timeout=timeout, + container=container, + ) diff --git a/src/parse/test_data/TEST_BUILD b/src/parse/test_data/TEST_BUILD new file mode 100644 index 0000000000..5b82685616 --- /dev/null +++ b/src/parse/test_data/TEST_BUILD @@ -0,0 +1 @@ +# Not a real BUILD file, used in interpreter_test. diff --git a/src/parse/test_data/test.txt b/src/parse/test_data/test.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parse/test_data/test_subfolder1/a.txt b/src/parse/test_data/test_subfolder1/a.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parse/test_data/test_subfolder2/BUILD b/src/parse/test_data/test_subfolder2/BUILD new file mode 100644 index 0000000000..4e1314b964 --- /dev/null +++ b/src/parse/test_data/test_subfolder2/BUILD @@ -0,0 +1,2 @@ +# This BUILD file is here to test that rules from parent +# directories can't glob its files. diff --git a/src/parse/test_data/test_subfolder2/b.txt b/src/parse/test_data/test_subfolder2/b.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parse/test_data/test_subfolder3/test.py b/src/parse/test_data/test_subfolder3/test.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parse/test_data/test_subfolder4/TEST_BUILD b/src/parse/test_data/test_subfolder4/TEST_BUILD new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/parse/test_data/test_subfolder4/test.py b/src/parse/test_data/test_subfolder4/test.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/please.go b/src/please.go new file mode 100644 index 0000000000..a12d62a72e --- /dev/null +++ b/src/please.go @@ -0,0 +1,551 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "runtime" + "strings" + "syscall" + + "build" + "cache" + "clean" + "core" + "output" + "parse" + "query" + "run" + "test" + "update" + "utils" + + "github.com/jessevdk/go-flags" + "github.com/kardianos/osext" + "github.com/op/go-logging" + "golang.org/x/crypto/ssh/terminal" +) + +var log = logging.MustGetLogger("plz") + +const testResultsFile = "plz-out/log/test_results.xml" +const coverageResultsFile = "plz-out/log/coverage.json" + +var Config core.Configuration + +var opts struct { + RepoRoot string `short:"r" long:"repo_root" description:"Root of repository to build."` + NumThreads int `short:"n" long:"num_threads" description:"Number of concurrent threads operations."` + Verbosity int `short:"v" long:"verbosity" description:"Verbosity of output (higher number = more output, default 1 -> warnings and errors only)" default:"1"` + KeepGoing bool `short:"k" long:"keep_going" description:"Don't stop on first failed target."` + InteractiveOutput bool `long:"interactive_output" description:"Show interactive output in a terminal"` + PlainOutput bool `short:"p" long:"plain_output" description:"Don't show interactive output."` + Include []string `short:"i" long:"include" description:"Label of targets to include from automatic detection."` + Exclude []string `short:"e" long:"exclude" description:"Label of targets to exclude from automatic detection."` + NoUpdate bool `long:"noupdate" description:"Disable Please attempting to auto-update itself." default:"false"` + NoCache bool `long:"no_cache" description:"Disable caching locally" default:"false"` + Version bool `long:"version" description:"Print the version of the tool"` + AssertVersion string `long:"assert_version" hidden:"true" description:"Assert the tool matches this version."` + NoHashVerification bool `long:"nohash_verification" description:"Hash verification errors are nonfatal." default:"false"` + LogFile string `long:"log_file" description:"File to echo full logging output to"` + LogFileLevel int `long:"log_file_level" description:"Log level for file output" default:"2"` + NoLock bool `long:"nolock" description:"Don't attempt to lock the repo exclusively. Use with care." default:"false"` + TraceFile string `long:"trace_file" description:"File to write Chrome tracing output into"` + PrintCommands bool `long:"print_commands" description:"Print each build / test command as they're run"` + Colour bool `long:"colour" description:"Forces coloured output from logging & other shell output."` + NoColour bool `long:"nocolour" description:"Forces colourless output from logging & other shell output."` + KeepWorkdirs bool `long:"keep_workdirs" description:"Don't clean directories in plz-out/tmp after successfully building targets."` + + ParsePackageOnly bool `description:"Parses a single package only. All that's necessary for some commands." no-flag:"true"` + NoCacheCleaner bool `description:"Don't start a cleaning process for the directory cache" default:"false" no-flag:"true"` + + Build struct { + Args struct { // Inner nesting is necessary to make positional-args work :( + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to build" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"build" description:"Builds one or more targets"` + + Test struct { + FailingTestsOk bool `long:"failing_tests_ok" description:"Exit with status 0 even if tests fail (nonzero only if catastrophe happens)" default:"false"` + MaxFlakes int `long:"max_flakes" description:"Max number of times to run a test (0 for default)"` + NumRuns int `long:"num_runs" short:"n" default:"1" description:"Number of times to run each test target."` + // Slightly awkward since we can specify a single test with arguments or multiple test targets. + Args struct { + Target core.BuildLabel `positional-arg-name:"target" description:"Target to test"` + Args []string `positional-arg-name:"arguments" description:"Arguments or test selectors"` + } `positional-args:"true" required:"true"` + } `command:"test" description:"Builds and tests one or more targets"` + + Cover struct { + FailingTestsOk bool `long:"failing_tests_ok" description:"Exit with status 0 even if tests fail (nonzero only if catastrophe happens)" default:"false"` + NoCoverageReport bool `long:"nocoverage_report" description:"Suppress the per-file coverage report displayed in the shell" default:"false"` + MaxFlakes int `long:"max_flakes" description:"Max number of times to run a test (0 for default)"` + NumRuns int `long:"num_runs" short:"n" default:"1" description:"Number of times to run each test target."` + Args struct { + Target core.BuildLabel `positional-arg-name:"target" description:"Target to test" group:"one test"` + Args []string `positional-arg-name:"arguments" description:"Arguments or test selectors" group:"one test"` + } `positional-args:"true" required:"true"` + } `command:"cover" description:"Builds and tests one or more targets, and calculates coverage."` + + Run struct { + Args struct { + Target core.BuildLabel `positional-arg-name:"target" description:"Target to run"` + Args []string `positional-arg-name:"arguments" description:"Arguments to pass to target when running (to pass flags to the target, put -- before them)"` + } `positional-args:"true" required:"true"` + } `command:"run" description:"Builds and runs a single target"` + + Clean struct { + Cache bool `long:"cache" short:"c" description:"Clean cache as well" default:"false"` + NoBackground bool `long:"nobackground" short:"f" description:"Don't fork & detach until clean is finished." default:"false"` + Args struct { // Inner nesting is necessary to make positional-args work :( + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to clean (default is to clean everything)"` + } `positional-args:"true"` + } `command:"clean" description:"Cleans build artifacts" subcommands-optional:"true"` + + Update struct { + } `command:"update" description:"Checks for an update and updates if needed."` + + Op struct { + } `command:"op" description:"Re-runs previous command."` + + Init struct { + Dir string `long:"dir" description:"Directory to create config in" default:"."` + } `command:"init" description:"Initialises a .plzconfig file in the current directory"` + + Query struct { + Deps struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to query" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"deps" description:"Queries the dependencies of a target."` + SomePath struct { + Args struct { + Target1 core.BuildLabel `positional-arg-name:"target1" description:"First build target" required:"true"` + Target2 core.BuildLabel `positional-arg-name:"target2" description:"Second build target" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"somepath" description:"Queries for a path between two targets"` + AllTargets struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to query"` + } `positional-args:"true"` + } `command:"alltargets" description:"Lists all targets in the graph"` + Print struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to print" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"print" description:"Prints a representation of a single target"` + Completions struct { + Cmd string `long:"cmd" description:"Command to complete for" default:"build"` + Args struct { + Fragments []string `positional-arg-name:"fragment" description:"Initial fragment to attempt to complete"` + } `positional-args:"true"` + } `command:"completions" description:"Prints possible completions for a string."` + AffectedTargets struct { + Tests bool `long:"tests" description:"Shows only affected tests, no other targets."` + Args struct { + Files []string `positional-arg-name:"files" description:"Files to query affected tests for"` + } `positional-args:"true"` + } `command:"affectedtargets" description:"Prints any targets affected by a set of files."` + AffectedTests struct { + Args struct { + Files []string `positional-arg-name:"files" description:"Files to query affected tests for"` + } `positional-args:"true"` + } `command:"affectedtests" description:"Prints any tests affected by a set of files."` + Input struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to display inputs for" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"input" description:"Prints all transitive inputs of a target."` + Output struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to display outputs for" required:"true"` + } `positional-args:"true" required:"true"` + } `command:"output" description:"Prints all outputs of a target."` + Graph struct { + Args struct { + Targets []core.BuildLabel `positional-arg-name:"targets" description:"Targets to render graph for"` + } `positional-args:"true"` + } `command:"graph" description:"Prints a JSON representation of the build graph."` + } `command:"query" description:"Queries information about the build graph"` +} + +// Definitions of what we do for each command. +// Functions are called after args are parsed and return true for success. +var buildFunctions = map[string]func() bool{ + "build": func() bool { + success, _ := runBuild(opts.Build.Args.Targets, true, false, true) + return success + }, + "test": func() bool { + os.RemoveAll(testResultsFile) + targets := testTargets(opts.Test.Args.Target, opts.Test.Args.Args) + success, state := runBuild(targets, true, true, true) + test.WriteResultsToFileOrDie(state.Graph, testResultsFile) + return success || opts.Test.FailingTestsOk + }, + "cover": func() bool { + os.RemoveAll(testResultsFile) + os.RemoveAll(coverageResultsFile) + targets := testTargets(opts.Cover.Args.Target, opts.Cover.Args.Args) + success, state := runBuild(targets, true, true, true) + test.WriteResultsToFileOrDie(state.Graph, testResultsFile) + test.AddOriginalTargetsToCoverage(state, opts.Include, opts.Exclude) + test.RemoveFilesFromCoverage(state.Coverage, state.Config.Cover.ExcludeExtension) + test.WriteCoverageToFileOrDie(state.Coverage, coverageResultsFile) + if !opts.Cover.NoCoverageReport { + output.PrintCoverage(state) + } + return success || opts.Cover.FailingTestsOk + }, + "run": func() bool { + if success, state := runBuild([]core.BuildLabel{opts.Run.Args.Target}, true, false, false); success { + run.Run(state.Graph, opts.Run.Args.Target, opts.Run.Args.Args) + } + return false // We should never return from run.Run so if we make it here something's wrong. + }, + "clean": func() bool { + opts.NoCacheCleaner = true + if len(opts.Clean.Args.Targets) == 0 { + opts.PlainOutput = true // No need for interactive display, we won't parse anything. + } + if success, state := runBuild(opts.Clean.Args.Targets, false, false, false); success { + clean.Clean(state, state.ExpandOriginalTargets(), opts.Clean.Cache, !opts.Clean.NoBackground) + return true + } + return false + }, + "update": func() bool { + log.Info("Up to date.") + return true // We'd have died already if something was wrong. + }, + "op": func() bool { + cmd := core.ReadLastOperationOrDie() + log.Notice("OP PLZ: %s", strings.Join(cmd, " ")) + // Annoyingly we don't seem to have any access to execvp() which would be rather useful here... + executable, err := osext.Executable() + if err == nil { + err = syscall.Exec(executable, append([]string{executable}, cmd...), os.Environ()) + } + log.Fatalf("SORRY OP: %s", err) // On success Exec never returns. + return false + }, + "deps": func() bool { + return runQuery(true, opts.Query.Deps.Args.Targets, func(state *core.BuildState) { + query.QueryDeps(state.Graph, state.ExpandOriginalTargets()) + }) + }, + "somepath": func() bool { + return runQuery(true, + []core.BuildLabel{opts.Query.SomePath.Args.Target1, opts.Query.SomePath.Args.Target2}, + func(state *core.BuildState) { + query.QuerySomePath(state.Graph, opts.Query.SomePath.Args.Target1, opts.Query.SomePath.Args.Target2) + }, + ) + }, + "alltargets": func() bool { + return runQuery(true, opts.Query.AllTargets.Args.Targets, func(state *core.BuildState) { + query.QueryAllTargets(state.Graph, state.ExpandOriginalTargets()) + }) + }, + "print": func() bool { + return runQuery(false, opts.Query.Print.Args.Targets, func(state *core.BuildState) { + query.QueryPrint(state.Graph, state.ExpandOriginalTargets()) + }) + }, + "affectedtargets": func() bool { + files := opts.Query.AffectedTargets.Args.Files + if len(files) == 1 && files[0] == "-" { + files = readStdin() + } + return runQuery(true, core.WholeGraph, func(state *core.BuildState) { + query.QueryAffectedTargets(state.Graph, files, opts.Include, opts.Exclude, opts.Query.AffectedTargets.Tests) + }) + }, + "affectedtests": func() bool { + // For backwards compatibility. + // TODO(pebers): Remove at plz 1.2. + files := opts.Query.AffectedTests.Args.Files + if len(files) == 1 && files[0] == "-" { + files = readStdin() + } + return runQuery(true, core.WholeGraph, func(state *core.BuildState) { + query.QueryAffectedTargets(state.Graph, files, opts.Include, opts.Exclude, true) + }) + }, + "input": func() bool { + return runQuery(true, opts.Query.Input.Args.Targets, func(state *core.BuildState) { + query.QueryTargetInputs(state.Graph, state.ExpandOriginalTargets()) + }) + }, + "output": func() bool { + return runQuery(true, opts.Query.Output.Args.Targets, func(state *core.BuildState) { + query.QueryTargetOutputs(state.Graph, state.ExpandOriginalTargets()) + }) + }, + "completions": func() bool { + // Somewhat fiddly because the inputs are not necessarily well-formed at this point. + opts.ParsePackageOnly = true + fragments := opts.Query.Completions.Args.Fragments + if len(fragments) == 1 && fragments[0] == "-" { + fragments = readStdin() + } else if len(fragments) == 0 || len(fragments) == 1 && strings.Trim(fragments[0], "/ ") == "" { + os.Exit(0) // Don't do anything for empty completion, it's normally too slow. + } + labels := query.QueryCompletionLabels(Config, fragments, core.RepoRoot) + if success, state := Please(labels, Config, false, false, false); success { + binary := opts.Query.Completions.Cmd == "run" + test := opts.Query.Completions.Cmd == "test" || opts.Query.Completions.Cmd == "cover" + query.QueryCompletions(state.Graph, labels, binary, test) + return true + } + return false + }, + "graph": func() bool { + return runQuery(true, opts.Query.Graph.Args.Targets, func(state *core.BuildState) { + query.QueryGraph(state.Graph, state.ExpandOriginalTargets()) + }) + }, +} + +// Used above as a convenience wrapper for query functions. +func runQuery(needFullParse bool, labels []core.BuildLabel, onSuccess func(state *core.BuildState)) bool { + opts.NoCacheCleaner = true + if !needFullParse { + opts.ParsePackageOnly = true + opts.PlainOutput = true // No point displaying this for one of these queries. + } + if success, state := runBuild(labels, false, false, true); success { + onSuccess(state) + return true + } + return false +} + +func please(tid int, state *core.BuildState, parsePackageOnly bool, include, exclude []string) { + pendingParses, pendingBuilds, pendingTests := state.ReceiveChannels() + for { + select { + case success := <-state.Stop: + state.Stop <- success // Pass on to another thread + return + case pendingParse, ok := <-pendingParses: + if ok { + parse.Parse(tid, state, pendingParse.Label, pendingParse.Dependor, parsePackageOnly, include, exclude) + } + case pendingBuild, ok := <-pendingBuilds: + if ok { + build.Build(tid, state, pendingBuild) + } + case pendingTest, ok := <-pendingTests: + if ok { + test.Test(tid, state, pendingTest) + } + } + state.ProcessedOne() + } +} + +// Determines from input flags whether we should show 'pretty' output (ie. interactive). +func prettyOutput(interactiveOutput bool, plainOutput bool, verbosity int) bool { + if interactiveOutput && plainOutput { + fmt.Printf("Can't pass both --interactive_output and --plain_output\n") + os.Exit(1) + } + return interactiveOutput || (!plainOutput && terminal.IsTerminal(int(os.Stderr.Fd())) && verbosity < 4) +} + +func Please(targets []core.BuildLabel, config core.Configuration, prettyOutput, shouldBuild, shouldTest bool) (bool, *core.BuildState) { + if opts.NumThreads <= 0 { + opts.NumThreads = runtime.NumCPU() + 2 + } + if opts.NoCacheCleaner { + config.Cache.DirCacheCleaner = "" + } + var cash *core.Cache = nil + if !opts.NoCache { + cash = cache.NewCache(config) + } + state := core.NewBuildState(opts.NumThreads, cash, opts.Verbosity, config) + state.VerifyHashes = !opts.NoHashVerification + state.MaxFlakes = opts.Test.MaxFlakes + opts.Cover.MaxFlakes // Only one of these can be passed. + state.TestArgs = append(opts.Test.Args.Args, opts.Cover.Args.Args...) // Similarly here. + state.NeedCoverage = opts.Cover.Args.Target != core.BuildLabel{} + state.NeedBuild = shouldBuild + state.NeedTests = shouldTest + state.PrintCommands = opts.PrintCommands + state.CleanWorkdirs = !opts.KeepWorkdirs + if opts.Test.NumRuns > opts.Cover.NumRuns { + state.NumTestRuns = opts.Test.NumRuns + } else { + state.NumTestRuns = opts.Cover.NumRuns + } + // Acquire the lock before we start building + if (shouldBuild || shouldTest) && !opts.NoLock { + core.AcquireRepoLock() + defer core.ReleaseRepoLock() + } + if (shouldBuild || shouldTest) && core.PathExists(testResultsFile) { + if err := os.Remove(testResultsFile); err != nil { + log.Fatalf("Failed to remove test results file: %s", err) + } + } + displayDone := make(chan bool) + go output.MonitorState(state, opts.NumThreads, !prettyOutput, opts.KeepGoing, shouldBuild, shouldTest, displayDone, opts.TraceFile) + for i := 0; i < opts.NumThreads; i++ { + go please(i, state, opts.ParsePackageOnly, opts.Include, opts.Exclude) + } + for _, target := range targets { + if target.IsAllSubpackages() { + for pkg := range parse.FindAllSubpackages(state.Config, target.PackageName, "") { + label := core.NewBuildLabel(pkg, "all") + state.OriginalTargets = append(state.OriginalTargets, label) + state.AddPendingParse(label, core.OriginalTarget) + } + } else { + state.OriginalTargets = append(state.OriginalTargets, target) + state.AddPendingParse(target, core.OriginalTarget) + } + } + state.ProcessedOne() // initial target adding counts as one. + state.TargetsLoaded = true + success := <-state.Stop + state.Stop <- success + close(state.Results) // This will signal the output goroutine to stop. + // TODO(pebers): shouldn't rely on the display routine to tell us whether we succeeded or not... + success = <-displayDone + return success, state +} + +// Allows input args to come from stdin. It's a little slack to insist on reading it all +// up front but it's too hard to pass around a potential stream of arguments, and none of +// our current use cases really make any difference anyway. +func handleStdinLabels(labels []core.BuildLabel) []core.BuildLabel { + if len(labels) == 1 && labels[0] == core.BuildLabelStdin { + return core.ParseBuildLabels(readStdin()) + } + return labels +} + +func readStdin() []string { + stdin, err := ioutil.ReadAll(os.Stdin) + if err != nil { + log.Fatalf("%s\n", err) + } + trimmed := strings.TrimSpace(string(stdin)) + if trimmed == "" { + log.Warning("No targets supplied; nothing to do.") + os.Exit(0) + } + ret := strings.Split(trimmed, "\n") + for i, s := range ret { + ret[i] = strings.TrimSpace(s) + } + return ret +} + +// Handles test targets which can be given in two formats; a list of targets or a single +// target with a list of trailing arguments. +func testTargets(target core.BuildLabel, args []string) []core.BuildLabel { + if len(args) > 0 && core.LooksLikeABuildLabel(args[0]) { + opts.Cover.Args.Args = []string{} + opts.Test.Args.Args = []string{} + return append(core.ParseBuildLabels(args), target) + } else { + return []core.BuildLabel{target} + } +} + +// Sets various things up and reads the initial configuration. +func readConfig(forceUpdate bool) core.Configuration { + if opts.AssertVersion != "" && core.PleaseVersion != opts.AssertVersion { + log.Fatalf("Requested Please version %s, but this is version %s", opts.AssertVersion, core.PleaseVersion) + } + if opts.NoHashVerification { + log.Warning("You've disabled hash verification; this is intended to help temporarily while modifying build targets. You shouldn't use this regularly.") + } + + config, err := core.ReadConfigFiles([]string{ + path.Join(core.RepoRoot, core.ConfigFileName), + core.MachineConfigFileName, + path.Join(core.RepoRoot, core.LocalConfigFileName), + }) + // This is kinda weird, but we need to check for an update before handling errors, because the + // error may be for a missing config value that we don't know about yet. If we error first it's + // essentially impossible to add new fields to the config because gcfg doesn't permit unknown fields. + update.CheckAndUpdate(config, !opts.NoUpdate, forceUpdate) + if err != nil { + log.Fatalf("Error reading config file: %s", err) + } + return config +} + +// Runs the actual build +// Which phases get run are controlled by shouldBuild and shouldTest. +func runBuild(targets []core.BuildLabel, shouldBuild, shouldTest, defaultToAllTargets bool) (bool, *core.BuildState) { + if len(targets) == 0 && defaultToAllTargets { + targets = core.WholeGraph + } + pretty := prettyOutput(opts.InteractiveOutput, opts.PlainOutput, opts.Verbosity) + return Please(handleStdinLabels(targets), Config, pretty, shouldBuild, shouldTest) +} + +// activeCommand returns the name of the currently active command. +func activeCommand(parser *flags.Parser) string { + if parser.Active == nil { + return "" + } else if parser.Active.Active != nil { + return parser.Active.Active.Name + } + return parser.Active.Name +} + +func main() { + parser, extraArgs, err := output.ParseFlags("Please", &opts, os.Args) + // PrintCommands implies verbosity of at least 2, because commands are logged at that level + if opts.PrintCommands && opts.Verbosity < 2 { + opts.Verbosity = 2 + } + if opts.Colour { + output.SetColouredOutput(true) + } else if opts.NoColour { + output.SetColouredOutput(false) + } + output.InitLogging(opts.Verbosity, opts.LogFile, opts.LogFileLevel) + + command := activeCommand(parser) + if command == "init" { + // If we're running plz init then we obviously don't expect to read a config file. + utils.InitConfig(opts.Init.Dir) + os.Exit(0) + } + if opts.RepoRoot == "" { + core.FindRepoRoot(true) + log.Debug("Found repo root at %s", core.RepoRoot) + } else { + core.RepoRoot = opts.RepoRoot + } + + // Please always runs from the repo root, so move there now. + if err := os.Chdir(core.RepoRoot); err != nil { + log.Fatalf("%s", err) + } + + Config = readConfig(command == "update") + + // Now we've read the config file, we may need to re-run the parser; the aliases in the config + // can affect how we parse otherwise illegal flag combinations. + if err != nil || len(extraArgs) > 0 { + argv := strings.Join(os.Args, " ") + for k, v := range Config.Aliases { + argv = strings.Replace(argv, k, v, 1) + } + parser = output.ParseFlagsFromArgsOrDie("Please", &opts, strings.Fields(argv)) + command = activeCommand(parser) + } + + if buildFunctions[command]() { + os.Exit(0) + } + os.Exit(1) +} diff --git a/src/query/BUILD b/src/query/BUILD new file mode 100644 index 0000000000..1ac38a3fa1 --- /dev/null +++ b/src/query/BUILD @@ -0,0 +1,30 @@ +go_library( + name = 'query', + srcs = glob(['*.go'], excludes=['*_test.go']), + deps = [ + '//src/build', + '//src/core', + '//src/parse', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'print_test', + srcs = ['print_test.go'], + deps = [ + ':query', + '//src/core', + ], +) + +go_test( + name = 'graph_test', + srcs = ['graph_test.go'], + deps = [ + ':query', + '//src/core', + '//third_party/go:testify', + ], +) diff --git a/src/query/affected_targets.go b/src/query/affected_targets.go new file mode 100644 index 0000000000..a65a4b7c8c --- /dev/null +++ b/src/query/affected_targets.go @@ -0,0 +1,85 @@ +package query + +import "core" +import "fmt" + +// Walks over the build graph and identifies all targets that have a transitive +// dependency on the given set of files. +// Targets are filtered by given include / exclude labels and if 'tests' is true only +// test targets will be returned. +func QueryAffectedTargets(graph *core.BuildGraph, files, include, exclude []string, tests bool) { + affectedTargets := make(chan *core.BuildTarget, 100) + done := make(chan bool) + + filePaths := map[string]bool{} + for _, file := range files { + filePaths[file] = true + } + + // Check all the targets to see if any own one of these files + go func() { + for _, target := range graph.AllTargets() { + for _, source := range target.AllSourcePaths(graph) { + if _, present := filePaths[source]; present { + affectedTargets <- target + break + } + } + } + done <- true + }() + + // Check all the packages to see if any are defined by these files. + // TODO(pebers): This is pretty pessimistic, we have to just assume the whole package is + // invalidated. A better but more complicated approach would be to generate + // the hash of every rule before and after the change and invalidate the ones + // that were different. + go func() { + invalidatePackage := func(pkg *core.Package) { + for _, target := range pkg.Targets { + affectedTargets <- target + } + } + for _, pkg := range graph.PackageMap() { + if _, present := filePaths[pkg.Filename]; present { + invalidatePackage(pkg) + } else { + for _, subinclude := range pkg.Subincludes { + if _, present := filePaths[subinclude]; present { + invalidatePackage(pkg) + break + } + } + } + } + done <- true + }() + + go handleAffectedTargets(graph, affectedTargets, done, include, exclude, tests) + + <-done + <-done + close(affectedTargets) + <-done +} + +func handleAffectedTargets(graph *core.BuildGraph, affectedTargets <-chan *core.BuildTarget, done chan<- bool, include, exclude []string, tests bool) { + seenTargets := map[*core.BuildTarget]bool{} + + var inner func(*core.BuildTarget) + inner = func(target *core.BuildTarget) { + if !seenTargets[target] { + seenTargets[target] = true + for _, revdep := range graph.ReverseDependencies(target) { + inner(revdep) + } + if (!tests || target.IsTest) && target.ShouldInclude(include, exclude) { + fmt.Printf("%s\n", target.Label) + } + } + } + for target := range affectedTargets { + inner(target) + } + done <- true +} diff --git a/src/query/alltargets.go b/src/query/alltargets.go new file mode 100644 index 0000000000..fbdbef9019 --- /dev/null +++ b/src/query/alltargets.go @@ -0,0 +1,11 @@ +package query + +import "fmt" + +import "core" + +func QueryAllTargets(graph *core.BuildGraph, labels []core.BuildLabel) { + for _, target := range graph.AllTargets() { + fmt.Printf("%s\n", target.Label) + } +} diff --git a/src/query/completions.go b/src/query/completions.go new file mode 100644 index 0000000000..733b7a9f3d --- /dev/null +++ b/src/query/completions.go @@ -0,0 +1,75 @@ +package query + +import "fmt" +import "os" +import "path" +import "strings" + +import "core" +import "parse" + +// Produces a set of labels that complete a given input. +func QueryCompletionLabels(config core.Configuration, args []string, repoRoot string) []core.BuildLabel { + if len(args) == 0 { + queryCompletionPackages(config, ".", repoRoot) + } else if !strings.Contains(args[0], ":") { + // Haven't picked a package yet so no parsing is necessary. + if strings.HasPrefix(args[0], "//") { + queryCompletionPackages(config, args[0][2:], repoRoot) + } else { + queryCompletionPackages(config, args[0], repoRoot) + } + } + if strings.HasSuffix(args[0], ":") { + args[0] += "all" + } + label := core.ParseBuildLabel(args[0], repoRoot) + // Return this label without the trailing bit. + return []core.BuildLabel{core.BuildLabel{PackageName: label.PackageName, Name: "all"}} +} + +func queryCompletionPackages(config core.Configuration, query, repoRoot string) { + root := path.Join(repoRoot, query) + origRoot := root + if !core.PathExists(root) { + root = path.Dir(root) + } + packages := []string{} + for pkg := range parse.FindAllSubpackages(config, root, origRoot) { + if strings.HasPrefix(pkg, origRoot) { + packages = append(packages, pkg[len(repoRoot):]) + } + } + // If there's only one package, we know it has to be that, but we don't present + // only one option otherwise bash completion will assume it's that. + if len(packages) == 1 { + fmt.Printf("/%s:\n", packages[0]) + fmt.Printf("/%s:all\n", packages[0]) + } else { + for _, pkg := range packages { + fmt.Printf("/%s\n", pkg) + } + } + os.Exit(0) // Don't need to run a full-blown parse, get out now. +} + +// Queries a set of possible completions for some build labels. +// If 'binary' is true it will complete only targets that are runnable binaries (but not tests). +// If 'test' is true it will similarly complete only targets that are tests. +func QueryCompletions(graph *core.BuildGraph, labels []core.BuildLabel, binary, test bool) { + for _, label := range labels { + count := 0 + for _, target := range graph.PackageOrDie(label.PackageName).Targets { + if (binary && (!target.IsBinary || target.IsTest)) || (test && !target.IsTest) { + continue + } + if !strings.HasPrefix(target.Label.Name, "_") { + fmt.Printf("%s\n", target.Label) + count++ + } + } + if !binary && count > 1 { + fmt.Printf("//%s:all\n", label.PackageName) + } + } +} diff --git a/src/query/deps.go b/src/query/deps.go new file mode 100644 index 0000000000..c17a827867 --- /dev/null +++ b/src/query/deps.go @@ -0,0 +1,17 @@ +package query + +import "core" +import "fmt" + +func QueryDeps(graph *core.BuildGraph, labels []core.BuildLabel) { + for _, label := range labels { + printTarget(graph, graph.TargetOrDie(label), "") + } +} + +func printTarget(graph *core.BuildGraph, target *core.BuildTarget, indent string) { + fmt.Printf("%s%s\n", indent, target.Label) + for _, dep := range target.Dependencies { + printTarget(graph, dep, indent+" ") + } +} diff --git a/src/query/graph.go b/src/query/graph.go new file mode 100644 index 0000000000..84bd6c259c --- /dev/null +++ b/src/query/graph.go @@ -0,0 +1,113 @@ +package query + +import ( + "encoding/base64" + "encoding/json" + "fmt" + "path" + + "build" + "core" +) + +// QueryGraph prints a representation of the build graph as JSON. +func QueryGraph(graph *core.BuildGraph, targets []core.BuildLabel) { + b, err := json.MarshalIndent(makeJSONGraph(graph, targets), "", " ") + if err != nil { + log.Fatalf("Failed to serialise JSON: %s\n", err) + } + fmt.Println(string(b)) +} + +// JSONGraph is an alternate representation of our build graph; will contain different information +// to the structures in core (also those ones can't be printed as JSON directly). +type JSONGraph struct { + Packages map[string]JSONPackage `json:"packages"` +} + +// JSONPackage is an alternate representation of a build package +type JSONPackage struct { + Targets map[string]JSONTarget `json:"targets"` +} + +// JSONTarget is an alternate representation of a build target +type JSONTarget struct { + Inputs []string `json:"inputs,omitempty" note:"declared inputs of target"` + Outputs []string `json:"outs,omitempty" note:"corresponds to outs in rule declaration"` + Sources []string `json:"srcs,omitempty" note:"corresponds to srcs in rule declaration"` + Deps []string `json:"deps,omitempty" note:"corresponds to deps in rule declaration"` + Labels []string `json:"labels,omitempty" note:"corresponds to labels in rule declaration"` + Hash string `json:"hash" note:"partial hash of target, does not include source hash"` + Test bool `json:"test,omitempty" note:"true if target is a test"` +} + +func makeJSONGraph(graph *core.BuildGraph, targets []core.BuildLabel) *JSONGraph { + ret := JSONGraph{Packages: map[string]JSONPackage{}} + if len(targets) == 0 { + for name, pkg := range graph.PackageMap() { + ret.Packages[name] = makeJSONPackage(graph, pkg) + } + } else { + done := map[core.BuildLabel]struct{}{} + for _, target := range targets { + addJSONTarget(graph, &ret, target, done) + } + } + return &ret +} + +func addJSONTarget(graph *core.BuildGraph, ret *JSONGraph, label core.BuildLabel, done map[core.BuildLabel]struct{}) { + if _, present := done[label]; present { + return + } + done[label] = struct{}{} + if label.IsAllTargets() { + pkg := graph.PackageOrDie(label.PackageName) + for _, target := range pkg.Targets { + addJSONTarget(graph, ret, target.Label, done) + } + return + } + target := graph.TargetOrDie(label) + if _, present := ret.Packages[label.PackageName]; present { + ret.Packages[label.PackageName].Targets[label.Name] = makeJSONTarget(graph, target) + } else { + ret.Packages[label.PackageName] = JSONPackage{ + Targets: map[string]JSONTarget{ + label.Name: makeJSONTarget(graph, target), + }, + } + } + for _, dep := range target.Dependencies { + addJSONTarget(graph, ret, dep.Label, done) + } +} + +func makeJSONPackage(graph *core.BuildGraph, pkg *core.Package) JSONPackage { + targets := map[string]JSONTarget{} + for name, target := range pkg.Targets { + targets[name] = makeJSONTarget(graph, target) + } + return JSONPackage{Targets: targets} +} + +func makeJSONTarget(graph *core.BuildGraph, target *core.BuildTarget) JSONTarget { + t := JSONTarget{} + for in := range core.IterSources(graph, target, true) { + t.Inputs = append(t.Inputs, in.Src) + } + for _, out := range target.Outputs() { + t.Outputs = append(t.Outputs, path.Join(target.Label.PackageName, out)) + } + for _, in := range target.Sources { + t.Sources = append(t.Sources, in.String()) + } + for _, dep := range target.DeclaredDependencies { + t.Deps = append(t.Deps, dep.String()) + } + t.Labels = target.Labels + rawHash := append(build.RuleHash(target, true, false), core.State.Hashes.Config...) + t.Hash = base64.RawStdEncoding.EncodeToString(rawHash) + t.Test = target.IsTest + return t +} diff --git a/src/query/graph_test.go b/src/query/graph_test.go new file mode 100644 index 0000000000..3f91506ed0 --- /dev/null +++ b/src/query/graph_test.go @@ -0,0 +1,62 @@ +package query + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "core" +) + +func TestQueryEntireGraph(t *testing.T) { + graph := makeJSONGraph(makeGraph(), nil) + assert.Equal(t, 2, len(graph.Packages)) + pkg1 := graph.Packages["package1"] + assert.Equal(t, 2, len(pkg1.Targets)) + assert.Equal(t, 0, len(pkg1.Targets["target1"].Deps)) + assert.Equal(t, []string{"//package1:target1"}, pkg1.Targets["target2"].Deps) + pkg2 := graph.Packages["package2"] + assert.Equal(t, 1, len(pkg2.Targets)) + assert.Equal(t, []string{"//package1:target2"}, pkg2.Targets["target3"].Deps) +} + +func TestQuerySingleTarget(t *testing.T) { + graph := makeJSONGraph(makeGraph(), []core.BuildLabel{core.ParseBuildLabel("//package1:target2", "")}) + assert.Equal(t, 1, len(graph.Packages)) + pkg1 := graph.Packages["package1"] + assert.Equal(t, 1, len(pkg1.Targets)) + assert.Equal(t, []string{"//package1:target1"}, pkg1.Targets["target2"].Deps) +} + +func TestQueryPackage(t *testing.T) { + graph := makeJSONGraph(makeGraph(), []core.BuildLabel{core.ParseBuildLabel("//package1:all", "")}) + assert.Equal(t, 1, len(graph.Packages)) + pkg1 := graph.Packages["package1"] + assert.Equal(t, 2, len(pkg1.Targets)) + assert.Equal(t, 0, len(pkg1.Targets["target1"].Deps)) + assert.Equal(t, []string{"//package1:target1"}, pkg1.Targets["target2"].Deps) +} + +func makeGraph() *core.BuildGraph { + core.State = &core.BuildState{} + graph := core.NewGraph() + pkg1 := core.NewPackage("package1") + pkg1.Targets["target1"] = makeTarget("//package1:target1") + pkg1.Targets["target2"] = makeTarget("//package1:target2", "//package1:target1") + graph.AddPackage(pkg1) + graph.AddTarget(pkg1.Targets["target1"]) + graph.AddTarget(pkg1.Targets["target2"]) + pkg2 := core.NewPackage("package2") + pkg2.Targets["target3"] = makeTarget("//package2:target3", "//package1:target2") + graph.AddPackage(pkg2) + graph.AddTarget(pkg2.Targets["target3"]) + return graph +} + +func makeTarget(label string, deps ...string) *core.BuildTarget { + target := core.NewBuildTarget(core.ParseBuildLabel(label, "")) + for _, dep := range deps { + target.AddDependency(core.ParseBuildLabel(dep, "")) + } + return target +} diff --git a/src/query/inputs.go b/src/query/inputs.go new file mode 100644 index 0000000000..56bab0ac55 --- /dev/null +++ b/src/query/inputs.go @@ -0,0 +1,17 @@ +package query + +import "fmt" +import "core" + +func QueryTargetInputs(graph *core.BuildGraph, labels []core.BuildLabel) { + inputPaths := map[string]bool{} + for _, label := range labels { + for sourcePath := range core.IterInputPaths(graph, graph.TargetOrDie(label)) { + inputPaths[sourcePath] = true + } + } + + for path := range inputPaths { + fmt.Printf("%s\n", path) + } +} diff --git a/src/query/outputs.go b/src/query/outputs.go new file mode 100644 index 0000000000..c1b575d3a9 --- /dev/null +++ b/src/query/outputs.go @@ -0,0 +1,14 @@ +package query + +import "fmt" +import "path" +import "core" + +func QueryTargetOutputs(graph *core.BuildGraph, labels []core.BuildLabel) { + for _, label := range labels { + target := graph.TargetOrDie(label) + for _, out := range target.Outputs() { + fmt.Printf("%s\n", path.Join(target.OutDir(), out)) + } + } +} diff --git a/src/query/print.go b/src/query/print.go new file mode 100644 index 0000000000..6dfa9fca27 --- /dev/null +++ b/src/query/print.go @@ -0,0 +1,174 @@ +package query + +import "core" +import "fmt" + +// Produces a Python call which would (hopefully) regenerate the same build rule if run. +// This is of course not ideal since they were almost certainly created as a java_library +// or some similar wrapper rule, but we've lost that information by now. +func QueryPrint(graph *core.BuildGraph, labels []core.BuildLabel) { + for _, label := range labels { + target := graph.TargetOrDie(label) + fmt.Printf("%s:\n", label) + fmt.Printf(" build_rule(\n") + fmt.Printf(" name = '%s'\n", target.Label.Name) + if len(target.Sources) > 0 { + fmt.Printf(" srcs = [\n") + for _, src := range target.Sources { + fmt.Printf(" '%s',\n", src) + } + fmt.Printf(" ],\n") + } else if target.NamedSources != nil { + fmt.Printf(" srcs = {\n") + for name, srcs := range target.NamedSources { + fmt.Printf(" '%s': [\n", name) + for _, src := range srcs { + fmt.Printf(" '%s'\n", src) + } + fmt.Printf(" ],\n") + } + fmt.Printf(" },\n") + } + if len(target.DeclaredOutputs()) > 0 { + fmt.Printf(" outs = [\n") + for _, out := range target.DeclaredOutputs() { + fmt.Printf(" '%s',\n", out) + } + fmt.Printf(" ],\n") + } + fmt.Printf(" cmd = '%s'\n", target.Command) + if target.TestCommand != "" { + fmt.Printf(" test_cmd = '%s'\n", target.TestCommand) + } + pythonBool("binary", target.IsBinary) + pythonBool("test", target.IsTest) + pythonBool("needs_transitive_deps", target.NeedsTransitiveDependencies) + pythonBool("output_is_complete", target.OutputIsComplete) + if target.ContainerSettings != nil { + fmt.Printf(" container = {\n") + fmt.Printf(" 'docker_image': '%s',\n", target.ContainerSettings.DockerImage) + fmt.Printf(" 'docker_user': '%s',\n", target.ContainerSettings.DockerUser) + fmt.Printf(" 'docker_run_args': '%s',\n", target.ContainerSettings.DockerRunArgs) + } else { + pythonBool("container", target.Containerise) + } + pythonBool("no_test_output", target.NoTestOutput) + pythonBool("test_only", target.TestOnly) + pythonBool("skip_cache", target.SkipCache) + labelList("deps", excludeLabels(target.DeclaredDependencies, target.ExportedDependencies), target) + labelList("exported_deps", target.ExportedDependencies, target) + labelList("tools", target.Tools, target) + if len(target.Data) > 0 { + fmt.Printf(" data = [\n") + for _, datum := range target.Data { + fmt.Printf(" '%s',\n", datum) + } + fmt.Printf(" ],\n") + } + stringList("labels", excludeStrings(target.Labels, target.Requires)) + stringList("hashes", target.Hashes) + stringList("licences", target.Licences) + stringList("test_outputs", target.TestOutputs) + stringList("requires", target.Requires) + if len(target.Provides) > 0 { + fmt.Printf(" provides = {\n") + for k, v := range target.Provides { + if v.PackageName == target.Label.PackageName { + fmt.Printf(" '%s': ':%s',\n", k, v.Name) + } else { + fmt.Printf(" '%s': '%s',\n", k, v) + } + } + fmt.Printf(" },\n") + } + if target.Flakiness > 0 { + fmt.Printf(" flaky = %d,\n", target.Flakiness) + } + if target.BuildTimeout > 0 { + fmt.Printf(" timeout = %d,\n", target.BuildTimeout) + } + if target.TestTimeout > 0 { + fmt.Printf(" test_timeout = %d,\n", target.TestTimeout) + } + if len(target.Visibility) > 0 { + fmt.Printf(" visibility = [\n") + for _, vis := range target.Visibility { + if vis.PackageName == "" && vis.IsAllSubpackages() { + fmt.Printf(" 'PUBLIC',\n") + } else { + fmt.Printf(" '%s',\n", vis) + } + } + fmt.Printf(" ],\n") + } + fmt.Printf(" building_description = '%s',\n", target.BuildingDescription) + if target.PreBuildFunction != 0 { + fmt.Printf(" pre_build = ,\n") // Don't have any sensible way of printing this. + } + if target.PostBuildFunction != 0 { + fmt.Printf(" post_build = ,\n") // Don't have any sensible way of printing this. + } + fmt.Printf(" )\n\n") + } +} + +func pythonBool(s string, b bool) { + if b { + fmt.Printf(" %s = True,\n", s) + } +} + +func labelList(s string, l []core.BuildLabel, target *core.BuildTarget) { + if len(l) > 0 { + fmt.Printf(" %s = [\n", s) + for _, d := range l { + if d.PackageName == target.Label.PackageName { + fmt.Printf(" ':%s',\n", d.Name) + } else { + fmt.Printf(" '%s',\n", d) + } + } + fmt.Printf(" ],\n") + } +} + +func stringList(s string, l []string) { + if len(l) > 0 { + fmt.Printf(" %s = [\n", s) + for _, d := range l { + fmt.Printf(" '%s',\n", d) + } + fmt.Printf(" ],\n") + } +} + +// excludeLabels returns a filtered slice of labels from l that are not in excl. +func excludeLabels(l, excl []core.BuildLabel) []core.BuildLabel { + var ret []core.BuildLabel + // This is obviously quadratic but who cares, the lists will not be long. +outer: + for _, x := range l { + for _, y := range excl { + if x == y { + continue outer + } + } + ret = append(ret, x) + } + return ret +} + +// excludeStrings returns a filtered slice of strings from l that are not in excl. +func excludeStrings(l, excl []string) []string { + var ret []string +outer: + for _, x := range l { + for _, y := range excl { + if x == y { + continue outer + } + } + ret = append(ret, x) + } + return ret +} diff --git a/src/query/print_test.go b/src/query/print_test.go new file mode 100644 index 0000000000..ea9521c6b4 --- /dev/null +++ b/src/query/print_test.go @@ -0,0 +1,66 @@ +// Test to make sure we don't forget about adding new fields to print +// (because I keep doing that...) + +package query + +import "reflect" +import "testing" + +import "core" + +// Add fields to this list *after* you teach print about them. +var KnownFields = map[string]bool{ + "BuildTimeout": true, + "BuildingDescription": true, + "Command": true, + "Containerise": true, + "ContainerSettings": true, + "Data": true, + "DeclaredDependencies": true, + "ExportedDependencies": true, + "Flakiness": true, + "Hashes": true, + "IsBinary": true, + "IsTest": true, + "Label": true, // this includes the target's name + "Labels": true, + "Licences": true, + "NamedSources": true, + "NeedsTransitiveDependencies": true, + "NoTestOutput": true, + "OutputIsComplete": true, + "outputs": true, + "PreBuildFunction": true, + "PostBuildFunction": true, + "Provides": true, + "Requires": true, + "SkipCache": true, + "Sources": true, + "TestCommand": true, + "TestOnly": true, + "TestOutputs": true, + "TestTimeout": true, + "Tools": true, + "Visibility": true, + + // These aren't part of the declaration, only used internally. + "Dependencies": true, + "state": true, + "Results": true, + "PreBuildHash": true, + "PostBuildHash": true, + "resolvedDependencies": true, + "RuleHash": true, + "mutex": true, +} + +func TestAllFieldsArePresentAndAccountedFor(t *testing.T) { + target := core.BuildTarget{} + val := reflect.ValueOf(target) + for i := 0; i < val.Type().NumField(); i++ { + field := val.Type().Field(i) + if !KnownFields[field.Name] { + t.Errorf("Unaccounted field in 'query print': %s", field.Name) + } + } +} diff --git a/src/query/query_step.go b/src/query/query_step.go new file mode 100644 index 0000000000..ddd366df53 --- /dev/null +++ b/src/query/query_step.go @@ -0,0 +1,24 @@ +// Basic query language for Please. +// +// Currently supported operations: +// 'deps': 'plz query deps //src:please' +// shows the dependency graph of this target. +// 'somepath': 'plz query somepath //src:please //src/parse/rules:java_rules_pyc' +// finds a route between these two targets, if there is one. +// useful for saying 'why on earth do I depend on that thing?' +// 'alltargets': 'plz query alltargets //src/...' +// shows all targets currently in the graph. careful in large repos! +// 'print': 'plz query print //src:please' +// produces a python-like function call that would define the rule. +// 'completions': 'plz query completions //sr' +// produces a list of possible completions for the given stem. +// 'affectedtests': 'plz query affectedtests path/to/changed_file.py' +// produces a list of test targets which have a transitive dependency on +// the given file. +// 'input': 'plz query input //src:label' produces a list of all the files +// (including transitive deps) that are referenced by this rule. +package query + +import "github.com/op/go-logging" + +var log = logging.MustGetLogger("query") diff --git a/src/query/somepath.go b/src/query/somepath.go new file mode 100644 index 0000000000..978cd60e59 --- /dev/null +++ b/src/query/somepath.go @@ -0,0 +1,30 @@ +package query + +import "fmt" + +import "core" + +// Finds and returns a path between two targets. +// Useful for a "why on earth do I depend on this thing" type query. +func QuerySomePath(graph *core.BuildGraph, label1 core.BuildLabel, label2 core.BuildLabel) { + target1 := graph.TargetOrDie(label1) + target2 := graph.TargetOrDie(label2) + if !printSomePath(graph, target1, target2) && !printSomePath(graph, target2, target1) { + fmt.Printf("Couldn't find any dependency path between %s and %s\n", label1, label2) + } +} + +// This is just a simple DFS through the graph. +func printSomePath(graph *core.BuildGraph, target1, target2 *core.BuildTarget) bool { + if target1 == target2 { + fmt.Printf("Found path:\n %s\n", target1.Label) + return true + } + for _, target := range graph.ReverseDependencies(target2) { + if printSomePath(graph, target1, target) { + fmt.Printf(" %s\n", target2.Label) + return true + } + } + return false +} diff --git a/src/run/BUILD b/src/run/BUILD new file mode 100644 index 0000000000..b87811b951 --- /dev/null +++ b/src/run/BUILD @@ -0,0 +1,10 @@ +go_library( + name = 'run', + srcs = glob(['*.go'], excludes=['*_test.go']), + deps = [ + '//src/core', + '//src/build', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) diff --git a/src/run/run_step.go b/src/run/run_step.go new file mode 100644 index 0000000000..f79ba038e0 --- /dev/null +++ b/src/run/run_step.go @@ -0,0 +1,36 @@ +// Code for running targets directly through Please. + +package run + +import "fmt" +import "os" +import "strings" +import "syscall" + +import "core" +import "build" + +import "github.com/op/go-logging" + +var log = logging.MustGetLogger("run") + +// Implements the running part of 'plz run'. +func Run(graph *core.BuildGraph, label core.BuildLabel, args []string) { + target := graph.Target(label) + if target == nil { + log.Fatalf("Unknown target %s", label) + } else if !target.IsBinary { + log.Fatalf("Target %s cannot be run; it's not marked as binary", label) + } + // ReplaceSequences always quotes stuff in case it contains spaces or special characters, + // that works fine if we interpret it as a shell but not to pass it as an argument here. + cmd := "plz-out/bin/" + strings.Trim(build.ReplaceSequences(target, fmt.Sprintf("$(exe %s)", target.Label)), "\"") + // Handle targets where $(exe ...) returns something nontrivial (used to be the case for + // java_binary rules, currently not really needed but probably more futureproof) + splitCmd := strings.Split(cmd, " ") + args = append(splitCmd, args...) + log.Info("Running target %s...", strings.Join(args, " ")) + if err := syscall.Exec(splitCmd[0], args, os.Environ()); err != nil { + log.Fatalf("Error running command %s: %s", strings.Join(args, " "), err) + } +} diff --git a/src/test/BUILD b/src/test/BUILD new file mode 100644 index 0000000000..1f12a781ec --- /dev/null +++ b/src/test/BUILD @@ -0,0 +1,74 @@ +go_library( + name = 'test', + srcs = glob(['*.go'], excludes=['*_test.go']), + deps = [ + '//src/core', + '//src/build', + '//third_party/go:cover', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) + +go_test( + name = 'results_test', + srcs = ['results_test.go'], + deps = [ + ':test', + ], + data = glob(['test_data/*']) +) + +go_test( + name = 'container_test', + srcs = ['container_test.go'], + data = ['test_data/container_data.txt'], + container = True +) + +go_test( + name = 'container_args_test', + srcs = ['container_args_test.go'], + container = { + 'docker_run_args': '-e TEST_VALUE=WIBBLE', + } +) + +go_test( + name = 'coverage_test', + srcs = ['coverage_test.go'], + data = [ + 'test_data/python-coverage.xml', + 'test_data/go_coverage.txt', + 'test_data/go_coverage_2.txt', + 'test_data/go_coverage_3.txt', + ], + deps = [ + ':test', + ], +) + +# This rule tests the no_test_output flag. If that isn't honoured +# plz would report a test failure because results were missing. +gentest( + name = 'no_test_output_test', + test_cmd = 'echo SUCCESS', + no_test_output = True +) + +# This tests that data files exist in the correct location, and +# indirectly performs a basic test of sh_test which we don't use elsewhere. +sh_test( + name = 'data_files_test', + src = 'data_files_test.sh', + data = ['test_data/container_data.txt'], +) + +# This test is here as a convenience to test the flakiness functionality. +# It's just using random internally so won't pass consistently. +python_test( + name = 'flakiness_test', + srcs = ['flakiness_test.py'], + flaky = 5, + labels = ['manual'], +) diff --git a/src/test/container.go b/src/test/container.go new file mode 100644 index 0000000000..c50bc4cfa9 --- /dev/null +++ b/src/test/container.go @@ -0,0 +1,115 @@ +// Support for containerising tests. Currently Docker only. + +package test + +import "fmt" +import "io/ioutil" +import "os/exec" +import "path" +import "strings" +import "time" + +import "build" +import "core" + +func runContainerisedTest(state *core.BuildState, target *core.BuildTarget) ([]byte, error) { + testDir := path.Join(core.RepoRoot, target.TestDir()) + replacedCmd := build.ReplaceTestSequences(target, target.TestCommand) + replacedCmd += " " + strings.Join(state.TestArgs, " ") + containerName := state.Config.Docker.DefaultImage + if target.ContainerSettings != nil && target.ContainerSettings.DockerImage != "" { + containerName = target.ContainerSettings.DockerImage + } + // Gentle hack: remove the absolute path from the command + replacedCmd = strings.Replace(replacedCmd, path.Join(core.RepoRoot, target.TestDir()), "/tmp/test", -1) + // Fiddly hack follows to handle docker run --rm failing saying "Cannot destroy container..." + // "Driver aufs failed to remove root filesystem... device or resource busy" + cidfile := path.Join(testDir, ".container_id") + defer retrieveResultsAndRemoveContainer(target, cidfile) + // Using C.UTF-8 for LC_ALL because it works. Not sure it's strictly + // correct to mix that with LANG=en_GB.UTF-8 + command := []string{"run", "--cidfile", cidfile, "-e", "LC_ALL=C.UTF-8"} + if target.ContainerSettings != nil { + if target.ContainerSettings.DockerRunArgs != "" { + command = append(command, strings.Split(target.ContainerSettings.DockerRunArgs, " ")...) + } + if target.ContainerSettings.DockerUser != "" { + command = append(command, "-u", target.ContainerSettings.DockerUser) + } + } else { + command = append(command, state.Config.Docker.RunArgs...) + } + for _, env := range core.BuildEnvironment(state, target, true) { + command = append(command, "-e", env) + } + replacedCmd = "mkdir -p /tmp/test && cp -r /tmp/test_in/* /tmp/test && cd /tmp/test && " + replacedCmd + command = append(command, "-v", testDir+":/tmp/test_in", "-w", "/tmp/test_in", containerName, "bash", "-c", replacedCmd) + if state.PrintCommands { + log.Notice("Running containerised test %s: docker %s", target.Label, strings.Join(command, " ")) + } else { + log.Debug("Running containerised test %s: docker %s", target.Label, strings.Join(command, " ")) + } + cmd := exec.Command("docker", command...) + cmd.Dir = target.TestDir() + return core.ExecWithTimeout(cmd, target.TestTimeout, state.Config.Test.Timeout) +} + +func runPossiblyContainerisedTest(state *core.BuildState, target *core.BuildTarget) (out []byte, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("%s", r) + } + }() + + if target.Containerise { + out, err = runContainerisedTest(state, target) + if err != nil && state.Config.Docker.AllowLocalFallback { + log.Warning("Failed to run %s containerised: %s %s. Falling back to local version.", + target.Label, out, err) + return runTest(state, target, state.Config.Test.Timeout) + } + return out, err + } + return runTest(state, target, state.Config.Test.Timeout) +} + +// retrieveResultsAndRemoveContainer copies the test.results file out of the Docker container and into +// the expected location. It then removes the container. +func retrieveResultsAndRemoveContainer(target *core.BuildTarget, containerFile string) { + cid, err := ioutil.ReadFile(containerFile) + if err != nil { + log.Warning("Failed to read Docker container file %s", containerFile) + return + } + retrieveFile(target, cid, "test.results", true) + if core.State.NeedCoverage { + retrieveFile(target, cid, "test.coverage", false) + } + for _, output := range target.TestOutputs { + retrieveFile(target, cid, output, false) + } + // Give this some time to complete. Processes inside the container might not be ready + // to shut down immediately. + timeout := core.State.Config.Docker.RemoveTimeout + for i := 0; i < 5; i++ { + cmd := exec.Command("docker", "rm", string(cid)) + if _, err := core.ExecWithTimeout(cmd, timeout, timeout); err == nil { + return + } + time.Sleep(100 * time.Millisecond) + } +} + +// retrieveFile retrieves a single file (or directory) from a Docker container. +func retrieveFile(target *core.BuildTarget, cid []byte, filename string, warn bool) { + log.Debug("Attempting to retrieve file %s for %s...", filename, target.Label) + timeout := core.State.Config.Docker.ResultsTimeout + cmd := exec.Command("docker", "cp", string(cid)+":/tmp/test/"+filename, target.TestDir()) + if out, err := core.ExecWithTimeout(cmd, timeout, timeout); err != nil { + if warn { + log.Warning("Failed to retrieve results for %s: %s [%s]", target.Label, err, out) + } else { + log.Debug("Failed to retrieve results for %s: %s [%s]", target.Label, err, out) + } + } +} diff --git a/src/test/container_args_test.go b/src/test/container_args_test.go new file mode 100644 index 0000000000..2e5268269f --- /dev/null +++ b/src/test/container_args_test.go @@ -0,0 +1,11 @@ +package test + +import "os" +import "testing" + +func TestContainerArgs(t *testing.T) { + // This value will only be set if we passed the argument to Docker correctly. + if env := os.Getenv("TEST_VALUE"); env != "WIBBLE" { + t.Errorf("Incorrect TEST_VALUE env var; was %s", env) + } +} diff --git a/src/test/container_test.go b/src/test/container_test.go new file mode 100644 index 0000000000..262b38876d --- /dev/null +++ b/src/test/container_test.go @@ -0,0 +1,27 @@ +package test + +import "io/ioutil" +import "os" +import "path/filepath" +import "testing" + +func TestInContainer(t *testing.T) { + abs, err := filepath.Abs(os.Args[0]) + if err != nil { + t.Errorf("Couldn't make path absolute: %s", err) + } else if abs != "/tmp/test/container_test" { + t.Errorf("Looks like we're not running inside a container: %s", os.Args[0]) + } +} + +func TestContainerData(t *testing.T) { + data, err := ioutil.ReadFile("src/test/test_data/container_data.txt") + if err != nil { + t.Errorf("Failed to read data file: %s", err) + } else { + expected := "This file will only appear in the container if data is working properly.\n" + if string(data) != expected { + t.Errorf("Unexpected file contents: expected [%s], was [%s]", expected, string(data)) + } + } +} diff --git a/src/test/coverage.go b/src/test/coverage.go new file mode 100644 index 0000000000..8eb322c62f --- /dev/null +++ b/src/test/coverage.go @@ -0,0 +1,161 @@ +// Code for parsing coverage output in various formats. + +package test + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "core" +) + +// Parses test coverage for a single target from its output file. +func parseTestCoverage(target *core.BuildTarget, outputFile string) (core.TestCoverage, error) { + coverage := core.NewTestCoverage() + data, err := ioutil.ReadFile(outputFile) + if err != nil && os.IsNotExist(err) { + return coverage, nil // Tests aren't required to produce coverage files. + } else if err != nil { + return coverage, err + } else if len(data) == 0 { + return coverage, fmt.Errorf("Empty coverage output") + } else if looksLikeGoCoverageResults(data) { + // TODO(pebers): this is a little wasteful, we've already read the file once and we must do it again. + return coverage, parseGoCoverageResults(target, &coverage, outputFile) + } else { + return coverage, parseXmlCoverageResults(target, &coverage, data) + } +} + +// Adds empty coverage entries for any files covered by the original query that we +// haven't discovered through tests to the overall report. +// The coverage reports only contain information about files that were covered during +// tests, so it's important that we identify anything with zero coverage here. +// This is made trickier by attempting to reconcile coverage targets from languages like +// Java that don't preserve the original file structure, which requires a slightly fuzzy match. +func AddOriginalTargetsToCoverage(state *core.BuildState, include, exclude []string) { + // First we collect all the source files from all relevant targets + allFiles := map[string]bool{} + doneTargets := map[*core.BuildTarget]bool{} + for _, label := range state.OriginalTargets { + if label.IsAllTargets() { + for _, target := range state.Graph.PackageOrDie(label.PackageName).Targets { + collectAllFiles(state, target, allFiles, doneTargets, include, exclude) + } + } else { + collectAllFiles(state, state.Graph.TargetOrDie(label), allFiles, doneTargets, include, exclude) + } + } + + // Now merge the recorded coverage so far into them + recordedCoverage := state.Coverage + state.Coverage = core.TestCoverage{Tests: recordedCoverage.Tests, Files: map[string][]core.LineCoverage{}} + mergeCoverage(state, recordedCoverage, allFiles) +} + +// Collects all the source files from a single target +func collectAllFiles(state *core.BuildState, target *core.BuildTarget, allFiles map[string]bool, doneTargets map[*core.BuildTarget]bool, include, exclude []string) { + doneTargets[target] = true + if !target.ShouldInclude(include, exclude) { + return + } + // Small hack here; explore these targets when we don't have any sources yet. Helps languages + // like Java where we generate a wrapper target with a complete one immediately underneath. + if !target.OutputIsComplete || len(allFiles) == 0 { + for _, dep := range target.Dependencies { + if !doneTargets[dep] { + collectAllFiles(state, dep, allFiles, doneTargets, include, exclude) + } + } + } + if target.IsTest { + return // Test sources don't count for coverage. + } + for _, path := range target.AllSourcePaths(state.Graph) { + extension := filepath.Ext(path) + for _, ext := range state.Config.Cover.FileExtension { + if ext == extension { + allFiles[path] = target.IsTest || target.TestOnly // Skip test source files from actual coverage display + break + } + } + } +} + +// Merges recorded coverage with the list of all existing files. +func mergeCoverage(state *core.BuildState, recordedCoverage core.TestCoverage, allFiles map[string]bool) { + for file, coverage := range recordedCoverage.Files { + state.Coverage.Files[file] = coverage + allFiles[file] = true + } + // For any files left over now, enter them in as 100% uncovered. + // This is pessimistic but there's not much we can do at this point. + for file, done := range allFiles { + if !done { + s := make([]core.LineCoverage, countLines(file)) + if len(s) > 0 { + for i := 0; i < len(s); i++ { + s[i] = core.Uncovered + } + state.Coverage.Files[file] = s + } + } + } +} + +// Returns the number of lines in a file. +func countLines(path string) int { + data, _ := ioutil.ReadFile(path) + return bytes.Count(data, []byte{'\n'}) +} + +// WriteCoverageToFileOrDie writes the collected coverage data to a file in JSON format. Dies on failure. +func WriteCoverageToFileOrDie(coverage core.TestCoverage, filename string) { + out := jsonCoverage{Tests: map[string]map[string]string{}} + for label, coverage := range coverage.Tests { + out.Tests[label.String()] = convertCoverage(coverage) + } + out.Files = convertCoverage(coverage.Files) + if b, err := json.MarshalIndent(out, "", " "); err != nil { + log.Fatalf("Failed to encode json: %s", err) + } else if err := ioutil.WriteFile(filename, b, 0644); err != nil { + log.Fatalf("Failed to write coverage results to %s: %s", filename, err) + } +} + +func convertCoverage(in map[string][]core.LineCoverage) map[string]string { + ret := map[string]string{} + for k, v := range in { + ret[k] = core.TestCoverageString(v) + } + return ret +} + +// Used to prepare core.TestCoverage objects for JSON marshalling. +type jsonCoverage struct { + Tests map[string]map[string]string `json:"tests"` + Files map[string]string `json:"files"` +} + +// RemoveFilesFromCoverage removes any files with extensions matching the given set from coverage. +func RemoveFilesFromCoverage(coverage core.TestCoverage, extensions []string) { + for _, files := range coverage.Tests { + removeFilesFromCoverage(files, extensions) + } + removeFilesFromCoverage(coverage.Files, extensions) +} + +func removeFilesFromCoverage(files map[string][]core.LineCoverage, extensions []string) { + for filename := range files { + for _, ext := range extensions { + if strings.HasSuffix(filename, ext) { + delete(files, filename) + } + } + } +} diff --git a/src/test/coverage_test.go b/src/test/coverage_test.go new file mode 100644 index 0000000000..78bc4a98e1 --- /dev/null +++ b/src/test/coverage_test.go @@ -0,0 +1,158 @@ +package test + +import ( + "testing" + + "golang.org/x/tools/cover" + + "core" +) + +var target = &core.BuildTarget{Label: core.BuildLabel{PackageName: "src/test", Name: "coverage_test"}} + +const pythonCoverageFile = "src/test/test_data/python-coverage.xml" +const goCoverageFile = "src/test/test_data/go_coverage.txt" +const goCoverageFile2 = "src/test/test_data/go_coverage_2.txt" +const goCoverageFile3 = "src/test/test_data/go_coverage_3.txt" + +// Test that tests aren't required to produce coverage, ie. it's not an error if the file doesn't exist. +func TestCoverageNotRequired(t *testing.T) { + coverage, err := parseTestCoverage(target, "src/test/test_data/blah.xml") + if err != nil { + t.Errorf("Incorrectly produced error attempting to read missing coverage file: %s", err) + } + if len(coverage.Files) != 0 { + t.Errorf("Incorrectly reported some coverage results when there should be none.") + } +} + +// Test that the target is recorded in the file list. +func TestTargetIsRecorded(t *testing.T) { + coverage, err := parseTestCoverage(target, pythonCoverageFile) + if err != nil { + t.Errorf("Failed to read coverage file %s", pythonCoverageFile) + } + if len(coverage.Tests) != 1 { + t.Errorf("Expected exactly one test label recorded (got %d)", len(coverage.Tests)) + } +} + +// Test the sample Python test output file. +func TestPythonResults(t *testing.T) { + coverage, err := parseTestCoverage(target, pythonCoverageFile) + if err != nil { + t.Errorf("Failed to read coverage file %s", pythonCoverageFile) + } + if len(coverage.Files) != 4 { + t.Errorf("Expected exactly four files covered by this test") + } + lines, present := coverage.Files["src/build/python/pex_test.py"] + if !present { + t.Errorf("Coverage info for src/build/python/pex_test.py not recorded.") + } + if len(lines) != 24 { + t.Errorf("Expected exactly 24 lines of coverage information, was %d.", len(lines)) + } + outputStr := core.TestCoverageString(lines) + expected := "NNCNNCNCNCNCNNUNCNNCNNCU" + if outputStr != expected { + t.Errorf("Incorrect coverage output; was %s, expected %s", outputStr, expected) + } +} + +// Test the sample Go test output file. +func TestGoResults(t *testing.T) { + coverage, err := parseTestCoverage(target, goCoverageFile) + if err != nil { + t.Errorf("Failed to read coverage file %s", goCoverageFile) + } + if len(coverage.Files) != 7 { + t.Errorf("Expected exactly seven files covered by this test") + } + lines, present := coverage.Files["src/core/file_label.go"] + if !present { + t.Errorf("Coverage info for src/core/file_label.go not recorded.") + } + if len(lines) != 55 { + t.Errorf("Expected exactly 55 lines of coverage information, was %d.", len(lines)) + } + outputStr := core.TestCoverageString(lines) + expected := "NNNNNNNNNNNNNNNUUUNUUUNUUUNUUUNNNNNNNNNNUUUNUUUNUUUNUUU" + if len(expected) != 55 { + t.Errorf("oops, expected string is wrong") + } + if outputStr != expected { + t.Errorf("Incorrect coverage output; was %s, expected %s", outputStr, expected) + } +} + +// Test another sample Go file which has been observed to be wrong. +func TestGoResults2(t *testing.T) { + coverage, err := parseTestCoverage(target, goCoverageFile2) + if err != nil { + t.Errorf("Failed to read coverage file %s", goCoverageFile2) + } + if len(coverage.Files) != 1 { + t.Errorf("Expected exactly one file covered by this test") + } + lines, present := coverage.Files["src/core/state.go"] + if !present { + t.Errorf("Coverage info for src/core/file_label.go not recorded.") + } + if len(lines) != 273 { + t.Errorf("Expected exactly 273 lines of coverage information, was %d.", len(lines)) + } + + assertLine(t, lines, 231, core.NotExecutable) + assertLine(t, lines, 232, core.Covered) + assertLine(t, lines, 233, core.Covered) + assertLine(t, lines, 234, core.Covered) + assertLine(t, lines, 235, core.Covered) + assertLine(t, lines, 236, core.Covered) + assertLine(t, lines, 237, core.Covered) + assertLine(t, lines, 238, core.Covered) + assertLine(t, lines, 239, core.Covered) + assertLine(t, lines, 240, core.Covered) +} + +func TestGoResults3(t *testing.T) { + coverage, err := parseTestCoverage(target, goCoverageFile3) + if err != nil { + t.Errorf("Failed to read coverage file %s", goCoverageFile3) + } + if len(coverage.Files) != 1 { + t.Errorf("Expected exactly one file covered by this test") + } + lines, present := coverage.Files["src/misc/plz_diff_graphs.go"] + if !present { + t.Errorf("Coverage info for src/misc/plz_diff_graphs.go not recorded.") + } + if len(lines) != 127 { + t.Errorf("Expected exactly 127 lines of coverage information, was %d.", len(lines)) + } + + assertLine(t, lines, 67, core.NotExecutable) + assertLine(t, lines, 68, core.Covered) + assertLine(t, lines, 69, core.Covered) + assertLine(t, lines, 81, core.NotExecutable) +} + +// Direct test on the block-parsing function. +func TestParseBlocks(t *testing.T) { + lines := parseBlocks([]cover.ProfileBlock{ + cover.ProfileBlock{StartLine: 2, EndLine: 3, Count: 1}, + }) + if len(lines) != 3 { + t.Errorf("Wrong number of lines, should have been %d, was %d", 3, len(lines)) + } + assertLine(t, lines, 1, core.NotExecutable) + assertLine(t, lines, 2, core.Covered) + assertLine(t, lines, 3, core.Covered) +} + +func assertLine(t *testing.T, lines []core.LineCoverage, i int, expected core.LineCoverage) { + i-- // 1-indexed + if lines[i] != expected { + t.Errorf("Line %d incorrect, should be %d, was %d", i, expected, lines[i]) + } +} diff --git a/src/test/data_files_test.sh b/src/test/data_files_test.sh new file mode 100755 index 0000000000..dce652cd82 --- /dev/null +++ b/src/test/data_files_test.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Check this file exists in the expected location. +if [ ! -f src/test/test_data/container_data.txt ]; then + exit 1 +fi diff --git a/src/test/flakiness_test.py b/src/test/flakiness_test.py new file mode 100644 index 0000000000..814c8877ce --- /dev/null +++ b/src/test/flakiness_test.py @@ -0,0 +1,13 @@ +import random +import unittest + + +class FlakinessTest(unittest.TestCase): + + def test_flakiness(self): + """This test is deliberately flaky to test that functionality.""" + self.assertLess(random.random(), 0.3) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/test/go_coverage.go b/src/test/go_coverage.go new file mode 100644 index 0000000000..96c6e9419d --- /dev/null +++ b/src/test/go_coverage.go @@ -0,0 +1,47 @@ +// Code for parsing Go's coverage output. +// +// Go comes with a built-in coverage tool and a package to parse its output format. <3 +// Its format is actually rather richer than ours and can handle sub-line coverage etc. +// We may look into taking more advantage of that later... + +package test + +import "bytes" +import "golang.org/x/tools/cover" + +import "core" + +func looksLikeGoCoverageResults(results []byte) bool { + return bytes.HasPrefix(results, []byte("mode: ")) +} + +func parseGoCoverageResults(target *core.BuildTarget, coverage *core.TestCoverage, filename string) error { + profiles, err := cover.ParseProfiles(filename) + if err != nil { + return err + } + for _, profile := range profiles { + // Prepending src/ is a bit of a hack but it's oh so easy... + coverage.Files["src/"+profile.FileName] = parseBlocks(profile.Blocks) + } + coverage.Tests[target.Label] = coverage.Files + return nil +} + +func parseBlocks(blocks []cover.ProfileBlock) []core.LineCoverage { + if len(blocks) == 0 { + return nil + } + lastLine := blocks[len(blocks)-1].EndLine + ret := make([]core.LineCoverage, lastLine, lastLine) + for _, block := range blocks { + for line := block.StartLine - 1; line < block.EndLine; line++ { + if block.Count > 0 { + ret[line] = core.Covered + } else { + ret[line] = core.Uncovered + } + } + } + return ret +} diff --git a/src/test/go_results.go b/src/test/go_results.go new file mode 100644 index 0000000000..e834d7331c --- /dev/null +++ b/src/test/go_results.go @@ -0,0 +1,67 @@ +// Parser for output from Go's testing package. +// +// This is a fairly straightforward microformat so pretty easy to parse ourselves. +// There's at least one package out there to convert it to JUnit XML but not worth +// the complexity of getting that installed as a standalone tool. + +package test + +import ( + "bytes" + "fmt" + "regexp" + "strings" + + "core" +) + +func looksLikeGoTestResults(results []byte) bool { + return bytes.HasPrefix(results, []byte("===")) +} + +// Not sure what the -6 suffixes are about. +var testStart = regexp.MustCompile("^=== RUN (.*)(?:-6)?$") +var testResult = regexp.MustCompile("^--- (PASS|FAIL|SKIP): (.*)(?:-6)? \\((.*)s\\)$") + +func parseGoTestResults(data []byte) (core.TestResults, error) { + results := core.TestResults{} + lines := bytes.Split(data, []byte{'\n'}) + lastTestStarted := "" + for i := 0; i < len(lines); i++ { + testStartMatches := testStart.FindSubmatch(lines[i]) + testResultMatches := testResult.FindSubmatch(lines[i]) + if testStartMatches != nil { + lastTestStarted = strings.TrimSpace(string(testStartMatches[1])) + } else if testResultMatches != nil { + testName := strings.TrimSpace(string(testResultMatches[2])) + if testName != lastTestStarted { + continue + } + results.NumTests++ + if bytes.Equal(testResultMatches[1], []byte("PASS")) { + results.Passed++ + results.Passes = append(results.Passes, testName) + } else if bytes.Equal(testResultMatches[1], []byte("SKIP")) { + results.Skipped++ + i++ // Skip following line too that has the reason for being skipped + } else { + output := "" + for j := i + 1; j < len(lines) && !bytes.HasPrefix(lines[j], []byte("===")); j++ { + output += string(lines[j]) + "\n" + i = j + } + results.Failed++ + results.Failures = append(results.Failures, core.TestFailure{ + Name: testName, Type: "FAILURE", Traceback: output, Stdout: "", Stderr: "", + }) + } + } else if bytes.Equal(lines[i], []byte("PASS")) { + // Do nothing, all's well. + } else if bytes.Equal(lines[i], []byte("FAIL")) { + if results.Failed == 0 { + return results, fmt.Errorf("Test indicated final failure but no failures found yet") + } + } + } + return results, nil +} diff --git a/src/test/results.go b/src/test/results.go new file mode 100644 index 0000000000..6d3b1f3f41 --- /dev/null +++ b/src/test/results.go @@ -0,0 +1,57 @@ +// Code for parsing the output of tests. + +package test + +import "fmt" +import "io/ioutil" +import "os" +import "path/filepath" + +import "core" + +func parseTestResults(target *core.BuildTarget, outputFile string, flakes int, cached bool) (core.TestResults, error) { + results, err := parseTestResultsDir(target, outputFile) + results.Flakes = flakes + results.Cached = cached + target.Results.Aggregate(results) + // Ensure that the target has a failure if we encountered an error + if err != nil && target.Results.Failed == 0 { + target.Results.NumTests++ + target.Results.Failed++ + } + return results, err +} + +func parseTestResultsImpl(target *core.BuildTarget, outputFile string) (core.TestResults, error) { + bytes, err := ioutil.ReadFile(outputFile) + if err != nil { + return core.TestResults{}, err + } + if len(bytes) == 0 { + return core.TestResults{}, fmt.Errorf("No results") + } else if looksLikeGoTestResults(bytes) { + return parseGoTestResults(bytes) + } else { + return parseJUnitXMLTestResults(bytes) + } +} + +func parseTestResultsDir(target *core.BuildTarget, outputDir string) (core.TestResults, error) { + results := core.TestResults{} + err := filepath.Walk(outputDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } else if !info.IsDir() { + fileResults, err := parseTestResultsImpl(target, path) + if err != nil { + return fmt.Errorf("Error parsing %s: %s", path, err) + } + results.Aggregate(fileResults) + } + return nil + }) + if err == nil && results.NumTests == 0 { + return results, fmt.Errorf("Didn't find any test results in %s", outputDir) + } + return results, err +} diff --git a/src/test/results_test.go b/src/test/results_test.go new file mode 100644 index 0000000000..fca2b221e5 --- /dev/null +++ b/src/test/results_test.go @@ -0,0 +1,150 @@ +package test + +import "testing" + +import "core" + +func TestGoFailure(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_failure.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 4, "tests") + assert(t, results.Passed, 2, "passes") + assert(t, results.Failed, 2, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoPassed(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_pass.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 4, "tests") + assert(t, results.Passed, 4, "passes") + assert(t, results.Failed, 0, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoMultipleFailure(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_multiple_failure.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 2, "tests") + assert(t, results.Passed, 0, "passes") + assert(t, results.Failed, 2, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoSkipped(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_skip.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 4, "tests") + assert(t, results.Passed, 3, "passes") + assert(t, results.Failed, 0, "failures") + assert(t, results.Skipped, 1, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestBuckXML(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/junit.xml", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 4, "tests") + assert(t, results.Passed, 4, "passes") + assert(t, results.Failed, 0, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestJUnitXML(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/xmlrunner-junit.xml", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 2, "tests") + assert(t, results.Passed, 1, "passes") + assert(t, results.Failed, 1, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestKarmaXML(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/karma-junit.xml", 1, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 10, "tests") + assert(t, results.Passed, 10, "passes") + assert(t, results.Failed, 0, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.Flakes, 1, "flakes") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestUnitTestXML(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/unittest.xml", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 2, "tests") + assert(t, results.Passed, 0, "passes") + assert(t, results.Failed, 2, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoSuite(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_suite.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 6, "tests") + assert(t, results.Passed, 4, "passes") + assert(t, results.Failed, 1, "failures") + assert(t, results.Skipped, 1, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoIgnoreUnknownOutput(t *testing.T) { + results, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_ignore_logs.txt", 0, false) + if err != nil { + t.Errorf("Unable to parse file: %s", err) + return + } + assert(t, results.NumTests, 4, "tests") + assert(t, results.Passed, 4, "passes") + assert(t, results.Failed, 0, "failures") + assert(t, results.Skipped, 0, "skipped tests") + assert(t, results.ExpectedFailures, 0, "expected failures") +} + +func TestGoFailIfUnknownTestPasses(t *testing.T) { + _, err := parseTestResults(new(core.BuildTarget), "src/test/test_data/go_test_unknown_test.txt", 0, false) + if err == nil { + t.Errorf("Results should not be parsable.") + } +} + +// because I'm already pining for self.assertEqual... +func assert(t *testing.T, actual int, expected int, description string) { + if actual != expected { + t.Errorf("Unexpected number of %s: should be %d, was %d", description, expected, actual) + } +} diff --git a/src/test/test_data/container_data.txt b/src/test/test_data/container_data.txt new file mode 100644 index 0000000000..7d2f09b8ed --- /dev/null +++ b/src/test/test_data/container_data.txt @@ -0,0 +1 @@ +This file will only appear in the container if data is working properly. diff --git a/src/test/test_data/go_coverage.txt b/src/test/test_data/go_coverage.txt new file mode 100644 index 0000000000..1a88d6772c --- /dev/null +++ b/src/test/test_data/go_coverage.txt @@ -0,0 +1,360 @@ +mode: set +core/build_target.go:134.54,143.2 7 0 +core/build_target.go:159.52,172.2 12 0 +core/build_target.go:177.44,179.2 1 0 +core/build_target.go:183.44,184.24 1 0 +core/build_target.go:184.24,186.6 1 0 +core/build_target.go:186.7,188.6 1 0 +core/build_target.go:195.45,197.2 1 0 +core/build_target.go:202.48,204.2 1 0 +core/build_target.go:207.71,209.45 2 0 +core/build_target.go:214.5,214.15 1 0 +core/build_target.go:209.45,210.51 1 0 +core/build_target.go:210.51,212.10 1 0 +core/build_target.go:218.90,220.36 2 0 +core/build_target.go:225.5,225.15 1 0 +core/build_target.go:220.36,221.51 1 0 +core/build_target.go:221.51,223.10 1 0 +core/build_target.go:229.48,230.69 1 0 +core/build_target.go:233.5,233.46 1 0 +core/build_target.go:238.5,238.16 1 0 +core/build_target.go:230.69,232.6 1 0 +core/build_target.go:233.46,234.30 1 0 +core/build_target.go:234.30,236.10 1 0 +core/build_target.go:242.58,244.58 1 0 +core/build_target.go:247.5,247.41 1 0 +core/build_target.go:259.5,259.17 1 0 +core/build_target.go:244.58,246.6 1 0 +core/build_target.go:247.41,248.73 1 0 +core/build_target.go:248.73,250.39 1 0 +core/build_target.go:250.39,252.14 1 0 +core/build_target.go:252.15,252.67 1 0 +core/build_target.go:252.67,253.71 1 0 +core/build_target.go:253.71,255.18 1 0 +core/build_target.go:264.62,265.46 1 0 +core/build_target.go:270.5,270.15 1 0 +core/build_target.go:265.46,266.32 1 0 +core/build_target.go:266.32,268.10 1 0 +core/build_target.go:274.65,275.53 1 0 +core/build_target.go:280.5,280.17 1 0 +core/build_target.go:275.53,276.25 1 0 +core/build_target.go:276.25,278.10 1 0 +core/build_target.go:284.73,285.53 1 0 +core/build_target.go:290.5,290.17 1 0 +core/build_target.go:285.53,286.25 1 0 +core/build_target.go:286.25,288.10 1 0 +core/build_target.go:298.51,301.31 3 0 +core/build_target.go:301.31,304.6 2 0 +core/build_target.go:304.7,306.6 1 0 +core/build_target.go:310.56,311.37 1 0 +core/build_target.go:316.5,316.17 1 0 +core/build_target.go:311.37,312.23 1 0 +core/build_target.go:312.23,314.10 1 0 +core/build_target.go:320.62,321.34 1 0 +core/build_target.go:326.5,326.17 1 0 +core/build_target.go:321.34,322.35 1 0 +core/build_target.go:322.35,324.10 1 0 +core/build_target.go:329.74,330.53 1 0 +core/build_target.go:340.5,340.98 1 0 +core/build_target.go:330.53,331.25 1 0 +core/build_target.go:331.25,332.39 1 0 +core/build_target.go:337.13,337.19 1 0 +core/build_target.go:332.39,334.14 1 0 +core/build_target.go:334.15,336.14 1 0 +core/build_target.go:344.70,345.44 1 0 +core/build_target.go:350.5,350.24 1 0 +core/build_target.go:345.44,346.64 1 0 +core/build_target.go:346.64,348.10 1 0 +core/build_target.go:353.75,354.35 1 0 +core/build_target.go:357.5,357.74 1 0 +core/build_target.go:354.35,356.6 1 0 +core/build_target.go:360.59,362.15 2 0 +core/build_target.go:375.5,375.14 1 0 +core/build_target.go:362.15,363.47 1 0 +core/build_target.go:366.9,366.39 1 0 +core/build_target.go:373.9,373.18 1 0 +core/build_target.go:363.47,365.10 1 0 +core/build_target.go:366.39,367.57 1 0 +core/build_target.go:367.57,368.48 1 0 +core/build_target.go:368.48,370.18 1 0 +core/build_target.go:378.58,379.35 1 0 +core/build_target.go:379.35,381.6 1 0 +core/build_target.go:384.66,385.43 1 0 +core/build_target.go:385.43,387.6 1 0 +core/build_target.go:392.37,394.2 1 0 +core/build_target.go:395.47,397.2 1 0 +core/build_target.go:398.42,400.2 1 0 +core/build_target.go:403.50,412.2 7 0 +core/build_target.go:428.39,433.2 4 0 +core/build_target.go:435.57,437.40 1 0 +core/build_target.go:442.5,442.56 1 0 +core/build_target.go:437.40,438.27 1 0 +core/build_target.go:438.27,440.10 1 0 +core/config.go:23.61,26.41 3 0 +core/config.go:29.5,29.42 1 0 +core/config.go:36.5,36.113 1 0 +core/config.go:39.5,39.23 1 0 +core/config.go:26.41,28.6 1 0 +core/config.go:30.5,30.69 1 0 +core/config.go:31.5,31.83 0 0 +core/config.go:32.5,33.113 1 0 +core/config.go:36.113,38.6 1 0 +core/config.go:42.43,75.2 32 0 +core/config.go:136.43,140.50 3 0 +core/config.go:143.5,144.22 2 0 +core/config.go:140.50,142.6 1 0 +core/file_label.go:16.58,18.2 1 0 +core/file_label.go:20.62,22.2 1 0 +core/file_label.go:24.44,26.2 1 0 +core/file_label.go:28.40,30.2 1 0 +core/file_label.go:41.64,43.2 1 0 +core/file_label.go:45.68,47.2 1 0 +core/file_label.go:49.50,51.2 1 0 +core/file_label.go:53.46,55.2 1 0 +core/graph.go:25.69,29.16 4 0 +core/graph.go:32.5,35.16 3 0 +core/graph.go:40.5,40.18 1 0 +core/graph.go:29.16,31.6 1 0 +core/graph.go:35.16,36.40 1 0 +core/graph.go:36.40,38.10 1 0 +core/graph.go:44.50,47.56 3 0 +core/graph.go:50.5,50.35 1 0 +core/graph.go:47.56,49.6 1 0 +core/graph.go:54.63,58.17 4 0 +core/graph.go:61.5,61.18 1 0 +core/graph.go:58.17,60.6 1 0 +core/graph.go:65.55,69.17 4 0 +core/graph.go:72.5,72.15 1 0 +core/graph.go:69.17,71.6 1 0 +core/graph.go:75.35,79.2 3 0 +core/graph.go:82.51,86.43 4 0 +core/graph.go:89.5,90.19 2 0 +core/graph.go:86.43,88.6 1 0 +core/graph.go:94.58,98.44 4 0 +core/graph.go:101.5,101.20 1 0 +core/graph.go:98.44,100.6 1 0 +core/graph.go:104.71,111.17 5 0 +core/graph.go:111.17,113.6 1 0 +core/graph.go:113.7,115.6 1 0 +core/graph.go:118.29,124.2 5 0 +core/graph.go:126.77,127.33 1 0 +core/graph.go:144.5,144.49 1 0 +core/graph.go:127.33,129.57 2 0 +core/graph.go:140.9,140.23 1 0 +core/graph.go:129.57,130.74 1 0 +core/graph.go:130.74,131.69 1 0 +core/graph.go:137.17,137.34 1 0 +core/graph.go:131.69,133.18 1 0 +core/graph.go:133.19,136.18 1 0 +core/graph.go:140.23,142.10 1 0 +core/graph.go:147.64,148.56 1 0 +core/graph.go:148.56,151.6 2 0 +core/graph.go:154.63,156.17 2 0 +core/graph.go:160.5,160.22 1 0 +core/graph.go:156.17,159.6 2 0 +core/state.go:47.60,49.2 1 0 +core/state.go:51.60,53.2 1 0 +core/state.go:55.59,57.2 1 0 +core/state.go:61.102,63.2 1 0 +core/state.go:65.77,70.2 4 0 +core/state.go:72.41,75.29 3 0 +core/state.go:78.5,78.25 1 0 +core/state.go:75.29,77.6 1 0 +core/state.go:81.66,82.52 1 0 +core/state.go:87.5,87.17 1 0 +core/state.go:82.52,83.30 1 0 +core/state.go:83.30,85.10 1 0 +core/state.go:90.114,99.2 1 0 +core/state.go:101.184,114.2 4 0 +core/state.go:116.140,125.2 1 0 +core/state.go:127.42,131.2 3 0 +core/state.go:133.99,151.2 1 0 +core/state.go:170.116,179.2 1 0 +core/state.go:213.56,217.48 2 0 +core/state.go:217.48,218.63 1 0 +core/state.go:218.63,219.43 1 0 +core/state.go:219.43,220.39 1 0 +core/state.go:220.39,222.18 1 0 +core/state.go:222.19,222.53 1 0 +core/state.go:222.53,224.18 1 0 +core/state.go:226.11,228.10 1 0 +core/state.go:233.50,235.37 2 0 +core/state.go:238.5,239.17 2 0 +core/state.go:235.37,237.6 1 0 +core/state.go:248.54,250.32 2 0 +core/state.go:253.5,253.27 1 0 +core/state.go:250.32,252.6 1 0 +core/utils.go:23.29,26.19 3 0 +core/utils.go:30.5,30.9 1 0 +core/utils.go:40.5,40.32 1 0 +core/utils.go:26.19,28.6 1 0 +core/utils.go:30.9,31.22 1 0 +core/utils.go:34.9,34.55 1 0 +core/utils.go:37.9,38.42 2 0 +core/utils.go:31.22,33.10 1 0 +core/utils.go:34.55,36.10 1 0 +core/utils.go:46.31,48.2 1 1 +core/utils.go:53.42,54.28 1 1 +core/utils.go:54.28,56.6 1 1 +core/utils.go:56.7,56.39 1 0 +core/utils.go:56.39,58.6 1 0 +core/utils.go:58.7,60.23 2 0 +core/utils.go:63.9,63.39 1 0 +core/utils.go:60.23,62.10 1 0 +core/utils.go:68.41,71.2 2 0 +core/utils.go:73.41,76.2 2 0 +core/utils.go:79.44,81.42 2 0 +core/utils.go:84.5,84.15 1 0 +core/utils.go:81.42,83.6 1 0 +core/utils.go:88.63,90.19 2 0 +core/utils.go:93.5,94.18 2 0 +core/utils.go:97.5,98.19 2 0 +core/utils.go:101.5,101.56 1 0 +core/utils.go:114.5,114.27 1 0 +core/utils.go:120.5,120.26 1 0 +core/utils.go:90.19,92.6 1 0 +core/utils.go:94.18,96.6 1 0 +core/utils.go:98.19,100.6 1 0 +core/utils.go:101.56,104.6 2 0 +core/utils.go:114.27,115.45 1 0 +core/utils.go:115.45,118.10 2 0 +core/utils.go:124.72,125.63 1 0 +core/utils.go:125.63,126.89 1 0 +core/utils.go:126.89,128.27 2 0 +core/utils.go:128.27,130.14 1 0 +core/utils.go:130.15,130.36 1 0 +core/utils.go:130.36,132.14 1 0 +core/utils.go:132.15,132.59 1 0 +core/utils.go:132.59,134.31 2 0 +core/utils.go:137.17,137.31 1 0 +core/utils.go:134.31,136.18 1 0 +core/utils.go:137.31,139.18 1 0 +core/utils.go:139.19,141.18 1 0 +core/utils.go:142.15,144.14 1 0 +core/utils.go:146.7,148.6 1 0 +core/utils.go:152.86,157.21 2 0 +core/utils.go:160.5,161.15 2 0 +core/utils.go:165.5,165.12 1 0 +core/utils.go:157.21,159.6 1 0 +core/utils.go:161.15,164.6 2 0 +core/utils.go:166.5,167.50 1 0 +core/utils.go:172.9,172.16 1 0 +core/utils.go:178.5,179.38 1 0 +core/utils.go:167.50,169.10 1 0 +core/utils.go:173.9,174.84 1 0 +core/utils.go:175.9,176.112 1 0 +core/utils.go:187.100,193.43 6 0 +core/utils.go:239.5,239.15 1 0 +core/utils.go:243.5,243.14 1 0 +core/utils.go:193.43,194.33 1 0 +core/utils.go:217.9,218.128 2 0 +core/utils.go:194.33,196.57 1 0 +core/utils.go:196.57,198.33 2 0 +core/utils.go:198.33,200.69 2 0 +core/utils.go:200.69,203.22 2 0 +core/utils.go:206.11,208.53 1 0 +core/utils.go:208.53,211.40 3 0 +core/utils.go:211.40,214.18 2 0 +core/utils.go:218.128,223.39 4 0 +core/utils.go:223.39,224.37 1 0 +core/utils.go:224.37,226.18 1 0 +core/utils.go:228.11,228.60 1 0 +core/utils.go:228.60,232.39 4 0 +core/utils.go:232.39,233.31 1 0 +core/utils.go:233.31,235.18 1 0 +core/utils.go:239.15,242.6 2 0 +core/utils.go:247.100,248.40 1 0 +core/utils.go:255.5,257.39 3 0 +core/utils.go:276.5,276.15 1 0 +core/utils.go:280.5,280.14 1 0 +core/utils.go:248.40,249.25 1 0 +core/utils.go:249.25,251.10 1 0 +core/utils.go:251.11,253.10 1 0 +core/utils.go:257.39,258.44 1 0 +core/utils.go:261.9,261.42 1 0 +core/utils.go:272.9,272.57 1 0 +core/utils.go:258.44,260.10 1 0 +core/utils.go:261.42,263.57 2 0 +core/utils.go:266.13,266.52 1 0 +core/utils.go:263.57,265.14 1 0 +core/utils.go:266.52,267.79 1 0 +core/utils.go:267.79,269.18 1 0 +core/utils.go:272.57,274.10 1 0 +core/utils.go:276.15,279.6 2 0 +core/utils.go:284.75,291.39 5 0 +core/utils.go:334.5,334.15 1 0 +core/utils.go:338.5,338.14 1 0 +core/utils.go:291.39,293.33 1 0 +core/utils.go:293.33,296.53 1 0 +core/utils.go:312.13,312.46 1 0 +core/utils.go:328.13,328.53 1 0 +core/utils.go:331.13,331.39 1 0 +core/utils.go:296.53,298.58 1 0 +core/utils.go:298.58,299.72 1 0 +core/utils.go:299.72,300.51 1 0 +core/utils.go:300.51,303.26 2 0 +core/utils.go:306.19,308.18 1 0 +core/utils.go:312.46,314.56 1 0 +core/utils.go:314.56,315.70 1 0 +core/utils.go:315.70,316.51 1 0 +core/utils.go:316.51,319.26 2 0 +core/utils.go:322.19,324.18 1 0 +core/utils.go:328.53,330.14 1 0 +core/utils.go:334.15,337.6 2 0 +core/utils.go:342.75,344.25 2 0 +core/utils.go:349.5,349.32 1 0 +core/utils.go:352.5,352.16 1 0 +core/utils.go:344.25,345.64 1 0 +core/utils.go:345.64,347.10 1 0 +core/utils.go:349.32,351.6 1 0 +core/utils.go:352.16,354.6 1 0 +core/utils.go:354.7,356.49 1 0 +core/utils.go:356.49,358.10 1 0 +core/utils.go:358.11,360.10 1 0 +core/utils.go:364.61,366.2 1 0 +core/utils.go:368.58,370.2 1 0 +core/build_label.go:35.41,37.2 1 0 +core/build_label.go:39.60,40.75 1 1 +core/build_label.go:43.5,43.56 1 1 +core/build_label.go:40.75,42.6 1 0 +core/build_label.go:47.70,49.23 2 1 +core/build_label.go:52.5,53.23 2 1 +core/build_label.go:56.5,57.23 2 1 +core/build_label.go:60.5,61.23 2 1 +core/build_label.go:64.5,65.23 2 1 +core/build_label.go:68.5,68.51 1 1 +core/build_label.go:49.23,51.6 1 1 +core/build_label.go:53.23,55.6 1 1 +core/build_label.go:57.23,59.6 1 1 +core/build_label.go:61.23,63.6 1 1 +core/build_label.go:65.23,67.6 1 1 +core/build_label.go:73.83,77.23 2 1 +core/build_label.go:80.5,81.23 2 1 +core/build_label.go:84.5,85.23 2 1 +core/build_label.go:88.5,88.48 1 1 +core/build_label.go:77.23,79.6 1 1 +core/build_label.go:81.23,83.6 1 1 +core/build_label.go:85.23,87.6 1 0 +core/build_label.go:93.76,95.37 2 0 +core/build_label.go:98.5,98.15 1 0 +core/build_label.go:95.37,97.6 1 0 +core/build_label.go:102.49,104.2 1 0 +core/build_label.go:107.45,109.2 1 0 +core/build_label.go:111.51,112.45 1 0 +core/build_label.go:112.45,114.6 1 0 +core/build_label.go:114.7,116.6 1 0 +core/build_label.go:120.59,122.22 2 0 +core/build_label.go:128.5,129.44 2 0 +core/build_label.go:132.5,132.15 1 0 +core/build_label.go:122.22,127.6 2 0 +core/build_label.go:129.44,131.6 1 0 +core/build_label.go:135.63,137.22 2 0 +core/build_label.go:140.5,141.44 2 0 +core/build_label.go:144.5,144.15 1 0 +core/build_label.go:137.22,139.6 1 0 +core/build_label.go:141.44,143.6 1 0 +core/build_label.go:147.45,149.2 1 0 +core/build_label.go:153.44,155.2 1 0 +core/build_label.go:159.36,161.2 1 0 +core/build_label.go:162.46,164.2 1 0 +core/build_label.go:165.41,167.2 1 0 diff --git a/src/test/test_data/go_coverage_2.txt b/src/test/test_data/go_coverage_2.txt new file mode 100644 index 0000000000..dd7be42e15 --- /dev/null +++ b/src/test/test_data/go_coverage_2.txt @@ -0,0 +1,40 @@ +mode: set +core/state.go:47.60,49.2 1 0 +core/state.go:51.60,53.2 1 0 +core/state.go:55.59,57.2 1 0 +core/state.go:61.102,63.2 1 0 +core/state.go:65.77,70.2 4 0 +core/state.go:72.41,75.29 3 0 +core/state.go:78.5,78.25 1 0 +core/state.go:75.29,77.6 1 0 +core/state.go:81.66,82.52 1 0 +core/state.go:87.5,87.17 1 0 +core/state.go:82.52,83.30 1 0 +core/state.go:83.30,85.10 1 0 +core/state.go:90.114,99.2 1 0 +core/state.go:101.184,114.2 4 0 +core/state.go:116.140,125.2 1 0 +core/state.go:127.42,131.2 3 0 +core/state.go:133.99,151.2 1 0 +core/state.go:170.116,179.2 1 0 +core/state.go:213.56,214.26 1 0 +core/state.go:217.5,217.26 1 0 +core/state.go:222.5,222.45 1 0 +core/state.go:227.5,227.48 1 0 +core/state.go:214.26,216.6 1 0 +core/state.go:217.26,219.6 1 0 +core/state.go:222.45,224.6 1 0 +core/state.go:227.48,229.6 1 0 +core/state.go:232.75,235.35 3 1 +core/state.go:242.5,242.15 1 1 +core/state.go:235.35,236.26 1 1 +core/state.go:236.26,238.10 1 1 +core/state.go:238.11,238.40 1 1 +core/state.go:238.40,240.10 1 1 +core/state.go:246.50,248.37 2 0 +core/state.go:251.5,252.17 2 0 +core/state.go:248.37,250.6 1 0 +core/state.go:255.37,260.2 1 0 +core/state.go:268.54,270.32 2 0 +core/state.go:273.5,273.27 1 0 +core/state.go:270.32,272.6 1 0 diff --git a/src/test/test_data/go_coverage_3.txt b/src/test/test_data/go_coverage_3.txt new file mode 100644 index 0000000000..28adf8cf87 --- /dev/null +++ b/src/test/test_data/go_coverage_3.txt @@ -0,0 +1,42 @@ +mode: set +misc/plz_diff_graphs.go:19.56,22.16 3 1 +misc/plz_diff_graphs.go:25.2,25.53 1 1 +misc/plz_diff_graphs.go:28.2,28.15 1 1 +misc/plz_diff_graphs.go:22.16,24.3 1 0 +misc/plz_diff_graphs.go:25.53,27.3 1 0 +misc/plz_diff_graphs.go:32.122,35.48 3 1 +misc/plz_diff_graphs.go:55.2,56.43 2 1 +misc/plz_diff_graphs.go:64.2,65.12 2 1 +misc/plz_diff_graphs.go:35.48,37.15 2 1 +misc/plz_diff_graphs.go:45.3,45.57 1 1 +misc/plz_diff_graphs.go:37.15,39.45 1 1 +misc/plz_diff_graphs.go:43.4,43.12 1 1 +misc/plz_diff_graphs.go:39.45,42.5 2 1 +misc/plz_diff_graphs.go:45.57,47.75 2 1 +misc/plz_diff_graphs.go:47.75,50.5 2 1 +misc/plz_diff_graphs.go:56.43,57.47 1 1 +misc/plz_diff_graphs.go:57.47,59.46 1 1 +misc/plz_diff_graphs.go:59.46,61.5 1 1 +misc/plz_diff_graphs.go:68.104,69.31 1 1 +misc/plz_diff_graphs.go:74.2,74.36 1 1 +misc/plz_diff_graphs.go:79.2,79.14 1 1 +misc/plz_diff_graphs.go:69.31,71.3 1 1 +misc/plz_diff_graphs.go:74.36,75.59 1 1 +misc/plz_diff_graphs.go:75.59,77.4 1 1 +misc/plz_diff_graphs.go:84.117,87.13 3 1 +misc/plz_diff_graphs.go:90.2,91.14 2 1 +misc/plz_diff_graphs.go:94.2,94.34 1 1 +misc/plz_diff_graphs.go:101.2,102.14 2 1 +misc/plz_diff_graphs.go:87.13,89.3 1 1 +misc/plz_diff_graphs.go:91.14,93.3 1 0 +misc/plz_diff_graphs.go:94.34,96.83 2 1 +misc/plz_diff_graphs.go:96.83,99.4 2 1 +misc/plz_diff_graphs.go:106.41,108.23 2 1 +misc/plz_diff_graphs.go:111.2,111.12 1 1 +misc/plz_diff_graphs.go:108.23,110.3 1 1 +misc/plz_diff_graphs.go:115.78,117.2 1 1 +misc/plz_diff_graphs.go:119.66,120.28 1 1 +misc/plz_diff_graphs.go:127.2,127.14 1 1 +misc/plz_diff_graphs.go:120.28,121.36 1 1 +misc/plz_diff_graphs.go:121.36,122.16 1 1 +misc/plz_diff_graphs.go:122.16,124.5 1 1 diff --git a/src/test/test_data/go_multiple_failure.txt b/src/test/test_data/go_multiple_failure.txt new file mode 100644 index 0000000000..b92faa9091 --- /dev/null +++ b/src/test/test_data/go_multiple_failure.txt @@ -0,0 +1,8 @@ +=== RUN TestPlzConfigWorking-6 +--- FAIL: TestPlzConfigWorking-6 (0.00s) + config_test.go:12: Failed to parse Python.PexTool correctly. + config_test.go:21: Failed to parse Java.TargetLevel correctly. +=== RUN TestPlzConfigFailing-6 +--- FAIL: TestPlzConfigFailing-6 (0.00s) + config_test.go:30: No error reported reading config file. +FAIL diff --git a/src/test/test_data/go_test_failure.txt b/src/test/test_data/go_test_failure.txt new file mode 100644 index 0000000000..d44d5e0903 --- /dev/null +++ b/src/test/test_data/go_test_failure.txt @@ -0,0 +1,11 @@ +=== RUN TestJSONExpectedFailure-6 +--- FAIL: TestJSONExpectedFailure-6 (0.00s) + results_test.go:11: Unable to parse file: EOF +=== RUN TestJSONSkipped-6 +--- FAIL: TestJSONSkipped-6 (0.00s) + results_test.go:24: Unable to parse file: EOF +=== RUN TestBuckXML-6 +--- PASS: TestBuckXML-6 (0.00s) +=== RUN TestJUnitXML-6 +--- PASS: TestJUnitXML-6 (0.00s) +FAIL diff --git a/src/test/test_data/go_test_ignore_logs.txt b/src/test/test_data/go_test_ignore_logs.txt new file mode 100644 index 0000000000..172dfbfe81 --- /dev/null +++ b/src/test/test_data/go_test_ignore_logs.txt @@ -0,0 +1,14 @@ +=== RUN TestA +log: some output +log: some more output +--- PASS: TestA (0.00s) +=== RUN TestB +log: log +log: log +--- PASS: TestB (0.00s) +=== RUN TestC +--- PASS: TestC (0.00s) +=== RUN TestD +--- PASS: TestD (0.00s) +PASS +coverage: 22.9% of statements diff --git a/src/test/test_data/go_test_pass.txt b/src/test/test_data/go_test_pass.txt new file mode 100644 index 0000000000..82b771365b --- /dev/null +++ b/src/test/test_data/go_test_pass.txt @@ -0,0 +1,9 @@ +=== RUN TestJSONExpectedFailure-6 +--- PASS: TestJSONExpectedFailure-6 (0.00s) +=== RUN TestJSONSkipped-6 +--- PASS: TestJSONSkipped-6 (0.00s) +=== RUN TestBuckXML-6 +--- PASS: TestBuckXML-6 (0.00s) +=== RUN TestJUnitXML-6 +--- PASS: TestJUnitXML-6 (0.00s) +PASS diff --git a/src/test/test_data/go_test_skip.txt b/src/test/test_data/go_test_skip.txt new file mode 100644 index 0000000000..d6e07c48d0 --- /dev/null +++ b/src/test/test_data/go_test_skip.txt @@ -0,0 +1,11 @@ +=== RUN TestLimitedPrintfSimple +--- PASS: TestLimitedPrintfSimple (0.00s) +=== RUN TestLimitedPrintfMore +--- PASS: TestLimitedPrintfMore (0.00s) +=== RUN TestLimitedPrintfAnsi +--- PASS: TestLimitedPrintfAnsi (0.00s) +=== RUN TestLimitedPrintfAnsiNotCountedWhenReducing +--- SKIP: TestLimitedPrintfAnsiNotCountedWhenReducing (0.00s) + interactive_display_test.go:21: haven't written proper support for this yet +PASS +coverage: 1.7% of statements diff --git a/src/test/test_data/go_test_suite.txt b/src/test/test_data/go_test_suite.txt new file mode 100644 index 0000000000..474781c1b8 --- /dev/null +++ b/src/test/test_data/go_test_suite.txt @@ -0,0 +1,19 @@ +=== RUN TestExampleTestSuite +=== RUN TestA +--- PASS: TestA (0.00s) +=== RUN TestB +--- PASS: TestB (0.00s) +=== RUN TestC +--- PASS: TestC (0.00s) +=== RUN TestD +--- PASS: TestD (0.00s) +=== RUN TestF +--- FAIL: TestF (0.00s) + config_test.go:12: Failed to parse Python.PexTool correctly. + config_test.go:21: Failed to parse Java.TargetLevel correctly. +=== RUN TestS +--- SKIP: TestS (0.00s) + interactive_display_test.go:21: haven't written proper support for this yet +--- PASS: TestExampleTestSuite (1.21s) +PASS +coverage: 22.9% of statements diff --git a/src/test/test_data/go_test_unknown_test.txt b/src/test/test_data/go_test_unknown_test.txt new file mode 100644 index 0000000000..eabac427f1 --- /dev/null +++ b/src/test/test_data/go_test_unknown_test.txt @@ -0,0 +1,6 @@ +=== RUN TestA +--- PASS: TestB (0.00s) +=== RUN TestB +--- PASS: TestA (0.00s) +PASS +coverage: 22.9% of statements diff --git a/src/test/test_data/junit.xml b/src/test/test_data/junit.xml new file mode 100644 index 0000000000..c5c7fe8099 --- /dev/null +++ b/src/test/test_data/junit.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/test/test_data/karma-junit.xml b/src/test/test_data/karma-junit.xml new file mode 100644 index 0000000000..edaf69a741 --- /dev/null +++ b/src/test/test_data/karma-junit.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/test_data/python-coverage.xml b/src/test/test_data/python-coverage.xml new file mode 100644 index 0000000000..7c101b8d78 --- /dev/null +++ b/src/test/test_data/python-coverage.xml @@ -0,0 +1,56 @@ + + + + + + /home/pebers/git/please/plz-out/tmp/src/build/python/pex_test.test + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/test_data/unittest.xml b/src/test/test_data/unittest.xml new file mode 100644 index 0000000000..46ba029475 --- /dev/null +++ b/src/test/test_data/unittest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/test/test_data/xmlrunner-junit.xml b/src/test/test_data/xmlrunner-junit.xml new file mode 100644 index 0000000000..80d4a0b72f --- /dev/null +++ b/src/test/test_data/xmlrunner-junit.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/src/test/test_step.go b/src/test/test_step.go new file mode 100644 index 0000000000..1aa81eeda1 --- /dev/null +++ b/src/test/test_step.go @@ -0,0 +1,340 @@ +package test + +import ( + "encoding/base64" + "fmt" + "io/ioutil" + "os" + "os/exec" + "path" + "strings" + "time" + + "github.com/op/go-logging" + + "build" + "core" +) + +var log = logging.MustGetLogger("test") + +const dummyOutput = "=== RUN DummyTest\n--- PASS: DummyTest (0.00s)\nPASS\n" +const dummyCoverage = "" + +func Test(tid int, state *core.BuildState, label core.BuildLabel) { + state.LogBuildResult(tid, label, core.TargetTesting, "Testing...") + startTime := time.Now() + target := state.Graph.TargetOrDie(label) + hash, err := build.RuntimeHash(state, target) + if err != nil { + state.LogBuildError(tid, label, core.TargetTestFailed, err, "Failed to calculate target hash") + return + } + // Check the cached output files if the target wasn't rebuilt. + hashStr := base64.RawURLEncoding.EncodeToString(core.CollapseHash(hash)) + resultsFileName := fmt.Sprintf(".test_results_%s_%s", label.Name, hashStr) + coverageFileName := fmt.Sprintf(".test_coverage_%s_%s", label.Name, hashStr) + outputFile := path.Join(target.TestDir(), "test.results") + coverageFile := path.Join(target.TestDir(), "test.coverage") + cachedOutputFile := path.Join(target.OutDir(), resultsFileName) + cachedCoverageFile := path.Join(target.OutDir(), coverageFileName) + needCoverage := state.NeedCoverage && !target.NoTestOutput + + cachedTest := func() { + log.Debug("Not re-running test %s; got cached results.", label) + coverage := parseCoverageFile(target, cachedCoverageFile) + results, err := parseTestResults(target, cachedOutputFile, 0, true) + target.Results.Duration = time.Since(startTime).Seconds() + target.Results.Cached = true + if err != nil { + state.LogBuildError(tid, label, core.TargetTestFailed, err, "Failed to parse cached test file %s", cachedOutputFile) + } else if results.Failed > 0 { + panic("Test results with failures shouldn't be cached.") + } else { + logTestSuccess(state, tid, label, results, coverage) + } + } + + moveAndCacheOutputFiles := func(results core.TestResults, coverage core.TestCoverage) bool { + // Never cache test results when given arguments; the results may be incomplete. + if len(state.TestArgs) > 0 { + log.Debug("Not caching results for %s, we passed it arguments", label) + return true + } + if err := moveAndCacheOutputFile(state, target, hash, outputFile, cachedOutputFile, resultsFileName, dummyOutput); err != nil { + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, "Failed to move test output file") + return false + } + if needCoverage || core.PathExists(coverageFile) { + if err := moveAndCacheOutputFile(state, target, hash, coverageFile, cachedCoverageFile, coverageFileName, dummyCoverage); err != nil { + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, "Failed to move test coverage file") + return false + } + } + for _, output := range target.TestOutputs { + tmpFile := path.Join(target.TestDir(), output) + outFile := path.Join(target.OutDir(), output) + if err := moveAndCacheOutputFile(state, target, hash, tmpFile, outFile, output, ""); err != nil { + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, "Failed to move test output file") + return false + } + } + return true + } + + needToRun := func() bool { + if target.State() == core.Unchanged && core.PathExists(cachedOutputFile) { + // Output file exists already and appears to be valid. We might still need to rerun though + // if the coverage files aren't available. + if needCoverage && !core.PathExists(cachedCoverageFile) { + return true + } + return false + } + // Check the cache for these artifacts. + if state.Cache == nil { + return true + } + cache := *state.Cache + if !cache.RetrieveExtra(target, hash, resultsFileName) { + return true + } + if needCoverage && !cache.RetrieveExtra(target, hash, coverageFileName) { + return true + } + for _, output := range target.TestOutputs { + if !cache.RetrieveExtra(target, hash, output) { + return true + } + } + return false + } + + // Don't cache when doing multiple runs, presumably the user explicitly wants to check it. + if state.NumTestRuns == 1 && !needToRun() { + cachedTest() + return + } + // Remove any cached test result file. + if err := RemoveCachedTestFiles(target); err != nil { + state.LogBuildError(tid, label, core.TargetTestFailed, err, "Failed to remove cached test files") + return + } + numSucceeded := 0 + for i := 0; i < state.NumTestRuns; i++ { + if state.NumTestRuns > 1 { + state.LogBuildResult(tid, label, core.TargetTesting, fmt.Sprintf("Testing (%d of %d)...", i, state.NumTestRuns)) + } + out, err, flakes := runTestWithRetries(tid, state, target) + duration := time.Since(startTime).Seconds() + startTime = time.Now() // reset this for next time + + // This is all pretty involved; there are lots of different possibilities of what could happen. + // The contract is that the test must return zero on success or non-zero on failure (Unix FTW). + // If it's successful, it must produce a parseable file named "test.results" in its temp folder. + // (alternatively, this can be a directory containing parseable files). + // Tests can opt out of the file requirement individually, in which case they're judged only + // by their return value. + // But of course, we still have to consider all the alternatives here and handle them nicely. + target.Results.Output = string(out) + if err != nil && target.Results.Output == "" { + target.Results.Output = err.Error() + } + coverage := parseCoverageFile(target, coverageFile) + if !core.PathExists(outputFile) { + target.Results.Duration += duration + if err == nil && target.NoTestOutput { + results := core.TestResults{NumTests: 1, Passed: 1, Flakes: flakes} + if moveAndCacheOutputFiles(results, coverage) { + target.Results.NumTests = 1 + target.Results.Passed = 1 + logTestSuccess(state, tid, label, results, coverage) + } + } else if err == nil { + target.Results.NumTests++ + target.Results.Failed++ + err = fmt.Errorf("Test failed to produce output results file") + state.LogBuildError(tid, label, core.TargetTestFailed, err, + "Test apparently succeeded but failed to produce %s. Output: %s", outputFile, string(out)) + } else { + target.Results.NumTests++ + target.Results.Failed++ + state.LogBuildError(tid, label, core.TargetTestFailed, err, + fmt.Sprintf("Test failed with no results. Output: %s", string(out))) + } + } else { + results, err2 := parseTestResults(target, outputFile, flakes, false) + target.Results.Duration += duration + if err2 != nil { + state.LogBuildError(tid, label, core.TargetTestFailed, err2, + "Couldn't parse test output file: %s. Stdout: %s", err2, string(out)) + } else if err != nil && results.Failed == 0 { + // Add a failure result to the test so it shows up in the final aggregation. + results.Failed = 1 + results.Failures = append(results.Failures, core.TestFailure{ + Name: "Return value", + Type: fmt.Sprintf("%s", err), + Stdout: string(out), + }) + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, + "Test returned nonzero but reported no errors: %s. Output: %s", err, string(out)) + } else if err == nil && results.Failed != 0 { + err = fmt.Errorf("Test returned 0 but still reported failures") + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, + "Test returned 0 but still reported failures. Stdout: %s", string(out)) + } else if results.Failed != 0 { + err = fmt.Errorf("Tests failed") + state.LogTestResult(tid, label, core.TargetTestFailed, results, coverage, err, + fmt.Sprintf("Tests failed. Stdout: %s", string(out))) + } else { + logTestSuccess(state, tid, label, results, coverage) + numSucceeded++ + // Cache only on the last run. + if numSucceeded == state.NumTestRuns { + moveAndCacheOutputFiles(results, coverage) + } + // Clean up the test directory. + if state.CleanWorkdirs { + if err := os.RemoveAll(target.TestDir()); err != nil { + log.Warning("Failed to remove test directory for %s: %s", target.Label, err) + } + } + } + } + } +} + +func logTestSuccess(state *core.BuildState, tid int, label core.BuildLabel, results core.TestResults, coverage core.TestCoverage) { + var description string + tests := pluralise("test", results.NumTests) + if results.Skipped != 0 || results.ExpectedFailures != 0 { + failures := pluralise("failure", results.ExpectedFailures) + description = fmt.Sprintf("%d %s passed. %d skipped, %d expected %s", + results.NumTests, tests, results.Skipped, results.ExpectedFailures, failures) + } else { + description = fmt.Sprintf("%d %s passed.", results.NumTests, tests) + } + state.LogTestResult(tid, label, core.TargetTested, results, coverage, nil, description) +} + +func pluralise(word string, quantity int) string { + if quantity == 1 { + return word + } + return word + "s" +} + +func prepareTestDir(graph *core.BuildGraph, target *core.BuildTarget) error { + if err := os.RemoveAll(target.TestDir()); err != nil { + return err + } + if err := os.MkdirAll(target.TestDir(), core.DirPermissions); err != nil { + return err + } + for out := range core.IterRuntimeFiles(graph, target, true) { + if err := core.PrepareSourcePair(out); err != nil { + return err + } + } + return nil +} + +func runTest(state *core.BuildState, target *core.BuildTarget, timeout int) ([]byte, error) { + replacedCmd := build.ReplaceTestSequences(target, target.TestCommand) + replacedCmd += " " + strings.Join(state.TestArgs, " ") + cmd := exec.Command("bash", "-c", replacedCmd) + cmd.Dir = target.TestDir() + cmd.Env = core.BuildEnvironment(state, target, true) + log.Debug("Running test %s\nENVIRONMENT:\n%s\n%s", target.Label, strings.Join(cmd.Env, "\n"), replacedCmd) + if state.PrintCommands { + log.Notice("Running test %s: %s", target.Label, replacedCmd) + } + return core.ExecWithTimeout(cmd, target.TestTimeout, timeout) +} + +// Runs a test some number of times as indicated by its flakiness. +func runTestWithRetries(tid int, state *core.BuildState, target *core.BuildTarget) (out []byte, err error, flakiness int) { + flakiness = target.Flakiness + if flakiness == 0 { + flakiness = 1 + } // Flakiness of 0 -> run it once. Equivalent behaviour to 1 but more intuitive. + if state.MaxFlakes > 0 && flakiness > state.MaxFlakes { + flakiness = state.MaxFlakes // Cap max flakes by flag + } + for i := 0; i < flakiness; i++ { + // Re-prepare test directory between each attempt so they can't accidentally contaminate each other. + if err = prepareTestDir(state.Graph, target); err != nil { + state.LogBuildError(tid, target.Label, core.TargetTestFailed, err, "Failed to prepare test directory for %s: %s", target.Label, err) + return []byte{}, err, i + } + out, err = runPossiblyContainerisedTest(state, target) + if err == nil { + return out, err, i + } else if i < flakiness-1 { + log.Warning("%s failed on attempt %d (%d more to go).", target.Label, i+1, flakiness-i-1) + } + } + if target.Flakiness == 0 { + flakiness = 0 + } // Reset this again so non-flaky targets don't appear so. + return out, err, flakiness +} + +// Parses the coverage output for a single target. +func parseCoverageFile(target *core.BuildTarget, coverageFile string) core.TestCoverage { + coverage, err := parseTestCoverage(target, coverageFile) + if err != nil { + log.Error("Failed to parse coverage file for %s: %s", target.Label, err) + } + return coverage +} + +// RemoveCachedTestFiles removes any cached test or coverage result files for a target. +func RemoveCachedTestFiles(target *core.BuildTarget) error { + if err := removeAnyFilesWithPrefix(target.OutDir(), ".test_results_"+target.Label.Name); err != nil { + return err + } + if err := removeAnyFilesWithPrefix(target.OutDir(), ".test_coverage_"+target.Label.Name); err != nil { + return err + } + for _, output := range target.TestOutputs { + if err := os.RemoveAll(path.Join(target.OutDir(), output)); err != nil { + return err + } + } + return nil +} + +// removeAnyFilesWithPrefix deletes any files in a directory matching a given prefix. +func removeAnyFilesWithPrefix(dir, prefix string) error { + infos, err := ioutil.ReadDir(dir) + if err != nil { + return err + } + for _, info := range infos { + if strings.HasPrefix(info.Name(), prefix) { + if err := os.RemoveAll(path.Join(dir, info.Name())); err != nil { + return err + } + } + } + return nil +} + +// Attempt to write a dummy coverage file to record that it's been done for a test. +func moveAndCacheOutputFile(state *core.BuildState, target *core.BuildTarget, hash []byte, from, to, filename, dummy string) error { + if !core.PathExists(from) { + if dummy == "" { + return nil + } + if err := ioutil.WriteFile(to, []byte(dummy), 0644); err != nil { + return err + } + } else if err := os.Rename(from, to); err != nil { + return err + } + if state.Cache != nil { + (*state.Cache).StoreExtra(target, hash, filename) + } + return nil +} diff --git a/src/test/xml_coverage.go b/src/test/xml_coverage.go new file mode 100644 index 0000000000..597a762028 --- /dev/null +++ b/src/test/xml_coverage.go @@ -0,0 +1,65 @@ +// Code for parsing XML coverage output (eg. Java or Python). + +package test + +import "encoding/xml" +import "strings" + +import "core" + +func parseXmlCoverageResults(target *core.BuildTarget, coverage *core.TestCoverage, data []byte) error { + xcoverage := xmlCoverage{} + if err := xml.Unmarshal(data, &xcoverage); err != nil { + return err + } + for _, pkg := range xcoverage.Packages.Package { + for _, cls := range pkg.Classes.Class { + if strings.HasPrefix(cls.Filename, core.RepoRoot) { + cls.Filename = cls.Filename[len(core.RepoRoot):] + } + // There can be multiple classes per file so we must merge here, not overwrite. + coverage.Files[cls.Filename] = core.MergeCoverageLines(coverage.Files[cls.Filename], parseXmlLines(cls.Lines.Line)) + } + } + coverage.Tests[target.Label] = coverage.Files + return nil +} + +func parseXmlLines(lines []xmlCoverageLine) []core.LineCoverage { + ret := []core.LineCoverage{} + for _, line := range lines { + for i := len(ret) + 1; i < line.Number; i++ { + ret = append(ret, core.NotExecutable) + } + if line.Hits > 0 { + ret = append(ret, core.Covered) + } else { + ret = append(ret, core.Uncovered) + } + } + return ret +} + +// Note that this is based off coverage.py's format, which is originally a Java format +// so some of the structures are a little awkward (eg. 'classes' actually refer to Python modules, not classes). +type xmlCoverage struct { + Packages struct { + Package []struct { + Classes struct { + Class []struct { + LineRate float32 `xml:"line-rate,attr"` + Filename string `xml:"filename,attr"` + Name string `xml:"name,attr"` + Lines struct { + Line []xmlCoverageLine `xml:"line"` + } `xml:"lines"` + } `xml:"class"` + } `xml:"classes"` + } `xml:"package"` + } `xml:"packages"` +} + +type xmlCoverageLine struct { + Hits int `xml:"hits,attr"` + Number int `xml:"number,attr"` +} diff --git a/src/test/xml_results.go b/src/test/xml_results.go new file mode 100644 index 0000000000..b125805242 --- /dev/null +++ b/src/test/xml_results.go @@ -0,0 +1,147 @@ +// Parser for JUnit XML output. + +package test + +import ( + "encoding/xml" + "io/ioutil" + "os" + "path" + "strings" + + "core" +) + +func parseJUnitXMLTestResults(bytes []byte) (core.TestResults, error) { + results := core.TestResults{} + junitCase := JUnitXMLTestResults{} + if err := xml.Unmarshal(bytes, &junitCase); err != nil { + return results, err + } + for _, test := range junitCase.Tests { + appendResult(test, &results) + } + for _, test := range junitCase.TestCases { + appendResult(test, &results) + } + for _, suite := range junitCase.TestSuites { + for _, test := range suite.TestCases { + appendResult(test, &results) + } + } + return results, nil +} + +func appendResult(test JUnitXMLTest, results *core.TestResults) { + results.NumTests++ + if test.Failure != nil { + appendResult2(test, results, *test.Failure) + } else if test.Error != nil { + appendResult2(test, results, *test.Error) + } else if test.Type == "FAILURE" || test.Success == "false" || test.Stacktrace != "" { + appendResult2(test, results, JUnitXMLFailure{"", "FAILURE", test.Stacktrace}) + } else { + results.Passed++ + results.Passes = append(results.Passes, test.Name) + } +} + +func appendResult2(test JUnitXMLTest, results *core.TestResults, failure JUnitXMLFailure) { + results.Failed++ + results.Failures = append(results.Failures, core.TestFailure{ + Name: combineNames(test.ClassName, test.Name), + Type: failure.Type, + Traceback: messageOrTraceback(failure), // TODO(pebers): store both of these, not just one. + Stdout: test.Stdout, + Stderr: test.Stderr, + }) +} + +func messageOrTraceback(failure JUnitXMLFailure) string { + if failure.Traceback != "" { + return failure.Traceback + } else { + return failure.Message + } +} + +func combineNames(className string, name string) string { + index := strings.LastIndex(className, ".") + if index != -1 { + return className[index+1:] + "." + name + } else { + return className + "." + name + } +} + +type JUnitXMLTestResults struct { + TestSuites []JUnitXMLTestSuite `xml:"testsuite"` + TestCases []JUnitXMLTest `xml:"testcase"` + Tests []JUnitXMLTest `xml:"test"` + XMLName xml.Name +} + +type JUnitXMLTestSuite struct { + Name string `xml:"name,attr"` + Failures int `xml:"failures,attr,omitempty"` + Tests int `xml:"tests,attr"` + TestCases []JUnitXMLTest `xml:"testcase"` +} + +type JUnitXMLTest struct { + ClassName string `xml:"classname,attr,omitempty"` + Name string `xml:"name,attr"` + Failure *JUnitXMLFailure `xml:"failure,omitempty"` + Error *JUnitXMLFailure `xml:"error,omitempty"` + Time float64 `xml:"time,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + Success string `xml:"success,attr,omitempty"` + Stacktrace string `xml:"stacktrace,attr,omitempty"` + Stdout string `xml:"stdout,omitempty"` + Stderr string `xml:"stderr,omitempty"` +} + +type JUnitXMLFailure struct { + Message string `xml:"message,attr,omitempty"` + Type string `xml:"type,attr,omitempty"` + Traceback string `xml:",chardata"` +} + +// Write test results out to a file in xUnit format. Dies on any errors. +func WriteResultsToFileOrDie(graph *core.BuildGraph, filename string) { + if err := os.MkdirAll(path.Dir(filename), core.DirPermissions); err != nil { + log.Fatalf("Failed to create directory for test output") + } + results := JUnitXMLTestResults{} + results.XMLName.Local = "testsuites" + for _, target := range graph.AllTargets() { + if target.Results.NumTests > 0 { + suite := JUnitXMLTestSuite{ + Name: target.Label.String(), + Failures: target.Results.Failed, + Tests: target.Results.NumTests, + } + for _, pass := range target.Results.Passes { + suite.TestCases = append(suite.TestCases, JUnitXMLTest{Name: pass}) + } + for _, fail := range target.Results.Failures { + suite.TestCases = append(suite.TestCases, JUnitXMLTest{ + Name: fail.Name, + Type: fail.Type, + Stdout: fail.Stdout, + Stderr: fail.Stderr, + Error: &JUnitXMLFailure{ + Type: fail.Type, + Traceback: fail.Traceback, + }, + }) + } + results.TestSuites = append(results.TestSuites, suite) + } + } + if b, err := xml.MarshalIndent(results, "", " "); err != nil { + log.Fatalf("Failed to serialise XML: %s", err) + } else if err = ioutil.WriteFile(filename, b, 0644); err != nil { + log.Fatalf("Failed to write XML to %s: %s", filename, err) + } +} diff --git a/src/update/BUILD b/src/update/BUILD new file mode 100644 index 0000000000..f1feb35c06 --- /dev/null +++ b/src/update/BUILD @@ -0,0 +1,9 @@ +go_library( + name = 'update', + srcs = glob(['*.go']), + deps = [ + '//src/core', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) diff --git a/src/update/update.go b/src/update/update.go new file mode 100644 index 0000000000..176f41ef34 --- /dev/null +++ b/src/update/update.go @@ -0,0 +1,174 @@ +// Code for Please auto-updating itself. +// At startup, Please can check a version set in the config file. If that doesn't +// match the version of the current binary, it will download the appropriate +// version from the website and swap to using that instead. +// +// This feature is fairly directly cribbed from Buck since we found it very useful, +// albeit implemented differently so it plays nicer with multiple simultaneous +// builds on the same machine. + +package update + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + "os/signal" + "path" + "runtime" + "strings" + "syscall" +) + +import "core" + +import "github.com/op/go-logging" + +var log = logging.MustGetLogger("update") + +func CheckAndUpdate(config core.Configuration, shouldUpdate, forceUpdate bool) { + if config.Please.Version == core.PleaseVersion { + return // Version matches, nothing to do here. + } else if config.Please.Version == "" { + return // No version specified, auto-update disabled. + } else if (!shouldUpdate || !config.Please.SelfUpdate) && !forceUpdate { + log.Warning("Update to Please version %s (currently %s) skipped", config.Please.Version, core.PleaseVersion) + return + } else if config.Please.Location == "" { + log.Warning("Please location not set in config, cannot auto-update.") + return + } else if config.Please.DownloadLocation == "" { + log.Warning("Please download location not set in config, cannot auto-update.") + return + } + // Okay, now we're past all that... + log.Warning("Updating to Please version %s (currently %s)", config.Please.Version, core.PleaseVersion) + + // Must lock here so that the update process doesn't race when running two instances + // simultaneously. + core.AcquireRepoLock() + defer core.ReleaseRepoLock() + + newPlease := path.Join(config.Please.Location, config.Please.Version, "please") + if !core.PathExists(newPlease) { + downloadPlease(config) + } + linkNewPlease(config) + args := append([]string{newPlease}, os.Args[1:]...) + args = append(args, "--assert_version", config.Please.Version) + log.Info("Executing %s", strings.Join(args, " ")) + if err := syscall.Exec(newPlease, args, os.Environ()); err != nil { + log.Fatalf("Failed to exec new Please version %s: %s", newPlease, err) + } + // Shouldn't ever get here. We should have either exec'd or died above. + panic("please update failed in an an unexpected and exciting way") +} + +func downloadPlease(config core.Configuration) { + newDir := path.Join(config.Please.Location, config.Please.Version) + if err := os.MkdirAll(newDir, core.DirPermissions); err != nil { + log.Fatalf("Failed to create directory %s: %s", newDir, err) + } + + // Make sure from here on that we don't leave partial directories hanging about. + // If someone ctrl+C's during this download then on re-running we might + // have partial files written there that don't really work. + defer func() { + if r := recover(); r != nil { + cleanDir(newDir) + log.Fatalf("Failed to download Please: %s", r) + } + }() + go handleSignals(newDir) + mustClose := func(closer io.Closer) { + if err := closer.Close(); err != nil { + panic(err) + } + } + + url := fmt.Sprintf("%s/%s_%s/%s/please.tar.gz", config.Please.DownloadLocation, runtime.GOOS, runtime.GOARCH, config.Please.Version) + log.Info("Downloading %s", url) + response, err := http.Get(url) + if err != nil { + panic(fmt.Sprintf("Failed to download %s: %s", url, err)) + } else if response.StatusCode < 200 || response.StatusCode > 299 { + panic(fmt.Sprintf("Failed to download %s: got response %s", url, response.Status)) + } + defer mustClose(response.Body) + + gzreader, err := gzip.NewReader(response.Body) + if err != nil { + panic(fmt.Sprintf("%s isn't a valid gzip file: %s", url, err)) + } + defer mustClose(gzreader) + + tarball := tar.NewReader(gzreader) + for { + hdr, err := tarball.Next() + if err == io.EOF { + break // End of archive + } else if err != nil { + panic(fmt.Sprintf("Error un-tarring %s: %s", url, err)) + } + filename := path.Base(hdr.Name) + destination := path.Join(newDir, filename) + log.Info("Extracting %s to %s", filename, destination) + if contents, err := ioutil.ReadAll(tarball); err != nil { + panic(fmt.Sprintf("Error extracting %s from tarball: %s", filename, err)) + } else if err := ioutil.WriteFile(destination, contents, fileMode(filename)); err != nil { + panic(fmt.Sprintf("Failed to write to %s: %s", destination, err)) + } + } +} + +func linkNewPlease(config core.Configuration) { + if files, err := ioutil.ReadDir(path.Join(config.Please.Location, config.Please.Version)); err != nil { + log.Fatalf("Failed to read directory: %s", err) + } else { + for _, file := range files { + linkNewFile(config, file.Name()) + } + } +} + +func linkNewFile(config core.Configuration, file string) { + newDir := path.Join(config.Please.Location, config.Please.Version) + globalFile := path.Join(config.Please.Location, file) + downloadedFile := path.Join(newDir, file) + if err := os.RemoveAll(globalFile); err != nil { + log.Fatalf("Failed to remove existing file %s: %s", globalFile, err) + } + if err := os.Symlink(downloadedFile, globalFile); err != nil { + log.Fatalf("Error linking %s -> %s: %s", downloadedFile, globalFile, err) + } + log.Info("Linked %s -> %s", globalFile, downloadedFile) +} + +func fileMode(filename string) os.FileMode { + if strings.HasSuffix(filename, ".jar") { + return 0664 // The .jar files obviously aren't executable + } else { + return 0775 // Everything else we download is. + } +} + +func cleanDir(newDir string) { + log.Notice("Attempting to clean directory %s", newDir) + if err := os.RemoveAll(newDir); err != nil { + log.Error("Failed to clean %s: %s", newDir, err) + } +} + +// handleSignals traps SIGINT and SIGKILL (if possible) and on receiving one cleans the given directory. +func handleSignals(newDir string) { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, os.Kill) + s := <-c + log.Notice("Got signal %s", s) + cleanDir(newDir) + log.Fatalf("Got signal %s", s) +} diff --git a/src/utils/BUILD b/src/utils/BUILD new file mode 100644 index 0000000000..5f15aa3224 --- /dev/null +++ b/src/utils/BUILD @@ -0,0 +1,10 @@ +go_library( + name = 'utils', + srcs = glob(['*.go']), + deps = [ + '//src/core', + '//third_party/go:prompter', + '//third_party/go:logging', + ], + visibility = ['PUBLIC'], +) diff --git a/src/utils/utils.go b/src/utils/utils.go new file mode 100644 index 0000000000..f333971424 --- /dev/null +++ b/src/utils/utils.go @@ -0,0 +1,54 @@ +// Package utils contains various utility functions and whatnot. +package utils + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + + "github.com/Songmu/prompter" + "github.com/op/go-logging" + + "core" +) + +var log = logging.MustGetLogger("utils") + +const configTemplate = `; Please config file +; Leaving this file as is is enough to use plz to build your project. +; Please will stay on whatever version you currently have until you run +; 'plz update', when it will download the latest available version. +; +; Or you can uncomment the following to pin everyone to a particular version; +; when you change it all users will automatically get updated. +; [please] +; version = %s +` + +// InitConfig initialises a .plzconfig template in the given directory. +func InitConfig(dir string) { + if dir == "." { + core.FindRepoRoot(false) + if core.RepoRoot != "" { + config := path.Join(core.RepoRoot, core.ConfigFileName) + if !prompter.YN(fmt.Sprintf("You already seem to be in a plz repo (found %s). Continue?", config), false) { + os.Exit(1) + } + } + } + dir, err := filepath.Abs(dir) + if err != nil { + log.Warning("Can't determine absolute directory: %s", err) + } + config := path.Join(dir, core.ConfigFileName) + if core.FileExists(config) && !prompter.YN(fmt.Sprintf("Would create %s but it already exists. This will wipe out any previous config in the file - continue?", config), false) { + os.Exit(1) + } + contents := fmt.Sprintf(configTemplate, core.PleaseVersion) + if err := ioutil.WriteFile(config, []byte(contents), 0644); err != nil { + log.Fatalf("Failed to write file: %s", err) + } + fmt.Printf("Wrote config template to %s, you're now ready to go!\n", config) +} diff --git a/test/BUILD b/test/BUILD new file mode 100644 index 0000000000..928b217e40 --- /dev/null +++ b/test/BUILD @@ -0,0 +1,289 @@ +# A series of end-to-end tests on the Please binary. +# +# These are a little fragile since they assume things about specific output messages, which +# of course we might rather not. However it's something of a pain to get good test coverage +# since by its nature the tool has heaps of side effects, so this is at least one way of +# reassuring ourselves that it does behave as expected. +# +# Note that we have to be kinda careful with this; since it invokes plz to run tests while +# an instance of it is already going, there are potential concurrency issues. These are +# mitigated by having these tests only run tests in this package which are tagged as manual +# so the bootstrap script won't try to run them twice simultaneously. + +subinclude('//test/build_defs:plz_e2e_test') + +export_file( + name = 'plz_e2e_test_build_defs', + src = 'plz_e2e_test.build_defs', +) + +# Tests the expected output of 'query somepath'. +# Note that you have to be careful with the choice of targets, since the path +# found is not necessarily unique or stable. +plz_e2e_test( + name = 'query_somepath_test', + cmd = 'plz query somepath //src/build/python:bootstrap_pexer //third_party/python:coverage', + expected_output = 'query_somepath_test.txt', +) +plz_e2e_test( + name = 'query_somepath_reverse_test', + cmd = 'plz query somepath //third_party/python:coverage //src/build/python:bootstrap_pexer', + expected_output = 'query_somepath_test.txt', # Output should be the same as above +) +plz_e2e_test( + name = 'query_somepath_nopath_test', + cmd = 'plz query somepath //src:please //third_party/java:guava', + expected_output = 'query_somepath_nopath_test.txt', +) + +# Tests that targets can only use other targets that they depend on. +plz_e2e_test( + name = 'dep_required_test', + cmd = 'plz build //test:failed_dep', + expect_output_contains = "//test:failed_dep can't use //src/core; doesn't depend on target //src/core", + expected_failure = True, +) +genrule( + name = 'failed_dep', + cmd = 'echo $(location //src/core)', +) + +# Test that we count test output correctly. Also indirectly tests access to test data files. +# Note that we're stripping coloured output for now. Later we should probably have a flag or something. +plz_e2e_test( + name = 'test_output_test', + cmd = 'plz test //test:test_output_test_1 //test:test_output_test_2 | sed "s/\x1B\[[0-9;]*[a-zA-Z]//g"', + expect_output_contains = '6 tests run; 6 passed.', + # Invokes a containerised test although it's not itself. + labels = ['container'], +) +gentest( + name = 'test_output_test_1', + data = ['test_output_test_1.txt'], + test_cmd = 'cp $(location test_output_test_1.txt) test.results', + labels = ['manual'], +) +gentest( + name = 'test_output_test_2', + data = ['test_output_test_2.xml'], + test_cmd = 'cp $(location test_output_test_2.xml) test.results', + container = True, + labels = ['manual'], +) + +# Test that on re-running a test it is cached. +plz_e2e_test( + name = 'test_caching_test', + cmd = 'plz test //test:caching_test && plz test -v 4 //test:caching_test', + expect_output_contains = 'Not re-running test //test:caching_test', +) +gentest( + name = 'caching_test', + test_cmd = 'true', + deps = ['//src:please'], + no_test_output = True, + labels = ['manual'], +) + +# Test that we don't generate coverage on running a test normally (because it's slower). +python_test( + name = '_no_coverage_output_test', + srcs = ['coverage_output_test.py'], + labels = ['manual'], +) +plz_e2e_test( + name = 'no_coverage_output_test', + cmd = 'plz test //test:_no_coverage_output_test', + expect_file_doesnt_exist = '../../../bin/test/.test_coverage__no_coverage_output_test*', +) +# Test that we do generate it when using plz cover. +python_test( + name = '_coverage_output_test', + srcs = ['coverage_output_test.py'], + labels = ['manual'], +) +plz_e2e_test( + name = 'coverage_output_test', + cmd = 'plz cover //test:_coverage_output_test', + expect_file_exists = '../../../bin/test/.test_coverage__coverage_output_test*', +) + +# Quick test for plz run +plz_e2e_test( + name = 'plz_run_test', + cmd = 'plz run //src:please -- --version', + expect_output_contains = 'Please version', +) + +# Test for query alltargets +plz_e2e_test( + name = 'query_alltargets_test', + cmd = 'plz query alltargets', + expect_output_contains = '//src:please', +) + +# Test for query output +plz_e2e_test( + name = 'query_output_test', + cmd = 'plz query output //test:query_output_filegroup', + expected_output = 'query_output_test.txt', +) +filegroup( + name = 'query_output_filegroup', + srcs = ['//src:please'], +) + +# Test running a test with no-cache +plz_e2e_test( + name = 'test_nocache_test', + cmd = 'plz test --no_cache //test:nocache_test', +) +gentest( + name = 'nocache_test', + test_cmd = 'true', + deps = ['//src:please'], + no_test_output = True, + labels = ['manual'], +) + +# Simulates a code generating rule to test the require / provide mechanism. +plz_e2e_test( + name = 'require_provide_test', + cmd = 'plz build //test/moar:require_provide_check -v 2 -p', + expect_output_doesnt_contain = '//test/moar:test_require', +) + +# Test for running individual tests +python_test( + name = 'individual_test_run_py', + srcs = ['individual_test_run.py'], + labels = ['manual'], +) +plz_e2e_test( + name = 'individual_python_test', + cmd = 'plz test //test:individual_test_run_py TestRunningIndividualTests.test_first_thing', + expect_output_contains = '1 test target and 1 test run', +) +java_test( + name = 'individual_test_run_java', + srcs = ['IndividualTestRun.java'], + labels = ['manual'], + deps = [ + '//third_party/java:junit', + ], +) +plz_e2e_test( + name = 'individual_java_test', + cmd = 'plz test //test:individual_test_run_java testFirstThing', + expect_output_contains = '1 test target and 1 test run', +) +java_test( + name = 'no_test_run_java', + srcs = ['NoTestRun.java'], + labels = ['manual'], + deps = [ + '//third_party/java:junit', + ], +) +plz_e2e_test( + name = 'no_java_test', + cmd = 'plz test -p //test:no_test_run_java wibblewobble', + expect_output_contains = '1 failed', + expected_failure = True, +) + +# Test re-runs. +go_test( + name = '_num_runs_test', + srcs = ['num_runs_test.go'], +) +plz_e2e_test( + name = 'num_runs_test', + cmd = 'plz test -p --num_runs=5 //test:_num_runs_test', + expect_output_contains = '5 passed', +) + +# Tests for query affectedtests. +plz_e2e_test( + name = 'query_affectedtests_test', + cmd = 'plz query affectedtests -p test/affectedtests_test.go', + expected_output = 'query_affectedtests_test.txt', +) +plz_e2e_test( + name = 'query_affectedtests_stdin_test', + cmd = 'echo test/affectedtests_test.go | plz query affectedtests -p -', + expected_output = 'query_affectedtests_test.txt', +) +go_test( + name = '_affectedtests_test', + srcs = ['affectedtests_test.go'], +) +go_test( + name = '_affectedtests_manual_test', + srcs = ['affectedtests_test.go'], + labels = ['manual'], +) + +# Tests for query completions +plz_e2e_test( + name = 'basic_completion_test', + cmd = 'plz query completions //test/completions: | sort', + expected_output = 'basic_completions.txt', +) +plz_e2e_test( + name = 'build_completion_test', + cmd = 'plz query completions //test/completions: --cmd build | sort', + expected_output = 'basic_completions.txt', +) +plz_e2e_test( + name = 'test_completion_test', + cmd = 'plz query completions //test/completions: --cmd test | sort', + expected_output = 'test_completions.txt', +) +plz_e2e_test( + name = 'run_completion_test', + cmd = 'plz query completions //test/completions: --cmd run | sort', + expected_output = 'run_completions.txt', +) + +# Flag tests +plz_e2e_test( + name = 'extra_flag_test', + cmd = 'plz cache clean', + expected_failure = True, +) + +# Test the add_out functionality which has a subtle dependency on the order +# we do things relating to the cache. +genrule( + name = '_add_out_gen', + cmd = 'echo hello > _add_out_gen.txt', + post_build = lambda name, _: add_out(name, '_add_out_gen.txt'), +) +gentest( + name = '_add_out_test', + data = [':_add_out_gen'], + test_cmd = 'ls test/_add_out_gen.txt', + no_test_output = True, + labels = ['manual'], +) +plz_e2e_test( + name = 'add_out_test', + cmd = 'plz build //test:_add_out_test && plz clean //test:_add_out_gen && plz test //test:_add_out_test', +) + +# Test the extra output functionality. +python_test( + name = '_extra_test_output_test', + srcs = ['extra_test_output_test.py'], + test_outputs = ['truth.txt'], + labels = ['manual'], + container = True, + interpreter = '/usr/bin/python3', # Docker image doesn't have /usr/bin/python +) +plz_e2e_test( + name = 'extra_test_output_test', + cmd = 'plz test //test:_extra_test_output_test', + expect_file_exists = '../../../bin/test/truth.txt', + labels = ['container', 'py3'], +) diff --git a/test/IndividualTestRun.java b/test/IndividualTestRun.java new file mode 100644 index 0000000000..dff26fc73b --- /dev/null +++ b/test/IndividualTestRun.java @@ -0,0 +1,20 @@ +package net.thoughtmachine.please.test; + +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class IndividualTestRun { + // Test for running individual Java tests. + + @Test + public void testFirstThing() { + assertEquals(42, 6 * 7); + } + + @Test + public void testOtherThing() { + assertEquals(19, 10 + 9); + } +} diff --git a/test/NoTestRun.java b/test/NoTestRun.java new file mode 100644 index 0000000000..9643c365f8 --- /dev/null +++ b/test/NoTestRun.java @@ -0,0 +1,10 @@ +package net.thoughtmachine.please.test; + +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class NoTestRun { + // Test for a Java test that has no actual test cases. +} diff --git a/test/affectedtests_test.go b/test/affectedtests_test.go new file mode 100644 index 0000000000..895b27b8f5 --- /dev/null +++ b/test/affectedtests_test.go @@ -0,0 +1,9 @@ +// Dummy test for testing 'plz query affectedtests. + +package test + +import "testing" + + +func TestAffectedTests(t *testing.T) { +} diff --git a/test/basic_completions.txt b/test/basic_completions.txt new file mode 100644 index 0000000000..1c9e744eca --- /dev/null +++ b/test/basic_completions.txt @@ -0,0 +1,4 @@ +//test/completions:all +//test/completions:binary +//test/completions:library +//test/completions:test diff --git a/test/build_defs/BUILD b/test/build_defs/BUILD new file mode 100644 index 0000000000..ffe03cda93 --- /dev/null +++ b/test/build_defs/BUILD @@ -0,0 +1,5 @@ +export_file( + name = 'plz_e2e_test', + src = 'plz_e2e_test.build_defs', + visibility = ['//test/...'], +) diff --git a/test/build_defs/plz_e2e_test.build_defs b/test/build_defs/plz_e2e_test.build_defs new file mode 100644 index 0000000000..a6d1e3dafc --- /dev/null +++ b/test/build_defs/plz_e2e_test.build_defs @@ -0,0 +1,38 @@ +# Rules for end-to-end tests on Please itself. + +def plz_e2e_test(name, cmd, expected_output=None, expected_failure=False, + expect_output_contains=None, expect_output_doesnt_contain=None, + deps=None, data=None, labels=None, + expect_file_exists=None, expect_file_doesnt_exist=None): + # Please isn't really designed to work this way (running a test against the entire source repo) + # but we can make it do it and it's a convenient way of testing the tool itself. + cmd = cmd.replace('plz', '$(location //src:please) --nolock') + data = (data or []) + ['//src:please'] + if expected_failure: + test_cmd = '%s 2>&1 | tee output; if [ $? -eq 0 ]; then exit 1; fi; ' % cmd + else: + test_cmd = '%s 2>&1 | tee output && ' % cmd + if expected_output and expect_output_contains: + raise ValueError('Can only pass one of expected_output and expect_output_contains') + elif expected_output: + test_cmd += 'diff -au output $(location %s)' % expected_output + data.append(expected_output) + elif expect_output_contains: + test_cmd += 'if [ ! grep -v "%s" output ]; then cat output; exit 1; fi' % expect_output_contains + elif expect_output_doesnt_contain: + test_cmd += 'if [ ! grep "%s" output ]; then cat output; exit 1; fi' % expect_output_doesnt_contain + elif expect_file_exists: + test_cmd += 'if [ ! -f %s ]; then cat output; exit 1; fi' % expect_file_exists + elif expect_file_doesnt_exist: + test_cmd += 'if [ -f %s ]; then cat output; exit 1; fi' % expect_file_doesnt_exist + else: + test_cmd += 'true' + + gentest( + name = name, + test_cmd='set -o pipefail; ' + test_cmd, + data = data, + deps = deps, + labels = ['e2e'] + (labels or []), + no_test_output = True, + ) diff --git a/test/cc_rules/BUILD b/test/cc_rules/BUILD new file mode 100644 index 0000000000..733b79dc20 --- /dev/null +++ b/test/cc_rules/BUILD @@ -0,0 +1,54 @@ +subinclude('//test/build_defs:plz_e2e_test') + +# Test the way cc rules depend on one another; ideally we should be able to +# pick up all transitive dependencies correctly but compile the .o files independently. + +cc_library( + name = 'lib1', + srcs = ['lib1.cc'], + hdrs = ['lib1.h'], +) + +cc_library( + name = 'lib2', + srcs = ['lib2.cc'], + hdrs = ['lib2.h'], + deps = [ + ':lib1', + ], +) + +cc_test( + name = 'cc_deps_test', + srcs = ['deps_test.cc'], + deps = [ + ':lib2', + ], +) + +# lib2 should express a direct dependency on lib1 +plz_e2e_test( + name = 'cc_query_somepath_test_1', + cmd = 'plz query somepath //test/cc_rules:lib2 //test/cc_rules:lib1', + expected_output = 'cc_query_somepath_test_1.txt', +) + +# lib2's object file should not have any dependency on lib1's though. +plz_e2e_test( + name = 'cc_query_somepath_test_2', + cmd = 'plz query somepath //test/cc_rules:_lib2#a //test/cc_rules:_lib1#a', + expected_output = 'cc_query_somepath_test_2.txt', +) + +# These rules test that cc_library correctly accepts multiple srcs. +cc_library( + name = 'multisrc_lib', + srcs = ['multisrc_1.cc', 'multisrc_2.cc'], + hdrs = ['multisrc.h'], +) + +cc_test( + name = 'cc_multisrc_test', + srcs = ['cc_multisrc_test.cc'], + deps = [':multisrc_lib'], +) diff --git a/test/cc_rules/cc_multisrc_test.cc b/test/cc_rules/cc_multisrc_test.cc new file mode 100644 index 0000000000..78635a0a3c --- /dev/null +++ b/test/cc_rules/cc_multisrc_test.cc @@ -0,0 +1,11 @@ +#include "test/cc_rules/multisrc.h" + +#include + +TEST(Multisrc1Result) { + CHECK_EQUAL(42, MultisrcFunction1()); +} + +TEST(Multisrc2Result) { + CHECK_EQUAL(19, MultisrcFunction2()); +} diff --git a/test/cc_rules/cc_query_somepath_test_1.txt b/test/cc_rules/cc_query_somepath_test_1.txt new file mode 100644 index 0000000000..f75eb74ee9 --- /dev/null +++ b/test/cc_rules/cc_query_somepath_test_1.txt @@ -0,0 +1,3 @@ +Found path: + //test/cc_rules:lib2 + //test/cc_rules:lib1 diff --git a/test/cc_rules/cc_query_somepath_test_2.txt b/test/cc_rules/cc_query_somepath_test_2.txt new file mode 100644 index 0000000000..d682cbd727 --- /dev/null +++ b/test/cc_rules/cc_query_somepath_test_2.txt @@ -0,0 +1 @@ +Couldn't find any dependency path between //test/cc_rules:_lib2#a and //test/cc_rules:_lib1#a diff --git a/test/cc_rules/deps_test.cc b/test/cc_rules/deps_test.cc new file mode 100644 index 0000000000..4a87681473 --- /dev/null +++ b/test/cc_rules/deps_test.cc @@ -0,0 +1,18 @@ +// Trivial test that doesn't really do much. Only exists for us to +// check its dependencies are set up as expected. + +#include +#include "test/cc_rules/lib1.h" +#include "test/cc_rules/lib2.h" + +namespace thought_machine { + +TEST(Number1) { + CHECK_EQUAL(107, get_number_1()); +} + +TEST(Number2) { + CHECK_EQUAL(215, get_number_2()); +} + +} diff --git a/test/cc_rules/lib1.cc b/test/cc_rules/lib1.cc new file mode 100644 index 0000000000..12be0adc52 --- /dev/null +++ b/test/cc_rules/lib1.cc @@ -0,0 +1,9 @@ +#include "test/cc_rules/lib1.h" + +namespace thought_machine { + +int get_number_1() { + return 107; +} + +} // namespace thought_machine diff --git a/test/cc_rules/lib1.h b/test/cc_rules/lib1.h new file mode 100644 index 0000000000..f21fbf2aa8 --- /dev/null +++ b/test/cc_rules/lib1.h @@ -0,0 +1,10 @@ +#ifndef _TEST_CC_RULES_LIB1_H +#define _TEST_CC_RULES_LIB1_H + +namespace thought_machine { + +int get_number_1(); + +} // namespace thought_machine + +#endif // _TEST_CC_RULES_LIB1_H diff --git a/test/cc_rules/lib2.cc b/test/cc_rules/lib2.cc new file mode 100644 index 0000000000..0755d4b2ad --- /dev/null +++ b/test/cc_rules/lib2.cc @@ -0,0 +1,9 @@ +#include "test/cc_rules/lib1.h" + +namespace thought_machine { + +int get_number_2() { + return 215; +} + +} // namespace thought_machine diff --git a/test/cc_rules/lib2.h b/test/cc_rules/lib2.h new file mode 100644 index 0000000000..5b7e3e0401 --- /dev/null +++ b/test/cc_rules/lib2.h @@ -0,0 +1,10 @@ +#ifndef _TEST_CC_RULES_LIB2_H +#define _TEST_CC_RULES_LIB2_H + +namespace thought_machine { + +int get_number_2(); + +} // namespace thought_machine + +#endif // _TEST_CC_RULES_LIB2_H diff --git a/test/cc_rules/multisrc.h b/test/cc_rules/multisrc.h new file mode 100644 index 0000000000..ac05bb8595 --- /dev/null +++ b/test/cc_rules/multisrc.h @@ -0,0 +1,7 @@ +#ifndef _TEST_CC_RULES_MULTISRC_H +#define _TEST_CC_RULES_MULTISRC_H + +int MultisrcFunction1(); +int MultisrcFunction2(); + +#endif // _TEST_CC_RULES_MULTISRC_H diff --git a/test/cc_rules/multisrc_1.cc b/test/cc_rules/multisrc_1.cc new file mode 100644 index 0000000000..5bdb56dfde --- /dev/null +++ b/test/cc_rules/multisrc_1.cc @@ -0,0 +1,5 @@ +#include "test/cc_rules/multisrc.h" + +int MultisrcFunction1() { + return 42; +} diff --git a/test/cc_rules/multisrc_2.cc b/test/cc_rules/multisrc_2.cc new file mode 100644 index 0000000000..2a556afd4a --- /dev/null +++ b/test/cc_rules/multisrc_2.cc @@ -0,0 +1,5 @@ +#include "test/cc_rules/multisrc.h" + +int MultisrcFunction2() { + return 19; +} diff --git a/test/completions/BUILD b/test/completions/BUILD new file mode 100644 index 0000000000..ada5adf960 --- /dev/null +++ b/test/completions/BUILD @@ -0,0 +1,22 @@ +# A little suite of targets that we use to test completions. + +genrule( + name = 'library', + outs = ['lib.txt'], + cmd = 'touch $OUT', +) + +genrule( + name = 'binary', + outs = ['bin.sh'], + cmd = 'touch $OUT', + binary = True, +) + +gentest( + name = 'test', + outs = ['test.sh'], + cmd = 'touch $OUT', + test_cmd = 'true', + labels = ['manual'], +) diff --git a/test/coverage_output_test.py b/test/coverage_output_test.py new file mode 100644 index 0000000000..01f2818f94 --- /dev/null +++ b/test/coverage_output_test.py @@ -0,0 +1,12 @@ +#!/usr/bin/python +# +# Dummy test file for some of the e2e tests. + +import unittest + + +class CoverageOutputTest(unittest.TestCase): + + def test_stuff(self): + """Test that the flux capacitor is correctly calibrated.""" + self.assertEquals(2, 2) diff --git a/test/extra_test_output_test.py b/test/extra_test_output_test.py new file mode 100644 index 0000000000..72d3ab0350 --- /dev/null +++ b/test/extra_test_output_test.py @@ -0,0 +1,11 @@ +import base64 +import unittest + +MSG = 'UmljY2FyZG8gbGlrZXMgcGluZWFwcGxlIHBpenphCg==' + + +class TestExtraTestOutput(unittest.TestCase): + + def test_extra_output(self): + with open('truth.txt', 'wb') as f: + f.write(base64.b64decode(MSG)) diff --git a/test/go_rules/BUILD b/test/go_rules/BUILD new file mode 100644 index 0000000000..02857fab3d --- /dev/null +++ b/test/go_rules/BUILD @@ -0,0 +1,25 @@ +# Test on the builtin go rules +go_library( + name = 'go_rules_test_lib', + srcs = ['go_rules_test_lib.go'], + deps = [ + '//test/go_rules/test', + ], + test_only = True, +) +go_binary( + name = 'go_rules_test_bin', + main = 'go_rules_test_bin.go', + deps = [ + ':go_rules_test_lib', + ], + test_only = True, +) +gentest( + name = 'go_rules_test', + test_cmd = '$(location :go_rules_test_bin)', + data = [ + ':go_rules_test_bin', + ], + no_test_output = True, +) diff --git a/test/go_rules/go_rules_test_bin.go b/test/go_rules/go_rules_test_bin.go new file mode 100644 index 0000000000..9a52d56c92 --- /dev/null +++ b/test/go_rules/go_rules_test_bin.go @@ -0,0 +1,13 @@ +// Used for testing the builtin Go rules. +package main + +import "os" +import "go_rules/test" + +func main() { + if test.GetAnswer() == 42 { + os.Exit(0) + } else { + os.Exit(1) + } +} diff --git a/test/go_rules/go_rules_test_lib.go b/test/go_rules/go_rules_test_lib.go new file mode 100644 index 0000000000..595678f883 --- /dev/null +++ b/test/go_rules/go_rules_test_lib.go @@ -0,0 +1,8 @@ +// Intermediate library used in this test. +package parse + +import "go_rules/test" + +func GetAnswer() int { + return test.GetAnswer() +} diff --git a/test/go_rules/test/BUILD b/test/go_rules/test/BUILD new file mode 100644 index 0000000000..566b5df927 --- /dev/null +++ b/test/go_rules/test/BUILD @@ -0,0 +1,8 @@ +# For testing the go build commands, where we need to be careful about things +# being in subdirectories. +go_library( + name = 'test', + srcs = ['test.go'], + visibility = ['//test/...'], + test_only = True, +) diff --git a/test/go_rules/test/test.go b/test/go_rules/test/test.go new file mode 100644 index 0000000000..dc17a42c4d --- /dev/null +++ b/test/go_rules/test/test.go @@ -0,0 +1,6 @@ +package test + + +func GetAnswer() int { + return 42 +} diff --git a/test/individual_test_run.py b/test/individual_test_run.py new file mode 100644 index 0000000000..2b248c8392 --- /dev/null +++ b/test/individual_test_run.py @@ -0,0 +1,13 @@ +import unittest + + +class TestRunningIndividualTests(unittest.TestCase): + + def test_first_thing(self): + pass + + def test_second_thing(self): + pass + + def test_other_thing(self): + pass diff --git a/test/moar/BUILD b/test/moar/BUILD new file mode 100644 index 0000000000..e1712be6ec --- /dev/null +++ b/test/moar/BUILD @@ -0,0 +1,30 @@ +# For testing certain things that require targets to be in a separate package. + +package(default_visibility=['//test/...']) + +genrule( + name = 'test_require_py', + outs = ['test_require.py'], + cmd = 'touch $OUT', +) +genrule( + name = 'test_require_go', + outs = ['test_require.go'], + cmd = 'touch $OUT', +) +filegroup( + name = 'test_require_fg', + srcs = [':test_require_py', ':test_require_go'], + deps = [':test_require_py', ':test_require_go'], + provides = { + 'py': ':test_require_py', + 'go': ':test_require_go', + } +) +python_library( + name = 'require_provide_check', + srcs = [], + deps = [ + ':test_require_fg', + ], +) diff --git a/test/num_runs_test.go b/test/num_runs_test.go new file mode 100644 index 0000000000..99974f5b2a --- /dev/null +++ b/test/num_runs_test.go @@ -0,0 +1,10 @@ +package test + +import "testing" +import "time" + +func TestNumRuns(t *testing.T) { + // Just take up a little time here so it's obvious how a number of runs + // multiplies up the duration (Go's so fast that this is essentially instant otherwise). + time.Sleep(100 * time.Millisecond) +} diff --git a/test/proto_rules/BUILD b/test/proto_rules/BUILD new file mode 100644 index 0000000000..b98213d414 --- /dev/null +++ b/test/proto_rules/BUILD @@ -0,0 +1,14 @@ +# Tests on the proto rules. + +proto_library( + name = 'test_proto', + srcs = ['test.proto'], +) + +python_test( + name = 'specific_out_test', + srcs = ['specific_out_test.py'], + deps = [ + ':test_proto', + ], +) diff --git a/test/proto_rules/specific_out_test.py b/test/proto_rules/specific_out_test.py new file mode 100644 index 0000000000..6adfb6cbba --- /dev/null +++ b/test/proto_rules/specific_out_test.py @@ -0,0 +1,18 @@ +import pkg_resources +import unittest + + +class SpecificOutTest(unittest.TestCase): + + @unittest.skip('Need third party module override') + def test_python_module_is_importable(self): + """Check that the Python module came through OK.""" + from test.proto_rules import test_pb2 + + def test_no_go_files(self): + """Test that there aren't any Go files in the .pex. + + If this fails the way the proto rules depend on specific files from the protoc rule + probably isn't being selective enough. + """ + self.assertFalse(pkg_resources.resource_exists('test.proto_rules', 'test.pb.go')) diff --git a/test/proto_rules/test.proto b/test/proto_rules/test.proto new file mode 100644 index 0000000000..0c418cb2f1 --- /dev/null +++ b/test/proto_rules/test.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +package proto_rules; + +message TestMessage { + string id = 1; +} \ No newline at end of file diff --git a/test/query_affectedtests_test.txt b/test/query_affectedtests_test.txt new file mode 100644 index 0000000000..a9c032275a --- /dev/null +++ b/test/query_affectedtests_test.txt @@ -0,0 +1 @@ +//test:_affectedtests_test diff --git a/test/query_output_test.txt b/test/query_output_test.txt new file mode 100644 index 0000000000..f19f69554c --- /dev/null +++ b/test/query_output_test.txt @@ -0,0 +1 @@ +plz-out/gen/test/please diff --git a/test/query_somepath_nopath_test.txt b/test/query_somepath_nopath_test.txt new file mode 100644 index 0000000000..77797c91e1 --- /dev/null +++ b/test/query_somepath_nopath_test.txt @@ -0,0 +1 @@ +Couldn't find any dependency path between //src:please and //third_party/java:guava diff --git a/test/query_somepath_test.txt b/test/query_somepath_test.txt new file mode 100644 index 0000000000..454addb4c4 --- /dev/null +++ b/test/query_somepath_test.txt @@ -0,0 +1,4 @@ +Found path: + //src/build/python:bootstrap_pexer + //src/build/python:main_files + //third_party/python:coverage diff --git a/test/run_completions.txt b/test/run_completions.txt new file mode 100644 index 0000000000..ad76398005 --- /dev/null +++ b/test/run_completions.txt @@ -0,0 +1 @@ +//test/completions:binary diff --git a/test/test_completions.txt b/test/test_completions.txt new file mode 100644 index 0000000000..10a8be3ab6 --- /dev/null +++ b/test/test_completions.txt @@ -0,0 +1 @@ +//test/completions:test diff --git a/test/test_output_test_1.txt b/test/test_output_test_1.txt new file mode 100644 index 0000000000..82b771365b --- /dev/null +++ b/test/test_output_test_1.txt @@ -0,0 +1,9 @@ +=== RUN TestJSONExpectedFailure-6 +--- PASS: TestJSONExpectedFailure-6 (0.00s) +=== RUN TestJSONSkipped-6 +--- PASS: TestJSONSkipped-6 (0.00s) +=== RUN TestBuckXML-6 +--- PASS: TestBuckXML-6 (0.00s) +=== RUN TestJUnitXML-6 +--- PASS: TestJUnitXML-6 (0.00s) +PASS diff --git a/test/test_output_test_2.xml b/test/test_output_test_2.xml new file mode 100644 index 0000000000..9b09c371e1 --- /dev/null +++ b/test/test_output_test_2.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/third_party/go/BUILD b/third_party/go/BUILD new file mode 100644 index 0000000000..1da1273ec7 --- /dev/null +++ b/third_party/go/BUILD @@ -0,0 +1,103 @@ +package(default_visibility = ['PUBLIC']) + +go_get( + name = 'logging', + get = 'github.com/op/go-logging', + revision = 'dfaf3dff9b631bc4236201d90d41ee0de9202889', +) + +go_get( + name = 'terminal', + get = 'golang.org/x/crypto/ssh/terminal', + revision = '7b85b097bf7527677d54d3220065e966a0e3b613', +) + +go_get( + name = 'cover', + get = 'golang.org/x/tools/cover', + revision = 'c0008c5889c0d5091cdfefd2bfb08bff96527879', +) + +go_get( + name = 'gcfg', + get = 'gopkg.in/gcfg.v1', + revision = 'a3bc0742e3bbfd16123e6cee742cadec9a3301d2', + patch = 'gcfg_dynamic_fields.patch', +) + +go_get( + name = 'go-bindata', + get = 'github.com/jteeuwen/go-bindata/...', + revision = 'a0ff2567cfb70903282db057e799fd826784d41d', + binary = True, +) + +go_get( + name = 'go-flags', + get = 'github.com/jessevdk/go-flags', + revision = '0a28dbe50f23d8fce6b016975b964cfe7b97a20a', +) + +go_get( + name = 'humanize', + get = 'github.com/dustin/go-humanize', + revision = '8929fe90cee4b2cb9deb468b51fb34eba64d1bf0', +) + +go_get( + name = 'mux', + get = 'github.com/gorilla/mux', + revision = '9c068cf16d982f8bd444b8c352acbeec34c4fe5b', + deps = [ + ':gorilla_context', + ], +) + +go_get( + name = 'gorilla_context', + get = 'github.com/gorilla/context', + revision = '1c83b3eabd45b6d76072b66b746c20815fb2872d', +) + +go_get( + name = 'grpc', + get = 'google.golang.org/grpc', + revision = 'ecd68681d46b97d7c84e7c7d12ee7a04c138a9fa', + deps = [ + ':protobuf', + ], +) + +go_get( + name = 'protoc-gen-go', + get = 'github.com/golang/protobuf/protoc-gen-go', + revision = '087949061006daa57b3a3be58d77092cf65f6cf7', + binary = True, +) + +go_get( + name = 'protobuf', + get = 'github.com/golang/protobuf/proto', + revision = '2402d76f3d41f928c7902a765dfc872356dd3aad', +) + +go_get( + name = 'testify', + get = 'github.com/stretchr/testify', + revision = 'f390dcf405f7b83c997eac1b06768bb9f44dec18', +) + +go_get( + name = 'osext', + get = 'github.com/kardianos/osext', + revision = '29ae4ffbc9a6fe9fb2bc5029050ce6996ea1d3bc', +) + +go_get( + name = 'prompter', + get = 'github.com/Songmu/prompter', + revision = 'f49666b0047d12850875d771340e1d862d9e7a0c', + deps = [ + ':terminal', + ], +) diff --git a/third_party/go/gcfg_dynamic_fields.patch b/third_party/go/gcfg_dynamic_fields.patch new file mode 100644 index 0000000000..55d29472bb --- /dev/null +++ b/third_party/go/gcfg_dynamic_fields.patch @@ -0,0 +1,24 @@ +diff --git a/set.go b/set.go +index 6ca1051..43de5dc 100644 +--- a/set.go ++++ b/set.go +@@ -201,6 +201,19 @@ func set(cfg interface{}, sect, sub, name string, blank bool, value string) erro + } + if vSect.Kind() == reflect.Map { + vst := vSect.Type() ++ if vst.Key().Kind() == reflect.String && vst.Elem().Kind() == reflect.String { ++ if vSect.IsNil() { ++ vSect.Set(reflect.MakeMap(vst)) ++ } ++ if value != "" { ++ if sub != "" { ++ vSect.SetMapIndex(reflect.ValueOf(sub + " " + name), reflect.ValueOf(value)) ++ } else { ++ vSect.SetMapIndex(reflect.ValueOf(name), reflect.ValueOf(value)) ++ } ++ } ++ return nil ++ } + if vst.Key().Kind() != reflect.String || + vst.Elem().Kind() != reflect.Ptr || + vst.Elem().Elem().Kind() != reflect.Struct { diff --git a/third_party/go/src/zip/BUILD b/third_party/go/src/zip/BUILD new file mode 100644 index 0000000000..8141d3578e --- /dev/null +++ b/third_party/go/src/zip/BUILD @@ -0,0 +1,9 @@ +# This directory contains a copy of the Go standard library archive/zip +# package that we need to make some minor modifications to. +# The code is therefore still copyright to the Go authors. + +go_library( + name = 'zip', + srcs = glob(['*.go']), + visibility = ['PUBLIC'], +) diff --git a/third_party/go/src/zip/reader.go b/third_party/go/src/zip/reader.go new file mode 100644 index 0000000000..8136b840d4 --- /dev/null +++ b/third_party/go/src/zip/reader.go @@ -0,0 +1,453 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package zip + +import ( + "bufio" + "encoding/binary" + "errors" + "hash" + "hash/crc32" + "io" + "os" +) + +var ( + ErrFormat = errors.New("zip: not a valid zip file") + ErrAlgorithm = errors.New("zip: unsupported compression algorithm") + ErrChecksum = errors.New("zip: checksum error") +) + +type Reader struct { + r io.ReaderAt + File []*File + Comment string +} + +type ReadCloser struct { + f *os.File + Reader +} + +type File struct { + FileHeader + zipr io.ReaderAt + zipsize int64 + headerOffset int64 +} + +func (f *File) hasDataDescriptor() bool { + return f.Flags&0x8 != 0 +} + +// OpenReader will open the Zip file specified by name and return a ReadCloser. +func OpenReader(name string) (*ReadCloser, error) { + f, err := os.Open(name) + if err != nil { + return nil, err + } + fi, err := f.Stat() + if err != nil { + f.Close() + return nil, err + } + r := new(ReadCloser) + if err := r.init(f, fi.Size()); err != nil { + f.Close() + return nil, err + } + r.f = f + return r, nil +} + +// NewReader returns a new Reader reading from r, which is assumed to +// have the given size in bytes. +func NewReader(r io.ReaderAt, size int64) (*Reader, error) { + zr := new(Reader) + if err := zr.init(r, size); err != nil { + return nil, err + } + return zr, nil +} + +func (z *Reader) init(r io.ReaderAt, size int64) error { + end, err := readDirectoryEnd(r, size) + if err != nil { + return err + } + z.r = r + z.File = make([]*File, 0, end.directoryRecords) + z.Comment = end.comment + rs := io.NewSectionReader(r, 0, size) + if _, err = rs.Seek(int64(end.directoryOffset), os.SEEK_SET); err != nil { + return err + } + buf := bufio.NewReader(rs) + + // The count of files inside a zip is truncated to fit in a uint16. + // Gloss over this by reading headers until we encounter + // a bad one, and then only report a ErrFormat or UnexpectedEOF if + // the file count modulo 65536 is incorrect. + for { + f := &File{zipr: r, zipsize: size} + err = readDirectoryHeader(f, buf) + if err == ErrFormat || err == io.ErrUnexpectedEOF { + break + } + if err != nil { + return err + } + z.File = append(z.File, f) + } + if uint16(len(z.File)) != uint16(end.directoryRecords) { // only compare 16 bits here + // Return the readDirectoryHeader error if we read + // the wrong number of directory entries. + return err + } + return nil +} + +// Close closes the Zip file, rendering it unusable for I/O. +func (rc *ReadCloser) Close() error { + return rc.f.Close() +} + +// DataOffset returns the offset of the file's possibly-compressed +// data, relative to the beginning of the zip file. +// +// Most callers should instead use Open, which transparently +// decompresses data and verifies checksums. +func (f *File) DataOffset() (offset int64, err error) { + bodyOffset, err := f.findBodyOffset() + if err != nil { + return + } + return f.headerOffset + bodyOffset, nil +} + +// Open returns a ReadCloser that provides access to the File's contents. +// Multiple files may be read concurrently. +func (f *File) Open() (rc io.ReadCloser, err error) { + bodyOffset, err := f.findBodyOffset() + if err != nil { + return + } + size := int64(f.CompressedSize64) + r := io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset, size) + dcomp := decompressor(f.Method) + if dcomp == nil { + err = ErrAlgorithm + return + } + rc = dcomp(r) + var desr io.Reader + if f.hasDataDescriptor() { + desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen) + } + rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil} + return +} + +type checksumReader struct { + rc io.ReadCloser + hash hash.Hash32 + f *File + desr io.Reader // if non-nil, where to read the data descriptor + err error // sticky error +} + +func (r *checksumReader) Read(b []byte) (n int, err error) { + if r.err != nil { + return 0, r.err + } + n, err = r.rc.Read(b) + r.hash.Write(b[:n]) + if err == nil { + return + } + if err == io.EOF { + if r.desr != nil { + if err1 := readDataDescriptor(r.desr, r.f); err1 != nil { + err = err1 + } else if r.hash.Sum32() != r.f.CRC32 { + err = ErrChecksum + } + } else { + // If there's not a data descriptor, we still compare + // the CRC32 of what we've read against the file header + // or TOC's CRC32, if it seems like it was set. + if r.f.CRC32 != 0 && r.hash.Sum32() != r.f.CRC32 { + err = ErrChecksum + } + } + } + r.err = err + return +} + +func (r *checksumReader) Close() error { return r.rc.Close() } + +// findBodyOffset does the minimum work to verify the file has a header +// and returns the file body offset. +func (f *File) findBodyOffset() (int64, error) { + var buf [fileHeaderLen]byte + if _, err := f.zipr.ReadAt(buf[:], f.headerOffset); err != nil { + return 0, err + } + b := readBuf(buf[:]) + if sig := b.uint32(); sig != fileHeaderSignature { + return 0, ErrFormat + } + b = b[22:] // skip over most of the header + filenameLen := int(b.uint16()) + extraLen := int(b.uint16()) + return int64(fileHeaderLen + filenameLen + extraLen), nil +} + +// readDirectoryHeader attempts to read a directory header from r. +// It returns io.ErrUnexpectedEOF if it cannot read a complete header, +// and ErrFormat if it doesn't find a valid header signature. +func readDirectoryHeader(f *File, r io.Reader) error { + var buf [directoryHeaderLen]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + return err + } + b := readBuf(buf[:]) + if sig := b.uint32(); sig != directoryHeaderSignature { + return ErrFormat + } + f.CreatorVersion = b.uint16() + f.ReaderVersion = b.uint16() + f.Flags = b.uint16() + f.Method = b.uint16() + f.ModifiedTime = b.uint16() + f.ModifiedDate = b.uint16() + f.CRC32 = b.uint32() + f.CompressedSize = b.uint32() + f.UncompressedSize = b.uint32() + f.CompressedSize64 = uint64(f.CompressedSize) + f.UncompressedSize64 = uint64(f.UncompressedSize) + filenameLen := int(b.uint16()) + extraLen := int(b.uint16()) + commentLen := int(b.uint16()) + b = b[4:] // skipped start disk number and internal attributes (2x uint16) + f.ExternalAttrs = b.uint32() + f.headerOffset = int64(b.uint32()) + d := make([]byte, filenameLen+extraLen+commentLen) + if _, err := io.ReadFull(r, d); err != nil { + return err + } + f.Name = string(d[:filenameLen]) + f.Extra = d[filenameLen : filenameLen+extraLen] + f.Comment = string(d[filenameLen+extraLen:]) + + if len(f.Extra) > 0 { + b := readBuf(f.Extra) + for len(b) >= 4 { // need at least tag and size + tag := b.uint16() + size := b.uint16() + if int(size) > len(b) { + return ErrFormat + } + if tag == zip64ExtraId { + // update directory values from the zip64 extra block + eb := readBuf(b[:size]) + if len(eb) >= 8 { + f.UncompressedSize64 = eb.uint64() + } + if len(eb) >= 8 { + f.CompressedSize64 = eb.uint64() + } + if len(eb) >= 8 { + f.headerOffset = int64(eb.uint64()) + } + } + b = b[size:] + } + // Should have consumed the whole header. + // But popular zip & JAR creation tools are broken and + // may pad extra zeros at the end, so accept those + // too. See golang.org/issue/8186. + for _, v := range b { + if v != 0 { + return ErrFormat + } + } + } + return nil +} + +func readDataDescriptor(r io.Reader, f *File) error { + var buf [dataDescriptorLen]byte + + // The spec says: "Although not originally assigned a + // signature, the value 0x08074b50 has commonly been adopted + // as a signature value for the data descriptor record. + // Implementers should be aware that ZIP files may be + // encountered with or without this signature marking data + // descriptors and should account for either case when reading + // ZIP files to ensure compatibility." + // + // dataDescriptorLen includes the size of the signature but + // first read just those 4 bytes to see if it exists. + if _, err := io.ReadFull(r, buf[:4]); err != nil { + return err + } + off := 0 + maybeSig := readBuf(buf[:4]) + if maybeSig.uint32() != dataDescriptorSignature { + // No data descriptor signature. Keep these four + // bytes. + off += 4 + } + if _, err := io.ReadFull(r, buf[off:12]); err != nil { + return err + } + b := readBuf(buf[:12]) + if b.uint32() != f.CRC32 { + return ErrChecksum + } + + // The two sizes that follow here can be either 32 bits or 64 bits + // but the spec is not very clear on this and different + // interpretations has been made causing incompatibilities. We + // already have the sizes from the central directory so we can + // just ignore these. + + return nil +} + +func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error) { + // look for directoryEndSignature in the last 1k, then in the last 65k + var buf []byte + var directoryEndOffset int64 + for i, bLen := range []int64{1024, 65 * 1024} { + if bLen > size { + bLen = size + } + buf = make([]byte, int(bLen)) + if _, err := r.ReadAt(buf, size-bLen); err != nil && err != io.EOF { + return nil, err + } + if p := findSignatureInBlock(buf); p >= 0 { + buf = buf[p:] + directoryEndOffset = size - bLen + int64(p) + break + } + if i == 1 || bLen == size { + return nil, ErrFormat + } + } + + // read header into struct + b := readBuf(buf[4:]) // skip signature + d := &directoryEnd{ + diskNbr: uint32(b.uint16()), + dirDiskNbr: uint32(b.uint16()), + dirRecordsThisDisk: uint64(b.uint16()), + directoryRecords: uint64(b.uint16()), + directorySize: uint64(b.uint32()), + directoryOffset: uint64(b.uint32()), + commentLen: b.uint16(), + } + l := int(d.commentLen) + if l > len(b) { + return nil, errors.New("zip: invalid comment length") + } + d.comment = string(b[:l]) + + p, err := findDirectory64End(r, directoryEndOffset) + if err == nil && p >= 0 { + err = readDirectory64End(r, p, d) + } + if err != nil { + return nil, err + } + + // Make sure directoryOffset points to somewhere in our file. + if o := int64(d.directoryOffset); o < 0 || o >= size { + return nil, ErrFormat + } + return d, nil +} + +// findDirectory64End tries to read the zip64 locator just before the +// directory end and returns the offset of the zip64 directory end if +// found. +func findDirectory64End(r io.ReaderAt, directoryEndOffset int64) (int64, error) { + locOffset := directoryEndOffset - directory64LocLen + if locOffset < 0 { + return -1, nil // no need to look for a header outside the file + } + buf := make([]byte, directory64LocLen) + if _, err := r.ReadAt(buf, locOffset); err != nil { + return -1, err + } + b := readBuf(buf) + if sig := b.uint32(); sig != directory64LocSignature { + return -1, nil + } + b = b[4:] // skip number of the disk with the start of the zip64 end of central directory + p := b.uint64() // relative offset of the zip64 end of central directory record + return int64(p), nil +} + +// readDirectory64End reads the zip64 directory end and updates the +// directory end with the zip64 directory end values. +func readDirectory64End(r io.ReaderAt, offset int64, d *directoryEnd) (err error) { + buf := make([]byte, directory64EndLen) + if _, err := r.ReadAt(buf, offset); err != nil { + return err + } + + b := readBuf(buf) + if sig := b.uint32(); sig != directory64EndSignature { + return ErrFormat + } + + b = b[12:] // skip dir size, version and version needed (uint64 + 2x uint16) + d.diskNbr = b.uint32() // number of this disk + d.dirDiskNbr = b.uint32() // number of the disk with the start of the central directory + d.dirRecordsThisDisk = b.uint64() // total number of entries in the central directory on this disk + d.directoryRecords = b.uint64() // total number of entries in the central directory + d.directorySize = b.uint64() // size of the central directory + d.directoryOffset = b.uint64() // offset of start of central directory with respect to the starting disk number + + return nil +} + +func findSignatureInBlock(b []byte) int { + for i := len(b) - directoryEndLen; i >= 0; i-- { + // defined from directoryEndSignature in struct.go + if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 { + // n is length of comment + n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8 + if n+directoryEndLen+i <= len(b) { + return i + } + } + } + return -1 +} + +type readBuf []byte + +func (b *readBuf) uint16() uint16 { + v := binary.LittleEndian.Uint16(*b) + *b = (*b)[2:] + return v +} + +func (b *readBuf) uint32() uint32 { + v := binary.LittleEndian.Uint32(*b) + *b = (*b)[4:] + return v +} + +func (b *readBuf) uint64() uint64 { + v := binary.LittleEndian.Uint64(*b) + *b = (*b)[8:] + return v +} diff --git a/third_party/go/src/zip/register.go b/third_party/go/src/zip/register.go new file mode 100644 index 0000000000..4211ec7af7 --- /dev/null +++ b/third_party/go/src/zip/register.go @@ -0,0 +1,110 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package zip + +import ( + "compress/flate" + "errors" + "io" + "io/ioutil" + "sync" +) + +// A Compressor returns a compressing writer, writing to the +// provided writer. On Close, any pending data should be flushed. +type Compressor func(io.Writer) (io.WriteCloser, error) + +// Decompressor is a function that wraps a Reader with a decompressing Reader. +// The decompressed ReadCloser is returned to callers who open files from +// within the archive. These callers are responsible for closing this reader +// when they're finished reading. +type Decompressor func(io.Reader) io.ReadCloser + +var flateWriterPool sync.Pool + +func newFlateWriter(w io.Writer) io.WriteCloser { + fw, ok := flateWriterPool.Get().(*flate.Writer) + if ok { + fw.Reset(w) + } else { + fw, _ = flate.NewWriter(w, 5) + } + return &pooledFlateWriter{fw: fw} +} + +type pooledFlateWriter struct { + mu sync.Mutex // guards Close and Write + fw *flate.Writer +} + +func (w *pooledFlateWriter) Write(p []byte) (n int, err error) { + w.mu.Lock() + defer w.mu.Unlock() + if w.fw == nil { + return 0, errors.New("Write after Close") + } + return w.fw.Write(p) +} + +func (w *pooledFlateWriter) Close() error { + w.mu.Lock() + defer w.mu.Unlock() + var err error + if w.fw != nil { + err = w.fw.Close() + flateWriterPool.Put(w.fw) + w.fw = nil + } + return err +} + +var ( + mu sync.RWMutex // guards compressor and decompressor maps + + compressors = map[uint16]Compressor{ + Store: func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }, + Deflate: func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }, + } + + decompressors = map[uint16]Decompressor{ + Store: ioutil.NopCloser, + Deflate: flate.NewReader, + } +) + +// RegisterDecompressor allows custom decompressors for a specified method ID. +func RegisterDecompressor(method uint16, d Decompressor) { + mu.Lock() + defer mu.Unlock() + + if _, ok := decompressors[method]; ok { + panic("decompressor already registered") + } + decompressors[method] = d +} + +// RegisterCompressor registers custom compressors for a specified method ID. +// The common methods Store and Deflate are built in. +func RegisterCompressor(method uint16, comp Compressor) { + mu.Lock() + defer mu.Unlock() + + if _, ok := compressors[method]; ok { + panic("compressor already registered") + } + compressors[method] = comp +} + +func compressor(method uint16) Compressor { + mu.RLock() + defer mu.RUnlock() + return compressors[method] +} + +func decompressor(method uint16) Decompressor { + mu.RLock() + defer mu.RUnlock() + return decompressors[method] +} diff --git a/third_party/go/src/zip/struct.go b/third_party/go/src/zip/struct.go new file mode 100644 index 0000000000..a05aaa3f29 --- /dev/null +++ b/third_party/go/src/zip/struct.go @@ -0,0 +1,315 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* +Package zip provides support for reading and writing ZIP archives. + +See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT + +This package does not support disk spanning. + +A note about ZIP64: + +To be backwards compatible the FileHeader has both 32 and 64 bit Size +fields. The 64 bit fields will always contain the correct value and +for normal archives both fields will be the same. For files requiring +the ZIP64 format the 32 bit fields will be 0xffffffff and the 64 bit +fields must be used instead. +*/ +package zip + +import ( + "os" + "path" + "time" +) + +// Compression methods. +const ( + Store uint16 = 0 + Deflate uint16 = 8 +) + +const ( + fileHeaderSignature = 0x04034b50 + directoryHeaderSignature = 0x02014b50 + directoryEndSignature = 0x06054b50 + directory64LocSignature = 0x07064b50 + directory64EndSignature = 0x06064b50 + dataDescriptorSignature = 0x08074b50 // de-facto standard; required by OS X Finder + fileHeaderLen = 30 // + filename + extra + directoryHeaderLen = 46 // + filename + extra + comment + directoryEndLen = 22 // + comment + dataDescriptorLen = 16 // four uint32: descriptor signature, crc32, compressed size, size + dataDescriptor64Len = 24 // descriptor with 8 byte sizes + directory64LocLen = 20 // + directory64EndLen = 56 // + extra + + dataDescriptorFlag = 0x8 // Flag indicating that there's a trailing data descriptor. + + // Constants for the first byte in CreatorVersion + creatorFAT = 0 + creatorUnix = 3 + creatorNTFS = 11 + creatorVFAT = 14 + creatorMacOSX = 19 + + // version numbers + zipVersion20 = 20 // 2.0 + zipVersion45 = 45 // 4.5 (reads and writes zip64 archives) + + // limits for non zip64 files + uint16max = (1 << 16) - 1 + uint32max = (1 << 32) - 1 + + // extra header id's + zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field +) + +// FileHeader describes a file within a zip file. +// See the zip spec for details. +type FileHeader struct { + // Name is the name of the file. + // It must be a relative path: it must not start with a drive + // letter (e.g. C:) or leading slash, and only forward slashes + // are allowed. + Name string + + CreatorVersion uint16 + ReaderVersion uint16 + Flags uint16 + Method uint16 + ModifiedTime uint16 // MS-DOS time + ModifiedDate uint16 // MS-DOS date + CRC32 uint32 + CompressedSize uint32 // deprecated; use CompressedSize64 + UncompressedSize uint32 // deprecated; use UncompressedSize64 + CompressedSize64 uint64 + UncompressedSize64 uint64 + Extra []byte + ExternalAttrs uint32 // Meaning depends on CreatorVersion + Comment string +} + +// FileInfo returns an os.FileInfo for the FileHeader. +func (h *FileHeader) FileInfo() os.FileInfo { + return headerFileInfo{h} +} + +// headerFileInfo implements os.FileInfo. +type headerFileInfo struct { + fh *FileHeader +} + +func (fi headerFileInfo) Name() string { return path.Base(fi.fh.Name) } +func (fi headerFileInfo) Size() int64 { + if fi.fh.UncompressedSize64 > 0 { + return int64(fi.fh.UncompressedSize64) + } + return int64(fi.fh.UncompressedSize) +} +func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() } +func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() } +func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() } +func (fi headerFileInfo) Sys() interface{} { return fi.fh } + +// FileInfoHeader creates a partially-populated FileHeader from an +// os.FileInfo. +// Because os.FileInfo's Name method returns only the base name of +// the file it describes, it may be necessary to modify the Name field +// of the returned header to provide the full path name of the file. +func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) { + size := fi.Size() + fh := &FileHeader{ + Name: fi.Name(), + UncompressedSize64: uint64(size), + } + fh.SetModTime(fi.ModTime()) + fh.SetMode(fi.Mode()) + if fh.UncompressedSize64 > uint32max { + fh.UncompressedSize = uint32max + } else { + fh.UncompressedSize = uint32(fh.UncompressedSize64) + } + return fh, nil +} + +type directoryEnd struct { + diskNbr uint32 // unused + dirDiskNbr uint32 // unused + dirRecordsThisDisk uint64 // unused + directoryRecords uint64 + directorySize uint64 + directoryOffset uint64 // relative to file + commentLen uint16 + comment string +} + +// msDosTimeToTime converts an MS-DOS date and time into a time.Time. +// The resolution is 2s. +// See: http://msdn.microsoft.com/en-us/library/ms724247(v=VS.85).aspx +func msDosTimeToTime(dosDate, dosTime uint16) time.Time { + return time.Date( + // date bits 0-4: day of month; 5-8: month; 9-15: years since 1980 + int(dosDate>>9+1980), + time.Month(dosDate>>5&0xf), + int(dosDate&0x1f), + + // time bits 0-4: second/2; 5-10: minute; 11-15: hour + int(dosTime>>11), + int(dosTime>>5&0x3f), + int(dosTime&0x1f*2), + 0, // nanoseconds + + time.UTC, + ) +} + +// timeToMsDosTime converts a time.Time to an MS-DOS date and time. +// The resolution is 2s. +// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx +func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) { + t = t.In(time.UTC) + fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) + fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) + return +} + +// ModTime returns the modification time in UTC. +// The resolution is 2s. +func (h *FileHeader) ModTime() time.Time { + return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime) +} + +// SetModTime sets the ModifiedTime and ModifiedDate fields to the given time in UTC. +// The resolution is 2s. +func (h *FileHeader) SetModTime(t time.Time) { + h.ModifiedDate, h.ModifiedTime = timeToMsDosTime(t) +} + +const ( + // Unix constants. The specification doesn't mention them, + // but these seem to be the values agreed on by tools. + s_IFMT = 0xf000 + s_IFSOCK = 0xc000 + s_IFLNK = 0xa000 + s_IFREG = 0x8000 + s_IFBLK = 0x6000 + s_IFDIR = 0x4000 + s_IFCHR = 0x2000 + s_IFIFO = 0x1000 + s_ISUID = 0x800 + s_ISGID = 0x400 + s_ISVTX = 0x200 + + msdosDir = 0x10 + msdosReadOnly = 0x01 +) + +// Mode returns the permission and mode bits for the FileHeader. +func (h *FileHeader) Mode() (mode os.FileMode) { + switch h.CreatorVersion >> 8 { + case creatorUnix, creatorMacOSX: + mode = unixModeToFileMode(h.ExternalAttrs >> 16) + case creatorNTFS, creatorVFAT, creatorFAT: + mode = msdosModeToFileMode(h.ExternalAttrs) + } + if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' { + mode |= os.ModeDir + } + return mode +} + +// SetMode changes the permission and mode bits for the FileHeader. +func (h *FileHeader) SetMode(mode os.FileMode) { + h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8 + h.ExternalAttrs = fileModeToUnixMode(mode) << 16 + + // set MSDOS attributes too, as the original zip does. + if mode&os.ModeDir != 0 { + h.ExternalAttrs |= msdosDir + } + if mode&0200 == 0 { + h.ExternalAttrs |= msdosReadOnly + } +} + +// isZip64 returns true if the file size exceeds the 32 bit limit +func (fh *FileHeader) isZip64() bool { + return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max +} + +func msdosModeToFileMode(m uint32) (mode os.FileMode) { + if m&msdosDir != 0 { + mode = os.ModeDir | 0777 + } else { + mode = 0666 + } + if m&msdosReadOnly != 0 { + mode &^= 0222 + } + return mode +} + +func fileModeToUnixMode(mode os.FileMode) uint32 { + var m uint32 + switch mode & os.ModeType { + default: + m = s_IFREG + case os.ModeDir: + m = s_IFDIR + case os.ModeSymlink: + m = s_IFLNK + case os.ModeNamedPipe: + m = s_IFIFO + case os.ModeSocket: + m = s_IFSOCK + case os.ModeDevice: + if mode&os.ModeCharDevice != 0 { + m = s_IFCHR + } else { + m = s_IFBLK + } + } + if mode&os.ModeSetuid != 0 { + m |= s_ISUID + } + if mode&os.ModeSetgid != 0 { + m |= s_ISGID + } + if mode&os.ModeSticky != 0 { + m |= s_ISVTX + } + return m | uint32(mode&0777) +} + +func unixModeToFileMode(m uint32) os.FileMode { + mode := os.FileMode(m & 0777) + switch m & s_IFMT { + case s_IFBLK: + mode |= os.ModeDevice + case s_IFCHR: + mode |= os.ModeDevice | os.ModeCharDevice + case s_IFDIR: + mode |= os.ModeDir + case s_IFIFO: + mode |= os.ModeNamedPipe + case s_IFLNK: + mode |= os.ModeSymlink + case s_IFREG: + // nothing to do + case s_IFSOCK: + mode |= os.ModeSocket + } + if m&s_ISGID != 0 { + mode |= os.ModeSetgid + } + if m&s_ISUID != 0 { + mode |= os.ModeSetuid + } + if m&s_ISVTX != 0 { + mode |= os.ModeSticky + } + return mode +} diff --git a/third_party/go/src/zip/writer.go b/third_party/go/src/zip/writer.go new file mode 100644 index 0000000000..fb75e9e8d2 --- /dev/null +++ b/third_party/go/src/zip/writer.go @@ -0,0 +1,381 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package zip + +import ( + "bufio" + "encoding/binary" + "errors" + "hash" + "hash/crc32" + "io" +) + +// TODO(adg): support zip file comments +// TODO(adg): support specifying deflate level + +// Writer implements a zip file writer. +type Writer struct { + cw *countWriter + dir []*header + last *fileWriter + closed bool +} + +type header struct { + *FileHeader + offset uint64 +} + +// NewWriter returns a new Writer writing a zip file to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}} +} + +// Flush flushes any buffered data to the underlying writer. +// Calling Flush is not normally necessary; calling Close is sufficient. +func (w *Writer) Flush() error { + return w.cw.w.(*bufio.Writer).Flush() +} + +// Close finishes writing the zip file by writing the central directory. +// It does not (and can not) close the underlying writer. +func (w *Writer) Close() error { + if w.last != nil && !w.last.closed { + if err := w.last.close(); err != nil { + return err + } + w.last = nil + } + if w.closed { + return errors.New("zip: writer closed twice") + } + w.closed = true + + // write central directory + start := w.cw.count + for _, h := range w.dir { + var buf [directoryHeaderLen]byte + b := writeBuf(buf[:]) + b.uint32(uint32(directoryHeaderSignature)) + b.uint16(h.CreatorVersion) + b.uint16(h.ReaderVersion) + b.uint16(h.Flags) + b.uint16(h.Method) + b.uint16(h.ModifiedTime) + b.uint16(h.ModifiedDate) + b.uint32(h.CRC32) + if h.isZip64() || h.offset > uint32max { + // the file needs a zip64 header. store maxint in both + // 32 bit size fields (and offset later) to signal that the + // zip64 extra header should be used. + b.uint32(uint32max) // compressed size + b.uint32(uint32max) // uncompressed size + + // append a zip64 extra block to Extra + var buf [28]byte // 2x uint16 + 3x uint64 + eb := writeBuf(buf[:]) + eb.uint16(zip64ExtraId) + eb.uint16(24) // size = 3x uint64 + eb.uint64(h.UncompressedSize64) + eb.uint64(h.CompressedSize64) + eb.uint64(h.offset) + h.Extra = append(h.Extra, buf[:]...) + } else { + b.uint32(h.CompressedSize) + b.uint32(h.UncompressedSize) + } + b.uint16(uint16(len(h.Name))) + b.uint16(uint16(len(h.Extra))) + b.uint16(uint16(len(h.Comment))) + b = b[4:] // skip disk number start and internal file attr (2x uint16) + b.uint32(h.ExternalAttrs) + if h.offset > uint32max { + b.uint32(uint32max) + } else { + b.uint32(uint32(h.offset)) + } + if _, err := w.cw.Write(buf[:]); err != nil { + return err + } + if _, err := io.WriteString(w.cw, h.Name); err != nil { + return err + } + if _, err := w.cw.Write(h.Extra); err != nil { + return err + } + if _, err := io.WriteString(w.cw, h.Comment); err != nil { + return err + } + } + end := w.cw.count + + records := uint64(len(w.dir)) + size := uint64(end - start) + offset := uint64(start) + + if records > uint16max || size > uint32max || offset > uint32max { + var buf [directory64EndLen + directory64LocLen]byte + b := writeBuf(buf[:]) + + // zip64 end of central directory record + b.uint32(directory64EndSignature) + b.uint64(directory64EndLen) + b.uint16(zipVersion45) // version made by + b.uint16(zipVersion45) // version needed to extract + b.uint32(0) // number of this disk + b.uint32(0) // number of the disk with the start of the central directory + b.uint64(records) // total number of entries in the central directory on this disk + b.uint64(records) // total number of entries in the central directory + b.uint64(size) // size of the central directory + b.uint64(offset) // offset of start of central directory with respect to the starting disk number + + // zip64 end of central directory locator + b.uint32(directory64LocSignature) + b.uint32(0) // number of the disk with the start of the zip64 end of central directory + b.uint64(uint64(end)) // relative offset of the zip64 end of central directory record + b.uint32(1) // total number of disks + + if _, err := w.cw.Write(buf[:]); err != nil { + return err + } + + // store max values in the regular end record to signal that + // that the zip64 values should be used instead + records = uint16max + size = uint32max + offset = uint32max + } + + // write end record + var buf [directoryEndLen]byte + b := writeBuf(buf[:]) + b.uint32(uint32(directoryEndSignature)) + b = b[4:] // skip over disk number and first disk number (2x uint16) + b.uint16(uint16(records)) // number of entries this disk + b.uint16(uint16(records)) // number of entries total + b.uint32(uint32(size)) // size of directory + b.uint32(uint32(offset)) // start of directory + // skipped size of comment (always zero) + if _, err := w.cw.Write(buf[:]); err != nil { + return err + } + + return w.cw.w.(*bufio.Writer).Flush() +} + +// WritePreamble writes some leading data to the file. Since zip files have their index at the end +// and file locations are specified there it's possible to lead off with something, for +// example a shebang to make them self-executing as with pexes. +func (w *Writer) WritePreamble(preamble string) error { + _, err := io.WriteString(w.cw, preamble) + return err +} + +// Create adds a file to the zip file using the provided name. +// It returns a Writer to which the file contents should be written. +// The name must be a relative path: it must not start with a drive +// letter (e.g. C:) or leading slash, and only forward slashes are +// allowed. +// The file's contents must be written to the io.Writer before the next +// call to Create, CreateHeader, or Close. +func (w *Writer) Create(name string) (io.Writer, error) { + header := &FileHeader{ + Name: name, + Method: Deflate, + } + return w.CreateHeader(header) +} + +// CreateHeader adds a file to the zip file using the provided FileHeader +// for the file metadata. +// It returns a Writer to which the file contents should be written. +// The file's contents must be written to the io.Writer before the next +// call to Create, CreateHeader, or Close. +func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { + comp := compressor(fh.Method) + if comp == nil { + return nil, ErrAlgorithm + } + fh.Flags |= dataDescriptorFlag // we will write a data descriptor + return w.CreateHeaderWithCompressor(fh, comp, crc32.NewIEEE()) +} + +// CreateHeaderWithCompressor behaves the same as CreateHeader but allows explicitly +// specifying the compressor to use, which may not necessarily correspond to the +// Method property of the actual file header. Some care should therefore be taken +// to ensure the zipfile will be decompressible if calling this directly. +func (w *Writer) CreateHeaderWithCompressor(fh *FileHeader, comp Compressor, crc hash.Hash32) (io.Writer, error) { + if w.last != nil && !w.last.closed { + if err := w.last.close(); err != nil { + return nil, err + } + } + + fh.CreatorVersion = fh.CreatorVersion&0xff00 | zipVersion20 // preserve compatibility byte + fh.ReaderVersion = zipVersion20 + + fw := &fileWriter{ + zipw: w.cw, + compCount: &countWriter{w: w.cw}, + crc32: crc, + } + var err error + fw.comp, err = comp(fw.compCount) + if err != nil { + return nil, err + } + fw.rawCount = &countWriter{w: fw.comp} + + h := &header{ + FileHeader: fh, + offset: uint64(w.cw.count), + } + w.dir = append(w.dir, h) + fw.header = h + + if err := writeHeader(w.cw, fh); err != nil { + return nil, err + } + + w.last = fw + return fw, nil +} + +func writeHeader(w io.Writer, h *FileHeader) error { + var buf [fileHeaderLen]byte + b := writeBuf(buf[:]) + b.uint32(uint32(fileHeaderSignature)) + b.uint16(h.ReaderVersion) + b.uint16(h.Flags) + b.uint16(h.Method) + b.uint16(h.ModifiedTime) + b.uint16(h.ModifiedDate) + if (h.Flags & dataDescriptorFlag) != 0 { + b.uint32(0) // since we are writing a data descriptor crc32, + b.uint32(0) // compressed size, + b.uint32(0) // and uncompressed size should be zero + } else { + b.uint32(h.CRC32) + b.uint32(h.CompressedSize) + b.uint32(h.UncompressedSize) + } + b.uint16(uint16(len(h.Name))) + b.uint16(uint16(len(h.Extra))) + if _, err := w.Write(buf[:]); err != nil { + return err + } + if _, err := io.WriteString(w, h.Name); err != nil { + return err + } + _, err := w.Write(h.Extra) + return err +} + +type fileWriter struct { + *header + zipw io.Writer + rawCount *countWriter + comp io.WriteCloser + compCount *countWriter + crc32 hash.Hash32 + closed bool +} + +func (w *fileWriter) Write(p []byte) (int, error) { + if w.closed { + return 0, errors.New("zip: write to closed file") + } + w.crc32.Write(p) + return w.rawCount.Write(p) +} + +func (w *fileWriter) close() error { + if w.closed { + return errors.New("zip: file closed twice") + } + w.closed = true + if err := w.comp.Close(); err != nil { + return err + } + + // update FileHeader + fh := w.header.FileHeader + if (fh.Flags & dataDescriptorFlag) == 0 { + return nil + } + fh.CRC32 = w.crc32.Sum32() + fh.CompressedSize64 = uint64(w.compCount.count) + fh.UncompressedSize64 = uint64(w.rawCount.count) + + if fh.isZip64() { + fh.CompressedSize = uint32max + fh.UncompressedSize = uint32max + fh.ReaderVersion = zipVersion45 // requires 4.5 - File uses ZIP64 format extensions + } else { + fh.CompressedSize = uint32(fh.CompressedSize64) + fh.UncompressedSize = uint32(fh.UncompressedSize64) + } + + // Write data descriptor. This is more complicated than one would + // think, see e.g. comments in zipfile.c:putextended() and + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7073588. + // The approach here is to write 8 byte sizes if needed without + // adding a zip64 extra in the local header (too late anyway). + var buf []byte + if fh.isZip64() { + buf = make([]byte, dataDescriptor64Len) + } else { + buf = make([]byte, dataDescriptorLen) + } + b := writeBuf(buf) + b.uint32(dataDescriptorSignature) // de-facto standard, required by OS X + b.uint32(fh.CRC32) + if fh.isZip64() { + b.uint64(fh.CompressedSize64) + b.uint64(fh.UncompressedSize64) + } else { + b.uint32(fh.CompressedSize) + b.uint32(fh.UncompressedSize) + } + _, err := w.zipw.Write(buf) + return err +} + +type countWriter struct { + w io.Writer + count int64 +} + +func (w *countWriter) Write(p []byte) (int, error) { + n, err := w.w.Write(p) + w.count += int64(n) + return n, err +} + +type nopCloser struct { + io.Writer +} + +func (w nopCloser) Close() error { + return nil +} + +type writeBuf []byte + +func (b *writeBuf) uint16(v uint16) { + binary.LittleEndian.PutUint16(*b, v) + *b = (*b)[2:] +} + +func (b *writeBuf) uint32(v uint32) { + binary.LittleEndian.PutUint32(*b, v) + *b = (*b)[4:] +} + +func (b *writeBuf) uint64(v uint64) { + binary.LittleEndian.PutUint64(*b, v) + *b = (*b)[8:] +} diff --git a/third_party/java/BUILD b/third_party/java/BUILD new file mode 100644 index 0000000000..11152c46e8 --- /dev/null +++ b/third_party/java/BUILD @@ -0,0 +1,94 @@ +package(default_visibility = ['PUBLIC']) + +maven_jar( + name = 'junit', + id = 'junit:junit:4.12', + hash = 'sha1: a791201ac8a3d2a251045a52e264de01343ad2df', +) + +maven_jar( + name = 'hamcrest', + id = 'org.hamcrest:hamcrest-all:1.3', + hash = 'sha1: 6e72502584462b2d35a7a6a18fc5541c412f08cc', +) + +maven_jars( + name = 'guava', + id = 'com.google.guava:guava:18.0', + exclude = ['jsr305'], + hashes = { + 'guava': 'sha1: 8908f57125132a4468ea9977705a83f61b94fa89', + } +) + +maven_jars( + name = 'jacoco', + id = 'org.jacoco:jacoco:0.7.5.201505241946', + exclude = [ + 'org.jacoco.ant', + 'org.jacoco.doc', + 'org.jacoco.examples', + 'asm-debug-all', + ], + hashes = { + 'org.jacoco.report': 'sha1: 1129a80f257387660125fde69c82591effa53601', + 'org.jacoco.agent': 'sha1: 3d9535a24f7536f643059d7bc41dafd3d99c96fb', + 'org.jacoco.core': 'sha1: ff91273abd22add0bdda7aea226fcfe0026d7c4c', + }, + deps = [':asm'], + deps_only = True, +) + +maven_jar( + name = 'asm', + id = 'org.ow2.asm:asm-debug-all:5.0.4', + hash = 'sha1: 079196a08a86094763068ac621ba90c73c2efa34', +) + +maven_jar( + name = 'logback-classic', + id = 'ch.qos.logback:logback-classic:1.1.3', + hash = 'sha1: 245ace75b7a18931f103a79e74d53c66f1f90a9e', + deps = [ + ':logback-core', + ':slf4j-api', + ] +) + +maven_jar( + name = 'logback-core', + id = 'ch.qos.logback:logback-core:1.1.3', + hash = 'sha1: 53732a6ab1f058ad76808646519801e30cc4a780', +) + +maven_jar( + name = 'slf4j-api', + id = 'org.slf4j:slf4j-api:1.7.10', + hash = 'sha1: 0ff5ea6b9f644c97ef1de83eb75e7cc304103549', +) + +maven_jar( + name = 'protobuf', + id = 'com.google.protobuf:protobuf-java:3.0.0-beta-1', + hash = 'b832e95bd94c68a01c32985d99ca5bb74bb0e0dc', +) + +maven_jars( + name = 'grpc-all', + id = 'io.grpc:grpc-all:0.9.0', + hashes = { + 'grpc-protobuf': 'sha1: 69a0cf75bcb8e34bbc7879f9b35e7c78f659030b', + 'grpc-protobuf-nano': 'sha1: 3d5ecd3cb028e39ec88563b5aeb7d7a87f13e6db', + 'grpc-core': 'sha1: 80acde31b47671eff450c27e5614c41328443b49', + 'grpc-okhttp': 'sha1: e9d3aa39d8f0798221c9e1f0635b1e2f51dd81f0', + 'grpc-netty': 'sha1: 50cfb2330e184269e050b2bb67fcf73d75153a62', + 'grpc-stub': 'sha1: 0c98dce9d8a4c741495cb2d3db054bcbec58dcab', + 'grpc-auth': 'sha1: 9c612b73342f1d71eead2524baab908544e58ff5', + 'grpc-all': 'sha1: 0aa2ccaf0093d9d670a5594a80163df3d6cf3ecf', + 'guava': 'sha1: 05e01289a2c9056ffadcf8723548cafb41a6a7d1', + 'jsr305': 'sha1: 05e01289a2c9056ffadcf8723548cafb41a6a7d1', + }, + deps = [ + ':guava', + ], +) diff --git a/third_party/python/BUILD b/third_party/python/BUILD new file mode 100644 index 0000000000..1efcdabc1b --- /dev/null +++ b/third_party/python/BUILD @@ -0,0 +1,112 @@ +package(default_visibility=['PUBLIC']) + +pip_library( + name = 'pex', + version = '1.1.1', + hashes = ['sha1: 44358d1ae57d75518346b3f913cabec5bcd6db49'], + patch = [ + # TODO(pebers): send this patch upstream so we don't have to have it here. + 'dont_recompress.patch', + # This one would need a lot more work to be generally usable. + 'never_cache_pex.patch', + ], +) + +pip_library( + name = 'xmlrunner', + package_name = 'unittest-xml-reporting', + version = '1.11.0', + hashes = ['sha1: 62e71134eb068413e40fe4d973451c0e4931db5a'], + deps = [':six'], +) + +pip_library( + name = 'six', + version = '1.9.0', + outs = ['six.py'], + hashes = ['sha1: 0c31ab7cf1a2761efa32d9a7e891ddeadc0d8673'], +) + +pip_library( + name = 'pkg_resources', + package_name = 'setuptools', + version = '6.1', + outs = ['pkg_resources.py'], + hashes = ['sha1: 33c8ea9686a15ca09ce96656d4a2074d75235dfe'], +) + +pip_library( + name = 'coverage', + version = '4.0a6', + hashes = [ + 'sha1: 39bc6df0d3f7c0633fed8336324e1a7caab58dfa', + 'sha1: 115cc5c535340856c390d6739c34b7a545349145', + 'sha1: df1bc0741e71507a107ccb40d710f7ae650c8b78', + ], + patch = 'coverage_pex.patch', +) + +pip_library( + name = 'requests', + version = '2.5.0', + hashes = [ + 'sha1: e43b552c4a6063d32b8c9bf742fb3e9ce579c4d8', + ], + test_only = True, # Not used by plz itself. +) + +pip_library( + name = 'dateutil', + package_name = 'python-dateutil', + version = '2.4.0', + hashes = [ + 'sha1: 62b97c332a2c118b8957d324d7ad3cbcc1f4f9eb', + ], + deps = [':six'], + test_only = True, # Not used by plz itself. +) + +pip_library( + name = 'protobuf', + outs = ['google'], + version = '3.0.0b1.post2', + hashes = [ + 'sha1: 4b74638c35f417ab33c3fe3a337f0bb18f0ff1ab', + 'sha1: 6d4c66f719238c058d3d5d1fbe7b2484eb0fe89d', + 'sha1: 4b74638c35f417ab33c3fe3a337f0bb18f0ff1ab', + ], + deps = [':six'], +) + +pip_library( + name = 'grpc', + package_name = 'grpcio', + version = '0.11.0b1', + deps = [ + ':enum', + ':futures' + ], + hashes = [ + 'sha1: 142a73fc44678075de122137954ea718f1a46013', + 'sha1: bce711d0a23350f0ff5a1281d61c514f93292da2', + ], +) + +pip_library( + name = 'enum', + version = '1.0.4', + hashes = [ + 'sha1: ce61fd8ab8ec1390ce3c42d3d042d7dded9ed205', + ], + package_name = 'enum34', + outs = ['enum'], +) + +pip_library( + name = 'futures', + version = '2.2.0', + hashes = [ + 'sha1: 3bb16f7c2ad9e13623349bd3f876c02d7e2e39f7', + ], + outs = ['futures', 'concurrent'] +) diff --git a/third_party/python/coverage_pex.patch b/third_party/python/coverage_pex.patch new file mode 100644 index 0000000000..a6b0cb9a43 --- /dev/null +++ b/third_party/python/coverage_pex.patch @@ -0,0 +1,11 @@ +--- coverage/python.py 2015-07-08 20:31:40.183290075 +0100 ++++ coverage/python.py.new 2015-07-08 20:35:55.269446685 +0100 +@@ -63,7 +63,7 @@ + an empty string if the file is empty. + + """ +- markers = ['.zip'+os.sep, '.egg'+os.sep] ++ markers = ['.zip'+os.sep, '.egg'+os.sep, '.pex'+os.sep] + for marker in markers: + if marker in filename: + parts = filename.split(marker) diff --git a/third_party/python/dont_recompress.patch b/third_party/python/dont_recompress.patch new file mode 100644 index 0000000000..542bab8dd7 --- /dev/null +++ b/third_party/python/dont_recompress.patch @@ -0,0 +1,10 @@ +--- pex/common.py 2015-06-28 13:08:26.627711606 +0100 ++++ pex/common.py.new 2015-06-28 13:09:26.164961700 +0100 +@@ -310,4 +310,6 @@ + def zip(self, filename, mode='wb'): + with contextlib.closing(zipfile.ZipFile(filename, mode)) as zf: + for f in sorted(self.files()): +- zf.write(os.path.join(self.chroot, f), arcname=f, compress_type=zipfile.ZIP_DEFLATED) ++ filename = os.path.join(self.chroot, f) ++ compression = zipfile.ZIP_STORED if zipfile.is_zipfile(filename) else zipfile.ZIP_DEFLATED ++ zf.write(filename, arcname=f, compress_type=compression) diff --git a/third_party/python/never_cache_pex.patch b/third_party/python/never_cache_pex.patch new file mode 100644 index 0000000000..7cbfe640a9 --- /dev/null +++ b/third_party/python/never_cache_pex.patch @@ -0,0 +1,21 @@ +--- pex/environment.py 2016-01-09 19:12:00.314371772 +0000 ++++ pex/environment.py.new 2016-01-09 19:18:01.887465480 +0000 +@@ -5,6 +5,7 @@ + + import itertools + import os ++import shutil + import site + import sys + import uuid +@@ -34,6 +35,10 @@ + return pex + explode_dir = os.path.join(pex_info.zip_unsafe_cache, pex_info.code_hash) + TRACER.log('PEX is not zip safe, exploding to %s' % explode_dir) ++ # plz modifies the .pex file after pex runs, so do not reuse the cached version ever. ++ # plz test does its own incrementality anyway. ++ if os.path.exists(explode_dir): ++ shutil.rmtree(explode_dir) + if not os.path.exists(explode_dir): + explode_tmp = explode_dir + '.' + uuid.uuid4().hex + with TRACER.timed('Unzipping %s' % pex):