2019-05-28 05:27:55 +00:00
|
|
|
@PYTHON@
|
|
|
|
# vim: set ts=4 et:
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
2020-05-21 17:45:05 +00:00
|
|
|
import json
|
|
|
|
import shutil
|
|
|
|
import argparse
|
2019-05-28 05:27:55 +00:00
|
|
|
from datetime import datetime, timedelta
|
2020-05-21 17:45:05 +00:00
|
|
|
|
2019-05-28 05:27:55 +00:00
|
|
|
from pyhocon import ConfigFactory
|
|
|
|
|
2020-05-21 17:45:05 +00:00
|
|
|
|
|
|
|
# Just group together our transforms
|
|
|
|
class Transforms:
|
|
|
|
|
|
|
|
NOW = datetime.utcnow()
|
|
|
|
TOMORROW = NOW + timedelta(days=1)
|
|
|
|
|
|
|
|
unquote = lambda x: x.strip('"')
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def force_iso_date(input):
|
|
|
|
return datetime.fromisoformat(input).isoformat(timespec="seconds")
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def resolve_tomorrow(cls, input):
|
|
|
|
return cls.TOMORROW.isoformat(timespec="seconds")
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def resolve_now(cls, input):
|
|
|
|
return cls.NOW.strftime("%Y%m%d%H%M%S")
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def fold_comma(cls, input):
|
|
|
|
return ",".join([cls.unquote(k) for k in input.keys()])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def fold_space(cls, input):
|
|
|
|
return " ".join([cls.unquote(k) for k in input.keys()])
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def fold_repos(cls, input):
|
|
|
|
return "\n".join(
|
|
|
|
f"@{v} {cls.unquote(k)}" if isinstance(v, str) else cls.unquote(k)
|
|
|
|
for k, v in input.items())
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def fold_packages(input):
|
|
|
|
return " ".join(
|
|
|
|
f"{k}@{v}" if isinstance(v, str) else k
|
|
|
|
for k, v in input.items())
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def fold_services(input):
|
|
|
|
return " ".join(
|
|
|
|
"{}={}".format(k, ",".join(v.keys()))
|
|
|
|
for k, v in input.items())
|
|
|
|
|
|
|
|
|
|
|
|
class ConfigBuilder:
|
|
|
|
|
|
|
|
_CFG_TRANSFORMS = {
|
|
|
|
"ami_access" : Transforms.fold_comma,
|
|
|
|
"ami_regions" : Transforms.fold_comma,
|
|
|
|
"kernel_modules" : Transforms.fold_comma,
|
|
|
|
"kernel_options" : Transforms.fold_space,
|
|
|
|
"repos" : Transforms.fold_repos,
|
|
|
|
"pkgs" : Transforms.fold_packages,
|
|
|
|
"svcs" : Transforms.fold_services,
|
|
|
|
"revision" : Transforms.resolve_now,
|
|
|
|
"end_of_life" : lambda x: \
|
|
|
|
Transforms.force_iso_date(Transforms.resolve_tomorrow(x)),
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, config_path, out_dir):
|
|
|
|
self.config_path = config_path
|
|
|
|
self.out_dir = out_dir
|
|
|
|
|
|
|
|
def build(self, profile):
|
|
|
|
build_config = ConfigFactory.parse_file(self.config_path)
|
|
|
|
|
|
|
|
for build, cfg in build_config["BUILDS"].items():
|
|
|
|
build_dir = os.path.join(self.out_dir, build)
|
|
|
|
|
|
|
|
# Always start fresh
|
|
|
|
shutil.rmtree(build_dir, ignore_errors=True)
|
|
|
|
os.makedirs(build_dir)
|
|
|
|
|
|
|
|
cfg["profile"] = profile
|
|
|
|
cfg["profile_build"] = build
|
|
|
|
|
|
|
|
# Order of operations is important here
|
|
|
|
for k, v in cfg.items():
|
|
|
|
transform = self._CFG_TRANSFORMS.get(k)
|
|
|
|
if transform:
|
|
|
|
cfg[k] = transform(v)
|
|
|
|
|
|
|
|
if isinstance(v, str) and "{var." in v:
|
|
|
|
cfg[k] = v.format(var=cfg)
|
|
|
|
|
|
|
|
with open(os.path.join(build_dir, "vars.json"), "w") as out:
|
|
|
|
json.dump(cfg, out, indent=4, separators=(",", ": "))
|
|
|
|
|
|
|
|
|
|
|
|
def find_repo_root():
|
|
|
|
path = os.getcwd()
|
|
|
|
|
|
|
|
while ".git" not in set(os.listdir(path)) and path != "/":
|
|
|
|
path = os.path.dirname(path)
|
|
|
|
|
|
|
|
if path == "/":
|
|
|
|
raise Exception("No repo found, stopping at /")
|
|
|
|
|
|
|
|
return path
|
|
|
|
|
|
|
|
|
|
|
|
def main(args):
|
|
|
|
parser = argparse.ArgumentParser(description="Build Packer JSON variable "
|
|
|
|
"files from HOCON build profiles")
|
|
|
|
parser.add_argument("profile", help="name of profile to build")
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
root = find_repo_root()
|
|
|
|
|
|
|
|
ConfigBuilder(
|
|
|
|
os.path.join(root, "profiles", f"{args.profile}.conf"),
|
|
|
|
os.path.join(root, "build", "profile", args.profile)
|
|
|
|
).build(args.profile)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main(sys.argv)
|