From 25ed213daaa896814d4979d3de3ec39c683d916b Mon Sep 17 00:00:00 2001 From: navigator Date: Fri, 20 Mar 2026 22:43:26 +0000 Subject: [PATCH 1/4] chore: migrate Python to 3.13 Automated migration by tkl-migrator - pyupgrade --py313-plus - autopep8 formatting - AI-assisted fixes for complex issues - Shebang updates --- cliwrapper.py | 6 ++++-- cmd.py | 11 +++++++---- cmd_backup.py | 2 +- cmd_escrow.py | 2 +- cmd_init.py | 2 +- cmd_internal.py | 10 ++++++---- cmd_internals/cmd_create_profile.py | 2 +- cmd_internals/cmd_delete.py | 2 +- cmd_internals/cmd_detect_profile_id.py | 2 +- cmd_internals/cmd_dirindex.py | 2 +- cmd_internals/cmd_fixstat.py | 2 +- cmd_internals/cmd_fs2mysql.py | 2 +- cmd_internals/cmd_fs2pgsql.py | 13 ++++++++----- cmd_internals/cmd_merge_userdb.py | 2 +- cmd_internals/cmd_mysql2fs.py | 2 +- cmd_internals/cmd_newpkgs.py | 2 +- cmd_internals/cmd_newpkgs_install.py | 2 +- cmd_internals/cmd_pgsql2fs.py | 15 +++++++++------ cmd_internals/cmd_stsagent.py | 2 +- cmd_list.py | 2 +- cmd_passphrase.py | 2 +- cmd_restore.py | 2 +- cmd_restore_rollback.py | 2 +- cmd_status.py | 2 +- passphrase.py | 6 ++++-- pathmap.py | 7 ++++--- pkgman.py | 26 ++++++++++++++++++-------- retry.py | 3 ++- tests/fmtbin.py | 2 ++ tests/resume.py | 2 +- userdb.py | 23 ++++++++++++++++------- utils.py | 17 ++++++++++++++--- version.py | 26 ++++++++++++++++++-------- 33 files changed, 132 insertions(+), 73 deletions(-) diff --git a/cliwrapper.py b/cliwrapper.py index b1cd830..ff42352 100644 --- a/cliwrapper.py +++ b/cliwrapper.py @@ -13,6 +13,7 @@ import sys import imp + class _Commands(dict): @staticmethod def _list_commands(paths): @@ -37,6 +38,7 @@ def __init__(self, path): for command in self._list_commands(path): self[command] = self._get_internals_module(command, path) + class CliWrapper: DESCRIPTION = "" PATH = None @@ -55,7 +57,7 @@ def _usage(cls, commands, e=None): command_names = commands.keys() command_names.sort() - maxlen = max([ len(name) for name in command_names ]) + 2 + maxlen = max([len(name) for name in command_names]) + 2 tpl = " %%-%ds %%s" % (maxlen) def shortdesc(command): @@ -68,7 +70,7 @@ def shortdesc(command): print >> sys.stderr, tpl % (command, shortdesc(command)) for command in set(commands.keys()) - set(cls.COMMANDS_USAGE_ORDER): - print >> sys.stderr, tpl % (command, shortdesc(command)) + print >> sys.stderr, tpl % (command, shortdesc(command)) sys.exit(1) diff --git a/cmd.py b/cmd.py index 5c9e157..75b0d9d 100755 --- a/cmd.py +++ b/cmd.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # @@ -29,11 +29,13 @@ import conf import registry + class CliWrapper(CliWrapper): - DESCRIPTION = Template(__doc__).substitute(TKLBAM_CONF=conf.Conf.DEFAULT_PATH, - TKLBAM_REGISTRY=registry._Registry.DEFAULT_PATH) + DESCRIPTION = Template(__doc__).substitute( + TKLBAM_CONF=conf.Conf.DEFAULT_PATH, + TKLBAM_REGISTRY=registry._Registry.DEFAULT_PATH) - PATH = [ dirname(realpath(__file__)) ] + PATH = [dirname(realpath(__file__))] COMMANDS_USAGE_ORDER = ['init', '', 'passphrase', 'escrow', @@ -42,5 +44,6 @@ class CliWrapper(CliWrapper): '', 'status', 'internal'] + if __name__ == "__main__": CliWrapper.main() diff --git a/cmd_backup.py b/cmd_backup.py index 570213e..8c506f8 100755 --- a/cmd_backup.py +++ b/cmd_backup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2013 Liraz Siri # diff --git a/cmd_escrow.py b/cmd_escrow.py index 25c69b5..2caa7d2 100755 --- a/cmd_escrow.py +++ b/cmd_escrow.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2013 Liraz Siri # diff --git a/cmd_init.py b/cmd_init.py index 572161b..f3f8eb9 100755 --- a/cmd_init.py +++ b/cmd_init.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2013 Liraz Siri # diff --git a/cmd_internal.py b/cmd_internal.py index 9208594..e5526ba 100755 --- a/cmd_internal.py +++ b/cmd_internal.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # @@ -19,17 +19,19 @@ import cmd_internals from executil import fmt_command + class CliWrapper(CliWrapper): DESCRIPTION = __doc__ PATH = cmd_internals.__path__ + main = CliWrapper.main + def fmt_internal_command(command, *args): - internal_command = [ realpath(__file__), command ] + list(args) + internal_command = [realpath(__file__), command] + list(args) return fmt_command("python2", *internal_command) + if __name__ == "__main__": CliWrapper.main() - - diff --git a/cmd_internals/cmd_create_profile.py b/cmd_internals/cmd_create_profile.py index 77015c8..34edb31 100755 --- a/cmd_internals/cmd_create_profile.py +++ b/cmd_internals/cmd_create_profile.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2013 Liraz Siri # diff --git a/cmd_internals/cmd_delete.py b/cmd_internals/cmd_delete.py index adf3fe2..f2e5292 100755 --- a/cmd_internals/cmd_delete.py +++ b/cmd_internals/cmd_delete.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_detect_profile_id.py b/cmd_internals/cmd_detect_profile_id.py index dac6487..a46de27 100755 --- a/cmd_internals/cmd_detect_profile_id.py +++ b/cmd_internals/cmd_detect_profile_id.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2013 Liraz Siri # diff --git a/cmd_internals/cmd_dirindex.py b/cmd_internals/cmd_dirindex.py index 84b6d83..e781e1c 100755 --- a/cmd_internals/cmd_dirindex.py +++ b/cmd_internals/cmd_dirindex.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_fixstat.py b/cmd_internals/cmd_fixstat.py index d25f8f2..4cd78c3 100755 --- a/cmd_internals/cmd_fixstat.py +++ b/cmd_internals/cmd_fixstat.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_fs2mysql.py b/cmd_internals/cmd_fs2mysql.py index 76a4ada..7a56d7b 100755 --- a/cmd_internals/cmd_fs2mysql.py +++ b/cmd_internals/cmd_fs2mysql.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_fs2pgsql.py b/cmd_internals/cmd_fs2pgsql.py index b1e6c5c..f6d519b 100755 --- a/cmd_internals/cmd_fs2pgsql.py +++ b/cmd_internals/cmd_fs2pgsql.py @@ -1,14 +1,14 @@ -#!/usr/bin/python2 -# +#!/usr/bin/python3 +# # Copyright (c) 2013 Liraz Siri -# +# # This file is part of TKLBAM (TurnKey GNU/Linux BAckup and Migration). -# +# # TKLBAM is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 3 of # the License, or (at your option) any later version. -# +# """ Map a filesystem created by pgsql2fs back to PostgreSQL """ @@ -17,6 +17,7 @@ import pgsql + def usage(e=None): if e: print >> sys.stderr, "error: " + str(e) @@ -25,6 +26,7 @@ def usage(e=None): print >> sys.stderr, __doc__.strip() sys.exit(1) + def main(): args = sys.argv[1:] if not args: @@ -38,5 +40,6 @@ def main(): pgsql.fs2pgsql(pgfs, limits) + if __name__ == "__main__": main() diff --git a/cmd_internals/cmd_merge_userdb.py b/cmd_internals/cmd_merge_userdb.py index 9639d3d..777c714 100755 --- a/cmd_internals/cmd_merge_userdb.py +++ b/cmd_internals/cmd_merge_userdb.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_mysql2fs.py b/cmd_internals/cmd_mysql2fs.py index f445f72..82a1fa7 100755 --- a/cmd_internals/cmd_mysql2fs.py +++ b/cmd_internals/cmd_mysql2fs.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_newpkgs.py b/cmd_internals/cmd_newpkgs.py index b50ef0b..f036031 100755 --- a/cmd_internals/cmd_newpkgs.py +++ b/cmd_internals/cmd_newpkgs.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_newpkgs_install.py b/cmd_internals/cmd_newpkgs_install.py index 1b0ceca..bc3d08f 100755 --- a/cmd_internals/cmd_newpkgs_install.py +++ b/cmd_internals/cmd_newpkgs_install.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_internals/cmd_pgsql2fs.py b/cmd_internals/cmd_pgsql2fs.py index 6021ad7..d879321 100755 --- a/cmd_internals/cmd_pgsql2fs.py +++ b/cmd_internals/cmd_pgsql2fs.py @@ -1,14 +1,14 @@ -#!/usr/bin/python2 -# +#!/usr/bin/python3 +# # Copyright (c) 2013 Liraz Siri -# +# # This file is part of TKLBAM (TurnKey GNU/Linux BAckup and Migration). -# +# # TKLBAM is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 3 of # the License, or (at your option) any later version. -# +# """ Dump PostgreSQL databases to a filesystem path. """ @@ -17,10 +17,12 @@ import sys import pgsql + def fatal(e): print >> sys.stderr, "fatal: " + str(e) sys.exit(1) + def usage(e=None): if e: print >> sys.stderr, "error: " + str(e) @@ -29,6 +31,7 @@ def usage(e=None): print >> sys.stderr, __doc__.strip() sys.exit(1) + def main(): args = sys.argv[1:] if not args: @@ -39,6 +42,6 @@ def main(): pgsql.backup(outdir, limits) + if __name__ == "__main__": main() - diff --git a/cmd_internals/cmd_stsagent.py b/cmd_internals/cmd_stsagent.py index 15407ec..870efa1 100755 --- a/cmd_internals/cmd_stsagent.py +++ b/cmd_internals/cmd_stsagent.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2015 Liraz Siri # diff --git a/cmd_list.py b/cmd_list.py index 8272c33..6b530cd 100755 --- a/cmd_list.py +++ b/cmd_list.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_passphrase.py b/cmd_passphrase.py index 81ace18..8de326d 100755 --- a/cmd_passphrase.py +++ b/cmd_passphrase.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_restore.py b/cmd_restore.py index 0d6d9a3..8b8cdb8 100755 --- a/cmd_restore.py +++ b/cmd_restore.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2013 Liraz Siri # diff --git a/cmd_restore_rollback.py b/cmd_restore_rollback.py index 28f5155..76d1287 100755 --- a/cmd_restore_rollback.py +++ b/cmd_restore_rollback.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/cmd_status.py b/cmd_status.py index 94c0d00..009e93d 100755 --- a/cmd_status.py +++ b/cmd_status.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 # # Copyright (c) 2010-2012 Liraz Siri # diff --git a/passphrase.py b/passphrase.py index 0dda538..8167962 100644 --- a/passphrase.py +++ b/passphrase.py @@ -13,17 +13,20 @@ import base64 import getpass + def random_passphrase(): random = base64.b32encode(os.urandom(10)) parts = [] for i in range(4): - parts.append(random[i * 4:(i+1) * 4]) + parts.append(random[i * 4:(i + 1) * 4]) return "-".join(parts) + class Error(Exception): pass + def get_passphrase(confirm=True): if not os.isatty(sys.stdin.fileno()): input = sys.stdin.readline() @@ -43,4 +46,3 @@ def get_passphrase(confirm=True): print >> sys.stderr, "Sorry, passphrases do not match" return passphrase - diff --git a/pathmap.py b/pathmap.py index 38da7f0..404025a 100644 --- a/pathmap.py +++ b/pathmap.py @@ -11,6 +11,7 @@ import glob from os.path import * + class PathMap(dict): @staticmethod def _expand(path): @@ -24,7 +25,7 @@ def needsglob(path): if needsglob(path): return glob.glob(path) else: - return [ path ] + return [path] def __init__(self, paths): self.default = True @@ -40,11 +41,11 @@ def __init__(self, paths): self[expanded] = sign def includes(self): - return [ path for path in self if self[path] ] + return [path for path in self if self[path]] includes = property(includes) def excludes(self): - return [ path for path in self if not self[path] ] + return [path for path in self if not self[path]] excludes = property(excludes) def __contains__(self, path): diff --git a/pkgman.py b/pkgman.py index 2f30b48..1574848 100644 --- a/pkgman.py +++ b/pkgman.py @@ -15,9 +15,11 @@ from fnmatch import fnmatch + class Error(Exception): pass + def installed(): """Return list of installed packages""" @@ -35,15 +37,16 @@ def parse_status(path): packages = [] for control in parse_status("/var/lib/dpkg/status"): - d = dict([ re.split(':\s*', line, 1) - for line in control.split('\n') - if line and (':' in line) and (line[0] != ' ') ]) + d = dict([re.split(r':\s*', line, 1) + for line in control.split('\n') + if line and (':' in line) and (line[0] != ' ')]) if "ok installed" in d['Status']: packages.append(d['Package']) return packages + class Packages(set): @classmethod def fromfile(cls, path): @@ -68,6 +71,7 @@ def __init__(self, packages=None): set.__init__(self, packages) + class AptCache(set): Error = Error @@ -76,14 +80,17 @@ def __init__(self, packages): status, output = commands.getstatusoutput(command) status = os.WEXITSTATUS(status) if status not in (0, 100): - raise self.Error("execution failed (%d): %s\n%s" % (status, command, output)) + raise self.Error( + "execution failed (%d): %s\n%s" % + (status, command, output)) - cached = [ line.split()[1] - for line in output.split("\n") if - line.startswith("Package: ") ] + cached = [line.split()[1] + for line in output.split("\n") if + line.startswith("Package: ")] set.__init__(self, cached) + class Blacklist: def __init__(self, patterns): self.patterns = patterns @@ -95,6 +102,7 @@ def __contains__(self, val): return True return False + def installable(packages, blacklist=[]): installed = Packages() aptcache = AptCache(packages) @@ -118,6 +126,7 @@ def installable(packages, blacklist=[]): return installable, skipped + class Installer: """ Interface:: @@ -139,7 +148,8 @@ def __init__(self, packages, blacklist=None): self.skipping.sort() if self.installable: - self.command = "apt-get install --assume-yes " + " ".join(self.installable) + self.command = "apt-get install --assume-yes " + \ + " ".join(self.installable) else: self.command = None diff --git a/retry.py b/retry.py index 509b70f..b4cfdd8 100644 --- a/retry.py +++ b/retry.py @@ -9,6 +9,7 @@ """ from time import sleep + def retry(retries, delay=1, backoff=0, fatal_exceptions=None): """ Argument: @@ -34,7 +35,7 @@ def wrapper(*args, **kwargs): return func(*args, **kwargs) except _fatal_exceptions: raise - except: + except BaseException: if attempt < retries and delay: sleep(delay + delay * attempt * backoff) else: diff --git a/tests/fmtbin.py b/tests/fmtbin.py index 3da4340..55731fc 100644 --- a/tests/fmtbin.py +++ b/tests/fmtbin.py @@ -1,8 +1,10 @@ import math + def bits(num): return int(math.log(num) / math.log(2)) + 1 + def fmtbin(num): bitnum = 0 for i in range(bits(num)): diff --git a/tests/resume.py b/tests/resume.py index 7ad4003..983b879 100755 --- a/tests/resume.py +++ b/tests/resume.py @@ -1,4 +1,4 @@ -#!/usr/bin/python2 +#!/usr/bin/python3 import os import sys import time diff --git a/userdb.py b/userdb.py index 50db763..6dd0c58 100644 --- a/userdb.py +++ b/userdb.py @@ -8,10 +8,12 @@ # published by the Free Software Foundation; either version 3 of # the License, or (at your option) any later version. # +from collections import OrderedDict + + class Error(Exception): pass -from collections import OrderedDict class Base(OrderedDict): class Ent(list): @@ -50,7 +52,7 @@ def get_altroot(db): else: names = db.keys() if not names: - return # empty db, nothing we can do. + return # empty db, nothing we can do. altroot = db[names.pop()].copy() altroot.id = 0 @@ -71,7 +73,9 @@ def __init__(self, arg=None): vals = line.split(':') if self.Ent.LEN: if len(vals) != self.Ent.LEN: - raise Error("line with incorrect field count (%d != %d) '%s'" % (len(vals), self.Ent.LEN, line)) + raise Error( + "line with incorrect field count (%d != %d) '%s'" % + (len(vals), self.Ent.LEN, line)) name = vals[0] self[name] = self.Ent(vals) @@ -83,12 +87,12 @@ def __init__(self, arg=None): def __str__(self): ents = self.values() - ents.sort(lambda a,b: cmp(a.id, b.id)) + ents.sort(lambda a, b: cmp(a.id, b.id)) - return "\n".join([ ':'.join(ent) for ent in ents ]) + "\n" + return "\n".join([':'.join(ent) for ent in ents]) + "\n" def ids(self): - return [ self[name].id for name in self ] + return [self[name].id for name in self] ids = property(ids) def new_id(self, extra_ids=[], old_id=1000): @@ -234,7 +238,8 @@ def get_merged_alias_id(name): if name in db_new and db_new[name].id != ent.id: - # we can't remap ids in new, so merge new entry as *_copy of itself + # we can't remap ids in new, so merge new entry as *_copy + # of itself new_ent = cls.Ent(db_new[name]) new_ent.name = new_ent.name + '_orig' @@ -242,15 +247,18 @@ def get_merged_alias_id(name): return db_merged, old2newids + class EtcGroup(Base): class Ent(Base.Ent): LEN = 4 gid = Base.Ent.id + class EtcPasswd(Base): class Ent(Base.Ent): LEN = 7 uid = Base.Ent.id + def gid(self, val=None): if val: self[3] = str(val) @@ -264,6 +272,7 @@ def fixgids(self, gidmap): if oldgid in gidmap: self[name].gid = gidmap[oldgid] + def merge(old_passwd, old_group, new_passwd, new_group): g1 = EtcGroup(old_group) g2 = EtcGroup(new_group) diff --git a/utils.py b/utils.py index a63b4a6..3f753a7 100644 --- a/utils.py +++ b/utils.py @@ -18,6 +18,7 @@ from StringIO import StringIO + def remove_any(path): """Remove a path whether it is a file or a directory. Return: True if removed, False if nothing to remove""" @@ -32,6 +33,7 @@ def remove_any(path): return True + class AttrDict(dict): def __getattr__(self, name): if name in self: @@ -41,14 +43,17 @@ def __getattr__(self, name): def __setattr__(self, name, val): self[name] = val + def is_writeable(fpath): try: file(fpath, "w+") return True - except IOError: + except OSError: return False # workaround for shutil.move across-filesystem bugs + + def move(src, dst): st = os.lstat(src) @@ -65,17 +70,21 @@ def move(src, dst): shutil.move(src, dst) os.lchown(dst, st.st_uid, st.st_gid) + def apply_overlay(src, dst, olist_path): orig_cwd = os.getcwd() os.chdir(src) - executil.getoutput("tar --create --files-from=%s | tar --extract --directory %s" % - (olist_path, executil.mkarg(dst))) + executil.getoutput( + "tar --create --files-from=%s | tar --extract --directory %s" % + (olist_path, executil.mkarg(dst))) os.chdir(orig_cwd) + def fmt_title(title, c='='): return title + "\n" + c * len(title) + "\n" + def fmt_timestamp(): fh = StringIO() @@ -87,6 +96,7 @@ def fmt_timestamp(): return fh.getvalue() + def path_global_or_local(path_global, path_local): """Return global path if writeable, otherwise return local path""" if os.access(os.path.dirname(path_global), os.W_OK): @@ -94,5 +104,6 @@ def path_global_or_local(path_global, path_local): return path_local + def iamroot(): return os.getuid() == 0 diff --git a/version.py b/version.py index e3a4d75..bbbed65 100644 --- a/version.py +++ b/version.py @@ -14,11 +14,14 @@ from utils import AttrDict + class Error(Exception): pass + class TurnKeyVersion(AttrDict): Error = Error + def __init__(self, codename, release=None, arch=None): AttrDict.__init__(self) self.codename = codename @@ -26,7 +29,8 @@ def __init__(self, codename, release=None, arch=None): self.arch = arch def __str__(self): - return "turnkey-%s-%s-%s" % (self.codename, self.release, self.arch) + return "turnkey-{}-{}-{}".format(self.codename, + self.release, self.arch) def is_complete(self): if self.codename and self.release and self.arch: @@ -38,7 +42,7 @@ def is_complete(self): def from_system(cls): try: system_version = file("/etc/turnkey_version").readline().strip() - except: + except BaseException: return return cls.from_string(system_version) @@ -49,7 +53,7 @@ def from_string(cls, version): raise Error("not a turnkey version '%s'" % version) version = re.sub(r'^turnkey-', '', version) - + m = re.match(r'(.*?)-((?:[\d\.]+|beta).*)-(amd64|i386|x86)$', version) if m: name, release, arch = m.groups() @@ -65,6 +69,7 @@ def from_string(cls, version): name = m.group(1) return cls(name) + def _get_turnkey_version(root): path = join(root, 'etc/turnkey_version') if not exists(path): @@ -72,6 +77,7 @@ def _get_turnkey_version(root): return file(path).read().strip() + def _parse_keyvals(path): if not exists(path): return @@ -86,14 +92,17 @@ def _parse_keyvals(path): d[key] = val return d + def _get_os_release(root): path = join(root, "etc/os-release") return _parse_keyvals(path) - + + def _get_lsb_release(root): path = join(root, "etc/lsb-release") return _parse_keyvals(path) - + + def _get_debian_version(root): path = join(root, "etc/debian_version") if not exists(path): @@ -107,6 +116,7 @@ def _get_debian_version(root): if '/' in s: return s.replace('/', '_') + def detect_profile_id(root='/'): val = _get_turnkey_version(root) if val: @@ -115,15 +125,15 @@ def detect_profile_id(root='/'): os_release = _get_os_release(root) if os_release: try: - return "%s-%s" % (os_release['ID'], os_release['VERSION_ID']) + return "{}-{}".format(os_release['ID'], os_release['VERSION_ID']) except KeyError: pass lsb_release = _get_lsb_release(root) if lsb_release: try: - return "%s-%s" % (lsb_release['DISTRIB_ID'].lower(), - lsb_release['DISTRIB_RELEASE']) + return "{}-{}".format(lsb_release['DISTRIB_ID'].lower(), + lsb_release['DISTRIB_RELEASE']) except KeyError: pass From b6f2cf519b6f640385fd12b41f3544a9dbf000eb Mon Sep 17 00:00:00 2001 From: navigator Date: Fri, 20 Mar 2026 23:32:57 +0000 Subject: [PATCH 2/4] chore: migrate Python to 3.13 (38 files fixed) --- backup.py | 28 ++++----- changes.py | 13 ++-- cmd_backup.py | 58 +++++++++--------- cmd_escrow.py | 23 ++++---- cmd_init.py | 36 +++++------ cmd_internals/cmd_create_profile.py | 52 ++++++++-------- cmd_internals/cmd_delete.py | 13 ++-- cmd_internals/cmd_detect_profile_id.py | 10 ++-- cmd_internals/cmd_dirindex.py | 14 ++--- cmd_internals/cmd_fixstat.py | 15 +++-- cmd_internals/cmd_fs2mysql.py | 14 ++--- cmd_internals/cmd_merge_userdb.py | 20 ++++--- cmd_internals/cmd_mysql2fs.py | 17 +++--- cmd_internals/cmd_newpkgs.py | 12 ++-- cmd_internals/cmd_newpkgs_install.py | 20 +++---- cmd_internals/cmd_stsagent.py | 16 ++--- cmd_list.py | 18 +++--- cmd_passphrase.py | 18 +++--- cmd_restore.py | 80 ++++++++++++------------- cmd_restore_rollback.py | 23 ++++---- cmd_status.py | 40 ++++++------- conf.py | 11 ++-- dirindex.py | 16 ++--- dummyhub.py | 39 ++++++------ duplicity.py | 6 +- hooks.py | 4 +- hub.py | 14 ++--- keypacket.py | 16 ++--- mysql.py | 82 +++++++++++++------------- pgsql.py | 24 ++++---- registry.py | 44 +++++++------- restore.py | 80 ++++++++++++------------- rollback.py | 15 +++-- squid.py | 4 +- tests/attr.py | 8 +-- tests/prop.py | 10 ++-- tests/registry.py | 8 +-- tests/resume.py | 20 +++---- 38 files changed, 468 insertions(+), 473 deletions(-) diff --git a/backup.py b/backup.py index 4b39799..da7d391 100644 --- a/backup.py +++ b/backup.py @@ -73,12 +73,12 @@ def fromfile(cls, path): if not exists(path): return None - d = simplejson.load(file(path)) + d = simplejson.load(open(path)) return cls(*(d[attr] for attr in ('profile_id', 'overrides', 'skip_files', 'skip_packages', 'skip_database'))) def tofile(self, path): - simplejson.dump(dict(self), file(path, "w")) + simplejson.dump(dict(self), open(path, "w")) class Backup: class Error(Exception): @@ -97,30 +97,30 @@ def _write_new_packages(self, dest, base_packages): self._log(" " + " ".join(new_packages)) self._log(" EOF\n") - fh = file(dest, "w") + fh = open(dest, "w") for package in new_packages: - print >> fh, package + print(package, file=fh) fh.close() def _write_whatchanged(self, dest, dest_olist, dirindex, dirindex_conf, overrides=[]): - paths = read_paths(file(dirindex_conf)) + paths = read_paths(open(dirindex_conf)) paths += overrides changes = whatchanged(dirindex, paths) - changes.sort(lambda a,b: cmp(a.path, b.path)) + changes.sort(key=lambda a: a.path) changes.tofile(dest) olist = [ change.path for change in changes if change.OP == 'o' ] - file(dest_olist, "w").writelines((path + "\n" for path in olist)) + open(dest_olist, "w").writelines((path + "\n" for path in olist)) if self.verbose: if changes: self._log("Save list of filesystem changes to %s:\n" % dest) actions = list(changes.deleted(optimized=False)) + list(changes.statfixes(optimized=False)) - actions.sort(lambda a,b: cmp(a.args[0], b.args[0])) + actions.sort(key=lambda a: a.args[0]) umask = os.umask(0) os.umask(umask) @@ -128,7 +128,7 @@ def _write_whatchanged(self, dest, dest_olist, dirindex, dirindex_conf, for action in actions: if action.func is os.chmod: path, mode = action.args - default_mode = (0777 if isdir(path) else 0666) ^ umask + default_mode = (0o777 if isdir(path) else 0o666) ^ umask if default_mode == stat.S_IMODE(mode): continue elif action.func is os.lchown: @@ -145,7 +145,7 @@ def _write_whatchanged(self, dest, dest_olist, dirindex, dirindex_conf, def _create_extras(self, extras, profile, conf): os.mkdir(extras.path) - os.chmod(extras.path, 0700) + os.chmod(extras.path, 0o700) etc = str(extras.etc) os.mkdir(etc) @@ -180,7 +180,7 @@ def _create_extras(self, extras, profile, conf): if mysql.MysqlService.is_running(): self._log("\n" + fmt_title("Serializing MySQL database to " + extras.myfs, '-')) mysql.backup(extras.myfs, extras.etc.mysql, - limits=conf.overrides.mydb, callback=mysql.cb_print()) if self.verbose else None + limits=conf.overrides.mydb, callback=mysql.cb_print() if self.verbose else None) except mysql.Error: pass @@ -194,7 +194,7 @@ def _create_extras(self, extras, profile, conf): def _log(self, s=""): if self.verbose: - print s + print(s) def __init__(self, profile, overrides, skip_files=False, skip_packages=False, skip_database=False, resume=False, verbose=True, extras_root="/"): @@ -248,7 +248,7 @@ def __init__(self, profile, overrides, fpaths= _fpaths(extras_paths.path) if not skip_files: - fsdelta_olist = file(extras_paths.fsdelta_olist).read().splitlines() + fsdelta_olist = open(extras_paths.fsdelta_olist).read().splitlines() fpaths += _filter_deleted(fsdelta_olist) size = sum([ os.lstat(fpath).st_size @@ -270,4 +270,4 @@ def r(p): return join(path, p.lstrip('/')) if exists(self.extras_paths.fsdelta_olist): - apply_overlay('/', path, self.extras_paths.fsdelta_olist) + apply_overlay('/', path, self.extras_paths.fsdelta_olist) \ No newline at end of file diff --git a/changes.py b/changes.py index 78079b8..b0865f7 100644 --- a/changes.py +++ b/changes.py @@ -70,7 +70,7 @@ def stat(self): stat = property(stat) def fmt(self, *args): - return "\t".join([self.OP, self.path] + map(str, args)) + return "\t".join([self.OP, self.path] + list(map(str, args))) def __str__(self): return self.fmt() @@ -119,7 +119,7 @@ def __str__(self): @classmethod def parse(cls, line): op2class = dict((val.OP, val) for val in cls.__dict__.values() - if isinstance(val, types.ClassType)) + if isinstance(val, type)) op = line[0] if op not in op2class: raise Error("illegal change line: " + line) @@ -129,7 +129,7 @@ def parse(cls, line): def mkdir(path): try: os.makedirs(path) - except OSError, e: + except OSError as e: if e.errno != errno.EEXIST: raise @@ -179,7 +179,7 @@ def fromfile(cls, f, paths=None): if f == '-': fh = sys.stdin else: - fh = file(f) + fh = open(f) changes = [ Change.parse(line) for line in fh.readlines() ] if paths: @@ -190,7 +190,7 @@ def fromfile(cls, f, paths=None): return cls(changes) def tofile(self, f): - file(f, "w").writelines((str(change) + "\n" for change in self)) + open(f, "w").writelines((str(change) + "\n" for change in self)) def deleted(self, optimized=True): for change in self: @@ -269,5 +269,4 @@ def whatchanged(di_path, paths): deleted = set(di_saved) - set(di_fs) changes += [ Change.Deleted(path) for path in deleted ] - return changes - + return changes \ No newline at end of file diff --git a/cmd_backup.py b/cmd_backup.py index 8c506f8..951492c 100755 --- a/cmd_backup.py +++ b/cmd_backup.py @@ -158,24 +158,24 @@ def usage(e=None): from paged import stdout if e: - print >> stdout, "error: " + str(e) + print("error: " + str(e), file=stdout) - print >> stdout, "Usage: %s [ -options ] [ override ... ]" % sys.argv[0] + print("Usage: %s [ -options ] [ override ... ]" % sys.argv[0], file=stdout) tpl = Template(__doc__.strip()) conf = Conf() - print >> stdout, tpl.substitute(CONF_PATH=conf.paths.conf, + print(tpl.substitute(CONF_PATH=conf.paths.conf, CONF_OVERRIDES=conf.paths.overrides, CONF_VOLSIZE=conf.volsize, CONF_FULL_BACKUP=conf.full_backup, CONF_S3_PARALLEL_UPLOADS=conf.s3_parallel_uploads, - LOGFILE=PATH_LOGFILE) + LOGFILE=PATH_LOGFILE), file=stdout) sys.exit(1) def warn(e): - print >> sys.stderr, "warning: " + str(e) + print("warning: " + str(e), file=sys.stderr) def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) from conffile import ConfFile @@ -202,7 +202,7 @@ def main(): 'simulate', 'quiet', 'force-profile=', 'secretfile=', 'address=', 'volsize=', 's3-parallel-uploads=', 'full-backup=']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) raw_upload_path = None @@ -257,7 +257,7 @@ def main(): elif opt == '--secretfile': if not exists(val): - usage("secretfile %s does not exist" % `val`) + usage("secretfile %s does not exist" % repr(val)) conf.secretfile = val elif opt == '--address': @@ -326,20 +326,20 @@ def main(): if not raw_upload_path: try: update_profile(conf.force_profile) - except hub.Backups.NotInitialized, e: + except hub.Backups.NotInitialized as e: fatal("you need a profile to backup, run tklbam-init first") credentials = None if not conf.address and not dump_path: try: hb = hub_backups() - except hub.Backups.NotInitialized, e: + except hub.Backups.NotInitialized as e: fatal(str(e) + "\n" + "tip: you can still use tklbam-backup with --dump or --address") try: registry.credentials = hb.get_credentials() - except hb.Error, e: + except hb.Error as e: # asking for get_credentials() might fail if the hub is down. # But If we already have the credentials we can survive that. @@ -355,7 +355,7 @@ def main(): if registry.hbr: try: registry.hbr = hb.get_backup_record(registry.hbr.backup_id) - except hb.Error, e: + except hb.Error as e: # if the Hub is down we can hope that the cached address # is still valid and warn and try to backup anyway. # @@ -380,9 +380,9 @@ def main(): else: # implicit resume if not opt_simulate and not opt_disable_resume and registry.backup_resume_conf == conf: - print "Implicit --resume: Detected a rerun of an aborted backup session" - print " You can disable this with the --disable-resume option" - print + print("Implicit --resume: Detected a rerun of an aborted backup session") + print(" You can disable this with the --disable-resume option") + print() time.sleep(5) opt_resume = True @@ -391,14 +391,14 @@ def main(): if not opt_simulate: registry.backup_resume_conf = conf - secret = file(conf.secretfile).readline().strip() + secret = open(conf.secretfile).readline().strip() target = duplicity.Target(conf.address, credentials, secret) if not (opt_simulate or opt_debug or dump_path): - log_fh = file(opt_logfile, "a") + log_fh = open(opt_logfile, "a") - print >> log_fh - print >> log_fh, "\n" + fmt_timestamp() + print(file=log_fh) + print("\n" + fmt_timestamp(), file=log_fh) log_fh.flush() @@ -412,7 +412,7 @@ def backup_inprogress(bool): if is_hub_address and not (dump_path or opt_simulate): try: hb.set_backup_inprogress(registry.hbr.backup_id, bool) - except hb.Error, e: + except hb.Error as e: warn("can't update Hub of backup %s: %s" % ("in progress" if bool else "completed", str(e))) try: @@ -420,12 +420,12 @@ def backup_inprogress(bool): def _print(s): if s == "\n": - print + print() else: - print "# " + str(s) + print("# " + str(s)) if raw_upload_path: - print fmt_title("Executing Duplicity to backup %s to %s" % (raw_upload_path, target.address)) + print(fmt_title("Executing Duplicity to backup %s to %s" % (raw_upload_path, target.address))) _print("export PASSPHRASE=$(cat %s)" % conf.secretfile) uploader = duplicity.Uploader(True, @@ -447,7 +447,7 @@ def _print(s): if dump_path: b.dump(dump_path) else: - print "\n" + fmt_title("Executing Duplicity to backup system changes to encrypted, incremental archives") + print("\n" + fmt_title("Executing Duplicity to backup system changes to encrypted, incremental archives")) _print("export PASSPHRASE=$(cat %s)" % conf.secretfile) uploader = duplicity.Uploader(True, @@ -466,14 +466,14 @@ def _print(s): hooks.backup.post() if opt_simulate: - print "Completed --simulate: Leaving %s intact so you can manually inspect it" % b.extras_paths.path + print("Completed --simulate: Leaving %s intact so you can manually inspect it" % b.extras_paths.path) else: if not dump_path: shutil.rmtree(b.extras_paths.path) except: if trap: - print >> log_fh + print(file=log_fh) traceback.print_exc(file=log_fh) raise @@ -493,7 +493,7 @@ def _print(s): m = re.search(r'(^---+\[ Backup Statistics \]---+.*)', output, re.M | re.S) if m: stats = m.group(1) - print stats.strip() + print(stats.strip()) registry.backup_resume_conf = None @@ -504,7 +504,7 @@ def _print(s): pass if not opt_simulate: - print "\nTIP: test your backups with a trial restore BEFORE something bad happens." + print("\nTIP: test your backups with a trial restore BEFORE something bad happens.") if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_escrow.py b/cmd_escrow.py index 2caa7d2..34d8b0b 100755 --- a/cmd_escrow.py +++ b/cmd_escrow.py @@ -22,6 +22,7 @@ """ import sys +import os import getopt import keypacket @@ -30,16 +31,16 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Usage: %s [-options] KEYFILE" % sys.argv[0] - print >> sys.stderr, __doc__ + print("Usage: %s [-options] KEYFILE" % sys.argv[0], file=sys.stderr) + print(__doc__, file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "hRP", ["help", "no-passphrase", "random-passphrase"]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) if not args: @@ -64,11 +65,11 @@ def main(): opt_random_passphrase = True if opt_no_passphrase and opt_random_passphrase: - print >> sys.stderr, "error: --no-passphrase and --random-passphrase are incompatible options" + print("error: --no-passphrase and --random-passphrase are incompatible options", file=sys.stderr) sys.exit(1) if not registry.secret: - print >> sys.stderr, "error: you need to run init first" + print("error: you need to run init first", file=sys.stderr) sys.exit(1) def _passphrase(): @@ -77,7 +78,7 @@ def _passphrase(): if opt_random_passphrase: passphrase = random_passphrase() - print passphrase + print(passphrase) return passphrase return get_passphrase() @@ -88,10 +89,10 @@ def _passphrase(): if keyfile == '-': fh = sys.stdout else: - fh = file(keyfile, "w") - os.chmod(keyfile, 0600) + fh = open(keyfile, "w") + os.chmod(keyfile, 0o600) - print >> fh, key + print(key, file=fh) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/cmd_init.py b/cmd_init.py index f3f8eb9..13fa997 100755 --- a/cmd_init.py +++ b/cmd_init.py @@ -98,26 +98,26 @@ def generate_secret(): # effective is key size: 160-bits (SHA1) # base64 encoding to ensure cli safeness # urandom guarantees we won't block. Redundant randomness just in case. - return base64.b64encode(hashlib.sha1(os.urandom(32)).digest()).rstrip("=") + return base64.b64encode(hashlib.sha1(os.urandom(32)).digest()).rstrip(b"=").decode('ascii') def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) def usage(e=None): from paged import stdout if e: - print >> stdout, "error: " + str(e) + print("error: " + str(e), file=stdout) - print >> stdout, "Usage: %s [ API-KEY ]" % sys.argv[0] - print >> stdout, __doc__.strip() + print("Usage: %s [ API-KEY ]" % sys.argv[0], file=stdout) + print(__doc__.strip(), file=stdout) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help", "solo", "force", "force-profile="]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) apikey = None @@ -150,7 +150,7 @@ def main(): if not registry.registry.secret: registry.registry.secret = generate_secret() registry.registry.key = keypacket.fmt(registry.registry.secret, "") - print """\ + print("""\ Generated backup encryption key: For extra security run "tklbam-passphrase" to cryptographically protect it @@ -158,21 +158,21 @@ def main(): the passphrase it will be impossible to restore your backup and you may suffer data loss. To safeguard against this you may want to create an escrow key with "tklbam-escrow". -""" +""") if solo: if registry.registry.sub_apikey: - print "Broken TKLBAM link to your Hub account (--solo mode)" + print("Broken TKLBAM link to your Hub account (--solo mode)") registry.registry.sub_apikey = None registry.registry.credentials = None else: if force or not registry.registry.sub_apikey: if not apikey: - print "Copy paste the API-KEY from your Hub account's user profile" - print + print("Copy paste the API-KEY from your Hub account's user profile") + print() while True: - apikey = raw_input("API-KEY: ").strip() + apikey = input("API-KEY: ").strip() if apikey: break @@ -181,7 +181,7 @@ def main(): try: sub_apikey = hub.Backups.get_sub_apikey(apikey) - except Exception, e: + except Exception as e: fatal(e) registry.registry.sub_apikey = sub_apikey @@ -190,11 +190,11 @@ def main(): try: credentials = hb.get_credentials() registry.registry.credentials = credentials - print "Linked TKLBAM to your Hub account." + print("Linked TKLBAM to your Hub account.") - except hub.NotSubscribed, e: - print "Linked TKLBAM to your Hub account but there's a problem:" - print + except hub.NotSubscribed as e: + print("Linked TKLBAM to your Hub account but there's a problem:") + print() elif not force_profile and registry.registry.profile: fatal("already initialized") @@ -206,4 +206,4 @@ def main(): fatal("--solo requires --force-profile=empty or --force-profile=path/to/custom/profile ") if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_create_profile.py b/cmd_internals/cmd_create_profile.py index 34edb31..a0c88ba 100755 --- a/cmd_internals/cmd_create_profile.py +++ b/cmd_internals/cmd_create_profile.py @@ -103,21 +103,21 @@ def usage(e=None): from paged import stdout if e: - print >> stdout, "error: " + str(e) + print("error: " + str(e), file=stdout) - print >> stdout, "Syntax: %s [ -options ] output/profile/ " % sys.argv[0] - print >> stdout, __doc__.strip() + print("Syntax: %s [ -options ] output/profile/ " % sys.argv[0], file=stdout) + print(__doc__.strip(), file=stdout) sys.exit(1) def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) class ProfileGenerator: @staticmethod def _get_dirindex(path_dirindex_conf, path_rootfs): - paths = dirindex.read_paths(file(path_dirindex_conf)) + paths = dirindex.read_paths(open(path_dirindex_conf)) paths = [ re.sub(r'^(-?)', '\\1' + path_rootfs, path) for path in paths ] @@ -125,14 +125,14 @@ def _get_dirindex(path_dirindex_conf, path_rootfs): dirindex.create(tmp.path, paths) filtered = [ re.sub(r'^' + path_rootfs, '', line) - for line in file(tmp.path).readlines() ] + for line in open(tmp.path).readlines() ] return "".join(filtered) @staticmethod def _get_packages(path_rootfs): def parse_status(path): control = "" - for line in file(path).readlines(): + for line in open(path).readlines(): if not line.strip(): yield control control = "" @@ -161,16 +161,16 @@ def __init__(self, conf_paths, path_output, rootfs="/", packages=True, dirindex= paths = ProfilePaths(path_output) - file(paths.dirindex_conf, "w").write(("\n".join(conf_paths) + "\n") + open(paths.dirindex_conf, "w").write(("\n".join(conf_paths) + "\n") if conf_paths else "") if dirindex: di = self._get_dirindex(paths.dirindex_conf, rootfs) - file(paths.dirindex, "w").write(di) + open(paths.dirindex, "w").write(di) if packages: packages = self._get_packages(rootfs) - file(paths.packages, "w").writelines([ package + "\n" + open(paths.packages, "w").writelines([ package + "\n" for package in packages ]) self.paths = paths @@ -187,7 +187,7 @@ def parse_conf(fh): for path in _paths: # only accept absolute paths if not re.match(r'^-?/', path): - raise Error("%s is not an absolute path, try %s instead" % (`path`, os.path.abspath(path))) + raise Error("%s is not an absolute path, try %s instead" % (repr(path), os.path.abspath(path))) paths += _paths @@ -200,7 +200,7 @@ def main(): 'root=', 'no-dirindex', 'no-packages']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_force = False @@ -243,29 +243,29 @@ def main(): os.mkdir(path_output) try: - conf_paths = parse_conf(sys.stdin if path_conf == '-' else file(path_conf)) - except Error, e: + conf_paths = parse_conf(sys.stdin if path_conf == '-' else open(path_conf)) + except Error as e: fatal(e) profile = ProfileGenerator(conf_paths, path_output, opt_root, packages=opt_packages, dirindex=opt_dirindex) title = "Custom profile written to %s" % profile.paths.path - print title - print "=" * len(title) + print(title) + print("=" * len(title)) - print - print "# List of backup includes and exclude paths" - print profile.paths.dirindex_conf + print() + print("# List of backup includes and exclude paths") + print(profile.paths.dirindex_conf) if exists(profile.paths.dirindex): - print - print "# Index of file timestamps, ownerships and permissions for paths in dirindex.conf" - print profile.paths.dirindex + print() + print("# Index of file timestamps, ownerships and permissions for paths in dirindex.conf") + print(profile.paths.dirindex) if exists(profile.paths.packages): - print - print "# List of currently installed packages" - print profile.paths.packages + print() + print("# List of currently installed packages") + print(profile.paths.packages) if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_delete.py b/cmd_internals/cmd_delete.py index f2e5292..554c643 100755 --- a/cmd_internals/cmd_delete.py +++ b/cmd_internals/cmd_delete.py @@ -26,17 +26,17 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [-options] delta|- [path ...]" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [-options] delta|- [path ...]" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'svh', ['simulate', 'verbose']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) simulate = False @@ -61,11 +61,10 @@ def main(): for action in changes.deleted(): if verbose: - print action + print(action) if not simulate: action() if __name__=="__main__": - main() - + main() \ No newline at end of file diff --git a/cmd_internals/cmd_detect_profile_id.py b/cmd_internals/cmd_detect_profile_id.py index a46de27..b4c53f6 100755 --- a/cmd_internals/cmd_detect_profile_id.py +++ b/cmd_internals/cmd_detect_profile_id.py @@ -19,14 +19,14 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) - print >> sys.stderr, "Syntax: %s [ path/to/root ]" % sys.argv[0] + print("error: " + str(e), file=sys.stderr) + print("Syntax: %s [ path/to/root ]" % sys.argv[0], file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'h', ['help']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) for opt, val in opts: @@ -35,7 +35,7 @@ def main(): root = args[0] if args else '/' - print detect_profile_id(root) + print(detect_profile_id(root)) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_dirindex.py b/cmd_internals/cmd_dirindex.py index e781e1c..5205fdd 100755 --- a/cmd_internals/cmd_dirindex.py +++ b/cmd_internals/cmd_dirindex.py @@ -25,17 +25,17 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [-options] index path1 ... pathN" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [-options] index path1 ... pathN" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'i:ch', ['create', 'input=']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_create = False @@ -58,7 +58,7 @@ def main(): paths = args[1:] if opt_input: - fh = file(opt_input) if opt_input != '-' else sys.stdin + fh = open(opt_input) if opt_input != '-' else sys.stdin paths = dirindex.read_paths(fh) + paths if opt_create: @@ -66,7 +66,7 @@ def main(): return for change in changes.whatchanged(path_index, paths): - print change + print(change) if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_fixstat.py b/cmd_internals/cmd_fixstat.py index 4cd78c3..4e30e4d 100755 --- a/cmd_internals/cmd_fixstat.py +++ b/cmd_internals/cmd_fixstat.py @@ -30,17 +30,17 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [-options] delta|- [path ...]" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [-options] delta|- [path ...]" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'u:g:svh', ['uid-map=', 'gid-map=', 'simulate', 'verbose']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) verbose = False @@ -50,7 +50,7 @@ def main(): gidmap = {} def parse_idmap(line): - return dict([ map(int, val.split(',', 1)) for val in line.split(':') ]) + return dict([ list(map(int, val.split(',', 1))) for val in line.split(':') ]) for opt, val in opts: if opt in ('-u', '--uid-map'): @@ -76,11 +76,10 @@ def parse_idmap(line): for action in changes.statfixes(uidmap, gidmap): if verbose: - print action + print(action) if not simulate: action() if __name__=="__main__": - main() - + main() \ No newline at end of file diff --git a/cmd_internals/cmd_fs2mysql.py b/cmd_internals/cmd_fs2mysql.py index 7a56d7b..edad482 100755 --- a/cmd_internals/cmd_fs2mysql.py +++ b/cmd_internals/cmd_fs2mysql.py @@ -35,10 +35,10 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [-options] path/to/myfs [ -?database/table ... ] " % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [-options] path/to/myfs [ -?database/table ... ] " % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): @@ -48,7 +48,7 @@ def main(): 'skip-extended-insert', 'add-drop-database', 'user=', 'password=', 'defaults-file=', 'host=']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_verbose = False @@ -86,13 +86,13 @@ def main(): if opt_tofile == '-': fh = sys.stdout else: - fh = file(opt_tofile, "w") + fh = open(opt_tofile, "w") else: fh = mysql.mysql(**myconf) callback = None if opt_verbose: - print "destination: " + fh.name + print("destination: " + fh.name) callback = mysql.cb_print() if opt_verbose: @@ -103,4 +103,4 @@ def main(): opt_add_drop_database) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_merge_userdb.py b/cmd_internals/cmd_merge_userdb.py index 777c714..9cdc9e5 100755 --- a/cmd_internals/cmd_merge_userdb.py +++ b/cmd_internals/cmd_merge_userdb.py @@ -15,10 +15,10 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s old-passwd old-group new-passwd new-group merged-passwd merged-group" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s old-passwd old-group new-passwd new-group merged-passwd merged-group" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): @@ -31,19 +31,21 @@ def main(): merged_passwd, merged_group = args[4:6] def r(path): - return file(path).read() + return open(path).read() passwd, group, uidmap, gidmap = userdb.merge(r(old_passwd), r(old_group), r(new_passwd), r(new_group)) - print >> file(merged_passwd, "w"), passwd - print >> file(merged_group, "w"), group + with open(merged_passwd, "w") as f: + print(passwd, file=f) + with open(merged_group, "w") as f: + print(group, file=f) def fmt_map(m): return ":".join([ "%d,%d" % (key, val) for key,val in m.items() ]) - print fmt_map(uidmap) - print fmt_map(gidmap) + print(fmt_map(uidmap)) + print(fmt_map(gidmap)) if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_mysql2fs.py b/cmd_internals/cmd_mysql2fs.py index 82a1fa7..6a988f1 100755 --- a/cmd_internals/cmd_mysql2fs.py +++ b/cmd_internals/cmd_mysql2fs.py @@ -39,15 +39,15 @@ import mysql def fatal(e): - print >> sys.stderr, "fatal: " + str(e) + print("fatal: " + str(e), file=sys.stderr) sys.exit(1) def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [-options] path/to/output [ -?database/table ... ] " % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [-options] path/to/output [ -?database/table ... ] " % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): @@ -55,7 +55,7 @@ def main(): opts, args = getopt.gnu_getopt(sys.argv[1:], 'Du:p:v', ['verbose', 'delete', 'fromfile=', 'user=', 'password=', 'defaults-file=', 'host=']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_verbose = False @@ -99,17 +99,16 @@ def main(): if opt_fromfile == '-': mysqldump_fh = sys.stdin else: - mysqldump_fh = file(opt_fromfile) + mysqldump_fh = open(opt_fromfile) else: mysqldump_fh = mysql.mysqldump(**myconf) callback = None if opt_verbose: - print "source: " + mysqldump_fh.name + print("source: " + mysqldump_fh.name) callback = mysql.cb_print() mysql.mysql2fs(mysqldump_fh, outdir, limits, callback) if __name__ == "__main__": - main() - + main() \ No newline at end of file diff --git a/cmd_internals/cmd_newpkgs.py b/cmd_internals/cmd_newpkgs.py index f036031..7965f05 100755 --- a/cmd_internals/cmd_newpkgs.py +++ b/cmd_internals/cmd_newpkgs.py @@ -12,16 +12,16 @@ """Print list of new packages""" import os import sys -import commands +import subprocess from pkgman import Packages def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s base-packages-list [ packages-list ]" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s base-packages-list [ packages-list ]" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): @@ -36,7 +36,7 @@ def main(): packages = Packages() for package in (packages - base_packages): - print package + print(package) if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_newpkgs_install.py b/cmd_internals/cmd_newpkgs_install.py index bc3d08f..695f638 100755 --- a/cmd_internals/cmd_newpkgs_install.py +++ b/cmd_internals/cmd_newpkgs_install.py @@ -27,10 +27,10 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s [ -options ] [ package-name ... ]" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s [ -options ] [ package-name ... ]" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def parse_input(inputfile): @@ -39,7 +39,7 @@ def parse_input(inputfile): if inputfile == '-': fh = sys.stdin else: - fh = file(inputfile) + fh = open(inputfile) for line in fh.readlines(): line = re.sub(r'#.*', '', line).strip() @@ -54,7 +54,7 @@ def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'i:svh', ['input=', 'simulate', 'verbose']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_input = None @@ -87,16 +87,16 @@ def main(): if opt_verbose: if installer.skipping: - print "# SKIPPING: " + " ".join(installer.skipping) + print("# SKIPPING: " + " ".join(installer.skipping)) if installer.command: - print installer.command + print(installer.command) if not opt_simulate: errno, output = installer(interactive=False) if opt_verbose: - print output - os.exit(errno) + print(output) + os._exit(errno) if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_internals/cmd_stsagent.py b/cmd_internals/cmd_stsagent.py index 870efa1..632d7fd 100755 --- a/cmd_internals/cmd_stsagent.py +++ b/cmd_internals/cmd_stsagent.py @@ -22,14 +22,14 @@ def get_credentials(hb): def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Syntax: %s" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Syntax: %s" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) def format(creds): @@ -44,14 +44,14 @@ def main(): try: hb = hub_backups() - except hub.Backups.NotInitialized, e: - print >> sys.stderr, "error: " + str(e) + except hub.Backups.NotInitialized as e: + print("error: " + str(e), file=sys.stderr) creds = get_credentials(hb) if creds.type != 'iamrole': fatal("STS agent incompatible with '%s' type credentials" % creds.type) - print format(creds) + print(format(creds)) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/cmd_list.py b/cmd_list.py index 6b530cd..884915d 100755 --- a/cmd_list.py +++ b/cmd_list.py @@ -44,10 +44,10 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Usage: %s [ ]" % (sys.argv[0]) - print >> sys.stderr, __doc__ + print("Usage: %s [ ]" % (sys.argv[0]), file=sys.stderr) + print(__doc__, file=sys.stderr) sys.exit(1) @@ -89,7 +89,7 @@ def fmt_size(bytes): def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help"]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) for opt, val in opts: @@ -112,12 +112,12 @@ def main(): for hbr in hbrs: hbr.id = hbr.backup_id hbr.skpp = fmt_skpp(hbr.key) - print format(hbr) + print(format(hbr)) elif hbrs: - print "# ID SKPP Created Updated Size (MB) Label" + print("# ID SKPP Created Updated Size (MB) Label") for hbr in hbrs: - print "%4s %-3s %s %-10s %-8s %s" % \ + print("%4s %-3s %s %-10s %-8s %s" % \ (hbr.backup_id, fmt_skpp(hbr.key), hbr.created.strftime("%Y-%m-%d"), @@ -125,7 +125,7 @@ def main(): if hbr.updated else "-", fmt_size(hbr.size), - hbr.label) + hbr.label)) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/cmd_passphrase.py b/cmd_passphrase.py index 8de326d..5eccc1e 100755 --- a/cmd_passphrase.py +++ b/cmd_passphrase.py @@ -27,16 +27,16 @@ def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Usage: %s [-options]" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Usage: %s [-options]" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help", "random"]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_random = False @@ -51,9 +51,9 @@ def main(): if opt_random: passphrase = random_passphrase() - print passphrase + print(passphrase) else: - print "(For no passphrase, just press Enter)" + print("(For no passphrase, just press Enter)") passphrase = get_passphrase() key = keypacket.fmt(registry.secret, passphrase) @@ -66,8 +66,8 @@ def main(): hb.update_key(hbr.backup_id, key) registry.key = key - print ("Updated" if passphrase else "Removed") + \ - " passphrase - uploaded key to Hub." + print(("Updated" if passphrase else "Removed") + \ + " passphrase - uploaded key to Hub.") except hub.Error: raise @@ -75,4 +75,4 @@ def main(): registry.key = key if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_restore.py b/cmd_restore.py index 8b8cdb8..01f087a 100755 --- a/cmd_restore.py +++ b/cmd_restore.py @@ -192,21 +192,21 @@ def fmt(s): backup_codename = fmt(backup_codename) local_codename = fmt(local_codename) - print "WARNING: INCOMPATIBLE APPLIANCE BACKUP" - print "======================================" - print - print "Restoring a %s backup to a %s appliance may create complications." % (backup_codename, local_codename) - print "For best results try restoring instead to a fresh %s installation." % backup_codename + print("WARNING: INCOMPATIBLE APPLIANCE BACKUP") + print("======================================") + print() + print("Restoring a %s backup to a %s appliance may create complications." % (backup_codename, local_codename)) + print("For best results try restoring instead to a fresh %s installation." % backup_codename) if not interactive: sys.exit(ExitCode.INCOMPATIBLE) - print - print "(Use --force to suppress this check)" - print + print() + print("(Use --force to suppress this check)") + print() while True: - answer = raw_input("Do you want to continue? [yes/no] ") + answer = input("Do you want to continue? [yes/no] ") if answer: break @@ -220,7 +220,7 @@ def get_backup_record(arg): try: return hb.get_backup_record(backup_id) - except hub.InvalidBackupError, e: + except hub.InvalidBackupError as e: raise Error('invalid backup id (%s)' % backup_id) # treat our argument as a pattern @@ -246,39 +246,39 @@ def decrypt_key(key, interactive=True): if interactive: p = passphrase.get_passphrase(confirm=False) else: - print "Passphrase: " + print("Passphrase: ") p = sys.stdin.readline().strip() return keypacket.parse(key, p) except keypacket.Error: if not interactive: - print >> sys.stderr, "Incorrect passphrase" + print("Incorrect passphrase", file=sys.stderr) sys.exit(ExitCode.BADPASSPHRASE) - print >> sys.stderr, "Incorrect passphrase, try again" + print("Incorrect passphrase, try again", file=sys.stderr) def warn(e): - print >> sys.stderr, "warning: " + str(e) + print("warning: " + str(e), file=sys.stderr) def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) def usage(e=None): from paged import stdout if e: - print >> stdout, "error: " + str(e) + print("error: " + str(e), file=stdout) - print >> stdout, "Usage: %s [ -options ] " % sys.argv[0] - print >> stdout, "Usage: %s [ -options ] --address=
--keyfile=path/to/key.escrow" % sys.argv[0] + print("Usage: %s [ -options ] " % sys.argv[0], file=stdout) + print("Usage: %s [ -options ] --address=
--keyfile=path/to/key.escrow" % sys.argv[0], file=stdout) tpl = Template(__doc__.strip()) conf = Conf() - print >> stdout, tpl.substitute(CONF_PATH=conf.paths.conf, + print(tpl.substitute(CONF_PATH=conf.paths.conf, CONF_RESTORE_CACHE_SIZE=conf.restore_cache_size, - CONF_RESTORE_CACHE_DIR=conf.restore_cache_dir) + CONF_RESTORE_CACHE_DIR=conf.restore_cache_dir), file=stdout) sys.exit(1) @@ -318,7 +318,7 @@ def main(): 'debug', 'skip-files', 'skip-database', 'skip-packages', 'no-rollback']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) conf = Conf() @@ -342,9 +342,9 @@ def main(): opt_limits += shlex.split(val) elif opt == '--keyfile': if not isfile(val): - fatal("keyfile %s does not exist or is not a file" % `val`) + fatal("keyfile %s does not exist or is not a file" % repr(val)) - opt_key = file(val).read() + opt_key = open(val).read() try: keypacket.fingerprint(opt_key) except keypacket.Error: @@ -412,14 +412,14 @@ def main(): try: try: hbr = get_backup_record(arg) - except hub.Backups.NotInitialized, e: - print >> sys.stderr, "error: " + str(e) - print >> sys.stderr, "tip: you can still use tklbam-restore with --address or a backup extract" + except hub.Backups.NotInitialized as e: + print("error: " + str(e), file=sys.stderr) + print("tip: you can still use tklbam-restore with --address or a backup extract", file=sys.stderr) sys.exit(1) credentials = hub.Backups(registry.sub_apikey).get_credentials() - except Error, e: + except Error as e: fatal(e) else: @@ -457,10 +457,10 @@ def main(): downloader = duplicity.Downloader(opt_time, restore_cache_size, restore_cache_dir) def _print(s): - print s + print(s) def get_backup_extract(): - print fmt_title("Executing Duplicity to download %s to %s " % (address, raw_download_path)) + print(fmt_title("Executing Duplicity to download %s to %s " % (address, raw_download_path))) downloader(raw_download_path, target, log=_print if not silent else None, debug=opt_debug, force=opt_force) return raw_download_path @@ -469,15 +469,15 @@ def get_backup_extract(): return else: raw_download_path = TempDir(prefix="tklbam-") - os.chmod(raw_download_path, 0700) + os.chmod(raw_download_path, 0o700) update_profile(conf.force_profile, strict=False) if not (opt_simulate or opt_debug): - log_fh = file(opt_logfile, "a") + log_fh = open(opt_logfile, "a") - print >> log_fh - print >> log_fh, "\n" + fmt_timestamp() + print(file=log_fh) + print("\n" + fmt_timestamp(), file=log_fh) log_fh.flush() @@ -499,7 +499,7 @@ def get_backup_extract(): os.environ['TKLBAM_BACKUP_EXTRACT_PATH'] = backup_extract_path if not silent: - print fmt_title("Restoring system from backup extract at " + backup_extract_path) + print(fmt_title("Restoring system from backup extract at " + backup_extract_path)) restore = Restore(backup_extract_path, limits=opt_limits, rollback=not no_rollback, simulate=opt_simulate) @@ -508,14 +508,14 @@ def get_backup_extract(): hooks.restore.inspect(restore.extras.path) if opt_debug: - print """\ + print("""\ The --debug option has (again) dropped you into an interactive shell so that you can explore the state of the system just before restore. The current working directory contains the backup extract. To exit from the shell and continue the restore run "exit 0". To exit from the shell and abort the restore run "exit 1". -""" +""") os.chdir(backup_extract_path) executil.system(os.environ.get("SHELL", "/bin/bash")) os.chdir('/') @@ -529,12 +529,12 @@ def get_backup_extract(): if not skip_database: restore.database() - print + print() hooks.restore.post() except: if trap: - print >> log_fh + print(file=log_fh) traceback.print_exc(file=log_fh) raise @@ -548,7 +548,7 @@ def get_backup_extract(): log_fh.close() if not silent: - print "We're done. You may want to reboot now to reload all service configurations." + print("We're done. You may want to reboot now to reload all service configurations.") if __name__=="__main__": - main() + main() \ No newline at end of file diff --git a/cmd_restore_rollback.py b/cmd_restore_rollback.py index 76d1287..64049b2 100755 --- a/cmd_restore_rollback.py +++ b/cmd_restore_rollback.py @@ -23,22 +23,22 @@ from rollback import Rollback def fatal(e): - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) sys.exit(1) def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Usage: %s" % sys.argv[0] - print >> sys.stderr, __doc__.strip() + print("Usage: %s" % sys.argv[0], file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], 'h', ['force', 'help']) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_force = False @@ -57,21 +57,20 @@ def main(): fatal("nothing to rollback") if not opt_force: - print "DATA LOSS WARNING: this will rollback your system to the pre-restore" - print "snapshot from " + rollback.timestamp.ctime() - print + print("DATA LOSS WARNING: this will rollback your system to the pre-restore") + print("snapshot from " + rollback.timestamp.ctime()) + print() while True: - answer = raw_input("Is this really what you want? [yes/no] ") + answer = input("Is this really what you want? [yes/no] ") if answer: break if answer.lower() != "yes": - print "You didn't answer 'yes'. Aborting!" + print("You didn't answer 'yes'. Aborting!") sys.exit(1) rollback.rollback() if __name__=="__main__": - main() - + main() \ No newline at end of file diff --git a/cmd_status.py b/cmd_status.py index 009e93d..786cb54 100755 --- a/cmd_status.py +++ b/cmd_status.py @@ -25,7 +25,7 @@ """ import sys import getopt -from StringIO import StringIO +from io import StringIO from registry import registry @@ -48,10 +48,10 @@ def get(cls): def usage(e=None): if e: - print >> sys.stderr, "error: " + str(e) + print("error: " + str(e), file=sys.stderr) - print >> sys.stderr, "Usage: %s [ -options ]" % (sys.argv[0]) - print >> sys.stderr, __doc__.strip() + print("Usage: %s [ -options ]" % (sys.argv[0]), file=sys.stderr) + print(__doc__.strip(), file=sys.stderr) sys.exit(1) @@ -59,7 +59,7 @@ def main(): try: opts, args = getopt.gnu_getopt(sys.argv[1:], "h", [ "short", "help" ]) - except getopt.GetoptError, e: + except getopt.GetoptError as e: usage(e) opt_short = False @@ -73,23 +73,23 @@ def main(): status = Status.get() if status == Status.NO_APIKEY: - print "TKLBAM (Backup and Migration): NOT INITIALIZED" + print("TKLBAM (Backup and Migration): NOT INITIALIZED") if not opt_short: - print - print ' To initialize TKLBAM, run the "tklbam-init" command to link this' - print ' system to your TurnKey Hub account. For details see the man page or' - print ' go to:' - print - print ' https://www.turnkeylinux.org/tklbam' + print() + print(' To initialize TKLBAM, run the "tklbam-init" command to link this') + print(' system to your TurnKey Hub account. For details see the man page or') + print(' go to:') + print() + print(' https://www.turnkeylinux.org/tklbam') elif status == Status.NO_BACKUP: - print "TKLBAM (Backup and Migration): NO BACKUPS" + print("TKLBAM (Backup and Migration): NO BACKUPS") if not opt_short: - print - print ' To backup for the first time run the "tklbam-backup" command. For' - print ' details see the man page or go to:' - print - print ' https://www.turnkeylinux.org/tklbam' + print() + print(' To backup for the first time run the "tklbam-backup" command. For') + print(' details see the man page or go to:') + print() + print(' https://www.turnkeylinux.org/tklbam') elif status == Status.OK: hbr = registry.hbr @@ -97,9 +97,9 @@ def main(): if registry.hbr.updated: s += ", Updated %s" % hbr.updated.strftime("%a %Y-%m-%d %H:%M") - print s + print(s) sys.exit(status) if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/conf.py b/conf.py index e791147..24fd1aa 100644 --- a/conf.py +++ b/conf.py @@ -20,7 +20,7 @@ def _is_db_limit(val): @classmethod def fromfile(cls, inputfile): try: - fh = file(inputfile) + fh = open(inputfile) except: return cls() @@ -43,7 +43,7 @@ def is_legal(limit): for limit in limits: if not is_legal(limit): - raise Error(`limit` + " is not a legal limit") + raise Error(repr(limit) + " is not a legal limit") return cls(limits) @@ -166,7 +166,7 @@ def __init__(self, path=None): if not exists(self.paths.conf): return - for line in file(self.paths.conf).read().split("\n"): + for line in open(self.paths.conf).read().split("\n"): line = line.strip() if not line or line.startswith("#"): continue @@ -187,6 +187,5 @@ def __init__(self, path=None): else: raise self.Error("unknown conf option '%s'" % opt) - except self.Error, e: - raise self._error(e) - + except self.Error as e: + raise self._error(e) \ No newline at end of file diff --git a/dirindex.py b/dirindex.py index d1b1ad3..7d26a39 100644 --- a/dirindex.py +++ b/dirindex.py @@ -69,7 +69,7 @@ def fmt(self): def __repr__(self): return "DirIndex.Record(%s, mod=%s, uid=%d, gid=%d, size=%d, mtime=%d)" % \ - (`self.path`, oct(self.mod), self.uid, self.gid, self.size, self.mtime) + (repr(self.path), oct(self.mod), self.uid, self.gid, self.size, self.mtime) @classmethod def create(cls, path_index, paths): @@ -82,7 +82,7 @@ def create(cls, path_index, paths): def __init__(self, fromfile=None): if fromfile: - for line in file(fromfile).readlines(): + for line in open(fromfile).readlines(): if not line.strip(): continue @@ -132,16 +132,16 @@ def prune(self, *paths): """prune index down to paths that are included AND not excluded""" pathmap = PathMap(paths) - for path in self.keys(): + for path in list(self.keys()): if not path in pathmap: del self[path] def save(self, tofile): - fh = file(tofile, "w") - paths = self.keys() + fh = open(tofile, "w") + paths = list(self.keys()) paths.sort() for path in paths: - print >> fh, self[path].fmt() + print(self[path].fmt(), file=fh) def diff(self, other): a = set(self) @@ -202,8 +202,8 @@ def read_paths(fh): # only accept absolute paths if not re.match(r'^-?/', path): - raise Error(`path` + " is not an absolute path") + raise Error(repr(path) + " is not an absolute path") paths.append(path) - return paths + return paths \ No newline at end of file diff --git a/dummyhub.py b/dummyhub.py index f6537e5..bf1bd90 100644 --- a/dummyhub.py +++ b/dummyhub.py @@ -9,6 +9,7 @@ import pickle import glob from datetime import datetime +from functools import cmp_to_key from utils import AttrDict @@ -34,21 +35,21 @@ def generate(cls, uid, secret=None): if secret is None: secret = os.urandom(8) else: - secret = sha(secret).digest()[:8] + secret = sha(secret.encode()).digest()[:8] packed = struct.pack("!L8s", uid, secret) - encoded = base64.b32encode(packed).lstrip("A").rstrip("=") + encoded = base64.b32encode(packed).decode('ascii').lstrip("A").rstrip("=") return cls(encoded) def subkey(self, namespace): - return self.generate(self.uid, namespace + self.secret) + return self.generate(self.uid, namespace.encode() + self.secret) def __str__(self): return self.encoded def __repr__(self): - return "APIKey(%s)" % `str(self)` + return "APIKey(%s)" % str(self) def __eq__(self, other): return self.encoded == other.encoded @@ -65,13 +66,13 @@ def __init__(self, uid, apikey): self.backups_max = 0 def subscribe(self): - accesskey = base64.b64encode(sha("%d" % self.uid).digest())[:20] + accesskey = base64.b64encode(sha(("%d" % self.uid).encode()).digest())[:20] secretkey = base64.b64encode(os.urandom(30))[:40] - producttoken = "{ProductToken}" + base64.b64encode("\x00" + os.urandom(2) + "AppTkn" + os.urandom(224)) - usertoken = "{UserToken}" + base64.b64encode("\x00" + os.urandom(2) + "UserTkn" + os.urandom(288)) + producttoken = "{ProductToken}" + base64.b64encode(b"\x00" + os.urandom(2) + b"AppTkn" + os.urandom(224)).decode('ascii') + usertoken = "{UserToken}" + base64.b64encode(b"\x00" + os.urandom(2) + b"UserTkn" + os.urandom(288)).decode('ascii') - self.credentials = Credentials({'accesskey': accesskey, - 'secretkey': secretkey, + self.credentials = Credentials({'accesskey': accesskey.decode('ascii'), + 'secretkey': secretkey.decode('ascii'), 'producttoken': producttoken, 'usertoken': usertoken}) @@ -138,7 +139,7 @@ def _parse_duplicity_sessions(path): else: sessions[df.timestamp].size += fsize - return sessions.values() + return list(sessions.values()) class DummyBackupRecord(AttrDict): # backup_id, address @@ -173,7 +174,8 @@ class Paths(Paths): @staticmethod def _save(path, obj): - pickle.dump(obj, file(path, "w")) + with open(path, "wb") as f: + pickle.dump(obj, f) @staticmethod def _load(path, default=None): @@ -181,7 +183,8 @@ def _load(path, default=None): return default try: - return pickle.load(file(path)) + with open(path, "rb") as f: + return pickle.load(f) except: return default @@ -311,7 +314,7 @@ def get_new_profile(self, profile_id, profile_timestamp): def new_backup_record(self, key, profile_id, server_id=None): # in the real implementation the hub would create a bucket not a dir... # the real implementation would have to make sure this is unique - path = "/var/tmp/duplicity/" + base64.b32encode(os.urandom(10)) + path = "/var/tmp/duplicity/" + base64.b32encode(os.urandom(10)).decode('ascii') os.makedirs(path) address = "file://" + path @@ -329,9 +332,9 @@ def get_backup_record(self, backup_id): return self.user.backups[backup_id] def list_backups(self): - backups = self.user.backups.values() - return sorted(self.user.backups.values(), - lambda a,b: cmp(int(a.backup_id), int(b.backup_id))) + backups = list(self.user.backups.values()) + return sorted(backups, + key=cmp_to_key(lambda a,b: (int(a.backup_id) > int(b.backup_id)) - (int(a.backup_id) < int(b.backup_id)))) def updated_backup(self, address): # In the real implementation this should add a task which queries S3 @@ -345,6 +348,4 @@ def updated_backup(self, address): return def set_backup_inprogress(self, backup_id, bool): - pass - - + pass \ No newline at end of file diff --git a/duplicity.py b/duplicity.py index f7f1fa6..2a0dd89 100644 --- a/duplicity.py +++ b/duplicity.py @@ -88,7 +88,7 @@ def run(self, passphrase, creds=None, debug=False): os.environ['PASSPHRASE'] = passphrase if debug: - print """ + print(""" The --debug option has dropped you into an interactive shell in which you can explore the state of the system just before the above duplicity command is run, and/or execute it manually. @@ -96,7 +96,7 @@ def run(self, passphrase, creds=None, debug=False): For Duplicity usage info, options and storage backends, run "duplicity --help". To exit from the shell and continue running duplicity "exit 0". To exit from the shell and abort this session "exit 1". -""" +""") import executil shell = os.environ.get("SHELL", "/bin/bash") @@ -266,4 +266,4 @@ def __call__(self, source_dir, target, force_cleanup=True, dry_run=False, debug= log(str(backup_command)) backup_command.run(target.secret, target.credentials, debug=debug) - log("\n") + log("\n") \ No newline at end of file diff --git a/hooks.py b/hooks.py index 22eb9a2..eb08cea 100644 --- a/hooks.py +++ b/hooks.py @@ -37,7 +37,7 @@ def _run_hooks(path, args, keyring=None): try: executil.system(fpath, *args) - except executil.ExecError, e: + except executil.ExecError as e: raise HookError("`%s %s` non-zero exitcode (%d)" % \ (fpath, " ".join(args), e.exitcode)) @@ -88,4 +88,4 @@ def inspect(self, extras_path): os.chdir(orig_cwd) backup = Hooks("backup") -restore = Hooks("restore") +restore = Hooks("restore") \ No newline at end of file diff --git a/hub.py b/hub.py index c02790b..209cec0 100644 --- a/hub.py +++ b/hub.py @@ -115,7 +115,7 @@ class API(_API): def request(self, method, url, attrs={}, headers={}): try: return _API.request(self, method, url, attrs, headers) - except self.Error, e: + except self.Error as e: if e.name == "BackupRecord.NotFound": raise InvalidBackupError(e.description) @@ -253,11 +253,11 @@ def get_new_profile(self, profile_id, profile_timestamp): return None response = self._api('GET', 'archive/', attrs) - content = base64.urlsafe_b64decode(str(response['archive_content'])) + content = base64.urlsafe_b64decode(str(response['archive_content']).encode()).decode('latin-1') fd, archive_path = tempfile.mkstemp(prefix="archive.") - fh = os.fdopen(fd, "w") - fh.write(content) + fh = os.fdopen(fd, "wb") + fh.write(content.encode('latin-1')) fh.close() return ProfileArchive(profile_id, archive_path, archive_timestamp) @@ -290,7 +290,7 @@ def updated_backup(self, address): def list_backups(self): response = self._api('GET', 'records/') - return map(lambda r: BackupRecord(r), response) + return list(map(lambda r: BackupRecord(r), response)) class ProfileArchive: def __init__(self, profile_id, archive, timestamp): @@ -307,6 +307,4 @@ def __del__(self): from conf import Conf if os.environ.get("TKLBAM_DUMMYHUB") or os.path.exists(os.path.join(Conf.DEFAULT_PATH, "dummyhub")): - from dummyhub import Backups - - + from dummyhub import Backups \ No newline at end of file diff --git a/keypacket.py b/keypacket.py index c748987..d338cff 100644 --- a/keypacket.py +++ b/keypacket.py @@ -32,11 +32,11 @@ def _pad(s): return os.urandom(padding_len) + s + struct.pack("!H", len(s)) def _unpad(padded): - len, = struct.unpack("!H", padded[-2:]) - return padded[-(2 + len) :-2] + length, = struct.unpack("!H", padded[-2:]) + return padded[-(2 + length) :-2] def _repeat(f, input, count): - for x in xrange(count): + for x in range(count): input = f(input) return input @@ -46,7 +46,7 @@ def _cipher_key(passphrase, repeats): return cipher_key def _cipher(cipher_key): - return AES.new(cipher_key, mode=AES.MODE_CBC, IV='\0' * 16) + return AES.new(cipher_key, mode=AES.MODE_CBC, IV=b'\0' * 16) def fmt(secret, passphrase): salt = os.urandom(SALT_LEN) @@ -65,8 +65,8 @@ def fmt(secret, passphrase): fingerprint = hashlib.sha1(secret).digest()[:FINGERPRINT_LEN] packet = struct.pack("!BHH", KEY_VERSION, - hash_repeats / 1000, - cipher_repeats / 1000) + fingerprint + ciphertext + hash_repeats // 1000, + cipher_repeats // 1000) + fingerprint + ciphertext return base64.b64encode(packet) @@ -74,7 +74,7 @@ def _parse(packet): try: packet = base64.b64decode(packet) version, khr, kcr = struct.unpack("!BHH", packet[:5]) - except (TypeError, struct.error), e: + except (TypeError, struct.error) as e: raise Error("can't parse key packet: " + str(e)) minimum_len = (5 + FINGERPRINT_LEN + 16) @@ -114,4 +114,4 @@ def parse(packet, passphrase): return secret def fingerprint(packet): - return base64.b16encode(_parse(packet)[2]) + return base64.b16encode(_parse(packet)[2]) \ No newline at end of file diff --git a/mysql.py b/mysql.py index cbfd7ae..970781f 100644 --- a/mysql.py +++ b/mysql.py @@ -37,7 +37,7 @@ class Error(Exception): def _mysql_opts(opts=[], defaults_file=None, **conf): def isreadable(path): try: - file(path) + open(path) return True except: return False @@ -99,7 +99,7 @@ def _match_name(sql): def _parse_statements(fh, delimiter=';'): statement = "" - for line in fh.xreadlines(): + for line in fh: if line.startswith("--"): continue if not line.strip(): @@ -126,16 +126,16 @@ def __init__(self, outdir, name, sql): if not exists(self.paths): os.mkdir(self.paths) - print >> file(self.paths.init, "w"), sql + print(sql, file=open(self.paths.init, "w")) self.name = name def add_view_pre(self, name, sql): view = self.View(self.paths.views, name) - print >> file(view.paths.pre, "w"), sql + print(sql, file=open(view.paths.pre, "w")) def add_view_post(self, name, sql): view = self.View(self.paths.views, name) - print >> file(view.paths.post, "w"), sql + print(sql, file=open(view.paths.post, "w")) class Table(MyFS.Table): def __init__(self, database, name, sql): @@ -143,19 +143,19 @@ def __init__(self, database, name, sql): if not exists(self.paths): os.makedirs(self.paths) - print >> file(self.paths.init, "w"), sql + print(sql, file=open(self.paths.init, "w")) if exists(self.paths.triggers): os.remove(self.paths.triggers) - self.rows_fh = file(self.paths.rows, "w") + self.rows_fh = open(self.paths.rows, "w") self.name = name self.database = database def add_row(self, sql): - print >> self.rows_fh, re.sub(r'.*?VALUES \((.*)\);', '\\1', sql) + print(re.sub(r'.*?VALUES \((.*)\);', '\\1', sql), file=self.rows_fh) def add_trigger(self, sql): - print >> file(self.paths.triggers, "a"), sql + "\n" + print(sql + "\n", file=open(self.paths.triggers, "a")) def __init__(self, outdir, limits=[]): self.limits = DBLimits(limits) @@ -291,25 +291,25 @@ def __init__(self, views_path, name): def pre(self): if not exists(self.paths.pre): return - sql = file(self.paths.pre).read().strip() + sql = open(self.paths.pre).read().strip() return Template(self.TPL_PRE).substitute(name=self.name, sql=sql) pre = property(pre) def post(self): if not exists(self.paths.post): return - sql = file(self.paths.post).read().strip() + sql = open(self.paths.post).read().strip() return Template(self.TPL_POST).substitute(name=self.name, sql=sql) post = property(post) def __init__(self, myfs, fname): self.paths = self.Paths(join(myfs.path, fname)) - self.sql_init = file(self.paths.init).read() + self.sql_init = open(self.paths.init).read() self.name = _match_name(self.sql_init) self.myfs = myfs def __repr__(self): - return "Database(%s)" % `self.paths.path` + return "Database(%s)" % repr(self.paths.path) def tables(self): if not exists(self.paths.tables): @@ -339,9 +339,9 @@ def tofile(self, fh, callback=None): callback(self) if self.myfs.add_drop_database and self.name != 'mysql': - print >> fh, "/*!40000 DROP DATABASE IF EXISTS `%s`*/;" % self.name - print >> fh, self.sql_init, - print >> fh, "USE `%s`;" % self.name + print("/*!40000 DROP DATABASE IF EXISTS `%s`*/;" % self.name, file=fh) + print(self.sql_init, file=fh, end='') + print("USE `%s`;" % self.name, file=fh) for table in self.tables: if callback: @@ -350,7 +350,7 @@ def tofile(self, fh, callback=None): for view in self.views: if view.pre: - print >> fh, "\n" + view.pre + print("\n" + view.pre, file=fh) class Table(MyFS.Table): TPL_CREATE = """\ @@ -391,15 +391,15 @@ class Table(MyFS.Table): def __init__(self, database, fname): self.paths = self.Paths(join(database.paths.tables, fname)) - self.sql_init = file(self.paths.init).read() + self.sql_init = open(self.paths.init).read() self.name = _match_name(self.sql_init) self.database = database def __repr__(self): - return "Table(%s)" % `self.paths.path` + return "Table(%s)" % repr(self.paths.path) def rows(self): - for line in file(self.paths.rows).xreadlines(): + for line in open(self.paths.rows): yield line.strip() def has_rows(self): @@ -413,7 +413,7 @@ def triggers(self): if not exists(self.paths.triggers): return [] - return list(_parse_statements(file(self.paths.triggers), ';;')) + return list(_parse_statements(open(self.paths.triggers), ';;')) triggers = property(triggers) def tofile(self, fh): @@ -423,18 +423,18 @@ def tofile(self, fh): is_log_table = (self.database.name == "mysql" and self.name in ('general_log', 'slow_log')) if not is_log_table: - print >> fh, "DROP TABLE IF EXISTS `%s`;" % self.name + print("DROP TABLE IF EXISTS `%s`;" % self.name, file=fh) - print >> fh, Template(self.TPL_CREATE).substitute(init=self.sql_init) + print(Template(self.TPL_CREATE).substitute(init=self.sql_init), file=fh) if self.has_rows(): if not is_log_table: - print >> fh, Template(self.TPL_INSERT_PRE).substitute(name=self.name).strip() + print(Template(self.TPL_INSERT_PRE).substitute(name=self.name).strip(), file=fh) insert_prefix = "INSERT INTO `%s` VALUES " % self.name if skip_extended_insert: for row in self.rows: - print >> fh, insert_prefix + "(%s);" % row + print(insert_prefix + "(%s);" % row, file=fh) else: rows = ( "(%s)" % row for row in self.rows ) @@ -448,16 +448,16 @@ def tofile(self, fh): fh.write("\n") if index is not None: - print >> fh, "\n-- CHUNKS: %d\n" % (index + 1) + print("\n-- CHUNKS: %d\n" % (index + 1), file=fh) if not is_log_table: - print >> fh, Template(self.TPL_INSERT_POST).substitute(name=self.name) + print(Template(self.TPL_INSERT_POST).substitute(name=self.name), file=fh) if self.triggers: - print >> fh, self.TPL_TRIGGERS_PRE.strip() + print(self.TPL_TRIGGERS_PRE.strip(), file=fh) for trigger in self.triggers: - print >> fh, trigger - print >> fh, self.TPL_TRIGGERS_POST + print(trigger, file=fh) + print(self.TPL_TRIGGERS_POST, file=fh) PRE = """\ /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; @@ -503,7 +503,7 @@ def __iter__(self): yield database def tofile(self, fh, callback=None): - print >> fh, self.PRE + print(self.PRE, file=fh) for database in self: database.tofile(fh, callback) @@ -513,11 +513,11 @@ def tofile(self, fh, callback=None): if not views: continue - print >> fh, "USE `%s`;" % database.name + print("USE `%s`;" % database.name, file=fh) for view in views: - print >> fh, "\n" + view.post + print("\n" + view.post, file=fh) - print >> fh, self.POST + print(self.POST, file=fh) def fs2mysql(fh, myfs, limits=[], callback=None, skip_extended_insert=False, add_drop_database=False): @@ -530,10 +530,10 @@ def cb_print(fh=None): def func(val): if isinstance(val, MyFS.Database): database = val - print >> fh, "database: " + database.name + print("database: " + database.name, file=fh) elif isinstance(val, MyFS.Table): table = val - print >> fh, "table: " + join(table.database.name, table.name) + print("table: " + join(table.database.name, table.name), file=fh) return func @@ -577,7 +577,7 @@ def restore(myfs, etc, **kws): mna = None if simulate: - mysql_fh = file("/dev/null", "w") + mysql_fh = open("/dev/null", "w") else: if not MysqlService.is_running(): raise Error("MySQL service not running") @@ -619,7 +619,7 @@ def get_pid(cls): if not exists(cls.PID_FILE): return - pid = int(file(cls.PID_FILE).read().strip()) + pid = int(open(cls.PID_FILE).read().strip()) if cls._pid_exists(pid): return pid @@ -641,7 +641,7 @@ def start(cls): try: executil.getoutput(cls.INIT_SCRIPT, "start") return - except executil.ExecError, e: + except executil.ExecError as e: pass raise e @@ -696,7 +696,7 @@ def __init__(self): was_running = False self.orig_varrun_mode = stat.S_IMODE(os.stat(self.PATH_VARRUN).st_mode) - os.chmod(self.PATH_VARRUN, 0750) + os.chmod(self.PATH_VARRUN, 0o750) command = Command(self.COMMAND) @@ -735,4 +735,4 @@ def stop(self): MysqlService.start() def __del__(self): - self.stop() + self.stop() \ No newline at end of file diff --git a/pgsql.py b/pgsql.py index 9ec4fdf..d0f011f 100644 --- a/pgsql.py +++ b/pgsql.py @@ -13,8 +13,9 @@ from os.path import * import re -import commands +import shlex import shutil +import subprocess from executil import system, getoutput, getoutput_popen @@ -27,7 +28,7 @@ class Error(Exception): pass def su(command): - return "su postgres -c" + commands.mkarg(command) + return "su postgres -c" + shlex.quote(command) def list_databases(): for line in getoutput(su('psql -l')).splitlines(): @@ -54,10 +55,10 @@ def dumpdb(outdir, name, tlimits=[]): pg_dump += " " + name manifest = getoutput(su(pg_dump) + " | tar xvC %s" % path) - file(join(path, FNAME_MANIFEST), "w").write(manifest + "\n") + open(join(path, FNAME_MANIFEST), "w").write(manifest + "\n") def restoredb(dbdump, dbname, tlimits=[]): - manifest = file(join(dbdump, FNAME_MANIFEST)).read().splitlines() + manifest = open(join(dbdump, FNAME_MANIFEST)).read().splitlines() # remove any malformed entries manifest = [i for i in manifest if not i.endswith('Permission denied')] try: @@ -93,7 +94,7 @@ def pgsql2fs(outdir, limits=[], callback=None): dumpdb(outdir, dbname, limits[dbname]) globals = getoutput(su("pg_dumpall --globals")) - file(join(outdir, FNAME_GLOBALS), "w").write(globals) + open(join(outdir, FNAME_GLOBALS), "w").write(globals) def fs2pgsql(outdir, limits=[], callback=None): limits = DBLimits(limits) @@ -101,8 +102,8 @@ def fs2pgsql(outdir, limits=[], callback=None): if (database, table) not in limits: raise Error("can't exclude %s/%s: table excludes not supported for postgres" % (database, table)) - # load globals first, suppress noise (e.g., "ERROR: role "postgres" already exists) - globals = file(join(outdir, FNAME_GLOBALS)).read() + # load globals first, suppress noise (e.g., "ERROR: role "postgres" already exists") + globals = open(join(outdir, FNAME_GLOBALS)).read() getoutput_popen(su("psql -q -o /dev/null"), globals) for dbname in os.listdir(outdir): @@ -121,7 +122,7 @@ def cb_print(fh=None): fh = sys.stdout def func(val): - print >> fh, "database: " + val + print("database: " + val, file=fh) return func @@ -134,7 +135,7 @@ def backup(outdir, limits=[], callback=None): try: pgsql2fs(outdir, limits, callback) - except Exception, e: + except Exception as e: if isdir(outdir): shutil.rmtree(outdir) raise Error("pgsql backup failed: " + str(e)) @@ -142,7 +143,7 @@ def backup(outdir, limits=[], callback=None): def restore(path, limits=[], callback=None): try: fs2pgsql(path, limits, callback=callback) - except Exception, e: + except Exception as e: raise Error("pgsql restore failed: " + str(e)) class PgsqlService: @@ -154,5 +155,4 @@ def is_running(cls): getoutput(cls.INIT_SCRIPT, "status") return True except: - return False - + return False \ No newline at end of file diff --git a/registry.py b/registry.py index 1ac7c2d..03e3365 100644 --- a/registry.py +++ b/registry.py @@ -75,7 +75,7 @@ def __init__(self, path=None): if not exists(path): os.makedirs(path) - os.chmod(path, 0700) + os.chmod(path, 0o700) self.path = self.Paths(path) @@ -85,16 +85,16 @@ def _file_str(path, s=UNDEFINED): if not exists(path): return None - return file(path).read().rstrip() + return open(path).read().rstrip() else: if s is None: if exists(path): os.remove(path) else: - fh = file(path, "w") - os.chmod(path, 0600) - print >> fh, s + fh = open(path, "w") + os.chmod(path, 0o600) + print(s, file=fh) fh.close() @classmethod @@ -109,7 +109,7 @@ def _file_tuple(cls, path, t=UNDEFINED): @classmethod def _file_dict(cls, path, d=UNDEFINED): if d and d is not UNDEFINED: - d = "\n".join([ "%s=%s" % (k, v) for k, v in d.items() ]) + d = "\n".join([ "%s=%s" % (k, v) for k, v in list(d.items()) ]) retval = cls._file_str(path, d) if retval: @@ -176,17 +176,17 @@ def profile(self, val=UNDEFINED): if val == self.EMPTY_PROFILE: self._file_str(self.path.profile.profile_id, val) - file(self.path.profile.stamp, "w").close() + open(self.path.profile.stamp, "w").close() elif isdir(str(val)): self.profile = None shutil.copytree(val, self.path.profile) self._file_str(self.path.profile.profile_id, self._custom_profile_id(val)) - file(self.path.profile.stamp, "w").close() + open(self.path.profile.stamp, "w").close() else: profile_archive.extract(self.path.profile) - file(self.path.profile.stamp, "w").close() + open(self.path.profile.stamp, "w").close() os.utime(self.path.profile.stamp, (0, profile_archive.timestamp)) self._file_str(self.path.profile.profile_id, profile_archive.profile_id) @@ -240,12 +240,12 @@ def _update_profile(self, profile_id=None): new_profile = hub_backups.get_new_profile(profile_id, profile_timestamp) if new_profile: self.profile = new_profile - print "Downloaded %s profile" % self.profile.profile_id + print("Downloaded %s profile" % self.profile.profile_id) except hub.NotSubscribed: raise - except hub_backups.Error, e: + except hub_backups.Error as e: errno, errname, desc = e.args if errname == "BackupArchive.NotFound": raise self.ProfileNotFound(desc) @@ -266,7 +266,7 @@ def update_profile(self, profile_id=None): try: # look for exact match first self._update_profile(profile_id) - except self.ProfileNotFound, first_exception: + except self.ProfileNotFound as first_exception: if profile_id: if not re.match(r'^turnkey-', profile_id): profile_id = "turnkey-" + profile_id @@ -326,7 +326,7 @@ def update_profile(profile_id=None, strict=True): global registry if profile_id == registry.EMPTY_PROFILE: - print """ + print(""" Creating an empty profile, which means: - We only backup files as included or excluded in the override paths specified @@ -334,7 +334,7 @@ def update_profile(profile_id=None, strict=True): - We can't detect which files have changed since installation so we will indiscriminately backup all files in the included directories. -""" +""") if not strict: @@ -348,17 +348,17 @@ def update_profile(profile_id=None, strict=True): except hub.Backups.NotInitialized: raise NotInitialized() - except hub.NotSubscribed, e: - print >> sys.stderr, str(e) + except hub.NotSubscribed as e: + print(str(e), file=sys.stderr) sys.exit(1) - except registry.CachedProfile, e: - print >> sys.stderr, "warning: " + str(e) - except registry.ProfileNotFound, e: - print >> sys.stderr, "TurnKey Hub Error: %s" % str(e) + except registry.CachedProfile as e: + print("warning: " + str(e), file=sys.stderr) + except registry.ProfileNotFound as e: + print("TurnKey Hub Error: %s" % str(e), file=sys.stderr) if not profile_id: # be extra nice to people who aren't using --force-profile - print >> sys.stderr, "\n" + e.__doc__ + print("\n" + e.__doc__, file=sys.stderr) sys.exit(1) os.environ['TKLBAM_PROFILE_ID'] = registry.profile.profile_id @@ -371,4 +371,4 @@ def hub_backups(): except hub.Backups.NotInitialized: raise NotInitialized() - return hb + return hb \ No newline at end of file diff --git a/restore.py b/restore.py index ed7469b..ae430fe 100644 --- a/restore.py +++ b/restore.py @@ -52,7 +52,7 @@ def __init__(self, backup_extract_path, limits=[], rollback=True, simulate=False if simulate: rollback = False - self.conf = AttrDict(simplejson.loads(file(self.extras.backup_conf).read())) \ + self.conf = AttrDict(simplejson.loads(open(self.extras.backup_conf).read())) \ if exists(self.extras.backup_conf) else None self.simulate = simulate @@ -69,81 +69,81 @@ def database(self): if exists(self.extras.myfs): - print fmt_title("DATABASE - unserializing MySQL databases from " + self.extras.myfs) + print(fmt_title("DATABASE - unserializing MySQL databases from " + self.extras.myfs)) try: mysql.restore(self.extras.myfs, self.extras.etc.mysql, limits=self.limits.mydb, callback=mysql.cb_print(), simulate=self.simulate) - except mysql.Error, e: - print "SKIPPING MYSQL DATABASE RESTORE: " + str(e) + except mysql.Error as e: + print("SKIPPING MYSQL DATABASE RESTORE: " + str(e)) if exists(self.extras.pgfs): - print "\n" + fmt_title("DATABASE - Unserializing PgSQL databases from " + self.extras.pgfs) + print("\n" + fmt_title("DATABASE - Unserializing PgSQL databases from " + self.extras.pgfs)) if self.simulate: - print "CAN'T SIMULATE PGSQL RESTORE, SKIPPING" + print("CAN'T SIMULATE PGSQL RESTORE, SKIPPING") return try: pgsql.restore(self.extras.pgfs, self.limits.pgdb, callback=pgsql.cb_print()) - except pgsql.Error, e: - print "SKIPPING PGSQL DATABASE RESTORE: " + str(e) + except pgsql.Error as e: + print("SKIPPING PGSQL DATABASE RESTORE: " + str(e)) def packages(self): newpkgs_file = self.extras.newpkgs if not exists(newpkgs_file): return - packages = file(newpkgs_file).read().strip() + packages = open(newpkgs_file).read().strip() packages = [] if not packages else packages.split('\n') if not packages: return - print fmt_title("PACKAGES - %d new packages listed in %s" % (len(packages), newpkgs_file), '-') + print(fmt_title("PACKAGES - %d new packages listed in %s" % (len(packages), newpkgs_file), '-')) already_installed = set(pkgman.installed()) & set(packages) if len(already_installed) == len(packages): - print "ALL NEW PACKAGES ALREADY INSTALLED\n" + print("ALL NEW PACKAGES ALREADY INSTALLED\n") return if already_installed: - print "// New packages not already installed: %d" % (len(packages) - len(already_installed)) + print("// New packages not already installed: %d" % (len(packages) - len(already_installed))) # apt-get update, otherwise installer may skip everything - print "// Update list of available packages" - print - print "# apt-get update" + print("// Update list of available packages") + print() + print("# apt-get update") system("apt-get update") installer = pkgman.Installer(packages, self.PACKAGES_BLACKLIST) - print - print "// Installing new packages" + print() + print("// Installing new packages") if installer.skipping: - print "// Skipping uninstallable packages: " + " ".join(installer.skipping) + print("// Skipping uninstallable packages: " + " ".join(installer.skipping)) - print + print() if not installer.command: - print "NO NEW PACKAGES TO INSTALL\n" + print("NO NEW PACKAGES TO INSTALL\n") return - print "# " + installer.command + print("# " + installer.command) if not self.simulate: exitcode = installer() if exitcode != 0: - print "# WARNING: non-zero exitcode (%d)" % exitcode + print("# WARNING: non-zero exitcode (%d)" % exitcode) if self.rollback: self.rollback.save_new_packages(installer.installed) - print + print() @staticmethod def _userdb_merge(old_etc, new_etc): @@ -154,7 +154,7 @@ def _userdb_merge(old_etc, new_etc): new_group = join(new_etc, "group") def r(path): - return file(path).read() + return open(path).read() return userdb.merge(r(old_passwd), r(old_group), r(new_passwd), r(new_group)) @@ -163,14 +163,14 @@ def r(path): def _get_fsdelta_olist(fsdelta_olist_path, limits=[]): pathmap = PathMap(limits) return [ fpath - for fpath in file(fsdelta_olist_path).read().splitlines() + for fpath in open(fsdelta_olist_path).read().splitlines() if fpath in pathmap ] @staticmethod def _apply_overlay(src, dst, olist): tmp = TempFile("fsdelta-olist-") for fpath in olist: - print >> tmp, fpath.lstrip('/') + print(fpath.lstrip('/'), file=tmp) tmp.close() apply_overlay(src, dst, tmp.path) @@ -185,19 +185,19 @@ def files(self): rollback = self.rollback limits = self.limits.fs - print fmt_title("FILES - restoring files, ownership and permissions", '-') + print(fmt_title("FILES - restoring files, ownership and permissions", '-')) passwd, group, uidmap, gidmap = self._userdb_merge(extras.etc, "/etc") if uidmap or gidmap: - print "MERGING USERS AND GROUPS:\n" + print("MERGING USERS AND GROUPS:\n") for olduid in uidmap: - print " UID %d => %d" % (olduid, uidmap[olduid]) + print(" UID %d => %d" % (olduid, uidmap[olduid])) for oldgid in gidmap: - print " GID %d => %d" % (oldgid, gidmap[oldgid]) + print(" GID %d => %d" % (oldgid, gidmap[oldgid])) - print + print() changes = Changes.fromfile(extras.fsdelta, limits) deleted = list(changes.deleted()) @@ -207,38 +207,38 @@ def files(self): fsdelta_olist = self._get_fsdelta_olist(extras.fsdelta_olist, limits) if fsdelta_olist: - print "OVERLAY:\n" + print("OVERLAY:\n") for fpath in fsdelta_olist: - print " " + fpath + print(" " + fpath) if not simulate: self._apply_overlay(overlay, '/', fsdelta_olist) - print + print() statfixes = list(changes.statfixes(uidmap, gidmap)) if statfixes or deleted: - print "POST-OVERLAY FIXES:\n" + print("POST-OVERLAY FIXES:\n") for action in statfixes: - print " " + str(action) + print(" " + str(action)) if not simulate: action() for action in deleted: - print " " + str(action) + print(" " + str(action)) # rollback moves deleted to 'originals' if not simulate and not rollback: action() if statfixes or deleted: - print + print() def w(path, s): - file(path, "w").write(str(s)) + open(path, "w").write(str(s)) if not simulate: w("/etc/passwd", passwd) - w("/etc/group", group) + w("/etc/group", group) \ No newline at end of file diff --git a/rollback.py b/rollback.py index 3989939..5d75ba0 100644 --- a/rollback.py +++ b/rollback.py @@ -45,7 +45,7 @@ def create(cls, path=PATH): if exists(path): shutil.rmtree(path) os.makedirs(path) - os.chmod(path, 0700) + os.chmod(path, 0o700) self = cls(path) @@ -57,7 +57,7 @@ def __init__(self, path=PATH): """deletes path if it exists and creates it if it doesn't""" if not exists(path): - raise Error("No such directory " + `path`) + raise Error("No such directory " + repr(path)) self.paths = self.Paths(path) self.timestamp = datetime.fromtimestamp(os.stat(path).st_ctime) @@ -65,7 +65,7 @@ def __init__(self, path=PATH): @staticmethod def _move(source, dest): if not lexists(source): - raise Error("no such file or directory " + `source`) + raise Error("no such file or directory " + repr(source)) if not exists(dirname(dest)): os.makedirs(dirname(dest)) @@ -150,7 +150,7 @@ def rollback(self): method() except: exceptions += 1 - print >> sys.stderr, "error: %s raised an exception:" % method.__name__ + print("error: %s raised an exception:" % method.__name__, file=sys.stderr) traceback.print_exc(file=sys.stderr) shutil.rmtree(self.paths) @@ -176,9 +176,9 @@ def save_new_packages(self, packages): packages = list(packages) packages.sort() - fh = file(self.paths.newpkgs, "w") + fh = open(self.paths.newpkgs, "w") for package in packages: - print >> fh, package + print(package, file=fh) fh.close() def save_database(self): @@ -190,5 +190,4 @@ def save_database(self): try: pgsql.backup(self.paths.pgfs) except pgsql.Error: - pass - + pass \ No newline at end of file diff --git a/squid.py b/squid.py index ac0cea2..41b1fca 100644 --- a/squid.py +++ b/squid.py @@ -15,7 +15,7 @@ def _is_listening(localport): try: sock.connect(('127.0.0.1', localport)) return True - except socket.error, e: + except socket.error as e: if e.errno == errno.ECONNREFUSED: return False @@ -63,4 +63,4 @@ def stop(self): self.command.terminate(gracetime=1, sig=signal.SIGINT) def __del__(self): - self.stop() + self.stop() \ No newline at end of file diff --git a/tests/attr.py b/tests/attr.py index 90e1671..77d5408 100644 --- a/tests/attr.py +++ b/tests/attr.py @@ -3,7 +3,7 @@ class Foo(object): dynamic_vals = {} def __getattr__(self, name): - print "__getattr__(%s)" % (name) + print("__getattr__(%s)" % (name)) if name in self.dynamic_props: if name not in self.dynamic_vals: @@ -14,13 +14,13 @@ def __getattr__(self, name): return object.__getattr__(self, name) def __setattr__(self, name, val): - print "__setattr__(%s, %s)" % (name, `val`) + print("__setattr__(%s, %s)" % (name, repr(val))) try: if name in self.dynamic_props: object.__getattr__(self, name) - print "object.__setattr__(%s, %s)" % (name, val) + print("object.__setattr__(%s, %s)" % (name, val)) object.__setattr__(self, name, val) except AttributeError: self.dynamic_vals[name] = val @@ -32,4 +32,4 @@ def bar(self, val=None): if val is None: return self._bar self._bar = val - bar = property(bar, bar) + bar = property(bar, bar) \ No newline at end of file diff --git a/tests/prop.py b/tests/prop.py index a20cab0..145371a 100644 --- a/tests/prop.py +++ b/tests/prop.py @@ -5,7 +5,7 @@ def __init__(self): self._test = None def test(self, val=None): - print "test(%s)" % `val` + print("test(%s)" % repr(val)) if val is None: return self._test else: @@ -17,11 +17,11 @@ def __init__(self): self._test = None def read_test(self): - print "read_test()" + print("read_test()") return self._test def write_test(self, val): - print "write_test(%s)" % val + print("write_test(%s)" % val) self._test = val test = property(read_test, write_test) @@ -34,9 +34,9 @@ def __init__(self): self._test = None def test(self, val=UNDEFINED): - print "test(%s)" % `val` + print("test(%s)" % repr(val)) if val is UNDEFINED: return self._test else: self._test = val - test = property(test, test) + test = property(test, test) \ No newline at end of file diff --git a/tests/registry.py b/tests/registry.py index 2b4dd51..5f0eaac 100644 --- a/tests/registry.py +++ b/tests/registry.py @@ -16,10 +16,10 @@ def foo(self, val=None): if not exists(path): return None - return file(path).read().rstrip() + return open(path).read().rstrip() else: - file(path, "w").write("%s\n" % val) + open(path, "w").write("%s\n" % val) foo = property(foo, foo) registry = _Registry() @@ -27,9 +27,9 @@ def foo(self, val=None): def main(): args = sys.argv[1:] - print `registry.foo` + print(repr(registry.foo)) if args: registry.foo = args[0] if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/tests/resume.py b/tests/resume.py index 983b879..a2a6926 100755 --- a/tests/resume.py +++ b/tests/resume.py @@ -17,11 +17,11 @@ class Session: @classmethod def load(cls): - return simplejson.loads(file(cls.SESSION_FILE).read()) + return simplejson.loads(open(cls.SESSION_FILE).read()) @classmethod def save(cls, conf): - file(cls.SESSION_FILE, "w").write(simplejson.dumps(conf)) + open(cls.SESSION_FILE, "w").write(simplejson.dumps(conf)) @classmethod def remove(cls): @@ -30,9 +30,9 @@ def remove(cls): def main(): try: opts, conf = getopt.gnu_getopt(sys.argv[1:], '', ['resume']) - except getopt.GetoptError, e: - print >> sys.stderr, "error: " + str(e) - print >> sys.stderr, "syntax: %s [ --resume ] [ conf ]" % sys.argv[0] + except getopt.GetoptError as e: + print("error: " + str(e), file=sys.stderr) + print("syntax: %s [ --resume ] [ conf ]" % sys.argv[0], file=sys.stderr) sys.exit(1) opt_resume = None @@ -59,16 +59,16 @@ def main(): elif conf != prev_conf: raise Error("can't resume with different arguments") - print "resuming..." + print("resuming...") else: - print "not resuming..." + print("not resuming...") - print "conf: " + `conf` - print "opt_resume = " + `opt_resume` + print("conf: " + repr(conf)) + print("opt_resume = " + repr(opt_resume)) Session.save(conf) time.sleep(3) Session.remove() if __name__ == "__main__": - main() + main() \ No newline at end of file From 7df6b3a7a54c163c4817ef57bb3877a470d43f89 Mon Sep 17 00:00:00 2001 From: PopSolutions Date: Sun, 22 Mar 2026 08:01:11 +0000 Subject: [PATCH 3/4] fix: update debian packaging for Python 3 (control, rules, dependencies) --- debian/control | 24 +++++++++++------------- debian/debhelper-build-stamp | 1 + debian/rules | 2 +- debian/tklbam.postinst.debhelper | 10 ++++++++++ debian/tklbam.prerm.debhelper | 10 ++++++++++ 5 files changed, 33 insertions(+), 14 deletions(-) create mode 100644 debian/debhelper-build-stamp create mode 100644 debian/tklbam.postinst.debhelper create mode 100644 debian/tklbam.prerm.debhelper diff --git a/debian/control b/debian/control index df6ebf9..1003b94 100644 --- a/debian/control +++ b/debian/control @@ -5,10 +5,10 @@ Maintainer: Liraz Siri Build-Depends: debhelper (>= 10), dh-exec, - dh-python2 (>= 4.20201102+turnkey0), - python-all (>= 2.6.6-3~), + dh-python, + python3-all (>= 3.11~), Standards-Version: 4.0.0 -X-Python-Version: >= 2.6 +X-Python3-Version: >= 3.11 Package: tklbam Architecture: all @@ -16,15 +16,13 @@ Depends: ca-certificates, ${misc:Depends}, gnupg, - ntpdate, - pycurl-wrapper (>= 1.2), - pycurl-wrapper (<< 2.0), + ntpsec-ntpdate | systemd-timesyncd, + py3curl-wrapper (>= 2.0), gpg (>= 2.2.12), - ${python:Depends}, - python-crypto, - python-simplejson, - tklbam-duplicity (>= 0.6.18), - tklbam-python-boto (>= 2.3.0-2turnkey), - tklbam-squid (>= 2.7.STABLE9-2.1turnkey+25), - turnkey-pylib (>= 0.5), + ${python3:Depends}, + python3-pycryptodome, + python3-simplejson, + duplicity (>= 3.0), + tklbam-squid (>= 2.7.STABLE9-2.1turnkey), + turnkey-pylib (>= 0.7), Description: TurnKey GNU/Linux Backup and Migration agent diff --git a/debian/debhelper-build-stamp b/debian/debhelper-build-stamp new file mode 100644 index 0000000..2666ba0 --- /dev/null +++ b/debian/debhelper-build-stamp @@ -0,0 +1 @@ +tklbam diff --git a/debian/rules b/debian/rules index 500f8be..2148ae1 100755 --- a/debian/rules +++ b/debian/rules @@ -3,7 +3,7 @@ include /usr/share/dpkg/pkg-info.mk %: - dh $@ --with python2 --buildsystem=makefile + dh $@ --with python3 --buildsystem=makefile override_dh_auto_install: dh_auto_install -- prefix=debian/$(DEB_SOURCE)/usr diff --git a/debian/tklbam.postinst.debhelper b/debian/tklbam.postinst.debhelper new file mode 100644 index 0000000..dacd557 --- /dev/null +++ b/debian/tklbam.postinst.debhelper @@ -0,0 +1,10 @@ + +# Automatically added by dh_python3 +if command -v py3compile >/dev/null 2>&1; then + py3compile -p tklbam /usr/lib/tklbam -V 3.11- +fi +if command -v pypy3compile >/dev/null 2>&1; then + pypy3compile -p tklbam /usr/lib/tklbam -V 3.11- || true +fi + +# End automatically added section diff --git a/debian/tklbam.prerm.debhelper b/debian/tklbam.prerm.debhelper new file mode 100644 index 0000000..7fd772c --- /dev/null +++ b/debian/tklbam.prerm.debhelper @@ -0,0 +1,10 @@ + +# Automatically added by dh_python3 +if command -v py3clean >/dev/null 2>&1; then + py3clean -p tklbam +else + dpkg -L tklbam | sed -En -e '/^(.*)\/(.+)\.py$/s,,rm "\1/__pycache__/\2".*,e' + find /usr/lib/python3/dist-packages/ -type d -name __pycache__ -empty -print0 | xargs --null --no-run-if-empty rmdir +fi + +# End automatically added section From 12ed37e868ad3410a63c2e2751b03fa386ba2a7f Mon Sep 17 00:00:00 2001 From: PopSolutions Date: Sun, 22 Mar 2026 08:19:38 +0000 Subject: [PATCH 4/4] fix: use explicit python3 dep instead of substvars (avoids python2:any) --- debian/control | 2 +- debian/tklbam.postinst.debhelper | 10 ---------- debian/tklbam.prerm.debhelper | 10 ---------- 3 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 debian/tklbam.postinst.debhelper delete mode 100644 debian/tklbam.prerm.debhelper diff --git a/debian/control b/debian/control index 1003b94..b1fca91 100644 --- a/debian/control +++ b/debian/control @@ -19,7 +19,7 @@ Depends: ntpsec-ntpdate | systemd-timesyncd, py3curl-wrapper (>= 2.0), gpg (>= 2.2.12), - ${python3:Depends}, + python3 (>= 3.11~), python3-pycryptodome, python3-simplejson, duplicity (>= 3.0), diff --git a/debian/tklbam.postinst.debhelper b/debian/tklbam.postinst.debhelper deleted file mode 100644 index dacd557..0000000 --- a/debian/tklbam.postinst.debhelper +++ /dev/null @@ -1,10 +0,0 @@ - -# Automatically added by dh_python3 -if command -v py3compile >/dev/null 2>&1; then - py3compile -p tklbam /usr/lib/tklbam -V 3.11- -fi -if command -v pypy3compile >/dev/null 2>&1; then - pypy3compile -p tklbam /usr/lib/tklbam -V 3.11- || true -fi - -# End automatically added section diff --git a/debian/tklbam.prerm.debhelper b/debian/tklbam.prerm.debhelper deleted file mode 100644 index 7fd772c..0000000 --- a/debian/tklbam.prerm.debhelper +++ /dev/null @@ -1,10 +0,0 @@ - -# Automatically added by dh_python3 -if command -v py3clean >/dev/null 2>&1; then - py3clean -p tklbam -else - dpkg -L tklbam | sed -En -e '/^(.*)\/(.+)\.py$/s,,rm "\1/__pycache__/\2".*,e' - find /usr/lib/python3/dist-packages/ -type d -name __pycache__ -empty -print0 | xargs --null --no-run-if-empty rmdir -fi - -# End automatically added section