commit 377fa2d14fc5b44dcb6d0819b55c821f3e51f69c
parent b6c34152a75eb70dd14229ead0d01967ce2bb024
Author: parazyd <parazyd@dyne.org>
Date: Wed, 20 Nov 2019 23:28:41 +0100
Add Makefile for installation.
Diffstat:
A | Makefile | | | 8 | ++++++++ |
A | docker2sh | | | 156 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | docker2sh.py | | | 172 | ------------------------------------------------------------------------------- |
3 files changed, 164 insertions(+), 172 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,8 @@
+PREFIX = /usr/local
+
+all:
+ @echo "Run 'make install' to install docker2sh."
+
+install:
+ cp -f docker2sh $(DESTDIR)$(PREFIX)/bin
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/docker2sh
diff --git a/docker2sh b/docker2sh
@@ -0,0 +1,156 @@
+#!/usr/bin/env python3
+"""
+Dockerfile parser module
+"""
+from argparse import ArgumentParser
+from base64 import b64encode
+from bz2 import compress
+from os.path import dirname, join
+from sys import stdin
+import json
+import re
+
+
+def rstrip_backslash(line):
+ """
+ Strip backslashes from end of line
+ """
+ line = line.rstrip()
+ if line.endswith('\\'):
+ return line[:-1]
+ return line
+
+
+def compress_and_b64(file, basepath=None):
+ """
+ Compress a file and turn it to base64 for output
+ """
+ spl = file.split()
+ if basepath:
+ file = open(join(basepath, spl[0])).read()
+ else:
+ file = open(spl[0]).read()
+
+ comp = compress(file.encode())
+ b64 = b64encode(comp)
+
+ cat = 'cat << __EOFF__ | base64 -d | bunzip2 > %s' % (spl[1])
+ return '\n'.join([cat, b64.decode(), '__EOFF__']) + '\n'
+
+
+def parse_instruction(inst, dfile=None):
+ """
+ Method for translating Dockerfile instructions to shell script
+ """
+ ins = inst['instruction'].upper()
+ val = inst['value']
+
+ # Valid Dockerfile instructions
+ cmds = ['ADD', 'ARG', 'CMD', 'COPY', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'FROM',
+ 'HEALTHCHECK', 'LABEL', 'MAINTAINER', 'ONBUILD', 'RUN', 'SHELL',
+ 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR']
+
+ if ins == 'ADD':
+ val = val.replace('$', '\\$')
+ args = val.split(' ')
+ return 'wget -O %s %s\n' % (args[1], args[0])
+
+ if ins == 'ARG':
+ return '%s\n' % val
+
+ if ins == 'ENV':
+ if '=' not in val:
+ val = val.replace(' ', '=', 1)
+ val = val.replace('$', '\\$')
+ return 'export %s\n' % val
+
+ if ins == 'RUN':
+ # Replace `` with $()
+ while '`' in val:
+ val = val.replace('`', '"$(', 1)
+ val = val.replace('`', ')"', 1)
+ return '%s\n' % val.replace('$', '\\$')
+
+ if ins == 'WORKDIR':
+ return 'mkdir -p %s && cd %s\n' % (val, val)
+
+ if ins == 'COPY':
+ if '/' in dfile:
+ return compress_and_b64(val, basepath=dirname(dfile))
+ return compress_and_b64(val)
+
+ if ins in cmds:
+ # TODO: Look at CMD being added to /etc/rc.local
+ return '#\n# %s not implemented\n# Instruction: %s %s\n#\n' % \
+ (ins, ins, val)
+
+ # Silently ignore unknown instructions
+ return ''
+
+
+def main():
+ """
+ Main parsing routine
+ """
+ parser = ArgumentParser()
+ parser.add_argument('-j', '--json', action='store_true',
+ help='output the data as a JSON structure')
+ parser.add_argument('-s', '--shell', action='store_true',
+ help='output the data as a shell script (default)')
+ parser.add_argument('--keeptabs', action='store_true',
+ help='do not replace \\t (tabs) in the strings')
+ parser.add_argument('Dockerfile')
+ args = parser.parse_args()
+
+ if args.Dockerfile != '-':
+ with open(args.Dockerfile) as file:
+ data = file.read().splitlines()
+ else:
+ data = stdin.read().splitlines()
+
+ instre = re.compile(r'^\s*(\w+)\s+(.*)$')
+ contre = re.compile(r'^.*\\\s*$')
+ commentre = re.compile(r'^\s*#')
+
+ instructions = []
+ lineno = -1
+ in_continuation = False
+ cur_inst = {}
+
+ for line in data:
+ lineno += 1
+ if commentre.match(line):
+ continue
+ if not in_continuation:
+ rematch = instre.match(line)
+ if not rematch:
+ continue
+ cur_inst = {
+ 'instruction': rematch.groups()[0].upper(),
+ 'value': rstrip_backslash(rematch.groups()[1]),
+ }
+ else:
+ if cur_inst['value']:
+ cur_inst['value'] += rstrip_backslash(line)
+ else:
+ cur_inst['value'] = rstrip_backslash(line.lstrip())
+
+ in_continuation = contre.match(line)
+ if not in_continuation and cur_inst is not None:
+ if not args.keeptabs:
+ cur_inst['value'] = cur_inst['value'].replace('\t', '')
+ instructions.append(cur_inst)
+
+ if args.json:
+ print(json.dumps(instructions))
+ return
+
+ # Default to shell script output
+ script = '#!/bin/sh\n'
+ for i in instructions:
+ script += parse_instruction(i, dfile=args.Dockerfile)
+ print(script)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/docker2sh.py b/docker2sh.py
@@ -1,172 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2018-2019 Dyne.org Foundation
-# docker2sh is maintained by Ivan J. <parazyd@dyne.org>
-#
-# This source code is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This software is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this source code. If not, see <http://www.gnu.org/licenses/>.
-
-"""
-Dockerfile parser module
-"""
-from argparse import ArgumentParser
-from base64 import b64encode
-from bz2 import compress
-from os.path import dirname, join
-from sys import stdin
-import json
-import re
-
-
-def rstrip_backslash(line):
- """
- Strip backslashes from end of line
- """
- line = line.rstrip()
- if line.endswith('\\'):
- return line[:-1]
- return line
-
-
-def compress_and_b64(file, basepath=None):
- """
- Compress a file and turn it to base64 for output
- """
- spl = file.split()
- if basepath:
- file = open(join(basepath, spl[0])).read()
- else:
- file = open(spl[0]).read()
-
- comp = compress(file.encode())
- b64 = b64encode(comp)
-
- cat = 'cat << __EOFF__ | base64 -d | bunzip2 > %s' % (spl[1])
- return '\n'.join([cat, b64.decode(), '__EOFF__']) + '\n'
-
-
-def parse_instruction(inst, dfile=None):
- """
- Method for translating Dockerfile instructions to shell script
- """
- ins = inst['instruction'].upper()
- val = inst['value']
-
- # Valid Dockerfile instructions
- cmds = ['ADD', 'ARG', 'CMD', 'COPY', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'FROM',
- 'HEALTHCHECK', 'LABEL', 'MAINTAINER', 'ONBUILD', 'RUN', 'SHELL',
- 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR']
-
- if ins == 'ADD':
- val = val.replace('$', '\\$')
- args = val.split(' ')
- return 'wget -O %s %s\n' % (args[1], args[0])
-
- if ins == 'ARG':
- return '%s\n' % val
-
- if ins == 'ENV':
- if '=' not in val:
- val = val.replace(' ', '=', 1)
- val = val.replace('$', '\\$')
- return 'export %s\n' % val
-
- if ins == 'RUN':
- # Replace `` with $()
- while '`' in val:
- val = val.replace('`', '"$(', 1)
- val = val.replace('`', ')"', 1)
- return '%s\n' % val.replace('$', '\\$')
-
- if ins == 'WORKDIR':
- return 'mkdir -p %s && cd %s\n' % (val, val)
-
- if ins == 'COPY':
- if '/' in dfile:
- return compress_and_b64(val, basepath=dirname(dfile))
- return compress_and_b64(val)
-
- if ins in cmds:
- # TODO: Look at CMD being added to /etc/rc.local
- return '#\n# %s not implemented\n# Instruction: %s %s\n#\n' % \
- (ins, ins, val)
-
- # Silently ignore unknown instructions
- return ''
-
-
-def main():
- """
- Main parsing routine
- """
- parser = ArgumentParser()
- parser.add_argument('-j', '--json', action='store_true',
- help='output the data as a JSON structure')
- parser.add_argument('-s', '--shell', action='store_true',
- help='output the data as a shell script (default)')
- parser.add_argument('--keeptabs', action='store_true',
- help='do not replace \\t (tabs) in the strings')
- parser.add_argument('Dockerfile')
- args = parser.parse_args()
-
- if args.Dockerfile != '-':
- with open(args.Dockerfile) as file:
- data = file.read().splitlines()
- else:
- data = stdin.read().splitlines()
-
- instre = re.compile(r'^\s*(\w+)\s+(.*)$')
- contre = re.compile(r'^.*\\\s*$')
- commentre = re.compile(r'^\s*#')
-
- instructions = []
- lineno = -1
- in_continuation = False
- cur_inst = {}
-
- for line in data:
- lineno += 1
- if commentre.match(line):
- continue
- if not in_continuation:
- rematch = instre.match(line)
- if not rematch:
- continue
- cur_inst = {
- 'instruction': rematch.groups()[0].upper(),
- 'value': rstrip_backslash(rematch.groups()[1]),
- }
- else:
- if cur_inst['value']:
- cur_inst['value'] += rstrip_backslash(line)
- else:
- cur_inst['value'] = rstrip_backslash(line.lstrip())
-
- in_continuation = contre.match(line)
- if not in_continuation and cur_inst is not None:
- if not args.keeptabs:
- cur_inst['value'] = cur_inst['value'].replace('\t', '')
- instructions.append(cur_inst)
-
- if args.json:
- print(json.dumps(instructions))
- return
-
- # Default to shell script output
- script = '#!/bin/sh\n'
- for i in instructions:
- script += parse_instruction(i, dfile=args.Dockerfile)
- print(script)
-
-
-if __name__ == '__main__':
- main()