268 lines
8.7 KiB
Python
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
|