summaryrefslogtreecommitdiff
path: root/pkg/private/pkg_files.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/private/pkg_files.bzl')
-rw-r--r--pkg/private/pkg_files.bzl397
1 files changed, 238 insertions, 159 deletions
diff --git a/pkg/private/pkg_files.bzl b/pkg/private/pkg_files.bzl
index f0fe60b..6fc0971 100644
--- a/pkg/private/pkg_files.bzl
+++ b/pkg/private/pkg_files.bzl
@@ -34,7 +34,6 @@ Concepts and terms:
load("//pkg:path.bzl", "compute_data_path", "dest_path")
load(
"//pkg:providers.bzl",
- "PackageArtifactInfo",
"PackageDirsInfo",
"PackageFilegroupInfo",
"PackageFilesInfo",
@@ -44,9 +43,10 @@ load(
ENTRY_IS_FILE = "file" # Entry is a file: take content from <src>
ENTRY_IS_LINK = "symlink" # Entry is a symlink: dest -> <src>
ENTRY_IS_DIR = "dir" # Entry is an empty dir
-ENTRY_IS_TREE = "tree" # Entry is a tree artifact: take tree from <src>
+ENTRY_IS_TREE = "tree" # Entry is a tree artifact: take tree from <src>
ENTRY_IS_EMPTY_FILE = "empty-file" # Entry is a an empty file
+# buildifier: disable=name-conventions
_DestFile = provider(
doc = """Information about each destination in the final package.""",
fields = {
@@ -57,10 +57,79 @@ _DestFile = provider(
"link_to": "path to link to. src must not be set",
"entry_type": "string. See ENTRY_IS_* values above.",
"origin": "target which added this",
+ "uid": "uid, or empty",
+ "gid": "gid, or empty",
},
)
-def _check_dest(content_map, dest, src, origin):
+# buildifier: disable=name-conventions
+_MappingContext = provider(
+ doc = """Fields passed to process_* methods.""",
+ fields = {
+ "content_map": "in/out The content_map we are building up",
+ "file_deps": "in/out list of file Depsets represented in the map",
+ "label": "ctx.label",
+
+ # Behaviors
+ "allow_duplicates_with_different_content": "bool: don't fail when you double mapped files",
+ "include_runfiles": "bool: include runfiles",
+ "strip_prefix": "strip_prefix",
+
+ "path_mapper": "function to map destination paths",
+
+ # Defaults
+ "default_mode": "Default mode to apply to file without a mode setting",
+ "default_user": "Default user name to apply to file without a user",
+ "default_group": "Default group name to apply to file without a group",
+ "default_uid": "Default numeric uid to apply to file without a uid",
+ "default_gid": "Default numeric gid to apply to file without a gid",
+ },
+)
+
+# buildifier: disable=function-docstring-args
+def create_mapping_context_from_ctx(
+ ctx,
+ label,
+ allow_duplicates_with_different_content = None,
+ strip_prefix = None,
+ include_runfiles = None,
+ default_mode = None,
+ path_mapper = None
+ ):
+ """Construct a MappingContext.
+
+ Args: See the provider definition.
+
+ Returns:
+ _MappingContext
+ """
+ if allow_duplicates_with_different_content == None:
+ allow_duplicates_with_different_content = ctx.attr.allow_duplicates_with_different_content if hasattr(ctx.attr, "allow_duplicates_with_different_content") else False
+ if strip_prefix == None:
+ strip_prefix = ctx.attr.strip_prefix if hasattr(ctx.attr, "strip_prefix") else ""
+ if include_runfiles == None:
+ include_runfiles = ctx.attr.include_runfiles if hasattr(ctx.attr, "include_runfiles") else False
+ if default_mode == None:
+ default_mode = ctx.attr.mode if hasattr(ctx.attr, "default_mode") else ""
+
+ return _MappingContext(
+ content_map = dict(),
+ file_deps = list(),
+ label = label,
+ allow_duplicates_with_different_content = allow_duplicates_with_different_content,
+ strip_prefix = strip_prefix,
+ include_runfiles = include_runfiles,
+ default_mode = default_mode,
+ path_mapper = path_mapper or (lambda x: x),
+ # TODO(aiuto): allow these to be passed in as needed. But, before doing
+ # that, explore defauilt_uid/gid as 0 rather than None
+ default_user = "",
+ default_group = "",
+ default_uid = None,
+ default_gid = None,
+ )
+
+def _check_dest(content_map, dest, src, origin, allow_duplicates_with_different_content = False):
old_entry = content_map.get(dest)
if not old_entry:
return
@@ -72,96 +141,116 @@ def _check_dest(content_map, dest, src, origin):
# people specify the owner in one place, but another overly broad glob
# brings in the file with a different owner.
if old_entry.src.path != src.path:
- # buildifier: disable=print
- print(
- "Duplicate output path: <%s>, declared in %s and %s" % (
- dest,
- origin,
- content_map[dest].origin,
- ),
- "\n SRC:",
+ msg = "Duplicate output path: <%s>, declared in %s and %s\n SRC: %s" % (
+ dest,
+ origin,
+ content_map[dest].origin,
src,
)
+ if allow_duplicates_with_different_content:
+ # buildifier: disable=print
+ print("WARNING:", msg)
+ else:
+ # When we default to this behaviour, we should consider telling
+ # users the attribute to set to deal with this.
+ # For now though, let's not, since they've explicitly opted in.
+ fail(msg)
-def _merge_attributes(info, mode, user, group):
+def _merge_attributes(info, mode, user, group, uid, gid):
if hasattr(info, "attributes"):
attrs = info.attributes
mode = attrs.get("mode") or mode
user = attrs.get("user") or user
group = attrs.get("group") or group
- return (mode, user, group)
-def _process_pkg_dirs(content_map, pkg_dirs_info, origin, default_mode, default_user, default_group):
- attrs = _merge_attributes(pkg_dirs_info, default_mode, default_user, default_group)
+ new_uid = attrs.get("uid")
+ if new_uid != None:
+ uid = new_uid
+ new_gid = attrs.get("gid")
+ if new_gid != None:
+ gid = new_gid
+ return (mode, user, group, uid, gid)
+
+def _merge_context_attributes(info, mapping_context):
+ """Merge defaults from mapping context with those in the source provider.
+
+ Args:
+ info: provider from a pkt_* target
+ mapping_context: MappingContext with the defaults.
+ """
+ default_mode = mapping_context.default_mode if hasattr(mapping_context, "default_mode") else ""
+ default_user = mapping_context.default_user if hasattr(mapping_context, "default_user") else ""
+ default_group = mapping_context.default_group if hasattr(mapping_context, "default_group") else ""
+ default_uid = mapping_context.default_uid if hasattr(mapping_context, "default_uid") else ""
+ default_gid = mapping_context.default_gid if hasattr(mapping_context, "default_gid") else ""
+ return _merge_attributes(info, default_mode, default_user, default_group, default_uid, default_gid)
+
+def _process_pkg_dirs(mapping_context, pkg_dirs_info, origin):
+ attrs = _merge_context_attributes(pkg_dirs_info, mapping_context)
for dir in pkg_dirs_info.dirs:
dest = dir.strip("/")
- _check_dest(content_map, dest, None, origin)
- content_map[dest] = _DestFile(
+ _check_dest(mapping_context.content_map, dest, None, origin, mapping_context.allow_duplicates_with_different_content)
+ mapping_context.content_map[dest] = _DestFile(
src = None,
entry_type = ENTRY_IS_DIR,
mode = attrs[0],
user = attrs[1],
group = attrs[2],
+ uid = attrs[3],
+ gid = attrs[4],
origin = origin,
)
-def _process_pkg_files(content_map, pkg_files_info, origin, default_mode, default_user, default_group):
- attrs = _merge_attributes(pkg_files_info, default_mode, default_user, default_group)
+def _process_pkg_files(mapping_context, pkg_files_info, origin):
+ attrs = _merge_context_attributes(pkg_files_info, mapping_context)
for filename, src in pkg_files_info.dest_src_map.items():
dest = filename.strip("/")
- _check_dest(content_map, dest, src, origin)
- content_map[dest] = _DestFile(
+ _check_dest(mapping_context.content_map, dest, src, origin, mapping_context.allow_duplicates_with_different_content)
+ mapping_context.content_map[dest] = _DestFile(
src = src,
entry_type = ENTRY_IS_TREE if src.is_directory else ENTRY_IS_FILE,
mode = attrs[0],
user = attrs[1],
group = attrs[2],
+ uid = attrs[3],
+ gid = attrs[4],
origin = origin,
)
-def _process_pkg_symlink(content_map, pkg_symlink_info, origin, default_mode, default_user, default_group):
+def _process_pkg_symlink(mapping_context, pkg_symlink_info, origin):
dest = pkg_symlink_info.destination.strip("/")
- attrs = _merge_attributes(pkg_symlink_info, default_mode, default_user, default_group)
- _check_dest(content_map, dest, None, origin)
- content_map[dest] = _DestFile(
+ attrs = _merge_context_attributes(pkg_symlink_info, mapping_context)
+ _check_dest(mapping_context.content_map, dest, None, origin, mapping_context.allow_duplicates_with_different_content)
+ mapping_context.content_map[dest] = _DestFile(
src = None,
entry_type = ENTRY_IS_LINK,
mode = attrs[0],
user = attrs[1],
group = attrs[2],
+ uid = attrs[3],
+ gid = attrs[4],
origin = origin,
link_to = pkg_symlink_info.target,
)
-def _process_pkg_filegroup(content_map, pkg_filegroup_info, origin, default_mode, default_user, default_group):
+def _process_pkg_filegroup(mapping_context, pkg_filegroup_info):
if hasattr(pkg_filegroup_info, "pkg_dirs"):
for d in pkg_filegroup_info.pkg_dirs:
- _process_pkg_dirs(content_map, d[0], d[1], default_mode, default_user, default_group)
+ _process_pkg_dirs(mapping_context, d[0], d[1])
if hasattr(pkg_filegroup_info, "pkg_files"):
for pf in pkg_filegroup_info.pkg_files:
- _process_pkg_files(content_map, pf[0], pf[1], default_mode, default_user, default_group)
+ _process_pkg_files(mapping_context, pf[0], pf[1])
if hasattr(pkg_filegroup_info, "pkg_symlinks"):
for psl in pkg_filegroup_info.pkg_symlinks:
- _process_pkg_symlink(content_map, psl[0], psl[1], default_mode, default_user, default_group)
+ _process_pkg_symlink(mapping_context, psl[0], psl[1])
-def process_src(
- content_map,
- files,
- src,
- origin,
- default_mode,
- default_user,
- default_group):
+def process_src(mapping_context, src, origin):
"""Add an entry to the content map.
Args:
- content_map: in/out The content map
- files: in/out list of file Depsets represented in the map
+ mapping_context: (r/w) a MappingContext
src: Source Package*Info object
origin: The rule instance adding this entry
- default_mode: fallback mode to use for Package*Info elements without mode
- default_user: fallback user to use for Package*Info elements without user
- default_group: fallback mode to use for Package*Info elements without group
Returns:
True if src was a Package*Info and added to content_map.
@@ -170,168 +259,133 @@ def process_src(
# Gather the files for every srcs entry here, even if it is not from
# a pkg_* rule.
if DefaultInfo in src:
- files.append(src[DefaultInfo].files)
+ mapping_context.file_deps.append(src[DefaultInfo].files)
found_info = False
if PackageFilesInfo in src:
_process_pkg_files(
- content_map,
+ mapping_context,
src[PackageFilesInfo],
origin,
- default_mode = default_mode,
- default_user = default_user,
- default_group = default_group,
)
found_info = True
if PackageFilegroupInfo in src:
_process_pkg_filegroup(
- content_map,
+ mapping_context,
src[PackageFilegroupInfo],
- origin,
- default_mode = default_mode,
- default_user = default_user,
- default_group = default_group,
)
found_info = True
if PackageSymlinkInfo in src:
_process_pkg_symlink(
- content_map,
+ mapping_context,
src[PackageSymlinkInfo],
origin,
- default_mode = default_mode,
- default_user = default_user,
- default_group = default_group,
)
found_info = True
if PackageDirsInfo in src:
_process_pkg_dirs(
- content_map,
+ mapping_context,
src[PackageDirsInfo],
origin,
- default_mode = "0555",
- default_user = default_user,
- default_group = default_group,
)
found_info = True
return found_info
-def add_directory(content_map, dir_path, origin, mode = None, user = None, group = None):
+def add_directory(mapping_context, dir_path, origin, mode = None, user = None, group = None, uid = None, gid = None):
"""Add an empty directory to the content map.
Args:
- content_map: The content map
+ mapping_context: (r/w) a MappingContext
dir_path: Where to place the file in the package.
origin: The rule instance adding this entry
mode: fallback mode to use for Package*Info elements without mode
user: fallback user to use for Package*Info elements without user
group: fallback mode to use for Package*Info elements without group
+ uid: numeric uid
+ gid: numeric gid
"""
- content_map[dir_path.strip("/")] = _DestFile(
+ mapping_context.content_map[dir_path.strip("/")] = _DestFile(
src = None,
entry_type = ENTRY_IS_DIR,
origin = origin,
mode = mode,
- user = user,
- group = group,
+ user = user or mapping_context.default_user,
+ group = group or mapping_context.default_group,
+ uid = uid or mapping_context.default_uid,
+ gid = gid or mapping_context.default_gid,
)
-def add_empty_file(content_map, dest_path, origin, mode = None, user = None, group = None):
+def add_empty_file(mapping_context, dest_path, origin, mode = None, user = None, group = None, uid = None, gid = None):
"""Add a single file to the content map.
Args:
- content_map: The content map
+ mapping_context: (r/w) a MappingContext
dest_path: Where to place the file in the package.
origin: The rule instance adding this entry
mode: fallback mode to use for Package*Info elements without mode
user: fallback user to use for Package*Info elements without user
group: fallback mode to use for Package*Info elements without group
+ uid: numeric uid
+ gid: numeric gid
"""
dest = dest_path.strip("/")
- _check_dest(content_map, dest, None, origin)
- content_map[dest] = _DestFile(
+ _check_dest(mapping_context.content_map, dest, None, origin)
+ mapping_context.content_map[dest] = _DestFile(
src = None,
entry_type = ENTRY_IS_EMPTY_FILE,
origin = origin,
mode = mode,
- user = user,
- group = group,
+ user = user or mapping_context.default_user,
+ group = group or mapping_context.default_group,
+ uid = uid or mapping_context.default_uid,
+ gid = gid or mapping_context.default_gid,
)
-def add_label_list(
- ctx,
- content_map,
- file_deps,
- srcs,
- default_mode = None,
- default_user = None,
- default_group = None):
+def add_label_list(mapping_context, srcs):
"""Helper method to add a list of labels (typically 'srcs') to a content_map.
Args:
- ctx: rule context.
- content_map: (r/w) The content map to update.
- file_deps: (r/w) The list of file Depsets that srcs depend on.
- srcs: List of source objects.
- default_mode: fallback mode to use for Package*Info elements without mode
- default_user: fallback user to use for Package*Info elements without user
- default_group: fallback mode to use for Package*Info elements without group
+ mapping_context: (r/w) a MappingContext
+ srcs: List of source objects
"""
- if hasattr(ctx.attr, "include_runfiles"):
- include_runfiles = ctx.attr.include_runfiles
- else:
- include_runfiles = False
-
# Compute the relative path
data_path = compute_data_path(
- ctx,
- ctx.attr.strip_prefix if hasattr(ctx.attr, "strip_prefix") else "",
+ mapping_context.label,
+ mapping_context.strip_prefix,
+ )
+ data_path_without_prefix = compute_data_path(
+ mapping_context.label,
+ ".",
)
- data_path_without_prefix = compute_data_path(ctx, ".")
for src in srcs:
if not process_src(
- content_map,
- file_deps,
+ mapping_context,
src = src,
origin = src.label,
- default_mode = default_mode,
- default_user = default_user,
- default_group = default_group,
):
# Add in the files of srcs which are not pkg_* types
add_from_default_info(
- content_map,
- file_deps,
+ mapping_context,
src,
data_path,
data_path_without_prefix,
- default_mode = default_mode,
- default_user = default_user,
- default_group = default_group,
- include_runfiles = include_runfiles,
+ include_runfiles = mapping_context.include_runfiles,
)
def add_from_default_info(
- content_map,
- file_deps,
+ mapping_context,
src,
data_path,
data_path_without_prefix,
- default_mode = None,
- default_user = None,
- default_group = None,
include_runfiles = False):
"""Helper method to add the DefaultInfo of a target to a content_map.
Args:
- content_map: (r/w) The content map to update.
- file_deps: (r/w) The list of file Depsets that srcs depend on.
+ mapping_context: (r/w) a MappingContext
src: A source object.
data_path: path to package
data_path_without_prefix: path to the package after prefix stripping
- default_mode: fallback mode to use for Package*Info elements without mode
- default_user: fallback user to use for Package*Info elements without user
- default_group: fallback mode to use for Package*Info elements without group
include_runfiles: Include runfiles
"""
if not DefaultInfo in src:
@@ -341,43 +395,54 @@ def add_from_default_info(
the_executable = get_my_executable(src)
all_files = src[DefaultInfo].files.to_list()
for f in all_files:
- d_path = dest_path(f, data_path, data_path_without_prefix)
+ d_path = mapping_context.path_mapper(
+ dest_path(f, data_path, data_path_without_prefix))
if f.is_directory:
add_tree_artifact(
- content_map,
- d_path,
- f,
+ mapping_context.content_map,
+ dest_path = d_path,
+ src = f,
origin = src.label,
- mode = default_mode,
- user = default_user,
- group = default_group,
+ mode = mapping_context.default_mode,
+ user = mapping_context.default_user,
+ group = mapping_context.default_group,
)
else:
- fmode = "0755" if f == the_executable else default_mode
+ fmode = "0755" if f == the_executable else mapping_context.default_mode
add_single_file(
- content_map,
+ mapping_context,
dest_path = d_path,
src = f,
origin = src.label,
mode = fmode,
- user = default_user,
- group = default_group,
+ user = mapping_context.default_user,
+ group = mapping_context.default_group,
)
if include_runfiles:
runfiles = src[DefaultInfo].default_runfiles
if runfiles:
- base_path = d_path + ".runfiles"
+ mapping_context.file_deps.append(runfiles.files)
+
+ # Computing the runfiles root is subtle. It should be based off of
+ # the executable, but that is not always obvious. When in doubt,
+ # the first file of DefaultInfo.files should be the right target.
+ base_file = the_executable or all_files[0]
+ base_file_path = dest_path(base_file, data_path, data_path_without_prefix)
+ base_path = base_file_path + ".runfiles"
+
for rf in runfiles.files.to_list():
- d_path = base_path + "/" + rf.short_path
- fmode = "0755" if rf == the_executable else default_mode
- _check_dest(content_map, d_path, rf, src.label)
- content_map[d_path] = _DestFile(
+ d_path = mapping_context.path_mapper(base_path + "/" + rf.short_path)
+ fmode = "0755" if rf == the_executable else mapping_context.default_mode
+ _check_dest(mapping_context.content_map, d_path, rf, src.label, mapping_context.allow_duplicates_with_different_content)
+ mapping_context.content_map[d_path] = _DestFile(
src = rf,
entry_type = ENTRY_IS_FILE,
origin = src.label,
mode = fmode,
- user = default_user,
- group = default_group,
+ user = mapping_context.default_user,
+ group = mapping_context.default_group,
+ uid = mapping_context.default_uid,
+ gid = mapping_context.default_gid,
)
def get_my_executable(src):
@@ -409,54 +474,61 @@ def get_my_executable(src):
return ftr.executable
return None
-def add_single_file(content_map, dest_path, src, origin, mode = None, user = None, group = None):
+def add_single_file(mapping_context, dest_path, src, origin, mode = None, user = None, group = None, uid = None, gid = None):
"""Add an single file to the content map.
Args:
- content_map: The content map
+ mapping_context: the MappingContext
dest_path: Where to place the file in the package.
src: Source object. Must have len(src[DefaultInfo].files) == 1
origin: The rule instance adding this entry
mode: fallback mode to use for Package*Info elements without mode
user: fallback user to use for Package*Info elements without user
group: fallback mode to use for Package*Info elements without group
+ uid: numeric uid
+ gid: numeric gid
"""
dest = dest_path.strip("/")
- _check_dest(content_map, dest, src, origin)
- content_map[dest] = _DestFile(
+ _check_dest(mapping_context.content_map, dest, src, origin, mapping_context.allow_duplicates_with_different_content)
+ mapping_context.content_map[dest] = _DestFile(
src = src,
entry_type = ENTRY_IS_FILE,
origin = origin,
mode = mode,
- user = user,
- group = group,
+ user = user or mapping_context.default_user,
+ group = group or mapping_context.default_group,
+ uid = uid or mapping_context.default_uid,
+ gid = gid or mapping_context.default_gid,
)
-def add_symlink(content_map, dest_path, src, origin, mode = None, user = None, group = None):
+def add_symlink(mapping_context, dest_path, src, origin):
"""Add a symlink to the content map.
+ TODO(aiuto): This is a vestage left from the pkg_tar use. We could
+ converge code by having pkg_tar be a macro that expands symlinks to
+ pkg_symlink targets and srcs them in.
+
Args:
- content_map: The content map
+ mapping_context: the MappingContext
dest_path: Where to place the file in the package.
src: Path to link to.
origin: The rule instance adding this entry
- mode: fallback mode to use for Package*Info elements without mode
- user: fallback user to use for Package*Info elements without user
- group: fallback mode to use for Package*Info elements without group
"""
dest = dest_path.strip("/")
- _check_dest(content_map, dest, None, origin)
- content_map[dest] = _DestFile(
+ _check_dest(mapping_context.content_map, dest, None, origin)
+ mapping_context.content_map[dest] = _DestFile(
src = None,
link_to = src,
entry_type = ENTRY_IS_LINK,
origin = origin,
- mode = mode,
- user = user,
- group = group,
+ mode = mapping_context.default_mode,
+ user = mapping_context.default_user,
+ group = mapping_context.default_group,
+ uid = mapping_context.default_uid,
+ gid = mapping_context.default_gid,
)
-def add_tree_artifact(content_map, dest_path, src, origin, mode = None, user = None, group = None):
+def add_tree_artifact(content_map, dest_path, src, origin, mode = None, user = None, group = None, uid = None, gid = None):
"""Add an tree artifact (directory output) to the content map.
Args:
@@ -465,8 +537,10 @@ def add_tree_artifact(content_map, dest_path, src, origin, mode = None, user = N
src: Source object. Must have len(src[DefaultInfo].files) == 1
origin: The rule instance adding this entry
mode: fallback mode to use for Package*Info elements without mode
- user: fallback user to use for Package*Info elements without user
- group: fallback mode to use for Package*Info elements without group
+ user: User name for the entry (probably unused)
+ group: group name for the entry (probably unused)
+ uid: User id for the entry (probably unused)
+ gid: Group id for the entry (probably unused)
"""
content_map[dest_path] = _DestFile(
src = src,
@@ -475,9 +549,11 @@ def add_tree_artifact(content_map, dest_path, src, origin, mode = None, user = N
mode = mode,
user = user,
group = group,
+ uid = uid,
+ gid = gid,
)
-def write_manifest(ctx, manifest_file, content_map, use_short_path=False, pretty_print=False):
+def write_manifest(ctx, manifest_file, content_map, use_short_path = False, pretty_print = False):
"""Write a content map to a manifest file.
The format of this file is currently undocumented, as it is a private
@@ -491,6 +567,7 @@ def write_manifest(ctx, manifest_file, content_map, use_short_path=False, pretty
manifest_file: File object used as the output destination
content_map: content_map (see concepts at top of file)
use_short_path: write out the manifest file destinations in terms of "short" paths, suitable for `bazel run`.
+ pretty_print: indent the output nicely. Takes more space so it is off by default.
"""
ctx.actions.write(
manifest_file,
@@ -498,11 +575,11 @@ def write_manifest(ctx, manifest_file, content_map, use_short_path=False, pretty
[
_encode_manifest_entry(dst, content_map[dst], use_short_path, pretty_print)
for dst in sorted(content_map.keys())
- ]
- ) + "\n]\n"
+ ],
+ ) + "\n]\n",
)
-def _encode_manifest_entry(dest, df, use_short_path, pretty_print=False):
+def _encode_manifest_entry(dest, df, use_short_path, pretty_print = False):
entry_type = df.entry_type if hasattr(df, "entry_type") else ENTRY_IS_FILE
if df.src:
src = df.src.short_path if use_short_path else df.src.path
@@ -522,16 +599,18 @@ def _encode_manifest_entry(dest, df, use_short_path, pretty_print=False):
# Since this causes all sorts of chaos with our tests, be consistent across
# all Bazel versions.
origin_str = str(df.origin)
- if not origin_str.startswith('@'):
- origin_str = '@' + origin_str
+ if not origin_str.startswith("@"):
+ origin_str = "@" + origin_str
data = {
- "type": df.entry_type,
+ "type": entry_type,
"src": src,
"dest": dest.strip("/"),
"mode": df.mode or "",
"user": df.user or None,
"group": df.group or None,
+ "uid": df.uid,
+ "gid": df.gid,
"origin": origin_str,
}