From 7896779ff18b304f8246c24123b8cbf9b82ec5b0 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 17:46:10 -0500 Subject: Bump requirements to Django 1.4 and add new manage.py The default manage.py script has been updated in Django 1.4, and the old version and functions it calls is deprecated. Signed-off-by: Dan McGee --- manage.py | 16 ++++++---------- requirements.txt | 6 +++--- requirements_prod.txt | 6 +++--- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/manage.py b/manage.py index 317dd156..debb55e5 100755 --- a/manage.py +++ b/manage.py @@ -1,16 +1,12 @@ #!/usr/bin/env python2 +import os +import sys -from django.core.management import execute_manager +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__) - sys.exit(1) + from django.core.management import execute_from_command_line -if __name__ == "__main__": - execute_manager(settings) + execute_from_command_line(sys.argv) # vim: set ts=4 sw=4 et: - diff --git a/requirements.txt b/requirements.txt index 83355a9e..1c1578cb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -Django==1.3.1 +Django==1.4 Markdown==2.1.1 -South==0.7.3 +South==0.7.4 pgpdump==1.1 -pytz>=2011n +pytz>=2012b diff --git a/requirements_prod.txt b/requirements_prod.txt index ebac73ca..7f7663a8 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,8 +1,8 @@ -Django==1.3.1 +Django==1.4 Markdown==2.1.1 MySQL-python==1.2.3 -South==0.7.3 +South==0.7.4 pgpdump==1.1 pyinotify==0.9.3 python-memcached==1.48 -pytz>=2011n +pytz>=2012b -- cgit v1.2.3-54-g00ecf From 6218ccc570c674bfaaf1c636382ac6f9adbf212b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 17:48:43 -0500 Subject: Use python hashlib directly Django hashcompat is now deprecated. Signed-off-by: Dan McGee --- feeds.py | 6 +++--- main/utils.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/feeds.py b/feeds.py index 74ae9ff9..ee856f62 100644 --- a/feeds.py +++ b/feeds.py @@ -1,10 +1,10 @@ +import hashlib import pytz from django.contrib.sites.models import Site from django.contrib.syndication.views import Feed from django.db.models import Q from django.utils.feedgenerator import Rss201rev2Feed -from django.utils.hashcompat import md5_constructor from django.views.decorators.http import condition from main.utils import retrieve_latest @@ -32,7 +32,7 @@ def write_items(self, handler): def package_etag(request, *args, **kwargs): latest = retrieve_latest(Package) if latest: - return md5_constructor(str(kwargs) + str(latest)).hexdigest() + return hashlib.md5(str(kwargs) + str(latest)).hexdigest() return None def package_last_modified(request, *args, **kwargs): @@ -108,7 +108,7 @@ def item_categories(self, item): def news_etag(request, *args, **kwargs): latest = retrieve_latest(News) if latest: - return md5_constructor(str(latest)).hexdigest() + return hashlib.md5(str(latest)).hexdigest() return None def news_last_modified(request, *args, **kwargs): diff --git a/main/utils.py b/main/utils.py index 81f689e7..03441c15 100644 --- a/main/utils.py +++ b/main/utils.py @@ -4,9 +4,9 @@ import pickle from datetime import datetime +import hashlib from django.core.cache import cache -from django.utils.hashcompat import md5_constructor CACHE_TIMEOUT = 1800 INVALIDATE_TIMEOUT = 10 @@ -15,7 +15,7 @@ def cache_function_key(func, args, kwargs): raw = [func.__name__, func.__module__, args, kwargs] pickled = pickle.dumps(raw, protocol=pickle.HIGHEST_PROTOCOL) - key = md5_constructor(pickled).hexdigest() + key = hashlib.md5(pickled).hexdigest() return 'cache_function.' + func.__name__ + '.' + key def cache_function(length): -- cgit v1.2.3-54-g00ecf From 5575b68272f1bc773f98ecdfd679e58e8be2ac9b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 17:59:54 -0500 Subject: reporead: use Django 1.4 select_for_update() As per TODO comments in the existing code. Signed-off-by: Dan McGee --- devel/management/commands/reporead.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index 8369b6ec..ebf17111 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -286,17 +286,6 @@ def populate_files(dbpkg, repopkg, force=False): dbpkg.save() -def select_pkg_for_update(dbpkg): - database = router.db_for_write(Package, instance=dbpkg) - connection = connections[database] - if 'sqlite' in connection.settings_dict['ENGINE'].lower(): - return dbpkg - new_pkg = Package.objects.raw( - 'SELECT * FROM packages WHERE id = %s FOR UPDATE', - [dbpkg.id]) - return list(new_pkg)[0] - - def update_common(archname, reponame, pkgs, sanity_check=True): # If isolation level is repeatable-read, we need to ensure each package # update starts a new transaction and re-queries the database as @@ -396,8 +385,7 @@ def db_update(archname, reponame, pkgs, force=False): # simultaneous updates don't happen on a package, causing # files/depends/all related items to be double-imported. with transaction.commit_on_success(): - # TODO Django 1.4 select_for_update() will work once released - dbpkg = select_pkg_for_update(dbpkg) + dbpkg = Package.objects.select_for_update().get(id=dbpkg.id) if not force and pkg_same_version(pkg, dbpkg): logger.debug("Package %s was already updated", pkg.name) continue @@ -428,8 +416,7 @@ def filesonly_update(archname, reponame, pkgs, force=False): elif not force and dbpkg.files_last_update > dbpkg.last_update: logger.debug("Files for %s are up to date", pkg.name) continue - # TODO Django 1.4 select_for_update() will work once released - dbpkg = select_pkg_for_update(dbpkg) + dbpkg = Package.objects.select_for_update().get(id=dbpkg.id) logger.debug("Checking files for package %s", pkg.name) populate_files(dbpkg, pkg, force=force) -- cgit v1.2.3-54-g00ecf From 95520ae26485e5c62ea1431ca82a7b42d01b923a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 18:03:28 -0500 Subject: reporead: use Django 1.4 bulk_create() for package files Signed-off-by: Dan McGee --- devel/management/commands/reporead.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index ebf17111..a8c58ba7 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -270,18 +270,17 @@ def populate_files(dbpkg, repopkg, force=False): delete_pkg_files(dbpkg) logger.info("adding %d files for package %s", len(repopkg.files), dbpkg.pkgname) + pkg_files = [] for f in repopkg.files: dirname, filename = f.rsplit('/', 1) if filename == '': filename = None - # this is basically like calling dbpkg.packagefile_set.create(), - # but much faster as we can skip a lot of the repeated code paths - # TODO use Django 1.4 bulk_create pkgfile = PackageFile(pkg=dbpkg, is_directory=(filename is None), directory=dirname + '/', filename=filename) - pkgfile.save(force_insert=True) + pkg_files.append(pkgfile) + PackageFile.objects.bulk_create(pkg_files) dbpkg.files_last_update = datetime.utcnow() dbpkg.save() -- cgit v1.2.3-54-g00ecf From 0545e3e0ec864eaed4facc94158e3ed9da1dfb2b Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 18:23:17 -0500 Subject: Django 1.4 admin and admin media changes Signed-off-by: Dan McGee --- templates/admin/index.html | 10 +++++----- templates/devel/admin_log.html | 4 ++-- templates/packages/search.html | 12 ++++++++---- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/templates/admin/index.html b/templates/admin/index.html index 1755d86f..203206d5 100644 --- a/templates/admin/index.html +++ b/templates/admin/index.html @@ -1,7 +1,7 @@ {% extends "admin/base_site.html" %} -{% load i18n %} +{% load i18n admin_static %} -{% block extrastyle %}{{ block.super }}{% endblock %} +{% block extrastyle %}{{ block.super }}{% endblock %} {% block coltype %}colMS{% endblock %} @@ -36,19 +36,19 @@ {% blocktrans with name=app.name %}{{ name }}{% endblocktrans %} {% for model in app.models %} - {% if model.perms.change %} + {% if model.admin_url %} {{ model.name }} {% else %} {{ model.name }} {% endif %} - {% if model.perms.add %} + {% if model.add_url %} {% trans 'Add' %} {% else %}   {% endif %} - {% if model.perms.change %} + {% if model.admin_url %} {% trans 'Change' %} {% else %}   diff --git a/templates/devel/admin_log.html b/templates/devel/admin_log.html index 0f22ba2b..1629c104 100644 --- a/templates/devel/admin_log.html +++ b/templates/devel/admin_log.html @@ -1,7 +1,7 @@ {% extends "admin/base_site.html" %} -{% load i18n %} +{% load i18n admin_static %} -{% block extrastyle %}{{ block.super }}{% endblock %} +{% block extrastyle %}{{ block.super }}{% endblock %} {% block breadcrumbs %}{% endblock %} diff --git a/templates/packages/search.html b/templates/packages/search.html index ae67b184..030f2671 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -1,13 +1,13 @@ {% extends "base.html" %} {% load package_extras %} -{% load adminmedia %} +{% load admin_static %} {% block title %}Arch Linux - Package Database{% endblock %} {% block navbarclass %}anb-packages{% endblock %} {% block head %} {% if is_paginated and page_obj.number > 1 %}{% endif %} - + {% endblock %} {% block content %} @@ -126,8 +126,12 @@

Package Search

title="AUR package database">Arch User Repository (AUR).

+{% load cdn %}{% jquery %} - - + + {{search_form.media}} {% endblock %} -- cgit v1.2.3-54-g00ecf From b8c20439c091aaa56e772441e6c3a7e57e8ef2d4 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 18:29:42 -0500 Subject: Change Django urls.py import Until Django 1.3, the functions include(), patterns() and url() plus handler404, handler500 were located in a django.conf.urls.defaults module. In Django 1.4, they live in django.conf.urls. Signed-off-by: Dan McGee --- devel/urls.py | 2 +- mirrors/urls.py | 2 +- mirrors/urls_mirrorlist.py | 2 +- news/urls.py | 2 +- packages/urls.py | 2 +- packages/urls_groups.py | 2 +- releng/urls.py | 2 +- todolists/urls.py | 2 +- urls.py | 2 +- visualize/urls.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/devel/urls.py b/devel/urls.py index 07cb321b..31afc86b 100644 --- a/devel/urls.py +++ b/devel/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('devel.views', (r'^admin_log/$','admin_log'), diff --git a/mirrors/urls.py b/mirrors/urls.py index fed9c807..f002e9d6 100644 --- a/mirrors/urls.py +++ b/mirrors/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('mirrors.views', (r'^$', 'mirrors', {}, 'mirror-list'), diff --git a/mirrors/urls_mirrorlist.py b/mirrors/urls_mirrorlist.py index 70bc18d2..e0f44c78 100644 --- a/mirrors/urls_mirrorlist.py +++ b/mirrors/urls_mirrorlist.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('mirrors.views', (r'^$', 'generate_mirrorlist', {}, 'mirrorlist'), diff --git a/news/urls.py b/news/urls.py index d938ef58..10020f31 100644 --- a/news/urls.py +++ b/news/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('news.views', (r'^$', 'news_list', {}, 'news-list'), diff --git a/packages/urls.py b/packages/urls.py index 52b09d2c..7e12a239 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import include, patterns +from django.conf.urls import include, patterns package_patterns = patterns('packages.views', (r'^$', 'details'), diff --git a/packages/urls_groups.py b/packages/urls_groups.py index d609944b..49ced145 100644 --- a/packages/urls_groups.py +++ b/packages/urls_groups.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('packages.views', (r'^$', 'groups', {}, 'groups-list'), diff --git a/releng/urls.py b/releng/urls.py index 239ad02b..8d1b8f24 100644 --- a/releng/urls.py +++ b/releng/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import include, patterns +from django.conf.urls import include, patterns feedback_patterns = patterns('releng.views', (r'^$', 'test_results_overview', {}, 'releng-test-overview'), diff --git a/todolists/urls.py b/todolists/urls.py index 0bd8817b..a379468f 100644 --- a/todolists/urls.py +++ b/todolists/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns from django.contrib.auth.decorators import permission_required from .views import DeleteTodolist diff --git a/urls.py b/urls.py index a061f030..9b9b4559 100644 --- a/urls.py +++ b/urls.py @@ -1,7 +1,7 @@ import os.path # Stupid Django. Don't remove these "unused" handler imports -from django.conf.urls.defaults import handler500, handler404, include, patterns +from django.conf.urls import handler500, handler404, include, patterns from django.conf import settings from django.contrib import admin diff --git a/visualize/urls.py b/visualize/urls.py index 02d83bec..907f6a22 100644 --- a/visualize/urls.py +++ b/visualize/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls.defaults import patterns +from django.conf.urls import patterns urlpatterns = patterns('visualize.views', (r'^$', 'index', {}, 'visualize-index'), -- cgit v1.2.3-54-g00ecf From bc1ba4e95a3e572779eb8ba8a947e8d3ce165845 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 18:45:01 -0500 Subject: PEP8 cleanup with blank lines Signed-off-by: Dan McGee --- main/utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/main/utils.py b/main/utils.py index 03441c15..8143ea6a 100644 --- a/main/utils.py +++ b/main/utils.py @@ -8,16 +8,19 @@ from django.core.cache import cache + 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) key = hashlib.md5(pickled).hexdigest() return 'cache_function.' + func.__name__ + '.' + key + def cache_function(length): """ A variant of the snippet posted by Jeff Wheeler at @@ -43,6 +46,7 @@ def inner_func(*args, **kwargs): return inner_func return decorator + def clear_cache_function(func, args, kwargs): key = cache_function_key(func, args, kwargs) cache.delete(key) @@ -50,6 +54,7 @@ def clear_cache_function(func, args, kwargs): # utility to make a pair of django choices 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. @@ -65,6 +70,7 @@ def refresh_latest(**kwargs): # will be valid again. See "Scaling Django" by Mike Malone, slide 30. cache.set(cache_key, None, INVALIDATE_TIMEOUT) + def retrieve_latest(sender): # we could break this down based on the request url, but it would probably # cost us more in query time to do so. @@ -84,6 +90,7 @@ def retrieve_latest(sender): pass return None + def set_created_field(sender, **kwargs): '''This will set the 'created' field on any object to datetime.utcnow() if it is unset. For use as a pre_save signal handler.''' @@ -91,6 +98,7 @@ def set_created_field(sender, **kwargs): if hasattr(obj, 'created') and not obj.created: obj.created = datetime.utcnow() + def groupby_preserve_order(iterable, keyfunc): '''Take an iterable and regroup using keyfunc to determine whether items belong to the same group. The order of the iterable is preserved and @@ -112,6 +120,7 @@ def groupby_preserve_order(iterable, keyfunc): return result + class PackageStandin(object): '''Resembles a Package object, and has a few of the same fields, but is really a link to a pkgbase that has no package with matching pkgname.''' -- cgit v1.2.3-54-g00ecf From 90e08b4863dfaecafee5b151478bda4513b12e85 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 19:29:40 -0500 Subject: Make all datetime objects fully timezone aware This is most of the transition to Django 1.4 `USE_TZ = True`. We need to ensure we don't mix aware and non-aware datetime objects when dealing with datetimes in the code. Add a utc_now() helper method that we can use most places, and ensure there is always a timezone attached when necessary. Signed-off-by: Dan McGee --- devel/management/commands/reporead.py | 12 +++++--- devel/views.py | 33 +++++++++------------- ...mpressed_size__chg_field_package_installed_s.py | 5 +++- .../0054_auto__add_field_donor_created.py | 5 +++- main/models.py | 4 +-- main/utils.py | 12 ++++++-- mirrors/management/commands/mirrorcheck.py | 5 +++- mirrors/utils.py | 13 +++++---- news/models.py | 7 +++-- packages/management/commands/signoff_report.py | 5 ++-- ...0007_auto__add_field_packagerelation_created.py | 5 +++- packages/views/flag.py | 5 ++-- packages/views/signoff.py | 4 +-- releng/management/commands/syncisos.py | 5 ++-- settings.py | 10 +++++-- sitemaps.py | 3 +- templates/devel/clock.html | 4 +-- 17 files changed, 80 insertions(+), 57 deletions(-) diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index a8c58ba7..60ee6ec0 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -22,6 +22,7 @@ import logging from datetime import datetime from optparse import make_option +from pytz import utc from django.core.management.base import BaseCommand, CommandError from django.db import connections, router, transaction @@ -29,8 +30,10 @@ from devel.utils import UserFinder from main.models import Arch, Package, PackageDepend, PackageFile, Repo +from main.utils import utc_now from packages.models import Conflict, Provision, Replacement + logging.basicConfig( level=logging.WARNING, format='%(asctime)s -> %(levelname)s: %(message)s', @@ -113,7 +116,8 @@ def populate(self, values): self.epoch = int(match.group(2)) elif k == 'builddate': try: - self.builddate = datetime.utcfromtimestamp(int(v[0])) + builddate = datetime.utcfromtimestamp(int(v[0])) + self.builddate = builddate.replace(tzinfo=utc) except ValueError: try: self.builddate = datetime.strptime(v[0], @@ -281,7 +285,7 @@ def populate_files(dbpkg, repopkg, force=False): filename=filename) pkg_files.append(pkgfile) PackageFile.objects.bulk_create(pkg_files) - dbpkg.files_last_update = datetime.utcnow() + dbpkg.files_last_update = utc_now() dbpkg.save() @@ -351,7 +355,7 @@ def db_update(archname, reponame, pkgs, force=False): dbpkg = Package(pkgname=pkg.name, arch=architecture, repo=repository) try: with transaction.commit_on_success(): - populate_pkg(dbpkg, pkg, timestamp=datetime.utcnow()) + populate_pkg(dbpkg, pkg, timestamp=utc_now()) except IntegrityError: logger.warning("Could not add package %s; " "not fatal if another thread beat us to it.", @@ -378,7 +382,7 @@ def db_update(archname, reponame, pkgs, force=False): if not force and pkg_same_version(pkg, dbpkg): continue elif not force: - timestamp = datetime.utcnow() + timestamp = utc_now() # The odd select_for_update song and dance here are to ensure # simultaneous updates don't happen on a package, causing diff --git a/devel/views.py b/devel/views.py index 328d52e4..3a9be757 100644 --- a/devel/views.py +++ b/devel/views.py @@ -1,3 +1,10 @@ +from datetime import datetime, timedelta +import operator +import pytz +import random +from string import ascii_letters, digits +import time + from django import forms from django.http import HttpResponseRedirect from django.contrib.auth.decorators import \ @@ -16,19 +23,13 @@ from django.utils.http import http_date from main.models import Package, PackageDepend, PackageFile, TodolistPkg -from main.models import Arch, Repo -from main.models import UserProfile +from main.models import Arch, Repo, UserProfile +from main.utils import utc_now from packages.models import PackageRelation from packages.utils import get_signoff_groups from todolists.utils import get_annotated_todolists from .utils import get_annotated_maintainers -from datetime import datetime, timedelta -import operator -import pytz -import random -from string import ascii_letters, digits -import time @login_required def index(request): @@ -85,22 +86,14 @@ def clock(request): devs = User.objects.filter(is_active=True).order_by( 'first_name', 'last_name').select_related('userprofile') - now = datetime.now() - utc_now = datetime.utcnow().replace(tzinfo=pytz.utc) - # now annotate each dev object with their current time - for dev in devs: - tz = pytz.timezone(dev.userprofile.time_zone) - dev.current_time = utc_now.astimezone(tz) - + now = utc_now() page_dict = { 'developers': devs, - 'now': now, - 'utc_now': utc_now, + 'utc_now': now, } response = direct_to_template(request, 'devel/clock.html', page_dict) if not response.has_header('Expires'): - # why this works only with the non-UTC date I have no idea... expire_time = now.replace(second=0, microsecond=0) expire_time += timedelta(minutes=1) expire_time = time.mktime(expire_time.timetuple()) @@ -168,12 +161,12 @@ def report(request, report_name, username=None): if report_name == 'old': title = 'Packages last built more than two years ago' - cutoff = datetime.utcnow() - timedelta(days=365 * 2) + cutoff = utc_now() - timedelta(days=365 * 2) packages = packages.filter( build_date__lt=cutoff).order_by('build_date') elif report_name == 'long-out-of-date': title = 'Packages marked out-of-date more than 90 days ago' - cutoff = datetime.utcnow() - timedelta(days=90) + cutoff = utc_now() - timedelta(days=90) packages = packages.filter( flag_date__lt=cutoff).order_by('flag_date') elif report_name == 'big': diff --git a/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py b/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py index 7aa09596..8368ae2e 100644 --- a/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py +++ b/main/migrations/0050_auto__chg_field_package_compressed_size__chg_field_package_installed_s.py @@ -1,5 +1,6 @@ # encoding: utf-8 import datetime +from pytz import utc from south.db import db from south.v2 import SchemaMigration from django.db import models @@ -9,7 +10,9 @@ class Migration(SchemaMigration): def forwards(self, orm): db.alter_column('packages', 'compressed_size', self.gf('main.models.PositiveBigIntegerField')(default=0)) db.alter_column('packages', 'installed_size', self.gf('main.models.PositiveBigIntegerField')(default=0)) - db.alter_column('packages', 'last_update', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime(2000, 1, 1))) + old_date = datetime.datetime(2000, 1, 1) + old_date = old_date.replace(tzinfo=utc) + db.alter_column('packages', 'last_update', self.gf('django.db.models.fields.DateTimeField')(default=old_date)) def backwards(self, orm): db.alter_column('packages', 'compressed_size', self.gf('django.db.models.fields.BigIntegerField')(null=True)) diff --git a/main/migrations/0054_auto__add_field_donor_created.py b/main/migrations/0054_auto__add_field_donor_created.py index f4d5b157..c96c0f5d 100644 --- a/main/migrations/0054_auto__add_field_donor_created.py +++ b/main/migrations/0054_auto__add_field_donor_created.py @@ -1,5 +1,6 @@ # encoding: utf-8 import datetime +from pytz import utc from south.db import db from south.v2 import SchemaMigration from django.db import models @@ -8,7 +9,9 @@ class Migration(SchemaMigration): def forwards(self, orm): # Adding field 'Donor.created' - db.add_column('donors', 'created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.date(2000, 1, 1)), keep_default=False) + old_date = datetime.datetime(2000, 1, 1) + old_date = old_date.replace(tzinfo=utc) + db.add_column('donors', 'created', self.gf('django.db.models.fields.DateTimeField')(default=old_date), keep_default=False) def backwards(self, orm): diff --git a/main/models.py b/main/models.py index 4f2d64ea..7d017242 100644 --- a/main/models.py +++ b/main/models.py @@ -9,7 +9,7 @@ from django.contrib.sites.models import Site from .fields import PositiveBigIntegerField, PGPKeyField -from .utils import cache_function, make_choice, set_created_field +from .utils import cache_function, make_choice, set_created_field, utc_now class UserProfile(models.Model): @@ -515,7 +515,7 @@ class Meta: def set_todolist_fields(sender, **kwargs): todolist = kwargs['instance'] if not todolist.date_added: - todolist.date_added = datetime.utcnow() + todolist.date_added = utc_now() # connect signals needed to keep cache in line with reality from main.utils import refresh_latest diff --git a/main/utils.py b/main/utils.py index 8143ea6a..e7e47c53 100644 --- a/main/utils.py +++ b/main/utils.py @@ -5,6 +5,7 @@ from datetime import datetime import hashlib +from pytz import utc from django.core.cache import cache @@ -91,12 +92,17 @@ def retrieve_latest(sender): return None +def utc_now(): + '''Returns a timezone-aware UTC date representing now.''' + return datetime.utcnow().replace(tzinfo=utc) + + def set_created_field(sender, **kwargs): - '''This will set the 'created' field on any object to datetime.utcnow() if - it is unset. For use as a pre_save signal handler.''' + '''This will set the 'created' field on any object to the current UTC time + if it is unset. For use as a pre_save signal handler.''' obj = kwargs['instance'] if hasattr(obj, 'created') and not obj.created: - obj.created = datetime.utcnow() + obj.created = utc_now() def groupby_preserve_order(iterable, keyfunc): diff --git a/mirrors/management/commands/mirrorcheck.py b/mirrors/management/commands/mirrorcheck.py index 8eb8b010..c2928e67 100644 --- a/mirrors/management/commands/mirrorcheck.py +++ b/mirrors/management/commands/mirrorcheck.py @@ -21,9 +21,11 @@ import time from threading import Thread import types +from pytz import utc from Queue import Queue, Empty import urllib2 +from main.utils import utc_now from mirrors.models import MirrorUrl, MirrorLog logging.basicConfig( @@ -50,7 +52,7 @@ def handle_noargs(self, **options): def check_mirror_url(mirror_url): url = mirror_url.url + 'lastsync' logger.info("checking URL %s", url) - log = MirrorLog(url=mirror_url, check_time=datetime.utcnow()) + log = MirrorLog(url=mirror_url, check_time=utc_now()) try: start = time.time() result = urllib2.urlopen(url, timeout=10) @@ -61,6 +63,7 @@ def check_mirror_url(mirror_url): parsed_time = None try: parsed_time = datetime.utcfromtimestamp(int(data)) + parsed_time = parsed_time.replace(tzinfo=utc) except ValueError: # it is bad news to try logging the lastsync value; # sometimes we get a crazy-encoded web page. diff --git a/mirrors/utils.py b/mirrors/utils.py index f05ffc77..0f8fef84 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -1,11 +1,12 @@ +from datetime import timedelta + from django.db.models import Avg, Count, Max, Min, StdDev -from main.utils import cache_function +from main.utils import cache_function, utc_now from .models import MirrorLog, MirrorProtocol, MirrorUrl -import datetime -default_cutoff = datetime.timedelta(hours=24) +default_cutoff = timedelta(hours=24) def annotate_url(url, delays): '''Given a MirrorURL object, add a few more attributes to it regarding @@ -13,7 +14,7 @@ def annotate_url(url, delays): url.completion_pct = float(url.success_count) / url.check_count if url.id in delays: url_delays = delays[url.id] - url.delay = sum(url_delays, datetime.timedelta()) / len(url_delays) + url.delay = sum(url_delays, timedelta()) / len(url_delays) hours = url.delay.days * 24.0 + url.delay.seconds / 3600.0 if url.completion_pct > 0: @@ -28,7 +29,7 @@ def annotate_url(url, delays): @cache_function(123) def get_mirror_statuses(cutoff=default_cutoff): - cutoff_time = datetime.datetime.utcnow() - cutoff + cutoff_time = utc_now() - cutoff protocols = list(MirrorProtocol.objects.filter(is_download=True)) # I swear, this actually has decent performance... urls = MirrorUrl.objects.select_related('mirror', 'protocol').filter( @@ -82,7 +83,7 @@ def get_mirror_statuses(cutoff=default_cutoff): @cache_function(117) def get_mirror_errors(cutoff=default_cutoff): - cutoff_time = datetime.datetime.utcnow() - cutoff + cutoff_time = utc_now() - cutoff errors = MirrorLog.objects.filter( is_success=False, check_time__gte=cutoff_time, url__mirror__active=True, url__mirror__public=True).values( diff --git a/news/models.py b/news/models.py index 33d958e0..95026e1d 100644 --- a/news/models.py +++ b/news/models.py @@ -1,9 +1,10 @@ -from datetime import datetime - from django.db import models from django.contrib.auth.models import User from django.contrib.sites.models import Site +from main.utils import utc_now + + class News(models.Model): slug = models.SlugField(max_length=255, unique=True) author = models.ForeignKey(User, related_name='news_author', @@ -28,7 +29,7 @@ class Meta: def set_news_fields(sender, **kwargs): news = kwargs['instance'] - now = datetime.utcnow() + now = utc_now() news.last_modified = now if not news.postdate: news.postdate = now diff --git a/packages/management/commands/signoff_report.py b/packages/management/commands/signoff_report.py index 3b67f518..ddf930db 100644 --- a/packages/management/commands/signoff_report.py +++ b/packages/management/commands/signoff_report.py @@ -17,12 +17,13 @@ from django.template import loader, Context from collections import namedtuple -from datetime import datetime, timedelta +from datetime import timedelta import logging from operator import attrgetter import sys from main.models import Repo +from main.utils import utc_now from packages.models import Signoff from packages.utils import get_signoff_groups @@ -65,7 +66,7 @@ def generate_report(email, repo_name): new_hours = 24 old_days = 14 - now = datetime.utcnow() + now = utc_now() new_cutoff = now - timedelta(hours=new_hours) old_cutoff = now - timedelta(days=old_days) diff --git a/packages/migrations/0007_auto__add_field_packagerelation_created.py b/packages/migrations/0007_auto__add_field_packagerelation_created.py index 37321fdb..b030909e 100644 --- a/packages/migrations/0007_auto__add_field_packagerelation_created.py +++ b/packages/migrations/0007_auto__add_field_packagerelation_created.py @@ -1,5 +1,6 @@ # encoding: utf-8 import datetime +from pytz import utc from south.db import db from south.v2 import SchemaMigration from django.db import models @@ -7,7 +8,9 @@ class Migration(SchemaMigration): def forwards(self, orm): - db.add_column('packages_packagerelation', 'created', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.utcnow()), keep_default=False) + old_date = datetime.datetime(2000, 1, 1) + old_date = old_date.replace(tzinfo=utc) + db.add_column('packages_packagerelation', 'created', self.gf('django.db.models.fields.DateTimeField')(default=old_date), keep_default=False) def backwards(self, orm): db.delete_column('packages_packagerelation', 'created') diff --git a/packages/views/flag.py b/packages/views/flag.py index c0990e8e..0d2f9009 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -1,5 +1,3 @@ -from datetime import datetime - from django import forms from django.conf import settings from django.contrib.auth.decorators import permission_required @@ -12,6 +10,7 @@ from ..models import FlagRequest from main.models import Package +from main.utils import utc_now def flaghelp(request): @@ -61,7 +60,7 @@ def flag(request, name, repo, arch): @transaction.commit_on_success def perform_updates(): - now = datetime.utcnow() + now = utc_now() pkgs.update(flag_date=now) # store our flag request flag_request = FlagRequest(created=now, diff --git a/packages/views/signoff.py b/packages/views/signoff.py index e3daf0dd..cf00b0b9 100644 --- a/packages/views/signoff.py +++ b/packages/views/signoff.py @@ -1,4 +1,3 @@ -from datetime import datetime from operator import attrgetter from django import forms @@ -13,6 +12,7 @@ from django.views.generic.simple import direct_to_template from main.models import Package, Arch, Repo +from main.utils import utc_now from ..models import SignoffSpecification, Signoff from ..utils import (get_signoff_groups, approved_by_signoffs, PackageSignoffGroup) @@ -45,7 +45,7 @@ def signoff_package(request, name, repo, arch, revoke=False): package, request.user, False) except Signoff.DoesNotExist: raise Http404 - signoff.revoked = datetime.utcnow() + signoff.revoked = utc_now() signoff.save() created = False else: diff --git a/releng/management/commands/syncisos.py b/releng/management/commands/syncisos.py index 270c6c34..62f005ff 100644 --- a/releng/management/commands/syncisos.py +++ b/releng/management/commands/syncisos.py @@ -1,4 +1,3 @@ -from datetime import datetime import re import urllib from HTMLParser import HTMLParser, HTMLParseError @@ -6,8 +5,10 @@ from django.conf import settings from django.core.management.base import BaseCommand, CommandError +from main.utils import utc_now from releng.models import Iso + class IsoListParser(HTMLParser): def __init__(self): HTMLParser.__init__(self) @@ -53,7 +54,7 @@ def handle(self, *args, **options): existing.active = True existing.removed = None existing.save() - now = datetime.utcnow() + now = utc_now() # and then mark all other names as no longer active Iso.objects.filter(active=True).exclude(name__in=active_isos).update( active=False, removed=now) diff --git a/settings.py b/settings.py index 9aba3881..e1d4d4a9 100644 --- a/settings.py +++ b/settings.py @@ -18,9 +18,13 @@ # Full path to the data directory DEPLOY_PATH = os.path.dirname(os.path.realpath(__file__)) -# Local time zone for this installation. All choices can be found here: -# http://www.postgresql.org/docs/current/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE -TIME_ZONE = 'US/Eastern' +# If you set this to False, Django will not use timezone-aware datetimes. +USE_TZ = True + +# Local time zone for this installation. Choices can be found here: +# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name +# although not all choices may be available on all operating systems. +TIME_ZONE = 'UTC' # Language code for this installation. All choices can be found here: # http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes diff --git a/sitemaps.py b/sitemaps.py index 177555ff..8e9ba36f 100644 --- a/sitemaps.py +++ b/sitemaps.py @@ -1,4 +1,5 @@ from datetime import datetime, timedelta +from pytz import utc from django.contrib.sitemaps import Sitemap from django.core.urlresolvers import reverse @@ -62,7 +63,7 @@ class NewsSitemap(Sitemap): priority = "0.8" def __init__(self): - now = datetime.utcnow() + now = datetime.utcnow().replace(tzinfo=utc) self.one_day_ago = now - timedelta(days=1) self.one_week_ago = now - timedelta(days=7) diff --git a/templates/devel/clock.html b/templates/devel/clock.html index 72a57d0f..3b00075f 100644 --- a/templates/devel/clock.html +++ b/templates/devel/clock.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load tz %} {% block title %}Arch Linux - Developer World Clocks{% endblock %} @@ -10,7 +11,6 @@

Developer World Clocks

depends on developers keeping the time zone information up to date, so if you see 'UTC' listed, pester them to update their settings.

- Arch Server Time: {{ now|date:"Y-m-d H:i T" }}
UTC Time: {{ utc_now|date:"Y-m-d H:i T" }}

@@ -33,7 +33,7 @@

Developer World Clocks

{{ dev.userprofile.alias }} {{ dev.userprofile.location }} {{ dev.userprofile.time_zone }} - {{ dev.current_time|date:"Y-m-d H:i T" }} + {{ utc_now|timezone:dev.userprofile.time_zone|date:"Y-m-d H:i T" }} {% endfor %} -- cgit v1.2.3-54-g00ecf From 8e10699d53281be53c88a3695de6aa496e084dc6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Fri, 23 Mar 2012 20:09:38 -0500 Subject: Use 'url from future' everywhere The old-style url template tag disappears in Django 1.5, so we can and should convert to the new-style tag now. Signed-off-by: Dan McGee --- templates/base.html | 14 +++++++------- templates/public/download.html | 5 +++-- templates/public/index.html | 31 ++++++++++++++++--------------- templates/releng/add.html | 3 ++- templates/releng/iso_overview.html | 3 ++- templates/releng/result_list.html | 3 ++- templates/releng/result_section.html | 7 ++++--- templates/releng/results.html | 5 +++-- templates/releng/thanks.html | 7 ++++--- templates/visualize/index.html | 7 ++++--- 10 files changed, 47 insertions(+), 38 deletions(-) diff --git a/templates/base.html b/templates/base.html index 0da77cf3..fa30df1a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,4 +1,4 @@ - +{% load url from future %} {% block title %}Arch Linux{% endblock %} @@ -10,7 +10,7 @@ - + {% block head %}{% endblock %} @@ -25,7 +25,7 @@
  • Wiki
  • Bugs
  • AUR
  • -
  • Download
  • +
  • Download
  • @@ -34,20 +34,20 @@
    {% if user.is_authenticated %} diff --git a/templates/public/index.html b/templates/public/index.html index 00edf8c4..53ccd2d2 100644 --- a/templates/public/index.html +++ b/templates/public/index.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load markup cache cdn %} +{% load url from future %} {% block head %} @@ -30,13 +31,13 @@

    A simple, lightweight distribution

    title="Arch Wiki">wiki if you want to learn more about Arch.

    -

    Learn more...

    - Latest News + Latest News

    @@ -57,7 +58,7 @@

    {% else %} {% if forloop.counter0 == 5 %}

    - Older News

    @@ -137,7 +138,7 @@

    Community

    Support

    diff --git a/templates/releng/add.html b/templates/releng/add.html index 8488b40c..ed02984e 100644 --- a/templates/releng/add.html +++ b/templates/releng/add.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load url from future %} {% block title %}Arch Linux - Test Result Entry{% endblock %} @@ -13,7 +14,7 @@

    Arch Releng Testbuild Feedback Entry

    installation properly. Some options require you to check several things (such as config files), this will be mentioned alongside the option.

    There is also an overview of all feedback on the - results page. Once we have + results page. Once we have builds that are properly tested (enough successful feedback for all important features of the ISO or a slightly earlier ISO), we can release new official media.

    diff --git a/templates/releng/iso_overview.html b/templates/releng/iso_overview.html index 5a4445b7..76479c52 100644 --- a/templates/releng/iso_overview.html +++ b/templates/releng/iso_overview.html @@ -1,10 +1,11 @@ {% extends "base.html" %} +{% load url from future %} {% block content %}

    Failures and Successes for Testing ISOs

    -

    Go back to testing results

    +

    Go back to testing results

    diff --git a/templates/releng/result_list.html b/templates/releng/result_list.html index 512e1bf3..62264217 100644 --- a/templates/releng/result_list.html +++ b/templates/releng/result_list.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load url from future %} {% block content %}
    @@ -7,7 +8,7 @@

    Results for: {{ iso_name|default:"" }}

    -

    Go back to testing results

    +

    Go back to testing results

    diff --git a/templates/releng/result_section.html b/templates/releng/result_section.html index 08e46fb7..c82a5532 100644 --- a/templates/releng/result_section.html +++ b/templates/releng/result_section.html @@ -1,3 +1,4 @@ +{% load url from future %} @@ -6,20 +7,20 @@ {% for item in option.values %}
    {% if option.is_rollback %}Rollback: {% endif %}{{ option.name|title }} Last Success
    - + {{ item.value.name|lower }} {% if item.success %} - + {{ item.success.name }} {% else %}Never succeeded{% endif %} {% if item.failure %} - + {{ item.failure.name }} {% else %}Never failed{% endif %} diff --git a/templates/releng/results.html b/templates/releng/results.html index 4ff3c864..71af708f 100644 --- a/templates/releng/results.html +++ b/templates/releng/results.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load url from future %} {% block title %}Arch Linux - Release Engineering Testbuild Results{% endblock %} @@ -9,12 +10,12 @@

    Release Engineering Testbuild Results

    This is an overview screen showing a test results matrix of release engineering produced ISOs. Various options and configurations are shown with last success and last failure results, if known. To help improve ISO - quality, you are encouraged to give feedback + quality, you are encouraged to give feedback if you have tested and used any ISOs. Both successful and failed results are encouraged and welcome.

    For a overview of which ISOs tested best, have a look at - the overview.

    + the overview.

    For more information, see the documentation diff --git a/templates/releng/thanks.html b/templates/releng/thanks.html index 80018b03..66d65a5c 100644 --- a/templates/releng/thanks.html +++ b/templates/releng/thanks.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load url from future %} {% block title %}Arch Linux - Feedback - Thanks!{% endblock %} @@ -7,9 +8,9 @@

    Thanks!

    Thank you for taking the time to give us this information! Your results have been succesfully added to our database.

    -

    You can now go back to the results, - give more feedback, or - have a look at the look at +

    You can now go back to the results, + give more feedback, or + have a look at the look at the ISO test overview.

    {% endblock %} diff --git a/templates/visualize/index.html b/templates/visualize/index.html index a7727b1f..a7855eb2 100644 --- a/templates/visualize/index.html +++ b/templates/visualize/index.html @@ -1,4 +1,5 @@ {% extends "base.html" %} +{% load url from future %} {% block title %}Arch Linux - Visualizations{% endblock %} @@ -34,11 +35,11 @@

    Visualization of PGP Master and Signing Keys

    {% endblock %} -- cgit v1.2.3-54-g00ecf