Prototype for a meta package manager
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

#!/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()