Skip to content

Commit be55d87

Browse files
committed
Add support for Zstandard and patching
1 parent 769c82b commit be55d87

File tree

5 files changed

+136
-14
lines changed

5 files changed

+136
-14
lines changed

BUILD.archive

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ package(default_visibility = ["//visibility:public"])
22

33
filegroup(
44
name = "files",
5-
srcs = glob(["*.txt"]),
5+
srcs = glob(["**/*.txt"]),
66
)

BUILD.main

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
load("@rules_cc//cc:defs.bzl", "cc_binary")
22

33
cc_binary(
4-
name = "hello_minio",
4+
name = "hello_world",
55
srcs = ["main.cc"],
6-
data = ["@archive_gcloud//:files"],
6+
data = [
7+
"@archive_gcloud_gz//:files",
8+
"@archive_gcloud_zstd//:files",
9+
"@archive_gcloud_zstd_patch//:files",
10+
"@archive_gcloud_zstd_strip2//:files",
11+
],
712
)

WORKSPACE

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
workspace(name = "cloud_archive")
22

3-
load(":cloud_archive.bzl", "minio_archive", "s3_archive", "gs_archive")
3+
load(":cloud_archive.bzl", "gs_archive", "minio_archive", "s3_archive")
44

55
s3_archive(
66
name = "archive_s3",
@@ -12,18 +12,55 @@ s3_archive(
1212
)
1313

1414
minio_archive(
15-
name = "archive_minio",
15+
name = "archive_minio_gz",
1616
build_file = "//:BUILD.archive",
1717
file_path = "minio/temp/cloud_archive_test.tar.gz",
1818
sha256 = "bf4dd5304180561a745e816ee6a8db974a3fcf5b9d706a493776d77202c48bc9",
1919
strip_prefix = "cloud_archive_test",
2020
)
2121

22-
gs_archive(
23-
name = "archive_gcloud",
22+
minio_archive(
23+
name = "archive_minio_zstd",
2424
build_file = "//:BUILD.archive",
25+
file_path = "minio/temp/cloud_archive_test.tar.zst",
26+
sha256 = "1891c85349f519206a2a2aa21f4927146b8cf84db04d3be91e0b54ce564d8b73",
27+
strip_prefix = "dir1",
28+
)
29+
30+
gs_archive(
31+
name = "archive_gcloud_gz",
2532
bucket = "depthwise-temp",
33+
build_file = "//:BUILD.archive",
2634
file_path = "cloud_archive_test.tar.gz",
2735
sha256 = "bf4dd5304180561a745e816ee6a8db974a3fcf5b9d706a493776d77202c48bc9",
2836
strip_prefix = "cloud_archive_test",
2937
)
38+
39+
gs_archive(
40+
name = "archive_gcloud_zstd",
41+
bucket = "depthwise-temp",
42+
build_file = "//:BUILD.archive",
43+
file_path = "cloud_archive_test.tar.zst",
44+
sha256 = "1891c85349f519206a2a2aa21f4927146b8cf84db04d3be91e0b54ce564d8b73",
45+
strip_prefix = "dir1",
46+
)
47+
48+
gs_archive(
49+
name = "archive_gcloud_zstd_strip2",
50+
bucket = "depthwise-temp",
51+
build_file = "//:BUILD.archive",
52+
file_path = "cloud_archive_test.tar.zst",
53+
sha256 = "1891c85349f519206a2a2aa21f4927146b8cf84db04d3be91e0b54ce564d8b73",
54+
strip_prefix = "dir1/dir2",
55+
)
56+
57+
gs_archive(
58+
name = "archive_gcloud_zstd_patch",
59+
bucket = "depthwise-temp",
60+
build_file = "//:BUILD.archive",
61+
file_path = "cloud_archive_test.tar.zst",
62+
patch_args = ["-p1"],
63+
patches = ["//:test.patch"],
64+
sha256 = "1891c85349f519206a2a2aa21f4927146b8cf84db04d3be91e0b54ce564d8b73",
65+
strip_prefix = "dir1",
66+
)

cloud_archive.bzl

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,37 @@ def validate_checksum(repo_ctx, url, local_path, expected_sha256):
2121
))
2222

2323
def extract_archive(repo_ctx, local_path, strip_prefix, build_file, build_file_contents):
24-
# Extract the downloaded archive.
25-
repo_ctx.extract(local_path, stripPrefix = strip_prefix)
24+
bash_path = repo_ctx.os.environ.get("BAZEL_SH", "bash")
25+
if local_path.endswith(".tar.zst") or local_path.endswith(".tar.zstd"):
26+
# Recent TAR supports zstd, if the compressor is installed.
27+
zst_path = repo_ctx.which("zstd")
28+
if zst_path == None:
29+
fail("To decompress .tar.zst, install zstd.")
30+
tar_path = repo_ctx.which("tar")
31+
if tar_path == None:
32+
fail("To decompress .tar.zst, install tar.")
33+
extra_tar_params = []
34+
if strip_prefix != None and strip_prefix:
35+
# Trick: we need to extract a subdir, and remove its components
36+
# from the path. We do so via `tar xvf file.tar.zst sub/dir
37+
# --strip-components=N`. Here we figure out the N.
38+
num_components = 0
39+
prefix = strip_prefix.strip("/")
40+
for c in prefix.split("/"):
41+
if len(c) > 0:
42+
num_components += 1
43+
extra_tar_params = [prefix, "--strip-components=" + str(num_components)]
44+
45+
# Decompress with tar, piping through zstd internally, and stripping prefix
46+
# if requested.
47+
tar_cmd = [tar_path, "-x", "-f", local_path] + extra_tar_params
48+
repo_ctx.execute(tar_cmd)
49+
else:
50+
# Extract the downloaded archive using Bazel's built-in decompressors.
51+
repo_ctx.extract(local_path, stripPrefix = strip_prefix)
2652

2753
# Provide external BUILD file if requested; `build_file_contents` takes
2854
# priority.
29-
bash_path = repo_ctx.os.environ.get("BAZEL_SH", "bash")
3055
if build_file_contents:
3156
repo_ctx.execute([bash_path, "-c", "rm -f BUILD BUILD.bazel"])
3257
repo_ctx.file("BUILD.bazel", build_file_contents, executable = False)
@@ -39,6 +64,8 @@ def cloud_archive_download(
3964
file_path,
4065
expected_sha256,
4166
provider,
67+
patches,
68+
patch_args,
4269
bucket = "",
4370
strip_prefix = "",
4471
build_file = "",
@@ -84,14 +111,46 @@ def cloud_archive_download(
84111
# Verify.
85112
filename = repo_ctx.path(src_url).basename
86113
validate_checksum(repo_ctx, file_path, filename, expected_sha256)
114+
115+
# Extract
87116
extract_archive(repo_ctx, filename, strip_prefix, build_file, build_file_contents)
88117

118+
# If patches are provided, apply them.
119+
if patches != None and len(patches) > 0:
120+
patches = [str(repo_ctx.path(patch)) for patch in patches]
121+
122+
# Built in Bazel patch only supports -pN or no parameters at all, so we
123+
# determine if we can use the built in patch.
124+
only_strip_param = (patch_args != None and
125+
len(patch_args) == 1 and
126+
patch_args[0].startswith("-p") and
127+
patch_args[0][2:].isdigit())
128+
strip_n = 0
129+
if only_strip_param:
130+
strip_n = int(patch_args[0][2])
131+
132+
if patch_args == None or only_strip_param:
133+
# OK to use built-in patch.
134+
for patch in patches:
135+
repo_ctx.patch(patch, strip = strip_n)
136+
else:
137+
# Must use extrenal patch. Note that this hasn't been tested, so it
138+
# might not work. If it's busted, please send a PR.
139+
patch_path = repo_ctx.which("patch")
140+
for patch in patches:
141+
patch_cmd = [patch_path] + patch_args + ["-i", patch]
142+
result = repo_ctx.execute(patch_cmd)
143+
if result.return_code != 0:
144+
fail("Patch {} failed to apply.")
145+
89146
def _cloud_archive_impl(ctx):
90147
cloud_archive_download(
91148
ctx,
92149
ctx.attr.file_path,
93150
ctx.attr.sha256,
94151
provider = ctx.attr._provider,
152+
patches = ctx.attr.patches,
153+
patch_args = ctx.attr.patch_args,
95154
strip_prefix = ctx.attr.strip_prefix,
96155
build_file = ctx.attr.build_file,
97156
build_file_contents = ctx.attr.build_file_contents,
@@ -112,6 +171,8 @@ minio_archive = repository_rule(
112171
doc = "BUILD file for the unpacked archive",
113172
),
114173
"build_file_contents": attr.string(doc = "The contents of the build file for the target"),
174+
"patches": attr.label_list(doc = "Patches to apply, if any.", allow_files = True),
175+
"patch_args": attr.string_list(doc = "Arguments to use when applying patches."),
115176
"strip_prefix": attr.string(doc = "Prefix to strip when archive is unpacked"),
116177
"_provider": attr.string(default = "minio"),
117178
},
@@ -132,6 +193,8 @@ s3_archive = repository_rule(
132193
doc = "BUILD file for the unpacked archive",
133194
),
134195
"build_file_contents": attr.string(doc = "The contents of the build file for the target"),
196+
"patches": attr.label_list(doc = "Patches to apply, if any.", allow_files = True),
197+
"patch_args": attr.string_list(doc = "Arguments to use when applying patches."),
135198
"strip_prefix": attr.string(doc = "Prefix to strip when archive is unpacked"),
136199
"_provider": attr.string(default = "s3"),
137200
},
@@ -151,6 +214,8 @@ gs_archive = repository_rule(
151214
doc = "BUILD file for the unpacked archive",
152215
),
153216
"build_file_contents": attr.string(doc = "The contents of the build file for the target"),
217+
"patches": attr.label_list(doc = "Patches to apply, if any.", allow_files = True),
218+
"patch_args": attr.string_list(doc = "Arguments to use when applying patches."),
154219
"strip_prefix": attr.string(doc = "Prefix to strip when archive is unpacked"),
155220
"_provider": attr.string(default = "google"),
156221
},
@@ -170,6 +235,8 @@ b2_archive = repository_rule(
170235
doc = "BUILD file for the unpacked archive",
171236
),
172237
"build_file_contents": attr.string(doc = "The contents of the build file for the target"),
238+
"patches": attr.label_list(doc = "Patches to apply, if any.", allow_files = True),
239+
"patch_args": attr.string_list(doc = "Arguments to use when applying patches."),
173240
"strip_prefix": attr.string(doc = "Prefix to strip when archive is unpacked"),
174241
"_provider": attr.string(default = "backblaze"),
175242
},

main.cc

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,30 @@
11
#include <cstdio>
2+
#include <filesystem>
23

3-
int main() {
4+
namespace {
5+
6+
void PrintFileContents(const std::filesystem::path path) {
47
printf("File contents:\n");
58
size_t bytes_read = 0;
69
char buf[256];
7-
FILE* f = fopen("external/archive_gcloud/cloud_archive_test.txt", "r");
10+
FILE* f = fopen(path.string().c_str(), "r");
811
if (f == nullptr) {
9-
fprintf(stderr, "Failed to open file.");
10-
return 1;
12+
throw std::invalid_argument("Failed to open file " + path.string());
1113
}
1214
while ((bytes_read = fread(buf, 1, sizeof(buf), f)) > 0) {
1315
fwrite(buf, 1, bytes_read, stdout);
16+
printf("\n");
1417
}
1518
fclose(f);
19+
}
20+
21+
} // namespace
22+
23+
int main() {
24+
PrintFileContents("external/archive_gcloud_gz/cloud_archive_test.txt");
25+
PrintFileContents("external/archive_gcloud_zstd/dir2/dir3/text3.txt");
26+
PrintFileContents("external/archive_gcloud_zstd_strip2/dir3/text3.txt");
27+
PrintFileContents("external/archive_gcloud_zstd_patch/dir2/dir3/text3.txt");
28+
1629
return 0;
1730
}

0 commit comments

Comments
 (0)