95 lines
3.1 KiB
Python
95 lines
3.1 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import json
|
||
|
import os
|
||
|
import shutil
|
||
|
import sys
|
||
|
from typing import Optional
|
||
|
from typing_extensions import Self
|
||
|
import zipfile
|
||
|
|
||
|
class Output:
|
||
|
def make_directory(self, name: str) -> Self:
|
||
|
pass
|
||
|
|
||
|
def include_file(self, source_path: str, dest_path: str):
|
||
|
pass
|
||
|
|
||
|
def create_zip(self, name: str) -> Self:
|
||
|
pass
|
||
|
|
||
|
def done(self):
|
||
|
pass
|
||
|
|
||
|
class ZipOutput(Output):
|
||
|
def __init__(self, zf: zipfile.ZipFile, inner_prefix: Optional[str] = None):
|
||
|
self._zf = zf
|
||
|
self._inner_prefix = inner_prefix
|
||
|
|
||
|
def make_directory(self, name: str) -> Self:
|
||
|
print(f'Making directory `{name}` in `{self._inner_prefix}` inside zip file')
|
||
|
return ZipOutput(self._zf, name if self._inner_prefix is None else os.path.join(self._inner_prefix, name))
|
||
|
|
||
|
def include_file(self, source_path: str, dest_path: str):
|
||
|
if self._inner_prefix is not None:
|
||
|
dest_path = os.path.join(self._inner_prefix, dest_path)
|
||
|
print(f'Adding file to zip: `{source_path}` as `{dest_path}`')
|
||
|
self._zf.write(source_path, dest_path)
|
||
|
|
||
|
def create_zip(self, name: str):
|
||
|
raise RuntimeError('cannot currently create a zip within a zip')
|
||
|
|
||
|
def done(self):
|
||
|
self._zf.close()
|
||
|
|
||
|
class DirectoryOutput(Output):
|
||
|
def __init__(self, target_dir: str) -> None:
|
||
|
self._target_dir = target_dir
|
||
|
if not os.path.exists(target_dir):
|
||
|
os.makedirs(target_dir)
|
||
|
|
||
|
def make_directory(self, name: str) -> Self:
|
||
|
return DirectoryOutput(os.path.join(self._target_dir, name))
|
||
|
|
||
|
def include_file(self, source_path: str, dest_path: str):
|
||
|
shutil.copy2(source_path, os.path.join(self._target_dir, dest_path))
|
||
|
|
||
|
def create_zip(self, name: str) -> Self:
|
||
|
return ZipOutput(zipfile.ZipFile(os.path.join(self._target_dir, name), 'w'))
|
||
|
|
||
|
def create_object(output: Output, obj: dict[str, any]):
|
||
|
if 'type' not in obj:
|
||
|
raise KeyError(f'`type` not found in `{obj}`')
|
||
|
if 'name' not in obj:
|
||
|
raise KeyError(f'`name` not found in `{obj}`')
|
||
|
ty = obj['type']
|
||
|
name = obj['name']
|
||
|
if ty == 'zip' or ty == 'directory':
|
||
|
if 'content' not in obj:
|
||
|
raise KeyError(f'`content` not found in `{obj}`')
|
||
|
sub_output = output.create_zip(name) if ty == 'zip' else output.make_directory(name)
|
||
|
for item in obj['content']:
|
||
|
create_object(sub_output, item)
|
||
|
elif ty == 'file':
|
||
|
if 'source' not in obj:
|
||
|
raise KeyError(f'`source` not found in `{obj}`')
|
||
|
source = obj['source']
|
||
|
output.include_file(source, name)
|
||
|
else:
|
||
|
raise ValueError(f'Unknown type: `{ty}`')
|
||
|
|
||
|
def main(args: list[str]):
|
||
|
if len(args) < 2:
|
||
|
print(f'Usage: {sys.argv[0]} <config>')
|
||
|
exit(1)
|
||
|
|
||
|
with open(sys.argv[1]) as f:
|
||
|
config = json.load(f)
|
||
|
|
||
|
print('Generating...')
|
||
|
create_object(DirectoryOutput('target/'), config)
|
||
|
print('Done!')
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main(sys.argv)
|