Skip to content

Instantly share code, notes, and snippets.

@tzickel
Created October 17, 2018 06:10
Show Gist options
  • Save tzickel/2111dd013d1c4f8c765a538e74646f95 to your computer and use it in GitHub Desktop.
Save tzickel/2111dd013d1c4f8c765a538e74646f95 to your computer and use it in GitHub Desktop.
A simple docker build extension that works with .gitignore file directives and you can specify both Dockerfile and multiple .gitignore paths
# Version 0.0.1 (works with python2.7 and python3)
# Does not work with non-local context (i.e. git, remote archives)
# You need the pathspec package installed (pip install pathspec)
# Pass any docker build arguments you want to use after -- argument (i.e., dockerignore.py . -- -t blah)
# This works with .gitignore syntax, not .dockerignore ( https://git-scm.com/docs/gitignore#_pattern_format )
import tarfile
import subprocess
import argparse
import os
import sys
try:
from StringIO import StringIO
except ModuleNotFoundError:
from io import BytesIO as StringIO
import pathspec
def tar_add_string_as_file(tar, name, s):
t = tarfile.TarInfo(name=name)
t.size = len(s)
tar.addfile(tarinfo=t, fileobj=StringIO(s))
def build_from(dockerfile, context, gitignorefiles, compress, buildparams, verbose):
def filter(tarinfo):
if not dockerfile and tarinfo.name == 'Dockerfile':
return tarinfo
for ps in pathspecs:
if ps.match_file(tarinfo.name):
return
if verbose:
print(tarinfo.name)
return tarinfo
if not gitignorefiles:
gitignorefiles = []
if not os.path.isdir(context):
raise Exception('context must be a directory: %s' % context)
pathspecs = []
for filepath in gitignorefiles:
with open(filepath, 'rt') as f:
spec = pathspec.PathSpec.from_lines('gitignore', f)
pathspecs.append(spec)
proc = subprocess.Popen(['docker', 'build', '-'] + buildparams, stdin=subprocess.PIPE)
try:
with tarfile.open(mode='w|' + compress, fileobj=proc.stdin) as tar:
tar_add_string_as_file(tar, '.dockerignore', b'Dockerfile\n.dockerignore')
tar.add(context, arcname='', filter=filter)
if dockerfile:
tar.add(dockerfile, arcname='Dockerfile')
proc.stdin.close()
return proc.wait()
except Exception:
proc.kill()
raise
def fix_argv():
try:
ind = sys.argv.index('--')
ret = sys.argv[ind+1:]
sys.argv = sys.argv[:ind]
return ret
except ValueError:
return []
if __name__ == '__main__':
docker_build_args = fix_argv()
parser = argparse.ArgumentParser()
parser.add_argument("context")
parser.add_argument("-f", "--file", help="Name of the Dockerfile (Default is 'PATH/Dockerfile')")
parser.add_argument("-i", "--gitignorefiles", action="append", help="a .gitignore file")
parser.add_argument("--gz", action="store_true", help="Compress the build context using gzip")
parser.add_argument("--bz2", action="store_true", help="Compress the build context using bzip2")
parser.add_argument("--verbose", action="store_true", help="Show the files added to the context")
args = parser.parse_args()
if args.gz and args.bz2:
raise Exception('Cannot enable both gzip and bzip2 compression')
compress = 'gz' if args.gz else 'bz2' if args.bz2 else ''
sys.exit(build_from(args.file, args.context, args.gitignorefiles, compress, docker_build_args, args.verbose))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment