Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create empty workspace directory to fix using python deps as layers #747

Merged
merged 10 commits into from
Mar 21, 2019
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion container/image_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def test_with_stamped_creation_time(self):
# Assume that any value for 'created' within a reasonable bound is fine.
self.assertLessEqual(now - created, datetime.timedelta(minutes=15))

# This test is flaky. If it fails, do a bazel clean --expunge_async and try again
# This test is flaky. If it fails, do a bazel clean --expunge_async and try again
def test_with_default_stamped_creation_time(self):
# {BUILD_TIMESTAMP} should be the default when `stamp = True` and
# `creation_time` isn't explicitly defined.
Expand Down Expand Up @@ -473,6 +473,7 @@ def test_py_image(self):
'./app/testdata/py_image.binary.runfiles/io_bazel_rules_docker/testdata/py_image.binary',
'./app/testdata/py_image.binary.runfiles/io_bazel_rules_docker/testdata/BUILD',
'./app/testdata/py_image.binary.runfiles/io_bazel_rules_docker/testdata/__init__.py',
'./app/io_bazel_rules_docker',
# TODO(mattmoor): The path normalization for symlinks should match
# files to avoid this redundancy.
'/app',
Expand Down Expand Up @@ -517,6 +518,7 @@ def test_py_image_with_symlinks_in_data(self):
'./app/testdata/py_image_with_symlinks_in_data.binary.runfiles/io_bazel_rules_docker/testdata/py_image_with_symlinks_in_data.binary',
'./app/testdata/py_image_with_symlinks_in_data.binary.runfiles/io_bazel_rules_docker/testdata/foo.txt',
'./app/testdata/py_image_with_symlinks_in_data.binary.runfiles/io_bazel_rules_docker/testdata/__init__.py',
'./app/io_bazel_rules_docker',
# TODO(mattmoor): The path normalization for symlinks should match
# files to avoid this redundancy.
'/app',
Expand Down Expand Up @@ -568,6 +570,7 @@ def test_py_image_complex(self):
'./app/testdata/py_image_complex.binary.runfiles/pypi__addict_2_1_2',
'./app/testdata/py_image_complex.binary.runfiles/pypi__addict_2_1_2/__init__.py',
'./app/testdata/py_image_complex.binary.runfiles/io_bazel_rules_docker/testdata/__init__.py',
'./app/io_bazel_rules_docker',
'/app',
'/app/testdata',
'/app/testdata/py_image_complex.binary',
Expand Down
3 changes: 3 additions & 0 deletions java/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ jar_dep_layer = rule(

# The binary target for which we are synthesizing an image.
"binary": attr.label(mandatory = False),
# Set this to true to create an empty workspace directory under the
# app directory specified as the 'directory' attribute.
"create_empty_workspace_dir": attr.bool(default = False),
# https://github.com/bazelbuild/bazel/issues/2176
"data_path": attr.string(default = "."),
# The dependency whose runfiles we're appending.
Expand Down
9 changes: 9 additions & 0 deletions lang/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def app_layer_impl(ctx, runfiles = None, emptyfiles = None):

runfiles = runfiles or _default_runfiles
emptyfiles = emptyfiles or _default_emptyfiles
empty_dirs = []
workdir = None

parent_parts = _get_layers(ctx, ctx.attr.name, ctx.attr.base)
Expand All @@ -146,6 +147,10 @@ def app_layer_impl(ctx, runfiles = None, emptyfiles = None):
dep = ctx.attr.dep or ctx.attr.binary
top_layer = ctx.attr.binary and not ctx.attr.dep

if ctx.attr.create_empty_workspace_dir:
# Create an empty directory for the workspace in the app directory.
empty_dirs.append("/".join([ctx.attr.directory, ctx.workspace_name]))

# Compute the set of runfiles that have been made available
# in our base image, tracking absolute paths.
available = {
Expand Down Expand Up @@ -215,6 +220,7 @@ def app_layer_impl(ctx, runfiles = None, emptyfiles = None):
directory = "/",
file_map = file_map,
empty_files = empty_files,
empty_dirs = empty_dirs,
symlinks = symlinks,
workdir = workdir,
# Use entrypoint so we can easily add arguments when the resulting
Expand Down Expand Up @@ -242,6 +248,9 @@ _app_layer = rule(
executable = True,
cfg = "target",
),
# Set this to true to create an empty workspace directory under the
# app directory specified as the 'directory' attribute.
"create_empty_workspace_dir": attr.bool(default = False),
"data": attr.label_list(allow_files = True),

# Override the defaults.
Expand Down
3 changes: 3 additions & 0 deletions nodejs/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ _dep_layer = rule(

# The binary target for which we are synthesizing an image.
"binary": attr.label(mandatory = False),
# Set this to true to create an empty workspace directory under the
# app directory specified as the 'directory' attribute.
"create_empty_workspace_dir": attr.bool(default = False),

# Override the defaults.
# https://github.com/bazelbuild/bazel/issues/2176
Expand Down
6 changes: 5 additions & 1 deletion python/image.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ def py_image(name, base = None, deps = [], layers = [], **kwargs):
for index, dep in enumerate(layers):
base = app_layer(name = "%s.%d" % (name, index), base = base, dep = dep)
base = app_layer(name = "%s.%d-symlinks" % (name, index), base = base, dep = dep, binary = binary_name)

visibility = kwargs.get("visibility", None)
tags = kwargs.get("tags", None)
app_layer(
Expand All @@ -108,4 +107,9 @@ def py_image(name, base = None, deps = [], layers = [], **kwargs):
args = kwargs.get("args"),
data = kwargs.get("data"),
testonly = kwargs.get("testonly"),
# The targets of the symlinks in the symlink layers are relative to the
# workspace directory under the app directory. Thus, create an empty
# workspace directory to ensure the symlinks are valid. See
# https://github.com/bazelbuild/rules_docker/issues/161 for details.
create_empty_workspace_dir = True,
)
11 changes: 10 additions & 1 deletion testdata/test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

load("@pip_deps//:requirements.bzl", "requirement")
load("@io_bazel_rules_docker//python:image.bzl", "py_image")
load("@pip_deps//:requirements.bzl", "all_requirements", "requirement")

package(default_visibility = ["//testdata:__subpackages__"])

Expand All @@ -31,3 +32,11 @@ py_library(
srcs = ["py_image_library_using_addict.py"],
deps = [requirement("addict")],
)

# For end to end testing of py_image dependencies specified as "layers"
py_image(
name = "py_image_using_layers",
srcs = ["py_image_using_layers.py"],
layers = all_requirements,
main = "py_image_using_layers.py",
)
10 changes: 10 additions & 0 deletions testdata/test/py_image_using_layers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Ensure the "six" module can be imported.

Used to end to end test python dependencies to py_image work when specified
as layers. https://github.com/bazelbuild/rules_docker/issues/161
"""

import six

if __name__ == "__main__":
print("Successfully imported {} {}.".format(six.__name__, six.__version__))
14 changes: 13 additions & 1 deletion testing/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,10 @@ EOF


function clear_docker() {
docker rmi -f $(docker images -aq) || true
# Get the IDs of images except the local registry image "registry:2". We only
# want to delete images that were created in the tests.
images=$(docker images -a --format "{{.ID}} {{.Repository}}:{{.Tag}}" | grep -v "registry:2" | cut -d' ' -f1)
docker rmi -f $images || builtin true
stop_containers
}

Expand Down Expand Up @@ -530,6 +533,15 @@ function test_dockerfile_image_basic() {
bazel test tests/docker:basic_dockerfile_image
}

function test_py_image_deps_as_layers() {
cd "${ROOT}"
clear_docker
# Build and run the python image where the "six" module pip dependency was
# specified via "layers". https://github.com/bazelbuild/rules_docker/issues/161
EXPECT_CONTAINS "$(bazel run testdata/test:py_image_using_layers)" "Successfully imported six 1.11.0"
}

test_py_image_deps_as_layers
test_container_push_with_stamp
test_container_push_all
test_container_push_with_auth
Expand Down