porting /compatibility (bug 647023, 647029)

This commit is contained in:
Jeff Balogh 2011-04-11 10:44:52 -07:00
Родитель c48e179500
Коммит b9d05898b0
9 изменённых файлов: 193 добавлений и 0 удалений

0
apps/compat/__init__.py Normal file
Просмотреть файл

62
apps/compat/cron.py Normal file
Просмотреть файл

@ -0,0 +1,62 @@
import logging
from django.conf import settings
from django.db.models import Sum, Max
import cronjobs
import redisutils
import amo
import versions.compare as vc
from addons.models import Addon
from stats.models import UpdateCount
log = logging.getLogger('z.compat')
@cronjobs.register
def compatibility_report():
redis = redisutils.connections['master']
# for app in amo.APP_USAGE:
for compat in settings.COMPAT:
app = amo.APPS_ALL[compat['app']]
version = compat['version']
log.info(u'Making compat report for %s %s.' % (app.pretty, version))
versions = (('latest', version), ('beta', version + 'b'),
('alpha', compat['alpha']))
rv = dict((k, 0) for k in dict(versions))
rv['other'] = 0
ignore = (amo.STATUS_NULL, amo.STATUS_DISABLED)
qs = (Addon.objects.exclude(type=amo.ADDON_PERSONA, status__in=ignore)
.filter(appsupport__app=app.id, name__locale='en-us'))
latest = UpdateCount.objects.aggregate(d=Max('date'))['d']
qs = UpdateCount.objects.filter(addon__appsupport__app=app.id,
date=latest)
total = qs.aggregate(Sum('count'))['count__sum']
addons = list(qs.values_list('addon', 'count', 'addon__appsupport__min',
'addon__appsupport__max'))
# Count up the top 95% of addons by ADU.
adus = 0
for addon, count, minver, maxver in addons:
# Don't count add-ons that weren't compatible with the previous
# release
if maxver < vc.version_int(compat['previous']):
continue
if adus < .95 * total:
adus += count
else:
break
for key, version in versions:
if minver <= vc.version_int(version) <= maxver:
rv[key] += 1
break
else:
rv['other'] += 1
log.info(u'Compat for %s %s: %s' % (app.pretty, version, rv))
key = '%s:%s' % (app.id, version)
redis.hmset('compat:' + key, rv)

Просмотреть файл

@ -0,0 +1,43 @@
{% extends "base.html" %}
{% block title %}{{ page_title(_('Compatibility Center')) }}{% endblock %}
{% block bodyclass %}inverse{% endblock %}
{% macro percent(x, y) %}{{ (x / y|float * 100)|int }}{% endmacro %}
{% set app = request.APP.pretty %}
{% set num = percent(versions['latest'], total) %}
{% block content %}
<h1>{{ _('{app} {version} Add-on Compatibility Report')|f(app=app, version=version) }}</h1>
<p>{% trans %}
<b>{{ num }}%</b> of add-ons on addons.mozilla.org are compatible with {{ app }} {{ version }}.
{% endtrans %}</p>
<div id="chart" class="primary"
data-keys="{{ dict(keys)|json }}"
data-data="{{ versions|json }}"
data-total="{{ total }}"></div>
<div class="secondary">
<table id="compat">
<tr>
<th>{{ _('Version') }}</th>
<th>{{ _('# of Add-ons') }}</th>
</tr>
{% for key, title in keys %}
<tr>
<td>{{ title }}</td>
<td>{{ versions[key]|numberfmt }}</td>
</tr>
{% endfor %}
</table>
<p><a href="{{ url('compat.details', version) }}">{{ _('Detailed Report') }}</a></p>
</div>
{% endblock %}
{% block js %}
<script src="{{ media('js/lib/highcharts.src.js') }}"></script>
<script src="{{ media('js/zamboni/compat.js') }}"></script>
{% endblock %}

9
apps/compat/urls.py Normal file
Просмотреть файл

@ -0,0 +1,9 @@
from django.conf.urls.defaults import patterns, url
from . import views
urlpatterns = patterns('',
url('^(?P<version>[.\w]+)?$', views.index, name='compat.index'),
url('^(?P<version>[.\w]+)/details$', views.details, name='compat.details'),
)

32
apps/compat/views.py Normal file
Просмотреть файл

@ -0,0 +1,32 @@
from django import http
from django.conf import settings
import jingo
import redisutils
from tower import ugettext_lazy as _lazy
KEYS = (
('latest', _lazy('Latest')),
('beta', _lazy('Beta')),
('alpha', _lazy('Alpha')),
('other', _lazy('Other')),
)
def index(request, version=None):
version = version or settings.COMPAT[0]['version']
if version not in [v['version'] for v in settings.COMPAT]:
raise http.Http404()
redis = redisutils.connections['master']
compat = redis.hgetall('compat:%s:%s' % (request.APP.id, version))
versions = dict((k, int(v)) for k, v in compat.items())
print versions
total = sum(versions.values())
keys = [(k, unicode(v)) for k, v in KEYS]
return jingo.render(request, 'compat/index.html',
{'versions': versions, 'total': total,
'version': version, 'keys': keys})
def details(request, version):
pass

Просмотреть файл

@ -31,6 +31,10 @@ def dict_from_int(version_int):
return d
def num(vint):
return '{major}.{minor1}.{minor2}.{minor3}'.format(**dict_from_int(vint))
def version_dict(version):
"""Turn a version string into a dict with major/minor/... info."""
match = version_re.match(version or '')

Просмотреть файл

@ -0,0 +1,29 @@
$(function() {
var chart = $('#chart'),
data = JSON.parse(chart.attr('data-data')),
total = chart.attr('data-total'),
keys = JSON.parse(chart.attr('data-keys')),
series = _.map(data, function(value, key) {
return [keys[key], parseInt(value / total * 100)];
});
console.log(JSON.stringify(series));
var chart = new Highcharts.Chart({
chart: {
renderTo: 'chart'
},
title: '',
plotOptions: {
pie: { cursor: 'pointer' }
},
tooltip: {
formatter: function() {
return '<b>'+ this.point.name +'</b>: '+ this.y +' %';
}
},
series: [{
type: 'pie',
data: series
}]
});
});

Просмотреть файл

@ -284,6 +284,7 @@ INSTALLED_APPS = (
'bandwagon',
'blocklist',
'browse',
'compat',
'cronjobs',
'csp',
'devhub',
@ -897,3 +898,14 @@ FILE_VIEWER_SIZE_LIMIT = 1048576
# How long to delay modify updates to cope with alleged NFS slowness.
MODIFIED_DELAY = 120
# This is a list of dictionaries that we should generate compat info for.
# app: should match amo.FIREFOX.id.
# version: the app version we're generating compat info for.
# alpha: the first version that should be considered alpha for :version.
# previous: the major version before :version.
COMPAT = (
dict(app=1, version='4.0', alpha='3.7a', previous='3.6'),
dict(app=1, version='5.0', alpha='5.0a', previous='4.0'),
dict(app=1, version='6.0', alpha='6.0a', previous='5.0'),
)

Просмотреть файл

@ -78,6 +78,8 @@ urlpatterns = patterns('',
# SAMO/API
('^api/', include('api.urls')),
('^compatibility/', include('compat.urls')),
# Review spam.
url('^reviews/spam/$', 'reviews.views.spam', name='reviews.spam'),