forked from pinterest/bazel
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
1 parent
6628d55
commit 5f99fda
Showing
3 changed files
with
113 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) |