diff --git a/bin/euscan b/bin/euscan
index e0371b4..441d479 100755
--- a/bin/euscan
+++ b/bin/euscan
@@ -5,7 +5,7 @@ Distributed under the terms of the GNU General Public License v2
"""
from __future__ import print_function
-
+import os
# Meta
@@ -19,7 +19,6 @@ __description__ = "A tool to detect new upstream releases."
# Imports
import sys
-import os
import getopt
from errno import EINTR, EINVAL
from httplib import HTTPConnection
diff --git a/euscanwww/djeuscan/admin.py b/euscanwww/djeuscan/admin.py
index a64007d..0322e18 100644
--- a/euscanwww/djeuscan/admin.py
+++ b/euscanwww/djeuscan/admin.py
@@ -7,7 +7,7 @@ from django.contrib import admin
class EuscanResultAdmin(admin.ModelAdmin):
search_fields = ('package__name', 'package__category')
- list_filter = ('datetime', )
+ list_filter = ('datetime', 'package__category')
ordering = ["-datetime"]
@@ -31,6 +31,12 @@ class VersionAdmin(admin.ModelAdmin):
list_filter = ('overlay', 'packaged', 'alive')
+class ProblemReportAdmin(admin.ModelAdmin):
+ list_display = ('package', 'subject', 'datetime')
+ search_fields = ('package__name', 'package__category')
+ list_filter = ('datetime', 'package__category')
+ ordering = ["-datetime"]
+
admin.site.register(Package, PackageAdmin)
admin.site.register(Herd, HerdAdmin)
@@ -52,4 +58,5 @@ admin.site.register(HerdAssociation)
admin.site.register(CategoryAssociation)
admin.site.register(MaintainerAssociation)
admin.site.register(PackageAssociation)
-admin.site.register(ProblemReport)
+
+admin.site.register(ProblemReport, ProblemReportAdmin)
diff --git a/euscanwww/djeuscan/models.py b/euscanwww/djeuscan/models.py
index 0c38909..6626a41 100644
--- a/euscanwww/djeuscan/models.py
+++ b/euscanwww/djeuscan/models.py
@@ -1,3 +1,5 @@
+import json
+
from django.db import models
from django.core.validators import RegexValidator, validate_email, URLValidator
from django.core.exceptions import ValidationError
@@ -215,6 +217,14 @@ class EuscanResult(models.Model):
self.full_clean()
super(EuscanResult, self).save(*args, **kwargs)
+ def messages(self):
+ result = json.loads(self.result)
+
+ if result and self.package.cp() in result:
+ return result[self.package.cp()]['messages']
+ else:
+ return ""
+
def __unicode__(self):
return '[%s] %s/%s' % (
self.datetime, self.package.category, self.package.name
diff --git a/euscanwww/djeuscan/templates/euscan/_package_details.html b/euscanwww/djeuscan/templates/euscan/_package_details.html
new file mode 100644
index 0000000..1e04911
--- /dev/null
+++ b/euscanwww/djeuscan/templates/euscan/_package_details.html
@@ -0,0 +1,122 @@
+{% load djeuscan_helpers %}
+{% load url from future %}
+
+
+ {% if package.description %}
+ - Description
+ - {{ package.description }}
+ {% endif %}
+ {% if package.homepage %}
+ - Homepage
+ -
+ {% for homepage in package.homepages %}
+ {{ homepage }}
+ {% endfor %}
+
+ {% endif %}
+ {% if package.herds.all %}
+ - Herds
+ -
+ {% for herd in package.herds.all %}
+
+ {{ herd.herd }}
+
+ <{{ herd.email }}>
+ {% endfor %}
+
+ {% endif %}
+ {% if package.maintainers.all %}
+ - Maintainers
+ -
+ {% for maintainer in package.maintainers.all %}
+ {% if maintainer.name != maintainer.email %}
+
+ {{ maintainer.name }}
+
+ <{{ maintainer.email }}>
+ {% else %}
+
+ {{ maintainer.email }}
+
+ {% endif %}
+ {% endfor %}
+
+ {% endif %}
+ {% if packaged %}
+ - Packaged Versions
+ -
+
+ {% for version in packaged %}
+ -
+ {% if version.overlay == "gentoo" %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% if version.vtype and not version.vtype|is_stable %}
+
+ {% endif %}
+
+ {{ version.version }}-{{ version.revision }} :{{ version.slot }} [{{ version.overlay }}]
+
+ {% endfor %}
+
+
+ {% endif %}
+ {% if upstream %}
+ - Upstream versions
+ -
+
+ {% for version in upstream %}
+ -
+
+
+ {% if version.vtype and not version.vtype|is_stable %}
+
+ {% endif %}
+
+ {{ version.version }} - {{ version.urls }}
+ {% if confidence < 100 %}({{ version.confidence }}%){% endif %}
+
+ {% endfor %}
+
+
+ {% endif %}
+ {% if vlog %}
+ - Version history
+ -
+
+ {% for version in vlog %}
+ {% if version.action == version.VERSION_ADDED %}
+ -
+ {% else %}
+
-
+ {% endif %}
+ {% if version.overlay == "gentoo" %}
+
+ {% elif version.overlay %}
+
+ {% else %}
+
+ {% endif %}
+
+ {% if version.vtype and not version.vtype|is_stable %}
+
+ {% endif %}
+
+ {{ version }} - {{ version.datetime }}
+
+
+ {% endfor %}
+
+
+ {% endif %}
+ {% if log %}
+ - euscan log
+ -
+
Date: {{ log.datetime }}
+
{{ msg|ansi_to_html|safe }}
+
+ {% endif %}
+
diff --git a/euscanwww/djeuscan/templates/euscan/package.html b/euscanwww/djeuscan/templates/euscan/package.html
index 2357318..8c90efe 100644
--- a/euscanwww/djeuscan/templates/euscan/package.html
+++ b/euscanwww/djeuscan/templates/euscan/package.html
@@ -1,7 +1,6 @@
{% extends "euscan/_datatable.html" %}
{% load sub %}
-{% load djeuscan_helpers %}
{% load url from future %}
{% block meta %}
@@ -26,12 +25,6 @@
{% block content %}
-{% if thanks_for_reporting %}
-
- Thanks! Your report has been sent to admins
-
-{% endif %}
-
A refresh request is in progress, please wait...
@@ -56,158 +49,18 @@
{% endif %}
-
- {% if package.description %}
- - Description
- - {{ package.description }}
- {% endif %}
- {% if package.homepage %}
- - Homepage
- -
- {% for homepage in package.homepages %}
- {{ homepage }}
- {% endfor %}
-
- {% endif %}
- {% if package.herds.all %}
- - Herds
- -
- {% for herd in package.herds.all %}
-
- {{ herd.herd }}
-
- <{{ herd.email }}>
- {% endfor %}
-
- {% endif %}
- {% if package.maintainers.all %}
- - Maintainers
- -
- {% for maintainer in package.maintainers.all %}
- {% if maintainer.name != maintainer.email %}
-
- {{ maintainer.name }}
-
- <{{ maintainer.email }}>
- {% else %}
-
- {{ maintainer.email }}
-
- {% endif %}
- {% endfor %}
-
- {% endif %}
- {% if packaged %}
- - Packaged Versions
- -
-
- {% for version in packaged %}
- -
- {% if version.overlay == "gentoo" %}
-
- {% else %}
-
- {% endif %}
- {% if version.vtype and not version.vtype|is_stable %}
-
- {% endif %}
-
- {{ version.version }}-{{ version.revision }} :{{ version.slot }} [{{ version.overlay }}]
-
- {% endfor %}
-
-
- {% endif %}
- {% if upstream %}
- - Upstream versions
- -
-
- {% for version in upstream %}
- -
-
-
- {% if version.vtype and not version.vtype|is_stable %}
-
- {% endif %}
-
- {{ version.version }} - {{ version.urls }}
- {% if confidence < 100 %}({{ version.confidence }}%){% endif %}
-
- {% endfor %}
-
-
- {% endif %}
- - Version history
- -
-
- {% for version in vlog %}
- {% if version.action == version.VERSION_ADDED %}
- -
- {% else %}
-
-
- {% endif %}
- {% if version.overlay == "gentoo" %}
-
- {% elif version.overlay %}
-
- {% else %}
-
- {% endif %}
-
- {% if version.vtype and not version.vtype|is_stable %}
-
- {% endif %}
-
- {{ version }} - {{ version.datetime }}
-
-
- {% endfor %}
-
-
- {% if log %}
- - euscan log
- -
-
Date: {{ log.datetime }}
-
{{ msg|ansi_to_html|safe }}
-
- {% endif %}
-
+{% include "euscan/_package_details.html" %}
-Report problems
-
+{% if user.is_authenticated %}
+
+{% endif %}
diff --git a/euscanwww/djeuscan/templates/euscan/problem.html b/euscanwww/djeuscan/templates/euscan/problem.html
new file mode 100644
index 0000000..828b7ab
--- /dev/null
+++ b/euscanwww/djeuscan/templates/euscan/problem.html
@@ -0,0 +1,57 @@
+{% extends "euscan/_datatable.html" %}
+
+{% load sub %}
+{% load djeuscan_helpers %}
+{% load url from future %}
+
+{% block title %}
+{{ block.super }} - Report Problem: {{ package.category }}/{{ package.name }}
+{% endblock %}
+
+{% block content %}
+
+{% if thanks_for_reporting %}
+
+ Thanks! Your report has been sent to admins
+
+{% endif %}
+
+
+ Report Problem: {{ package.category }}/{{ package.name }}
+
+
+{% include "euscan/_package_details.html" %}
+
+
+
+{% endblock %}
diff --git a/euscanwww/djeuscan/urls.py b/euscanwww/djeuscan/urls.py
index e4611d7..b1b1f88 100644
--- a/euscanwww/djeuscan/urls.py
+++ b/euscanwww/djeuscan/urls.py
@@ -22,6 +22,8 @@ package_patterns = patterns('djeuscan.views',
'unfavourite/$'), 'unfavourite_package', name="unfavourite_package"),
url((r'^(?P[\w+][\w+.-]*)/(?P[\w+][\w+.-]*)/'
'refresh$'), "refresh_package", name="refresh_package"),
+ url(r'^(?P[\w+][\w+.-]*)/(?P[\w+][\w+.-]*)/problem$',
+ 'problem', name="problem"),
)
categories_patterns = patterns('djeuscan.views',
diff --git a/euscanwww/djeuscan/views.py b/euscanwww/djeuscan/views.py
index 3d96cb0..68b3d07 100644
--- a/euscanwww/djeuscan/views.py
+++ b/euscanwww/djeuscan/views.py
@@ -1,7 +1,6 @@
""" Views """
import inspect
-import json
from annoying.decorators import render_to, ajax_request
from django.http import Http404
@@ -203,13 +202,6 @@ def package(request, category, package):
log = log[0] if log else None
vlog = VersionLog.objects.for_package(package, order=True)
- result = json.loads(log.result) if log else None
-
- if result and package.cp() in result:
- msg = result[package.cp()]['messages']
- else:
- msg = ""
-
try:
last_scan = EuscanResult.objects.for_package(package).latest().datetime
except EuscanResult.DoesNotExist:
@@ -230,32 +222,52 @@ def package(request, category, package):
except RefreshPackageQuery.DoesNotExist:
refreshed = False
- thanks_for_reporting = False
- if request.method == "POST":
- problem_form = ProblemReportForm(package, request.POST)
- if problem_form.is_valid():
- ProblemReport(
- package=package,
- version=problem_form.cleaned_data["version"],
- subject=problem_form.cleaned_data["subject"],
- message=problem_form.cleaned_data["message"],
- ).save()
- thanks_for_reporting = True
- else:
- problem_form = ProblemReportForm(package)
-
return {
'package': package,
'packaged': packaged,
'upstream': upstream,
- 'log': log,
+ 'log': log.messages(),
'vlog': vlog,
- 'msg': msg,
+ 'msg': log.messages() if log else "",
'last_scan': last_scan,
'favourited': favourited,
'refreshed': refreshed,
- 'problem_form': problem_form,
- 'thanks_for_reporting': thanks_for_reporting
+ }
+
+
+@login_required
+@render_to('euscan/problem.html')
+def problem(request, category, package):
+ package = get_object_or_404(Package, category=category, name=package)
+ packaged = Version.objects.filter(package=package, packaged=True)
+ upstream = Version.objects.filter(package=package, packaged=False)
+
+ log = EuscanResult.objects.filter(package=package).\
+ order_by('-datetime')[:1]
+ log = log[0] if log else None
+
+ thanks_for_reporting = False
+
+ if request.method == "POST":
+ form = ProblemReportForm(package, request.POST)
+ if form.is_valid():
+ ProblemReport(
+ package=package,
+ version=form.cleaned_data["version"],
+ subject=form.cleaned_data["subject"],
+ message=form.cleaned_data["message"],
+ ).save()
+ thanks_for_reporting = True
+ else:
+ form = ProblemReportForm(package)
+
+ return {
+ 'form': form,
+ 'thanks_for_reporting': thanks_for_reporting,
+ 'package': package,
+ 'packaged': packaged,
+ 'upstream': upstream,
+ 'msg': log.messages() if log else "",
}
@@ -264,8 +276,10 @@ def world(request):
world_form = WorldForm()
packages_form = PackagesForm()
- return {'world_form': world_form,
- 'packages_form': packages_form}
+ return {
+ 'world_form': world_form,
+ 'packages_form': packages_form
+ }
@render_to('euscan/world_scan.html')
diff --git a/euscanwww/htdocs/img/bug.png b/euscanwww/htdocs/img/bug.png
new file mode 100644
index 0000000..c33bfb9
Binary files /dev/null and b/euscanwww/htdocs/img/bug.png differ
diff --git a/pym/euscan/handlers/watch.py b/pym/euscan/handlers/watch.py
new file mode 100644
index 0000000..a129281
--- /dev/null
+++ b/pym/euscan/handlers/watch.py
@@ -0,0 +1,143 @@
+import re
+import urllib2
+
+import portage
+
+from euscan.handlers import generic
+from euscan import output, helpers
+
+PRIORITY = 100
+
+HANDLER_NAME = "watch"
+CONFIDENCE = 100.0
+
+
+is_pattern = r"\([^\/]+\)"
+
+
+def can_handle(pkg, url):
+ try:
+ return pkg.metadata._xml_tree.find("upstream").find("watch") \
+ is not None
+ except AttributeError:
+ return False
+
+
+def parse_mangles(mangles, string):
+ for mangle in mangles:
+ # convert regex from perl format to python format
+ # there are some regex in this format: s/pattern/replacement/
+ m = re.match(r"s/(.*[^\\])/(.*)/", mangle)
+ if not m:
+ # or in this format s|pattern|replacement|
+ m = re.match(r"s\|(.*[^\\])\|(.*)\|", mangle)
+ pattern, repl = m.groups()
+ repl = re.sub(r"\$(\d+)", r"\\\1", repl)
+ string = re.sub(pattern, repl, string)
+ return string
+
+
+def clean_results(results, versionmangle, urlmangle):
+ ret = []
+
+ for path, version, _, _ in results:
+ version = parse_mangles(versionmangle, version)
+ path = parse_mangles(urlmangle, path)
+ ret.append((path, version, HANDLER_NAME, CONFIDENCE))
+
+ return ret
+
+
+def parse_watch(pkg):
+ for watch_tag in pkg.metadata._xml_tree.find("upstream").findall("watch"):
+ try:
+ base, file_pattern = watch_tag.text.split(" ")[:2]
+ except ValueError:
+ base, file_pattern = watch_tag.text, None
+
+ # the file pattern can be in the base url
+ pattern_regex = r"/([^/]*\([^/]*\)[^/]*)$"
+ match = re.search(pattern_regex, base)
+ if match:
+ file_pattern = match.group(1)
+ base = base.replace(file_pattern, "")
+
+ # handle sf.net specially
+ base = base.replace(
+ "http://sf.net/", "http://qa.debian.org/watch/sf.php/"
+ )
+
+ vmangle = watch_tag.attrib.get("uversionmangle", None) or \
+ watch_tag.attrib.get("versionmangle", None)
+ versionmangle = vmangle.split(";") if vmangle else []
+
+ umangle = watch_tag.attrib.get("downloadurlmangle", None)
+ urlmangle = umangle.split(";") if umangle else []
+
+ yield (base, file_pattern, versionmangle, urlmangle)
+
+
+def handle_directory_patterns(base, file_pattern):
+ """
+ Directory pattern matching
+ e.g.: base: ftp://ftp.nessus.org/pub/nessus/nessus-([\d\.]+)/src/
+ file_pattern: nessus-core-([\d\.]+)\.tar\.gz
+ """
+ splitted = base.split("/")
+ i = 0
+ basedir = []
+ for elem in splitted:
+ if re.search(is_pattern, elem):
+ break
+ basedir.append(elem)
+ i += 1
+ basedir = "/".join(basedir)
+ directory_pattern = splitted[i]
+ final = "/".join(splitted[i + 1:])
+
+ try:
+ fp = helpers.urlopen(basedir)
+ except urllib2.URLError:
+ return []
+ except IOError:
+ return []
+
+ if not fp:
+ return []
+
+ data = fp.read()
+
+ if basedir.startswith("ftp://"):
+ scan_data = generic.scan_ftp(data, basedir, directory_pattern)
+ else:
+ scan_data = generic.scan_html(data, basedir, directory_pattern)
+
+ return [("/".join((basedir, path, final)), file_pattern)
+ for _, path in scan_data]
+
+
+def scan(pkg, url):
+ output.einfo("Using watch data")
+
+ cp, ver, rev = portage.pkgsplit(pkg.cpv)
+
+ results = []
+ for base, file_pattern, versionmangle, urlmangle in parse_watch(pkg):
+ if not re.search(is_pattern, base):
+ steps = [(base, file_pattern)]
+ res = generic.scan_directory_recursive(
+ cp, ver, rev, "", steps, url
+ )
+ else:
+ res = []
+ for step in handle_directory_patterns(base, file_pattern):
+ res += generic.scan_directory_recursive(
+ cp, ver, rev, "", [step], url
+ )
+
+ results += clean_results(res, versionmangle, urlmangle)
+ return results
+
+
+def brute_force(pkg, url):
+ return []
diff --git a/setup.py b/setup.py
index 85856aa..9b7179f 100755
--- a/setup.py
+++ b/setup.py
@@ -70,7 +70,7 @@ packages = [
]
tests_require = [
- 'factory-boy==1.1.3',
+ 'factory-boy>=1.1.3',
]
setup(
@@ -88,10 +88,13 @@ setup(
('master' if __version__ == '9999' else ('euscan-%s' % __version__))
),
install_requires=[
- 'Django==1.4', 'django-annoying==0.7.6', 'South==0.7.4',
- 'django-piston==0.2.3', 'BeautifulSoup==3.2.1', 'matplotlib==1.1.0',
- 'django-celery==3.0.1', 'django-registration==0.8',
- 'python-ldap==2.4.10', 'django-auth-ldap==1.1',
+ # Command line utility
+ 'BeautifulSoup>=3.2.1',
+ # Web interface
+ 'Django>=1.4', 'django-annoying>=0.7.6', 'South>=0.7',
+ 'django-piston>=0.2.3', 'matplotlib>=1.1.0',
+ 'django-celery>=3.0.1', 'django-registration>=0.8',
+ 'python-ldap>=2.4.10', 'django-auth-ldap>=1.1',
],
package_dir={'': 'pym'},
packages=packages,