From 91a36e65a3564d9fe265aaea90a895143764f2ba Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 09:32:27 -0500 Subject: Tweak sorting settings on stale relations page * Don't allow sorting of packages columns, doesn't make much sense * Default to sorting by pkgbase on all tables * Ensure all JS is executed inside doc.ready function (wow, how has this been wrong for so long?) Signed-off-by: Dan McGee --- templates/packages/stale_relations.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/packages/stale_relations.html b/templates/packages/stale_relations.html index f1ad4373..2b5af236 100644 --- a/templates/packages/stale_relations.html +++ b/templates/packages/stale_relations.html @@ -117,13 +117,13 @@

Maintainers with Wrong Permissions ({{ wrong_permissions|length }})

{% endblock %} -- cgit v1.2.3-54-g00ecf From d088579eba892abd990e47dadf9a64a6d1771b42 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 10:25:10 -0500 Subject: Only show arches/repos that are necessary After the refactor in commit 7947d36c4, we weren't gathering arches and repos from the correct list of packages. Fix this. Signed-off-by: Dan McGee --- devel/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devel/views.py b/devel/views.py index 92cb098e..66f6a965 100644 --- a/devel/views.py +++ b/devel/views.py @@ -197,6 +197,7 @@ def report(request, report_name, username=None): maints = User.objects.filter(id__in=PackageRelation.objects.filter( type=PackageRelation.MAINTAINER).values('user')) + packages = report.packages(packages, username) arches = {pkg.arch for pkg in packages} repos = {pkg.repo for pkg in packages} context = { @@ -204,7 +205,7 @@ def report(request, report_name, username=None): 'title': report.description, 'report': report, 'maintainer': user, - 'packages': report.packages(packages, username), + 'packages': packages, 'arches': sorted(arches), 'repos': sorted(repos), 'column_names': report.names, -- cgit v1.2.3-54-g00ecf From fe20aff2bb32a7e2a691f2f78b5cd617ed618243 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 12:45:51 -0500 Subject: Disable eggs template loader --- settings.py | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.py b/settings.py index 368dcb73..cc1f3a53 100644 --- a/settings.py +++ b/settings.py @@ -61,7 +61,6 @@ TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.eggs.Loader', 'django.template.loaders.app_directories.Loader', ) -- cgit v1.2.3-54-g00ecf From f4a6eff33815a713b1141ea94a872bd7c6233699 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 13:38:54 -0500 Subject: Install and wire up django-jinja Signed-off-by: Dan McGee --- requirements.txt | 2 ++ requirements_prod.txt | 2 ++ settings.py | 8 ++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index eff75bad..e2b49aba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,10 @@ -e git+git://github.com/SmileyChris/django-countries.git@a2c924074dbe2f0b9b3059bf70064aeadf5643ed#egg=django-countries Django==1.7 IPy==0.81 +Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 +django-jinja==1.0.4 jsmin==2.0.11 pgpdump==1.5 pytz>=2014.7 diff --git a/requirements_prod.txt b/requirements_prod.txt index c181c3af..020a5ac4 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -2,8 +2,10 @@ -e git+git://github.com/SmileyChris/django-countries.git@a2c924074dbe2f0b9b3059bf70064aeadf5643ed#egg=django-countries Django==1.7 IPy==0.81 +Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 +django-jinja==1.0.4 jsmin==2.0.11 pgpdump==1.5 psycopg2==2.5.4 diff --git a/settings.py b/settings.py index cc1f3a53..5b2195cb 100644 --- a/settings.py +++ b/settings.py @@ -60,10 +60,13 @@ ) TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', + 'django_jinja.loaders.FileSystemLoader', + 'django_jinja.loaders.AppLoader', ) +# Send templates matching the following to the Jinja2 engine +DEFAULT_JINJA2_TEMPLATE_EXTENSION = '.jinja' + MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -114,6 +117,7 @@ 'django.contrib.admin', 'django.contrib.staticfiles', 'django_countries', + 'django_jinja', 'main', 'mirrors', -- cgit v1.2.3-54-g00ecf From 2f19529c922172007ff3894ad0e0fca0b3e33f5b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 13:48:07 -0500 Subject: Convert details sub-tempates to Jinja2 This is a start at improving performance of rendering the package details page, our most-visited and slowest page on the production website. The Django template system is not very efficient due to our heavy use of broken out templates and pulling of various attributes and such on related packages. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 5 ----- templates/packages/details.html | 10 +++++----- templates/packages/details_depend.html | 13 ------------- templates/packages/details_depend.html.jinja | 13 +++++++++++++ templates/packages/details_link.html.jinja | 1 + templates/packages/details_relatedto.html | 2 -- templates/packages/details_relatedto.html.jinja | 3 +++ templates/packages/details_requiredby.html | 8 -------- templates/packages/details_requiredby.html.jinja | 8 ++++++++ 9 files changed, 30 insertions(+), 33 deletions(-) delete mode 100644 templates/packages/details_depend.html create mode 100644 templates/packages/details_depend.html.jinja create mode 100644 templates/packages/details_link.html.jinja delete mode 100644 templates/packages/details_relatedto.html create mode 100644 templates/packages/details_relatedto.html.jinja delete mode 100644 templates/packages/details_requiredby.html create mode 100644 templates/packages/details_requiredby.html.jinja diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 3ce64748..2784546d 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -79,11 +79,6 @@ def pkg_details_link(pkg, link_title=None, honor_flagged=False): return link % (pkg.get_absolute_url(), pkg.pkgname, link_content) -@register.simple_tag -def multi_pkg_details(pkgs): - return ', '.join([pkg_details_link(pkg) for pkg in pkgs]) - - @register.simple_tag def maintainer_link(user): if user: diff --git a/templates/packages/details.html b/templates/packages/details.html index bfa2de16..c4c1f6b2 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -134,19 +134,19 @@

Versions Elsewhere

{% with pkg.provides.all as all_related %}{% if all_related %} Provides: - {% include "packages/details_relatedto.html" %} + {% include "packages/details_relatedto.html.jinja" %} {% endif %}{% endwith %} {% with pkg.replaces.all as all_related %}{% if all_related %} Replaces: - {% include "packages/details_relatedto.html" %} + {% include "packages/details_relatedto.html.jinja" %} {% endif %}{% endwith %} {% with pkg.conflicts.all as all_related %}{% if all_related %} Conflicts: - {% include "packages/details_relatedto.html" %} + {% include "packages/details_relatedto.html.jinja" %} {% endif %}{% endwith %} {% with pkg.reverse_conflicts as rev_conflicts %}{% if rev_conflicts %} @@ -205,7 +205,7 @@

Versions Elsewhere

Dependencies ({{deps|length}})

{% if deps %}
    - {% for depend in deps %}{% include "packages/details_depend.html" %}{% endfor %} + {% for depend in deps %}{% include "packages/details_depend.html.jinja" %}{% endfor %}
{% endif %} {% endwith %} @@ -214,7 +214,7 @@

Required By ({{rqdby|length}})

{% if rqdby %}
    - {% for req in rqdby %}{% include "packages/details_requiredby.html" %}{% endfor %} + {% for req in rqdby %}{% include "packages/details_requiredby.html.jinja" %}{% endfor %}
{% endif %} {% endwith %} diff --git a/templates/packages/details_depend.html b/templates/packages/details_depend.html deleted file mode 100644 index b89ffbfa..00000000 --- a/templates/packages/details_depend.html +++ /dev/null @@ -1,13 +0,0 @@ -{% load package_extras %}
  • {% ifequal depend.pkg None %} -{% if depend.providers %}{{ depend.dep.name }}{{ depend.dep.comparison|default:"" }}{{ depend.dep.version|default:"" }} ({% multi_pkg_details depend.providers %}) -{% else %}{{ depend.dep.name }}{{ depend.dep.comparison|default:"" }}{{ depend.dep.version|default:"" }} (virtual) -{% endif %}{% else %} -{% pkg_details_link depend.pkg %}{{ depend.dep.comparison|default:"" }}{{ depend.dep.version|default:"" }} -{% if depend.pkg.repo.testing %} (testing) -{% endif %}{% if depend.pkg.repo.staging %} (staging) -{% endif %}{% endifequal %} -{% if depend.dep.deptype == 'O' %} (optional) -{% endif %}{% if depend.dep.deptype == 'M' %} (make) -{% endif %}{% if depend.dep.deptype == 'C' %} (check) -{% endif %}{% if depend.dep.description %} - {{ depend.dep.description }} -{% endif %}
  • diff --git a/templates/packages/details_depend.html.jinja b/templates/packages/details_depend.html.jinja new file mode 100644 index 00000000..404793b6 --- /dev/null +++ b/templates/packages/details_depend.html.jinja @@ -0,0 +1,13 @@ +{% import 'packages/details_link.html.jinja' as details %}
  • {% if depend.pkg == None %} +{% if depend.providers %}{{ depend.dep.name }}{{ depend.dep.comparison|default("") }}{{ depend.dep.version|default("") }} ({% for pkg in depend.providers %}{{ details.details_link(pkg) }}{% if not loop.last %}, {% endif %}{% endfor %}) +{% else %}{{ depend.dep.name }}{{ depend.dep.comparison|default("") }}{{ depend.dep.version|default("") }} (virtual) +{% endif %}{% else %} +{{ details.details_link(depend.pkg) }}{{ depend.dep.comparison|default("") }}{{ depend.dep.version|default("") }} +{% if depend.pkg.repo.testing %} (testing) +{% endif %}{% if depend.pkg.repo.staging %} (staging) +{% endif %}{% endif %} +{% if depend.dep.deptype == 'O' %} (optional) +{% endif %}{% if depend.dep.deptype == 'M' %} (make) +{% endif %}{% if depend.dep.deptype == 'C' %} (check) +{% endif %}{% if depend.dep.description %} - {{ depend.dep.description }} +{% endif %}
  • diff --git a/templates/packages/details_link.html.jinja b/templates/packages/details_link.html.jinja new file mode 100644 index 00000000..b7e75fe5 --- /dev/null +++ b/templates/packages/details_link.html.jinja @@ -0,0 +1 @@ +{% macro details_link(pkg) %}{{ pkg.pkgname }}{% endmacro %} diff --git a/templates/packages/details_relatedto.html b/templates/packages/details_relatedto.html deleted file mode 100644 index e14375d3..00000000 --- a/templates/packages/details_relatedto.html +++ /dev/null @@ -1,2 +0,0 @@ -{% load package_extras %}{% for related in all_related %}{% with related.get_best_satisfier as best_satisfier %}{% ifequal best_satisfier None %}{{ related.name }}{% else %}{% pkg_details_link best_satisfier %}{% endifequal %}{{ related.comparison|default:"" }}{{ related.version|default:"" }}{% if not forloop.last %}, {% endif %} -{% endwith %}{% endfor %} diff --git a/templates/packages/details_relatedto.html.jinja b/templates/packages/details_relatedto.html.jinja new file mode 100644 index 00000000..955fdd37 --- /dev/null +++ b/templates/packages/details_relatedto.html.jinja @@ -0,0 +1,3 @@ +{% import 'packages/details_link.html.jinja' as details %}{% for related in all_related %}{% with best_satisfier = related.get_best_satisfier() %} +{% if best_satisfier == None %}{{ related.name }}{% else %}{{ details.details_link(best_satisfier) }}{% endif %}{{ related.comparison|default("") }}{{ related.version|default("") }}{% if not loop.last %}, {% endif %} +{% endwith %}{% endfor %} diff --git a/templates/packages/details_requiredby.html b/templates/packages/details_requiredby.html deleted file mode 100644 index 504a322f..00000000 --- a/templates/packages/details_requiredby.html +++ /dev/null @@ -1,8 +0,0 @@ -{% load package_extras %}
  • {% pkg_details_link req.pkg %} -{% if req.name != pkg.pkgname %} (requires {{ req.name }}) -{% endif %}{% if req.pkg.repo.testing %} (testing) -{% endif %}{% if req.pkg.repo.staging %} (staging) -{% endif %}{% if req.deptype == 'O' %} (optional) -{% endif %}{% if req.deptype == 'M' %} (make) -{% endif %}{% if req.deptype == 'C' %} (check) -{% endif %}
  • diff --git a/templates/packages/details_requiredby.html.jinja b/templates/packages/details_requiredby.html.jinja new file mode 100644 index 00000000..b083a7fc --- /dev/null +++ b/templates/packages/details_requiredby.html.jinja @@ -0,0 +1,8 @@ +{% import 'packages/details_link.html.jinja' as details %}
  • {{ details.details_link(req.pkg) }} +{% if req.name != pkg.pkgname %} (requires {{ req.name }}) +{% endif %}{% if req.pkg.repo.testing %} (testing) +{% endif %}{% if req.pkg.repo.staging %} (staging) +{% endif %}{% if req.deptype == 'O' %} (optional) +{% endif %}{% if req.deptype == 'M' %} (make) +{% endif %}{% if req.deptype == 'C' %} (check) +{% endif %}
  • -- cgit v1.2.3-54-g00ecf From 2914fc55c4618d97a3ab5a7d519545979f526677 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 14:05:47 -0500 Subject: Enable Jinja2 template bytecode caching Signed-off-by: Dan McGee --- settings.py | 1 + 1 file changed, 1 insertion(+) diff --git a/settings.py b/settings.py index 5b2195cb..ba6c68ee 100644 --- a/settings.py +++ b/settings.py @@ -183,6 +183,7 @@ TEMPLATE_LOADERS = ( ('django.template.loaders.cached.Loader', TEMPLATE_LOADERS), ) + JINJA2_BYTECODE_CACHE_ENABLE = True # Enable the debug toolbar if requested if DEBUG_TOOLBAR: -- cgit v1.2.3-54-g00ecf From fff9cf9c5537d9f758a9e30fcb18df800c70f051 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 15:17:56 -0500 Subject: Convert bulk of package details page to Jinja2 We wrap the whole thing in a Django template so we don't have to convert our base template to Jinja2 (or have one for each templating engine). This also simplifies the static stuff so we can just keep using the Django tags. Signed-off-by: Dan McGee --- packages/templatetags/package_extras.py | 26 ++-- templates/packages/details.html | 225 +------------------------------- templates/packages/details.html.jinja | 221 +++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+), 233 deletions(-) create mode 100644 templates/packages/details.html.jinja diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 2784546d..f6d6ee73 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -6,6 +6,9 @@ from django import template from django.utils.html import escape +from django_jinja import library + +from main.templatetags import pgp register = template.Library() @@ -14,11 +17,11 @@ def link_encode(url, query): # massage the data into all utf-8 encoded strings first, so urlencode # doesn't barf at the data we pass it query = {k: unicode(v).encode('utf-8') for k, v in query.items()} - data = urlencode(query).replace('&', '&') + data = urlencode(query) return "%s?%s" % (url, data) -@register.filter +@library.filter def url_unquote(original_url): try: url = original_url @@ -79,7 +82,7 @@ def pkg_details_link(pkg, link_title=None, honor_flagged=False): return link % (pkg.get_absolute_url(), pkg.pkgname, link_content) -@register.simple_tag +@library.global_function def maintainer_link(user): if user: # TODO don't hardcode @@ -92,7 +95,7 @@ def maintainer_link(user): return '' -@register.simple_tag +@library.global_function def packager_link(user): if user: # TODO don't hardcode @@ -105,7 +108,12 @@ def packager_link(user): return '' -@register.simple_tag +@library.global_function +def pgp_key_link(key_id, link_text=None): + return pgp.pgp_key_link(key_id, link_text) + + +@library.global_function def scm_link(package, operation): parts = (package.repo.svn_root, operation, package.pkgbase) linkbase = ( @@ -114,8 +122,8 @@ def scm_link(package, operation): return linkbase % tuple(urlquote(part.encode('utf-8')) for part in parts) -@register.simple_tag -def get_wiki_link(package): +@library.global_function +def wiki_link(package): url = "https://wiki.archlinux.org/index.php/Special:Search" data = { 'search': package.pkgname, @@ -123,7 +131,7 @@ def get_wiki_link(package): return link_encode(url, data) -@register.simple_tag +@library.global_function def bugs_list(package): url = "https://bugs.archlinux.org/" data = { @@ -134,7 +142,7 @@ def bugs_list(package): return link_encode(url, data) -@register.simple_tag +@library.global_function def bug_report(package): url = "https://bugs.archlinux.org/newtask" data = { diff --git a/templates/packages/details.html b/templates/packages/details.html index c4c1f6b2..7a0f8e88 100644 --- a/templates/packages/details.html +++ b/templates/packages/details.html @@ -1,234 +1,11 @@ {% extends "base.html" %} {% load static from staticfiles %} -{% load package_extras %} -{% load pgp %} {% block title %}Arch Linux - {{ pkg.pkgname }} {{ pkg.full_version }} ({{ pkg.arch.name }}){% endblock %} {% block navbarclass %}anb-packages{% endblock %} -{% load package_extras %} {% block content %} -
    - -

    {{ pkg.pkgname }} {{ pkg.full_version }}

    - - - -
    - - - - - - - -
    - -
    - - - - - - - - - {% ifequal pkg.pkgname pkg.pkgbase %} - {% with pkg.split_packages as splits %}{% if splits %} - - - - - {% endif %}{% endwith %} - {% else %} - - - {% with pkg.base_package as base %}{% if base %} - - {% else %} - - {% endif %}{% endwith %} - - {% endifequal %} - - - - - - - - - - - {% with pkg.groups.all as groups %}{% if groups %} - - - - - {% endif %}{% endwith %} - {% with pkg.provides.all as all_related %}{% if all_related %} - - - - - {% endif %}{% endwith %} - {% with pkg.replaces.all as all_related %}{% if all_related %} - - - - - {% endif %}{% endwith %} - {% with pkg.conflicts.all as all_related %}{% if all_related %} - - - - - {% endif %}{% endwith %} - {% with pkg.reverse_conflicts as rev_conflicts %}{% if rev_conflicts %} - - - - - {% endif %}{% endwith %} - - - {% with pkg.maintainers as maints %} - - {% endwith %} - - - - - - - - - - - - - {% if pkg.signature %} - - - - - - {% else %} - - - {% endif %} - - - - {% if user.is_authenticated %}{% with pkg.flag_request as flag_request %}{% if flag_request %} - - - {% endif %}{% endwith %}{% endif %} -
    Architecture:{{ pkg.arch.name }}
    Repository:{{ pkg.repo.name|capfirst }}
    Split Packages:{% for s in splits %}{% pkg_details_link s %}{% if not forloop.last %}, {% endif %}{% endfor %}
    Base Package:{% pkg_details_link base %}{{ pkg.pkgbase }}
    Description:{{ pkg.pkgdesc|default:"" }}
    Upstream URL:{% if pkg.url %}{% endif %}
    License(s):{{ pkg.licenses.all|join:", " }}
    Groups:{% for g in groups %} - {{ g.name }}{% if not forloop.last %}, {% endif %}{% endfor %} -
    Provides:{% include "packages/details_relatedto.html.jinja" %}
    Replaces:{% include "packages/details_relatedto.html.jinja" %}
    Conflicts:{% include "packages/details_relatedto.html.jinja" %}
    Reverse Conflicts:{% for conflict in rev_conflicts %} - {% pkg_details_link conflict %}{% if not forloop.last %}, {% endif %}{% endfor %}
    Maintainers:{% if maints %} - {% for m in maints %} - {% maintainer_link m %}
    - {% endfor %} - {% else %}Orphan{% endif %} -
    Package Size:{{ pkg.compressed_size|filesizeformat }}
    Installed Size:{{ pkg.installed_size|filesizeformat }}
    Last Packager:{% with pkg.packager as pkgr %}{% if pkgr %}{% packager_link pkgr %}{% else %}{{ pkg.packager_str }}{% endif %}{% endwith %}
    Build Date:{{ pkg.build_date|date:"DATETIME_FORMAT" }} UTC
    Signed By:{% with pkg.signer as signer %}{% if signer %}{% pgp_key_link pkg.signature.key_id signer.get_full_name %}{% else %}Unknown ({% pgp_key_link pkg.signature.key_id %}){% endif %}{% endwith %}
    Signature Date:{{ pkg.signature.creation_time|date:"DATETIME_FORMAT" }} UTC
    Signed By:Unsigned
    Last Updated:{{ pkg.last_update|date:"DATETIME_FORMAT" }} UTC
    Last Flag Request:From {{ flag_request.who }} on {{ flag_request.created|date }}:
    -
    {{ flag_request.message|linebreaksbr|default:"{no message}" }}
    -
    - -
    - {% with pkg.get_depends as deps %} -
    -

    - Dependencies ({{deps|length}})

    - {% if deps %}
      - {% for depend in deps %}{% include "packages/details_depend.html.jinja" %}{% endfor %} -
    {% endif %} -
    - {% endwith %} - {% with pkg.get_requiredby as rqdby %} -
    -

    - Required By ({{rqdby|length}})

    - {% if rqdby %}
      - {% for req in rqdby %}{% include "packages/details_requiredby.html.jinja" %}{% endfor %} -
    {% endif %} -
    - {% endwith %} -
    -

    - Package Contents

    - -
    -
    -
    +{% include "packages/details.html.jinja" %} {% endblock %} {% block script_block %} diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja new file mode 100644 index 00000000..7ca5629c --- /dev/null +++ b/templates/packages/details.html.jinja @@ -0,0 +1,221 @@ +{% import 'packages/details_link.html.jinja' as details %} +
    +

    {{ pkg.pkgname }} {{ pkg.full_version }}

    + + + +
    + + + + + + + +
    + +
    + + + + + + + + + {% if pkg.pkgname == pkg.pkgbase %} + {% with splits = pkg.split_packages() %}{% if splits %} + + + + + {% endif %}{% endwith %} + {% else %} + + + {% with base = pkg.base_package %}{% if base %} + + {% else %} + + {% endif %}{% endwith %} + + {% endif %} + + + + + + + + + + + {% with groups = pkg.groups.all() %}{% if groups %} + + + + + {% endif %}{% endwith %} + {% with all_related = pkg.provides.all() %}{% if all_related %} + + + + + {% endif %}{% endwith %} + {% with all_related = pkg.replaces.all() %}{% if all_related %} + + + + + {% endif %}{% endwith %} + {% with all_related = pkg.conflicts.all() %}{% if all_related %} + + + + + {% endif %}{% endwith %} + {% with rev_conflicts = pkg.reverse_conflicts() %}{% if rev_conflicts %} + + + + + {% endif %}{% endwith %} + + + {% with maints = pkg.maintainers %} + + {% endwith %} + + + + + + + + + + + + + {% if pkg.signature %} + + + + + + {% else %} + + + {% endif %} + + + + {% if user.is_authenticated %}{% with flag_request = pkg.flag_request() %}{% if flag_request %} + + + {% endif %}{% endwith %}{% endif %} +
    Architecture:{{ pkg.arch.name }}
    Repository:{{ pkg.repo.name|capfirst }}
    Split Packages:{% for s in splits %}{{ details.details_link(s) }}{% if not loop.last %}, {% endif %}{% endfor %}
    Base Package:{{ details.details_link(base) }}{{ pkg.pkgbase }}
    Description:{{ pkg.pkgdesc|default("") }}
    Upstream URL:{% if pkg.url %}{% endif %}
    License(s):{{ pkg.licenses.all()|join(", ") }}
    Groups:{% for g in groups %} + {{ g.name }}{% if not loop.last %}, {% endif %}{% endfor %} +
    Provides:{% include "packages/details_relatedto.html.jinja" %}
    Replaces:{% include "packages/details_relatedto.html.jinja" %}
    Conflicts:{% include "packages/details_relatedto.html.jinja" %}
    Reverse Conflicts:{% for conflict in rev_conflicts %} + {{ details.details_link(conflict) }}{% if not loop.last %}, {% endif %}{% endfor %}
    Maintainers:{% if maints %} + {% for m in maints %} + {{ maintainer_link(m)|safe }}
    + {% endfor %} + {% else %}Orphan{% endif %} +
    Package Size:{{ pkg.compressed_size|filesizeformat }}
    Installed Size:{{ pkg.installed_size|filesizeformat }}
    Last Packager:{% with pkgr = pkg.packager %}{% if pkgr %}{{ packager_link(pkgr)|safe }}{% else %}{{ pkg.packager_str }}{% endif %}{% endwith %}
    Build Date:{{ pkg.build_date|date("DATETIME_FORMAT") }} UTC
    Signed By:{% with signer = pkg.signer %}{% if signer %}{{ pgp_key_link(pkg.signature.key_id, signer.get_full_name())|safe }}{% else %}Unknown ({{ pgp_key_link(pkg.signature.key_id)|safe }}){% endif %}{% endwith %}
    Signature Date:{{ pkg.signature.creation_time|date("DATETIME_FORMAT") }} UTC
    Signed By:Unsigned
    Last Updated:{{ pkg.last_update|date("DATETIME_FORMAT") }} UTC
    Last Flag Request:From {{ flag_request.who() }} on {{ flag_request.created|date }}:
    +
    {{ flag_request.message|linebreaksbr|default("{no message}") }}
    +
    + +
    + {% with deps = pkg.get_depends() %} +
    +

    + Dependencies ({{deps|length}})

    + {% if deps %}
      + {% for depend in deps %}{% include "packages/details_depend.html.jinja" %}{% endfor %} +
    {% endif %} +
    + {% endwith %} + {% with rqdby = pkg.get_requiredby() %} +
    +

    + Required By ({{rqdby|length}})

    + {% if rqdby %}
      + {% for req in rqdby %}{% include "packages/details_requiredby.html.jinja" %}{% endfor %} +
    {% endif %} +
    + {% endwith %} +
    +

    + Package Contents

    + +
    +
    +
    -- cgit v1.2.3-54-g00ecf From e5e5632fb3432e153d0677b4bf145bc2eb72ef65 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 15:25:30 -0500 Subject: Break out Jinja2-specific template helpers Signed-off-by: Dan McGee --- packages/templatetags/jinja2.py | 98 +++++++++++++++++++++++++++++++++ packages/templatetags/package_extras.py | 95 +------------------------------- 2 files changed, 99 insertions(+), 94 deletions(-) create mode 100644 packages/templatetags/jinja2.py diff --git a/packages/templatetags/jinja2.py b/packages/templatetags/jinja2.py new file mode 100644 index 00000000..263fc156 --- /dev/null +++ b/packages/templatetags/jinja2.py @@ -0,0 +1,98 @@ +from urllib import urlencode, quote as urlquote, unquote +from django.utils.html import escape +from django_jinja import library +from main.templatetags import pgp + + +@library.filter +def url_unquote(original_url): + try: + url = original_url + if isinstance(url, unicode): + url = url.encode('ascii') + url = unquote(url).decode('utf-8') + return url + except UnicodeError: + return original_url + + +def link_encode(url, query): + # massage the data into all utf-8 encoded strings first, so urlencode + # doesn't barf at the data we pass it + query = {k: unicode(v).encode('utf-8') for k, v in query.items()} + data = urlencode(query) + return "%s?%s" % (url, data) + + +@library.global_function +def maintainer_link(user): + if user: + # TODO don't hardcode + title = escape('View packages maintained by ' + user.get_full_name()) + return '%s' % ( + user.username, + title, + user.get_full_name(), + ) + return '' + + +@library.global_function +def packager_link(user): + if user: + # TODO don't hardcode + title = escape('View packages packaged by ' + user.get_full_name()) + return '%s' % ( + user.username, + title, + user.get_full_name(), + ) + return '' + + +@library.global_function +def pgp_key_link(key_id, link_text=None): + return pgp.pgp_key_link(key_id, link_text) + + +@library.global_function +def scm_link(package, operation): + parts = (package.repo.svn_root, operation, package.pkgbase) + linkbase = ( + "https://projects.archlinux.org/svntogit/%s.git/%s/trunk?" + "h=packages/%s") + return linkbase % tuple(urlquote(part.encode('utf-8')) for part in parts) + + +@library.global_function +def wiki_link(package): + url = "https://wiki.archlinux.org/index.php/Special:Search" + data = { + 'search': package.pkgname, + } + return link_encode(url, data) + + +@library.global_function +def bugs_list(package): + url = "https://bugs.archlinux.org/" + data = { + 'project': package.repo.bugs_project, + 'cat[]': package.repo.bugs_category, + 'string': package.pkgname, + } + return link_encode(url, data) + + +@library.global_function +def bug_report(package): + url = "https://bugs.archlinux.org/newtask" + data = { + 'project': package.repo.bugs_project, + 'product_category': package.repo.bugs_category, + 'item_summary': '[%s] PLEASE ENTER SUMMARY' % package.pkgname, + } + return link_encode(url, data) + + +# vim: set ts=4 sw=4 et: diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index f6d6ee73..73a39092 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -1,38 +1,15 @@ -from urllib import urlencode, quote as urlquote, unquote +from urllib import urlencode try: from urlparse import parse_qs except ImportError: from cgi import parse_qs from django import template -from django.utils.html import escape -from django_jinja import library -from main.templatetags import pgp register = template.Library() -def link_encode(url, query): - # massage the data into all utf-8 encoded strings first, so urlencode - # doesn't barf at the data we pass it - query = {k: unicode(v).encode('utf-8') for k, v in query.items()} - data = urlencode(query) - return "%s?%s" % (url, data) - - -@library.filter -def url_unquote(original_url): - try: - url = original_url - if isinstance(url, unicode): - url = url.encode('ascii') - url = unquote(url).decode('utf-8') - return url - except UnicodeError: - return original_url - - class BuildQueryStringNode(template.Node): def __init__(self, sortfield): self.sortfield = sortfield @@ -82,74 +59,4 @@ def pkg_details_link(pkg, link_title=None, honor_flagged=False): return link % (pkg.get_absolute_url(), pkg.pkgname, link_content) -@library.global_function -def maintainer_link(user): - if user: - # TODO don't hardcode - title = escape('View packages maintained by ' + user.get_full_name()) - return '%s' % ( - user.username, - title, - user.get_full_name(), - ) - return '' - - -@library.global_function -def packager_link(user): - if user: - # TODO don't hardcode - title = escape('View packages packaged by ' + user.get_full_name()) - return '%s' % ( - user.username, - title, - user.get_full_name(), - ) - return '' - - -@library.global_function -def pgp_key_link(key_id, link_text=None): - return pgp.pgp_key_link(key_id, link_text) - - -@library.global_function -def scm_link(package, operation): - parts = (package.repo.svn_root, operation, package.pkgbase) - linkbase = ( - "https://projects.archlinux.org/svntogit/%s.git/%s/trunk?" - "h=packages/%s") - return linkbase % tuple(urlquote(part.encode('utf-8')) for part in parts) - - -@library.global_function -def wiki_link(package): - url = "https://wiki.archlinux.org/index.php/Special:Search" - data = { - 'search': package.pkgname, - } - return link_encode(url, data) - - -@library.global_function -def bugs_list(package): - url = "https://bugs.archlinux.org/" - data = { - 'project': package.repo.bugs_project, - 'cat[]': package.repo.bugs_category, - 'string': package.pkgname, - } - return link_encode(url, data) - - -@library.global_function -def bug_report(package): - url = "https://bugs.archlinux.org/newtask" - data = { - 'project': package.repo.bugs_project, - 'product_category': package.repo.bugs_category, - 'item_summary': '[%s] PLEASE ENTER SUMMARY' % package.pkgname, - } - return link_encode(url, data) - # vim: set ts=4 sw=4 et: -- cgit v1.2.3-54-g00ecf From 122302e9e5fb9752a942abe5691ad3dd6d186196 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 15:36:56 -0500 Subject: Move maintainer/packager link code back into template Signed-off-by: Dan McGee --- packages/templatetags/jinja2.py | 26 -------------------------- templates/packages/details.html.jinja | 14 ++++++++------ 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/packages/templatetags/jinja2.py b/packages/templatetags/jinja2.py index 263fc156..22f9914b 100644 --- a/packages/templatetags/jinja2.py +++ b/packages/templatetags/jinja2.py @@ -24,32 +24,6 @@ def link_encode(url, query): return "%s?%s" % (url, data) -@library.global_function -def maintainer_link(user): - if user: - # TODO don't hardcode - title = escape('View packages maintained by ' + user.get_full_name()) - return '%s' % ( - user.username, - title, - user.get_full_name(), - ) - return '' - - -@library.global_function -def packager_link(user): - if user: - # TODO don't hardcode - title = escape('View packages packaged by ' + user.get_full_name()) - return '%s' % ( - user.username, - title, - user.get_full_name(), - ) - return '' - - @library.global_function def pgp_key_link(key_id, link_text=None): return pgp.pgp_key_link(key_id, link_text) diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja index 7ca5629c..52d13f14 100644 --- a/templates/packages/details.html.jinja +++ b/templates/packages/details.html.jinja @@ -149,11 +149,10 @@ Maintainers: {% with maints = pkg.maintainers %} - {% if maints %} - {% for m in maints %} - {{ maintainer_link(m)|safe }}
    - {% endfor %} - {% else %}Orphan{% endif %} + {% if maints %}{% for m in maints %} + {{ m.get_full_name() }}
    + {% endfor %}{% else %}Orphan{% endif %} {% endwith %} @@ -164,7 +163,10 @@ {{ pkg.installed_size|filesizeformat }} Last Packager: - {% with pkgr = pkg.packager %}{% if pkgr %}{{ packager_link(pkgr)|safe }}{% else %}{{ pkg.packager_str }}{% endif %}{% endwith %} + {% with pkgr = pkg.packager %}{% if pkgr %} + {{ pkgr.get_full_name() }} + {% else %}{{ pkg.packager_str }}{% endif %}{% endwith %} Build Date: {{ pkg.build_date|date("DATETIME_FORMAT") }} UTC -- cgit v1.2.3-54-g00ecf From 0e90423fc09f53317992bbb024e82ef65728aa11 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 17:25:21 -0500 Subject: Add possible optimization as a TODO for later --- packages/models.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/models.py b/packages/models.py index dd69e7d3..03f03422 100644 --- a/packages/models.py +++ b/packages/models.py @@ -379,6 +379,13 @@ def get_best_satisfier(self): given criteria. It will not search provisions, but will find packages named and matching repo characteristics if possible.''' pkgs = Package.objects.normal().filter(pkgname=self.name) + # TODO: this may in fact be faster- select only the fields we know will + # actually get used, saving us some bandwidth and hopefully query + # construction time. However, reality hasn't quite proved it out yet. + #pkgs = Package.objects.select_related('repo', 'arch').only( + # 'id', 'pkgname', 'epoch', 'pkgver', 'pkgrel', + # 'repo__id', 'repo__name', 'repo__testing', 'repo__staging', + # 'arch__id', 'arch__name').filter(pkgname=self.name) if not self.pkg.arch.agnostic: # make sure we match architectures if possible arches = self.pkg.applicable_arches() -- cgit v1.2.3-54-g00ecf From a07740f230f733f98200fcb4e4528cc01a3bf2d1 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 17:25:34 -0500 Subject: Change case of SUM() SQL function --- todolists/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todolists/utils.py b/todolists/utils.py index 7b98c887..e04c2e5e 100644 --- a/todolists/utils.py +++ b/todolists/utils.py @@ -6,7 +6,7 @@ def todo_counts(): sql = """ -SELECT todolist_id, count(*), sum(CASE WHEN status = %s THEN 1 ELSE 0 END) +SELECT todolist_id, count(*), SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) FROM todolists_todolistpackage WHERE removed IS NULL GROUP BY todolist_id -- cgit v1.2.3-54-g00ecf From 4def86ec76d9975be8a357b6fc06104cc2b31fed Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 18:03:42 -0500 Subject: Package search HTML cleanups Signed-off-by: Dan McGee --- templates/packages/search.html | 15 ++++----------- templates/packages/search_paginator.html | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/templates/packages/search.html b/templates/packages/search.html index d312c374..db86fb67 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -2,7 +2,7 @@ {% load cycle from future %} {% load package_extras %} -{% block title %}Arch Linux - Package Database{% endblock %} +{% block title %}Arch Linux - Package Search{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block head %} @@ -12,10 +12,7 @@ {% block content %} - - + {% if package_list %}
    {% include "packages/search_paginator.html" %}
    {% csrf_token %} - @@ -96,10 +91,8 @@

    Package Search

    {% endif %} - - - + {% else %}

    We couldn't find any packages matching your query. Try searching again diff --git a/templates/packages/search_paginator.html b/templates/packages/search_paginator.html index 3c368b82..4c2bef03 100644 --- a/templates/packages/search_paginator.html +++ b/templates/packages/search_paginator.html @@ -22,6 +22,6 @@

    {% else %} -

    {{ package_list.count }} packages found.

    +

    {{ package_list|length }} packages found.

    {% endif %} -- cgit v1.2.3-54-g00ecf From 061805aa73d3d5b418a61fa6d6591d1a7d03d9ed Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 18:28:26 -0500 Subject: FS#30773: put exact matches at top There have been a few proposed solutions to this, but there really isn't anything without a drawback. Things break pagination, require loading the entire result set from the database, etc. Just plop a new table on the page if someone did a so-called "simple" search and we have a match. Only show on the first page of the search results. This results in a relatively fast experience for someone doing something like searching for the "perl" package. Signed-off-by: Dan McGee --- packages/views/search.py | 6 ++++++ templates/packages/search.html | 36 ++++++++++++++++++++++++++++++++ templates/packages/search_paginator.html | 4 ++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/views/search.py b/packages/views/search.py index b3778172..0b776d79 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -45,6 +45,12 @@ def __init__(self, *args, **kwargs): [('', 'All'), ('unknown', 'Unknown')] + \ [(m.username, m.get_full_name()) for m in maints] + def exact_matches(self): + # only do exact match search if 'q' is sole parameter + if self.changed_data != ['q']: + return [] + return Package.objects.normal().filter(pkgname=self.cleaned_data['q']) + def parse_form(form, packages): if form.cleaned_data['repo']: diff --git a/templates/packages/search.html b/templates/packages/search.html index db86fb67..ca95c3f0 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -40,6 +40,42 @@

    Package Search

    +{% if not is_paginated or page_obj.number == 1 %}{% with search_form.exact_matches as exact_matches %}{% if exact_matches %} +
    +
    +

    {{ exact_matches|length }} exact match{{ exact_matches|pluralize:"es" }} found.

    +
    +
    + + + + + + + + + + + + + {% for pkg in exact_matches %} + + + + {% if pkg.flag_date %} + + {% else %} + + {% endif %} + + + + {% endfor %} + +
    ArchRepoNameVersionDescriptionLast UpdatedFlag Date
    {{ pkg.arch.name }}{{ pkg.repo.name|capfirst }}{% pkg_details_link pkg %}{{ pkg.full_version }}{{ pkg.full_version }}{{ pkg.pkgdesc }}{{ pkg.last_update|date }}{{ pkg.flag_date|date }}
    +
    +{% endif %}{% endwith %}{% endif %} + {% if package_list %}
    {% include "packages/search_paginator.html" %} diff --git a/templates/packages/search_paginator.html b/templates/packages/search_paginator.html index 4c2bef03..a748d26b 100644 --- a/templates/packages/search_paginator.html +++ b/templates/packages/search_paginator.html @@ -1,6 +1,6 @@
    {% if is_paginated %} -

    {{ paginator.count }} packages found. +

    {{ paginator.count }} matching packages found. Page {{ page_obj.number }} of {{ paginator.num_pages }}.

    @@ -22,6 +22,6 @@
    {% else %} -

    {{ package_list|length }} packages found.

    +

    {{ package_list|length }} matching package{{ package_list|pluralize }} found.

    {% endif %}
    -- cgit v1.2.3-54-g00ecf From 15a27036a51d71f6f0bc4f15ae4e79b5b4de6637 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 18:43:24 -0500 Subject: Fix colspan values Signed-off-by: Dan McGee --- templates/packages/stale_relations.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/packages/stale_relations.html b/templates/packages/stale_relations.html index 2b5af236..2dafc2be 100644 --- a/templates/packages/stale_relations.html +++ b/templates/packages/stale_relations.html @@ -37,7 +37,7 @@

    Inactive User Relations ({{ inactive_user|length }})

    {{ relation.created }} {% empty %} - No inactive user relations. + No inactive user relations. {% endfor %} @@ -66,7 +66,7 @@

    Relations with Non-existent pkgbase ({{ missing_pkgbase|length }})< {{ relation.last_update.created }} {% empty %} - No non-existent pkgbase relations. + No non-existent pkgbase relations. {% endfor %} @@ -100,7 +100,7 @@

    Maintainers with Wrong Permissions ({{ wrong_permissions|length }})

    {{ relation.repositories|join:", " }} {% empty %} - No relations with wrong permissions. + No relations with wrong permissions. {% endfor %} -- cgit v1.2.3-54-g00ecf From 21b8ff5cf2b60f862e3fc3cfb43d8d8af0d6189f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 18 Oct 2014 19:21:26 -0500 Subject: Tweak search results page a bit more Signed-off-by: Dan McGee --- sitestatic/archweb.css | 4 ++++ templates/packages/search.html | 28 ++++++++++++++-------------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/sitestatic/archweb.css b/sitestatic/archweb.css index 53fa6274..edabcfb7 100644 --- a/sitestatic/archweb.css +++ b/sitestatic/archweb.css @@ -701,6 +701,10 @@ table.results { color: red; } + .results tr.empty td { + text-align: center; + } + /* pkglist: layout */ #pkglist-about { margin-top: 1.5em; diff --git a/templates/packages/search.html b/templates/packages/search.html index ca95c3f0..d4a47b26 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -58,7 +58,8 @@

    Package Search

    - {% for pkg in exact_matches %} + {% for pkg in exact_matches %} + {{ pkg.arch.name }} {{ pkg.repo.name|capfirst }} {% pkg_details_link pkg %} @@ -70,13 +71,13 @@

    Package Search

    {{ pkg.pkgdesc }} {{ pkg.last_update|date }} {{ pkg.flag_date|date }} - {% endfor %} + + {% endfor %}
    {% endif %}{% endwith %}{% endif %} -{% if package_list %}
    {% include "packages/search_paginator.html" %}
    {% csrf_token %} @@ -101,7 +102,8 @@

    Package Search

    - {% for pkg in package_list %} + {% for pkg in package_list %} + {% if perms.main.change_package %} {% endif %} @@ -116,7 +118,10 @@

    Package Search

    {{ pkg.pkgdesc }} {{ pkg.last_update|date }} {{ pkg.flag_date|date }} - {% endfor %} + + {% empty %} + No matching packages found + {% endfor %} {% include "packages/search_paginator.html" %} @@ -129,21 +134,16 @@

    Package Search

    {% endif %}
    -{% else %} -
    -

    We couldn't find any packages matching your query. Try searching again + +

    +

    Can't find what you are looking for? Try searching again using different criteria, or try {% if search_form.q.data %} searching the AUR {% else %}searching the AUR{% endif %} to see if the package can be found there.

    -
    -{% endif %} -

    You are browsing the Arch Linux package database. From here you can find - detailed information about packages located in the official supported repositories. - For unsupported packages, browse the Arch User Repository (AUR).

    + detailed information about packages located in the official supported repositories.

    {% endblock %} -- cgit v1.2.3-54-g00ecf From ff09c7877e58ddadaf677bf133cd110711bbc5a8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 10:39:03 -0500 Subject: Fix function vs. property reference in Jinja template Signed-off-by: Dan McGee --- templates/packages/details.html.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja index 52d13f14..0b5d0ae8 100644 --- a/templates/packages/details.html.jinja +++ b/templates/packages/details.html.jinja @@ -93,7 +93,7 @@ {% else %} Base Package: - {% with base = pkg.base_package %}{% if base %} + {% with base = pkg.base_package() %}{% if base %} {{ details.details_link(base) }} {% else %} Date: Sun, 19 Oct 2014 11:00:20 -0500 Subject: Fix Jinja2 render in no-packager case Signed-off-by: Dan McGee --- templates/packages/details.html.jinja | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja index 0b5d0ae8..21be80f5 100644 --- a/templates/packages/details.html.jinja +++ b/templates/packages/details.html.jinja @@ -69,10 +69,10 @@ - -
    + + {% if pkg.packager %}
    -
    +
    {% endif %} -- cgit v1.2.3-54-g00ecf From 9589a7eadeb05e82c2d63f6fe128316fdb6dcc8a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 11:14:26 -0500 Subject: Convert package files view to Jinja2 This is another one we spend a lot of time rendering, and packges like sage-mathematics with 80,000+ files can really make the Django template engine grind. Signed-off-by: Dan McGee --- templates/packages/files.html | 2 +- templates/packages/files_list.html | 16 ---------------- templates/packages/files_list.html.jinja | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 templates/packages/files_list.html create mode 100644 templates/packages/files_list.html.jinja diff --git a/templates/packages/files.html b/templates/packages/files.html index 3e718ed0..879fcbff 100644 --- a/templates/packages/files.html +++ b/templates/packages/files.html @@ -9,7 +9,7 @@

    {{ pkg.pkgname }} {{ pkg.full_version }} File List

    Package has {{ files_count }} file{{ files_count|pluralize }} and {{ dir_count }} director{{ dir_count|pluralize:"y,ies" }}.

    Back to Package

    - {% include "packages/files_list.html" %} + {% include "packages/files_list.html.jinja" %}
    diff --git a/templates/packages/files_list.html b/templates/packages/files_list.html deleted file mode 100644 index 93a2c847..00000000 --- a/templates/packages/files_list.html +++ /dev/null @@ -1,16 +0,0 @@ -{% if pkg.last_update > pkg.files_last_update %} -

    Note: This file list was generated from a previous version -of the package; it may be out of date.

    -{% endif %} -{% if pkg.files_last_update %} -{% if files|length %} -
      -{% for file in files %} -
    • {{ file.directory }}{{ file.filename|default:'' }}
    • {% endfor %} -
    -{% else %} -

    Package has no files.

    -{% endif %} -{% else %} -

    No file list available.

    -{% endif %} diff --git a/templates/packages/files_list.html.jinja b/templates/packages/files_list.html.jinja new file mode 100644 index 00000000..c8fc3b1a --- /dev/null +++ b/templates/packages/files_list.html.jinja @@ -0,0 +1,16 @@ +{% if pkg.last_update > pkg.files_last_update %} +

    Note: This file list was generated from a previous version +of the package; it may be out of date.

    +{% endif %} +{% if pkg.files_last_update %} +{% if files|length %} +
      +{% for file in files %} +
    • {{ file.directory }}{{ file.filename|default('') }}
    • {% endfor %} +
    +{% else %} +

    Package has no files.

    +{% endif %} +{% else %} +

    No file list available.

    +{% endif %} -- cgit v1.2.3-54-g00ecf From 7c26f6b7a4d29faede58d2feb13ef961e4725637 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 14:08:15 -0500 Subject: Use raw DB query to fetch last modified date Signed-off-by: Dan McGee --- mirrors/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mirrors/views.py b/mirrors/views.py index 26b5b802..55c40c4d 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -6,6 +6,7 @@ from django import forms from django.forms.widgets import CheckboxSelectMultiple from django.core.serializers.json import DjangoJSONEncoder +from django.db import connection from django.db.models import Q from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect, render @@ -222,7 +223,9 @@ def url_details(request, name, url_id): def status_last_modified(request, *args, **kwargs): - return MirrorLog.objects.values_list('check_time', flat=True).latest() + cursor = connection.cursor() + cursor.execute("SELECT MAX(check_time) FROM mirrors_mirrorlog") + return cursor.fetchone()[0] @condition(last_modified_func=status_last_modified) -- cgit v1.2.3-54-g00ecf From 1ff2e37e049004852681794537417a1947bf6f18 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 14:19:05 -0500 Subject: Simplify last modified and etags processing for feeds We had this elaborate system set up with caching and invalidation, which is overkill since we cache the result of the view anyway. Just hit the database when needed to find the last change to the respective model class and be done with it. Signed-off-by: Dan McGee --- feeds.py | 14 +++++++++----- main/models.py | 6 +----- main/utils.py | 42 ------------------------------------------ news/models.py | 7 ++----- 4 files changed, 12 insertions(+), 57 deletions(-) diff --git a/feeds.py b/feeds.py index feb8a84a..d1836178 100644 --- a/feeds.py +++ b/feeds.py @@ -4,11 +4,11 @@ from django.contrib.sites.models import Site from django.contrib.syndication.views import Feed +from django.db import connection from django.db.models import Q from django.utils.feedgenerator import Rss201rev2Feed from django.views.decorators.http import condition -from main.utils import retrieve_latest from main.models import Arch, Repo, Package from news.models import News from releng.models import Release @@ -64,13 +64,15 @@ def write(self, outfile, encoding): def package_etag(request, *args, **kwargs): - latest = retrieve_latest(Package) + latest = package_last_modified(request) if latest: return hashlib.md5(str(kwargs) + str(latest)).hexdigest() return None def package_last_modified(request, *args, **kwargs): - return retrieve_latest(Package) + cursor = connection.cursor() + cursor.execute("SELECT MAX(last_update) FROM packages") + return cursor.fetchone()[0] class PackageFeed(Feed): @@ -148,13 +150,15 @@ def item_categories(self, item): def news_etag(request, *args, **kwargs): - latest = retrieve_latest(News, 'last_modified') + latest = news_last_modified(request) if latest: return hashlib.md5(str(latest)).hexdigest() return None def news_last_modified(request, *args, **kwargs): - return retrieve_latest(News, 'last_modified') + cursor = connection.cursor() + cursor.execute("SELECT MAX(last_modified) FROM news") + return cursor.fetchone()[0] class NewsFeed(Feed): diff --git a/main/models.py b/main/models.py index 09b1adc0..1b95f3fa 100644 --- a/main/models.py +++ b/main/models.py @@ -443,12 +443,8 @@ class Meta: db_table = 'package_files' -# connect signals needed to keep cache in line with reality -from main.utils import refresh_latest -from django.db.models.signals import pre_save, post_save +from django.db.models.signals import pre_save -post_save.connect(refresh_latest, sender=Package, - dispatch_uid="main.models") # note: reporead sets the 'created' field on Package objects, so no signal # listener is set up here to do so pre_save.connect(set_created_field, sender=Donor, diff --git a/main/utils.py b/main/utils.py index 97cc540a..cf156566 100644 --- a/main/utils.py +++ b/main/utils.py @@ -12,11 +12,6 @@ from django.template.defaultfilters import slugify -CACHE_TIMEOUT = 1800 -INVALIDATE_TIMEOUT = 10 -CACHE_LATEST_PREFIX = 'cache_latest_' - - def cache_function_key(func, args, kwargs): raw = [func.__name__, func.__module__, args, kwargs] pickled = pickle.dumps(raw, protocol=pickle.HIGHEST_PROTOCOL) @@ -76,43 +71,6 @@ def format_http_headers(request): make_choice = lambda l: [(str(m), str(m)) for m in l] -# These are in here because we would be jumping around in some import circles -# and hoops otherwise. The only thing currently using these keys is the feed -# caching stuff. - -def refresh_latest(**kwargs): - '''A post_save signal handler to clear out the cached latest value for a - given model.''' - cache_key = CACHE_LATEST_PREFIX + kwargs['sender'].__name__ - # We could delete the value, but that could open a race condition - # where the new data wouldn't have been committed yet by the calling - # thread. Instead, explicitly set it to None for a short amount of time. - # Hopefully by the time it expires we will have committed, and the cache - # will be valid again. See "Scaling Django" by Mike Malone, slide 30. - cache.set(cache_key, None, INVALIDATE_TIMEOUT) - - -def retrieve_latest(sender, latest_by=None): - # we could break this down based on the request url, but it would probably - # cost us more in query time to do so. - cache_key = CACHE_LATEST_PREFIX + sender.__name__ - latest = cache.get(cache_key) - if latest: - return latest - try: - if latest_by is None: - latest_by = sender._meta.get_latest_by - latest = sender.objects.values(latest_by).latest(latest_by)[latest_by] - # Using add means "don't overwrite anything in there". What could be in - # there is an explicit None value that our refresh signal set, which - # means we want to avoid race condition possibilities for a bit. - cache.add(cache_key, latest, CACHE_TIMEOUT) - return latest - except sender.DoesNotExist: - pass - return None - - def set_created_field(sender, **kwargs): '''This will set the 'created' field on any object to the current UTC time if it is unset. diff --git a/news/models.py b/news/models.py index d51db7c7..985c1088 100644 --- a/news/models.py +++ b/news/models.py @@ -45,12 +45,9 @@ def set_news_fields(sender, **kwargs): news.guid = 'tag:%s,%s:%s' % (Site.objects.get_current(), current_time.strftime('%Y-%m-%d'), news.get_absolute_url()) -# connect signals needed to keep cache in line with reality -from main.utils import refresh_latest -from django.db.models.signals import pre_save, post_save -post_save.connect(refresh_latest, sender=News, - dispatch_uid="news.models") +from django.db.models.signals import pre_save + pre_save.connect(set_news_fields, sender=News, dispatch_uid="news.models") -- cgit v1.2.3-54-g00ecf From 7c46d07f6417382e560d32c361c94dd8f2b9ddb8 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 18:12:58 -0500 Subject: Use varied prime numbers for caching lengths Signed-off-by: Dan McGee --- devel/utils.py | 2 +- main/templatetags/pgp.py | 2 +- packages/views/__init__.py | 4 ++-- public/views.py | 14 +++++++------- urls.py | 17 ++++++++--------- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/devel/utils.py b/devel/utils.py index 340841f5..0cafbb59 100644 --- a/devel/utils.py +++ b/devel/utils.py @@ -9,7 +9,7 @@ from main.models import Package from packages.models import PackageRelation -@cache_function(300) +@cache_function(283) def get_annotated_maintainers(): maintainers = User.objects.filter(is_active=True).order_by( 'first_name', 'last_name') diff --git a/main/templatetags/pgp.py b/main/templatetags/pgp.py index cc080439..2417f688 100644 --- a/main/templatetags/pgp.py +++ b/main/templatetags/pgp.py @@ -44,7 +44,7 @@ def pgp_key_link(key_id, link_text=None): return '%s' % values -@cache_function(1800) +@cache_function(1741) def name_for_key(normalized): try: matching_key = DeveloperKey.objects.select_related( diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 46c99985..6b44206a 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -35,7 +35,7 @@ def opensearch(request): @require_safe -@cache_control(public=True, max_age=300) +@cache_control(public=True, max_age=613) def opensearch_suggest(request): search_term = request.GET.get('q', '') if search_term == '': @@ -55,7 +55,7 @@ def opensearch_suggest(request): 'pkgname', flat=True).order_by('pkgname').distinct()[:10] results = [search_term, list(names)] to_json = json.dumps(results, ensure_ascii=False) - cache.set(cache_key, to_json, 300) + cache.set(cache_key, to_json, 613) return HttpResponse(to_json, content_type='application/x-suggestions+json') diff --git a/public/views.py b/public/views.py index 3b23bd42..62d1137a 100644 --- a/public/views.py +++ b/public/views.py @@ -17,7 +17,7 @@ from .utils import get_recent_updates -@cache_control(max_age=300) +@cache_control(max_age=307) def index(request): if request.user.is_authenticated(): def updates(): @@ -50,7 +50,7 @@ def updates(): } -@cache_control(max_age=300) +@cache_control(max_age=307) def userlist(request, user_type='devs'): users = User.objects.order_by( 'first_name', 'last_name').select_related('userprofile') @@ -70,7 +70,7 @@ def userlist(request, user_type='devs'): return render(request, 'public/userlist.html', context) -@cache_control(max_age=300) +@cache_control(max_age=307) def donate(request): context = { 'donors': Donor.objects.filter(visible=True).order_by('name'), @@ -88,7 +88,7 @@ def _mirror_urls(): return sorted(urls, key=sort_by) -@cache_control(max_age=300) +@cache_control(max_age=307) def download(request): try: release = Release.objects.filter(available=True).latest() @@ -104,7 +104,7 @@ def download(request): return render(request, 'public/download.html', context) -@cache_control(max_age=300) +@cache_control(max_age=307) def feeds(request): repos = Repo.objects.all() if not request.user.is_authenticated(): @@ -116,7 +116,7 @@ def feeds(request): return render(request, 'public/feeds.html', context) -@cache_control(max_age=300) +@cache_control(max_age=307) def keys(request): users = User.objects.filter(is_active=True).select_related( 'userprofile__pgp_key').order_by('first_name', 'last_name') @@ -153,7 +153,7 @@ def keys(request): return render(request, 'public/keys.html', context) -@cache_page(1800) +@cache_page(1789) def keys_json(request): node_list = [] diff --git a/urls.py b/urls.py index e7f2b24c..8f0bbe21 100644 --- a/urls.py +++ b/urls.py @@ -41,20 +41,19 @@ # Feeds patterns, used below feeds_patterns = patterns('', (r'^$', 'public.views.feeds', {}, 'feeds-list'), - (r'^news/$', cache_page(300)(NewsFeed())), - (r'^packages/$', cache_page(300)(PackageFeed())), + (r'^news/$', cache_page(311)(NewsFeed())), + (r'^packages/$', cache_page(313)(PackageFeed())), (r'^packages/(?P[A-z0-9]+)/$', - cache_page(300)(PackageFeed())), + cache_page(313)(PackageFeed())), (r'^packages/all/(?P[A-z0-9\-]+)/$', - cache_page(300)(PackageFeed())), + cache_page(313)(PackageFeed())), (r'^packages/(?P[A-z0-9]+)/(?P[A-z0-9\-]+)/$', - cache_page(300)(PackageFeed())), - (r'^releases/$', cache_page(300)(ReleaseFeed())), + cache_page(313)(PackageFeed())), + (r'^releases/$', cache_page(317)(ReleaseFeed())), ) # Includes and other remaining stuff urlpatterns += patterns('', - # cache this static JS resource for 1 week rather than default 5 minutes (r'^admin/', include(admin.site.urls)), (r'^devel/', include('devel.urls')), (r'^feeds/', include(feeds_patterns)), @@ -80,10 +79,10 @@ # Sitemaps urlpatterns += patterns('', (r'^sitemap.xml$', - cache_page(1800)(sitemap_views.index), + cache_page(1831)(sitemap_views.index), {'sitemaps': our_sitemaps, 'sitemap_url_name': 'sitemaps'}), (r'^sitemap-(?P
    .+)\.xml$', - cache_page(1800)(sitemap_views.sitemap), + cache_page(1831)(sitemap_views.sitemap), {'sitemaps': our_sitemaps}, 'sitemaps'), ) -- cgit v1.2.3-54-g00ecf From f7d1940a731370ceee6e1c6eaae2cc2f5bab0432 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 19 Oct 2014 18:30:32 -0500 Subject: Remove usage of templates for RSS feeds Signed-off-by: Dan McGee --- feeds.py | 8 ++++++-- templates/feeds/news_description.html | 2 -- templates/feeds/packages_title.html | 1 - 3 files changed, 6 insertions(+), 5 deletions(-) delete mode 100644 templates/feeds/news_description.html delete mode 100644 templates/feeds/packages_title.html diff --git a/feeds.py b/feeds.py index d1836178..0bbac270 100644 --- a/feeds.py +++ b/feeds.py @@ -79,7 +79,6 @@ class PackageFeed(Feed): feed_type = GuidNotPermalinkFeed link = '/packages/' - title_template = 'feeds/packages_title.html' def __call__(self, request, *args, **kwargs): wrapper = condition(etag_func=package_etag, last_modified_func=package_last_modified) @@ -142,6 +141,9 @@ def item_guid(self, item): def item_pubdate(self, item): return item.last_update + def item_title(self, item): + return '%s %s %s' % (item.pkgname, item.full_version, item.arch.name) + def item_description(self, item): return item.pkgdesc @@ -168,7 +170,6 @@ class NewsFeed(Feed): link = '/news/' description = 'The latest and greatest news from the Arch Linux distribution.' subtitle = description - description_template = 'feeds/news_description.html' def __call__(self, request, *args, **kwargs): wrapper = condition(etag_func=news_etag, last_modified_func=news_last_modified) @@ -192,6 +193,9 @@ def item_author_name(self, item): def item_title(self, item): return item.title + def item_description(self, item): + return item.html() + class ReleaseFeed(Feed): feed_type = GuidNotPermalinkFeed diff --git a/templates/feeds/news_description.html b/templates/feeds/news_description.html deleted file mode 100644 index 61ceedf3..00000000 --- a/templates/feeds/news_description.html +++ /dev/null @@ -1,2 +0,0 @@ -

    {{obj.author.get_full_name}} wrote:

    -{{ obj.html }} diff --git a/templates/feeds/packages_title.html b/templates/feeds/packages_title.html deleted file mode 100644 index f92ac684..00000000 --- a/templates/feeds/packages_title.html +++ /dev/null @@ -1 +0,0 @@ -{{ obj.pkgname }} {{ obj.full_version }} {{ obj.arch.name }} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From f9f8683799ef96904a7165adcfdeb0d13cb7ff61 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 20 Oct 2014 07:55:24 -0500 Subject: Fix display of flag requests for non-logged-in users More Jinja2 conversion fallout, whoops. Signed-off-by: Dan McGee --- templates/packages/details.html.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja index 21be80f5..2215f8dc 100644 --- a/templates/packages/details.html.jinja +++ b/templates/packages/details.html.jinja @@ -183,7 +183,7 @@
    - {% if user.is_authenticated %}{% with flag_request = pkg.flag_request() %}{% if flag_request %} + {% if user.is_authenticated() %}{% with flag_request = pkg.flag_request() %}{% if flag_request %} -- cgit v1.2.3-54-g00ecf From ee6bf2782068b917232c71189aea0011b47e876d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 09:10:28 -0500 Subject: Small performance tweaks to mirror status JSON encoding Do a few things to speed up the encoding of the JSON, including better usage of list comprehensions, less dynamic setattr() usage, and removal of the queryset specialization since we can easily do it outside of the encoder. Signed-off-by: Dan McGee --- mirrors/utils.py | 30 ++++++++++++++---------------- mirrors/views.py | 7 ++----- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/mirrors/utils.py b/mirrors/utils.py index fe18cd6a..4484fa24 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -84,19 +84,16 @@ def status_data(cutoff=DEFAULT_CUTOFF, mirror_id=None): def annotate_url(url, url_data): '''Given a MirrorURL object, add a few more attributes to it regarding status, including completion_pct, delay, and score.''' - known_attrs = ( - ('success_count', 0), - ('check_count', 0), - ('completion_pct', None), - ('duration_avg', None), - ('duration_stddev', None), - ('last_check', None), - ('last_sync', None), - ('delay', None), - ('score', None), - ) - for k, v in known_attrs: - setattr(url, k, v) + # set up some sane default values in case we are missing anything + url.success_count = 0 + url.check_count = 0 + url.completion_pct = None + url.duration_avg = None + url.duration_stddev = None + url.last_check = None + url.last_sync = None + url.delay = None + url.score = None for k, v in url_data.items(): if k not in ('url_id', 'mirror_id'): setattr(url, k, v) @@ -107,7 +104,7 @@ def annotate_url(url, url_data): if url.delay is not None: hours = url.delay.days * 24.0 + url.delay.seconds / 3600.0 - if url.completion_pct > 0: + if url.completion_pct > 0.0: divisor = url.completion_pct else: # arbitrary small value @@ -115,6 +112,8 @@ def annotate_url(url, url_data): stddev = url.duration_stddev or 0.0 url.score = (hours + url.duration_avg + stddev) / divisor + return url + def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): cutoff_time = now() - cutoff @@ -133,8 +132,7 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): id__in=valid_urls).order_by('mirror__id', 'url') if urls: - for url in urls: - annotate_url(url, url_data.get(url.id, {})) + urls = [annotate_url(url, url_data.get(url.id, {})) for url in urls] last_check = max([u.last_check for u in urls if u.last_check]) num_checks = max([u.check_count for u in urls]) check_info = MirrorLog.objects.filter(check_time__gte=cutoff_time) diff --git a/mirrors/views.py b/mirrors/views.py index 55c40c4d..0bf0a267 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -275,9 +275,6 @@ def default(self, obj): if isinstance(obj, timedelta): # always returned as integer seconds return obj.days * 24 * 3600 + obj.seconds - if hasattr(obj, '__iter__'): - # mainly for queryset serialization - return list(obj) if isinstance(obj, MirrorUrl): data = {attr: getattr(obj, attr) for attr in self.url_attributes} country = obj.country @@ -298,8 +295,8 @@ def default(self, obj): if isinstance(obj, MirrorUrl): data = super(ExtendedMirrorStatusJSONEncoder, self).default(obj) cutoff = now() - DEFAULT_CUTOFF - data['logs'] = obj.logs.filter( - check_time__gte=cutoff).order_by('check_time') + data['logs'] = list(obj.logs.filter( + check_time__gte=cutoff).order_by('check_time')) return data if isinstance(obj, MirrorLog): return {attr: getattr(obj, attr) for attr in self.log_attributes} -- cgit v1.2.3-54-g00ecf From 087b4b00031fed52eeddf05ae36825cb498680f0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 09:11:48 -0500 Subject: Remove queryset specialization in JSON encoder Signed-off-by: Dan McGee --- mirrors/views.py | 5 +---- releng/views.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/mirrors/views.py b/mirrors/views.py index 0bf0a267..1a9741ed 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -323,9 +323,6 @@ class LocationJSONEncoder(DjangoJSONEncoder): '''Base JSONEncoder extended to handle CheckLocation objects.''' def default(self, obj): - if hasattr(obj, '__iter__'): - # mainly for queryset serialization - return list(obj) if isinstance(obj, CheckLocation): return { 'id': obj.pk, @@ -341,7 +338,7 @@ def default(self, obj): def locations_json(request): data = {} data['version'] = 1 - data['locations'] = CheckLocation.objects.all().order_by('pk') + data['locations'] = list(CheckLocation.objects.all().order_by('pk')) to_json = json.dumps(data, ensure_ascii=False, cls=LocationJSONEncoder) response = HttpResponse(to_json, content_type='application/json') return response diff --git a/releng/views.py b/releng/views.py index ef81a65c..dbb65c2e 100644 --- a/releng/views.py +++ b/releng/views.py @@ -247,9 +247,6 @@ class ReleaseJSONEncoder(DjangoJSONEncoder): 'created', 'md5_sum', 'sha1_sum') def default(self, obj): - if hasattr(obj, '__iter__'): - # mainly for queryset serialization - return list(obj) if isinstance(obj, Release): data = {attr: getattr(obj, attr) or None for attr in self.release_attributes} @@ -276,7 +273,7 @@ def releases_json(request): data = { 'version': 1, - 'releases': releases, + 'releases': list(releases), 'latest_version': latest_version, } to_json = json.dumps(data, ensure_ascii=False, cls=ReleaseJSONEncoder) -- cgit v1.2.3-54-g00ecf From 86fd0b722afb53670ef9a155a3c55d688f275c6d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 09:39:06 -0500 Subject: Reduce complexity of status data URL query Get rid of all the junk trying to only return URLs that have been checked in the last 24 hours; it just isn't worth it. Instead, do that screening only in the views that need it, namely the HTML status page. Signed-off-by: Dan McGee --- mirrors/utils.py | 14 +++++--------- mirrors/views.py | 5 ++++- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/mirrors/utils.py b/mirrors/utils.py index 4484fa24..8edceb9b 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -118,20 +118,16 @@ def annotate_url(url, url_data): def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): cutoff_time = now() - cutoff - valid_urls = MirrorUrl.objects.filter( - logs__check_time__gte=cutoff_time).distinct() - + urls = MirrorUrl.objects.select_related( + 'mirror', 'protocol').order_by('mirror__id', 'url') if mirror_id: - valid_urls = valid_urls.filter(mirror_id=mirror_id) + urls = urls.filter(mirror_id=mirror_id) if not show_all: - valid_urls = valid_urls.filter(active=True, mirror__active=True, + urls = urls.filter(active=True, mirror__active=True, mirror__public=True) - url_data = status_data(cutoff, mirror_id) - urls = MirrorUrl.objects.select_related('mirror', 'protocol').filter( - id__in=valid_urls).order_by('mirror__id', 'url') - if urls: + url_data = status_data(cutoff, mirror_id) urls = [annotate_url(url, url_data.get(url.id, {})) for url in urls] last_check = max([u.last_check for u in urls if u.last_check]) num_checks = max([u.check_count for u in urls]) diff --git a/mirrors/views.py b/mirrors/views.py index 1a9741ed..90787763 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -245,7 +245,10 @@ def status(request, tier=None): if tier is not None and url.mirror.tier != tier: continue # split them into good and bad lists based on delay - if not url.delay or url.delay > bad_timedelta: + if url.completion_pct is None: + # skip URLs that have never been checked + continue + elif not url.delay or url.delay > bad_timedelta: bad_urls.append(url) else: good_urls.append(url) -- cgit v1.2.3-54-g00ecf From 48509bfdbdadb8255f32c56d993f91262516916f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 10:00:48 -0500 Subject: Simplify/clean-up finding of download mirror Signed-off-by: Dan McGee --- mirrors/utils.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mirrors/utils.py b/mirrors/utils.py index 8edceb9b..fb867dee 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -189,23 +189,21 @@ def get_mirror_url_for_download(cutoff=DEFAULT_CUTOFF): if status_data['check_time__max'] is not None: min_check_time = status_data['check_time__max'] - timedelta(minutes=5) min_sync_time = status_data['last_sync__max'] - timedelta(minutes=20) - best_logs = MirrorLog.objects.filter(is_success=True, + best_logs = MirrorLog.objects.select_related('url').filter( + is_success=True, check_time__gte=min_check_time, last_sync__gte=min_sync_time, url__active=True, url__mirror__public=True, url__mirror__active=True, url__protocol__default=True).order_by( 'duration')[:1] if best_logs: - return MirrorUrl.objects.get(id=best_logs[0].url_id) + return best_logs[0].url mirror_urls = MirrorUrl.objects.filter(active=True, - mirror__public=True, mirror__active=True, protocol__default=True) - # look first for a country-agnostic URL, then fall back to any HTTP URL - filtered_urls = mirror_urls.filter(country='')[:1] - if not filtered_urls: - filtered_urls = mirror_urls[:1] - if not filtered_urls: + mirror__public=True, mirror__active=True, + protocol__default=True)[:1] + if not mirror_urls: return None - return filtered_urls[0] + return mirror_urls[0] # vim: set ts=4 sw=4 et: -- cgit v1.2.3-54-g00ecf From f53ea0b102d0251a98116aad445d55570c71931c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 10:01:53 -0500 Subject: Move caching of function data back to get_mirror_statuses We've moved this around a few times, including changing the parameters to ensure they are stable (commit bdfa22500f4). However, the bulk of the work takes place in the mashing up of the data, so cache the full result rather than just the result of a single query. Signed-off-by: Dan McGee --- mirrors/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mirrors/utils.py b/mirrors/utils.py index fb867dee..5685c9c8 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -21,9 +21,7 @@ def dictfetchall(cursor): for row in cursor.fetchall() ] -@cache_function(178) -def status_data(cutoff=DEFAULT_CUTOFF, mirror_id=None): - cutoff_time = now() - cutoff +def status_data(cutoff_time, mirror_id=None): if mirror_id is not None: params = [cutoff_time, mirror_id] mirror_where = 'AND u.mirror_id = %s' @@ -115,6 +113,7 @@ def annotate_url(url, url_data): return url +@cache_function(178) def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): cutoff_time = now() - cutoff @@ -127,7 +126,7 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): mirror__public=True) if urls: - url_data = status_data(cutoff, mirror_id) + url_data = status_data(cutoff_time, mirror_id) urls = [annotate_url(url, url_data.get(url.id, {})) for url in urls] last_check = max([u.last_check for u in urls if u.last_check]) num_checks = max([u.check_count for u in urls]) -- cgit v1.2.3-54-g00ecf From 72535f8e93b144528baf98c4998430ba3a030a70 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 17:04:39 -0500 Subject: Update django_countries to latest release Signed-off-by: Dan McGee --- requirements.txt | 2 +- requirements_prod.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index e2b49aba..5d544e3c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,11 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin --e git+git://github.com/SmileyChris/django-countries.git@a2c924074dbe2f0b9b3059bf70064aeadf5643ed#egg=django-countries Django==1.7 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 +django_countries==3.0 jsmin==2.0.11 pgpdump==1.5 pytz>=2014.7 diff --git a/requirements_prod.txt b/requirements_prod.txt index 020a5ac4..e3bc0ae2 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,11 +1,11 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin --e git+git://github.com/SmileyChris/django-countries.git@a2c924074dbe2f0b9b3059bf70064aeadf5643ed#egg=django-countries Django==1.7 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 +django_countries==3.0 jsmin==2.0.11 pgpdump==1.5 psycopg2==2.5.4 -- cgit v1.2.3-54-g00ecf From c86ef5c326212f09a22f5ae3502a0bc79033a23a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 17:08:56 -0500 Subject: Use cache_page on mirror status JSON Signed-off-by: Dan McGee --- mirrors/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mirrors/views.py b/mirrors/views.py index 90787763..c2736da8 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -11,6 +11,7 @@ from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect, render from django.utils.timezone import now +from django.views.decorators.cache import cache_page from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import condition from django_countries.data import COUNTRIES @@ -306,6 +307,7 @@ def default(self, obj): return super(ExtendedMirrorStatusJSONEncoder, self).default(obj) +@cache_page(67) @condition(last_modified_func=status_last_modified) def status_json(request, tier=None): if tier is not None: -- cgit v1.2.3-54-g00ecf From 9f20cf7c81a38283fa08552f59a149d6abd76516 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 17:32:09 -0500 Subject: Remove old suggested recommended settings Signed-off-by: Dan McGee --- local_settings.py.example | 4 ---- 1 file changed, 4 deletions(-) diff --git a/local_settings.py.example b/local_settings.py.example index df141521..ffd6d8a6 100644 --- a/local_settings.py.example +++ b/local_settings.py.example @@ -1,5 +1,3 @@ -### Django settings for archlinux project. - ## Debug settings DEBUG = False TEMPLATE_DEBUG = False @@ -41,8 +39,6 @@ CACHES = { #'LOCATION': '127.0.0.1:11211', } } -CACHE_MIDDLEWARE_KEY_PREFIX = 'arch' -CACHE_MIDDLEWARE_SECONDS = 300 ## Use secure session cookies? Make this true if you want all ## logged-in actions to take place over HTTPS only. If developing -- cgit v1.2.3-54-g00ecf From 69d771978bcf7d70d106c3e704fde203451fd48e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 17:32:29 -0500 Subject: Fix 500 when no URLs have been checked Signed-off-by: Dan McGee --- mirrors/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirrors/utils.py b/mirrors/utils.py index 5685c9c8..51daf50e 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -128,8 +128,8 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): if urls: url_data = status_data(cutoff_time, mirror_id) urls = [annotate_url(url, url_data.get(url.id, {})) for url in urls] - last_check = max([u.last_check for u in urls if u.last_check]) - num_checks = max([u.check_count for u in urls]) + last_check = max([u.last_check for u in urls if u.last_check] or [None]) + num_checks = max(u.check_count for u in urls) check_info = MirrorLog.objects.filter(check_time__gte=cutoff_time) if mirror_id: check_info = check_info.filter(url__mirror_id=mirror_id) -- cgit v1.2.3-54-g00ecf From d009cd0b5c4ba018681942daa59452fe2b1a42c2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 20:33:12 -0500 Subject: Fix error when viewing mirror with no active URLs Signed-off-by: Dan McGee --- mirrors/utils.py | 1 + mirrors/views.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mirrors/utils.py b/mirrors/utils.py index 51daf50e..930adb8d 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -141,6 +141,7 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): else: check_frequency = None else: + urls = [] last_check = None num_checks = 0 check_frequency = None diff --git a/mirrors/views.py b/mirrors/views.py index c2736da8..cffafbf5 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -193,6 +193,8 @@ def mirror_details(request, name): def mirror_details_json(request, name): authorized = request.user.is_authenticated() mirror = get_object_or_404(Mirror, name=name) + if not authorized and (not mirror.public or not mirror.active): + raise Http404 status_info = get_mirror_statuses(mirror_id=mirror.id, show_all=authorized) data = status_info.copy() -- cgit v1.2.3-54-g00ecf From abb3a507a1e8f218b5225d3e00187808e323e48a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 21 Oct 2014 21:12:24 -0500 Subject: Move all homepage JavaScript into single file We had two small files plus a handful of inline stuff in the HTML; move as much of it as possible into a single static file. Signed-off-by: Dan McGee --- sitestatic/bootstrap-typeahead.min.js | 1 - sitestatic/homepage.js | 42 +++++++++++++++++++++++++++++++++++ templates/public/index.html | 38 +------------------------------ 3 files changed, 43 insertions(+), 38 deletions(-) delete mode 100644 sitestatic/bootstrap-typeahead.min.js create mode 100644 sitestatic/homepage.js diff --git a/sitestatic/bootstrap-typeahead.min.js b/sitestatic/bootstrap-typeahead.min.js deleted file mode 100644 index 7d555ed9..00000000 --- a/sitestatic/bootstrap-typeahead.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery) \ No newline at end of file diff --git a/sitestatic/homepage.js b/sitestatic/homepage.js new file mode 100644 index 00000000..48dab93f --- /dev/null +++ b/sitestatic/homepage.js @@ -0,0 +1,42 @@ +!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.typeahead.defaults,n),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.updater=this.options.updater||this.updater,this.$menu=e(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};t.prototype={constructor:t,select:function(){var e=this.$menu.find(".active").attr("data-value");return e&&this.$element.val(this.updater(e)).change(),this.hide()},updater:function(e){return e},show:function(){var t=e.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:t.top+t.height,left:t.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(t){var n;return this.query=this.$element.val(),!this.query||this.query.length"+t+""})},render:function(t){var n=this;return t=e(t).map(function(t,r){return t=e(n.options.item).attr("data-value",r),t.find("a").html(n.highlighter(r)),t[0]}),this.$menu.html(t),this},next:function(t){var n=this.$menu.find(".active").removeClass("active"),r=n.next();r.length||(r=e(this.$menu.find("li")[0])),r.addClass("active")},prev:function(e){var t=this.$menu.find(".active").removeClass("active"),n=t.prev();n.length||(n=this.$menu.find("li").last()),n.addClass("active")},listen:function(){this.$element.on("blur",e.proxy(this.blur,this)).on("keypress",e.proxy(this.keypress,this)).on("keyup",e.proxy(this.keyup,this)),(e.browser.chrome||e.browser.webkit||e.browser.msie)&&this.$element.on("keydown",e.proxy(this.keydown,this)),this.$menu.on("click",e.proxy(this.click,this)).on("mouseenter","li",e.proxy(this.mouseenter,this))},move:function(e){if(!this.shown)return;switch(e.keyCode){case 9:case 13:case 27:e.preventDefault();break;case 38:e.preventDefault(),this.prev();break;case 40:e.preventDefault(),this.next()}e.stopPropagation()},keydown:function(t){this.suppressKeyPressRepeat=!~e.inArray(t.keyCode,[40,38,9,13,27]),this.move(t)},keypress:function(e){if(this.suppressKeyPressRepeat)return;this.move(e)},keyup:function(e){switch(e.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:if(!this.shown)return;this.hide();break;default:this.lookup()}e.stopPropagation(),e.preventDefault()},blur:function(e){var t=this;setTimeout(function(){t.hide()},150)},click:function(e){e.stopPropagation(),e.preventDefault(),this.select()},mouseenter:function(t){this.$menu.find(".active").removeClass("active"),e(t.currentTarget).addClass("active")}},e.fn.typeahead=function(n){return this.each(function(){var r=e(this),i=r.data("typeahead"),s=typeof n=="object"&&n;i||r.data("typeahead",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.typeahead.defaults={source:[],items:8,menu:'',item:'
  • ',minLength:1},e.fn.typeahead.Constructor=t,e(function(){e("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(t){var n=e(this);if(n.data("typeahead"))return;t.preventDefault(),n.typeahead(n.data())})})}(window.jQuery); +var Konami=function(t){var e={addEvent:function(t,e,n,i){t.addEventListener?t.addEventListener(e,n,!1):t.attachEvent&&(t["e"+e+n]=n,t[e+n]=function(){t["e"+e+n](window.event,i)},t.attachEvent("on"+e,t[e+n]))},input:"",pattern:"3838404037393739666513",load:function(t){this.addEvent(document,"keydown",function(n,i){return i&&(e=i),e.input+=n?n.keyCode:event.keyCode,e.input.length>e.pattern.length&&(e.input=e.input.substr(e.input.length-e.pattern.length)),e.input==e.pattern?(e.code(t),e.input="",void 0):void 0},this),this.iphone.load(t)},code:function(t){window.location=t},iphone:{start_x:0,start_y:0,stop_x:0,stop_y:0,tap:!1,capture:!1,orig_keys:"",keys:["UP","UP","DOWN","DOWN","LEFT","RIGHT","LEFT","RIGHT","TAP","TAP","TAP"],code:function(t){e.code(t)},load:function(t){this.orig_keys=this.keys,e.addEvent(document,"touchmove",function(t){if(1==t.touches.length&&e.iphone.capture===!0){var n=t.touches[0] +e.iphone.stop_x=n.pageX,e.iphone.stop_y=n.pageY,e.iphone.tap=!1,e.iphone.capture=!1,e.iphone.check_direction()}}),e.addEvent(document,"touchend",function(){e.iphone.tap===!0&&e.iphone.check_direction(t)},!1),e.addEvent(document,"touchstart",function(t){e.iphone.start_x=t.changedTouches[0].pageX,e.iphone.start_y=t.changedTouches[0].pageY,e.iphone.tap=!0,e.iphone.capture=!0})},check_direction:function(t){var e=Math.abs(this.start_x-this.stop_x),n=Math.abs(this.start_y-this.stop_y),i=0>this.start_x-this.stop_x?"RIGHT":"LEFT",o=0>this.start_y-this.stop_y?"DOWN":"UP",s=e>n?i:o +s=this.tap===!0?"TAP":s,s==this.keys[0]&&(this.keys=this.keys.slice(1,this.keys.length)),0==this.keys.length&&(this.keys=this.orig_keys,this.code(t))}}} +return"string"==typeof t&&e.load(t),"function"==typeof t&&(e.code=t,e.load()),e}; + +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '
      ', + items: 10, + updater: function(item) { + $('#pkgsearch-field').val(item); + $('#pkgsearch-form').submit(); + return item; + } + }).attr('autocomplete', 'off'); + $('#pkgsearch-field').keyup(function(e) { + if (e.keyCode === 13 && + $('ul.pkgsearch-typeahead li.active').size() === 0) { + $('#pkgsearch-form').submit(); + } + }); +} + +function setupKonami(image_src) { + var konami = new Konami(function() { + $('#konami').html(''); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} diff --git a/templates/public/index.html b/templates/public/index.html index 89486be8..d815363b 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -214,44 +214,8 @@

      More Resources

      {% load cdn %}{% jquery %} {% endblock %} -- cgit v1.2.3-54-g00ecf From fae6da4d69564f0172d14047b81c0d8a9acc45a5 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 23 Oct 2014 07:27:07 -0500 Subject: Bump to Django 1.7.1 Signed-off-by: Dan McGee --- requirements.txt | 2 +- requirements_prod.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 5d544e3c..4b111f06 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin -Django==1.7 +Django==1.7.1 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 diff --git a/requirements_prod.txt b/requirements_prod.txt index e3bc0ae2..4f52ce3e 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,5 +1,5 @@ -e git+git://github.com/fredj/cssmin.git@master#egg=cssmin -Django==1.7 +Django==1.7.1 IPy==0.81 Jinja2==2.7.3 Markdown==2.4.1 -- cgit v1.2.3-54-g00ecf From 651678be2b6208cbfb45e11f5f390d66cf3eb8a6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 24 Oct 2014 13:50:38 -0500 Subject: Reorganize sidebar links involving people Signed-off-by: Dan McGee --- templates/public/index.html | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/templates/public/index.html b/templates/public/index.html index d815363b..3b17803c 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -108,7 +108,6 @@

      Recent Updates (

      Documentation

      -
      • Wiki
      • @@ -119,7 +118,6 @@

        Documentation

      Community

      -

      Support

      -

      Tools

      -

      Development

      - -

      More Resources

      - +

      People

      + +

      More Resources

      + -
      -- cgit v1.2.3-54-g00ecf From 15bb0e7101aa9bfa3f63e8ef44f4a8e1e310e3c1 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 21:44:11 -0500 Subject: Remove Etag header from feeds We have Last-Modified here, and from what I can tell with some more reading and playing with caching, it isn't necessarily wise to set both of them in the same response. Set the one that we actually trust. Signed-off-by: Dan McGee --- feeds.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/feeds.py b/feeds.py index 0bbac270..cb01fbb1 100644 --- a/feeds.py +++ b/feeds.py @@ -1,5 +1,4 @@ from datetime import datetime, time -import hashlib from pytz import utc from django.contrib.sites.models import Site @@ -63,12 +62,6 @@ def write(self, outfile, encoding): wrapper.flush() -def package_etag(request, *args, **kwargs): - latest = package_last_modified(request) - if latest: - return hashlib.md5(str(kwargs) + str(latest)).hexdigest() - return None - def package_last_modified(request, *args, **kwargs): cursor = connection.cursor() cursor.execute("SELECT MAX(last_update) FROM packages") @@ -81,7 +74,7 @@ class PackageFeed(Feed): link = '/packages/' def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=package_etag, last_modified_func=package_last_modified) + wrapper = condition(last_modified_func=package_last_modified) return wrapper(super(PackageFeed, self).__call__)(request, *args, **kwargs) __name__ = 'package_feed' @@ -151,12 +144,6 @@ def item_categories(self, item): return (item.repo.name, item.arch.name) -def news_etag(request, *args, **kwargs): - latest = news_last_modified(request) - if latest: - return hashlib.md5(str(latest)).hexdigest() - return None - def news_last_modified(request, *args, **kwargs): cursor = connection.cursor() cursor.execute("SELECT MAX(last_modified) FROM news") @@ -172,7 +159,7 @@ class NewsFeed(Feed): subtitle = description def __call__(self, request, *args, **kwargs): - wrapper = condition(etag_func=news_etag, last_modified_func=news_last_modified) + wrapper = condition(last_modified_func=news_last_modified) return wrapper(super(NewsFeed, self).__call__)(request, *args, **kwargs) __name__ = 'news_feed' -- cgit v1.2.3-54-g00ecf From 8e990ca945f4fc5b27c0a81a484a107c83aa69d3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 21:56:24 -0500 Subject: Kill now unneeded workaround for Django issue #9800 Signed-off-by: Dan McGee --- feeds.py | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/feeds.py b/feeds.py index cb01fbb1..24611e7e 100644 --- a/feeds.py +++ b/feeds.py @@ -18,38 +18,20 @@ def __init__(self, outfile, chunks=20): self.outfile = outfile self.chunks = chunks self.buf = [] + def write(self, s): buf = self.buf buf.append(s) if len(buf) >= self.chunks: self.outfile.write(''.join(buf)) self.buf = [] + def flush(self): self.outfile.write(''.join(self.buf)) self.outfile.flush() -class GuidNotPermalinkFeed(Rss201rev2Feed): - @staticmethod - def check_for_unique_id(f): - def wrapper(name, contents=None, attrs=None): - if attrs is None: - attrs = {} - if name == 'guid': - attrs['isPermaLink'] = 'false' - return f(name, contents, attrs) - return wrapper - - def write_items(self, handler): - ''' - Totally disgusting. Monkey-patch the handler so if it sees a - 'unique-id' field come through, add an isPermalink="false" attribute. - Workaround for http://code.djangoproject.com/ticket/9800 - ''' - handler.addQuickElement = self.check_for_unique_id( - handler.addQuickElement) - super(GuidNotPermalinkFeed, self).write_items(handler) - +class FasterRssFeed(Rss201rev2Feed): def write(self, outfile, encoding): ''' Batch the underlying 'write' calls on the outfile because Python's @@ -58,7 +40,7 @@ def write(self, outfile, encoding): '>' closing tags and over 1600 write calls in our package feed. ''' wrapper = BatchWritesWrapper(outfile) - super(GuidNotPermalinkFeed, self).write(wrapper, encoding) + super(FasterRssFeed, self).write(wrapper, encoding) wrapper.flush() @@ -69,7 +51,7 @@ def package_last_modified(request, *args, **kwargs): class PackageFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed link = '/packages/' @@ -124,6 +106,8 @@ def description(self, obj): def items(self, obj): return obj['qs'] + item_guid_is_permalink = False + def item_guid(self, item): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.last_update @@ -151,7 +135,7 @@ def news_last_modified(request, *args, **kwargs): class NewsFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed title = 'Arch Linux: Recent news updates' link = '/news/' @@ -168,6 +152,8 @@ def items(self): return News.objects.select_related('author').order_by( '-postdate', '-id')[:10] + item_guid_is_permalink = False + def item_guid(self, item): return item.guid @@ -185,7 +171,7 @@ def item_description(self, item): class ReleaseFeed(Feed): - feed_type = GuidNotPermalinkFeed + feed_type = FasterRssFeed title = 'Arch Linux: Releases' link = '/download/' @@ -206,6 +192,8 @@ def item_description(self, item): def item_pubdate(self, item): return datetime.combine(item.release_date, time()).replace(tzinfo=utc) + item_guid_is_permalink = False + def item_guid(self, item): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.release_date -- cgit v1.2.3-54-g00ecf From 9c701ebba1f2ef403aab95354a8ae4efdb7df74c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 22:06:08 -0500 Subject: Double batch size in BatchWritesWrapper Signed-off-by: Dan McGee --- feeds.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/feeds.py b/feeds.py index 24611e7e..7247e95c 100644 --- a/feeds.py +++ b/feeds.py @@ -14,15 +14,14 @@ class BatchWritesWrapper(object): - def __init__(self, outfile, chunks=20): + def __init__(self, outfile): self.outfile = outfile - self.chunks = chunks self.buf = [] def write(self, s): buf = self.buf buf.append(s) - if len(buf) >= self.chunks: + if len(buf) >= 40: self.outfile.write(''.join(buf)) self.buf = [] -- cgit v1.2.3-54-g00ecf From bd2bc6a1c58723502ef6c2e9f49248908a161b13 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 26 Oct 2014 22:23:56 -0500 Subject: Add last modified date to releases Signed-off-by: Dan McGee --- feeds.py | 6 ++++++ releng/admin.py | 1 + releng/migrations/0002_release_last_modified.py | 22 ++++++++++++++++++++++ .../0003_release_populate_last_modified.py | 21 +++++++++++++++++++++ releng/models.py | 1 + 5 files changed, 51 insertions(+) create mode 100644 releng/migrations/0002_release_last_modified.py create mode 100644 releng/migrations/0003_release_populate_last_modified.py diff --git a/feeds.py b/feeds.py index 7247e95c..0f7fa5d7 100644 --- a/feeds.py +++ b/feeds.py @@ -159,6 +159,9 @@ def item_guid(self, item): def item_pubdate(self, item): return item.postdate + def item_updateddate(self, item): + return item.last_modified + def item_author_name(self, item): return item.author.get_full_name() @@ -191,6 +194,9 @@ def item_description(self, item): def item_pubdate(self, item): return datetime.combine(item.release_date, time()).replace(tzinfo=utc) + def item_updateddate(self, item): + return item.last_modified + item_guid_is_permalink = False def item_guid(self, item): diff --git a/releng/admin.py b/releng/admin.py index c7e6396e..9c93c4be 100644 --- a/releng/admin.py +++ b/releng/admin.py @@ -18,6 +18,7 @@ class ReleaseAdmin(admin.ModelAdmin): list_display = ('version', 'release_date', 'kernel_version', 'available', 'created') list_filter = ('available', 'release_date') + readonly_fields = ('created', 'last_modified') SIMPLE_MODELS = (Architecture, BootType, Bootloader, ClockChoice, Filesystem, diff --git a/releng/migrations/0002_release_last_modified.py b/releng/migrations/0002_release_last_modified.py new file mode 100644 index 00000000..58502452 --- /dev/null +++ b/releng/migrations/0002_release_last_modified.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='release', + name='last_modified', + field=models.DateTimeField(default=datetime.datetime(2001, 1, 1, tzinfo=utc), editable=False), + preserve_default=False, + ), + ] diff --git a/releng/migrations/0003_release_populate_last_modified.py b/releng/migrations/0003_release_populate_last_modified.py new file mode 100644 index 00000000..ec7b6fda --- /dev/null +++ b/releng/migrations/0003_release_populate_last_modified.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + +def forwards(apps, schema_editor): + Release = apps.get_model('releng', 'Release') + Release.objects.update(last_modified=models.F('created')) + +def backwards(apps, schema_editor): + pass + +class Migration(migrations.Migration): + + dependencies = [ + ('releng', '0002_release_last_modified'), + ] + + operations = [ + migrations.RunPython(forwards, backwards) + ] diff --git a/releng/models.py b/releng/models.py index c3ffd322..436308f2 100644 --- a/releng/models.py +++ b/releng/models.py @@ -120,6 +120,7 @@ class Release(models.Model): md5_sum = models.CharField('MD5 digest', max_length=32, blank=True) sha1_sum = models.CharField('SHA1 digest', max_length=40, blank=True) created = models.DateTimeField(editable=False) + last_modified = models.DateTimeField(editable=False) available = models.BooleanField(default=True) info = models.TextField('Public information', blank=True) torrent_data = models.TextField(blank=True, -- cgit v1.2.3-54-g00ecf From e7449f7063f3f56af118ed8ad703ec3fce6bc39a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 28 Oct 2014 14:14:00 -0500 Subject: Bump to django_countries bugfix release Signed-off-by: Dan McGee --- requirements.txt | 2 +- requirements_prod.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 4b111f06..e1acd2e9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 -django_countries==3.0 +django_countries==3.0.1 jsmin==2.0.11 pgpdump==1.5 pytz>=2014.7 diff --git a/requirements_prod.txt b/requirements_prod.txt index 4f52ce3e..ef535eb8 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -5,7 +5,7 @@ Jinja2==2.7.3 Markdown==2.4.1 bencode==1.0 django-jinja==1.0.4 -django_countries==3.0 +django_countries==3.0.1 jsmin==2.0.11 pgpdump==1.5 psycopg2==2.5.4 -- cgit v1.2.3-54-g00ecf From 02ffa37f8607634e5e4eccba7ef25d4f48b29b3b Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 13 Apr 2015 21:01:41 -0400 Subject: Catch an instance of "Arch Linux" in packages/details.html --- templates/packages/details.html.jinja | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/packages/details.html.jinja b/templates/packages/details.html.jinja index 21be80f5..3632ecf0 100644 --- a/templates/packages/details.html.jinja +++ b/templates/packages/details.html.jinja @@ -69,7 +69,7 @@ - + {% if pkg.packager %}
      {% endif %} -- cgit v1.2.3-54-g00ecf From 65e3ef63f7475a217da5205a788f52f3888ebea7 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Tue, 14 Apr 2015 02:17:54 -0400 Subject: Replace usage of parabolagnulinux.org with parabola.nu, also replace repo.parabola.nu/isos/ with /iso/, in settings.py --- common.mk | 2 +- main/templatetags/wiki.py | 4 ++-- packages/templatetags/jinja2.py | 4 ++-- public/views.py | 2 +- settings.py | 14 +++++++------- templates/packages/search.html | 2 +- templates/public/art.html | 2 +- templates/public/https.html | 2 +- templates/public/index.html | 4 ++-- urls.py | 6 +++--- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/common.mk b/common.mk index 35f0b3bb..92f26337 100644 --- a/common.mk +++ b/common.mk @@ -22,7 +22,7 @@ $(www)/https/%: touch '$@' $(branding)/%: - gitget checkout 'git://projects.parabolagnulinux.org/artwork.git#branch=master' '$(artwork)' + gitget checkout 'git://projects.parabola.nu/artwork.git#branch=master' '$(artwork)' make -C '$(branding)' .PHONY: PHONY diff --git a/main/templatetags/wiki.py b/main/templatetags/wiki.py index 4a3b2f83..e3ffb138 100644 --- a/main/templatetags/wiki.py +++ b/main/templatetags/wiki.py @@ -4,6 +4,6 @@ @register.simple_tag def wiki_url(article=""): if article == "": - return "https://wiki.parabolagnulinux.org/" + return "https://wiki.parabola.nu/" else: - return "https://wiki.parabolagnulinux.org/"+article.replace(' ', '_') + return "https://wiki.parabola.nu/"+article.replace(' ', '_') diff --git a/packages/templatetags/jinja2.py b/packages/templatetags/jinja2.py index c9d602a6..86bbd03e 100644 --- a/packages/templatetags/jinja2.py +++ b/packages/templatetags/jinja2.py @@ -33,13 +33,13 @@ def pgp_key_link(key_id, link_text=None): def scm_link(package, operation): parts = ("abslibre", operation, package.repo.name.lower(), package.pkgbase) linkbase = ( - "https://projects.parabolagnulinux.org/%s.git/%s/%s/%s") + "https://projects.parabola.nu/%s.git/%s/%s/%s") return linkbase % tuple(urlquote(part.encode('utf-8')) for part in parts) @library.global_function def wiki_link(package): - url = "https://wiki.parabolagnulinux.org/index.php" + url = "https://wiki.parabola.nu/index.php" data = { 'title': "Special:Search", 'search': package.pkgname, diff --git a/public/views.py b/public/views.py index 7414b330..1197322d 100644 --- a/public/views.py +++ b/public/views.py @@ -83,7 +83,7 @@ def _mirror_urls(): @cache_control(max_age=307) def download(request): - return HttpResponseRedirect('https://wiki.parabolagnulinux.org/get') + return HttpResponseRedirect('https://wiki.parabola.nu/get') @cache_control(max_age=307) def feeds(request): diff --git a/settings.py b/settings.py index dc93eb1e..d0738e7b 100644 --- a/settings.py +++ b/settings.py @@ -13,7 +13,7 @@ MANAGERS = ADMINS # Package out-of-date emails for orphans -NOTIFICATIONS = ['dev@lists.parabolagnulinux.org'] +NOTIFICATIONS = ['dev@lists.parabola.nu'] # Full path to the data directory DEPLOY_PATH = os.path.dirname(os.path.realpath(__file__)) @@ -161,17 +161,17 @@ PGP_SERVER = 'pgp.mit.edu:11371' # URL to fetch a current list of available ISOs -ISO_LIST_URL = 'https://repo.parabolagnulinux.org/isos/' +ISO_LIST_URL = 'https://repo.parabola.nu/iso/' # URL to the PXE netboot instructions -PXEBOOT_URL = 'http://repo.parabolagnulinux.org/pxeboot/' +PXEBOOT_URL = 'http://repo.parabola.nu/pxeboot/' # URL for SVN access for fetching commit messages (note absence of packages or # community bit on the end, repo.svn_root is appended) #SVN_BASE_URL = 'svn://svn.archlinux.org/' # URL for linking to mailing lists -MAILMAN_BASE_URL = 'https://lists.parabolagnulinux.org/' +MAILMAN_BASE_URL = 'https://lists.parabola.nu/' # URL for linking to the bugtracker BUGTRACKER_URL = 'https://labs.parabola.nu/' @@ -180,7 +180,7 @@ BUGTRACKER_RELENG_URL = 'https://labs.parabola.nu/projects/isos' # URL for linking to projects in git -PROJECTS_URL = 'https://projects.parabolagnulinux.org' +PROJECTS_URL = 'https://projects.parabola.nu' # Trackers used for ISO download magnet links TORRENT_TRACKERS = ( @@ -189,14 +189,14 @@ 'udp://tracker.istole.it:80', ) -DOMAIN_RE = r'^(.+\.)?parabolagnulinux.org$' +DOMAIN_RE = r'^(.+\.)?parabola(\.nu|gnulinux\.org)$' BRANDING_APPNAME = 'parabolaweb' BRANDING_DISTRONAME = 'Parabola GNU/Linux-libre' BRANDING_SHORTNAME = 'Parabola' BRANDING_SLUG = 'parabola' BRANDING_WIKINAME = 'ParabolaWiki' -BRANDING_EMAIL = 'Parabola Website Notification ' +BRANDING_EMAIL = 'Parabola Website Notification ' BRANDING_OSEARCH_TAGS = 'gnu linuxlibre parabola package software' ## Import local settings diff --git a/templates/packages/search.html b/templates/packages/search.html index 7509864e..41e36193 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -141,7 +141,7 @@

      Package Search

      You are browsing the {{ BRANDING_DISTRONAME }} package database. From here you can find detailed information about packages located in the official supported repositories. If you need the sourceball from where a package is built, you can look at our sources repo.

      {% endblock %} diff --git a/templates/public/art.html b/templates/public/art.html index 80c5ac95..32acc172 100644 --- a/templates/public/art.html +++ b/templates/public/art.html @@ -10,7 +10,7 @@

      {{ BRANDING_DISTRONAME }} Logos and Artwork

      You can help by creating artwork for {{ BRANDING_DISTRONAME }}.

      -

      Send your designs to dev@lists.parabolagnulinux.org and state they are CC-by-sa +

      Send your designs to dev@lists.parabola.nu and state they are CC-by-sa or another free culture friendly license.

      {% comment %} diff --git a/templates/public/https.html b/templates/public/https.html index df3e2c73..88056346 100644 --- a/templates/public/https.html +++ b/templates/public/https.html @@ -11,7 +11,7 @@

      This is the unsecure version of the website

      is the only page on the whole site that can be accessed without a secure connection, all other pages will redirect to the secure version.

      -

      Enter the secure site

      +

      Enter the secure site

      But my browser says the secure site is untrusted

      diff --git a/templates/public/index.html b/templates/public/index.html index 6ef6b4bf..64d19e6d 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -28,9 +28,9 @@

      A fully free, simple, and lightweight operating system

      Our community is friendly and helpful. Please hop on IRC channel and check out our - mailing + mailing lists to get your feet wet. Also glance through our - wiki if you want to learn + wiki if you want to learn more about Parabola.

      Date: Wed, 15 Apr 2015 00:37:35 -0400 Subject: Add a Makefile to generate all of the 3rd party or minimized Javascript. The goal here is to generate the files *exactly* as they are currently in the repository, which sometimes means using a specific version of a minifier or other weird things. --- Makefile | 100 ++++++++++++++++++++++ Makefile.d/bootstrap-typeahead.js.patch | 38 ++++++++ Makefile.d/homepage.js.in | 36 ++++++++ Makefile.d/jquery-1.8.3.min.js.preamble | 1 + Makefile.d/jquery.tablesorter-2.7.min.js.preamble | 4 + Makefile.d/konami.js.patch | 46 ++++++++++ 6 files changed, 225 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.d/bootstrap-typeahead.js.patch create mode 100644 Makefile.d/homepage.js.in create mode 100644 Makefile.d/jquery-1.8.3.min.js.preamble create mode 100644 Makefile.d/jquery.tablesorter-2.7.min.js.preamble create mode 100644 Makefile.d/konami.js.patch diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..6b633158 --- /dev/null +++ b/Makefile @@ -0,0 +1,100 @@ +# The idea here is to be able to re-generate the exact Javascript +# files as they exist in git. This means munging whitespace in weird +# ways, using specific versions of various JS minimizers... + +# Where are we? +topdir := $(dir $(lastword $(MAKEFILE_LIST))) +www = $(topdir)/../web-cache/www + +# Where are the Javascript minimizers? +# Any of the 1.3.x or 2.2.x will produce the same output for these +uglifyjs-1.3 = ~/Downloads/UglifyJS/bin/uglifyjs --no-copyright --ascii --max-line-len 0 +uglifyjs-2.2 = ~/Downloads/UglifyJS2/bin/uglifyjs --mangle --compress -- +closure-compiler = java -jar ~/Downloads/compiler-20121212/compiler.jar + +# What versions of 3rd party libraries are we using? +jquery-ver=1.8.3 +bootstrap-ver=2.1.1 +tablesorter-ver=2.7 +d3-ver=3.0.6 +konami-ver=c0f686e647765860ff4d2fcb7b48122785432b75 + +targets = \ + sitestatic/bootstrap-typeahead.js \ + sitestatic/homepage.js \ + sitestatic/jquery-$(jquery-ver).min.js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).js \ + sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js \ + sitestatic/konami.min.js \ + visualize/static/d3-$(d3-ver).js \ + visualize/static/d3-$(d3-ver).min.js + + +# The base rules + +all: $(targets) +.PHONY: all + +basenames = $(sort $(patsubst %.min,%,$(patsubst %.js,%,$(targets)))) +generated = $(addsuffix .js,$(basenames)) $(addsuffix .min.js,$(basenames)) +clean: + rm -f -- $(generated) +.PHONY: clean + +# Don't have non-minimized .js stick around unless we asked for them. +.INTERMEDIATE: $(filter-out $(targets),$(generated)) + +# Turn on sane error handling +.DELETE_ON_ERROR: + + +# How to download files + +$(www)/http/%: + mkdir -p '$(@D)' + wget 'http://$*' -O '$@' + touch '$@' + +$(www)/https/%: + mkdir -p '$(@D)' + wget 'https://$*' -O '$@' + touch '$@' + + +# Non-minimized .js files +sitestatic/bootstrap-typeahead.js: sitestatic/%: $(www)/https/raw.github.com/twitter/bootstrap/v$(bootstrap-ver)/js/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/jquery-$(jquery-ver).js: sitestatic/%: $(www)/http/code.jquery.com/% + cp $< $@ +sitestatic/jquery.tablesorter-$(tablesorter-ver).js: $(www)/https/raw.github.com/Mottie/tablesorter/v$(tablesorter-ver)/js/jquery.tablesorter.js + cp $< $@ +sitestatic/konami.js: sitestatic/%: $(www)/https/raw.github.com/snaptortoise/konami-js/$(konami-ver)/% Makefile.d/%.patch + cp $< $@ + patch -i Makefile.d/$*.patch $@ +sitestatic/homepage.js: sitestatic/bootstrap-typeahead.min.js sitestatic/konami.min.js Makefile.d/homepage.js.in + { \ + cat sitestatic/bootstrap-typeahead.min.js && \ + echo && \ + sed -e 's,^\s*,,' -e 's,^return.*,&;,' sitestatic/konami.min.js && \ + echo && \ + cat Makefile.d/homepage.js.in ; \ + } > $@ +visualize/static/d3-$(d3-ver).js: %: $(www)/https/raw.github.com/mbostock/d3/v$(d3-ver)/d3.js + cp $< $@ + + +# The crazy minimization processes + +sitestatic/bootstrap-typeahead.min.js: %.min.js: %.js + $(uglifyjs-1.3) $< > $@ +sitestatic/jquery-$(jquery-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble + { cat Makefile.d/$*.min.js.preamble && echo && $(uglifyjs-1.3) $<; } > $@ +sitestatic/jquery.tablesorter-$(tablesorter-ver).min.js: sitestatic/%.min.js: sitestatic/%.js Makefile.d/%.min.js.preamble + @# The tr/sed is to turn all of the newlines except for the last one into spaces + { cat Makefile.d/$*.min.js.preamble && echo && $(closure-compiler) $< | tr '\n' ' ' | sed 's, $$,\n,'; } > $@ +sitestatic/konami.min.js: %.min.js: %.js + @# The sed is to insert newlines and whitespace at the correct places; presumably to match Dan copy/pasting into an editor. + $(uglifyjs-2.2) $< | sed -r -e 's:e\.iphone\.stop_x|s=this\.tap===:\n\t&:g' -e 's,return"string",\n&,' | sed -e 's,;$$,,' -e '$$s,$$,\n,' > $@ +visualize/static/d3-$(d3-ver).min.js: %.min.js: %.js + $(uglifyjs-2.2) $< > $@ diff --git a/Makefile.d/bootstrap-typeahead.js.patch b/Makefile.d/bootstrap-typeahead.js.patch new file mode 100644 index 00000000..dfbab80b --- /dev/null +++ b/Makefile.d/bootstrap-typeahead.js.patch @@ -0,0 +1,38 @@ +commit f3e23371fa0473c82c28932e85570d94e5fc232a +Author: Dan McGee +Date: Mon Sep 24 20:21:15 2012 -0500 + + Don't auto-select the first item in typeahead + + This assumption was baked into the Twitter bootstrap JS; kill it so it + is still easy to do a freeform search if wanted. + + Signed-off-by: Dan McGee + +diff --git a/sitestatic/bootstrap-typeahead.js b/sitestatic/bootstrap-typeahead.js +index c2ccdea..3d355ae 100644 +--- a/sitestatic/bootstrap-typeahead.js ++++ b/sitestatic/bootstrap-typeahead.js +@@ -45,9 +45,11 @@ + + , select: function () { + var val = this.$menu.find('.active').attr('data-value') +- this.$element +- .val(this.updater(val)) +- .change() ++ if (val) { ++ this.$element ++ .val(this.updater(val)) ++ .change() ++ } + return this.hide() + } + +@@ -141,7 +143,6 @@ + return i[0] + }) + +- items.first().addClass('active') + this.$menu.html(items) + return this + } diff --git a/Makefile.d/homepage.js.in b/Makefile.d/homepage.js.in new file mode 100644 index 00000000..2d6f7910 --- /dev/null +++ b/Makefile.d/homepage.js.in @@ -0,0 +1,36 @@ +function setupTypeahead() { + $('#pkgsearch-field').typeahead({ + source: function(query, callback) { + $.getJSON('/opensearch/packages/suggest', {q: query}, function(data) { + callback(data[1]); + }); + }, + matcher: function(item) { return true; }, + sorter: function(items) { return items; }, + menu: '

        ', + items: 10, + updater: function(item) { + $('#pkgsearch-field').val(item); + $('#pkgsearch-form').submit(); + return item; + } + }).attr('autocomplete', 'off'); + $('#pkgsearch-field').keyup(function(e) { + if (e.keyCode === 13 && + $('ul.pkgsearch-typeahead li.active').size() === 0) { + $('#pkgsearch-form').submit(); + } + }); +} + +function setupKonami(image_src) { + var konami = new Konami(function() { + $('#konami').html(''); + setTimeout(function() { + $('#konami').fadeIn(500); + }, 500); + $('#konami').click(function() { + $('#konami').fadeOut(500); + }); + }); +} diff --git a/Makefile.d/jquery-1.8.3.min.js.preamble b/Makefile.d/jquery-1.8.3.min.js.preamble new file mode 100644 index 00000000..ca451d71 --- /dev/null +++ b/Makefile.d/jquery-1.8.3.min.js.preamble @@ -0,0 +1 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ \ No newline at end of file diff --git a/Makefile.d/jquery.tablesorter-2.7.min.js.preamble b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble new file mode 100644 index 00000000..e57e2d88 --- /dev/null +++ b/Makefile.d/jquery.tablesorter-2.7.min.js.preamble @@ -0,0 +1,4 @@ +/*! +* TableSorter 2.7 min - Client-side table sorting with ease! +* Copyright (c) 2007 Christian Bach +*/ \ No newline at end of file diff --git a/Makefile.d/konami.js.patch b/Makefile.d/konami.js.patch new file mode 100644 index 00000000..f6df91c4 --- /dev/null +++ b/Makefile.d/konami.js.patch @@ -0,0 +1,46 @@ +--- ..//web-cache/www/https/raw.github.com/snaptortoise/konami-js/c0f686e647765860ff4d2fcb7b48122785432b75/konami.js 2015-04-14 17:46:09.372597458 -0400 ++++ sitestatic/konami.js 2015-04-14 22:39:28.549281737 -0400 +@@ -56,7 +56,7 @@ + load: function(link){ + this.orig_keys = this.keys; + konami.addEvent(document,"touchmove",function(e){ +- if(e.touches.length == 1 && konami.iphone.capture==true){ ++ if(e.touches.length == 1 && konami.iphone.capture===true){ + var touch = e.touches[0]; + konami.iphone.stop_x = touch.pageX; + konami.iphone.stop_y = touch.pageY; +@@ -66,7 +66,7 @@ + } + }); + konami.addEvent(document,"touchend",function(evt){ +- if (konami.iphone.tap==true) konami.iphone.check_direction(link); ++ if (konami.iphone.tap===true) konami.iphone.check_direction(link); + },false); + konami.addEvent(document,"touchstart", function(evt){ + konami.iphone.start_x = evt.changedTouches[0].pageX +@@ -76,12 +76,12 @@ + }); + }, + check_direction: function(link){ +- x_magnitude = Math.abs(this.start_x-this.stop_x) +- y_magnitude = Math.abs(this.start_y-this.stop_y) +- x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; +- y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; +- result = (x_magnitude > y_magnitude) ? x : y; +- result = (this.tap==true) ? "TAP" : result; ++ var x_magnitude = Math.abs(this.start_x-this.stop_x) ++ var y_magnitude = Math.abs(this.start_y-this.stop_y) ++ var x = ((this.start_x-this.stop_x) < 0) ? "RIGHT" : "LEFT"; ++ var y = ((this.start_y-this.stop_y) < 0) ? "DOWN" : "UP"; ++ var result = (x_magnitude > y_magnitude) ? x : y; ++ result = (this.tap===true) ? "TAP" : result; + + if (result==this.keys[0]) this.keys = this.keys.slice(1,this.keys.length) + if (this.keys.length==0) { +@@ -99,4 +99,4 @@ + } + + return konami; +-} +\ No newline at end of file ++} -- cgit v1.2.3-54-g00ecf
        Architecture:Last Updated: {{ pkg.last_update|date("DATETIME_FORMAT") }} UTC
        Last Flag Request: From {{ flag_request.who() }} on {{ flag_request.created|date }}:
        {{ flag_request.message|linebreaksbr|default("{no message}") }}