Florian Festi wrote: > > Please add the packages you changed or plan to change to > https://fedoraproject.org/wiki/Features/NoarchSubpackages/PackagesChanged > Put the later in parenthesis. That way it will be easier to justify a > release note entry and to argue that the Feature is (at least a bit) > finished. > I explored what would be changed if we enabled a lenient-hash check on these files I discovered these things: 1) Asking reviewers to check this is pretty hard. I'll add the steps at the end. 2) If reviewers are expected to do this, we need to get our user interface changes to rpmdiff merged upstream. rpmlint's rpmdiff can only ignore timestamp. Reviewers are going to want to have something like lenient-hash as well. 3) devhelp documentation should be marked as %doc 4) It might be reasonable for --lenient-hash to not check f.startswith('/usr/share')... I'm on the fence about this. 5) Most of these would have checked fine even if we used a full hash check instead of lenient 6) I discoverd a package with architecture specific differences. Luckily, it's just a problem in documentation. Check results with: ./rpmdiff.mine -iS -iT --lenient-hash Script attached. Summary: 23 packages listed 14 actually built with noarch subpackages 1 false positive (dbus) (files should have been marked %doc) 1 actual problem detected (dbus) 13 problem free runs So the net change would have been one package. Not sure if the maintainer would have caught the noarch vs arch specific difference as it is an error within documentation and they might have just added %doc without exploring further. ConsoleKit: package has failed rebuild dbus: package has false positives that would be fixed by marking devhelp as %doc - the dbus documentation is not arch-independent: * /usr/share/devhelp/books/dbus/api/dbus-arch-deps_8h-source.html * /usr/share/devhelp/books/dbus/api/group__DBusTypes.html em8300: no false positives evolution: no false positives evolution-data-server: No false positives festival: package has failed rebuild gdl: failed rebuild gmt: No false positives gnome-games: No false positives gnome-session: Latest version reverts noarch subpackage gtk2: No false positives javasqlite: not built with noarch subpackage kst: not rebuilt with noarch subpackage libtheora: no false positives libxcb: no false positives with --lenient-hash * There is a harmless difference in two png files used in documentation ncl: no false positives nted: failed rebuild PackageKit: no false positives paraview: no false positives PolicyKit: no false positives with --lenient-hash pygobject2: hasn't been rebuilt pygtk2: no false positives xemacs: hasn't been rebuilt Steps a reviewer would have to take: 1) Submit SRPM as a scratch build in koji. 2) Go to the package page 3) Go to the build page for the scratch build. 4) Go to the task page for the build 5) For at least two dissimilar architectures, click on the task for that arch. 6) For each of those tasks, download any noarch packages that were built (minimum 2 clicks) 7) run /usr/bin/rpmdiff --ignore-times on each of those pairs of packages. 8) For each of the many differences, decide whether the problem is an actual problem. -Toshio
#!/usr/bin/python # # Copyright (C) 2006 Mandriva; 2009 Red Hat, Inc. # Authors: Frederic Lepied, Florian Festi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as published by # the Free Software Foundation; version 2 only # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # This library and program is heavily based on rpmdiff from the rpmlint package # It was modified to be used as standalone library for the Koji project. import rpm import os import itertools import sys, getopt class Rpmdiff: # constants TAGS = ( rpm.RPMTAG_NAME, rpm.RPMTAG_SUMMARY, rpm.RPMTAG_DESCRIPTION, rpm.RPMTAG_GROUP, rpm.RPMTAG_LICENSE, rpm.RPMTAG_URL, rpm.RPMTAG_PREIN, rpm.RPMTAG_POSTIN, rpm.RPMTAG_PREUN, rpm.RPMTAG_POSTUN) PRCO = ( 'REQUIRES', 'PROVIDES', 'CONFLICTS', 'OBSOLETES') #{fname : (size, mode, mtime, flags, dev, inode, # nlink, state, vflags, user, group, digest)} __FILEIDX = [ ['S', 0], ['M', 1], ['5', 11], ['D', 4], ['N', 6], ['L', 7], ['V', 8], ['U', 9], ['G', 10], ['F', 3], ['T', 2] ] try: if rpm.RPMSENSE_SCRIPT_PRE: PREREQ_FLAG=rpm.RPMSENSE_PREREQ|rpm.RPMSENSE_SCRIPT_PRE|\ rpm.RPMSENSE_SCRIPT_POST|rpm.RPMSENSE_SCRIPT_PREUN|\ rpm.RPMSENSE_SCRIPT_POSTUN except AttributeError: try: PREREQ_FLAG=rpm.RPMSENSE_PREREQ except: #(proyvind): This seems ugly, but then again so does # this whole check as well. PREREQ_FLAG=False DEPFORMAT = '%-12s%s %s %s %s' FORMAT = '%-12s%s' ADDED = 'added' REMOVED = 'removed' # code starts here def __init__(self, old, new, ignore=None, lenient_hash=False): self.result = [] self.ignore = ignore if self.ignore is None: self.ignore = [] FILEIDX = self.__FILEIDX for tag in self.ignore: for entry in FILEIDX: if tag == entry[0]: entry[1] = None break old = self.__load_pkg(old) new = self.__load_pkg(new) # Compare single tags for tag in self.TAGS: old_tag = old[tag] new_tag = new[tag] if old_tag != new_tag: tagname = rpm.tagnames[tag] if old_tag == None: self.__add(self.FORMAT, (self.ADDED, tagname)) elif new_tag == None: self.__add(self.FORMAT, (self.REMOVED, tagname)) else: self.__add(self.FORMAT, ('S.5........', tagname)) # compare Provides, Requires, ... for tag in self.PRCO: self.__comparePRCOs(old, new, tag) # compare the files old_files_dict = self.__fileIteratorToDict(old.fiFromHeader()) new_files_dict = self.__fileIteratorToDict(new.fiFromHeader()) files = list(set(itertools.chain(old_files_dict.iterkeys(), new_files_dict.iterkeys()))) files.sort() for f in files: diff = 0 old_file = old_files_dict.get(f) new_file = new_files_dict.get(f) if not old_file: self.__add(self.FORMAT, (self.ADDED, f)) elif not new_file: self.__add(self.FORMAT, (self.REMOVED, f)) else: format = '' for entry in FILEIDX: if entry[1] != None and \ old_file[entry[1]] != new_file[entry[1]]: format = format + entry[0] diff = 1 else: format = format + '.' if lenient_hash: # 11 => hash of file # 3 => flags for file if (old_file[11] != new_file[11] and not ( new_file[3] == rpm.RPMFILE_DOC or f.endswith('.pyc') or f.endswith('.pyo'))): format = format[:2] + '5' + format[2:] diff = 1 else: format = format[:2] + '.' + format[2:] if diff: self.__add(self.FORMAT, (format, f)) # return a report of the differences def textdiff(self): return '\n'.join((format % data for format, data in self.result)) # do the two rpms differ def differs(self): return bool(self.result) # add one differing item def __add(self, format, data): self.result.append((format, data)) # load a package from a file or from the installed ones def __load_pkg(self, filename): ts = rpm.ts() f = os.open(filename, os.O_RDONLY) hdr = ts.hdrFromFdno(f) os.close(f) return hdr # output the right string according to RPMSENSE_* const def sense2str(self, sense): s = "" for tag, char in ((rpm.RPMSENSE_LESS, "<"), (rpm.RPMSENSE_GREATER, ">"), (rpm.RPMSENSE_EQUAL, "=")): if sense & tag: s += char return s # compare Provides, Requires, Conflicts, Obsoletes def __comparePRCOs(self, old, new, name): oldflags = old[name[:-1]+'FLAGS'] newflags = new[name[:-1]+'FLAGS'] # fix buggy rpm binding not returning list for single entries if not isinstance(oldflags, list): oldflags = [ oldflags ] if not isinstance(newflags, list): newflags = [ newflags ] o = zip(old[name], oldflags, old[name[:-1]+'VERSION']) n = zip(new[name], newflags, new[name[:-1]+'VERSION']) if name == 'PROVIDES': # filter our self provide oldNV = (old['name'], rpm.RPMSENSE_EQUAL, "%s-%s" % (old['version'], old['release'])) newNV = (new['name'], rpm.RPMSENSE_EQUAL, "%s-%s" % (new['version'], new['release'])) o = [entry for entry in o if entry != oldNV] n = [entry for entry in n if entry != newNV] for oldentry in o: if not oldentry in n: if name == 'REQUIRES' and oldentry[1] & self.PREREQ_FLAG: tagname = 'PREREQ' else: tagname = name self.__add(self.DEPFORMAT, (self.REMOVED, tagname, oldentry[0], self.sense2str(oldentry[1]), oldentry[2])) for newentry in n: if not newentry in o: if name == 'REQUIRES' and newentry[1] & self.PREREQ_FLAG: tagname = 'PREREQ' else: tagname = name self.__add(self.DEPFORMAT, (self.ADDED, tagname, newentry[0], self.sense2str(newentry[1]), newentry[2])) def __fileIteratorToDict(self, fi): result = {} for filedata in fi: result[filedata[0]] = filedata[1:] return result def _usage(exit=1): print "Usage: %s [<options>] <old package> <new package>" % sys.argv[0] print "Options:" print " -h, --help Output this message and exit" print " -i, --ignore Tag to ignore when calculating differences" print " (may be used multiple times)" print " Valid values are: SM5DNLVUGFT" print " --lenient-hash Ignore hash only for certain files: %doc," print " *.pyc, *.pyo" print " (this implies -i5)" sys.exit(exit) def main(): ignore_tags = [] try: opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "ignore=", "lenient-hash"]) except getopt.GetoptError, e: print "Error: %s" % e _usage() lenient = False for option, argument in opts: if option in ("-h", "--help"): _usage(0) if option in ("-i", "--ignore"): ignore_tags.append(argument) elif option in ("--lenient-hash"): ignore_tags.append("5") lenient = True if len(args) != 2: _usage() d = Rpmdiff(args[0], args[1], ignore=ignore_tags, lenient_hash=lenient) print d.textdiff() sys.exit(int(d.differs())) if __name__ == '__main__': main() # rpmdiff ends here
Attachment:
signature.asc
Description: OpenPGP digital signature
-- fedora-devel-list mailing list fedora-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/fedora-devel-list