summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHolger Freyther <zecke@selfish.org>2006-05-03 23:34:38 +0000
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>2006-05-03 23:34:38 +0000
commit9ebd3327ea63e2a3ffbae655c73fbc535b904f6e (patch)
tree7dd85d86b2117aedac7cdc1ae77bc5196edc6b39
parent59a30d011ab87e0c548218ae5f4cfc76f3b18e64 (diff)
parent8c0187854b498bc0603590205213e604ad76a636 (diff)
merge of 3a1f3b49721651ad51810489d8d2924c5e347a54
and cb1b20a4461b3e3cbbc5d4c0596b25de8394246c
-rw-r--r--contrib/qa/.mtn2git_empty0
-rw-r--r--contrib/qa/ipkg-diff/.mtn2git_empty0
-rw-r--r--contrib/qa/ipkg-diff/README12
-rw-r--r--contrib/qa/ipkg-diff/ipkg-diff134
-rw-r--r--contrib/qa/ipkg-diff/ipkg.py462
5 files changed, 608 insertions, 0 deletions
diff --git a/contrib/qa/.mtn2git_empty b/contrib/qa/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/qa/.mtn2git_empty
diff --git a/contrib/qa/ipkg-diff/.mtn2git_empty b/contrib/qa/ipkg-diff/.mtn2git_empty
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/qa/ipkg-diff/.mtn2git_empty
diff --git a/contrib/qa/ipkg-diff/README b/contrib/qa/ipkg-diff/README
new file mode 100644
index 0000000000..7ddc4419cd
--- /dev/null
+++ b/contrib/qa/ipkg-diff/README
@@ -0,0 +1,12 @@
+A Small utility to diff two directories of Itsy Packages.
+
+This utility will take two directories hopefully containing
+Itsy Packages (ipk) and compare the ipks. It will find deleted
+and new packages but will also compare packages with the same
+name. And check file types, sizes, control files. And one time
+it will be able to find upgrades and scan them as well.
+
+(this script is meant to be hacky, hacky, hacky and to do the
+ job)
+
+The only pattern applied is a Anti-Pattern: Time pressure
diff --git a/contrib/qa/ipkg-diff/ipkg-diff b/contrib/qa/ipkg-diff/ipkg-diff
new file mode 100644
index 0000000000..276b8b2e1e
--- /dev/null
+++ b/contrib/qa/ipkg-diff/ipkg-diff
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# License of this file:
+# Copy, Modify, Change, Sell it at your will.
+#
+# There is absolutely no warranty with this file
+#
+# (C) Copyright 2006 Holger Hans Peter Freyther
+
+
+
+def check_dir(name, error):
+ """
+ Check if the given directory exists, if not error
+ is printed and the application is left.
+ """
+ import os, sys
+ import stat
+ if not os.path.isdir(name):
+ print error
+ sys.exit(-1)
+
+
+def find_packages(dir):
+ import os
+ contents = os.listdir(dir)
+ ipks = []
+ for f in contents:
+ (root,ext) = os.path.splitext(f)
+ if ext == ".ipk":
+ ipks.append( f )
+ return ipks
+
+def diff_dirs( old_ipks, new_ipks ):
+ """
+ We will return three lists. The first one will
+ contain the files that are only in a, the second
+ the files in both directories and the third one
+ will
+ """
+ only_old = [ i for i in old_ipks if i not in new_ipks]
+ both = [ i for i in old_ipks if i in new_ipks ]
+ only_new = [ i for i in new_ipks if i not in old_ipks]
+
+ return only_old, both, only_new
+
+def diff_packages( old, new ):
+ def compare( name, version, method, txt ):
+ """
+ Compare package with name and version with method
+ and print error message
+ """
+ try:
+ if not method( old[package_name][version], new[package_name][version] ):
+ print txt
+ except:
+ print "Error with %s %s and '%s'" % (package_name,version, txt)
+
+ for package_name in old.keys():
+ for version in old[package_name].keys():
+ print "Comparing %s %s" % (package_name, version)
+ compare( package_name, version, lambda x,y: x.get_maintainer() == y.get_maintainer(), "Maintainer is different" )
+ compare( package_name, version, lambda x,y: x.get_architecture() == y.get_architecture(), "Architecture is different" )
+ compare( package_name, version, lambda x,y: x.get_description() == y.get_description(), "Description is different" )
+ compare( package_name, version, lambda x,y: x.get_depends() == y.get_depends(), "Depends are different" )
+ compare( package_name, version, lambda x,y: x.get_provides() == y.get_provides(), "Provides are different" )
+ compare( package_name, version, lambda x,y: x.get_conflicts() == y.get_conflicts(), "Provides are different" )
+ compare( package_name, version, lambda x,y: x.get_suggests() == y.get_suggests(), "Suggests are different" )
+ compare( package_name, version, lambda x,y: x.get_source() == y.get_source(), "Source is different" )
+ compare( package_name, version, lambda x,y: x.get_section() == y.get_section(), "Section is different" )
+ compare( package_name, version, lambda x,y: x.get_file_list() == y.get_file_list(), "Filelist is different" )
+ compare( package_name, version, lambda x,y: x.md5 == y.md5, "MD5 is different" )
+
+def print_result_start( old, both, new ):
+ """
+ Print the findings of ipkg-diff
+ """
+ print "ipkg-diff diff report"
+ print "%d packages found" % (len(old)+len(both)+len(new))
+ print "# of old/removed packages: %d" % len(old)
+ print "# of new packages: %d" % len(new)
+ print "# of possible changed packages: %d" % len(both)
+ print ""
+
+ if len(old) > 0:
+ for i in old:
+ print "Vanished ipk: %s" % i
+
+ if len(new) > 0:
+ for i in new:
+ print "New ipk: %s" % i
+
+
+def parse_packages(dir, package_names):
+ import ipkg, os
+ packages = {}
+
+ for package in package_names:
+ p = ipkg.Package(os.path.join(dir, package))
+
+ if not p.get_package() in packages:
+ packages[p.get_package()] = {}
+ packages[p.get_package()][p.get_version()] = p
+
+ return packages
+
+
+if __name__ == "__main__":
+ import os,sys
+
+ # sanity
+ if len(sys.argv) != 3:
+ print "ipkg-diff OLD NEW"
+ sys.exit(-2)
+
+ # check dirs
+ check_dir(sys.argv[1], "Source Directory does not exist")
+ check_dir(sys.argv[2], "Dest Directory does not exists")
+
+ # find packages
+ old_ipks = find_packages(sys.argv[1])
+ new_ipks = find_packages(sys.argv[2])
+
+ # find removed and new files
+ only_old, both, only_new = diff_dirs( old_ipks, new_ipks )
+
+ # print a summary header
+ print_result_start( only_old, both, only_new )
+
+ # start diffing the content by parsing the packages
+ print "Loading Content into memory"
+ old_packages = parse_packages(sys.argv[1], both )
+ new_packages = parse_packages(sys.argv[2], both )
+
+ diff_packages( old_packages, new_packages )
diff --git a/contrib/qa/ipkg-diff/ipkg.py b/contrib/qa/ipkg-diff/ipkg.py
new file mode 100644
index 0000000000..02aab229ee
--- /dev/null
+++ b/contrib/qa/ipkg-diff/ipkg.py
@@ -0,0 +1,462 @@
+#!/usr/bin/env python
+# Copyright (C) 2001 Alexander S. Guy <a7r@andern.org>
+# Andern Research Labs
+#
+# 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
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU 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. */
+#
+# Copyright 2001, Russell Nelson <ipkg.py@russnelson.com>
+# Added reading in of packages.
+# Added missing package information fields.
+# Changed render_control() to __repr__().
+#
+# Current Issues:
+# The API doesn't validate package information fields. It should be
+# throwing exceptions in the right places.
+# Executions of tar could silently fail.
+# Executions of tar *do* fail, and loudly, because you have to specify a full filename,
+# and tar complains if any files are missing, and the ipkg spec doesn't require
+# people to say "./control.tar.gz" or "./control" when they package files.
+# It would be much better to require ./control or disallow ./control (either)
+# rather than letting people pick. Some freedoms aren't worth their cost.
+
+import tempfile
+import os
+import sys
+import glob
+import md5
+import re
+import string
+import commands
+from stat import ST_SIZE
+
+class Version:
+ """A class for holding parsed package version information."""
+ def __init__(self, epoch, version):
+ self.epoch = epoch
+ self.version = version
+
+ def _versioncompare(self, ref):
+ selfversion = self.version
+ refversion = ref.version
+ while 1:
+ ## first look for non-numeric version component
+ selfm = re.match('([^0-9]*)(.*)', selfversion)
+ #print 'selfm', selfm.groups()
+ (selfalpha, selfversion) = selfm.groups()
+ refm = re.match('([^0-9]*)(.*)', refversion)
+ #print 'refm', refm.groups()
+ (refalpha, refversion) = refm.groups()
+ if (selfalpha > refalpha):
+ return 1
+ elif (selfalpha < refalpha):
+ return -1
+ ## now look for numeric version component
+ (selfnum, selfversion) = re.match('([0-9]*)(.*)', selfversion).groups()
+ (refnum, refversion) = re.match('([0-9]*)(.*)', refversion).groups()
+ #print 'selfnum', selfnum, selfversion
+ #print 'refnum', refnum, refversion
+ if (selfnum != ''):
+ selfnum = int(selfnum)
+ else:
+ selfnum = -1
+ if (refnum != ''):
+ refnum = int(refnum)
+ else:
+ refnum = -1
+ if (selfnum > refnum):
+ return 1
+ elif (selfnum < refnum):
+ return -1
+ if selfversion == '' and refversion == '':
+ return 0
+
+ def compare(self, ref):
+ if (self.epoch > ref.epoch):
+ return 1
+ elif (self.epoch < ref.epoch):
+ return -1
+ else:
+ return self._versioncompare(ref)
+
+def parse_version(versionstr):
+ epoch = 0
+ # check for epoch
+ m = re.match('([0-9]*):(.*)', versionstr)
+ if m:
+ (epochstr, versionstr) = m.groups()
+ epoch = int(epochstr)
+ return Version(epoch, versionstr)
+
+class Package:
+ """A class for creating objects to manipulate (e.g. create) ipkg
+ packages."""
+ def __init__(self, fn=None):
+ self.package = None
+ self.version = 'none'
+ self.parsed_version = None
+ self.architecture = None
+ self.maintainer = None
+ self.source = None
+ self.description = None
+ self.depends = None
+ self.provides = None
+ self.replaces = None
+ self.conflicts = None
+ self.recommends = None
+ self.suggests = None
+ self.section = None
+ self.filename_header = None
+ self.file_list = []
+ self.md5 = None
+ self.size = None
+ self.installed_size = None
+ self.filename = None
+ self.isdeb = 0
+
+ if fn:
+ # see if it is deb format
+ f = open(fn, "r")
+ magic = f.read(4)
+ f.close()
+ if (magic == "!<ar"):
+ self.isdeb = 1
+
+ # compute the MD5.
+ f = open(fn, "r")
+ sum = md5.new()
+ while 1:
+ data = f.read(1024)
+ if not data: break
+ sum.update(data)
+ f.close()
+ if sys.version[:1] > '2':
+ # when using Python 2.0 or newer
+ self.md5 = sum.hexdigest()
+ else:
+ self.md5 = string.join(map((lambda x:"%02x" % ord(x)),sum.digest()),'')
+ stat = os.stat(fn)
+ self.size = stat[ST_SIZE]
+ self.filename = os.path.basename(fn)
+ ## sys.stderr.write(" extracting control.tar.gz from %s\n"% (fn,))
+ if self.isdeb:
+ control = os.popen("ar p "+fn+" control.tar.gz | tar xfzO - '*control'","r")
+ else:
+ control = os.popen("tar xfzO "+fn+" '*control.tar.gz' | tar xfzO - '*control'","r")
+ line = control.readline()
+ while 1:
+ if not line: break
+ line = string.rstrip(line)
+ lineparts = re.match(r'([\w-]*?):\s*(.*)', line)
+ if lineparts:
+ name = string.lower(lineparts.group(1))
+ value = lineparts.group(2)
+ while 1:
+ line = control.readline()
+ if not line: break
+ if line[0] != ' ': break
+ line = string.rstrip(line)
+ value = value + '\n' + line
+ # don't allow package to override its own filename
+ if name == "filename":
+ self.filename_header = value
+ else:
+ if self.__dict__.has_key(name):
+ self.__dict__[name] = value
+ else:
+ line = control.readline()
+ control.close()
+ if self.isdeb:
+ data = os.popen("ar p "+fn+" data.tar.gz | tar tfz -","r")
+ else:
+ data = os.popen("tar xfzO "+fn+" '*data.tar.gz' | tar tfz -","r")
+ while 1:
+ line = data.readline()
+ if not line: break
+ self.file_list.append(string.rstrip(line))
+ data.close()
+
+ self.scratch_dir = None
+ self.file_dir = None
+ self.meta_dir = None
+
+ def read_control(self, control):
+ import os
+
+ line = control.readline()
+ while 1:
+ if not line: break
+ line = string.rstrip(line)
+ lineparts = re.match(r'([\w-]*?):\s*(.*)', line)
+ if lineparts:
+ name = string.lower(lineparts.group(1))
+ value = lineparts.group(2)
+ while 1:
+ line = control.readline()
+ if not line: break
+ if line[0] != ' ': break
+ value = value + '\n' + line
+ if name == 'size':
+ self.size = int(value)
+ elif self.__dict__.has_key(name):
+ self.__dict__[name] = value
+ if line[0] == '\n':
+ return # consumes one blank line at end of package descriptoin
+ else:
+ line = control.readline()
+ pass
+ return
+
+ def _setup_scratch_area(self):
+ self.scratch_dir = "%s/%sipkg" % (tempfile.gettempdir(),
+ tempfile.gettempprefix())
+ self.file_dir = "%s/files" % (self.scratch_dir)
+ self.meta_dir = "%s/meta" % (self.scratch_dir)
+
+ os.mkdir(self.scratch_dir)
+ os.mkdir(self.file_dir)
+ os.mkdir(self.meta_dir)
+
+ def set_package(self, package):
+ self.package = package
+
+ def get_package(self):
+ return self.package
+
+ def set_version(self, version):
+ self.version = version
+ self.parsed_version = parse_version(version)
+
+ def get_version(self):
+ return self.version
+
+ def set_architecture(self, architecture):
+ self.architecture = architecture
+
+ def get_architecture(self):
+ return self.architecture
+
+ def set_maintainer(self, maintainer):
+ self.maintainer = maintainer
+
+ def get_maintainer(self):
+ return self.maintainer
+
+ def set_source(self, source):
+ self.source = source
+
+ def get_source(self):
+ return self.source
+
+ def set_description(self, description):
+ self.description = description
+
+ def get_description(self):
+ return self.description
+
+ def set_depends(self, depends):
+ self.depends = depends
+
+ def get_depends(self, depends):
+ return self.depends
+
+ def set_provides(self, provides):
+ self.provides = provides
+
+ def get_provides(self, provides):
+ return self.provides
+
+ def set_replaces(self, replaces):
+ self.replaces = replaces
+
+ def get_replaces(self, replaces):
+ return self.replaces
+
+ def set_conflicts(self, conflicts):
+ self.conflicts = conflicts
+
+ def get_conflicts(self, conflicts):
+ return self.conflicts
+
+ def set_suggests(self, suggests):
+ self.suggests = suggests
+
+ def get_suggests(self, suggests):
+ return self.suggests
+
+ def set_section(self, section):
+ self.section = section
+
+ def get_section(self, section):
+ return self.section
+
+ def get_file_list(self):
+ return self.file_list
+
+ def write_package(self, dirname):
+ buf = self.render_control()
+ file = open("%s/control" % self.meta_dir, 'w')
+ file.write(buf)
+
+ self._setup_scratch_area()
+ cmd = "cd %s ; tar cvfz %s/control.tar.gz control" % (self.meta_dir,
+ self.scratch_dir)
+
+ cmd_out, cmd_in, cmd_err = os.popen3(cmd)
+
+ while cmd_err.readline() != "":
+ pass
+
+ cmd_out.close()
+ cmd_in.close()
+ cmd_err.close()
+
+ bits = "control.tar.gz"
+
+ if self.file_list:
+ cmd = "cd %s ; tar cvfz %s/data.tar.gz" % (self.file_dir,
+ self.scratch_dir)
+
+ cmd_out, cmd_in, cmd_err = os.popen3(cmd)
+
+ while cmd_err.readline() != "":
+ pass
+
+ cmd_out.close()
+ cmd_in.close()
+ cmd_err.close()
+
+ bits = bits + " data.tar.gz"
+
+ file = "%s_%s_%s.ipk" % (self.package, self.version, self.architecture)
+ cmd = "cd %s ; tar cvfz %s/%s %s" % (self.scratch_dir,
+ dirname,
+ file,
+ bits)
+
+ cmd_out, cmd_in, cmd_err = os.popen3(cmd)
+
+ while cmd_err.readline() != "":
+ pass
+
+ cmd_out.close()
+ cmd_in.close()
+ cmd_err.close()
+
+ def compare_version(self, ref):
+ """Compare package versions of self and ref"""
+ if not self.version:
+ print 'No version for package %s' % self.package
+ if not ref.version:
+ print 'No version for package %s' % ref.package
+ if not self.parsed_version:
+ self.parsed_version = parse_version(self.version)
+ if not ref.parsed_version:
+ ref.parsed_version = parse_version(ref.version)
+ return self.parsed_version.compare(ref.parsed_version)
+
+ def __repr__(self):
+ out = ""
+
+ # XXX - Some checks need to be made, and some exceptions
+ # need to be thrown. -- a7r
+
+ if self.package: out = out + "Package: %s\n" % (self.package)
+ if self.version: out = out + "Version: %s\n" % (self.version)
+ if self.depends: out = out + "Depends: %s\n" % (self.depends)
+ if self.provides: out = out + "Provides: %s\n" % (self.provides)
+ if self.replaces: out = out + "Replaces: %s\n" % (self.replaces)
+ if self.conflicts: out = out + "Conflicts: %s\n" % (self.conflicts)
+ if self.suggests: out = out + "Suggests: %s\n" % (self.suggests)
+ if self.recommends: out = out + "Recommends: %s\n" % (self.recommends)
+ if self.section: out = out + "Section: %s\n" % (self.section)
+ if self.architecture: out = out + "Architecture: %s\n" % (self.architecture)
+ if self.maintainer: out = out + "Maintainer: %s\n" % (self.maintainer)
+ if self.md5: out = out + "MD5Sum: %s\n" % (self.md5)
+ if self.size: out = out + "Size: %d\n" % int(self.size)
+ if self.installed_size: out = out + "InstalledSize: %d\n" % int(self.installed_size)
+ if self.filename: out = out + "Filename: %s\n" % (self.filename)
+ if self.source: out = out + "Source: %s\n" % (self.source)
+ if self.description: out = out + "Description: %s\n" % (self.description)
+ out = out + "\n"
+
+ return out
+
+ def __del__(self):
+ # XXX - Why is the `os' module being yanked out before Package objects
+ # are being destroyed? -- a7r
+ pass
+
+class Packages:
+ """A currently unimplemented wrapper around the ipkg utility."""
+ def __init__(self):
+ self.packages = {}
+ return
+
+ def add_package(self, pkg):
+ package = pkg.package
+ arch = pkg.architecture
+ name = ("%s:%s" % (package, arch))
+ if (not self.packages.has_key(name)):
+ self.packages[name] = pkg
+
+ if pkg.compare_version(self.packages[name]) >= 0:
+ self.packages[name] = pkg
+ return 0
+ else:
+ return 1
+
+ def read_packages_file(self, fn):
+ f = open(fn, "r")
+ while 1:
+ pkg = Package()
+ pkg.read_control(f)
+ if pkg.get_package():
+ self.add_package(pkg)
+ else:
+ break
+ f.close()
+ return
+
+ def write_packages_file(self, fn):
+ f = open(fn, "w")
+ names = self.packages.keys()
+ names.sort()
+ for name in names:
+ f.write(self.packages[name].__repr__())
+ return
+
+ def keys(self):
+ return self.packages.keys()
+
+ def __getitem__(self, key):
+ return self.packages[key]
+
+if __name__ == "__main__":
+ package = Package()
+
+ package.set_package("FooBar")
+ package.set_version("0.1-fam1")
+ package.set_architecture("arm")
+ package.set_maintainer("Testing <testing@testing.testing>")
+ package.set_depends("libc")
+ package.set_description("A test of the APIs.")
+
+ print "<"
+ sys.stdout.write(package)
+ print ">"
+
+ package.write_package("/tmp")
+