diff --git a/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkRepositoryContext.java b/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkRepositoryContext.java index 05a98da4e115f7..5e1076de8bf95c 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkRepositoryContext.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/repository/starlark/StarlarkRepositoryContext.java @@ -448,6 +448,118 @@ public void patch(Object patchFile, StarlarkInt stripI, String watchPatch, Starl } } + @StarlarkMethod( + name = "extract", + doc = "Extract an archive to the repository directory.", + useStarlarkThread = true, + parameters = { + @Param( + name = "archive", + allowedTypes = { + @ParamType(type = String.class), + @ParamType(type = Label.class), + @ParamType(type = StarlarkPath.class) + }, + named = true, + doc = + "path to the archive that will be unpacked," + + " relative to the repository directory."), + @Param( + name = "output", + allowedTypes = { + @ParamType(type = String.class), + @ParamType(type = Label.class), + @ParamType(type = StarlarkPath.class) + }, + defaultValue = "''", + named = true, + doc = + "path to the directory where the archive will be unpacked," + + " relative to the repository directory."), + @Param( + name = "stripPrefix", + defaultValue = "''", + named = true, + doc = + "a directory prefix to strip from the extracted files." + + "\nMany archives contain a top-level directory that contains all files in the" + + " archive. Instead of needing to specify this prefix over and over in the" + + " build_file, this field can be used to strip it from extracted" + + " files."), + @Param( + name = "rename_files", + defaultValue = "{}", + named = true, + positional = false, + doc = + "An optional dict specifying files to rename during the extraction. Archive entries" + + " with names exactly matching a key will be renamed to the value, prior to" + + " any directory prefix adjustment. This can be used to extract archives that" + + " contain non-Unicode filenames, or which have files that would extract to" + + " the same path on case-insensitive filesystems."), + @Param( + name = "watch_archive", + defaultValue = "'auto'", + positional = false, + named = true, + doc = + "whether to watch the archive file. Can be the string " + + "'yes', 'no', or 'auto'. Passing 'yes' is equivalent to immediately invoking " + + "the watch() method; passing 'no' does " + + "not attempt to watch the file; passing 'auto' will only attempt to watch " + + "the file when it is legal to do so (see watch() docs for more " + + "information."), + }) + public void extract( + Object archive, + Object output, + String stripPrefix, + Dict renameFiles, // expected + String watchArchive, + StarlarkThread thread) + throws RepositoryFunctionException, InterruptedException, EvalException { + StarlarkPath archivePath = getPath("extract()", archive); + + if (!archivePath.exists()) { + throw new RepositoryFunctionException( + Starlark.errorf("Archive path '%s' does not exist.", archivePath), Transience.TRANSIENT); + } + if (archivePath.isDir()) { + throw Starlark.errorf("attempting to extract a directory: %s", archivePath); + } + maybeWatch(archivePath, ShouldWatch.fromString(watchArchive)); + + StarlarkPath outputPath = getPath("extract()", output); + checkInOutputDirectory("write", outputPath); + + Map renameFilesMap = + Dict.cast(renameFiles, String.class, String.class, "rename_files"); + + WorkspaceRuleEvent w = + WorkspaceRuleEvent.newExtractEvent( + archive.toString(), + output.toString(), + stripPrefix, + renameFilesMap, + identifyingStringForLogging, + thread.getCallerLocation()); + env.getListener().post(w); + + env.getListener() + .post( + new ExtractProgress( + outputPath.getPath().toString(), "Extracting " + archivePath.getBasename())); + DecompressorValue.decompress( + DecompressorDescriptor.builder() + .setContext(identifyingStringForLogging) + .setArchivePath(archivePath.getPath()) + .setDestinationPath(outputPath.getPath()) + .setPrefix(stripPrefix) + .setRenameFiles(renameFilesMap) + .build()); + env.getListener().post(new ExtractProgress(outputPath.getPath().toString())); + } + @StarlarkMethod( name = "watch_tree", doc = diff --git a/src/test/py/bazel/bzlmod/bazel_module_test.py b/src/test/py/bazel/bzlmod/bazel_module_test.py index 6cbc5b503e49f5..2d3cf21d2e5e4e 100644 --- a/src/test/py/bazel/bzlmod/bazel_module_test.py +++ b/src/test/py/bazel/bzlmod/bazel_module_test.py @@ -1069,6 +1069,5 @@ def testRegression22754(self): self.ScratchFile('testdata/WORKSPACE') self.RunBazel(['build', ':all']) - if __name__ == '__main__': absltest.main()