# Utility functions
# Copyright (C) 2000 James Troup <james@nocrew.org>
-# $Id: utils.py,v 1.8 2000-12-13 03:18:50 troup Exp $
+# $Id: utils.py,v 1.17 2001-03-02 02:46:57 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
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)');
changes_parse_error_exc = "Can't parse line in .changes file";
+invalid_dsc_format_exc = "Invalid .dsc file";
nk_format_exc = "Unknown Format: in .changes file";
no_files_exc = "No Files: field in .dsc file.";
cant_open_exc = "Can't read file.";
unknown_hostname_exc = "Unknown hostname";
+cant_overwrite_exc = "Permission denied; can't overwrite existent file."
######################################################################################
######################################################################################
-def parse_changes(filename):
+def str_isnum (s):
+ for c in s:
+ if c not in string.digits:
+ return 0;
+ return 1;
+
+######################################################################################
+
+# What a mess. 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 s == "main" or s == "non-free" or s == "contrib": # Avoid e.g. non-US/libs
+ component = string.split(section, '/')[0]+ '/' + string.split(section, '/')[1];
+
+ if string.lower(section) == "non-us":
+ component = "non-US/main";
+
+ if component == "":
+ component = "main";
+ elif string.lower(component) == "non-us":
+ component = "non-US/main";
+
+ return (section, component);
+
+######################################################################################
+
+# dsc_whitespace_rules turns on strict format checking to avoid
+# allowing in source packages which are unextracable by the
+# inappropriately fragile dpkg-source.
+#
+# The rules are:
+#
+#
+# o The PGP header consists of "-----BEGIN PGP SIGNED MESSAGE-----"
+# followed by any PGP header data and must end with a blank line.
+#
+# 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):
changes_in = open_file(filename,'r');
- error = ""
+ error = "";
changes = {};
lines = changes_in.readlines();
+
+ if lines == []:
+ raise changes_parse_error_exc, "[Empty changes file]";
+
+ # Reindex by line number so we can easily verify the format of
+ # .dsc files...
+ index = 0;
+ indexed_lines = {};
for line in lines:
+ index = index + 1;
+ indexed_lines[index] = line[:-1];
+
+ inside_signature = 0;
+
+ indices = indexed_lines.keys()
+ index = 0;
+ while index < max(indices):
+ index = index + 1;
+ line = indexed_lines[index];
+ if line == "":
+ if dsc_whitespace_rules:
+ index = index + 1;
+ if index > max(indices):
+ raise invalid_dsc_format_exc, index;
+ line = indexed_lines[index];
+ if not re.match('^-----BEGIN PGP SIGNATURE', line):
+ raise invalid_dsc_format_exc, index;
+ inside_signature = 0;
+ break;
if re.match('^-----BEGIN PGP SIGNATURE', line):
break;
- if re.match(r'^\s*$|^-----BEGIN PGP SIGNED MESSAGE', line):
+ if re.match(r'^-----BEGIN PGP SIGNED MESSAGE', line):
+ if dsc_whitespace_rules:
+ inside_signature = 1;
+ while index < max(indices) and line != "":
+ index = index + 1;
+ line = indexed_lines[index];
continue;
slf = re.match(r'^(\S*)\s*:\s*(.*)', line);
if slf:
changes[field] = changes[field] + mlf.groups()[0] + '\n';
continue;
error = error + line;
+
+ if dsc_whitespace_rules and inside_signature:
+ raise invalid_dsc_format_exc, index;
+
changes_in.close();
changes["filecontents"] = string.join (lines, "");
+
if error != "":
raise changes_parse_error_exc, error;
+
return changes;
######################################################################################
if i == "":
break
s = string.split(i)
- section = priority = component = ""
- if dsc != "":
- (md5, size, name) = s
- else:
- (md5, size, section, priority, name) = s
+ section = priority = "";
+ try:
+ if dsc != "":
+ (md5, size, name) = s
+ else:
+ (md5, size, section, priority, name) = s
+ except ValueError:
+ raise changes_parse_error_exc, i
if section == "": section = "-"
if priority == "": priority = "-"
- # What a mess. FIXME
- 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 s == "main" or s == "non-free" or s == "contrib": # Avoid e.g. non-US/libs
- component = string.split(section, '/')[0]+ '/' + string.split(section, '/')[1]
-
- if string.lower(section) == "non-us":
- component = "non-US/main";
-
- if component == "":
- component = "main";
- elif string.lower(component) == "non-us":
- component = "non-US/main";
+ (section, component) = extract_component_from_section(section);
files[name] = { "md5sum" : md5,
"size" : size,
os.makedirs(dest_dir, 02775);
os.umask(umask);
#print "Moving %s to %s..." % (src, dest);
- shutil.copy2(src, dest);
if os.path.exists(dest) and os.path.isdir(dest):
dest = dest + '/' + os.path.basename(src);
+ # Check for overwrite permission on existent files
+ if os.path.exists(dest) and not os.access(dest, os.W_OK):
+ raise cant_overwrite_exc
+ shutil.copy2(src, dest);
os.chmod(dest, 0664);
os.unlink(src);
os.makedirs(dest_dir, 02775);
os.umask(umask);
#print "Copying %s to %s..." % (src, dest);
- shutil.copy2(src, dest);
if os.path.exists(dest) and os.path.isdir(dest):
dest = dest + '/' + os.path.basename(src);
+ if os.path.exists(dest) and not os.access(dest, os.W_OK):
+ raise cant_overwrite_exc
+ shutil.copy2(src, dest);
os.chmod(dest, 0664);
######################################################################################
else:
raise unknown_hostname_exc, archive
+# FIXME: if the above isn't great, this can't be either :)
+
+def which_apt_conf_file ():
+ archive = where_am_i ();
+ if archive == 'non-US':
+ return '/org/non-us.debian.org/katie/apt.conf-non-US';
+ elif archive == 'ftp-master':
+ return '/org/ftp.debian.org/katie/apt.conf';
+ else:
+ raise unknown_hostname_exc, archive
+
######################################################################################
# Escape characters which have meaning to SQL's regex comparison operator ('~')
######################################################################################
+def size_type (c):
+ t = " b";
+ if c > 10000:
+ c = c / 1000;
+ t = " Kb";
+ if c > 10000:
+ c = c / 1000;
+ t = " Mb";
+ return ("%d%s" % (c, t))