Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • bazel/download_utils
1 result
Show changes
Commits on Source (22)
Showing
with 9147 additions and 52 deletions
# Use pre-release registry. Remove when available in BCR
# `bzlmod` pre-release registries
common --registry https://bcr.bazel.build
common --registry=https://gitlab.arm.com/bazel/toolchain_utils/-/releases/v1.0.2/downloads
common --registry=https://gitlab.arm.com/bazel/pre-commit/-/releases/v1.0.7/downloads
common --registry=https://gitlab.arm.com/bazel/pre-commit/-/releases/v1.0.4/downloads
common --registry=https://gitlab.arm.com/bazel/pre-commit-hooks/-/releases/v1.1.0/downloads
# Build cache
build --experimental_guard_against_concurrent_changes
......@@ -20,8 +22,15 @@ test --build_tests_only
# Print relative paths where possible to reduce noise
common --attempt_to_print_relative_paths
# Enable hermetic `rules_python`
common --@rules_python//python/config_settings:bootstrap_impl=script
# Disable warning transitive module versions
common --check_direct_dependencies=off
# User-specific .bazelrc
try-import %workspace%/.bazelrc.user
# Disable Bazel output for `pre-commit` hooks
common:pre-commit --ui_event_filters=-info,-stdout,-stderr
common:pre-commit --noshow_progress
8.0.1
8.2.1
8de8de34364c23a5ad5317854e418f9ab4ad364d
include:
- component: "${CI_SERVER_HOST}/ci/component/bazelisk/ruleset@v1.2.0"
- component: "${CI_SERVER_HOST}/ci/component/bazelisk/ruleset@v1.5.0"
inputs:
oses:
- linux
......@@ -8,10 +8,12 @@ include:
versions:
- 7.4.0
- 7.x
- 8.x
- last_rc
# TODO: reenable when `--repo_contents_cache` is resolved
# - 8.x
# - last_rc
default:
tags:
- arm64
- linux
- dind
......@@ -22,5 +22,8 @@ package_info(
# Just here to provide a test target so `bazel test ...` passes
build_test(
name = "test",
targets = [":license", ":package_info"],
targets = [
":license",
":package_info",
],
)
# [1.1.0](https://git.gitlab.arm.com/bazel/download_utils/compare/v1.0.1...v1.1.0) (2025-06-26)
### Bug Fixes
- add `links` to `{srcs}` replacement ([7cdde03](https://git.gitlab.arm.com/bazel/download_utils/commit/7cdde03d46f62f4d70076cb829477b02957ac834))
- append canonical arguments to `WORKSPACE` if it exists ([86b169d](https://git.gitlab.arm.com/bazel/download_utils/commit/86b169d04841489f83c13a64a8b48dd24f0e3fad))
- **archive:** allow empty string for `extension` attribute ([e0fa71a](https://git.gitlab.arm.com/bazel/download_utils/commit/e0fa71aec075840a59fa179ccc615d125db11049))
- do not write `WORKSPACE` if `metadata` attribute is set ([1dc4fb7](https://git.gitlab.arm.com/bazel/download_utils/commit/1dc4fb7fc1b7b0e92cdfa4d9693e5df5b17ed4b6))
### Features
- add `download_template` extension ([32479b1](https://git.gitlab.arm.com/bazel/download_utils/commit/32479b12a3a18b97f5b58a1c1ab73fbe3f896a2c))
- add pre-commit hooks ([062cad4](https://git.gitlab.arm.com/bazel/download_utils/commit/062cad437b5d44190594a1365d46586627c8f714))
- allow custom metadata files ([ea05186](https://git.gitlab.arm.com/bazel/download_utils/commit/ea05186e72848a1dca7348f035989cf40d7ab91c))
## [1.0.1](https://git.gitlab.arm.com/bazel/download_utils/compare/v1.0.0...v1.0.1) (2025-02-12)
### Bug Fixes
......
......@@ -11,6 +11,14 @@ $ (cd e2e; bazelisk test //...)
[bazelisk-install]: https://github.com/bazelbuild/bazelisk?tab=readme-ov-file#installation
# Hooks
Install the `git` hooks with:
```console
$ bazelisk run hooks:install
```
## Workflow
- Follow the [contributions guide] to be granted forking permissions.
......
module(
name = "download_utils",
version = "1.0.1",
version = "1.1.0",
bazel_compatibility = [
">=7.1.0",
],
......@@ -8,10 +8,40 @@ module(
)
bazel_dep(name = "rules_license", version = "1.0.0")
bazel_dep(name = "rules_python", version = "1.0.0")
bazel_dep(name = "bazel_skylib", version = "1.0.3")
bazel_dep(name = "bazel_skylib", version = "1.7.1", dev_dependency = True)
bazel_dep(name = "toolchain_utils", version = "1.0.2", dev_dependency = True)
bazel_dep(name = "pre-commit", version = "1.0.7", dev_dependency = True)
bazel_dep(name = "pre-commit-hooks", version = "1.1.0", dev_dependency = True)
bazel_dep(name = "hermetic_cc_toolchain", version = "3.1.0", dev_dependency = True)
# We have to avoid the `chmod`/`chown`/`id` unhermetic-ness
# TODO: remove this when `ignore_root_user_error` is hermetic
dev = use_extension("@rules_python//python/extensions:python.bzl", "python", dev_dependency = True)
dev.toolchain(
# TODO: remove this when `ignore_root_user_error` is hermetic
# https://github.com/bazelbuild/rules_python/issues/2016
ignore_root_user_error = True,
python_version = "3.13",
)
separator = use_repo_rule("//lib:separator.bzl", "separator")
separator(name = "separator")
download = use_extension("//download/template:defs.bzl", "download_template")
download.substitutions(
srcs = [
"//download/template:rust.json",
"//download/template:triplet.json",
],
)
download.substitution(
key = "executable.extension",
match = "{os}",
select = {
"windows": ".exe",
"//conditions:default": "",
},
)
This diff is collapsed.
......@@ -12,15 +12,23 @@ bazel_dep(name="download_utils", version="0.0.0")
Use the repository rules in `MODULE.bazel` to download artifacts:
### `download_archive`
Download an archive and unpack it:
```py
# Download an archive and unpack it
download_archive = use_repo_rule("@download_utils//download/archive:defs.bzl", "download_archive")
download_archive(
name = "archive",
urls = ["https://some.thing/archive.tar"],
)
```
# Download a single file and possibly make it executable
### `download_file`
Download a single file and optionally make it executable:
```py
download_file = use_repo_rule("@download_utils//download/file:defs.bzl", "download_file")
download_file(
name = "file",
......@@ -28,8 +36,13 @@ download_file(
executable = True,
urls = ["https://some.thing/executable-amd64-linux"],
)
```
### `download_deb`
Download a Debian package, unpack it then unpack the `data.tar.{xz,zst}`:
# Download a Debian package, unpack it then unpack the `data.tar.{xz,zst}`
```py
download_deb = use_repo_rule("@download_utils//download/deb:defs.bzl", "download_deb")
download_deb(
name = "deb",
......@@ -52,6 +65,118 @@ download_deb(
)
```
# `download_template`
Use an extension to template the attributes based on provided `substitutions`:
```py
download = use_extension("@download_utils//download/template:defs.bzl", "download_template")
download.archive(
name = "coreutils-{version}-{triplet}",
srcs = ["entrypoint"],
links = {
"coreutils{executable.extension}": "entrypoint",
},
# Run `bazel run @download_utils//download/template/lock coreutils/lock.json` to lock integrities
lock = "//coreutils:lock.json",
strip_prefix = "coreutils-{version}-{rust.triplet}",
substitutions = {
"version": [
"0.0.28",
"0.1.0",
],
"triplets": [
"arm64-linux-gnu",
"amd64-linux-gnu",
"arm64-linux-musl",
"amd64-linux-musl",
"amd64-windows-msvc",
"arm64-macos-darwin",
"amd64-macos-darwin",
],
},
# Run `bazel run @download_utils//download/template/lock:upload coreutils/lock.json` to mirror binaries and lock integrities
uploads = [
"https://gitlab.arm.com/api/v4/projects/bazel%2Fdownload_utils/packages/generic/coreutils/{version}/{rust.archive.basename}",
],
urls = [
"https://gitlab.arm.com/api/v4/projects/bazel%2Fdownload_utils/packages/generic/coreutils/{version}/{rust.archive.basename}",
"https://github.com/uutils/coreutils/releases/download/{version}/coreutils-{version}-{rust.archive.basename}",
],
)
# Run `bazel mod tidy` to update these
use_repo(
download,
"coreutils-0.0.28-amd64-linux-gnu",
"coreutils-0.0.28-amd64-linux-musl",
"coreutils-0.0.28-amd64-macos-darwin",
"coreutils-0.0.28-amd64-windows-msvc",
"coreutils-0.0.28-arm64-linux-gnu",
"coreutils-0.0.28-arm64-linux-musl",
"coreutils-0.0.28-arm64-macos-darwin",
"coreutils-0.1.0-amd64-linux-gnu",
"coreutils-0.1.0-amd64-linux-musl",
"coreutils-0.1.0-amd64-macos-darwin",
"coreutils-0.1.0-amd64-windows-msvc",
"coreutils-0.1.0-arm64-linux-gnu",
"coreutils-0.1.0-arm64-linux-musl",
"coreutils-0.1.0-arm64-macos-darwin",
)
```
Extra substitutions, such as `{rust.archive.basename}` are created using the `download_template.substitution` and `download_template.substitutions` APIs:
```py
download = use_extension("@download_utils//download/template:defs.bzl", "download_template")
# Create derived `{cpu}` substitution based on an incomming `{triplet}` substitution.
download.substitution(
name = "cpu",
match = "{triplet}",
select = {
"//conditions:default": "{triplet.split('-')[0]}",
},
)
# Read substitutions from a JSON file
download.substitutions(
srcs = [
"substitutions.json",
],
)
```
The layout of the JSON is as so:
```JSON
{
"<name>": "<value>",
"<name>": {
"<match>": {
"<key>": "<value>",
},
},
}
```
Concretly, as an example, two substitutions:
```json
{
"os": "{triplet.split('-')[1]}",
"rust.vendor": {
"{os}": {
"macos": "apple",
"windows": "pc",
"//conditions:default": "unknown"
}
}
}
```
`@download_utils` has a set of subtitutions already registered. See `download/template/*.json`
### Integrity
The [sub-resource integrity (SRI)][sri] is not required for secure URLs. For non-secure (`http`, `ftp`) it is. It is
......
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:commands.bzl", "commands", _COMMANDS = "ATTRS")
load("//lib:download_and_extract.bzl", "download_and_extract", _DOWNLOAD_AND_EXTRACT = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:links.bzl", "links", _LINKS = "ATTRS")
load("//lib:metadata.bzl", "metadata", _METADATA = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:workspace.bzl", "write")
visibility("//download/...")
......@@ -18,10 +19,10 @@ download_archive(
```
"""
ATTRS = _COMMANDS | _DOWNLOAD_AND_EXTRACT | _PATCH | _BUILD | _LINKS | {
ATTRS = _COMMANDS | _DOWNLOAD_AND_EXTRACT | _PATCH | _BUILD | _LINKS | _METADATA | {
"extension": attr.string(
doc = "The extension of the archive when not available from the URL.",
values = [".zip", ".tar", ".tar.gz", ".tar.bz2", ".tar.xz", ".tar.zst"],
values = ["", ".zip", ".tar", ".tar.gz", ".tar.bz2", ".tar.xz", ".tar.zst"],
),
}
......@@ -34,6 +35,8 @@ def implementation(rctx):
canonical |= links(rctx)
canonical |= commands(rctx)
metadata(rctx, canonical)
return write(rctx, canonical)
archive = repository_rule(
......
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:commands.bzl", "commands", _COMMANDS = "ATTRS")
load("//lib:download_and_extract.bzl", "download_and_extract", _DOWNLOAD_AND_EXTRACT = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:links.bzl", "links", _LINKS = "ATTRS")
load("//lib:metadata.bzl", "metadata", _METADATA = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:workspace.bzl", "write")
visibility("//download/...")
......@@ -21,7 +22,7 @@ download_deb(
```
"""
ATTRS = _COMMANDS | _DOWNLOAD_AND_EXTRACT | _PATCH | _BUILD | _LINKS
ATTRS = _COMMANDS | _DOWNLOAD_AND_EXTRACT | _PATCH | _BUILD | _LINKS | _METADATA
def implementation(rctx):
canonical = {a: getattr(rctx.attr, a) for a in ATTRS} | {"name": rctx.name}
......@@ -32,6 +33,8 @@ def implementation(rctx):
canonical |= links(rctx)
canonical |= commands(rctx)
metadata(rctx, canonical)
return write(rctx, canonical)
deb = repository_rule(
......
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:commands.bzl", "commands", _COMMANDS = "ATTRS")
load("//lib:download.bzl", "download", _DOWNLOAD = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:build.bzl", "build", _BUILD = "ATTRS")
load("//lib:links.bzl", "links", _LINKS = "ATTRS")
load("//lib:metadata.bzl", "metadata", _METADATA = "ATTRS")
load("//lib:patch.bzl", "patch", _PATCH = "ATTRS")
load("//lib:workspace.bzl", "write")
visibility("//download/...")
......@@ -20,12 +21,7 @@ download_file(
```
"""
ATTRS = _COMMANDS | _DOWNLOAD | _PATCH | _BUILD | _LINKS | {
"build": attr.label(
doc = "The template for the `BUILD.bazel` file.",
default = ":BUILD.tmpl.bazel",
),
}
ATTRS = _COMMANDS | _DOWNLOAD | _PATCH | _BUILD | _LINKS | _METADATA
def implementation(rctx):
canonical = {a: getattr(rctx.attr, a) for a in ATTRS} | {"name": rctx.name}
......@@ -36,6 +32,8 @@ def implementation(rctx):
canonical |= links(rctx)
canonical |= commands(rctx)
metadata(rctx, canonical)
return write(rctx, canonical)
file = repository_rule(
......
load("//download/archive:repository.bzl", _ARCHIVE = "ATTRS", _rule = "archive")
load(":repository.bzl", _ATTRS = "ATTRS", _implementation = "implementation")
visibility("//...")
DOC = """Downloads an archive and extracts it using templated attributes.
```python
download = use_extension("@download_utils//download/template:defs.bzl", "download_template")
download.archive(
name = "coreutils-{version}-{triplet}",
srcs = ["entrypoint"],
links = {
"coreutils{executable.extension}": "entrypoint",
},
lock = "//coreutils:lock.json",
strip_prefix = "coreutils-{version}-{rust.triplet}",
substitutions = {
"version": [
"0.1.0",
],
"triplets": [
"arm64-linux-gnu",
"amd64-linux-gnu",
"arm64-linux-musl",
"amd64-linux-musl",
"amd64-windows-msvc",
"arm64-macos-darwin",
"amd64-macos-darwin",
],
},
urls = [
"https://github.com/uutils/coreutils/releases/download/{version}/coreutils-{version}-{rust.archive.basename}",
],
)
use_repo(
download,
"coreutils-0.1.0-amd64-linux-gnu",
"coreutils-0.1.0-amd64-linux-musl",
"coreutils-0.1.0-amd64-macos-darwin",
"coreutils-0.1.0-amd64-windows-msvc",
"coreutils-0.1.0-arm64-linux-gnu",
"coreutils-0.1.0-arm64-linux-musl",
"coreutils-0.1.0-arm64-macos-darwin",
)
```
The attributes will be templated using the `triplet` and `substitutions` values.
Each triplet is split into `{cpu}`, `{os}` and `{libc}` substitutions which can be used to create other substitutions.
`download_utils` has certain substitutions implemented such as `{rust.archive.basename}`.
The built-in substitutions can be seen in the `@download_utils//:MODULE.bazel` file via `download.substitutions` invocations.
Other substitutions can be added by other modules.
Running `bazel mod tidy` will generate the `lock` with the templated URLs and blank integrities.
The lock file sub-resource integrities can be updated with:
```console
$ bazel run @download_utils//download/template/lock coreutils/lock.json
```
Alternatively, generate the lock from an upstream checksum file.
Binaries can be mirrored by setting `upload` attribute and running:
```console
$ bazel run @download_utils//download/template/lock:upload coreutils/lock.json
```
"""
ATTRS = _ARCHIVE | _ATTRS
ATTRS.pop("integrity")
def implementation(ctx, attrs, data):
return _implementation(ctx, _rule, attrs, data)
download_template_archive = tag_class(
doc = DOC,
attrs = ATTRS,
)
archive = download_template_archive
load("//download/deb:repository.bzl", _DEB = "ATTRS", _rule = "deb")
load(":repository.bzl", _ATTRS = "ATTRS", _implementation = "implementation")
visibility("//...")
DOC = """Downloads an archive and extracts it using templated attributes.
```python
download = use_extension("@download_utils//download/template:defs.bzl", "download_template")
download.deb(
name = "busybox-{version}-{cpu}-{os}",
srcs = ["busybox"],
links = {
"busybox": "entrypoint",
},
lock = "//busybox:lock.json",
strip_prefix = "usr/bin",
substitutions = {
"version": [
"1.36.1",
],
"revision": [
"6",
],
"triplet": [
"arm64-linux-gnu",
"amd64-linux-gnu",
],
},
uploads = [
"https://gitlab.arm.com/api/v4/projects/bazel%2Fdownload_utils/packages/generic/busybox-static/{version}/busybox-static_{version}-{revision}_{cpu}.deb",
],
urls = [
"https://gitlab.arm.com/api/v4/projects/bazel%2Fdownload_utils/packages/generic/busybox-static/{version}/busybox-static_{version}-{revision}_{cpu}.deb",
"https://snapshot-cloudflare.debian.org/archive/debian/20240210T223313Z/pool/main/b/busybox/busybox-static_{version}-{revision}_{cpu}.deb",
],
)
```
The attributes will be templated using the `triplet` and `substitutions` values.
Each triplet is split into `{cpu}`, `{os}` and `{libc}` substitutions which can be used to create other substitutions.
`download_utils` has certain substitutions implemented such as `{rust.archive.basename}`.
The built-in substitutions can be seen in the `@download_utils//:MODULE.bazel` file via `download.substitutions` invocations.
Other substitutions can be added by other modules.
Running `bazel mod tidy` will generate the `lock` with the templated URLs and blank integrities.
The lock file sub-resource integrities can be updated with:
```console
$ bazel run @download_utils//download/template/lock busybox/lock.json
```
Alternatively, generate the lock from an upstream checksum file.
Binaries can be mirrored by setting `upload` attribute and running:
```console
$ bazel run @download_utils//download/template/lock:upload busybox/lock.json
```
"""
ATTRS = _DEB | _ATTRS
ATTRS.pop("integrity")
def implementation(ctx, attrs, data):
return _implementation(ctx, _rule, attrs, data)
download_template_deb = tag_class(
doc = DOC,
attrs = ATTRS,
)
deb = download_template_deb
load(":extension.bzl", _template = "template")
visibility("public")
download_template = _template
load(":archive.bzl", "archive", _archive = "implementation")
load(":deb.bzl", "deb", _deb = "implementation")
load(":file.bzl", "file", _file = "implementation")
load(":substitution.bzl", "substitution")
load(":substitutions.bzl", "substitutions", _load = "read")
visibility("//...")
DOC = """An extension to perform templated substitution of downloads.
Download artifacts with the `archive`, `file` and `deb` tags.
Provide substitutions data with the `substitution` and `substitutions` tags.
"""
TAGS = {
"archive": archive,
"file": file,
"deb": deb,
"substitution": substitution,
"substitutions": substitutions,
}
def _substitutions(mctx):
data = {}
ctx = struct(read = mctx.read)
for m in mctx.modules:
substitutions = [s for t in m.tags.substitutions for s in _load(ctx, t.srcs)]
for s in m.tags.substitution + substitutions:
if s.key in data:
fail("`{}` already defined in `{}`".format(s.key, data[s.key].module))
data[s.key] = struct(key = s.key, match = s.match, select = struct(**s.select), module = m.name)
return tuple(data.values())
def _write(ctx, path, content, *, executable = True):
"""
Enables writing outside the repository bounds.
`ctx.file` does not allow that, which we need.
"""
path = ctx.path(path)
exe = ctx.which("cmd.exe")
if exe:
cmd = (exe, "/C", "echo '{}' > {}".format(content, path))
ctx.execute(cmd, timeout = 10)
return None
for exe in ("sh", "bash", "dash", "zsh", "fish"):
exe = ctx.which("sh")
if exe:
cmd = (exe, "-c", "echo '{}' > {}".format(content, path))
ctx.execute(cmd, timeout = 10)
return None
fail("failed to find a executable to write `{}`".format(path))
def implementation(mctx):
# Collect templating substitution data
substitutions = _substitutions(mctx)
# Build a reduced context to pass to repository helpers
ctx = struct(
read = mctx.read,
file = lambda *k, **kw: _write(mctx, *k, **kw),
path = mctx.path,
)
# Create repositories
direct = []
reproducible = True
for module in mctx.modules:
for rule, tags in (
(_archive, module.tags.archive),
(_file, module.tags.file),
(_deb, module.tags.deb),
):
for attrs in tags:
names, repro = rule(ctx, attrs, substitutions)
if not repro:
reproducible = False
if module.is_root:
direct += names
# Done!
if direct:
return mctx.extension_metadata(
root_module_direct_deps = direct,
root_module_direct_dev_deps = [],
reproducible = reproducible,
)
return mctx.extension_metadata(
reproducible = reproducible,
)
download_template = module_extension(
doc = DOC,
tag_classes = TAGS,
implementation = implementation,
)
template = download_template
load("//download/file:repository.bzl", _FILE = "ATTRS", _rule = "file")
load(":repository.bzl", _ATTRS = "ATTRS", _implementation = "implementation")
visibility("//...")
DOC = """Downloads an archive and extracts it using templated attributes.
```python
download = use_extension("@download_utils//download/template:defs.bzl", "download_template")
download.file(
name = "shfmt-{version}-{cpu}-{os}",
lock = "//shfmt:lock.json",
output = "shfmt{executable.extension}",
substitutions = {
"version": [
"3.11.0",
],
"triplets": [
"arm64-linux-gnu",
"amd64-linux-gnu",
],
},
executable = True,
links = {
"shfmt{executable.extension}": "entrypoint",
},
urls = [
"https://github.com/mvdan/sh/releases/download/v{version}/shfmt_v{version}_{os}_{cpu}",
],
)
use_repo(
download,
"shfmt-3.11.0-amd64-linux",
"shfmt-3.11.0-arm64-linux",
)
```
The attributes will be templated using the `triplet` and `substitutions` values.
Each triplet is split into `{cpu}`, `{os}` and `{libc}` substitutions which can be used to create other substitutions.
`download_utils` has certain substitutions implemented such as `{executable.extension}`.
The built-in substitutions can be seen in the `@download_utils//:MODULE.bazel` file via `download.substitutions` invocations.
Other substitutions can be added by other modules.
Running `bazel mod tidy` will generate the `lock` with the templated URLs and blank integrities.
The lock file sub-resource integrities can be updated with:
```console
$ bazel run @download_utils//download/template/lock shfmt/lock.json
```
Alternatively, generate the lock from an upstream checksum file.
Binaries can be mirrored by setting `upload` attribute and running:
```console
$ bazel run @download_utils//download/template/lock:upload shfmt/lock.json
```
"""
ATTRS = _FILE | _ATTRS
ATTRS.pop("integrity")
def implementation(ctx, attrs, data):
return _implementation(ctx, _rule, attrs, data)
download_template_file = tag_class(
doc = DOC,
attrs = ATTRS,
)
file = download_template_file
load("@bazel_skylib//rules:native_binary.bzl", "native_binary")
load("@rules_python//python:py_binary.bzl", "py_binary")
py_binary(
name = "cli",
srcs = [
"__main__.py",
"cli.py",
"download.py",
"file.py",
"integrity.py",
"substitutions.py",
"typing.py",
"upload.py",
"url.py",
],
main = "__main__.py",
visibility = ["//visibility:public"],
)
native_binary(
name = "lock",
src = ":cli",
args = [
"lock",
],
visibility = ["//visibility:public"],
)
native_binary(
name = "upload",
src = ":cli",
args = [
"upload",
],
visibility = ["//visibility:public"],
)