X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;ds=sidebyside;f=utils.py;h=fb32bc237926cccb571936cb35b5a739bb8e4e7f;hb=b5d32f0b8626ba2ddc832ba32fa5dd805abc8a7e;hp=97598f98ea8aa93c0b547262d7441113662e69dd;hpb=083a06be9f96e0e19bed7642352dbf14aa267044;p=dak.git diff --git a/utils.py b/utils.py index 97598f98..fb32bc23 100644 --- a/utils.py +++ b/utils.py @@ -1,6 +1,6 @@ # Utility functions -# Copyright (C) 2000, 2001 James Troup -# $Id: utils.py,v 1.35 2001-11-04 22:33:22 troup Exp $ +# Copyright (C) 2000, 2001, 2002 James Troup +# $Id: utils.py,v 1.50 2002-07-14 15:01:04 troup Exp $ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -16,20 +16,25 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -import commands, os, pwd, re, socket, shutil, stat, string, sys, tempfile -import apt_pkg +################################################################################ + +import commands, os, pwd, re, socket, shutil, string, sys, tempfile; +import apt_pkg; +import db_access; + +################################################################################ re_comments = re.compile(r"\#.*") re_no_epoch = re.compile(r"^\d*\:") re_no_revision = re.compile(r"\-[^-]*$") re_arch_from_filename = re.compile(r"/binary-[^/]+/") re_extract_src_version = re.compile (r"(\S+)\s*\((.*)\)") -re_isadeb = re.compile (r".*\.u?deb$"); -re_issource = re.compile (r"(.+)_(.+?)\.(orig\.tar\.gz|diff\.gz|tar\.gz|dsc)"); +re_isadeb = re.compile (r"(.+?)_(.+?)_(.+)\.u?deb$"); +re_issource = re.compile (r"(.+)_(.+?)\.(orig\.tar\.gz|diff\.gz|tar\.gz|dsc)$"); re_single_line_field = re.compile(r"^(\S*)\s*:\s*(.*)"); re_multi_line_field = re.compile(r"^\s(.*)"); -re_taint_free = re.compile(r"^[-+\.\w]+$"); +re_taint_free = re.compile(r"^[-+~\.\w]+$"); re_parse_maintainer = re.compile(r"^\s*(\S.*\S)\s*\<([^\> \t]+)\>"); @@ -45,19 +50,8 @@ send_mail_invalid_args_exc = "Both arguments are non-null."; sendmail_failed_exc = "Sendmail invocation failed"; tried_too_hard_exc = "Tried too hard to find a free filename."; -# Valid components; used by extract_component_from_section() because -# it doesn't know about Conf from it's caller. FIXME - -valid_components = { - "main": "", - "contrib": "", - "non-free": "" - }; - default_config = "/etc/katie/katie.conf"; default_apt_config = "/etc/katie/apt.conf"; -DefaultCnf = apt_pkg.newConfiguration(); -apt_pkg.ReadConfigFileISC(DefaultCnf,default_config); ###################################################################################### @@ -68,21 +62,18 @@ def open_file(filename, mode='r'): raise cant_open_exc, filename return f -def touch_file(filename): - fd = os.open(filename, os.O_RDONLY | os.O_CREAT); - os.close(fd); - ###################################################################################### -# From reportbug -def our_raw_input(): - sys.stdout.flush() +def our_raw_input(prompt=""): + if prompt: + sys.stdout.write(prompt); + sys.stdout.flush(); try: - ret = raw_input() + ret = raw_input(); return ret except EOFError: - sys.stderr.write('\nUser interrupt (^D).\n') - raise SystemExit + sys.stderr.write('\nUser interrupt (^D).\n'); + raise SystemExit; ###################################################################################### @@ -94,18 +85,15 @@ def str_isnum (s): ###################################################################################### -# Prefix and components hardcoded into this like a good'un; need to unhardcod at some -# stage. [FIXME] - def extract_component_from_section(section): component = ""; if string.find(section, '/') != -1: component = string.split(section, '/')[0]; if string.lower(component) == "non-us" and string.count(section, '/') > 0: - s = string.split(section, '/')[1]; - if valid_components.has_key(s): # Avoid e.g. non-US/libs - component = string.split(section, '/')[0]+ '/' + string.split(section, '/')[1]; + s = component + '/' + string.split(section, '/')[1]; + if Cnf.has_key("Component::%s" % s): # Avoid e.g. non-US/libs + component = s; if string.lower(section) == "non-us": component = "non-US/main"; @@ -116,7 +104,7 @@ def extract_component_from_section(section): # Expand default component if component == "": - if valid_components.has_key(section): + if Cnf.has_key("Component::%s" % section): component = section; else: component = "main"; @@ -140,7 +128,7 @@ def extract_component_from_section(section): # o The data section must end with a blank line and must be followed by # "-----BEGIN PGP SIGNATURE-----". -def parse_changes(filename, dsc_whitespace_rules): +def parse_changes(filename, dsc_whitespace_rules=0): changes_in = open_file(filename); error = ""; changes = {}; @@ -161,6 +149,7 @@ def parse_changes(filename, dsc_whitespace_rules): indices = indexed_lines.keys() index = 0; + first = -1; while index < max(indices): index = index + 1; line = indexed_lines[index]; @@ -194,6 +183,8 @@ def parse_changes(filename, dsc_whitespace_rules): continue; mlf = re_multi_line_field.match(line); if mlf: + if first == -1: + raise changes_parse_error_exc, "'%s'\n [Multi-line field continuing on from nothing?]" % (line); if first == 1 and changes[field] != "": changes[field] = changes[field] + '\n'; first = 0; @@ -216,12 +207,12 @@ def parse_changes(filename, dsc_whitespace_rules): # Dropped support for 1.4 and ``buggy dchanges 3.4'' (?!) compared to di.pl -def build_file_list(changes, dsc): +def build_file_list(changes, is_a_dsc=0): files = {} format = changes.get("format", "") if format != "": format = float(format) - if dsc == "" and (format < 1.5 or format > 2.0): + if not is_a_dsc and (format < 1.5 or format > 2.0): raise nk_format_exc, format; # No really, this has happened. Think 0 length .dsc file. @@ -234,7 +225,7 @@ def build_file_list(changes, dsc): s = string.split(i) section = priority = ""; try: - if dsc != "": + if is_a_dsc: (md5, size, name) = s else: (md5, size, section, priority, name) = s @@ -279,9 +270,6 @@ def fix_maintainer (maintainer): # sendmail wrapper, takes _either_ a message string or a file as arguments def send_mail (message, filename): - #### FIXME, how do I get this out of Cnf in katie? - sendmail_command = "/usr/sbin/sendmail -odq -oi -t"; - # Sanity check arguments if message != "" and filename != "": raise send_mail_invalid_args_exc; @@ -294,7 +282,7 @@ def send_mail (message, filename): os.close (fd); # Invoke sendmail - (result, output) = commands.getstatusoutput("%s < %s" % (sendmail_command, filename)); + (result, output) = commands.getstatusoutput("%s < %s" % (Cnf["Dinstall::SendmailCommand"], filename)); if (result != 0): raise sendmail_failed_exc, output; @@ -317,7 +305,7 @@ def poolify (source, component): ###################################################################################### -def move (src, dest, overwrite = 0): +def move (src, dest, overwrite = 0, perms = 0664): if os.path.exists(dest) and os.path.isdir(dest): dest_dir = dest; else: @@ -337,10 +325,10 @@ def move (src, dest, overwrite = 0): if not os.access(dest, os.W_OK): raise cant_overwrite_exc shutil.copy2(src, dest); - os.chmod(dest, 0664); + os.chmod(dest, perms); os.unlink(src); -def copy (src, dest, overwrite = 0): +def copy (src, dest, overwrite = 0, perms = 0664): if os.path.exists(dest) and os.path.isdir(dest): dest_dir = dest; else: @@ -360,13 +348,13 @@ def copy (src, dest, overwrite = 0): if not os.access(dest, os.W_OK): raise cant_overwrite_exc shutil.copy2(src, dest); - os.chmod(dest, 0664); + os.chmod(dest, perms); ###################################################################################### def where_am_i (): res = socket.gethostbyaddr(socket.gethostname()); - database_hostname = DefaultCnf.get("Config::" + res[0] + "::DatabaseHostname"); + database_hostname = Cnf.get("Config::" + res[0] + "::DatabaseHostname"); if database_hostname: return database_hostname; else: @@ -374,15 +362,15 @@ def where_am_i (): def which_conf_file (): res = socket.gethostbyaddr(socket.gethostname()); - if DefaultCnf.get("Config::" + res[0] + "::KatieConfig"): - return DefaultCnf["Config::" + res[0] + "::KatieConfig"] + if Cnf.get("Config::" + res[0] + "::KatieConfig"): + return Cnf["Config::" + res[0] + "::KatieConfig"] else: return default_config; def which_apt_conf_file (): res = socket.gethostbyaddr(socket.gethostname()); - if DefaultCnf.get("Config::" + res[0] + "::AptConfig"): - return DefaultCnf["Config::" + res[0] + "::AptConfig"] + if Cnf.get("Config::" + res[0] + "::AptConfig"): + return Cnf["Config::" + res[0] + "::AptConfig"] else: return default_apt_config; @@ -399,10 +387,13 @@ def regex_safe (s): ###################################################################################### # Perform a substition of template -def TemplateSubst(Map,Template): - for x in Map.keys(): - Template = string.replace(Template,x,Map[x]); - return Template; +def TemplateSubst(map, filename): + file = open_file(filename); + template = file.read(); + for x in map.keys(): + template = string.replace(template,x,map[x]); + file.close(); + return template; ###################################################################################### @@ -442,33 +433,22 @@ def cc_fix_changes (changes): for j in string.split(o): changes["architecture"][j] = 1 -# Sort by 'have source', by source name, by source version number, by filename - +# Sort by source name, source version, 'have source', and then by filename def changes_compare (a, b): try: - a_changes = parse_changes(a, 0) + a_changes = parse_changes(a); except: return -1; try: - b_changes = parse_changes(b, 0) + b_changes = parse_changes(b); except: return 1; cc_fix_changes (a_changes); cc_fix_changes (b_changes); - # Sort by 'have source' - - a_has_source = a_changes["architecture"].get("source") - b_has_source = b_changes["architecture"].get("source") - if a_has_source and not b_has_source: - return -1; - elif b_has_source and not a_has_source: - return 1; - # Sort by source name - a_source = a_changes.get("source"); b_source = b_changes.get("source"); q = cmp (a_source, b_source); @@ -476,15 +456,21 @@ def changes_compare (a, b): return q; # Sort by source version - a_version = a_changes.get("version"); b_version = b_changes.get("version"); q = apt_pkg.VersionCompare(a_version, b_version); if q: - return q + return q; - # Fall back to sort by filename + # Sort by 'have source' + a_has_source = a_changes["architecture"].get("source"); + b_has_source = b_changes["architecture"].get("source"); + if a_has_source and not b_has_source: + return -1; + elif b_has_source and not a_has_source: + return 1; + # Fall back to sort by filename return cmp(a, b); ################################################################################ @@ -511,3 +497,130 @@ def result_join (original, sep = '\t'): return string.join(list, sep); ################################################################################ + +def prefix_multi_line_string(str, prefix): + out = ""; + for line in string.split(str, '\n'): + line = string.strip(line); + if line: + out = out + "%s%s\n" % (prefix, line); + # Strip trailing new line + if out: + out = out[:-1]; + return out; + +################################################################################ + +def validate_changes_file_arg(file, fatal=1): + error = None; + + orig_filename = file + if file[-6:] == ".katie": + file = file[:-6]+".changes"; + + if file[-8:] != ".changes": + error = "invalid file type; not a changes file"; + else: + if not os.access(file,os.R_OK): + if os.path.exists(file): + error = "permission denied"; + else: + error = "file not found"; + + if error: + if fatal: + fubar("%s: %s." % (orig_filename, error)); + else: + warn("Skipping %s - %s" % (orig_filename, error)); + return None; + else: + return file; + +################################################################################ + +def real_arch(arch): + return (arch != "source" and arch != "all"); + +################################################################################ + +def join_with_commas_and(list): + if len(list) == 0: return "nothing"; + if len(list) == 1: return list[0]; + return string.join(list[:-1], ", ") + " and " + list[-1]; + +################################################################################ + +def get_conf(): + return Cnf; + +################################################################################ + +# Handle -a, -c and -s arguments; returns them as SQL constraints +def parse_args(Options): + # Process suite + if Options["Suite"]: + suite_ids_list = []; + for suite in string.split(Options["Suite"]): + suite_id = db_access.get_suite_id(suite); + if suite_id == -1: + utils.warn("suite '%s' not recognised." % (suite)); + else: + suite_ids_list.append(suite_id); + if suite_ids_list: + con_suites = "AND su.id IN (%s)" % string.join(map(str, suite_ids_list), ", "); + else: + fubar("No valid suite given."); + else: + con_suites = ""; + + # Process component + if Options["Component"]: + component_ids_list = []; + for component in string.split(Options["Component"]): + component_id = db_access.get_component_id(component); + if component_id == -1: + warn("component '%s' not recognised." % (component)); + else: + component_ids_list.append(component_id); + if component_ids_list: + con_components = "AND c.id IN (%s)" % string.join(map(str, component_ids_list), ", "); + else: + fubar("No valid component given."); + else: + con_components = ""; + + # Process architecture + con_architectures = ""; + if Options["Architecture"]: + arch_ids_list = []; + check_source = 0; + for architecture in string.split(Options["Architecture"]): + if architecture == "source": + check_source = 1; + else: + architecture_id = db_access.get_architecture_id(architecture); + if architecture_id == -1: + warn("architecture '%s' not recognised." % (architecture)); + else: + arch_ids_list.append(architecture_id); + if arch_ids_list: + con_architectures = "AND a.id IN (%s)" % string.join(map(str, arch_ids_list), ", "); + else: + if not check_source: + fubar("No valid architecture given."); + else: + check_source = 1; + + return (con_suites, con_architectures, con_components, check_source); + +################################################################################ + +apt_pkg.init() + +Cnf = apt_pkg.newConfiguration(); +apt_pkg.ReadConfigFileISC(Cnf,default_config); + +if which_conf_file() != default_config: + apt_pkg.ReadConfigFileISC(Cnf,which_conf_file()) + +################################################################################