#!/usr/bin/env python import os import re import urllib from tempfile import mkstemp import tarfile import logging import shutil from gentoolkit.query import Query from BeautifulSoup import BeautifulSoup, SoupStrainer logger = logging.getLogger(__name__) # From portage-janitor def guess_indent_values(before): rindent = -1 indent = -1 tab = False def guess_for_tags(tags): for tag in tags: for i in [0, 2, 4, 6, 8, 12, 16]: if '\n%s<%s' % (' ' * i, tag) in before: return i, False for i in [0, 1, 2]: if '\n%s<%s' % ('\t' * i, tag) in before: return i, True return -1, False rindent, tab = guess_for_tags( ['herd', 'maintainer', 'longdescription', 'use', 'upstream'] ) if rindent == -1: rindent = 2 rindent_str = ('\t' if tab else ' ') * rindent indent, tab = guess_for_tags(['watch', 'name', 'email']) if indent == -1: indent = rindent * 2 if rindent else 4 if rindent and rindent_str == '\t': tab = True indent_str = ('\t' if tab else ' ') * indent return rindent_str, indent_str def get_watch_data(package): deb_url = get_deb_url(package.name) _, temp_deb = mkstemp() temp_dir = os.path.dirname(temp_deb) logger.info(" Downloading debian source %s...", deb_url) urllib.urlretrieve(deb_url, temp_deb) tar = tarfile.open(temp_deb) watch_data = None try: tar.extract("debian/watch", temp_dir) except KeyError: pass else: debian_path = os.path.join(temp_dir, "debian") watch_path = os.path.join(debian_path, "watch") watch_data = open(os.path.join(watch_path)).read() shutil.rmtree(debian_path) os.unlink(temp_deb) return watch_data def get_deb_url(name): deb_url = None while not deb_url: url = "http://packages.debian.org/source/unstable/%s" % name opened = urllib.urlopen(url) content = opened.read() for link in BeautifulSoup(content, parseOnlyThese=SoupStrainer("a")): if re.match("[^\s]+\.debian\.tar\.gz", link.text): deb_url = link["href"] break if not deb_url: logger.error(" Cannot get package from %s" % url) name = raw_input(" Package name in Debian: ") return deb_url def patch_metadata(metadata_path, watch_data): watch_data = "\n".join([line for line in watch_data.split("\n") if not line.startswith("#")]) # comments watch_data = watch_data.replace("\\\n", "") # remove backslashes watch_data = " ".join(watch_data.split()) # remove extra spaces and \n result = re.match( r'(version=\d+?) (opts=(?:"[^"]+?"|[^\s]+?) )?(.*)', watch_data ) version, attrs, url = [r.strip() for r in result.groups()] with open(metadata_path) as fp: original = fp.read() rindent, indent = guess_indent_values(original) data = original logger.info(" Patching metadata file") if attrs: watch_tag = '%s%s' % (indent, version, attrs, url) else: watch_tag = '%s%s' % (indent, version, url) if '' in data: data = data.replace('', '\n%s' % watch_tag, 1) else: rep = '%s\n%s\n%s\n' % \ (rindent, watch_tag, rindent) data = data.replace('', rep, 1) print data def process_package(query): matches = Query(query).smart_find( in_installed=True, in_porttree=True, in_overlay=True, include_masked=True, show_progress=False, no_matches_fatal=False, ) if len(matches) == 0: logger.error(" Package not found") return None matches = sorted(matches) package = matches.pop() if '9999' in package.version and len(matches) > 0: package = matches.pop() metadata_path = package.metadata.metadata_path watch_data = get_watch_data(package) if watch_data is None: logger.error(" No watch file found") else: patch_metadata(metadata_path, watch_data) def main(): import optparse p = optparse.OptionParser( usage="usage: %prog [ [...]]", ) opts, packages = p.parse_args() logging.basicConfig(level=logging.INFO, format='%(message)s') for package in packages: logger.info("Processing %s..." % package) process_package(package) if __name__ == "__main__": main()