From 8edc3c4b9dddecac436a741aa54b8ada52f87dae Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 26 Mar 2012 10:27:01 -0500 Subject: Bump signoffs and mirror status JSON API versions Due to datetime formatting changes in Django 1.4, we know follow the ECMA specification more closely and use 'yyyy-mm-ddThh:mm_ssZ' format. As this could break existing users of the JSON data, bump the version. Signed-off-by: Dan McGee --- mirrors/views.py | 2 +- packages/views/signoff.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mirrors/views.py b/mirrors/views.py index 2ef8654d..e93097a3 100644 --- a/mirrors/views.py +++ b/mirrors/views.py @@ -169,7 +169,7 @@ def default(self, obj): def status_json(request): status_info = get_mirror_statuses() data = status_info.copy() - data['version'] = 1 + data['version'] = 2 to_json = simplejson.dumps(data, ensure_ascii=False, cls=MirrorStatusJSONEncoder) response = HttpResponse(to_json, mimetype='application/json') diff --git a/packages/views/signoff.py b/packages/views/signoff.py index cf00b0b9..63341a1d 100644 --- a/packages/views/signoff.py +++ b/packages/views/signoff.py @@ -180,7 +180,7 @@ def default(self, obj): def signoffs_json(request): signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) data = { - 'version': 1, + 'version': 2, 'signoff_groups': signoff_groups, } to_json = simplejson.dumps(data, ensure_ascii=False, -- cgit v1.2.3-54-g00ecf From 493092f88f03ae7ec385f76abeeb51516ff888e3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 26 Mar 2012 12:29:37 -0500 Subject: Add more info to package JSON dump Signed-off-by: Dan McGee --- packages/views/__init__.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 8f22a8a1..a915d58c 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -1,3 +1,6 @@ +from string import Template +from urllib import urlencode + from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.models import User @@ -9,12 +12,10 @@ from django.views.decorators.vary import vary_on_headers from django.views.generic.simple import direct_to_template -from string import Template -from urllib import urlencode - -from main.models import Package, PackageFile, Arch, Repo +from main.models import Package, PackageFile, PackageDepend, Arch, Repo from mirrors.models import MirrorUrl -from ..models import PackageRelation, PackageGroup +from ..models import (PackageRelation, PackageGroup, License, + Conflict, Provision, Replacement) from ..utils import (get_group_info, get_differences_info, multilib_differences, get_wrong_permissions) @@ -29,6 +30,8 @@ class PackageJSONEncoder(DjangoJSONEncoder): 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', 'installed_size', 'build_date', 'last_update', 'flag_date', 'maintainers', 'packager' ] + pkg_list_attributes = [ 'groups', 'licenses', 'conflicts', + 'provides', 'replaces', 'packagedepend_set' ] def default(self, obj): if hasattr(obj, '__iter__'): @@ -37,13 +40,22 @@ def default(self, obj): if isinstance(obj, Package): data = dict((attr, getattr(obj, attr)) for attr in self.pkg_attributes) - data['groups'] = obj.groups.all() + for attr in self.pkg_list_attributes: + values = getattr(obj, attr).all() + # TODO: temporary rename becuase the name sucks + if attr == 'packagedepend_set': + attr = 'depends' + data[attr] = values return data if isinstance(obj, PackageFile): filename = obj.filename or '' return obj.directory + filename - if isinstance(obj, (Repo, Arch, PackageGroup)): + if isinstance(obj, (Repo, Arch)): return obj.name.lower() + if isinstance(obj, (PackageGroup, License)): + return obj.name + if isinstance(obj, (Conflict, Provision, Replacement, PackageDepend)): + return unicode(obj) elif isinstance(obj, User): return obj.username return super(PackageJSONEncoder, self).default(obj) -- cgit v1.2.3-54-g00ecf From 611e30172ae8db58fc2f6146fd1bee428e55ea6a Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 26 Mar 2012 12:33:28 -0500 Subject: Rename 'packagedepend_set' attribute to 'depends' We do this for every other related package attribute, so do it here too. Signed-off-by: Dan McGee --- devel/management/commands/reporead.py | 2 +- main/models.py | 4 ++-- packages/views/__init__.py | 8 ++------ 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index c5a2ece5..fd8e3979 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -229,7 +229,7 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): populate_files(dbpkg, repopkg, force=force) - dbpkg.packagedepend_set.all().delete() + dbpkg.depends.all().delete() deps = [create_depend(dbpkg, y) for y in repopkg.depends] deps += [create_depend(dbpkg, y, True) for y in repopkg.optdepends] PackageDepend.objects.bulk_create(deps) diff --git a/main/models.py b/main/models.py index 289cbb84..34cbcd17 100644 --- a/main/models.py +++ b/main/models.py @@ -288,7 +288,7 @@ def get_depends(self): if not self.arch.agnostic: arches = self.applicable_arches() # TODO: we can use list comprehension and an 'in' query to make this more effective - for dep in self.packagedepend_set.order_by('optional', 'depname'): + for dep in self.depends.order_by('optional', 'depname'): pkg = dep.get_best_satisfier(arches, testing=self.repo.testing, staging=self.repo.staging) providers = None @@ -391,7 +391,7 @@ class Meta: db_table = 'package_files' class PackageDepend(models.Model): - pkg = models.ForeignKey(Package) + pkg = models.ForeignKey(Package, related_name='depends') depname = models.CharField(max_length=255, db_index=True) depvcmp = models.CharField(max_length=255, default='') optional = models.BooleanField(default=False) diff --git a/packages/views/__init__.py b/packages/views/__init__.py index a915d58c..afb1de31 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -31,7 +31,7 @@ class PackageJSONEncoder(DjangoJSONEncoder): 'installed_size', 'build_date', 'last_update', 'flag_date', 'maintainers', 'packager' ] pkg_list_attributes = [ 'groups', 'licenses', 'conflicts', - 'provides', 'replaces', 'packagedepend_set' ] + 'provides', 'replaces', 'depends' ] def default(self, obj): if hasattr(obj, '__iter__'): @@ -41,11 +41,7 @@ def default(self, obj): data = dict((attr, getattr(obj, attr)) for attr in self.pkg_attributes) for attr in self.pkg_list_attributes: - values = getattr(obj, attr).all() - # TODO: temporary rename becuase the name sucks - if attr == 'packagedepend_set': - attr = 'depends' - data[attr] = values + data[attr] = getattr(obj, attr).all() return data if isinstance(obj, PackageFile): filename = obj.filename or '' -- cgit v1.2.3-54-g00ecf From 23cb0d0956f31d855e0e06649998f724d97b0560 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 26 Mar 2012 12:34:16 -0500 Subject: Remove media/ staticfiles URL location Signed-off-by: Dan McGee --- urls.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/urls.py b/urls.py index 9b9b4559..0f2e07af 100644 --- a/urls.py +++ b/urls.py @@ -107,9 +107,4 @@ urlpatterns += patterns('django.views.generic.simple', (old_url, 'redirect_to', {'url': new_url})) -if settings.DEBUG == True: - urlpatterns += patterns('', - (r'^media/(.*)$', 'django.views.static.serve', - {'document_root': os.path.join(settings.DEPLOY_PATH, 'media')})) - # vim: set ts=4 sw=4 et: -- cgit v1.2.3-54-g00ecf From ff5965f45db9e9e0c997f80c798417f3a71c848f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sat, 24 Mar 2012 15:17:54 -0500 Subject: Switch to recommending PostgreSQL by default Signed-off-by: Dan McGee --- README | 7 ++++--- local_settings.py.example | 5 ++--- requirements_prod.txt | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index 0d3ee082..707ab7ca 100644 --- a/README +++ b/README @@ -23,9 +23,9 @@ More detail in `requirements.txt` and `requirements_prod.txt`; it is best to use virtualenv and pip to handle these. But if you insist on (Arch Linux) packages, you will probably want the following: -- mysql-python or python-pysqlite - django -- python-markdown +- python2-psycopg2 +- python2-markdown - python-south - python-memcached @@ -44,7 +44,8 @@ packages, you will probably want the following: (archweb-env) $ pip install -r requirements.txt 3. Copy `local_settings.py.example` to `local_settings.py` and modify. - Make sure to uncomment the appropriate db section (either sqlite or mysql). + Make sure to uncomment the appropriate database section (either sqlite or + PostgreSQL). 4. Sync the database to create it. diff --git a/local_settings.py.example b/local_settings.py.example index 37ac29a6..b8407d3e 100644 --- a/local_settings.py.example +++ b/local_settings.py.example @@ -13,16 +13,15 @@ ADMINS = ( # ('Joe Admin', 'joeadmin@example.com'), ) -## MySQL Database settings +## PostgreSQL Database settings DATABASES = { 'default': { - 'ENGINE' : 'django.db.backends.mysql', + 'ENGINE' : 'django.db.backends.postgresql_psycopg2', 'NAME' : 'archlinux', 'USER' : 'archlinux', 'PASSWORD': 'archlinux', 'HOST' : '', 'PORT' : '', - 'OPTIONS' : {'init_command': 'SET storage_engine=InnoDB'}, }, } diff --git a/requirements_prod.txt b/requirements_prod.txt index 7f7663a8..517000a9 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -1,8 +1,8 @@ Django==1.4 Markdown==2.1.1 -MySQL-python==1.2.3 South==0.7.4 pgpdump==1.1 +psycopg2=2.4.4 pyinotify==0.9.3 python-memcached==1.48 pytz>=2012b -- cgit v1.2.3-54-g00ecf From fd53e0248fdefc4d49fdb739767c496d42396c5e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 00:39:21 -0500 Subject: Fix bad merge in releng section template Signed-off-by: Dan McGee --- templates/releng/result_section.html | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/releng/result_section.html b/templates/releng/result_section.html index 45838b86..91a75613 100644 --- a/templates/releng/result_section.html +++ b/templates/releng/result_section.html @@ -7,7 +7,6 @@ {% for item in option.values %} - {{ item.value.name|lower }} -- cgit v1.2.3-54-g00ecf From 076f9c51d50be9bb567e8477eff4c15bde62fcb3 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 10:00:11 -0500 Subject: Return files in default order When we read the repository databases, we get a filelist in sorted order. Save time by returning the file list in that order rather than resorting it based on filename and directory. Signed-off-by: Dan McGee --- packages/views/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/views/__init__.py b/packages/views/__init__.py index afb1de31..2798fff1 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -185,7 +185,8 @@ def group_details(request, arch, name): def files(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) - fileslist = PackageFile.objects.filter(pkg=pkg).order_by('directory', 'filename') + # files are inserted in sorted order, so preserve that + fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') dir_count = sum(1 for f in fileslist if f.is_directory) files_count = len(fileslist) - dir_count context = { @@ -209,7 +210,8 @@ def details_json(request, name, repo, arch): def files_json(request, name, repo, arch): pkg = get_object_or_404(Package, pkgname=name, repo__name__iexact=repo, arch__name=arch) - fileslist = PackageFile.objects.filter(pkg=pkg).order_by('directory', 'filename') + # files are inserted in sorted order, so preserve that + fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') data = { 'pkgname': pkg.pkgname, 'repo': pkg.repo.name.lower(), -- cgit v1.2.3-54-g00ecf From 5555ce02278defaef0ef1388c163701eea3aff7e Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 11:35:40 -0500 Subject: Use spaceless tag in mirror status output This removes a lot of needless whitespace in the generated output, shrinking the uncompressed page size by 30KB to 54KB total on my current set of mirror test data. Signed-off-by: Dan McGee --- templates/mirrors/status.html | 4 ++-- templates/mirrors/status_table.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/mirrors/status.html b/templates/mirrors/status.html index 4f09be8b..225572ee 100644 --- a/templates/mirrors/status.html +++ b/templates/mirrors/status.html @@ -89,7 +89,7 @@

Mirror Syncing Error Log

{% for log in error_logs %} - + {% spaceless %} {{ log.url__url }} {{ log.url__protocol__protocol }} {{ log.country }} @@ -97,7 +97,7 @@

Mirror Syncing Error Log

{{ log.last_occurred|date:'Y-m-d H:i' }} {{ log.error_count }} - {% endfor %} + {% endspaceless %}{% endfor %} diff --git a/templates/mirrors/status_table.html b/templates/mirrors/status_table.html index 72de25dc..bd70115c 100644 --- a/templates/mirrors/status_table.html +++ b/templates/mirrors/status_table.html @@ -15,7 +15,7 @@ {% for m_url in urls %} - + {% spaceless %} {{ m_url.url }} {{ m_url.protocol }} {{ m_url.real_country }} @@ -26,6 +26,6 @@ {{ m_url.duration_stddev|floatformat:2 }} {{ m_url.score|floatformat:1|default:'∞' }} - {% endfor %} + {% endspaceless %}{% endfor %} -- cgit v1.2.3-54-g00ecf From ef88f3d5ef696b71a65a81f143b13ae27175a1c5 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 11:37:07 -0500 Subject: Add developer status table to master keys page This shows the cross-product of each master key with each developer key so you can see who has been signed, where signatures are missing, etc. Signed-off-by: Dan McGee --- main/templatetags/pgp.py | 8 +++++++ public/views.py | 21 ++++++++++++++--- sitestatic/archweb.css | 8 +++++++ templates/public/keys.html | 56 ++++++++++++++++++++++++++++++++++++++-------- visualize/views.py | 2 +- 5 files changed, 82 insertions(+), 13 deletions(-) diff --git a/main/templatetags/pgp.py b/main/templatetags/pgp.py index 1ffc5241..50b1aa17 100644 --- a/main/templatetags/pgp.py +++ b/main/templatetags/pgp.py @@ -50,4 +50,12 @@ def pgp_fingerprint(key_id, autoescape=True): return mark_safe(format_key(esc(key_id))) pgp_fingerprint.needs_autoescape = True + +@register.assignment_tag +def signature_exists(signatures, signer, signee): + if not signer or not signee: + return False + lookup = (signer[-16:], signee[-16:]) + return lookup in signatures + # vim: set ts=4 sw=4 et: diff --git a/public/views.py b/public/views.py index 1e1ffc6c..a85d7389 100644 --- a/public/views.py +++ b/public/views.py @@ -1,6 +1,8 @@ +from datetime import datetime + from django.conf import settings from django.contrib.auth.models import User -from django.db.models import Count +from django.db.models import Count, Q from django.http import Http404 from django.views.decorators.cache import cache_control from django.views.generic import list_detail @@ -88,17 +90,30 @@ def feeds(request): @cache_control(max_age=300) def keys(request): + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) master_keys = MasterKey.objects.select_related('owner', 'revoker', 'owner__userprofile', 'revoker__userprofile').filter( revoked__isnull=True) - sig_counts = PGPSignature.objects.filter(valid=True, - expires__isnull=True).values_list('signer').annotate( + + sig_counts = PGPSignature.objects.filter( + not_expired, valid=True).values_list('signer').annotate( Count('signer')) sig_counts = dict((key_id[-16:], ct) for key_id, ct in sig_counts) + for key in master_keys: key.signature_count = sig_counts.get(key.pgp_key[-16:], 0) + + users = User.objects.filter(is_active=True).select_related( + 'userprofile__pgp_key').order_by('first_name', 'last_name') + + # frozenset because we are going to do lots of __contains__ lookups + signatures = frozenset(PGPSignature.objects.filter( + not_expired, valid=True).values_list('signer', 'signee')) + context = { 'keys': master_keys, + 'active_users': users, + 'signatures': signatures, } return direct_to_template(request, 'public/keys.html', context) diff --git a/sitestatic/archweb.css b/sitestatic/archweb.css index d2286329..ac0dff52 100644 --- a/sitestatic/archweb.css +++ b/sitestatic/archweb.css @@ -957,6 +957,14 @@ ul.signoff-list { color: red; } +#key-status .signed-yes { + color: green; +} + +#key-status .signed-no { + color: red; +} + /* highlight current website in the navbar */ #archnavbar.anb-home ul li#anb-home a, #archnavbar.anb-packages ul li#anb-packages a, diff --git a/templates/public/keys.html b/templates/public/keys.html index 6b06cc32..a7c91c43 100644 --- a/templates/public/keys.html +++ b/templates/public/keys.html @@ -15,15 +15,6 @@

Master Signing Keys

The {{ keys|length }} key{{ keys|pluralize }} listed below should be regarded as the current set of master keys. They are available on public keyservers and should be signed by the owner of the key.

-

All official Arch Linux developers and trusted users should have their - key signed by at least three of these master keys. This is in accordance - with the PGP web of trust concept. If a user is willing to - marginally trust all of the master keys, three signatures from different - master keys will consider a given developer's key as valid. For more - information on trust, please consult the - GNU Privacy Handbook - and Using trust to - validate keys.

@@ -55,5 +46,52 @@

Master Signing Keys

{% endfor %}
+ +

The following table shows all active developers and trusted users along + with the status of their personal signing key. A 'Yes' indicates that the + personal key of the developer is signed by the given master key. A 'No' + indicates it has not been signed; however, this does not necessarily mean + the key should not be trusted.

+

All official Arch Linux developers and trusted users should have their + key signed by at least three master keys if they are responsible for + packaging software in the repositories. This is in accordance with the PGP + web of trust concept. If a user is willing to marginally trust all + of the master keys, three signatures from different master keys will + consider a given developer's key as valid. For more information on trust, + please consult the + GNU Privacy Handbook + and Using trust to + validate keys.

+ + + + + + + {% for key in keys %} + + {% endfor %} + + + + + {% for key in keys %} + + {% endfor %} + + + + {% for user in active_users %} + + + + {% spaceless %}{% for key in keys %} + {% signature_exists signatures key.pgp_key user.userprofile.pgp_key as signed %} + + {% endfor %}{% endspaceless %} + + {% endfor %} + +
PGP Key{{ key.owner.get_full_name }}
{% pgp_key_link key.pgp_key %}
{{ user.get_full_name }}{% pgp_key_link user.userprofile.pgp_key %}{{ signed|yesno|capfirst }}
{% endblock %} diff --git a/visualize/views.py b/visualize/views.py index be6057b2..afc5429d 100644 --- a/visualize/views.py +++ b/visualize/views.py @@ -102,7 +102,7 @@ def pgp_keys(request): 'group': 'cacert', }) - not_expired = Q(expires__gt=datetime.now) | Q(expires__isnull=True) + not_expired = Q(expires__gt=datetime.utcnow) | Q(expires__isnull=True) signatures = PGPSignature.objects.filter(not_expired, valid=True) edge_list = [{ 'signee': sig.signee, 'signer': sig.signer } for sig in signatures] -- cgit v1.2.3-54-g00ecf From 30f775f0b4242e1c6788a7fb1b513a888617de8f Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 11:50:21 -0500 Subject: Use spaceless tag on signoffs page More whitespace collapsing to shrink the HTML size quite a bit. Signed-off-by: Dan McGee --- templates/packages/signoff_cell.html | 2 -- templates/packages/signoffs.html | 12 +++++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/templates/packages/signoff_cell.html b/templates/packages/signoff_cell.html index 01a5d58d..7d9e1972 100644 --- a/templates/packages/signoff_cell.html +++ b/templates/packages/signoff_cell.html @@ -1,4 +1,3 @@ -{% spaceless %} {% if group.signoffs %}
    {% for signoff in group.signoffs %} @@ -22,4 +21,3 @@ Signoff Options {% endif %} -{% endspaceless %} diff --git a/templates/packages/signoffs.html b/templates/packages/signoffs.html index 3a2c3509..b20483c0 100644 --- a/templates/packages/signoffs.html +++ b/templates/packages/signoffs.html @@ -52,6 +52,7 @@

    Filter Displayed Signoffs

    {% for group in signoff_groups %} + {% spaceless %} {% pkg_details_link group.package %} {{ group.version }} {{ group.arch.name }} {{ group.target_repo }} @@ -68,12 +69,13 @@

    Filter Displayed Signoffs

    {% endif %} {% endif %} {% include "packages/signoff_cell.html" %} - {% if not group.default_spec %}{% with group.specification as spec %} - {% if spec.required != 2 %}Required signoffs: {{ spec.required }}
    {% endif %} - {% if not spec.enabled %}Signoffs are not currently enabled
    {% endif %} - {% if spec.known_bad %}Package is known to be bad
    {% endif %} - {{ spec.comments|default:""|linebreaksbr }} + {% if not group.default_spec %}{% with group.specification as spec %}{% comment %} + {% endcomment %}{% if spec.required != 2 %}Required signoffs: {{ spec.required }}
    {% endif %}{% comment %} + {% endcomment %}{% if not spec.enabled %}Signoffs are not currently enabled
    {% endif %}{% comment %} + {% endcomment %}{% if spec.known_bad %}Package is known to be bad
    {% endif %}{% comment %} + {% endcomment %}{{ spec.comments|default:""|linebreaksbr }} {% endwith %}{% endif %} + {% endspaceless %} {% endfor %} -- cgit v1.2.3-54-g00ecf From 9eb5b4e607cd0886578da104617a6209aa89ec8d Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Thu, 29 Mar 2012 11:53:32 -0500 Subject: Use spaceless tag on package search results Signed-off-by: Dan McGee --- templates/packages/search.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/packages/search.html b/templates/packages/search.html index 030f2671..ebd4e6c4 100644 --- a/templates/packages/search.html +++ b/templates/packages/search.html @@ -77,7 +77,7 @@

    Package Search

    {% for pkg in package_list %} - + {% spaceless %} {% if perms.main.change_package %} {% endif %} @@ -93,7 +93,7 @@

    Package Search

    {{ pkg.last_update|date }} {{ pkg.flag_date|date }} - {% endfor %} + {% endspaceless %}{% endfor %} {% include "packages/search_paginator.html" %} -- cgit v1.2.3-54-g00ecf From cbdcb08557112f53ddcf074b950ee0950e12a045 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 2 Apr 2012 10:37:11 -0500 Subject: Fix missing = sign in requirements_prod Signed-off-by: Dan McGee --- requirements_prod.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_prod.txt b/requirements_prod.txt index 517000a9..e43437de 100644 --- a/requirements_prod.txt +++ b/requirements_prod.txt @@ -2,7 +2,7 @@ Django==1.4 Markdown==2.1.1 South==0.7.4 pgpdump==1.1 -psycopg2=2.4.4 +psycopg2==2.4.4 pyinotify==0.9.3 python-memcached==1.48 pytz>=2012b -- cgit v1.2.3-54-g00ecf