(root, files=None, fileobj=None, gzip=False,
extra_files=None)
| 68 | |
| 69 | |
| 70 | def create_archive(root, files=None, fileobj=None, gzip=False, |
| 71 | extra_files=None): |
| 72 | extra_files = extra_files or [] |
| 73 | if not fileobj: |
| 74 | fileobj = tempfile.NamedTemporaryFile() |
| 75 | t = tarfile.open(mode='w:gz' if gzip else 'w', fileobj=fileobj) |
| 76 | if files is None: |
| 77 | files = build_file_list(root) |
| 78 | extra_names = {e[0] for e in extra_files} |
| 79 | for path in files: |
| 80 | if path in extra_names: |
| 81 | # Extra files override context files with the same name |
| 82 | continue |
| 83 | full_path = os.path.join(root, path) |
| 84 | |
| 85 | i = t.gettarinfo(full_path, arcname=path) |
| 86 | if i is None: |
| 87 | # This happens when we encounter a socket file. We can safely |
| 88 | # ignore it and proceed. |
| 89 | continue |
| 90 | |
| 91 | # Workaround https://bugs.python.org/issue32713 |
| 92 | if i.mtime < 0 or i.mtime > 8**11 - 1: |
| 93 | i.mtime = int(i.mtime) |
| 94 | |
| 95 | if IS_WINDOWS_PLATFORM: |
| 96 | # Windows doesn't keep track of the execute bit, so we make files |
| 97 | # and directories executable by default. |
| 98 | i.mode = i.mode & 0o755 | 0o111 |
| 99 | |
| 100 | if i.isfile(): |
| 101 | try: |
| 102 | with open(full_path, 'rb') as f: |
| 103 | t.addfile(i, f) |
| 104 | except OSError as oe: |
| 105 | raise OSError( |
| 106 | f'Can not read file in context: {full_path}' |
| 107 | ) from oe |
| 108 | else: |
| 109 | # Directories, FIFOs, symlinks... don't need to be read. |
| 110 | t.addfile(i, None) |
| 111 | |
| 112 | for name, contents in extra_files: |
| 113 | info = tarfile.TarInfo(name) |
| 114 | contents_encoded = contents.encode('utf-8') |
| 115 | info.size = len(contents_encoded) |
| 116 | t.addfile(info, io.BytesIO(contents_encoded)) |
| 117 | |
| 118 | t.close() |
| 119 | fileobj.seek(0) |
| 120 | return fileobj |
| 121 | |
| 122 | |
| 123 | def mkbuildcontext(dockerfile): |
no test coverage detected