Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package opi for openSUSE:Factory checked in at 2023-07-28 22:20:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/opi (Old) and /work/SRC/openSUSE:Factory/.opi.new.32662 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "opi" Fri Jul 28 22:20:37 2023 rev:46 rq:1101179 version:3.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/opi/opi.changes 2023-07-13 17:18:59.581274666 +0200 +++ /work/SRC/openSUSE:Factory/.opi.new.32662/opi.changes 2023-07-28 22:20:41.105315708 +0200 @@ -1,0 +2,8 @@ +Fri Jul 28 10:01:44 UTC 2023 - Dominik Heidler <dheid...@suse.de> + +- Version 3.3.0 +- Add tests and tweak weighting algorithm for non interactive mode +- Allow running without user interaction +- Add config option to disable auto refresh + +------------------------------------------------------------------- Old: ---- opi-3.2.0.tar.gz New: ---- opi-3.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ opi.spec ++++++ --- /var/tmp/diff_new_pack.xDyZfk/_old 2023-07-28 22:20:41.869320352 +0200 +++ /var/tmp/diff_new_pack.xDyZfk/_new 2023-07-28 22:20:41.881320425 +0200 @@ -17,7 +17,7 @@ Name: opi -Version: 3.2.0 +Version: 3.3.0 Release: 0 Summary: OBS Package Installer (CLI) License: GPL-3.0-only ++++++ opi-3.2.0.tar.gz -> opi-3.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/bin/opi new/opi-3.3.0/bin/opi --- old/opi-3.2.0/bin/opi 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/bin/opi 2023-07-28 12:01:38.000000000 +0200 @@ -5,12 +5,14 @@ import re import argparse import textwrap +import subprocess from termcolor import colored sys.path.insert(0, os.path.abspath(os.path.dirname(__file__) + '/..')) import opi from opi.plugins import PluginManager from opi.version import __version__ +from opi.state import global_state class PreserveWhiteSpaceWrapRawTextHelpFormatter(argparse.RawTextHelpFormatter): @@ -55,6 +57,7 @@ If multiple query arguments are provided only results matching all of them are returned. ''')) ap.add_argument('-v', '--version', action='version', version=f'opi version {__version__}') + ap.add_argument('-n', dest='non_interactive', action='store_true', help="Run in non interactive mode") args = ap.parse_args() @@ -62,6 +65,13 @@ ap.print_help() sys.exit() + if args.non_interactive: + global_state.arg_non_interactive = True + if subprocess.run(['sudo', '-n', 'true']).returncode != 0: + print('Error: In non-interactive mode this command must be run as root') + print(' or sudo must not require interaction.') + sys.exit(1) + # Try to find a matching plugin for the query (and run it and exit afterwards) pm.run(args.query[0]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi/__init__.py new/opi-3.3.0/opi/__init__.py --- old/opi-3.2.0/opi/__init__.py 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/opi/__init__.py 2023-07-28 12:01:38.000000000 +0200 @@ -16,6 +16,7 @@ from opi.backends import get_backend, BackendConstants from opi import pager from opi import config +from opi.state import global_state OBS_APIROOT = { 'openSUSE': 'https://api.opensuse.org', @@ -94,7 +95,7 @@ filename = 'packman', name = 'Packman', url = f'https://ftp.gwdg.de/pub/linux/misc/packman/suse/{project}/', - auto_refresh = True, + auto_refresh = config.get_key_from_config('new_repo_auto_refresh'), priority = 90 ) @@ -118,7 +119,7 @@ name = repo, url = url, gpgkey = f"{url.replace('http://', 'https://')}repodata/repomd.xml.key", - auto_refresh = True, + auto_refresh = config.get_key_from_config('new_repo_auto_refresh'), priority = 90 ) @@ -191,6 +192,7 @@ 'filename': re.sub(r'\.repo$', '', repo_file), 'name': cp[mainsec].get('name', mainsec), 'url': cp[mainsec].get('baseurl'), + 'auto_refresh': bool(int(cp[mainsec].get('autorefresh', '0'))), } if cp.has_option(mainsec, 'gpgkey'): repo['gpgkey'] = cp[mainsec].get('gpgkey') @@ -203,7 +205,7 @@ if url_normalize(repo['url']) == url_normalize(url): return repo -def add_repo(filename, name, url, enabled=True, gpgcheck=True, gpgkey=None, repo_type='rpm-md', auto_import_key=False, auto_refresh=False, priority=None): +def add_repo(filename, name, url, enabled=True, gpgcheck=True, gpgkey=None, repo_type='rpm-md', auto_import_keys=False, auto_refresh=False, priority=None): tf = tempfile.NamedTemporaryFile('w') tf.file.write(f'[{filename}]\n') tf.file.write(f'name={name}\n') @@ -222,14 +224,19 @@ subprocess.call(['sudo', 'cp', tf.name, os.path.join(REPO_DIR, f'{filename}.repo')]) subprocess.call(['sudo', 'chmod', '644', os.path.join(REPO_DIR, f'{filename}.repo')]) tf.file.close() + refresh_repos(auto_import_keys=auto_import_keys) + +def refresh_repos(repo=None, auto_import_keys=False): refresh_cmd = [] if get_backend() == BackendConstants.zypp: refresh_cmd = ['sudo', 'zypper'] - if auto_import_key: + if auto_import_keys: refresh_cmd.append('--gpg-auto-import-keys') refresh_cmd.append('ref') elif get_backend() == BackendConstants.dnf: refresh_cmd = ['sudo', 'dnf', 'ref'] + if repo: + refresh_cmd.append(repo) subprocess.call(refresh_cmd) def normalize_key(pem): @@ -272,11 +279,17 @@ def pkgmgr_action(action, packages=[], from_repo=None, allow_vendor_change=False, allow_arch_change=False, allow_downgrade=False, allow_name_change=False): if get_backend() == BackendConstants.zypp: - args = ['sudo', 'zypper', action] + args = ['sudo', 'zypper'] + if global_state.arg_non_interactive: + args.append('-n') + args.append(action) if from_repo: args.extend(['--from', from_repo]) elif get_backend() == BackendConstants.dnf: - args = ['sudo', 'dnf', action] + args = ['sudo', 'dnf'] + if global_state.arg_non_interactive: + args.append('-y') + args.append(action) if from_repo: args.extend(['--repo', from_repo]) if get_backend() == BackendConstants.zypp: @@ -396,21 +409,22 @@ def get_binary_weight(binary): weight = 0 + + dash_count = binary['name'].count('-') + weight += 1e5 * (0.5 ** dash_count) + + weight -= 1e4 * len(binary['name']) + if is_official_project(binary['project']): - weight += 200000 + weight += 2e3 elif not is_personal_project(binary['project']): - weight += 100000 + weight += 1e3 if binary['name'] == binary['package']: - weight += 10000 - - dash_count = binary['name'].count('-') - weight += 1000 * (0.5 ** dash_count) + weight += 1e2 if not (get_cpu_arch() == 'x86_64' and binary['arch'] == 'i586'): - weight += 100 - - weight -= 10 * len(binary['name']) + weight += 1e1 if binary['repository'].startswith('openSUSE_Tumbleweed'): weight += 2 @@ -459,6 +473,9 @@ if existing_repo: # Install from existing repos (don't add a repo) print(f"Installing from existing repo '{existing_repo['name']}'") + # ensure that this repo is up to date if no auto_refresh is configured + if not existing_repo['auto_refresh']: + refresh_repos(existing_repo['alias']) install_packages([name_with_arch], from_repo=existing_repo['alias']) else: print(f"Adding repo '{project}'") @@ -468,7 +485,7 @@ url = url, gpgkey = gpgkey, gpgcheck = True, - auto_refresh = True + auto_refresh = config.get_key_from_config('new_repo_auto_refresh') ) install_packages([name_with_arch], from_repo=repo_alias, allow_downgrade=True, @@ -490,7 +507,11 @@ else: q += '(y/N)' q += ' ' - answer = input(q) or default_answer + if global_state.arg_non_interactive: + print(q) + answer = default_answer + else: + answer = input(q) or default_answer return answer.strip().lower() == 'y' def ask_for_option(options, question='Pick a number (0 to quit):', option_filter=lambda a: a, disable_pager=False): @@ -521,7 +542,10 @@ numbered_options.append(numbered_option) i += 1 text = '\n'.join(numbered_options) - if not sys.stdout.isatty() or len(numbered_options) < (os.get_terminal_size().lines - 1) or disable_pager: + if global_state.arg_non_interactive: + input_string = '1' # default to first option in the list + print(f"{text}\n{question} {input_string}") + elif not sys.stdout.isatty() or len(numbered_options) < (os.get_terminal_size().lines - 1) or disable_pager: # no pager needed print(text) input_string = input(question + ' ') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi/config/__init__.py new/opi-3.3.0/opi/config/__init__.py --- old/opi-3.2.0/opi/config/__init__.py 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/opi/config/__init__.py 2023-07-28 12:01:38.000000000 +0200 @@ -3,7 +3,8 @@ default_config = { 'backend': 'zypp', - 'use_releasever_var': True + 'use_releasever_var': True, + 'new_repo_auto_refresh': True, } class ConfigError(Exception): @@ -21,6 +22,7 @@ ocfg = cp['opi'] config_cache.update({ 'backend': ocfg.get('backend'), - 'use_releasever_var': ocfg.getboolean('use_releasever_var') + 'use_releasever_var': ocfg.getboolean('use_releasever_var'), + 'new_repo_auto_refresh': ocfg.getboolean('new_repo_auto_refresh'), }) return config_cache[key] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi/state.py new/opi-3.3.0/opi/state.py --- old/opi-3.2.0/opi/state.py 1970-01-01 01:00:00.000000000 +0100 +++ new/opi-3.3.0/opi/state.py 2023-07-28 12:01:38.000000000 +0200 @@ -0,0 +1,14 @@ +class GlobalState: + default_state = { + 'arg_non_interactive': False, + } + state = { + } + + def __setattr__(self, key, value): + type(self).state[key] = value + + def __getattr__(self, key): + return type(self).state.get(key, type(self).default_state[key]) + +global_state = GlobalState() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi/version.py new/opi-3.3.0/opi/version.py --- old/opi-3.2.0/opi/version.py 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/opi/version.py 2023-07-28 12:01:38.000000000 +0200 @@ -1 +1 @@ -__version__ = '3.2.0' +__version__ = '3.3.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi.changes new/opi-3.3.0/opi.changes --- old/opi-3.2.0/opi.changes 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/opi.changes 2023-07-28 12:01:38.000000000 +0200 @@ -1,4 +1,12 @@ ------------------------------------------------------------------- +Fri Jul 28 10:01:21 UTC 2023 - Dominik Heidler <dheid...@suse.de> + +- Version 3.3.0 +- Add tests and tweak weighting algorithm for non interactive mode +- Allow running without user interaction +- Add config option to disable auto refresh + +------------------------------------------------------------------- Thu Jul 13 09:12:57 UTC 2023 - Dominik Heidler <dheid...@suse.de> - Version 3.2.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/opi.default.cfg new/opi-3.3.0/opi.default.cfg --- old/opi-3.2.0/opi.default.cfg 2023-07-13 11:13:04.000000000 +0200 +++ new/opi-3.3.0/opi.default.cfg 2023-07-28 12:01:38.000000000 +0200 @@ -1,3 +1,4 @@ [opi] backend = zypp use_releasever_var = true +new_repo_auto_refresh = true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/opi-3.2.0/test/06_install_non_interactive.py new/opi-3.3.0/test/06_install_non_interactive.py --- old/opi-3.2.0/test/06_install_non_interactive.py 1970-01-01 01:00:00.000000000 +0100 +++ new/opi-3.3.0/test/06_install_non_interactive.py 2023-07-28 12:01:38.000000000 +0200 @@ -0,0 +1,34 @@ +#!/usr/bin/python3 + +import sys +import pexpect +import subprocess + +c = pexpect.spawn('./bin/opi -n html2text', logfile=sys.stdout.buffer, echo=False) + +c.expect(r'([0-9]+)\. html2text', timeout=10) +c.expect('Pick a number') +c.expect(r'([0-9]+)\. [^ ]*(openSUSE-Tumbleweed-Oss|Main Repository)', timeout=10) +c.expect('Installing from existing repo', timeout=10) +c.expect('Continue?', timeout=10) +c.interact() +c.wait() +c.close() +print() +assert c.exitstatus == 0, f'Exit code: {c.exitstatus}' +subprocess.check_call(['rpm', '-qi', 'html2text']) + + +c = pexpect.spawn('./bin/opi -n zfs', logfile=sys.stdout.buffer, echo=False) + +c.expect(r'([0-9]+)\. zfs', timeout=10) +c.expect('Pick a number') +c.expect(r'([0-9]+)\. [^ ]*(filesystems)', timeout=10) +c.expect('Adding repo \'filesystems\'', timeout=10) +c.expect('Continue?', timeout=10) +c.interact() +c.wait() +c.close() +print() +assert c.exitstatus == 0, f'Exit code: {c.exitstatus}' +subprocess.check_call(['rpm', '-qi', 'zfs'])