aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/create_embedded_tools_lib.py
diff options
context:
space:
mode:
authorGravatar László Csomor <laszlocsomor@google.com>2017-08-11 09:28:12 +0200
committerGravatar Marcel Hlopko <hlopko@google.com>2017-08-11 12:56:48 +0200
commit5f99fdab1485186292068d274411201e4fb9208f (patch)
tree0219a2f3ea288d6e16863da1f45c9f9cc2d47c68 /src/create_embedded_tools_lib.py
parent6628d55c07e312ea6645f2957e4ab81dd66b937e (diff)
Extract a library from create_embedded_tools.py
We'll use the extracted functions in the upcoming Python-based reincarnation of the //:bazel-distfile rule. Change-Id: I5140938ae4af50f62fb695b5b96cd41f3cd939ef PiperOrigin-RevId: 164950515
Diffstat (limited to 'src/create_embedded_tools_lib.py')
-rw-r--r--src/create_embedded_tools_lib.py94
1 files changed, 94 insertions, 0 deletions
diff --git a/src/create_embedded_tools_lib.py b/src/create_embedded_tools_lib.py
new file mode 100644
index 0000000000..a730ce6b9a
--- /dev/null
+++ b/src/create_embedded_tools_lib.py
@@ -0,0 +1,94 @@
+# pylint: disable=g-bad-file-header
+# Copyright 2017 The Bazel Authors. All rights reserved.
+#
+# 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.
+"""Utils to the contents of a tar or zip file into another zip file."""
+
+import contextlib
+import os.path
+import stat
+import tarfile
+import zipfile
+
+
+def is_mode_executable(mode):
+ """Returns true if `mode` has any of the executable bits set."""
+ return mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) > 0
+
+
+def is_executable(path):
+ """Returns true if `path` is an executable file/directory."""
+ return is_mode_executable(os.stat(path)[stat.ST_MODE])
+
+
+def copy_tar_to_zip(output_zip, input_file, process_filename=None):
+ """Copy a tar file's contents into a zip file.
+
+ This function unpacks every file from `input_file` and puts them into
+ `output_zip`. The unpacking is performed in-memory.
+
+ Args:
+ output_zip: zipfile.ZipFile; the destination archive
+ input_file: string; path to the source tar file
+ process_filename: function(str) -> str; optional; for a packed file entry in
+ `input_file` it computes the path in `output_zip`
+ """
+ with tarfile.open(input_file, 'r', errorlevel=2) as tar_file:
+ while True:
+ tar_entry = tar_file.next()
+ if tar_entry is None:
+ break
+ filename = (process_filename(tar_entry.name)
+ if process_filename else tar_entry.name)
+ zipinfo = zipfile.ZipInfo(filename, (1980, 1, 1, 0, 0, 0))
+ if tar_entry.isreg():
+ if is_mode_executable(tar_entry.mode):
+ zipinfo.external_attr = 0o755 << 16
+ else:
+ zipinfo.external_attr = 0o644 << 16
+ zipinfo.compress_type = zipfile.ZIP_DEFLATED
+ output_zip.writestr(zipinfo, tar_file.extractfile(tar_entry).read())
+ elif tar_entry.issym():
+ # 0120000 originally comes from the definition of S_IFLNK and
+ # marks a symbolic link in the Zip file format.
+ zipinfo.external_attr = 0o120000 << 16
+ output_zip.writestr(zipinfo, tar_entry.linkname)
+ else:
+ # Ignore directories, hard links, special files, ...
+ pass
+
+
+def copy_zip_to_zip(output_zip, input_file, process_filename=None):
+ """Copy a zip file's contents into another zip file.
+
+ This function unpacks every file from `input_file` and puts them into
+ `output_zip`. The unpacking is performed in-memory.
+
+ Args:
+ output_zip: zipfile.ZipFile; the destination archive
+ input_file: string; path to the source tar file
+ process_filename: function(str) -> str; optional; for a packed file entry in
+ `input_file` it computes the path in `output_zip`
+ """
+ # Adding contextlib.closing to be python 2.6 (for centos 6.7) compatible
+ with contextlib.closing(zipfile.ZipFile(input_file, 'r')) as zip_file:
+ for zip_entry in zip_file.infolist():
+ filename = (process_filename(zip_entry.filename)
+ if process_filename else zip_entry.filename)
+ zipinfo = zipfile.ZipInfo(filename, (1980, 1, 1, 0, 0, 0))
+ if is_mode_executable(zip_entry.external_attr >> 16 & 0xFFFF):
+ zipinfo.external_attr = 0o755 << 16
+ else:
+ zipinfo.external_attr = 0o644 << 16
+ zipinfo.compress_type = zip_entry.compress_type
+ output_zip.writestr(zipinfo, zip_file.read(zip_entry))