def create_image(output, identifier, base=None, layer=None, metadata=None, name=None, repository=None): """Creates a Docker image. Args: output: the name of the docker image file to create. identifier: the identifier of the top layer for this image. base: a base layer (optional) to merge to current layer. layer: the layer content (a tar file). metadata: the json metadata file for the top layer. name: symbolic name for this docker image. repository: repository name for this docker image. """ tar = archive.TarFileWriter(output) # Write our id to 'top' as we are now the topmost layer. tar.add_file('top', content=identifier) # Each layer is encoded as a directory in the larger tarball of the form: # {id}\ # layer.tar # VERSION # json # Create the directory for us to now fill in. tar.add_file(identifier + '/', tarfile.DIRTYPE) # VERSION generally seems to contain 1.0, not entirely sure # what the point of this is. tar.add_file(identifier + '/VERSION', content=DATA_FORMAT_VERSION) # Add the layer file tar.add_file(identifier + '/layer.tar', file_content=layer) # Now the json metadata tar.add_file(identifier + '/json', file_content=metadata) # Merge the base if any if base: tar.add_tar(base, name_filter=_base_name_filter) # In addition to N layers of the form described above, there is # a single file at the top of the image called repositories. # This file contains a JSON blob of the form: # { # 'repo':{ # 'tag-name': 'top-most layer hex', # ... # }, # ... # } if repository: tar.add_file('repositories', content='\n'.join([ '{', ' "%s": {' % repository, ' "%s": "%s"' % (name, identifier), ' }', '}' ]))
def testMergeTar(self): content = [ {"name": "./a", "data": "a"}, {"name": "./ab", "data": "ab"} ] for ext in ["", ".gz", ".bz2", ".xz"]: with archive.TarFileWriter(self.tempfile) as f: f.add_tar(os.path.join(testenv.TESTDATA_PATH, "archive", "tar_test.tar" + ext), name_filter=lambda n: n != "./b") self.assertTarFileContent(self.tempfile, content)
def testDottedFiles(self): with archive.TarFileWriter(self.tempfile) as f: f.add_file("a") f.add_file("/b") f.add_file("./c") f.add_file("./.d") f.add_file("..e") f.add_file(".f") content = [ {"name": "./a"}, {"name": "/b"}, {"name": "./c"}, {"name": "./.d"}, {"name": "./..e"}, {"name": "./.f"} ] self.assertTarFileContent(self.tempfile, content)
def testAddDir(self): # For some strange reason, ending slash is stripped by the test content = [ {"name": ".", "mode": 0755}, {"name": "./a", "mode": 0755}, {"name": "./a/b", "data": "ab", "mode": 0644}, {"name": "./a/c", "mode": 0755}, {"name": "./a/c/d", "data": "acd", "mode": 0644}, ] tempdir = os.path.join(os.environ["TEST_TMPDIR"], "test_dir") # Iterate over the `content` array to create the directory # structure it describes. for c in content: if "data" in c: p = os.path.join(tempdir, c["name"][2:]) os.makedirs(os.path.dirname(p)) with open(p, "w") as f: f.write(c["data"]) with archive.TarFileWriter(self.tempfile) as f: f.add_dir("./", tempdir, mode=0644) self.assertTarFileContent(self.tempfile, content)
# # 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. """A simple cross-platform helper to create a timestamped tar file.""" import datetime import sys import tarfile from tools.build_defs.docker import archive if __name__ == '__main__': mtime = int(datetime.datetime.now().strftime('%s')) with archive.TarFileWriter(sys.argv[1]) as f: f.add_file('./', tarfile.DIRTYPE, uname='root', gname='root', mtime=mtime) f.add_file('./usr/', tarfile.DIRTYPE, uname='root', gname='root', mtime=mtime) f.add_file('./usr/bin/', tarfile.DIRTYPE, uname='root', gname='root', mtime=mtime)
def __enter__(self): self.tarfile = archive.TarFileWriter(self.output) return self
def assertSimpleFileContent(self, names): with archive.TarFileWriter(self.tempfile) as f: for n in names: f.add_file(n, content=n) content = [{"name": n, "size": len(n), "data": n} for n in names] self.assertTarFileContent(self.tempfile, content)
def testEmptyTarFile(self): with archive.TarFileWriter(self.tempfile): pass self.assertTarFileContent(self.tempfile, [])