aboutsummaryrefslogtreecommitdiff
path: root/examples/build_file_generation
diff options
context:
space:
mode:
Diffstat (limited to 'examples/build_file_generation')
-rw-r--r--examples/build_file_generation/.bazelrc5
-rw-r--r--examples/build_file_generation/.gitignore1
-rw-r--r--examples/build_file_generation/BUILD.bazel106
-rw-r--r--examples/build_file_generation/README.md22
-rw-r--r--examples/build_file_generation/WORKSPACE123
-rw-r--r--examples/build_file_generation/__init__.py26
-rw-r--r--examples/build_file_generation/__main__.py18
-rw-r--r--examples/build_file_generation/__test__.py28
-rw-r--r--examples/build_file_generation/gazelle_python.yaml118
-rw-r--r--examples/build_file_generation/random_number_generator/BUILD.bazel19
-rw-r--r--examples/build_file_generation/random_number_generator/__init__.py14
-rw-r--r--examples/build_file_generation/random_number_generator/__test__.py25
-rw-r--r--examples/build_file_generation/random_number_generator/generate_random_number.py19
-rw-r--r--examples/build_file_generation/requirements.in1
-rw-r--r--examples/build_file_generation/requirements_lock.txt78
-rw-r--r--examples/build_file_generation/requirements_windows.txt82
16 files changed, 685 insertions, 0 deletions
diff --git a/examples/build_file_generation/.bazelrc b/examples/build_file_generation/.bazelrc
new file mode 100644
index 0000000..28f634b
--- /dev/null
+++ b/examples/build_file_generation/.bazelrc
@@ -0,0 +1,5 @@
+test --test_output=errors --enable_runfiles
+
+# Windows requires these for multi-python support:
+build --enable_runfiles
+startup --windows_enable_symlinks
diff --git a/examples/build_file_generation/.gitignore b/examples/build_file_generation/.gitignore
new file mode 100644
index 0000000..ac51a05
--- /dev/null
+++ b/examples/build_file_generation/.gitignore
@@ -0,0 +1 @@
+bazel-*
diff --git a/examples/build_file_generation/BUILD.bazel b/examples/build_file_generation/BUILD.bazel
new file mode 100644
index 0000000..928fb12
--- /dev/null
+++ b/examples/build_file_generation/BUILD.bazel
@@ -0,0 +1,106 @@
+# Load various rules so that we can have bazel download
+# various rulesets and dependencies.
+# The `load` statement imports the symbol for the rule, in the defined
+# ruleset. When the symbol is loaded you can use the rule.
+load("@bazel_gazelle//:def.bzl", "gazelle")
+load("@pip//:requirements.bzl", "all_whl_requirements")
+load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")
+load("@rules_python//python:pip.bzl", "compile_pip_requirements")
+load("@rules_python_gazelle_plugin//:def.bzl", "GAZELLE_PYTHON_RUNTIME_DEPS")
+load("@rules_python_gazelle_plugin//manifest:defs.bzl", "gazelle_python_manifest")
+load("@rules_python_gazelle_plugin//modules_mapping:def.bzl", "modules_mapping")
+
+compile_pip_requirements(
+ name = "requirements",
+ extra_args = ["--allow-unsafe"],
+ requirements_in = "requirements.in",
+ requirements_txt = "requirements_lock.txt",
+ requirements_windows = "requirements_windows.txt",
+)
+
+# This repository rule fetches the metadata for python packages we
+# depend on. That data is required for the gazelle_python_manifest
+# rule to update our manifest file.
+# To see what this rule does, try `bazel run @modules_map//:print`
+modules_mapping(
+ name = "modules_map",
+ exclude_patterns = [
+ "^_|(\\._)+", # This is the default.
+ "(\\.tests)+", # Add a custom one to get rid of the psutil tests.
+ ],
+ wheels = all_whl_requirements,
+)
+
+# Gazelle python extension needs a manifest file mapping from
+# an import to the installed package that provides it.
+# This macro produces two targets:
+# - //:gazelle_python_manifest.update can be used with `bazel run`
+# to recalculate the manifest
+# - //:gazelle_python_manifest.test is a test target ensuring that
+# the manifest doesn't need to be updated
+gazelle_python_manifest(
+ name = "gazelle_python_manifest",
+ modules_mapping = ":modules_map",
+ pip_repository_name = "pip",
+ # NOTE: We can pass a list just like in `bzlmod_build_file_generation` example
+ # but we keep a single target here for regression testing.
+ requirements = "//:requirements_lock.txt",
+ # NOTE: we can use this flag in order to make our setup compatible with
+ # bzlmod.
+ use_pip_repository_aliases = True,
+)
+
+# Our gazelle target points to the python gazelle binary.
+# This is the simple case where we only need one language supported.
+# If you also had proto, go, or other gazelle-supported languages,
+# you would also need a gazelle_binary rule.
+# See https://github.com/bazelbuild/bazel-gazelle/blob/master/extend.rst#example
+gazelle(
+ name = "gazelle",
+ data = GAZELLE_PYTHON_RUNTIME_DEPS,
+ gazelle = "@rules_python_gazelle_plugin//python:gazelle_binary",
+)
+
+# This rule is auto-generated and managed by Gazelle,
+# because it found the __init__.py file in this folder.
+# See: https://bazel.build/reference/be/python#py_library
+py_library(
+ name = "build_file_generation",
+ srcs = ["__init__.py"],
+ visibility = ["//:__subpackages__"],
+ deps = [
+ "//random_number_generator",
+ "@pip//flask",
+ ],
+)
+
+# A py_binary is an executable Python program consisting of a collection of .py source files.
+# See: https://bazel.build/reference/be/python#py_binary
+#
+# This rule is auto-generated and managed by Gazelle,
+# because it found the __main__.py file in this folder.
+# This rule creates a target named //:build_file_generation_bin and you can use
+# bazel to run the target:
+# `bazel run //:build_file_generation_bin`
+py_binary(
+ name = "build_file_generation_bin",
+ srcs = ["__main__.py"],
+ main = "__main__.py",
+ visibility = ["//:__subpackages__"],
+ deps = [":build_file_generation"],
+)
+
+# A py_test is a Python unit test.
+# See: https://bazel.build/reference/be/python#py_test
+#
+# This rule is auto-generated and managed by Gazelle,
+# because it found the __test__.py file in this folder.
+# This rule creates a target named //:build_file_generation_test and you can use
+# bazel to run the target:
+# `bazel test //:build_file_generation_test`
+py_test(
+ name = "build_file_generation_test",
+ srcs = ["__test__.py"],
+ main = "__test__.py",
+ deps = [":build_file_generation"],
+)
diff --git a/examples/build_file_generation/README.md b/examples/build_file_generation/README.md
new file mode 100644
index 0000000..cd3cd1f
--- /dev/null
+++ b/examples/build_file_generation/README.md
@@ -0,0 +1,22 @@
+# Build file generation with Gazelle
+
+This example shows a project that has Gazelle setup with the rules_python
+extension, so that targets like `py_library` and `py_binary` can be
+automatically created just by running
+
+```sh
+bazel run //:requirements.update
+bazel run //:gazelle_python_manifest.update
+bazel run //:gazelle
+```
+
+As a demo, try creating a `__main__.py` file in this directory, then
+re-run that gazelle command. You'll see that a `py_binary` target
+is created in the `BUILD` file.
+
+Or, try importing the `requests` library in `__init__.py`.
+You'll see that `deps = ["@pip//pypi__requests"]` is automatically
+added to the `py_library` target in the `BUILD` file.
+
+For more information on the behavior of the rules_python gazelle extension,
+see the README.md file in the /gazelle folder.
diff --git a/examples/build_file_generation/WORKSPACE b/examples/build_file_generation/WORKSPACE
new file mode 100644
index 0000000..7c74835
--- /dev/null
+++ b/examples/build_file_generation/WORKSPACE
@@ -0,0 +1,123 @@
+# Set the name of the bazel workspace.
+workspace(name = "build_file_generation_example")
+
+# Load the http_archive rule so that we can have bazel download
+# various rulesets and dependencies.
+# The `load` statement imports the symbol for http_archive from the http.bzl
+# file. When the symbol is loaded you can use the rule.
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+######################################################################
+# We need rules_go and bazel_gazelle, to build the gazelle plugin from source.
+# Setup instructions for this section are at
+# https://github.com/bazelbuild/bazel-gazelle#running-gazelle-with-bazel
+# You may need to update the version of the rule, which is listed in the above
+# documentation.
+######################################################################
+
+# Define an http_archive rule that will download the below ruleset,
+# test the sha, and extract the ruleset to you local bazel cache.
+
+http_archive(
+ name = "io_bazel_rules_go",
+ sha256 = "6dc2da7ab4cf5d7bfc7c949776b1b7c733f05e56edc4bcd9022bb249d2e2a996",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
+ "https://github.com/bazelbuild/rules_go/releases/download/v0.39.1/rules_go-v0.39.1.zip",
+ ],
+)
+
+# Download the bazel_gazelle ruleset.
+
+http_archive(
+ name = "bazel_gazelle",
+ sha256 = "727f3e4edd96ea20c29e8c2ca9e8d2af724d8c7778e7923a854b2c80952bc405",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.30.0/bazel-gazelle-v0.30.0.tar.gz",
+ "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.30.0/bazel-gazelle-v0.30.0.tar.gz",
+ ],
+)
+
+# Load rules_go ruleset and expose the toolchain and dep rules.
+load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
+load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
+
+# go_rules_dependencies is a function that registers external dependencies
+# needed by the Go rules.
+# See: https://github.com/bazelbuild/rules_go/blob/master/go/dependencies.rst#go_rules_dependencies
+go_rules_dependencies()
+
+# go_rules_dependencies is a function that registers external dependencies
+# needed by the Go rules.
+# See: https://github.com/bazelbuild/rules_go/blob/master/go/dependencies.rst#go_rules_dependencies
+go_register_toolchains(version = "1.19.4")
+
+# The following call configured the gazelle dependencies, Go environment and Go SDK.
+gazelle_dependencies()
+
+# Remaining setup is for rules_python.
+
+# DON'T COPY_PASTE THIS.
+# Our example uses `local_repository` to point to the HEAD version of rules_python.
+# Users should instead use the installation instructions from the release they use.
+# See https://github.com/bazelbuild/rules_python/releases
+local_repository(
+ name = "rules_python",
+ path = "../..",
+)
+
+local_repository(
+ name = "rules_python_gazelle_plugin",
+ path = "../../gazelle",
+)
+
+# Next we load the toolchain from rules_python.
+load("@rules_python//python:repositories.bzl", "python_register_toolchains")
+
+# We now register a hermetic Python interpreter rather than relying on a system-installed interpreter.
+# This toolchain will allow bazel to download a specific python version, and use that version
+# for compilation.
+python_register_toolchains(
+ name = "python39",
+ python_version = "3.9",
+)
+
+# Load the interpreter and pip_parse rules.
+load("@python39//:defs.bzl", "interpreter")
+load("@rules_python//python:pip.bzl", "pip_parse")
+
+# This macro wraps the `pip_repository` rule that invokes `pip`, with `incremental` set.
+# Accepts a locked/compiled requirements file and installs the dependencies listed within.
+# Those dependencies become available in a generated `requirements.bzl` file.
+# You can instead check this `requirements.bzl` file into your repo.
+pip_parse(
+ name = "pip",
+ # Generate user friendly alias labels for each dependency that we have.
+ incompatible_generate_aliases = True,
+ # (Optional) You can provide a python_interpreter (path) or a python_interpreter_target (a Bazel target, that
+ # acts as an executable). The latter can be anything that could be used as Python interpreter. E.g.:
+ # 1. Python interpreter that you compile in the build file.
+ # 2. Pre-compiled python interpreter included with http_archive.
+ # 3. Wrapper script, like in the autodetecting python toolchain.
+ #
+ # Here, we use the interpreter constant that resolves to the host interpreter from the default Python toolchain.
+ python_interpreter_target = interpreter,
+ # Set the location of the lock file.
+ requirements_lock = "//:requirements_lock.txt",
+ requirements_windows = "//:requirements_windows.txt",
+)
+
+# Load the install_deps macro.
+load("@pip//:requirements.bzl", "install_deps")
+
+# Initialize repositories for all packages in requirements_lock.txt.
+install_deps()
+
+# The rules_python gazelle extension has some third-party go dependencies
+# which we need to fetch in order to compile it.
+load("@rules_python_gazelle_plugin//:deps.bzl", _py_gazelle_deps = "gazelle_deps")
+
+# See: https://github.com/bazelbuild/rules_python/blob/main/gazelle/README.md
+# This rule loads and compiles various go dependencies that running gazelle
+# for python requirements.
+_py_gazelle_deps()
diff --git a/examples/build_file_generation/__init__.py b/examples/build_file_generation/__init__.py
new file mode 100644
index 0000000..add73da
--- /dev/null
+++ b/examples/build_file_generation/__init__.py
@@ -0,0 +1,26 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from flask import Flask, jsonify
+from random_number_generator import generate_random_number
+
+app = Flask(__name__)
+
+@app.route('/random-number', methods=['GET'])
+def get_random_number():
+ return jsonify({'number': generate_random_number.generate_random_number()})
+
+"""Start the python web server"""
+def main():
+ app.run()
diff --git a/examples/build_file_generation/__main__.py b/examples/build_file_generation/__main__.py
new file mode 100644
index 0000000..8f8efba
--- /dev/null
+++ b/examples/build_file_generation/__main__.py
@@ -0,0 +1,18 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from __init__ import main
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/build_file_generation/__test__.py b/examples/build_file_generation/__test__.py
new file mode 100644
index 0000000..c4fa5ef
--- /dev/null
+++ b/examples/build_file_generation/__test__.py
@@ -0,0 +1,28 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+from __init__ import app
+
+class TestServer(unittest.TestCase):
+ def setUp(self):
+ self.app = app.test_client()
+
+ def test_get_random_number(self):
+ response = self.app.get('/random-number')
+ self.assertEqual(response.status_code, 200)
+ self.assertIn('number', response.json)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/examples/build_file_generation/gazelle_python.yaml b/examples/build_file_generation/gazelle_python.yaml
new file mode 100644
index 0000000..1000757
--- /dev/null
+++ b/examples/build_file_generation/gazelle_python.yaml
@@ -0,0 +1,118 @@
+# GENERATED FILE - DO NOT EDIT!
+#
+# To update this file, run:
+# bazel run //:gazelle_python_manifest.update
+
+manifest:
+ modules_mapping:
+ click: click
+ click.core: click
+ click.decorators: click
+ click.exceptions: click
+ click.formatting: click
+ click.globals: click
+ click.parser: click
+ click.shell_completion: click
+ click.termui: click
+ click.testing: click
+ click.types: click
+ click.utils: click
+ flask: Flask
+ flask.app: Flask
+ flask.blueprints: Flask
+ flask.cli: Flask
+ flask.config: Flask
+ flask.ctx: Flask
+ flask.debughelpers: Flask
+ flask.globals: Flask
+ flask.helpers: Flask
+ flask.json: Flask
+ flask.json.provider: Flask
+ flask.json.tag: Flask
+ flask.logging: Flask
+ flask.scaffold: Flask
+ flask.sessions: Flask
+ flask.signals: Flask
+ flask.templating: Flask
+ flask.testing: Flask
+ flask.typing: Flask
+ flask.views: Flask
+ flask.wrappers: Flask
+ importlib_metadata: importlib_metadata
+ itsdangerous: itsdangerous
+ itsdangerous.encoding: itsdangerous
+ itsdangerous.exc: itsdangerous
+ itsdangerous.serializer: itsdangerous
+ itsdangerous.signer: itsdangerous
+ itsdangerous.timed: itsdangerous
+ itsdangerous.url_safe: itsdangerous
+ jinja2: Jinja2
+ jinja2.async_utils: Jinja2
+ jinja2.bccache: Jinja2
+ jinja2.compiler: Jinja2
+ jinja2.constants: Jinja2
+ jinja2.debug: Jinja2
+ jinja2.defaults: Jinja2
+ jinja2.environment: Jinja2
+ jinja2.exceptions: Jinja2
+ jinja2.ext: Jinja2
+ jinja2.filters: Jinja2
+ jinja2.idtracking: Jinja2
+ jinja2.lexer: Jinja2
+ jinja2.loaders: Jinja2
+ jinja2.meta: Jinja2
+ jinja2.nativetypes: Jinja2
+ jinja2.nodes: Jinja2
+ jinja2.optimizer: Jinja2
+ jinja2.parser: Jinja2
+ jinja2.runtime: Jinja2
+ jinja2.sandbox: Jinja2
+ jinja2.utils: Jinja2
+ jinja2.visitor: Jinja2
+ markupsafe: MarkupSafe
+ werkzeug: Werkzeug
+ werkzeug.datastructures: Werkzeug
+ werkzeug.debug: Werkzeug
+ werkzeug.debug.console: Werkzeug
+ werkzeug.debug.repr: Werkzeug
+ werkzeug.debug.tbtools: Werkzeug
+ werkzeug.exceptions: Werkzeug
+ werkzeug.formparser: Werkzeug
+ werkzeug.http: Werkzeug
+ werkzeug.local: Werkzeug
+ werkzeug.middleware: Werkzeug
+ werkzeug.middleware.dispatcher: Werkzeug
+ werkzeug.middleware.http_proxy: Werkzeug
+ werkzeug.middleware.lint: Werkzeug
+ werkzeug.middleware.profiler: Werkzeug
+ werkzeug.middleware.proxy_fix: Werkzeug
+ werkzeug.middleware.shared_data: Werkzeug
+ werkzeug.routing: Werkzeug
+ werkzeug.routing.converters: Werkzeug
+ werkzeug.routing.exceptions: Werkzeug
+ werkzeug.routing.map: Werkzeug
+ werkzeug.routing.matcher: Werkzeug
+ werkzeug.routing.rules: Werkzeug
+ werkzeug.sansio: Werkzeug
+ werkzeug.sansio.http: Werkzeug
+ werkzeug.sansio.multipart: Werkzeug
+ werkzeug.sansio.request: Werkzeug
+ werkzeug.sansio.response: Werkzeug
+ werkzeug.sansio.utils: Werkzeug
+ werkzeug.security: Werkzeug
+ werkzeug.serving: Werkzeug
+ werkzeug.test: Werkzeug
+ werkzeug.testapp: Werkzeug
+ werkzeug.urls: Werkzeug
+ werkzeug.user_agent: Werkzeug
+ werkzeug.utils: Werkzeug
+ werkzeug.wrappers: Werkzeug
+ werkzeug.wrappers.request: Werkzeug
+ werkzeug.wrappers.response: Werkzeug
+ werkzeug.wsgi: Werkzeug
+ zipp: zipp
+ zipp.py310compat: zipp
+ pip_repository:
+ name: pip
+ use_pip_repository_aliases: true
+integrity: 030d6d99b56c32d6577e616b617260d0a93588af791269162e43391a5a4fa576
diff --git a/examples/build_file_generation/random_number_generator/BUILD.bazel b/examples/build_file_generation/random_number_generator/BUILD.bazel
new file mode 100644
index 0000000..95e16fd
--- /dev/null
+++ b/examples/build_file_generation/random_number_generator/BUILD.bazel
@@ -0,0 +1,19 @@
+load("@rules_python//python:defs.bzl", "py_library", "py_test")
+
+py_library(
+ name = "random_number_generator",
+ srcs = [
+ "__init__.py",
+ "generate_random_number.py",
+ ],
+ imports = [".."],
+ visibility = ["//:__subpackages__"],
+)
+
+py_test(
+ name = "random_number_generator_test",
+ srcs = ["__test__.py"],
+ imports = [".."],
+ main = "__test__.py",
+ deps = [":random_number_generator"],
+)
diff --git a/examples/build_file_generation/random_number_generator/__init__.py b/examples/build_file_generation/random_number_generator/__init__.py
new file mode 100644
index 0000000..bbdfb4c
--- /dev/null
+++ b/examples/build_file_generation/random_number_generator/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
diff --git a/examples/build_file_generation/random_number_generator/__test__.py b/examples/build_file_generation/random_number_generator/__test__.py
new file mode 100644
index 0000000..8cfb235
--- /dev/null
+++ b/examples/build_file_generation/random_number_generator/__test__.py
@@ -0,0 +1,25 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import random_number_generator.generate_random_number as generate_random_number
+
+class TestRandomNumberGenerator(unittest.TestCase):
+ def test_generate_random_number(self):
+ number = generate_random_number.generate_random_number()
+ self.assertGreaterEqual(number, 1)
+ self.assertLessEqual(number, 10)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/examples/build_file_generation/random_number_generator/generate_random_number.py b/examples/build_file_generation/random_number_generator/generate_random_number.py
new file mode 100644
index 0000000..e198b5b
--- /dev/null
+++ b/examples/build_file_generation/random_number_generator/generate_random_number.py
@@ -0,0 +1,19 @@
+# Copyright 2022 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import random
+
+"""Generate a random number"""
+def generate_random_number():
+ return random.randint(1, 10)
diff --git a/examples/build_file_generation/requirements.in b/examples/build_file_generation/requirements.in
new file mode 100644
index 0000000..7e10602
--- /dev/null
+++ b/examples/build_file_generation/requirements.in
@@ -0,0 +1 @@
+flask
diff --git a/examples/build_file_generation/requirements_lock.txt b/examples/build_file_generation/requirements_lock.txt
new file mode 100644
index 0000000..443db71
--- /dev/null
+++ b/examples/build_file_generation/requirements_lock.txt
@@ -0,0 +1,78 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+click==8.1.3 \
+ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
+ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
+ # via flask
+flask==2.2.2 \
+ --hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
+ --hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
+ # via -r requirements.in
+importlib-metadata==5.2.0 \
+ --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
+ --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
+ # via flask
+itsdangerous==2.1.2 \
+ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
+ --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
+ # via flask
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via flask
+markupsafe==2.1.1 \
+ --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
+ --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
+ --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
+ --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
+ --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
+ --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
+ --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
+ --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
+ --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
+ --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
+ --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
+ --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
+ --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
+ --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
+ --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
+ --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
+ --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
+ --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
+ --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
+ --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
+ --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
+ --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
+ --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
+ --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
+ --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
+ --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
+ --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
+ --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
+ --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
+ --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
+ --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
+ --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
+ --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
+ --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
+ --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
+ --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
+ --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
+ --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
+ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
+ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
+ # via
+ # jinja2
+ # werkzeug
+werkzeug==2.2.2 \
+ --hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
+ --hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
+ # via flask
+zipp==3.11.0 \
+ --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \
+ --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766
+ # via importlib-metadata
diff --git a/examples/build_file_generation/requirements_windows.txt b/examples/build_file_generation/requirements_windows.txt
new file mode 100644
index 0000000..bdd536f
--- /dev/null
+++ b/examples/build_file_generation/requirements_windows.txt
@@ -0,0 +1,82 @@
+#
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
+#
+# bazel run //:requirements.update
+#
+click==8.1.3 \
+ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \
+ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
+ # via flask
+colorama==0.4.6 \
+ --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
+ --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
+ # via click
+flask==2.2.2 \
+ --hash=sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b \
+ --hash=sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526
+ # via -r requirements.in
+importlib-metadata==5.2.0 \
+ --hash=sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f \
+ --hash=sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd
+ # via flask
+itsdangerous==2.1.2 \
+ --hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
+ --hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
+ # via flask
+jinja2==3.1.2 \
+ --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \
+ --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61
+ # via flask
+markupsafe==2.1.1 \
+ --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \
+ --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \
+ --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \
+ --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \
+ --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \
+ --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \
+ --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \
+ --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \
+ --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \
+ --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \
+ --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \
+ --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \
+ --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \
+ --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \
+ --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \
+ --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \
+ --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \
+ --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \
+ --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \
+ --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \
+ --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \
+ --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \
+ --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \
+ --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \
+ --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \
+ --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \
+ --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \
+ --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \
+ --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \
+ --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \
+ --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \
+ --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \
+ --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \
+ --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \
+ --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \
+ --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \
+ --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \
+ --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \
+ --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \
+ --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7
+ # via
+ # jinja2
+ # werkzeug
+werkzeug==2.2.2 \
+ --hash=sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f \
+ --hash=sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5
+ # via flask
+zipp==3.11.0 \
+ --hash=sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa \
+ --hash=sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766
+ # via importlib-metadata