def __init__(self, fname="", base_url=None): DpkgParagraph.__init__(self, fname) self.base_url = base_url self.__files = None self.__urls = None self.__pkgid = None self.__source_version = None
def __init__(self, pkgfile=None): """ path -- path to .deb package """ self.control = DpkgParagraph() self.md5sums = None self.__md5files = None self.changes = None self.news = None self.files = None self.__raw_files = None self.path = None if pkgfile: self.path = os.path.abspath(pkgfile) if not os.path.isfile(self.path): raise DpkgDebPackageException("Unable to locate file: %s" % self.path) self.load_control()
def load_control(self): """ Reads control information into memory """ if self.path and os.path.isfile(self.path): tempdir = self.__extract_control() fhdl = open(os.path.join(tempdir, "control"), "r") self.control = DpkgParagraph() self.control.load(fhdl) fhdl.close() if not self.__parse_md5sums(tempdir): self._logger.warning("Can't parse md5sums") else: self.__md5files = [xsum[1] for xsum in self.md5sums] shutil.rmtree(tempdir, True) else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path)
class DpkgDebPackage(LoggableObject): """This class represent complete information about Debian binary package""" def __init__(self, pkgfile=None): """ path -- path to .deb package """ self.control = DpkgParagraph() self.md5sums = None self.__md5files = None self.changes = None self.news = None self.files = None self.__raw_files = None self.path = None if pkgfile: self.path = os.path.abspath(pkgfile) if not os.path.isfile(self.path): raise DpkgDebPackageException("Unable to locate file: %s" % self.path) self.load_control() def load(self, path=None, getfiles=True, getchanges='both'): """ Loads .deb file for processing """ path_changed = False if not path and not self.path: raise DpkgDebPackageException("No deb file specified") if path: new_path = os.path.abspath(path) if new_path != self.path: self.path = new_path path_changed = True if not os.path.isfile(self.path): raise DpkgDebPackageException("Unable to locate file: %s" % self.path) if path_changed or not self.control: self.load_control() if getchanges: self.load_changes(getchanges) if getfiles: self.load_contents() def load_contents(self): """ Reads contents of .deb file into memory """ if self.path and os.path.isfile(self.path): self.__raw_files = self.__list_contents() if self.__raw_files: self.files = [fname[5] for fname in self.__raw_files] else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def load_changes(self, getchanges='both'): """ Reads changelog and/or news information into memory """ if self.path and os.path.isfile(self.path): (news, changes) = self.__extract_changes(getchanges) self.news = news self.changes = changes else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def load_control(self): """ Reads control information into memory """ if self.path and os.path.isfile(self.path): tempdir = self.__extract_control() fhdl = open(os.path.join(tempdir, "control"), "r") self.control = DpkgParagraph() self.control.load(fhdl) fhdl.close() if not self.__parse_md5sums(tempdir): self._logger.warning("Can't parse md5sums") else: self.__md5files = [xsum[1] for xsum in self.md5sums] shutil.rmtree(tempdir, True) else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def __extract_changes(self, which, since_version=None): '''Extract changelog entries, news or both from the package. If since_version is specified, only return entries later than the specified version. returns a sequence of Changes objects.''' def changelog_variations(fname): """Return list of all possible changelog/news locations""" formats = ['usr/doc/*/%s.gz', 'usr/share/doc/*/%s.gz', 'usr/doc/*/%s', 'usr/share/doc/*/%s', './usr/doc/*/%s.gz', './usr/share/doc/*/%s.gz', './usr/doc/*/%s', './usr/share/doc/*/%s'] return [fmt % fname for fmt in formats] news_filenames = changelog_variations('NEWS.Debian') changelog_filenames = changelog_variations('changelog.Debian') changelog_filenames_native = changelog_variations('changelog') filenames = [] if which == 'both' or which == 'news': filenames.extend(news_filenames) if which == 'both' or which == 'changelogs': filenames.extend(changelog_filenames) filenames.extend(changelog_filenames_native) tempdir = self.extract_contents(filenames) news = None for filename in news_filenames: news = self.__read_changelog(os.path.join(tempdir, filename), since_version) if news: break changelog = None for batch in (changelog_filenames, changelog_filenames_native): for filename in batch: changelog = self.__read_changelog(os.path.join(tempdir, filename), since_version) if changelog: break if changelog: break shutil.rmtree(tempdir, True) return (news, changelog) def __extract_control(self): """Extracts content of control.tar.gz from .deb package""" try: tempdir = tempfile.mkdtemp(prefix='dpkgdebpackage') except AttributeError: tempdir = tempfile.mktemp() os.mkdir(tempdir) extract_command = 'ar p %s control.tar.gz | tar zxf - -C %s 2>/dev/null' % (self.path, tempdir) os.system(extract_command) return tempdir def extract_contents(self, filenames): """Extracts partial contents of Debian package to temporary directory""" try: tempdir = tempfile.mkdtemp(prefix='dpkgdebpackage') except AttributeError: tempdir = tempfile.mktemp() os.mkdir(tempdir) extract_command = 'ar p %s data.tar.gz |tar zxf - -C %s %s 2>/dev/null' % ( self.path, tempdir, ' '.join(["'%s'" % filen for filen in filenames]) ) # tar exits unsuccessfully if _any_ of the files we wanted # were not available, so we can't do much with its status os.system(extract_command) return tempdir def __parse_md5sums(self, tempdir): """Parses md5sums file from extracted control section of debian package""" path = os.path.join(tempdir, "md5sums") if not os.access(path, os.R_OK): print "Can't open file %s" % path return False self.md5sums = [] fhdl = open(path, "r") for line in fhdl.readlines(): if line[33] != " ": print "33 is not a space.\n %s" % line # Something bad happend, unknown file format. fhdl.close() return False argl = [line[:32].strip(), line[34:].strip()] self.md5sums.append(argl) fhdl.close() return True def __list_contents(self): """Returns filelist of data.tar.gz""" (status, output) = commands.getstatusoutput("ar p %s data.tar.gz | tar ztvf -" % self.path) if status != 0: return [] files = [line.split() for line in output.splitlines()] return files def __read_changelog(self, filename, since_version): """Read changelog up to specified version""" changelog_header = re.compile('^\S+ \((?P<version>.*)\) .*;.*urgency=(?P<urgency>\w+).*') filenames = glob.glob(filename) fhdl = None for filename in filenames: try: if filename.endswith('.gz'): fhdl = gzip.GzipFile(filename) else: fhdl = open(filename) break except IOError, ioerr: if ioerr.errno == errno.ENOENT: pass else: raise if not fhdl: return None changes = '' is_debian_changelog = 0 for line in fhdl.readlines(): match = changelog_header.match(line) if match: is_debian_changelog = 1 if since_version: if DpkgVersion(match.group('version')) <= since_version: break changes += line fhdl.close() if not is_debian_changelog: return None return changes
class DpkgDebPackage(LoggableObject): """This class represent complete information about Debian binary package""" def __init__(self, pkgfile=None): """ path -- path to .deb package """ self.control = DpkgParagraph() self.md5sums = None self.__md5files = None self.changes = None self.news = None self.files = None self.__raw_files = None self.path = None if pkgfile: self.path = os.path.abspath(pkgfile) if not os.path.isfile(self.path): raise DpkgDebPackageException("Unable to locate file: %s" % self.path) self.load_control() def load(self, path=None, getfiles=True, getchanges='both'): """ Loads .deb file for processing """ path_changed = False if not path and not self.path: raise DpkgDebPackageException("No deb file specified") if path: new_path = os.path.abspath(path) if new_path != self.path: self.path = new_path path_changed = True if not os.path.isfile(self.path): raise DpkgDebPackageException("Unable to locate file: %s" % self.path) if path_changed or not self.control: self.load_control() if getchanges: self.load_changes(getchanges) if getfiles: self.load_contents() def load_contents(self): """ Reads contents of .deb file into memory """ if self.path and os.path.isfile(self.path): self.__raw_files = self.__list_contents() if self.__raw_files: self.files = [fname[5] for fname in self.__raw_files] else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def load_changes(self, getchanges='both'): """ Reads changelog and/or news information into memory """ if self.path and os.path.isfile(self.path): (news, changes) = self.__extract_changes(getchanges) self.news = news self.changes = changes else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def load_control(self): """ Reads control information into memory """ if self.path and os.path.isfile(self.path): tempdir = self.__extract_control() fhdl = open(os.path.join(tempdir, "control"), "r") self.control = DpkgParagraph() self.control.load(fhdl) fhdl.close() if not self.__parse_md5sums(tempdir): self._logger.warning("Can't parse md5sums") else: self.__md5files = [xsum[1] for xsum in self.md5sums] shutil.rmtree(tempdir, True) else: raise DpkgDebPackageException("Unable to locate file: %s" % self.path) def __extract_changes(self, which, since_version=None): '''Extract changelog entries, news or both from the package. If since_version is specified, only return entries later than the specified version. returns a sequence of Changes objects.''' def changelog_variations(filename): """Return list of all possible changelog/news locations""" formats = [ 'usr/doc/*/%s.gz', 'usr/share/doc/*/%s.gz', 'usr/doc/*/%s', 'usr/share/doc/*/%s', './usr/doc/*/%s.gz', './usr/share/doc/*/%s.gz', './usr/doc/*/%s', './usr/share/doc/*/%s' ] return [format % filename for format in formats] news_filenames = changelog_variations('NEWS.Debian') changelog_filenames = changelog_variations('changelog.Debian') changelog_filenames_native = changelog_variations('changelog') filenames = [] if which == 'both' or which == 'news': filenames.extend(news_filenames) if which == 'both' or which == 'changelogs': filenames.extend(changelog_filenames) filenames.extend(changelog_filenames_native) tempdir = self.extract_contents(filenames) news = None for filename in news_filenames: news = self.__read_changelog(os.path.join(tempdir, filename), since_version) if news: break changelog = None for batch in (changelog_filenames, changelog_filenames_native): for filename in batch: changelog = self.__read_changelog( os.path.join(tempdir, filename), since_version) if changelog: break if changelog: break shutil.rmtree(tempdir, True) return (news, changelog) def __extract_control(self): """Extracts content of control.tar.gz from .deb package""" try: tempdir = tempfile.mkdtemp(prefix='dpkgdebpackage') except AttributeError: tempdir = tempfile.mktemp() os.mkdir(tempdir) extract_command = 'ar p %s control.tar.gz | tar zxf - -C %s 2>/dev/null' % ( self.path, tempdir) os.system(extract_command) return tempdir def extract_contents(self, filenames): """Extracts partial contents of Debian package to temporary directory""" try: tempdir = tempfile.mkdtemp(prefix='dpkgdebpackage') except AttributeError: tempdir = tempfile.mktemp() os.mkdir(tempdir) extract_command = 'ar p %s data.tar.gz |tar zxf - -C %s %s 2>/dev/null' % ( self.path, tempdir, ' '.join( ["'%s'" % filen for filen in filenames])) # tar exits unsuccessfully if _any_ of the files we wanted # were not available, so we can't do much with its status os.system(extract_command) return tempdir def __parse_md5sums(self, tempdir): """Parses md5sums file from extracted control section of debian package""" path = os.path.join(tempdir, "md5sums") if not os.access(path, os.R_OK): print "Can't open file %s" % path return False self.md5sums = [] fhdl = open(path, "r") for line in fhdl.readlines(): if line[33] != " ": print "33 is not a space.\n %s" % line # Something bad happend, unknown file format. fhdl.close() return False argl = [line[:32].strip(), line[34:].strip()] self.md5sums.append(argl) fhdl.close() return True def __list_contents(self): """Returns filelist of data.tar.gz""" (status, output) = commands.getstatusoutput( "ar p %s data.tar.gz | tar ztvf -" % self.path) if status != 0: return [] files = [line.split() for line in output.splitlines()] return files def __read_changelog(self, filename, since_version): """Read changelog up to specified version""" changelog_header = re.compile( '^\S+ \((?P<version>.*)\) .*;.*urgency=(?P<urgency>\w+).*') filenames = glob.glob(filename) fhdl = None for filename in filenames: try: if filename.endswith('.gz'): fhdl = gzip.GzipFile(filename) else: fhdl = open(filename) break except IOError, ioerr: if ioerr.errno == errno.ENOENT: pass else: raise if not fhdl: return None changes = '' is_debian_changelog = 0 for line in fhdl.readlines(): match = changelog_header.match(line) if match: is_debian_changelog = 1 if since_version: if DpkgVersion(match.group('version')) <= since_version: break changes += line fhdl.close() if not is_debian_changelog: return None return changes