diff --git a/README.md b/README.md index 5fee54d..ac1162e 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,76 @@ Repo for learning Bazel +## Basics + +https://bazel.build/start/bazel-intro + +Rules are defined in a DSL called [Starlark](https://bazel.build/rules/language) + +- A WORKSPACE is a hierarchy of directories + - Contains Packages + - Contains source files + - Denoted by a one BUILD file. + - Build files contain Rules + - Targets: Identified by labels. + - Labels + - Sub directories containing a BUILD file are different packages. A file can only belong to one package. + - Ignores sub dirs that contain another workspace + +## Builds + +https://bazel.build/concepts/build-ref + +### Workspaces + +Alias `@` + +Denoted by WORKSPACE or WORKSPACE.bazel file. Subdirectories under the Workspace that contain a WORKSPACE are ignored as they are considered different workspaces. + +External repositoies are defined in the WORKSPACE using workspace rules + +### Packages + +The primary unit of code organization in a repository is the package. A package is a collection of related files and a specification of how they can be used to produce output artifacts. + +A package is defined as a directory containing a file named BUILD (or BUILD.bazel). A package includes all files in its directory, plus all subdirectories beneath it, except those which themselves contain a BUILD file. From this definition, no file or directory may be a part of two different packages. + +### Targets + +A package is a container of targets, which are defined in the package's BUILD file. Most targets are one of two principal kinds, files and rules. + +Files are further divided into two kinds. Source files are usually written by the efforts of people, and checked in to the repository. Generated files, sometimes called derived files or output files, are not checked in, but are generated from source files. + +The second kind of target is declared with a rule. Each rule instance specifies the relationship between a set of input and a set of output files. The inputs to a rule may be source files, but they also may be the outputs of other rules. + +All targets belong to exactly one package. The name of a target is called its [label](https://bazel.build/concepts/labels). Every label uniquely identifies a target. A typical label in canonical form looks like: + +``` +@myrepo//my/app/main:app_binary +``` + +### Build rules + +A build rule specifies the build tools Bazel will use, such as compilers and linkers, and their configurations. Bazel ships with a number of build rules covering the most common artifact types in the supported languages on supported platforms. + ## Commands From top level dir -Build all packages(Denoted by BUILD.bazel files) in this project. +Build all packages(Denoted by BUILD.bazel files) in this project. `...` refers to all targets + +Targets all Build files: ``` bazel build //... ``` + +Building just the `c_project` but using it's package's label + +``` +bazel build //c_project/... +``` + +# Python Builds + +https://bazel.build/reference/be/python diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index e69de29..fa2de84 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -0,0 +1,24 @@ +# https://github.com/bazelbuild/rules_python#Migrating-from-the-bundled-rules + +# We will use the future interface for Python Rules in Bazel I am not focusing on +# a hermetic build yet. + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "rules_python", + sha256 = "9fcf91dbcc31fde6d1edb15f117246d912c33c36f44cf681976bd886538deba6", + strip_prefix = "rules_python-0.8.0", + url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.8.0.tar.gz", +) + +# PIP STUFFS https://github.com/bazelbuild/rules_python#using-the-packaging-rules + +load("@rules_python//python:pip.bzl", "pip_install") + +# Create a central external repo, @my_deps, that contains Bazel targets for all the +# third-party packages specified in the requirements.txt file. +pip_install( + name = "my_py_app_deps", + requirements = "//third_party_py:requirements.txt", +) diff --git a/c_project/BUILD.bazel b/c_project/BUILD.bazel new file mode 100644 index 0000000..e69de29 diff --git a/c_project/hello.c b/c_project/hello.c new file mode 100644 index 0000000..6cad9b2 --- /dev/null +++ b/c_project/hello.c @@ -0,0 +1,8 @@ +#import +int main() +{ + char name[10] = "Laura"; + + printf("Hello %s!\n", name); + return 0; +} \ No newline at end of file diff --git a/gen_package/BUILD.bazel b/gen_package/BUILD.bazel new file mode 100644 index 0000000..0fea6b2 --- /dev/null +++ b/gen_package/BUILD.bazel @@ -0,0 +1,14 @@ +genrule( + name = "foo", + srcs = [], + outs = ["foo.txt"], + cmd = "sleep 3 && echo 'Hello Bazel!' > $@ ", +) + +# This is a comment? +genrule( + name = "bar", + srcs = [], + outs = ["bar.txt"], + cmd = "printenv > $@ ", +) diff --git a/gen_package/README.md b/gen_package/README.md new file mode 100644 index 0000000..fce9871 --- /dev/null +++ b/gen_package/README.md @@ -0,0 +1,13 @@ +Just an example of a Rule producing a file. + +https://bazel.build/reference/be/general#genrule + +See also: https://bazel.build/reference/be/make-variables + +``` +bazel build //gen_package:foo +``` + +``` +bazel build //gen_package:foo +``` diff --git a/ignored_workspace/README.md b/ignored_workspace/README.md new file mode 100644 index 0000000..6e74d83 --- /dev/null +++ b/ignored_workspace/README.md @@ -0,0 +1,5 @@ +This entire workspace should be ignored by the workspace at this git repo root. + +This means this entire tree can be committed to our version control system without it and it's containing packages from being reviewed by the workspace in the repo root. + +As far as I can tell if you want to use this sub workspace you have to cd to this dir. diff --git a/ignored_workspace/WORKSPACE.bazel b/ignored_workspace/WORKSPACE.bazel new file mode 100644 index 0000000..e69de29 diff --git a/ignored_workspace/another_fake_pgk/BUILD.bazel b/ignored_workspace/another_fake_pgk/BUILD.bazel new file mode 100644 index 0000000..e69de29 diff --git a/ignored_workspace/fake_pgk/BUILD.bazel b/ignored_workspace/fake_pgk/BUILD.bazel new file mode 100644 index 0000000..e69de29 diff --git a/my_py_app/BUILD.bazel b/my_py_app/BUILD.bazel new file mode 100644 index 0000000..aa33a1f --- /dev/null +++ b/my_py_app/BUILD.bazel @@ -0,0 +1,11 @@ +# Load Deps +load("@my_py_app_deps//:requirements.bzl", "requirement") + +py_binary( + name = "main", + srcs = ["main.py"], + deps = [ + "//py_project:calculator", + requirement("Flask"), + ], +) diff --git a/my_py_app/README.md b/my_py_app/README.md new file mode 100644 index 0000000..c39bc5f --- /dev/null +++ b/my_py_app/README.md @@ -0,0 +1,19 @@ +This app is a simple flask application. It specifies Flask as a dependency which is provided in the `third_party_py` package at the root of our workspace. We also rely on `py_project:calculator` target. This is possible because we have set the visibility for this project `py_library` to public. + +In the `WORKSPACE` file we have specified an `external` repo called `my_py_app_deps` this is where all of our pip installed libs +will be downloaded, and converted into Bazel packages automatically. + +``` +drewbednar@MacBook-Pro learn_bazel % ls ./bazel-learn_bazel/external/my_py_app_deps +BUILD.bazel pypi__click pypi__itsdangerous pypi__werkzeug +WORKSPACE pypi__flask pypi__jinja2 pypi__zipp +annotations.json pypi__importlib_metadata pypi__markupsafe requirements.bzl +``` + +## Executing + +You can run the built Flask app with: + +``` +FLASK_ENV="development" bazel run my_py_app:main +``` diff --git a/my_py_app/main.py b/my_py_app/main.py new file mode 100644 index 0000000..b2143bc --- /dev/null +++ b/my_py_app/main.py @@ -0,0 +1,20 @@ +from flask import Flask +from random import randint + +from py_project.calculator import Calculator + +app = Flask(__name__) +my_calculator = Calculator() + + +@app.route("/") +def index(): + num1 = randint(0, 100) + num2 = randint(0, 100) + _sum = my_calculator.add(num1, num2) + message = f" {num1} + {num2} = {_sum}" + return message + + +if __name__ == "__main__": + app.run() diff --git a/py_project/BUILD.bazel b/py_project/BUILD.bazel index e69de29..1db3ee1 100644 --- a/py_project/BUILD.bazel +++ b/py_project/BUILD.bazel @@ -0,0 +1,15 @@ +py_library( + name = "calculator", + srcs = ["calculator.py"], + # visibility + visibility = ["//visibility:public"], +) + +py_test( + name = "calculator_test", + srcs = ["calculator_test.py"], + deps = [ + # These are dependencies spelled out as targets? + "//py_project:calculator", + ], +) diff --git a/py_project/README.md b/py_project/README.md new file mode 100644 index 0000000..38050b0 --- /dev/null +++ b/py_project/README.md @@ -0,0 +1,9 @@ +# Pyproject + +This package gives us two targets `calculator` and `calculator_test`. + +## Tests + +``` +bazel test py_project/... +``` diff --git a/py_project/calculator.py b/py_project/calculator.py new file mode 100644 index 0000000..1f9d5c2 --- /dev/null +++ b/py_project/calculator.py @@ -0,0 +1,3 @@ +class Calculator: + def add(self, x, y): + return x+y diff --git a/py_project/calculator_test.py b/py_project/calculator_test.py new file mode 100644 index 0000000..06051cd --- /dev/null +++ b/py_project/calculator_test.py @@ -0,0 +1,17 @@ +from calendar import c +import unittest +from py_project.calculator import Calculator + + +class TestCalculator(unittest.TestCase): + def test_sum(self): + calc = Calculator() + self.assertEqual(calc.add(3, 4), 7) + + # def test_sub(self): + # calc = Calculator() + # self.assertEqual(calc.sub(4, 2), 2) + + +if __name__ == "__main__": + unittest.main() diff --git a/third_party_py/BUILD.bazel b/third_party_py/BUILD.bazel new file mode 100644 index 0000000..e69de29 diff --git a/third_party_py/requirements.txt b/third_party_py/requirements.txt new file mode 100644 index 0000000..de8ecac --- /dev/null +++ b/third_party_py/requirements.txt @@ -0,0 +1 @@ +Flask==2.1.1 \ No newline at end of file