euscan-ng/bin/euscan_patch_metadata

215 lines
5.7 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env python
import os
import re
import urllib
from tempfile import mkstemp
import tarfile
import gzip
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, deb_type = get_deb_url(package.name)
if deb_type == "source":
return handle_source(deb_url)
if deb_type == "diff":
return handle_diff(deb_url)
def handle_diff(deb_url):
_, temp_deb = mkstemp()
logger.info(" Downloading debian diff %s...", deb_url)
urllib.urlretrieve(deb_url, temp_deb)
watch_data = ""
fp = gzip.open(temp_deb, 'rb')
for line in fp:
if re.match(r"\+\+\+ .+?/debian/watch", line):
fp.readline() # diff lines, don't care
cur_line = fp.readline()
while cur_line.startswith("+"):
watch_data += cur_line[1:]
cur_line = fp.readline()
fp.close()
os.unlink(temp_deb)
return watch_data
def handle_source(deb_url):
_, 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
deb_type = 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"]
deb_type = "source"
break
if re.match("[^\s]+\.diff\.gz", link.text):
deb_url = link["href"]
deb_type = "diff"
break
if not deb_url:
logger.error(" Cannot get package from %s" % url)
name = raw_input(" Package name in Debian: ")
return deb_url, deb_type
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_quote, attrs, url = result.groups()
attrs = attrs_quote or attrs
if attrs:
attrs = [x.replace('=', '="') + '"' for x in attrs.split(",")]
attrs = " ".join(attrs)
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<watch %s %s>%s</watch>' % (indent, version, attrs, url)
else:
watch_tag = '%s<watch %s>%s</watch>' % (indent, version, url)
if '<upstream>' in data:
data = data.replace('<upstream>', '<upstream>\n%s' % watch_tag, 1)
else:
rep = '%s<upstream>\n%s\n%s</upstream>\n</pkgmetadata>' % \
(rindent, watch_tag, rindent)
data = data.replace('</pkgmetadata>', 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 <package> [<package> [...]]",
)
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()