-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpacker2.py
130 lines (112 loc) · 4.05 KB
/
packer2.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/python3
import hashlib
import json
import os
from os.path import isdir, isfile
import sys
import platform
import argparse
import subprocess as sp
from typing import NamedTuple
import shutil
import logging as log
import copy
def sha256(fpath):
BYTES_MAGIC = 65536
sha = hashlib.sha256()
if os.path.isdir(fpath): # HACK: since we declare an output directory, but sometimes give files (http_file)
fpath = fpath + os.path.sep + os.path.basename(fpath)
with open(fpath, "rb") as f:
d = f.read(BYTES_MAGIC)
while len(d) > 0:
sha.update(d)
d = f.read(BYTES_MAGIC)
return sha.hexdigest()
class Config(NamedTuple):
"""config for the python packer runner to set up packer invocation and overwrite"""
overwrite: bool
packerfile: str
out_dir: str
var_file: str
cli_vars: dict[str, str]
packer_path: str
sha256_var_name: str
iso_img_loc: str
@staticmethod
def from_json(args):
# this try-except is to allow for parsing only the top-level object
# inner objects are not parsed into a class
try:
return Config(**args)
except TypeError:
return args
def cli(self):
cmd = [self.packer_path,
"build",
"-force" if self.overwrite else None,
"-var-file=" + self.var_file if self.var_file else None,
"-var " + self.sha256_var_name + "=" + sha256(self.iso_img_loc) if self.sha256_var_name else None,
*["-var " + '"' + k + '=' + v + '"' for k, v in self.cli_vars.items()],
self.packerfile]
return list(filter(lambda x: x is not None, cmd))
def parse_input_json(json_path):
ret = None
with open(os.path.abspath(json_path), "rb") as f:
input = f.read()
ret = json.loads(input, object_hook=Config.from_json)
return ret
def deal_with_existing_out_dir(path):
# deal with output directory
if os.path.exists(path):
log.debug("output dir exists, removing contents of " + path)
f_contents = os.listdir(path)
if len(f_contents) == 0:
log.debug("folder empty, removing folder")
os.rmdir(path)
else:
if config.overwrite:
for root, dirs, files in os.walk(path):
print(root)
print(dirs)
print(files)
raise NotImplementedError("with files existsing is not implemented")
else:
raise NotImplementedError("not implemented for non-overwrite")
pass # some clever sha thing? or just never run packer
def find_system_qemu(tgt_arch):
# simple case, qemu_system_{tgt-arch} exists on $PATH
qemu_search = "qemu-system-" + tgt_arch
qemu = shutil.which(qemu_search)
if qemu is None:
system = platform.system().lower()
if system == "linux":
qemu = shutil.which(qemu_search, path = "/bin:/usr/bin:/usr/local/bin")
elif system == "macos":
raise NotImplementedError("TODO")
if qemu is None:
raise RuntimeError("cannot find " + qemu_search)
return qemu
def invoke_packer(config, qemu_path):
log.debug("calling: " + str(config.cli()))
path = os.environ.get("PATH")
if path is None:
path = qemu_path
else:
path = path + ":" + qemu_path
env = dict(copy.deepcopy(os.environ))
env.update({"PATH": path, "PWD": os.getcwd()})
log.debug("with PATH: " + path)
log.debug("with ENV: " + str(env))
proc = sp.run(' '.join(config.cli()), shell = True, env = env, cwd = os.getcwd())
return proc
if __name__ == "__main__":
log.basicConfig(level=log.DEBUG)
parser = argparse.ArgumentParser()
parser.add_argument("config")
args = parser.parse_args()
config = parse_input_json(args.config)
qemu_name = find_system_qemu(platform.processor())
qemu_path = os.path.dirname(qemu_name)
deal_with_existing_out_dir(config.out_dir)
packer = invoke_packer(config, qemu_path)
sys.exit(packer.returncode)