1 changed files with 182 additions and 0 deletions
@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python3 |
||||
from datetime import datetime, timezone |
||||
from pathlib import Path |
||||
from typing import Optional |
||||
import argparse |
||||
import logging |
||||
import os |
||||
import pwd |
||||
|
||||
logging.basicConfig( |
||||
level=logging.INFO, |
||||
format='%(levelname)s: %(message)s', |
||||
) |
||||
logger = logging.getLogger(__name__) |
||||
|
||||
|
||||
def _get_username(): |
||||
return pwd.getpwuid(os.getuid()).pw_name |
||||
|
||||
|
||||
# The recfile descriptor for package requests. |
||||
# Used if Breadpack generates the file from scratch. |
||||
REQUEST_DESCRIPTOR = """ |
||||
%rec: PackageRequest |
||||
%type: Date date |
||||
%type: Processed bool |
||||
%type: User line |
||||
%type: Package line |
||||
%mandatory: Package |
||||
%allowed: Date User Processed Package Comment |
||||
%sort: Processed Date |
||||
%doc: Package requests made via breadpack |
||||
""".strip() |
||||
|
||||
|
||||
def request_subcommand( |
||||
requestsfile: Path, |
||||
package_name: str, |
||||
comment: Optional[str] = None, |
||||
**kwargs): |
||||
if not requestsfile.exists(): |
||||
logger.warning(f'Creating file {requestsfile}') |
||||
with requestsfile.open('w') as f: |
||||
f.write(REQUEST_DESCRIPTOR) |
||||
|
||||
data = { |
||||
'Date': datetime.now(timezone.utc).isoformat(), |
||||
'User': _get_username(), |
||||
'Processed': 'no', |
||||
'Package': package_name, |
||||
} |
||||
if comment: |
||||
data['Comment'] = comment |
||||
|
||||
with requestsfile.open('a') as f: |
||||
f.write('\n\n' + '\n'.join([f'{k}: {v}' for k, v in data.items()])) |
||||
|
||||
logger.info(f'Your request for {package_name!r} has been sent!') |
||||
|
||||
|
||||
def list_subcommand(json: bool = False, upgradable: bool = False, **kwargs): |
||||
raise NotImplementedError |
||||
|
||||
|
||||
def lint_subcommand(file, **kwargs): |
||||
raise NotImplementedError |
||||
|
||||
|
||||
def check_subcommand(json: bool = False, save: bool = True, **kwargs): |
||||
raise NotImplementedError |
||||
|
||||
|
||||
def lock_subcommand(**kwargs): |
||||
raise NotImplementedError |
||||
|
||||
|
||||
def main(): |
||||
parser = argparse.ArgumentParser( |
||||
description='Breadpunk.club meta-package manager' |
||||
) |
||||
parser.add_argument( |
||||
'--file', |
||||
type=Path, |
||||
help='Path to the breadpack.json file.', |
||||
default=Path('/bread/breadpack.json'), |
||||
) |
||||
parser.add_argument( |
||||
'--lockfile', |
||||
type=Path, |
||||
help='Path to the breadpack-lock.json file.', |
||||
default=Path('/bread/breadpack-lock.json'), |
||||
) |
||||
parser.add_argument( |
||||
'--requestsfile', |
||||
type=Path, |
||||
help='Path to the breadpack-requests.rec file.', |
||||
default=Path('/bread/breadpack-requests.rec'), |
||||
) |
||||
|
||||
def nocommand(**kwargs): |
||||
parser.error('A subcommand is required.') |
||||
|
||||
parser.set_defaults(func=nocommand) |
||||
subparsers = parser.add_subparsers( |
||||
title='subcommands', |
||||
) |
||||
|
||||
request_parser = subparsers.add_parser( |
||||
'request', |
||||
help='Request for a new package to be installed.', |
||||
) |
||||
request_parser.add_argument( |
||||
'package_name', |
||||
help='Name of the requested package.', |
||||
) |
||||
request_parser.add_argument( |
||||
'-c', '--comment', |
||||
help='Optional comment to add notes ' |
||||
'for the admin processing your request.', |
||||
default=None, |
||||
) |
||||
request_parser.set_defaults(func=request_subcommand) |
||||
|
||||
list_parser = subparsers.add_parser( |
||||
'list', |
||||
help='List installed packages.', |
||||
) |
||||
list_parser.add_argument( |
||||
'--json', |
||||
help='Use JSON output.', |
||||
action='store_true', |
||||
default=False, |
||||
) |
||||
list_parser.add_argument( |
||||
'--upgradable', |
||||
help='Only list packages with available updates.', |
||||
action='store_true', |
||||
default=False, |
||||
) |
||||
list_parser.set_defaults(func=list_subcommand) |
||||
|
||||
lint_parser = subparsers.add_parser( |
||||
'lint', |
||||
help='Check the syntax of the packages file and lockfile.', |
||||
) |
||||
lint_parser.set_defaults(func=lint_subcommand) |
||||
|
||||
lock_parser = subparsers.add_parser( |
||||
'lock', |
||||
help='Regenerate the lockfile from scratch.', |
||||
) |
||||
lock_parser.set_defaults(func=lock_subcommand) |
||||
|
||||
check_parser = subparsers.add_parser( |
||||
'check', |
||||
help='Check for available updates.', |
||||
) |
||||
check_parser.add_argument( |
||||
'--json', |
||||
help='Use JSON output.', |
||||
action='store_true', |
||||
default=False, |
||||
) |
||||
check_parser.add_argument( |
||||
'--save', |
||||
help='Update the lockfile. This is the default.', |
||||
action='store_true', |
||||
default=True, |
||||
) |
||||
check_parser.add_argument( |
||||
'--no-save', |
||||
help='Do not update the lockfile.', |
||||
action='store_false', |
||||
dest='save', |
||||
) |
||||
|
||||
args = vars(parser.parse_args()) |
||||
args.pop('func', nocommand)(**args) |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
main() |
Loading…
Reference in new issue