blob: d0273a60852edbee16c3a57978b7991be1119c9a [file] [log] [blame]
# Copyright 2015 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.
"""This tool creates a docker image from a list of layers."""
# This is the main program to create a docker image. It expect to be run with:
# join_layers --output=output_file \
# --layer=layer1 [--layer=layer2 ... --layer=layerN] \
# --id=@identifier \
# --name=myname --repository=repositoryName
# See the gflags declaration about the flags argument details.
import os.path
import sys
from tools.build_defs.pkg import archive
from third_party.py import gflags
gflags.DEFINE_string('output', None, 'The output file, mandatory')
gflags.MarkFlagAsRequired('output')
gflags.DEFINE_multistring('layer', [], 'The tar files for layers to join.')
gflags.DEFINE_string(
'id', None, 'The hex identifier of the top layer (hexstring or @filename).')
gflags.DEFINE_string(
'repository', None,
'The name of the repository to add this image (use with --id and --name).')
gflags.DEFINE_string(
'name', None,
'The symbolic name of this image (use with --id and --repsoitory).')
FLAGS = gflags.FLAGS
def _layer_filter(name):
"""Ignore files 'top' and 'repositories' when merging layers."""
basename = os.path.basename(name)
return basename not in ('top', 'repositories')
def create_image(output, layers, identifier=None,
name=None, repository=None):
"""Creates a Docker image from a list of layers.
Args:
output: the name of the docker image file to create.
layers: the layers (tar files) to join to the image.
identifier: the identifier of the top layer for this image.
name: symbolic name for this docker image.
repository: repository name for this docker image.
"""
tar = archive.TarFileWriter(output)
for layer in layers:
tar.add_tar(layer, name_filter=_layer_filter)
# In addition to N layers of the form described above, there might be
# 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 identifier:
# If the identifier is not provided, then the resulted layer will be
# created without a 'top' file. Docker doesn't needs that file nor
# the repository to load the image and for intermediate layer,
# docker_build store the name of the layer in a separate artifact so
# this 'top' file is not needed.
tar.add_file('top', content=identifier)
if repository and name:
tar.add_file('repositories',
content='\n'.join([
'{', ' "%s": {' % repository, ' "%s": "%s"' % (
name, identifier), ' }', '}'
]))
def main(unused_argv):
identifier = FLAGS.id
if identifier and identifier.startswith('@'):
with open(identifier[1:], 'r') as f:
identifier = f.read()
create_image(FLAGS.output, FLAGS.layer, identifier, FLAGS.name,
FLAGS.repository)
if __name__ == '__main__':
main(FLAGS(sys.argv))