python-pid/archive/repolib/command/add.py
2023-02-23 22:05:14 +02:00

268 lines
8.7 KiB
Python

#!/usr/bin/python3
"""
Copyright (c) 2022, Ian Santopietro
All rights reserved.
This file is part of RepoLib.
RepoLib is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
RepoLib is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with RepoLib. If not, see <https://www.gnu.org/licenses/>.
"""
from httplib2.error import ServerNotFoundError
from urllib.error import URLError
from .. import util
from ..source import Source, SourceError
from ..file import SourceFile, SourceFileError
from ..shortcuts import ppa, popdev, shortcut_prefixes
from .command import Command, RepolibCommandError
class Add(Command):
"""Add subcommand
Adds a new source into the system. Requests root, if not present.
Options:
--disable, d
--source-code, -s
--terse, -t
--name, -n
--identifier, -i
--format, -f
--skip-keys, -k
"""
@classmethod
def init_options(cls, subparsers):
""" Sets up the argument parser for this command.
Returns: argparse.subparser
The subparser for this command
"""
sub = subparsers.add_parser(
'add',
help='Add a new repository to the system'
)
sub.add_argument(
'deb_line',
nargs='*',
default=['822styledeb'],
help='The deb line of the repository to add'
)
sub.add_argument(
'-d',
'--disable',
action='store_true',
help='Add the repository and then set it to disabled.'
)
sub.add_argument(
'-s',
'--source-code',
action='store_true',
help='Also enable source code packages for the repository.'
)
sub.add_argument(
'-t',
'--terse',
action='store_true',
help='Do not display expanded info about a repository before adding it.'
)
sub.add_argument(
'-n',
'--name',
default='',
help='A name to set for the new repo'
)
sub.add_argument(
'-i',
'--identifier',
default='',
help='The filename to use for the new source'
)
sub.add_argument(
'-f',
'--format',
default='sources',
help='The source format to save as, `sources` or `list`'
)
sub.add_argument(
'-k',
'--skip-keys',
action='store_true',
help='Skip adding signing keys (not recommended!)'
)
return sub
def finalize_options(self, args):
super().finalize_options(args)
self.deb_line = ' '.join(args.deb_line)
self.terse = args.terse
self.source_code = args.source_code
self.disable = args.disable
self.log.debug(args)
try:
name = args.name.split()
except AttributeError:
name = args.name
try:
ident = args.identifier.split()
except AttributeError:
ident = args.identifier
self.name = ' '.join(name)
pre_ident:str = '-'.join(ident)
self.ident = util.scrub_filename(pre_ident)
self.skip_keys = args.skip_keys
self.format = args.format.lower()
def run(self) -> bool:
"""Run the command, return `True` if successful; otherwise `False`"""
if self.deb_line == '822styledeb':
self.parser.print_usage()
self.log.error('A repository is required')
return False
repo_is_url = self.deb_line.startswith('http')
repo_is_nospaced = len(self.deb_line.split()) == 1
if repo_is_url and repo_is_nospaced:
self.deb_line = f'deb {self.deb_line} {util.DISTRO_CODENAME} main'
print('Fetching repository information...')
self.log.debug('Adding line %s', self.deb_line)
new_source: Source = Source()
for prefix in shortcut_prefixes:
self.log.debug('Trying prefix %s', prefix)
if self.deb_line.startswith(prefix):
self.log.debug('Line is prefix: %s', prefix)
new_source = shortcut_prefixes[prefix]()
if not new_source.validator(self.deb_line):
self.log.error(
'The shortcut "%s" is malformed',
self.deb_line
)
# Try and get a suggested correction for common errors
try:
if self.deb_line[len(prefix)] != ':':
fixed_debline: str = self.deb_line.replace(
self.deb_line[len(prefix)],
":",
1
)
print(f'Did you mean "{fixed_debline}"?')
except IndexError:
pass
return False
try:
new_source.load_from_data([self.deb_line])
except (URLError, ServerNotFoundError) as err:
import traceback
self.log.debug(
'Exception info: %s \n %s \n %s',
type(err),
''.join(traceback.format_exception(err)),
err.args
)
self.log.error(
'System is offline. A connection is required to add '
'PPA and Popdev sources.'
)
return False
except Exception as err:
import traceback
self.log.debug(
'Exception info: %s \n %s \n %s',
type(err),
err.__traceback__,
err
)
self.log.error('An error ocurred: %s', err)
return False
break
if not new_source:
self.log.error(
f'Could not parse line "{self.deb_line}". Double-check the '
'spelling.'
)
valid_shortcuts: str = ''
for shortcut in shortcut_prefixes:
if shortcut.startswith('deb'):
continue
valid_shortcuts += f'{shortcut}, '
valid_shortcuts = valid_shortcuts.strip(', ')
print(f'Supported repository shortcuts:\n {valid_shortcuts}')
return False
new_source.twin_source = True
new_source.sourcecode_enabled = self.source_code
if self.name:
new_source.name = self.name
if self.ident:
new_source.ident = self.ident
if self.disable:
new_source.enabled = False
if not new_source.ident:
new_source.ident = new_source.generate_default_ident()
new_file = SourceFile(name=new_source.ident)
new_file.format = new_source.default_format
if self.format:
self.log.info('Setting new source format to %s', self.format)
for format in util.SourceFormat:
if self.format == format.value:
new_file.format = format
self.log.debug('New source format set to %s', format.value)
new_file.add_source(new_source)
new_source.file = new_file
self.log.debug('File format: %s', new_file.format)
self.log.debug('File path: %s', new_file.path)
self.log.debug('Sources in file %s:\n%s', new_file.path, new_file.sources)
if not self.terse:
print(
'Adding the following source: \n',
new_source.get_description(),
'\n\n',
new_source.ui
)
try:
input(
'Press ENTER to continue adding this source or Ctrl+C '
'to cancel'
)
except KeyboardInterrupt:
# Handled here to avoid printing the exception to console
exit(0)
new_file.save()
util.dbus_quit()
return True