2011-04-14 08:52:26 +02:00
|
|
|
import subprocess
|
|
|
|
import portage
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import re
|
|
|
|
|
2011-04-14 19:28:38 +02:00
|
|
|
from StringIO import StringIO
|
2011-04-14 08:52:26 +02:00
|
|
|
from datetime import datetime
|
|
|
|
from portage import versions
|
|
|
|
from optparse import make_option
|
|
|
|
|
|
|
|
from django.db.transaction import commit_on_success
|
|
|
|
from django.core.management.base import BaseCommand, CommandError
|
2011-08-25 15:39:54 +02:00
|
|
|
from euscanwww.euscan.models import Package, Version, EuscanResult, VersionLog
|
2011-04-14 08:52:26 +02:00
|
|
|
|
|
|
|
class Command(BaseCommand):
|
|
|
|
_overlays = {}
|
|
|
|
|
|
|
|
option_list = BaseCommand.option_list + (
|
|
|
|
make_option('--all',
|
|
|
|
action='store_true',
|
|
|
|
dest='all',
|
|
|
|
default=False,
|
|
|
|
help='Scan all packages'),
|
2011-04-14 19:28:38 +02:00
|
|
|
make_option('--feed',
|
2011-04-14 08:52:26 +02:00
|
|
|
action='store_true',
|
2011-04-14 19:28:38 +02:00
|
|
|
dest='feed',
|
2011-04-14 08:52:26 +02:00
|
|
|
default=False,
|
2011-04-14 19:28:38 +02:00
|
|
|
help='Read euscan output from stdin'),
|
2011-08-25 15:39:54 +02:00
|
|
|
make_option('--purge-versions',
|
|
|
|
action='store_true',
|
|
|
|
dest='purge-versions',
|
|
|
|
default=False,
|
|
|
|
help='Purge old versions'),
|
2011-04-14 08:52:26 +02:00
|
|
|
make_option('--quiet',
|
|
|
|
action='store_true',
|
|
|
|
dest='quiet',
|
|
|
|
default=False,
|
|
|
|
help='Be quiet'),
|
|
|
|
)
|
|
|
|
args = '<package package ...>'
|
|
|
|
help = 'Scans metadata and fills database'
|
|
|
|
|
|
|
|
def handle(self, *args, **options):
|
2011-04-14 19:28:38 +02:00
|
|
|
if len(args) == 0 and options['all'] == False and options['feed'] == False:
|
2011-04-14 08:52:26 +02:00
|
|
|
raise CommandError('You must specify a package or use --all')
|
|
|
|
|
2011-04-14 19:28:38 +02:00
|
|
|
if options['feed']:
|
|
|
|
self.parse_output(options, sys.stdin)
|
2011-08-25 15:39:54 +02:00
|
|
|
if options['purge-versions']:
|
|
|
|
self.purge_versions(options)
|
2011-04-14 19:28:38 +02:00
|
|
|
return
|
|
|
|
|
2011-04-14 08:52:26 +02:00
|
|
|
if not options['quiet']:
|
|
|
|
self.stdout.write('Scanning upstream...\n')
|
|
|
|
|
|
|
|
packages = []
|
|
|
|
|
|
|
|
if len(args) == 0:
|
|
|
|
for pkg in Package.objects.all():
|
|
|
|
packages.append('%s/%s' % (pkg.category, pkg.name))
|
|
|
|
else:
|
|
|
|
packages = list(args)
|
|
|
|
|
|
|
|
self.scan(options, packages)
|
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
if options['purge-versions']:
|
|
|
|
self.purge_versions(options)
|
|
|
|
|
2011-04-14 08:52:26 +02:00
|
|
|
if not options['quiet']:
|
|
|
|
self.stdout.write('Done.\n')
|
|
|
|
|
|
|
|
def scan(self, options, packages=None):
|
2011-04-14 19:28:38 +02:00
|
|
|
for package in packages:
|
|
|
|
cmd = ['euscan', package]
|
2011-04-14 08:52:26 +02:00
|
|
|
|
2011-04-14 19:28:38 +02:00
|
|
|
fp = subprocess.Popen(cmd, stdout=subprocess.PIPE)
|
|
|
|
output = StringIO(fp.communicate()[0])
|
2011-04-14 08:52:26 +02:00
|
|
|
|
|
|
|
self.parse_output(options, output)
|
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
@commit_on_success
|
2011-04-14 08:52:26 +02:00
|
|
|
def parse_output(self, options, output):
|
|
|
|
from portage.versions import _cp
|
|
|
|
|
|
|
|
package_re = re.compile(r'^ \* (?P<cpv>' + _cp + ') \[(?P<overlay>.*?)\]$')
|
|
|
|
version_re = re.compile(r'^Upstream Version: (?P<ver>.*?) (?P<url>.*?)$')
|
|
|
|
|
|
|
|
package = None
|
|
|
|
log = ""
|
|
|
|
|
2011-04-14 19:28:38 +02:00
|
|
|
while True:
|
|
|
|
line = output.readline()
|
|
|
|
if line == '':
|
|
|
|
break
|
2011-04-14 08:52:26 +02:00
|
|
|
match = package_re.match(line)
|
|
|
|
if match:
|
|
|
|
if package:
|
|
|
|
self.store_result(options, package, log)
|
|
|
|
|
|
|
|
cpv = match.group('cpv')
|
|
|
|
package = self.store_package(options, cpv)
|
|
|
|
log = line
|
|
|
|
continue
|
|
|
|
|
|
|
|
log += line
|
|
|
|
|
|
|
|
match = version_re.match(line)
|
|
|
|
if match:
|
|
|
|
ver = match.group('ver')
|
|
|
|
url = match.group('url')
|
|
|
|
self.store_version(options, package, ver, url)
|
|
|
|
|
|
|
|
if package:
|
|
|
|
self.store_result(options, package, log)
|
|
|
|
|
|
|
|
def store_result(self, options, package, log):
|
2011-08-22 10:46:56 +02:00
|
|
|
# Remove previous logs
|
|
|
|
EuscanResult.objects.filter(package=package).delete()
|
|
|
|
|
2011-04-14 08:52:26 +02:00
|
|
|
obj = EuscanResult()
|
|
|
|
obj.package = package
|
|
|
|
obj.result = log
|
|
|
|
obj.datetime = datetime.now()
|
|
|
|
obj.save()
|
|
|
|
|
2011-08-22 10:46:56 +02:00
|
|
|
|
2011-04-14 08:52:26 +02:00
|
|
|
def store_package(self, options, cpv):
|
|
|
|
cat, pkg, ver, rev = portage.catpkgsplit(cpv)
|
|
|
|
|
|
|
|
obj, created = Package.objects.get_or_create(category=cat, name=pkg)
|
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
if created and not options['quiet']:
|
|
|
|
sys.stdout.write('+ [p] %s/%s\n' % (cat, pkg))
|
2011-04-14 08:52:26 +02:00
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
' Set all versions dead, then set found versions alive and delete old versions '
|
|
|
|
Version.objects.filter(package=obj, packaged=False).update(alive=False)
|
2011-04-14 08:52:26 +02:00
|
|
|
|
|
|
|
return obj
|
|
|
|
|
|
|
|
def store_version(self, options, package, ver, url):
|
|
|
|
obj, created = Version.objects.get_or_create(package=package, slot='',
|
|
|
|
revision='r0', version=ver,
|
|
|
|
overlay='')
|
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
obj.alive = True
|
|
|
|
obj.urls = url
|
|
|
|
obj.packaged = False
|
|
|
|
obj.save()
|
|
|
|
|
|
|
|
''' If it's not a new version, just update the object and continue '''
|
|
|
|
if not created:
|
|
|
|
return
|
|
|
|
|
|
|
|
if not options['quiet']:
|
|
|
|
sys.stdout.write('+ [u] %s %s\n' % (obj, url))
|
|
|
|
|
|
|
|
entry = VersionLog.objects.create(package=package, action=VersionLog.VERSION_ADDED)
|
|
|
|
entry.slot = ''
|
|
|
|
entry.revision = 'r0'
|
|
|
|
entry.version = ver
|
|
|
|
entry.overlay = ''
|
|
|
|
entry.save()
|
|
|
|
|
|
|
|
package.n_versions += 1
|
|
|
|
package.save()
|
2011-04-14 08:52:26 +02:00
|
|
|
|
|
|
|
|
2011-08-25 15:39:54 +02:00
|
|
|
@commit_on_success
|
|
|
|
def purge_versions(self, options):
|
|
|
|
' For each dead versions '
|
|
|
|
for version in Version.objects.filter(packaged=False, alive=False):
|
|
|
|
entry = VersionLog.objects.create(package=version.package, action=VersionLog.VERSION_REMOVED)
|
|
|
|
entry.slot = version.slot
|
|
|
|
entry.revision = version.revision
|
|
|
|
entry.version = version.version
|
|
|
|
entry.overlay = version.overlay
|
|
|
|
entry.save()
|
|
|
|
|
|
|
|
version.package.n_versions -= 1
|
|
|
|
version.package.save()
|
|
|
|
|
|
|
|
if not options['quiet']:
|
|
|
|
sys.stdout.write('- [u] %s %s\n' % (version, version.urls))
|
|
|
|
Version.objects.filter(packaged=False, alive=False).delete()
|
|
|
|
|