summaryrefslogtreecommitdiff
path: root/kleaf/directory_with_structure.bzl
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2022-04-05 22:27:05 -0700
committerYifan Hong <elsk@google.com>2022-04-20 05:31:37 +0000
commitaddad5dd7075ffbe631cac98b97a621e3f1e2958 (patch)
tree87382d4abd2a6c2a73f91d9350bd9242608af9ca /kleaf/directory_with_structure.bzl
parentfcc476ee4fe5cf6e51da9b34e3e892bc224b0bb1 (diff)
downloadbuild-addad5dd7075ffbe631cac98b97a621e3f1e2958.tar.gz
kleaf: Add directory_with_structure.
This is a "class" that aims to replace tarballs with declare_directory. However, the problem with declare_directory is that, empty directories and subdirectories are not symlinked in the sandbox. To fix this problem, the "class" declares another text file that stores the directory structure, and recovers it upon request. Test: TH Bug: 226673718 Change-Id: I26868d60bd311a4195c11b313f322845bcf9dcda
Diffstat (limited to 'kleaf/directory_with_structure.bzl')
-rw-r--r--kleaf/directory_with_structure.bzl102
1 files changed, 102 insertions, 0 deletions
diff --git a/kleaf/directory_with_structure.bzl b/kleaf/directory_with_structure.bzl
new file mode 100644
index 0000000..87d7696
--- /dev/null
+++ b/kleaf/directory_with_structure.bzl
@@ -0,0 +1,102 @@
+# Copyright (C) 2022 The Android Open Source Project
+#
+# 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.
+
+# When a directory created dy ctx.actions.declare_directory is referred to
+# in a sandbox, if it is empty, or a subdirectory of it is empty, the empty
+# directory won't be created in the sandbox.
+# These functions resolve the problem by also recording the directory structure
+# in a text file.
+
+def _make(ctx, filename):
+ """The replacement of [ctx.actions.declare_directory](https://bazel.build/rules/lib/actions#declare_directory) that also preserves empty directories.
+
+ Return a struct with the following fields:
+ - `directory`: A [File](https://bazel.build/rules/lib/File) object from
+ [ctx.actions.declare_directory](https://bazel.build/rules/lib/actions#declare_directory).
+ - `structure_file`: A [File](https://bazel.build/rules/lib/File) object that will the
+ directory structure.
+
+ Args:
+ filename: See [ctx.actions.declare_directory](https://bazel.build/rules/lib/actions#declare_directory).
+ """
+ directory = ctx.actions.declare_directory(filename)
+ structure_file = ctx.actions.declare_file(filename + ".structure.txt")
+ return struct(directory = directory, structure_file = structure_file)
+
+def _record(directory_with_structure):
+ """Return a command that records the directory structure to the `structure_file`.
+
+ It is expected that the shell has properly set up [hermetic tools](#hermetic_tools).
+
+ Args:
+ directory_with_structure: struct returned by `[directory_with_structure.declare](#directory_with_structuredeclare)`.
+ """
+ return """
+ mkdir -p {structure_file_dir}
+ : > {structure_file}
+ (
+ real_structure_file=$(readlink -e {structure_file})
+ cd {directory}
+ find . -type d > $real_structure_file
+ )
+ """.format(
+ structure_file_dir = directory_with_structure.structure_file.dirname,
+ directory = directory_with_structure.directory.path,
+ structure_file = directory_with_structure.structure_file.path,
+ )
+
+def _files(directory_with_structure):
+ """Return the list of declared [File](https://bazel.build/rules/lib/File) objects in a `directory_with_structure`."""
+ return [
+ directory_with_structure.directory,
+ directory_with_structure.structure_file,
+ ]
+
+def _restore(
+ directory_with_structure,
+ dst,
+ options = None):
+ """Return a command that restores a `directory_with_structure`.
+
+ It is expected that the shell has properly set up [hermetic tools](#hermetic_tools).
+
+ Args:
+ directory_with_structure: struct returned by `declare_directory_with_structure`.
+ dest: a string containing the path to the destination directory.
+ options: a string containing options to `rsync`. If `None`, default to `"-a"`.
+ """
+
+ if options == None:
+ options = "-a"
+
+ return """
+ cat {structure_file} | sed 's:^:{dst}/:' | xargs mkdir -p
+ rsync {options} {src}/ {dst}/
+ """.format(
+ structure_file = directory_with_structure.structure_file.path,
+ options = options,
+ src = directory_with_structure.directory.path,
+ dst = dst,
+ )
+
+def _isinstance(obj):
+ return hasattr(obj, "directory") and hasattr(obj, "structure_file")
+
+directory_with_structure = struct(
+ make = _make,
+ record = _record,
+ files = _files,
+ restore = _restore,
+ isinstance = _isinstance,
+)