Skip to content

Commit

Permalink
Add support for no parent directory inference (#832) (#834)
Browse files Browse the repository at this point in the history
Add feature as described in #832.

RELNOTES: Automatic creation of parent directory specifications for
paths with depth can be prevented in `pkg_tar` archives by setting `create_parents=False`.
  • Loading branch information
eejayes authored Mar 21, 2024
1 parent 20100ce commit a0eb69a
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 15 deletions.
3 changes: 2 additions & 1 deletion docs/latest.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ pkg_tar(<a href="#pkg_tar-name">name</a>, <a href="#pkg_tar-allow_duplicates_wit
<a href="#pkg_tar-empty_dirs">empty_dirs</a>, <a href="#pkg_tar-empty_files">empty_files</a>, <a href="#pkg_tar-extension">extension</a>, <a href="#pkg_tar-files">files</a>, <a href="#pkg_tar-include_runfiles">include_runfiles</a>, <a href="#pkg_tar-mode">mode</a>, <a href="#pkg_tar-modes">modes</a>, <a href="#pkg_tar-mtime">mtime</a>, <a href="#pkg_tar-out">out</a>,
<a href="#pkg_tar-owner">owner</a>, <a href="#pkg_tar-ownername">ownername</a>, <a href="#pkg_tar-ownernames">ownernames</a>, <a href="#pkg_tar-owners">owners</a>, <a href="#pkg_tar-package_dir">package_dir</a>, <a href="#pkg_tar-package_dir_file">package_dir_file</a>, <a href="#pkg_tar-package_file_name">package_file_name</a>,
<a href="#pkg_tar-package_variables">package_variables</a>, <a href="#pkg_tar-portable_mtime">portable_mtime</a>, <a href="#pkg_tar-private_stamp_detect">private_stamp_detect</a>, <a href="#pkg_tar-remap_paths">remap_paths</a>, <a href="#pkg_tar-srcs">srcs</a>, <a href="#pkg_tar-stamp">stamp</a>,
<a href="#pkg_tar-strip_prefix">strip_prefix</a>, <a href="#pkg_tar-symlinks">symlinks</a>)
<a href="#pkg_tar-strip_prefix">strip_prefix</a>, <a href="#pkg_tar-symlinks">symlinks</a>, <a href="#pkg_tar-create_parents">symlinks</a>)
</pre>


Expand Down Expand Up @@ -326,6 +326,7 @@ pkg_tar(<a href="#pkg_tar-name">name</a>, <a href="#pkg_tar-allow_duplicates_wit
| <a id="pkg_tar-stamp"></a>stamp | Enable file time stamping. Possible values: <li>stamp = 1: Use the time of the build as the modification time of each file in the archive. <li>stamp = 0: Use an "epoch" time for the modification time of each file. This gives good build result caching. <li>stamp = -1: Control the chosen modification time using the --[no]stamp flag. <div class="since"><i>Since 0.5.0</i></div> | Integer | optional | 0 |
| <a id="pkg_tar-strip_prefix"></a>strip_prefix | (note: Use strip_prefix = "." to strip path to the package but preserve relative paths of sub directories beneath the package.) | String | optional | "" |
| <a id="pkg_tar-symlinks"></a>symlinks | - | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
| <a id="pkg_tar-create_parents"></a>create_parents | Implicitly create parent directories with default permissions for file paths where parent directories are not specified. | Boolean | optional | True |



Expand Down
11 changes: 9 additions & 2 deletions pkg/private/tar/build_tar.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,22 @@ class TarFile(object):
class DebError(Exception):
pass

def __init__(self, output, directory, compression, compressor, default_mtime):
def __init__(self, output, directory, compression, compressor, create_parents, default_mtime):
# Directory prefix on all output paths
d = directory.strip('/')
self.directory = (d + '/') if d else None
self.output = output
self.compression = compression
self.compressor = compressor
self.default_mtime = default_mtime
self.create_parents = create_parents

def __enter__(self):
self.tarfile = tar_writer.TarFileWriter(
self.output,
self.compression,
self.compressor,
self.create_parents,
default_mtime=self.default_mtime)
return self

Expand Down Expand Up @@ -383,6 +385,10 @@ def main():
'path/to/file=root.root.')
parser.add_argument('--stamp_from', default='',
help='File to find BUILD_STAMP in')
parser.add_argument('--create_parents',
action='store_true',
help='Automatically creates parent directories implied by a'
' prefix if they do not exist')
options = parser.parse_args()

# Parse modes arguments
Expand Down Expand Up @@ -432,7 +438,8 @@ def main():
directory = helpers.GetFlagValue(options.directory),
compression = options.compression,
compressor = options.compressor,
default_mtime=default_mtime) as output:
default_mtime=default_mtime,
create_parents=options.create_parents) as output:

def file_attributes(filename):
if filename.startswith('/'):
Expand Down
4 changes: 4 additions & 0 deletions pkg/private/tar/tar.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ def _pkg_tar_impl(ctx):
args.set_param_file_format("flag_per_line")
args.use_param_file("@%s", use_always = False)

if ctx.attr.create_parents:
args.add("--create_parents")

inputs = depset(
direct = ctx.files.deps + files,
transitive = mapping_context.file_deps,
Expand Down Expand Up @@ -264,6 +267,7 @@ pkg_tar_impl = rule(
"compressor_args": attr.string(
doc = """Arg list for `compressor`.""",
),
"create_parents": attr.bool(default = True),

# Common attributes
"out": attr.output(mandatory = True),
Expand Down
22 changes: 13 additions & 9 deletions pkg/private/tar/tar_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def __init__(self,
name,
compression='',
compressor='',
create_parents=False,
default_mtime=None,
preserve_tar_mtimes=True):
"""TarFileWriter wraps tarfile.open().
Expand Down Expand Up @@ -106,6 +107,7 @@ def __init__(self,
# we can adjust that here based on the setting of root_dirctory.
self.directories.add('/')
self.directories.add('./')
self.create_parents = create_parents

def __enter__(self):
return self
Expand Down Expand Up @@ -219,7 +221,8 @@ def add_file(self,
mtime = self.default_mtime

# Make directories up the file
self.add_parents(name, mtime=mtime, mode=0o755, uid=uid, gid=gid, uname=uname, gname=gname)
if self.create_parents:
self.add_parents(name, mtime=mtime, mode=0o755, uid=uid, gid=gid, uname=uname, gname=gname)

tarinfo = tarfile.TarInfo(name)
tarinfo.mtime = mtime
Expand Down Expand Up @@ -291,14 +294,15 @@ def add_tar(self,
if prefix:
in_name = os.path.normpath(prefix + in_name).replace(os.path.sep, '/')
tarinfo.name = in_name
self.add_parents(
path=tarinfo.name,
mtime=tarinfo.mtime,
mode=0o755,
uid=tarinfo.uid,
gid=tarinfo.gid,
uname=tarinfo.uname,
gname=tarinfo.gname)
if self.create_parents:
self.add_parents(
path=tarinfo.name,
mtime=tarinfo.mtime,
mode=0o755,
uid=tarinfo.uid,
gid=tarinfo.gid,
uname=tarinfo.uname,
gname=tarinfo.gname)

if prefix is not None:
# Relocate internal hardlinks as well to avoid breaking them.
Expand Down
19 changes: 16 additions & 3 deletions tests/tar/tar_writer_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def testMergeTarRelocated(self):
{"name": "foo/a", "data": b"a"},
{"name": "foo/ab", "data": b"ab"},
]
with tar_writer.TarFileWriter(self.tempfile) as f:
with tar_writer.TarFileWriter(self.tempfile, create_parents=True) as f:
datafile = self.data_files.Rlocation(
"rules_pkg/tests/testdata/tar_test.tar")
f.add_tar(datafile, name_filter=lambda n: n != "./b", prefix="foo")
Expand Down Expand Up @@ -176,7 +176,7 @@ def testPreserveTarMtimesFalse(self):
self.assertEqual(output_file.mtime, 0)

def testAddingDirectoriesForFile(self):
with tar_writer.TarFileWriter(self.tempfile) as f:
with tar_writer.TarFileWriter(self.tempfile, create_parents=True) as f:
f.add_file("d/f")
content = [
{"name": "d", "mode": 0o755},
Expand All @@ -185,7 +185,7 @@ def testAddingDirectoriesForFile(self):
self.assertTarFileContent(self.tempfile, content)

def testAddingDirectoriesForFileManually(self):
with tar_writer.TarFileWriter(self.tempfile) as f:
with tar_writer.TarFileWriter(self.tempfile, create_parents=True) as f:
f.add_file("d", tarfile.DIRTYPE)
f.add_file("d/f")

Expand All @@ -210,6 +210,19 @@ def testAddingDirectoriesForFileManually(self):
]
self.assertTarFileContent(self.tempfile, content)

def testAddingOnlySpecifiedFiles(self):
with tar_writer.TarFileWriter(self.tempfile) as f:
f.add_file("a", tarfile.DIRTYPE)
f.add_file("a/b", tarfile.DIRTYPE)
f.add_file("a/b/", tarfile.DIRTYPE)
f.add_file("a/b/c/f")
content = [
{"name": "a", "mode": 0o755},
{"name": "a/b", "mode": 0o755},
{"name": "a/b/c/f"},
]
self.assertTarFileContent(self.tempfile, content)

def testPackageDirAttribute(self):
"""Tests package_dir of pkg_tar."""
package_dir = self.data_files.Rlocation(
Expand Down

0 comments on commit a0eb69a

Please sign in to comment.