flake8 cleanups

This commit is contained in:
Ville Skyttä 2014-05-29 21:50:58 +03:00
parent b2bc56a5c6
commit 543a05f084
23 changed files with 8398 additions and 8308 deletions

View File

@ -21,9 +21,12 @@ import Config
# Note: do not add any capturing parentheses here
macro_regex = re.compile('%+[{(]?[a-zA-Z_]\w{2,}[)}]?')
class _HeadRequest(urllib2.Request):
def get_method(self):
return "HEAD"
class _HeadRedirectHandler(urllib2.HTTPRedirectHandler):
def redirect_request(*args):
res = urllib2.HTTPRedirectHandler.redirect_request(*args)
@ -31,6 +34,7 @@ class _HeadRedirectHandler(urllib2.HTTPRedirectHandler):
res = _HeadRequest(res.get_full_url())
return res
class AbstractCheck:
known_checks = {}
@ -86,17 +90,18 @@ class AbstractCheck:
res.close()
return info
class AbstractFilesCheck(AbstractCheck):
def __init__(self, name, file_regexp):
self.__files_re = re.compile(file_regexp)
AbstractCheck.__init__(self, name)
def check_binary(self, pkg):
ghosts = pkg.ghostFiles()
for filename in (x for x in pkg.files() if x not in ghosts):
if self.__files_re.match(filename):
self.check_file(pkg, filename)
def check_file(self, pkg, filename):
"""Virtual method called for each file that match the regexp passed
to the constructor.

View File

@ -24,12 +24,14 @@ DEFAULT_SYSTEM_LIB_PATHS = (
'/lib', '/usr/lib', '/usr/X11R6/lib',
'/lib64', '/usr/lib64', '/usr/X11R6/lib64')
def create_regexp_call(call):
if type(call) == type([]):
call = '(?:' + '|'.join(call) + ')'
r = "\s+FUNC\s+.*?\s+(%s(?:@GLIBC\S+)?)(?:\s|$)" % call
return re.compile(r)
class BinaryInfo:
needed_regex = re.compile('\s+\(NEEDED\).*\[(\S+)\]')
@ -45,11 +47,11 @@ class BinaryInfo:
exit_call_regex = create_regexp_call('_?exit')
fork_call_regex = create_regexp_call('fork')
# regexp for setgid setegid setresgid set(?:res|e)?gid
setgid_call_regex = create_regexp_call(['setresgid','setegid','setgid'])
setuid_call_regex = create_regexp_call(['setresuid','seteuid','setuid'])
setgroups_call_regex = create_regexp_call(['initgroups','setgroups'])
setgid_call_regex = create_regexp_call(['setresgid', 'setegid', 'setgid'])
setuid_call_regex = create_regexp_call(['setresuid', 'seteuid', 'setuid'])
setgroups_call_regex = create_regexp_call(['initgroups', 'setgroups'])
chroot_call_regex = create_regexp_call('chroot')
chdir_call_regex = create_regexp_call('chdir')
chdir_call_regex = create_regexp_call('chdir')
mktemp_call_regex = create_regexp_call('mktemp')
def __init__(self, pkg, path, file, is_ar, is_shlib):
@ -165,7 +167,7 @@ class BinaryInfo:
# call is for x86 32 bits, callq for x86_64
if l.find('callq ') >= 0 or l.find('call ') >= 0:
call.append(l.rpartition(' ')[2])
for index,c in enumerate(call):
for index, c in enumerate(call):
if c.find('chroot@plt') >= 0:
for i in call[index-2:index+2]:
if i.find('chdir@plt'):
@ -247,6 +249,7 @@ srcname_regex = re.compile('(.*?)-[0-9]')
invalid_dir_ref_regex = re.compile('/(home|tmp)(\W|$)')
ocaml_mixed_regex = re.compile('^Caml1999X0\d\d$')
def dir_base(path):
res = path_regex.search(path)
if res:
@ -254,6 +257,7 @@ def dir_base(path):
else:
return '', path
class BinariesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -423,7 +427,8 @@ class BinariesCheck(AbstractCheck.AbstractCheck):
continue
if not bin_info.needed and not (
bin_info.soname and ldso_soname_regex.search(bin_info.soname)):
bin_info.soname and
ldso_soname_regex.search(bin_info.soname)):
if is_shobj:
printError(pkg,
'shared-lib-without-dependency-information',
@ -434,9 +439,9 @@ class BinariesCheck(AbstractCheck.AbstractCheck):
else:
# linked against libc ?
if "libc." not in fname and \
(not bin_info.soname or \
("libc." not in bin_info.soname and \
not ldso_soname_regex.search(bin_info.soname))):
(not bin_info.soname or
("libc." not in bin_info.soname and
not ldso_soname_regex.search(bin_info.soname))):
found_libc = False
for lib in bin_info.needed:
@ -456,8 +461,9 @@ class BinariesCheck(AbstractCheck.AbstractCheck):
if bin_info.exec_stack:
printWarning(pkg, 'executable-stack', fname)
elif not bin_info.readelf_error and (
pkg.arch.endswith("86") or pkg.arch.startswith("pentium") or
pkg.arch in ("athlon", "x86_64")):
pkg.arch.endswith("86") or
pkg.arch.startswith("pentium") or
pkg.arch in ("athlon", "x86_64")):
printError(pkg, 'missing-PT_GNU_STACK-section', fname)
if bin_info.setgid and bin_info.setuid and not bin_info.setgroups:

View File

@ -56,20 +56,24 @@ no_exception = False
_checks = []
_checks.extend(DEFAULT_CHECKS)
def addCheck(check):
check = re.sub('\.py[co]?$', '', check)
if check not in _checks:
_checks.append(check)
def allChecks():
if _checks == []:
defaultChecks()
return _checks
def defaultChecks():
resetChecks()
_checks.extend(DEFAULT_CHECKS)
def resetChecks():
global _checks
@ -79,11 +83,13 @@ def resetChecks():
_dirs = ["/usr/share/rpmlint"]
def addCheckDir(dir):
d = os.path.expanduser(dir)
if d not in _dirs:
_dirs.insert(0, d)
def checkDirs():
return _dirs
@ -91,10 +97,12 @@ def checkDirs():
_options = {}
def setOption(name, value):
_options[name] = value
def getOption(name, default = ""):
def getOption(name, default=""):
try:
return _options[name]
except:
@ -104,12 +112,14 @@ def getOption(name, default = ""):
_filters = []
_filters_re = None
def addFilter(s):
global _filters_re
_filters.append(s)
_filters_re = None
def removeFilter(s):
global _filters_re
@ -122,17 +132,21 @@ def removeFilter(s):
_scoring = {}
def setBadness(s, score):
_scoring[s] = score
def badness(s):
return _scoring.get(s, 0)
_non_named_group_re = re.compile('[^\\](\()[^:]')
def isFiltered(s):
global _filters_re
if _filters_re == None:
if _filters_re is None:
# no filter
if len(_filters) == 0:
return False
@ -144,7 +158,7 @@ def isFiltered(s):
# version only supports 100 named groups
if '(' in _filters[idx]:
_non_named_group_re.subn('(:?', _filters[idx])
_filters_re = _filters_re + '|(?:' + _filters[idx] +')'
_filters_re = _filters_re + '|(?:' + _filters[idx] + ')'
_filters_re = re.compile(_filters_re)
if not no_exception:

View File

@ -22,8 +22,8 @@ vendor = Config.getOption("Vendor")
distribution = Config.getOption("Distribution")
compress_ext = Config.getOption("CompressExtension", "bz2")
class DistributionCheck(AbstractCheck.AbstractCheck):
class DistributionCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, "DistributionCheck")
@ -65,7 +65,7 @@ addDetails(
automatically when the package is rebuilt, make sure that you have the
appropriate rpm helper and/or config packages for your target distribution
installed and try rebuilding again; if it still does not happen automatically,
you can compress this file in the %%install section of the spec file.''' \
you can compress this file in the %%install section of the spec file.'''
% (compress_ext, compress_ext),
'infopage-not-compressed',
@ -74,7 +74,7 @@ you can compress this file in the %%install section of the spec file.''' \
automatically when the package is rebuilt, make sure that you have the
appropriate rpm helper and/or config packages for your target distribution
installed and try rebuilding again; if it still does not happen automatically,
you can compress this file in the %%install section of the spec file.''' \
you can compress this file in the %%install section of the spec file.'''
% (compress_ext, compress_ext),
)

View File

@ -35,7 +35,7 @@ class DocFilesCheck(AbstractCheck.AbstractCheck):
reqs[fname] = [x[0] for x in pkgfile.requires]
core_reqs = {} # dependencies of non-doc files
doc_reqs = {} # dependencies of doc files
doc_reqs = {} # dependencies of doc files
for dep in pkg.header.dsFromHeader():
# skip deps which were found by find-requires
@ -51,7 +51,7 @@ class DocFilesCheck(AbstractCheck.AbstractCheck):
for i in files:
if not reqs[i]:
continue # skip empty dependencies
continue # skip empty dependencies
if i in doc_files:
target = doc_reqs
else:

View File

@ -161,9 +161,9 @@ DEFAULT_DANGLING_EXCEPTIONS = (['consolehelper$', 'usermode-consoleonly'],
)
# Standard users and groups from LSB Core 4.0.0: 21.2 User & Group Names
DEFAULT_STANDARD_USERS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
'shutdown', 'halt', 'mail', 'news', 'uucp',
'operator', 'man', 'nobody',)
DEFAULT_STANDARD_USERS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
'shutdown', 'halt', 'mail', 'news', 'uucp',
'operator', 'man', 'nobody',)
DEFAULT_STANDARD_GROUPS = ('root', 'bin', 'daemon', 'adm', 'lp', 'sync',
'shutdown', 'halt', 'mail', 'news', 'uucp',
'man', 'nobody',)
@ -217,7 +217,7 @@ sourced_script_regex = re.compile('^/etc/(bash_completion\.d|profile\.d)/')
use_utf8 = Config.getOption('UseUTF8', Config.USEUTF8_DEFAULT)
skipdocs_regex = re.compile(Config.getOption('SkipDocsRegexp', '\.(?:rtf|x?html?|svg|ml[ily]?)$'), re.IGNORECASE)
meta_package_regex = re.compile(Config.getOption('MetaPackageRegexp', '^(bundle|task)-'))
filesys_packages = ['filesystem'] # TODO: make configurable?
filesys_packages = ['filesystem'] # TODO: make configurable?
quotes_regex = re.compile('[\'"]+')
start_certificate_regex = re.compile('^-----BEGIN CERTIFICATE-----$')
start_private_key_regex = re.compile('^----BEGIN PRIVATE KEY-----$')
@ -261,6 +261,7 @@ else:
# Python 3 means bytes accepts integer input directly
printable_extended_ascii += bytes(range(32, 256))
def peek(filename, pkg, length=1024):
"""Peek into a file, return a chunk from its beginning and a flag if it
seems to be a text file."""
@ -270,7 +271,7 @@ def peek(filename, pkg, length=1024):
fobj = open(filename, 'rb')
chunk = fobj.read(length)
fobj.close()
except IOError: # eg. https://bugzilla.redhat.com/209876
except IOError: # eg. https://bugzilla.redhat.com/209876
e = sys.exc_info()[1]
printWarning(pkg, 'read-error', e)
if fobj:
@ -316,6 +317,7 @@ _python_magic_values = {
'3.4': 3310,
}
def get_expected_pyc_magic(path):
""".pyc/.pyo files embed a 4-byte magic value identifying which version of
the python bytecode ABI they are for. Given a path to a .pyc/.pyo file,
@ -347,6 +349,7 @@ def get_expected_pyc_magic(path):
return (expected_magic_value, ver_from_path)
def py_demarshal_long(b):
"""Counterpart to Python's PyMarshal_ReadLongFromFile, operating on the
bytes in a string."""
@ -357,6 +360,7 @@ def py_demarshal_long(b):
+ (b[2] << 16)
+ (b[3] << 24))
def python_bytecode_to_script(path):
"""Given a python bytecode path, give the path of the .py file
(or None if not python bytecode)."""
@ -371,6 +375,7 @@ def python_bytecode_to_script(path):
return None
class FilesCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -452,8 +457,8 @@ class FilesCheck(AbstractCheck.AbstractCheck):
is_kernel_package:
printError(pkg, "kernel-modules-not-in-kernel-packages", f)
for i in ['mnt','opt','usr-local','var-local','home']:
if f.startswith('/%s/' % i.replace('-','/')):
for i in ('mnt', 'opt', 'usr-local', 'var-local', 'home'):
if f.startswith('/%s/' % i.replace('-', '/')):
printError(pkg, 'dir-or-file-in-%s' % i, f)
if tmp_regex.search(f):
@ -644,8 +649,8 @@ class FilesCheck(AbstractCheck.AbstractCheck):
bindir_exes.setdefault(exe, []).append(f)
if not devel_pkg and not is_doc and \
(includefile_regex.search(f) or \
develfile_regex.search(f) or is_buildconfig):
(includefile_regex.search(f) or develfile_regex.search(f) or
is_buildconfig):
printWarning(pkg, 'devel-file-in-non-devel-package', f)
if mode & int("444", 8) != int("444", 8) and \
perm & int("7000", 8) == 0:
@ -844,7 +849,7 @@ class FilesCheck(AbstractCheck.AbstractCheck):
# normal dir check
elif stat.S_ISDIR(mode):
if mode & int("1002", 8) == 2: # world writable w/o sticky bit
if mode & int("1002", 8) == 2: # world writable w/o sticky bit
printError(pkg, 'world-writable', f, oct(perm))
if perm != int("755", 8):
printError(pkg, 'non-standard-dir-perm', f, oct(perm))
@ -853,7 +858,6 @@ class FilesCheck(AbstractCheck.AbstractCheck):
if hidden_file_regex.search(f):
printWarning(pkg, 'hidden-file-or-dir', f)
# symbolic link check
elif stat.S_ISLNK(mode):

View File

@ -21,7 +21,7 @@ except ImportError:
_rawout = None
_diagnostic = list()
_badness_score = 0
printed_messages = { "I": 0, "W": 0, "E": 0 }
printed_messages = {"I": 0, "W": 0, "E": 0}
if sys.stdout.isatty():
def __print(s):
@ -32,15 +32,19 @@ else:
s = s.encode(locale.getpreferredencoding(), "replace")
print(s)
def printInfo(pkg, reason, *details):
_print("I", pkg, reason, details)
def printWarning(pkg, reason, *details):
_print("W", pkg, reason, details)
def printError(pkg, reason, *details):
_print("E", pkg, reason, details)
def _print(msgtype, pkg, reason, details):
global _badness_score
@ -85,6 +89,7 @@ def _print(msgtype, pkg, reason, details):
return False
def printDescriptions(reason):
try:
d = _details[reason]
@ -94,17 +99,19 @@ def printDescriptions(reason):
except KeyError:
pass
def _diag_sortkey(x):
xs = x.split()
return (xs[2], xs[1])
def printAllReasons():
threshold = badnessThreshold()
if threshold < 0:
return False
global _diagnostic
_diagnostic.sort(key = _diag_sortkey, reverse = True)
_diagnostic.sort(key=_diag_sortkey, reverse=True)
last_reason = ''
for diag in _diagnostic:
if Config.info:
@ -122,17 +129,21 @@ def printAllReasons():
_details = {}
def addDetails(*details):
for idx in range(int(len(details)/2)):
if not details[idx*2] in _details:
_details[details[idx*2]] = details[idx*2+1]
def badnessScore():
return _badness_score
def badnessThreshold():
return Config.getOption("BadnessThreshold", -1)
def setRawOut(file):
global _rawout
if _rawout:

View File

@ -26,7 +26,7 @@ INCORRECT_LOCALES = {
'gr_GR': 'el_GR',
'cz': 'cs',
'cz_CZ': 'cs_CZ',
'lug': 'lg', # 'lug' is valid, but we standardize on 2 letter codes
'lug': 'lg', # 'lug' is valid, but we standardize on 2 letter codes
'en_UK': 'en_GB'}
package_regex = re.compile('-(' + '|'.join(LANGUAGES) + ')$')
@ -46,6 +46,7 @@ EXCEPTION_DIRS = ('C', 'POSIX', 'CP1251', 'CP1255', 'CP1256',
'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15',
'KOI8-R', 'KOI8-U', 'UTF-8', 'default')
def is_valid_lang(lang):
# TODO: @Foo and charset handling
lang = re.sub("[@.].*$", "", lang)
@ -69,6 +70,7 @@ def is_valid_lang(lang):
return True
class I18NCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -150,6 +152,7 @@ class I18NCheck(AbstractCheck.AbstractCheck):
if locales not in (x[0] for x in pkg.requires()):
printError(pkg, 'no-dependency-on', locales)
def is_prefix(p, s):
return len(p) <= len(s) and p == s[:len(p)]

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
#---------------------------------------------------------------
#############################################################################
# Project : Mandriva Linux
# Module : rpmlint
# File : InitScriptCheck.py
# Author : Frederic Lepied
# Created On : Fri Aug 25 09:26:37 2000
# Purpose : check init scripts (files in /etc/rc.d/init.d)
#---------------------------------------------------------------
#############################################################################
import os
import re
@ -36,6 +36,7 @@ LSB_KEYWORDS = ('Provides', 'Required-Start', 'Required-Stop', 'Should-Start',
RECOMMENDED_LSB_KEYWORDS = ('Provides', 'Required-Start', 'Required-Stop',
'Default-Stop', 'Short-Description')
class InitScriptCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -90,7 +91,7 @@ class InitScriptCheck(AbstractCheck.AbstractCheck):
continue
content_str = "".join(content)
for line in content:
line = line[:-1] # chomp
line = line[:-1] # chomp
# TODO check if there is only one line like this
if line.startswith('### BEGIN INIT INFO'):
in_lsb_tag = True

View File

@ -1,25 +1,25 @@
# -*- coding: utf-8 -*-
#---------------------------------------------------------------
#############################################################################
# Project : Mandriva Linux
# Module : rpmlint
# File : LSBCheck.py
# Author : Frederic Lepied
# Created On : Tue Jan 30 14:44:37 2001
# Purpose : LSB non compliance checks
#---------------------------------------------------------------
#############################################################################
import re
import rpm
from Filter import addDetails, printError
from Pkg import b2s
import AbstractCheck
version_regex = re.compile('^[a-zA-Z0-9.+]+$')
name_regex = re.compile('^[a-z0-9.+-]+$')
class LSBCheck(AbstractCheck.AbstractCheck):
def __init__(self):

View File

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
#---------------------------------------------------------------
#############################################################################
# Project : Mandriva Linux
# Module : rpmlint
# File : MenuCheck.py
# Author : Frederic Lepied
# Created On : Mon Mar 20 07:43:37 2000
#---------------------------------------------------------------
#############################################################################
import re
import stat
@ -154,6 +154,7 @@ for l in launchers:
l[0] = re.compile(l[0])
del l
class MenuCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -302,7 +303,7 @@ class MenuCheck(AbstractCheck.AbstractCheck):
if res:
grp = res.groups()
needs = (grp[1] or grp[2]).lower()
if needs in ('x11', 'text' ,'wm'):
if needs in ('x11', 'text', 'wm'):
res = section_regex.search(line)
if res:
grp = res.groups()

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
#---------------------------------------------------------------
#############################################################################
# Project : Mandriva Linux
# Module : rpmlint
# File : NamingPolicyCheck.py
# Author : Michael Scherer
# Created On : Mon May 19 11:25:37 2003
# Purpose : Check package names according to their content.
#---------------------------------------------------------------
#############################################################################
import re
@ -28,9 +28,11 @@ import AbstractCheck
simple_naming_policy_re = re.compile('\^[a-zA-Z1-9-_]*$')
class NamingPolicyNotAppliedException(Exception):
pass
class NamingPolicyCheck(AbstractCheck.AbstractCheck):
checks_ = []

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
#---------------------------------------------------------------
#############################################################################
# Project : Mandriva Linux
# Module : rpmlint
# File : PamCheck.py
# Author : Michael Scherer
# Created On : 31/01/2006
# Purpose : Apply pam policy
#---------------------------------------------------------------
#############################################################################
import re
@ -16,6 +16,7 @@ import AbstractCheck
pam_stack_re = re.compile('^\s*[^#].*pam_stack\.so\s*service')
class PamCheck(AbstractCheck.AbstractFilesCheck):
def __init__(self):
AbstractCheck.AbstractFilesCheck.__init__(self, "PamCheck",

56
Pkg.py
View File

@ -37,6 +37,7 @@ if sys.version_info[0] > 2:
# Blows up with Python < 3 without the exec() hack
exec('def warn(s): print (s, file=sys.stderr)')
long = int
def b2s(b):
if b is None:
return None
@ -44,7 +45,9 @@ if sys.version_info[0] > 2:
return [b2s(x) for x in b]
return b.decode(errors='replace')
else:
def warn(s): print >> sys.stderr, s
def warn(s):
print >> sys.stderr, s
def b2s(b):
return b
@ -61,6 +64,7 @@ PREREQ_FLAG = (rpm.RPMSENSE_PREREQ or 64) | \
var_regex = re.compile('^(.*)\${?(\w+)}?(.*)$')
def shell_var_value(var, script):
assign_regex = re.compile('\\b' + re.escape(var) + '\s*=\s*(.+)\s*(#.*)*$',
re.MULTILINE)
@ -68,12 +72,13 @@ def shell_var_value(var, script):
if res:
res2 = var_regex.search(res.group(1))
if res2:
if res2.group(2) == var: # infinite loop
if res2.group(2) == var: # infinite loop
return None
return substitute_shell_vars(res.group(1), script)
else:
return None
def substitute_shell_vars(val, script):
res = var_regex.search(val)
if res:
@ -85,7 +90,8 @@ def substitute_shell_vars(val, script):
else:
return val
def getstatusoutput(cmd, stdoutonly = False, shell = False):
def getstatusoutput(cmd, stdoutonly=False, shell=False):
'''A version of commands.getstatusoutput() which can take cmd as a
sequence, thus making it potentially more secure.'''
if stdoutonly:
@ -107,6 +113,7 @@ def getstatusoutput(cmd, stdoutonly = False, shell = False):
bz2_regex = re.compile('\.t?bz2?$')
xz_regex = re.compile('\.(t[xl]z|xz|lzma)$')
def catcmd(fname):
"""Get a 'cat' command that handles possibly compressed files."""
cat = 'gzip -dcf'
@ -116,12 +123,14 @@ def catcmd(fname):
cat = 'xz -dc'
return cat
def is_utf8(fname):
(sts, text) = getstatusoutput(catcmd(fname).split() + [fname])
return not sts and is_utf8_str(text)
REPLACEMENT_CHAR = unicodedata.lookup('REPLACEMENT CHARACTER')
def is_utf8_str(s):
if hasattr(s, 'decode'):
# byte string
@ -133,6 +142,7 @@ def is_utf8_str(s):
# unicode string
return REPLACEMENT_CHAR not in s
# TODO: PY3
def to_utf8(string):
if string is None:
@ -160,6 +170,7 @@ def to_utf8(string):
newstring = newstring + char
return newstring
def readlines(path):
fobj = open(path, 'rb')
try:
@ -168,8 +179,9 @@ def readlines(path):
finally:
fobj.close()
def mktemp():
tmpfd, tmpname = tempfile.mkstemp(prefix = 'rpmlint.')
tmpfd, tmpname = tempfile.mkstemp(prefix='rpmlint.')
tmpfile = os.fdopen(tmpfd, 'w')
return tmpfile, tmpname
@ -177,6 +189,7 @@ slash_regex = re.compile('/+')
slashdot_regex = re.compile('/(\.(/|$))+')
slashend_regex = re.compile('([^/])/+$')
def safe_normpath(path):
"""Like os.path.normpath but normalizes less aggressively thus being
potentially safer for paths containing symlinks."""
@ -185,7 +198,8 @@ def safe_normpath(path):
ret = slashend_regex.sub('\\1', ret)
return ret
def get_default_valid_rpmgroups(filename = None):
def get_default_valid_rpmgroups(filename=None):
"""Get default rpm groups from filename, or try to look them up from
the rpm package (if installed) if no filename is given"""
groups = []
@ -206,11 +220,12 @@ def get_default_valid_rpmgroups(filename = None):
fobj.close()
if 'Development/Debug' not in groups:
groups.append('Development/Debug')
if 'Unspecified' not in groups: # auto-added by rpm >= 4.6.0
if 'Unspecified' not in groups: # auto-added by rpm >= 4.6.0
groups.append('Unspecified')
groups.sort()
return groups
# from yum 3.2.27, rpmUtils.miscutils, with rpmlint modifications
def compareEVR(evr1, evr2):
(e1, v1, r1) = evr1
@ -230,6 +245,7 @@ def compareEVR(evr1, evr2):
rc = rpm.labelCompare((e1, v1, r1), (e2, v2, r2))
return rc
# from yum 3.2.27, rpmUtils.miscutils, with rpmlint modifications
def rangeCompare(reqtuple, provtuple):
"""returns true if provtuple satisfies reqtuple"""
@ -253,7 +269,7 @@ def rangeCompare(reqtuple, provtuple):
# "Requires: foo < 1.0" should not be satisfied by "Provides: foo = 1:0.5"
#if reqe is None:
# e = None
if reqv is None: # just for the record if ver is None then we're going to segfault
if reqv is None: # just for the record if ver is None then we're going to segfault
v = None
# if we just require foo-version, then foo-version-* will match
@ -307,6 +323,7 @@ def rangeCompare(reqtuple, provtuple):
return 0
# from yum 3.2.23, rpmUtils.miscutils, with rpmlint modifications
def formatRequire(name, flags, evr):
s = name
@ -324,6 +341,7 @@ def formatRequire(name, flags, evr):
s = "%s %s" % (s, versionToString(evr))
return s
def versionToString(evr):
if not isinstance(evr, (list, tuple)):
# assume string
@ -337,6 +355,7 @@ def versionToString(evr):
ret += "-" + evr[2]
return ret
# from yum 3.2.23, rpmUtils.miscutils, with some rpmlint modifications
def stringToVersion(verstring):
if verstring in (None, ''):
@ -365,6 +384,7 @@ def stringToVersion(verstring):
release = None
return (epoch, version, release)
def parse_deps(line):
'''Parse provides/requires/conflicts/obsoletes line to list of
(name, flags, (epoch, version, release)) tuples.'''
@ -434,7 +454,7 @@ class Pkg:
_magic_from_compressed_re = re.compile('\([^)]+\s+compressed\s+data\\b')
def __init__(self, filename, dirname, header = None, is_source = False):
def __init__(self, filename, dirname, header=None, is_source=False):
self.filename = filename
self.extracted = False
self.dirname = dirname
@ -508,8 +528,8 @@ class Pkg:
return None
else:
self.dirname = tempfile.mkdtemp(
prefix = 'rpmlint.%s.' % os.path.basename(self.filename),
dir = self.dirname)
prefix='rpmlint.%s.' % os.path.basename(self.filename),
dir=self.dirname)
# TODO: better shell escaping or sequence based command invocation
command_str = \
'rpm2cpio "%s" | (cd "%s"; cpio -id); chmod -R +rX "%s"' % \
@ -629,7 +649,7 @@ class Pkg:
provides = [b2s(x) for x in self.header[rpm.RPMTAG_FILEPROVIDE]]
files = [b2s(x) for x in self.header[rpm.RPMTAG_FILENAMES]]
magics = [b2s(x) for x in self.header[rpm.RPMTAG_FILECLASS]]
try: # rpm >= 4.7.0
try: # rpm >= 4.7.0
filecaps = self.header[rpm.RPMTAG_FILECAPS]
except:
filecaps = None
@ -732,7 +752,7 @@ class Pkg:
# internal function to gather dependency info used by the above ones
def _gather_aux(self, header, list, nametag, flagstag, versiontag,
prereq = None):
prereq=None):
names = header[nametag]
flags = header[flagstag]
versions = header[versiontag]
@ -784,6 +804,7 @@ class Pkg:
prog = b' '.join(prog)
return b2s(prog)
def getInstalledPkgs(name):
"""Get list of installed package objects by name."""
@ -800,9 +821,10 @@ def getInstalledPkgs(name):
return pkgs
# Class to provide an API to an installed package
class InstalledPkg(Pkg):
def __init__(self, name, hdr = None):
def __init__(self, name, hdr=None):
if not hdr:
ts = rpm.TransactionSet()
mi = ts.dbMatch('name', name)
@ -827,6 +849,7 @@ class InstalledPkg(Pkg):
def checkSignature(self):
return (0, 'fake: pgp md5 OK')
# Class to provide an API to a "fake" package, eg. for specfile-only checks
class FakePkg:
def __init__(self, name):
@ -837,6 +860,7 @@ class FakePkg:
def cleanup(self):
pass
# Class for files in packages
class PkgFile(object):
@ -862,10 +886,10 @@ class PkgFile(object):
# TODO: decompression support
is_config = property(lambda self: self.flags & rpm.RPMFILE_CONFIG)
is_doc = property(lambda self: self.flags & rpm.RPMFILE_DOC)
is_config = property(lambda self: self.flags & rpm.RPMFILE_CONFIG)
is_doc = property(lambda self: self.flags & rpm.RPMFILE_DOC)
is_noreplace = property(lambda self: self.flags & rpm.RPMFILE_NOREPLACE)
is_ghost = property(lambda self: self.flags & rpm.RPMFILE_GHOST)
is_ghost = property(lambda self: self.flags & rpm.RPMFILE_GHOST)
is_missingok = property(lambda self: self.flags & rpm.RPMFILE_MISSINGOK)

View File

@ -50,7 +50,7 @@ menu_regex = re.compile('^/usr/lib/menu/|^/etc/menu-methods/|^/usr/share/applica
bogus_var_regex = re.compile('(\${?RPM_BUILD_(ROOT|DIR)}?)')
prereq_assoc = (
# ['chkconfig', ('chkconfig', '/sbin/chkconfig')],
#['chkconfig', ('chkconfig', '/sbin/chkconfig')],
['chkfontpath', ('chkfontpath', '/usr/sbin/chkfontpath')],
['rpm-helper', ('rpm-helper',)],
)
@ -72,11 +72,14 @@ script_tags = [
(rpm.RPMTAG_VERIFYSCRIPT, rpm.RPMTAG_VERIFYSCRIPTPROG, '%verifyscript'),
]
def incorrect_shell_script(prog, shellscript):
return check_syntax_script(prog,'-n', shellscript)
return check_syntax_script(prog, '-n', shellscript)
def incorrect_perl_script(prog, perlscript):
return check_syntax_script(prog,'-wc', perlscript)
return check_syntax_script(prog, '-wc', perlscript)
def check_syntax_script(prog, commandline, script):
if not script:

View File

@ -20,8 +20,8 @@ source_regex = re.compile('\\.(tar|patch|tgz|diff)$')
compress_ext = Config.getOption("CompressExtension", "bz2")
valid_src_perms = Config.getOption("ValidSrcPerms", DEFAULT_VALID_SRC_PERMS)
class SourceCheck(AbstractCheck.AbstractCheck):
class SourceCheck(AbstractCheck.AbstractCheck):
def __init__(self):
AbstractCheck.AbstractCheck.__init__(self, 'SourceCheck')

View File

@ -11,7 +11,7 @@ import re
import unicodedata
try:
from urlparse import urlparse
except ImportError: # Python 3
except ImportError: # Python 3
from urllib.parse import urlparse
import rpm
@ -31,24 +31,23 @@ DEFAULT_BIARCH_PACKAGES = '^(gcc|glibc)'
# be installed on biarch systems
DEFAULT_HARDCODED_LIB_PATH_EXCEPTIONS = '/lib/(modules|cpp|perl5|rpm|hotplug|firmware)($|[\s/,])'
def re_tag_compile(tag):
if type(tag) == type([]):
tag = '(?:' + '|'.join(tag) + ')'
r = "^%s\s*:\s*(\S.*?)\s*$" % tag
return re.compile(r, re.IGNORECASE)
patch_regex = re_tag_compile('Patch(\d*)')
applied_patch_regex = re.compile("^%patch(\d*)")
applied_patch_p_regex = re.compile("\s-P\s+(\d+)\\b")
applied_patch_pipe_regex = re.compile(r'\s%\{PATCH(\d+)\}\s*\|\s*(%\{?__)?patch\b')
source_dir_regex = re.compile("^[^#]*(\$RPM_SOURCE_DIR|%{?_sourcedir}?)")
obsolete_tags_regex = re_tag_compile(['Serial','Copyright'])
obsolete_tags_regex = re_tag_compile(['Serial', 'Copyright'])
buildroot_regex = re_tag_compile('BuildRoot')
prefix_regex = re_tag_compile('Prefix')
packager_regex = re_tag_compile('Packager')
buildarch_regex = re_tag_compile(['BuildArch','BuildArchitectures'])
buildarch_regex = re_tag_compile(['BuildArch', 'BuildArchitectures'])
buildprereq_regex = re_tag_compile('BuildPreReq')
prereq_regex = re_tag_compile('PreReq(\(.*\))')
@ -82,7 +81,7 @@ hardcoded_library_path_regex = re.compile('^[^#]*((^|\s+|\.\./\.\.|\${?RPM_BUILD
# https://bugzilla.redhat.com/118780 and bugs linked to that one.
scriptlet_requires_regex = re.compile('^(PreReq|Requires)\([^\)]*,', re.IGNORECASE)
DEFINE_RE='(^|\s)%(define|global)\s+'
DEFINE_RE = '(^|\s)%(define|global)\s+'
depscript_override_regex = re.compile(DEFINE_RE + '__find_(requires|provides)\s')
depgen_disable_regex = re.compile(DEFINE_RE + '_use_internal_dependency_generator\s+0')
patch_fuzz_override_regex = re.compile(DEFINE_RE + '_default_patch_fuzz\s+(\d+)')
@ -110,18 +109,20 @@ tarball_regex = re.compile('\.(?:t(?:ar|[glx]z|bz2?)|zip)\\b', re.IGNORECASE)
UNICODE_NBSP = unicodedata.lookup('NO-BREAK SPACE')
def unversioned(deps):
'''Yield unversioned dependency names from the given list.'''
for dep in deps:
if not dep[1]:
yield dep[0]
def contains_buildroot(line):
'''Check if the given line contains use of rpm buildroot.'''
res = rpm_buildroot_regex.search(line)
if res and \
(not res.group(1) or len(res.group(1)) % 2 == 0) and \
(not res.group(2) or len(res.group(2)) % 2 != 0):
(not res.group(1) or len(res.group(1)) % 2 == 0) and \
(not res.group(2) or len(res.group(2)) % 2 != 0):
return True
return False
@ -171,7 +172,7 @@ class SpecCheck(AbstractCheck.AbstractCheck):
if_depth = 0
ifarch_depth = -1
current_section = 'package'
buildroot_clean = {'clean': False, 'install' : False}
buildroot_clean = {'clean': False, 'install': False}
depscript_override = False
depgen_disabled = False
patch_fuzz_override = False
@ -337,7 +338,7 @@ class SpecCheck(AbstractCheck.AbstractCheck):
if current_section != 'changelog' and res and not \
(biarch_package_regex.match(pkg.name) or
hardcoded_lib_path_exceptions_regex.search(
res.group(1).lstrip())):
res.group(1).lstrip())):
printError(pkg, "hardcoded-library-path", "in",
res.group(1).lstrip())
@ -482,7 +483,7 @@ class SpecCheck(AbstractCheck.AbstractCheck):
# If not checking spec file only, we're checking one inside a
# SRPM -> skip this check to avoid duplicate warnings (#167)
if spec_only and VALID_GROUPS and \
line.lower().startswith("group:"):
line.lower().startswith("group:"):
group = line[6:].strip()
if group not in VALID_GROUPS:
printWarning(pkg, 'non-standard-group', group)
@ -491,7 +492,7 @@ class SpecCheck(AbstractCheck.AbstractCheck):
if hashPos != -1 and \
(hashPos == 0 or line[hashPos-1] in (" ", "\t")):
for match in AbstractCheck.macro_regex.findall(
line[hashPos+1:]):
line[hashPos+1:]):
res = re.match('%+', match)
if len(res.group(0)) % 2:
printWarning(pkg, 'macro-in-comment', match)
@ -577,7 +578,7 @@ class SpecCheck(AbstractCheck.AbstractCheck):
for src in sources:
(url, num, flags) = src
(scheme, netloc) = urlparse(url)[0:2]
if flags & 1: # rpmspec.h, rpm.org ticket #123
if flags & 1: # rpmspec.h, rpm.org ticket #123
srctype = "Source"
else:
srctype = "Patch"
@ -835,7 +836,7 @@ intended contents.''',
'patch-fuzz-is-changed',
'''The internal patch fuzz value was changed, and could hide patchs issues, or
could lead to applying a patch at the wrong location. Usually, this is often the
could lead to applying a patch at the wrong location. Usually, this is often the
sign that someone didn't check if a patch is still needed and do not want to rediff
it. It is usually better to rediff the patch and try to send it upstream.'''
)

View File

@ -13,7 +13,7 @@ import re
import time
try:
from urlparse import urlparse
except ImportError: # Python 3
except ImportError: # Python 3
from urllib.parse import urlparse
import rpm
@ -42,8 +42,8 @@ DEFAULT_VALID_LICENSES = (
# the full name). Updated 2010-02-01.
'Academic Free License',
'Adaptive Public License',
'AGPLv3', # Affero GNU Public License
'AGPLv3+', # Affero GNU Public License
'AGPLv3', # Affero GNU Public License
'AGPLv3+', # Affero GNU Public License
'Apache License',
'Apache Software License',
'Apple Public Source License',
@ -52,7 +52,7 @@ DEFAULT_VALID_LICENSES = (
'BSD',
'Boost Software License',
'Computer Associates Trusted Open Source License',
'CDDL', # Common Development and Distribution License
'CDDL', # Common Development and Distribution License
'Common Public Attribution License',
'CUA Office Public License',
'EU DataGrid Software License',
@ -83,7 +83,7 @@ DEFAULT_VALID_LICENSES = (
'MirOS License',
'MIT',
'Motosoto License',
'MPL', # Mozilla Public License
'MPL', # Mozilla Public License
'Multics License',
'NASA Open Source Agreement',
'Naumen Public License',
@ -92,13 +92,13 @@ DEFAULT_VALID_LICENSES = (
'Non-profit Open Software License',
'NTP License',
'OCLC Research Public License',
'OFL', # Open Font License
'OFL', # Open Font License
'Open Group Test Suite License',
'Open Software License',
'PHP License',
'Python license', # CNRI Python License
'Python license', # CNRI Python License
'Python Software Foundation License',
'QPL', # Qt Public License
'QPL', # Qt Public License
'RealNetworks Public Source License',
'Reciprocal Public License',
'Ricoh Source Code Public License',
@ -121,8 +121,8 @@ DEFAULT_VALID_LICENSES = (
'Creative Commons Attribution-NonCommercial-ShareAlike',
'Creative Commons Attribution-ShareAlike',
# Others:
'Design Public License', # ???
'GFDL', # GNU Free Documentation License
'Design Public License', # ???
'GFDL', # GNU Free Documentation License
'LaTeX Project Public License',
'OpenContent License',
'Open Publication License',
@ -400,7 +400,7 @@ BAD_WORDS = {
DEFAULT_INVALID_REQUIRES = ('^is$', '^not$', '^owned$', '^by$', '^any$', '^package$', '^libsafe\.so\.')
VALID_GROUPS = Config.getOption('ValidGroups', None)
if VALID_GROUPS is None: # get defaults from rpm package only if it's not set
if VALID_GROUPS is None: # get defaults from rpm package only if it's not set
VALID_GROUPS = Pkg.get_default_valid_rpmgroups()
VALID_LICENSES = Config.getOption('ValidLicenses', DEFAULT_VALID_LICENSES)
INVALID_REQUIRES = map(re.compile, Config.getOption('InvalidRequires', DEFAULT_INVALID_REQUIRES))
@ -440,6 +440,8 @@ for path in ('%perl_archlib', '%perl_vendorarch', '%perl_sitearch',
private_so_paths.add(re.sub(r'/lib(?=/|$)', '/lib64', epath))
_enchant_checkers = {}
def spell_check(pkg, str, fmt, lang, ignored):
dict_found = True
@ -452,9 +454,9 @@ def spell_check(pkg, str, fmt, lang, ignored):
if not checker and lang not in _enchant_checkers:
try:
checker = enchant.checker.SpellChecker(
lang, filters = [ enchant.tokenize.EmailFilter,
enchant.tokenize.URLFilter,
enchant.tokenize.WikiWordFilter ])
lang, filters=[enchant.tokenize.EmailFilter,
enchant.tokenize.URLFilter,
enchant.tokenize.WikiWordFilter])
except enchant.DictNotFoundError:
printInfo(pkg, 'enchant-dictionary-not-found', lang)
pass
@ -738,7 +740,7 @@ class TagsCheck(AbstractCheck.AbstractCheck):
# only check when source name correspond to name
if srpm[0:-8] == '%s-%s-%s' % (name, version, release):
expected = [version + '-' + release]
if epoch is not None: # regardless of use_epoch
if epoch is not None: # regardless of use_epoch
expected[0] = str(epoch) + ':' + expected[0]
# Allow EVR in changelog without release extension,
# the extension is often a macro or otherwise dynamic.
@ -758,13 +760,13 @@ class TagsCheck(AbstractCheck.AbstractCheck):
clt = pkg[rpm.RPMTAG_CHANGELOGTIME][0]
if clt:
clt -= clt % (24*3600) # roll back to 00:00:00, see #246
clt -= clt % (24*3600) # roll back to 00:00:00, see #246
if clt < oldest_changelog_timestamp:
printWarning(pkg, 'changelog-time-overflow',
time.strftime("%Y-%m-%d", time.gmtime(clt)))
elif clt > time.time():
printError(pkg, 'changelog-time-in-future',
time.strftime("%Y-%m-%d", time.gmtime(clt)))
time.strftime("%Y-%m-%d", time.gmtime(clt)))
# for provide_name in (x[0] for x in pkg.provides()):
# if name == provide_name:
@ -794,12 +796,12 @@ class TagsCheck(AbstractCheck.AbstractCheck):
for tag in ('URL', 'DistURL', 'BugURL'):
if hasattr(rpm, 'RPMTAG_%s' % tag.upper()):
url = Pkg.b2s(pkg[getattr(rpm, 'RPMTAG_%s' % tag.upper())])
self._unexpanded_macros(pkg, tag, url, is_url = True)
self._unexpanded_macros(pkg, tag, url, is_url=True)
if url:
(scheme, netloc) = urlparse(url)[0:2]
if not scheme or not netloc or "." not in netloc or \
scheme not in ('http', 'https', 'ftp') or \
(Config.getOption('InvalidURL') and \
(Config.getOption('InvalidURL') and
invalid_url_regex.search(url)):
printWarning(pkg, 'invalid-url', tag, url)
else:
@ -867,7 +869,6 @@ class TagsCheck(AbstractCheck.AbstractCheck):
printWarning(pkg, "private-shared-object-provides",
fname, Pkg.formatRequire(*prov))
def check_description(self, pkg, lang, ignored_words):
description = pkg.langtag(rpm.RPMTAG_DESCRIPTION, lang)
self._unexpanded_macros(pkg, '%%description -l %s' % lang, description)

View File

@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
#------------------------------------------------------------------------------
#############################################################################
# File : ZipCheck.py
# Package : rpmlint
# Author : Ville Skyttä
# Created on : Thu Oct 30 00:14:45 EET 2003
# Purpose : Verify Zip/Jar file correctness
#------------------------------------------------------------------------------
#############################################################################
import os
import re
@ -24,6 +24,7 @@ classpath_regex = re.compile('^\s*Class-Path\s*:', re.M | re.I)
want_indexed_jars = Config.getOption('UseIndexedJars', True)
class ZipCheck(AbstractCheck.AbstractCheck):
def __init__(self):
@ -33,8 +34,8 @@ class ZipCheck(AbstractCheck.AbstractCheck):
for fname, pkgfile in pkg.files().items():
path = pkgfile.path
if zip_regex.search(fname) and os.path.exists(path) and \
stat.S_ISREG(os.lstat(path)[stat.ST_MODE]) and \
zipfile.is_zipfile(path):
stat.S_ISREG(os.lstat(path)[stat.ST_MODE]) and \
zipfile.is_zipfile(path):
z = None
try:
z = zipfile.ZipFile(path, 'r')

File diff suppressed because it is too large Load Diff

20
rpmlint
View File

@ -30,7 +30,7 @@ sys.path.insert(1, '/usr/share/rpmlint')
# place for those variables.
from Filter import badnessScore, badnessThreshold, printAllReasons, \
printDescriptions, printInfo, printed_messages, setRawOut
printDescriptions, printInfo, printed_messages, setRawOut
import AbstractCheck
import Config
import Pkg
@ -39,6 +39,7 @@ import Pkg
_default_user_conf = '%s/rpmlint' % \
(os.environ.get('XDG_CONFIG_HOME') or '~/.config')
# Print usage information
def usage(name):
print ('''usage: %s [<options>] <rpm files|installed packages|specfiles|dirs>
@ -55,13 +56,15 @@ def usage(name):
\t[-n|--noexception]
\t[ --rawout <file>]
\t[-f|--file <user config file to use instead of %s]
\t[-o|--option <key value>]''' \
% (name, _default_user_conf))
\t[-o|--option <key value>]'''
% (name, _default_user_conf))
# Print version information
def printVersion():
print ('rpmlint version %s Copyright (C) 1999-2007 Frederic Lepied, Mandriva' % Config.__version__)
def loadCheck(name):
'''Load a (check) module by its name, unless it is already loaded.'''
# Avoid loading more than once (initialization costs)
@ -74,6 +77,7 @@ def loadCheck(name):
finally:
fobj.close()
#############################################################################
# main program
#############################################################################
@ -135,8 +139,8 @@ def main():
Pkg.warn(
'(none): E: no installed packages by name %s' % arg)
else:
ipkgs.sort(key = lambda x: locale.strxfrm(
x.header.sprintf("%{NAME}.%{ARCH}")))
ipkgs.sort(key=lambda x: locale.strxfrm(
x.header.sprintf("%{NAME}.%{ARCH}")))
pkgs.extend(ipkgs)
except KeyboardInterrupt:
if isfile:
@ -194,7 +198,7 @@ def main():
sys.exit(66)
finally:
print("%d packages and %d specfiles checked; %d errors, %d warnings." \
print("%d packages and %d specfiles checked; %d errors, %d warnings."
% (packages_checked, specfiles_checked,
printed_messages["E"], printed_messages["W"]))
@ -202,6 +206,7 @@ def main():
sys.exit(64)
sys.exit(0)
def runChecks(pkg):
try:
@ -218,6 +223,7 @@ def runChecks(pkg):
finally:
pkg.cleanup()
def runSpecChecks(pkg, fname):
try:
@ -228,7 +234,7 @@ def runSpecChecks(pkg, fname):
check = AbstractCheck.AbstractCheck.known_checks.get(name)
if check:
check.verbose = verbose
check.check_spec(pkg,fname)
check.check_spec(pkg, fname)
else:
Pkg.warn('(none): W: unknown check %s, skipping' % name)
finally:

View File

@ -10,27 +10,33 @@ import Pkg
currently_testing = 0
output = []
def isTest():
return currently_testing
def startTest():
global currently_testing
global output
output = []
currently_testing = 1
def addOutput(s):
global output
output.append(s)
def getOutput():
global output
return output
def getTestedPackage(name):
pkg_path = glob.glob(os.environ['TESTPATH'] + '/' + name + '-*.rpm')[0]
return Pkg.Pkg(pkg_path, tempfile.gettempdir())
def getTestedSpecPackage(name):
pkg_path = glob.glob(os.environ['TESTPATH'] + '/' + name + '.spec')[0]
return Pkg.FakePkg(pkg_path)

View File

@ -11,12 +11,12 @@ langs = set()
countries = set()
# 2-letter country codes
tree = ElementTree(file = "/usr/share/xml/iso-codes/iso_3166.xml")
tree = ElementTree(file="/usr/share/xml/iso-codes/iso_3166.xml")
for entry in tree.findall("iso_3166_entry"):
countries.add(entry.get("alpha_2_code"))
# 2-letter codes
tree = ElementTree(file = "/usr/share/xml/iso-codes/iso_639.xml")
tree = ElementTree(file="/usr/share/xml/iso-codes/iso_639.xml")
for entry in tree.findall("iso_639_entry"):
for attr in ("iso_639_1_code", "iso_639_2T_code"):
code = entry.get(attr)
@ -25,7 +25,7 @@ for entry in tree.findall("iso_639_entry"):
break
# Remaining 2-letter codes plus 3-letter ones for which we have no 2-letter one
tree = ElementTree(file = "/usr/share/xml/iso-codes/iso_639_3.xml")
tree = ElementTree(file="/usr/share/xml/iso-codes/iso_639_3.xml")
for entry in tree.findall("iso_639_3_entry"):
code = entry.get("part1_code")
if code:
@ -38,11 +38,11 @@ print ""
print "LANGUAGES = set(("
for code in sorted(langs):
if code:
print "\t\"%s\"," % code
print " \"%s\"," % code
print "))"
print ""
print "COUNTRIES = set(("
for code in sorted(countries):
if code:
print "\t\"%s\"," % code
print " \"%s\"," % code
print "))"