You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
182 lines
4.5 KiB
182 lines
4.5 KiB
#!/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()
|
|
|