diff --git a/example/squeeze/Fockerfile b/example/squeeze/Fockerfile new file mode 100644 index 0000000..820ee88 --- /dev/null +++ b/example/squeeze/Fockerfile @@ -0,0 +1,14 @@ +base: freebsd-latest + +steps: + - run: + - touch /a + - touch /b + - touch /c + - run: + - touch /d + - touch /e + - touch /f + - copy: + - [ files/g, /g ] + diff --git a/example/squeeze/files/g b/example/squeeze/files/g new file mode 100644 index 0000000..c9180d9 --- /dev/null +++ b/example/squeeze/files/g @@ -0,0 +1,2 @@ +foo bar + diff --git a/focker/focker.py b/focker/focker.py index 6596e0a..8c517fa 100644 --- a/focker/focker.py +++ b/focker/focker.py @@ -83,6 +83,7 @@ def create_parser(): parser.set_defaults(func=command_image_build) parser.add_argument('focker_dir', type=str) parser.add_argument('--tags', '-t', type=str, nargs='+', default=[]) + parser.add_argument('--squeeze', '-s', action='store_true') parser = ListForwarder([subparsers.add_parser(cmd) for cmd in ['tag', 't']]) parser.set_defaults(func=command_image_tag) diff --git a/focker/image.py b/focker/image.py index 9928cf1..0a50b1e 100644 --- a/focker/image.py +++ b/focker/image.py @@ -12,15 +12,55 @@ from .steps import create_step from .snapshot import new_snapshot from tabulate import tabulate import subprocess +from .misc import find_prefix -def build(spec, args): +def validate_spec(spec): if 'base' not in spec: raise ValueError('Missing base in specification') if 'steps' not in spec: raise ValueError('Missing steps in specification') + +def build_squeeze(spec, args): + validate_spec(spec) + + base = spec['base'] + base, sha256 = zfs_find(base, focker_type='image', zfs_type='snapshot') + + root = '/'.join(base.split('/')[:-1]) + print('base:', base, 'root:', root) + + steps = spec['steps'] + if not isinstance(steps, list): + steps = [ steps ] + + for st in steps: + st = create_step(st) + sha256 = st.hash(sha256, args=args) + + if zfs_exists_snapshot_sha256(sha256): + name = zfs_snapshot_by_sha256(sha256) + print('Reusing:', name) + return (name, sha256) + + name = find_prefix(root + '/', sha256) + + def atomic(): + for st in steps: + st = create_step(st) + st.execute(zfs_mountpoint(name), args=args) + zfs_set_props(name, + { 'focker:sha256': sha256 }) + + name = new_snapshot(base, atomic, name) + return (name, sha256) + + +def build(spec, args): + validate_spec(spec) + base = spec['base'] base, base_sha256 = zfs_find(base, focker_type='image', zfs_type='snapshot') @@ -67,7 +107,8 @@ def command_image_build(args): with open(fname, 'r') as f: spec = yaml.safe_load(f) print('spec:', spec) - image, image_sha256 = build(spec, args) + image, image_sha256 = build_squeeze(spec, args) \ + if args.squeeze else build(spec, args) zfs_untag(args.tags) zfs_tag(image.split('@')[0], args.tags)