view contrib/packaging/hg-docker @ 49325:bf66f7a1e3f8

bundlespec: merge the contentopts and params dictionnary They are content using the same keys. Using differents object for access open the gates for confusion in the code using them (this is already the case). So we start fusing their usages to make the parameters more useful. More work will be needed to make them really useful, but the first step is here: not throwing the value away. However this is still not making the previously introduced test useful because currently, the default config value overwrite the one from the bundlespec. We will fix this in the coming changesets.
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Tue, 17 May 2022 16:36:32 +0100
parents 99e231afc29c
children
line wrap: on
line source

#!/usr/bin/env python3
#
# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

import argparse
import pathlib
import shutil
import subprocess
import sys


def get_docker() -> str:
    docker = shutil.which('docker.io') or shutil.which('docker')
    if not docker:
        print('could not find docker executable')
        return 1

    try:
        out = subprocess.check_output([docker, '-h'], stderr=subprocess.STDOUT)

        if b'Jansens' in out:
            print(
                '%s is the Docking System Tray; try installing docker.io'
                % docker
            )
            sys.exit(1)
    except subprocess.CalledProcessError as e:
        print('error calling `%s -h`: %s' % (docker, e.output))
        sys.exit(1)

    out = subprocess.check_output([docker, 'version'], stderr=subprocess.STDOUT)

    lines = out.splitlines()
    if not any(l.startswith((b'Client:', b'Client version:')) for l in lines):
        print('`%s version` does not look like Docker' % docker)
        sys.exit(1)

    if not any(l.startswith((b'Server:', b'Server version:')) for l in lines):
        print('`%s version` does not look like Docker' % docker)
        sys.exit(1)

    return docker


def get_dockerfile(path: pathlib.Path, args: list) -> bytes:
    with path.open('rb') as fh:
        df = fh.read()

    for k, v in args:
        df = df.replace(bytes('%%%s%%' % k.decode(), 'utf-8'), v)

    return df


def build_docker_image(dockerfile: pathlib.Path, params: list, tag: str):
    """Build a Docker image from a templatized Dockerfile."""
    docker = get_docker()

    dockerfile_path = pathlib.Path(dockerfile)

    dockerfile = get_dockerfile(dockerfile_path, params)

    print('building Dockerfile:')
    print(dockerfile.decode('utf-8', 'replace'))

    args = [
        docker,
        'build',
        '--build-arg',
        'http_proxy',
        '--build-arg',
        'https_proxy',
        '--tag',
        tag,
        '-',
    ]

    print('executing: %r' % args)
    p = subprocess.Popen(args, stdin=subprocess.PIPE)
    p.communicate(input=dockerfile)
    if p.returncode:
        raise subprocess.CalledProcessException(
            p.returncode,
            'failed to build docker image: %s %s' % (p.stdout, p.stderr),
        )


def command_build(args):
    build_args = []
    for arg in args.build_arg:
        k, v = arg.split('=', 1)
        build_args.append((k.encode('utf-8'), v.encode('utf-8')))

    build_docker_image(pathlib.Path(args.dockerfile), build_args, args.tag)


def command_docker(args):
    print(get_docker())


def main() -> int:
    parser = argparse.ArgumentParser()

    subparsers = parser.add_subparsers(title='subcommands')

    build = subparsers.add_parser('build', help='Build a Docker image')
    build.set_defaults(func=command_build)
    build.add_argument(
        '--build-arg',
        action='append',
        default=[],
        help='Substitution to perform in Dockerfile; ' 'format: key=value',
    )
    build.add_argument('dockerfile', help='path to Dockerfile to use')
    build.add_argument('tag', help='Tag to apply to created image')

    docker = subparsers.add_parser('docker-path', help='Resolve path to Docker')
    docker.set_defaults(func=command_docker)

    args = parser.parse_args()

    return args.func(args)


if __name__ == '__main__':
    sys.exit(main())