Source code for univention.updater.scripts.repo_update

#!/usr/bin/python3
# SPDX-FileCopyrightText: 2004-2025 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""Update a local repository."""


import errno
import os
import shutil
import sys
import time
from argparse import ArgumentParser, Namespace
from textwrap import dedent, wrap

import univention.updater.repository as urepo
from univention.config_registry import ConfigRegistry, handler_commit, handler_set
from univention.lib.ucs import UCS_Version
from univention.updater.errors import UpdaterException, VerificationError
from univention.updater.locking import UpdaterLock
from univention.updater.mirror import UniventionMirror, makedirs


configRegistry = ConfigRegistry()
configRegistry.load()

# base directory for local repository
_mirror_base = configRegistry.get('repository/mirror/basepath', '/var/lib/univention-repository')
# directory of current version's repository
_current_version = '%s-%s' % (configRegistry.get('version/version'), configRegistry.get('version/patchlevel'))
_repo_base = os.path.join(_mirror_base, 'mirror', configRegistry.get('version/version'), 'maintained', '%s-0' % configRegistry.get('version/version'))


[docs] def copy_repository(options: Namespace, source: str, version: UCS_Version) -> None: """Copy packages and scripts belonging to version from source directory into local repository""" print('Please be patient, copying packages ...', end=' ') sys.stdout.flush() dest_repo = os.path.join(_mirror_base, 'mirror', '%(major)s.%(minor)s/maintained/%(major)s.%(minor)s-%(patchlevel)s' % version) # check if repository already exists if os.path.isdir(os.path.join(dest_repo)): print('\nWarning: repository for UCS version %(major)s.%(minor)s-%(patchlevel)s already exists' % version) else: # create directory structure for arch in urepo.ARCHITECTURES: makedirs(os.path.join(dest_repo, arch)) # copy packages to new directory structure urepo.copy_package_files(source, dest_repo) # create Packages files print('Packages ...', end=' ') urepo.gen_indexes(dest_repo, version) print('Scripts ...', end=' ') for script in ('preup.sh', 'preup.sh.gpg', 'postup.sh', 'postup.sh.gpg'): if os.path.exists(os.path.join(source, script)): shutil.copy2(os.path.join(source, script), os.path.join(dest_repo, 'all', script)) print('Done.')
[docs] def update_net(options: Namespace) -> None: """Copy packages and scripts from remote mirror into local repository""" mirror = UniventionMirror() # update local repository if available urepo.assert_local_repository() # mirror.run calls "apt-mirror", which needs /etc/apt/mirror.conf, which is # only generated with repository/mirror=true if not configRegistry.is_true('repository/mirror', False): print('Error: Mirroring for the local repository is disabled. Set the Univention Configuration Registry variable repository/mirror to yes.') sys.exit(1) # create mirror_base and symbolic link "univention-repository" if missing destdir = os.path.join(configRegistry.get('repository/mirror/basepath', '/var/lib/univention-repository'), 'mirror') makedirs(destdir) try: os.symlink('.', os.path.join(destdir, 'univention-repository')) except OSError as e: if e.errno != errno.EEXIST: raise if options.sync: # only update packages of current repositories mirror.run() elif options.errata_only: # trigger update to find new errata repositories handler_commit(['/etc/apt/mirror.list']) mirror.run() elif options.update_to: # trigger update to explicitly mirror until given versions handler_set(['repository/mirror/version/end=%s' % options.update_to]) mirror = UniventionMirror() mirror.run() else: # mirror all future versions handler_commit(['/etc/apt/mirror.list']) nextupdate = mirror.release_update_available() mirror_run = False while nextupdate: handler_set(['repository/mirror/version/end=%s' % nextupdate]) # UCR variable repository/mirror/version/end has change - reinit Mirror object mirror = UniventionMirror() mirror.run() mirror_run = True nextupdate = mirror.release_update_available(nextupdate) if not mirror_run: # sync only mirror.run()
[docs] def parse_args() -> Namespace: parser = ArgumentParser(description=__doc__) parser.add_argument( '-s', '--sync-only', action='store_true', dest='sync', help='if given no new release repositories will be added, just the existing will be updated') parser.add_argument( '-E', '--errata-only', action='store_true', help='if given only errata repositories will be updated') parser.add_argument( '-u', '--updateto', dest='update_to', default='', help='if given the repository is updated to the specified version but not higher') parser.add_argument( "command", choices=("net", ), help="Update command") return parser.parse_args()
[docs] def main() -> None: # PATH does not contain */sbin when called from cron os.putenv('PATH', '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin') options = parse_args() print('***** Starting univention-repository-update at %s\n' % time.ctime()) urepo.assert_local_repository() with UpdaterLock(): if options.command == 'net': local_server = '%(hostname)s.%(domainname)s' % configRegistry # BUG: The localhost has many names, FQDNs and addresses ... if configRegistry['repository/mirror/server'] == local_server: print('Error: The local server is configured as mirror source server (repository/mirror/server)') sys.exit(1) try: update_net(options) except VerificationError as ex: print("Error: %s" % (ex,)) print('\n'.join(wrap(dedent( """\ This can and should only be disabled temporarily using the UCR variable 'repository/mirror/verify'. """, )))) sys.exit(1) except UpdaterException as e: print("Error: %s" % e) sys.exit(1)
if __name__ == '__main__': main()