contrib/packaging/hg-docker
author Sandu Turcan <idlsoft@gmail.com>
Tue, 03 May 2022 21:44:30 -0400
branchstable
changeset 49241 6b10151b9621
parent 43659 99e231afc29c
permissions -rwxr-xr-x
narrow_widen_acl: enforce narrowacl in narrow_widen (SEC) Reviewer note: this was sent by the author as a simple bugfix, but can be considered a security patch, since it allows users to access things outside of the ACL, hence the (SEC) prefix. However, this affects the `narrow` extention which is still marked as experimental and has relatively few users aside from large companies with their own security layers on top from what we can gather. We feel (Alphare: or at least, I feel) like pinging the packaging list is enough in this case.

#!/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())