summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2010-03-01 21:07:23 -0600
committerDan McGee <dan@archlinux.org>2010-03-01 21:07:23 -0600
commit096c6ef26f0849150629bf6567be0efa9e61409f (patch)
tree83c921fa80c4eb0b08fceb7a378e06ed582b6949
parentc19cec1820bc61f0a7c09d7cbed3b7d0adcb2824 (diff)
parentab459d4d182cc56bbaf24b0e483e83267a9df432 (diff)
downloadarchweb-096c6ef26f0849150629bf6567be0efa9e61409f.tar.gz
archweb-096c6ef26f0849150629bf6567be0efa9e61409f.zip
Merge branch 'package-files'
-rw-r--r--devel/management/commands/reporead.py90
-rw-r--r--main/migrations/0007_add_files_last_update.py193
-rw-r--r--main/models.py1
-rw-r--r--packages/views.py16
-rw-r--r--templates/packages/details.html22
-rw-r--r--templates/packages/files-list.html12
-rw-r--r--templates/packages/files.html8
-rw-r--r--todolists/views.py2
-rw-r--r--urls.py3
9 files changed, 304 insertions, 43 deletions
diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py
index 3ff6f596..34b291eb 100644
--- a/devel/management/commands/reporead.py
+++ b/devel/management/commands/reporead.py
@@ -6,7 +6,7 @@ Parses a repo.db.tar.gz file and updates the Arch database with the relevant
changes.
Usage: ./manage.py reporead ARCH PATH
- ARCH: architecture to update, and can be one of: i686, x86_64
+ ARCH: architecture to update; must be available in the database
PATH: full path to the repo.db.tar.gz file.
Example:
@@ -55,6 +55,8 @@ class Command(BaseCommand):
option_list = BaseCommand.option_list + (
make_option('-f', '--force', action='store_true', dest='force', default=False,
help='Force a re-import of data for all packages instead of only new ones. Will not touch the \'last updated\' value.'),
+ make_option('--filesonly', action='store_true', dest='filesonly', default=False,
+ help='Load filelists if they are outdated, but will not add or remove any packages. Will not touch the \'last updated\' value.'),
)
help = "Runs a package repository import for the given arch and file."
args = "<arch> <filename>"
@@ -132,7 +134,7 @@ class Pkg(object):
return None
-def populate_pkg(dbpkg, repopkg, timestamp=None):
+def populate_pkg(dbpkg, repopkg, force=False, timestamp=None):
dbpkg.pkgbase = repopkg.base
dbpkg.pkgver = repopkg.ver
dbpkg.pkgrel = repopkg.rel
@@ -153,9 +155,9 @@ def populate_pkg(dbpkg, repopkg, timestamp=None):
dbpkg.needupdate = False
dbpkg.last_update = timestamp
dbpkg.save()
- # files are not in the repo.db.tar.gz
- #for x in repopkg.files:
- # dbpkg.packagefile_set.create(path=x)
+
+ populate_files(dbpkg, repopkg, force=force)
+
dbpkg.packagedepend_set.all().delete()
if 'depends' in repopkg.__dict__:
for y in repopkg.depends:
@@ -168,8 +170,22 @@ def populate_pkg(dbpkg, repopkg, timestamp=None):
dbpkg.packagedepend_set.create(depname=dpname, depvcmp=dpvcmp)
logger.debug('Added %s as dep for pkg %s' % (dpname,repopkg.name))
-
-def db_update(archname, pkgs, force):
+def populate_files(dbpkg, repopkg, force=False):
+ if not force:
+ if not dbpkg.files_last_update or not dbpkg.last_update:
+ pass
+ elif dbpkg.files_last_update > dbpkg.last_update:
+ return
+ # only delete files if we are reading a DB that contains them
+ if 'files' in repopkg.__dict__:
+ dbpkg.packagefile_set.all().delete()
+ logger.info("adding %d files for package %s" % (len(repopkg.files), dbpkg.pkgname))
+ for x in repopkg.files:
+ dbpkg.packagefile_set.create(path=x)
+ dbpkg.files_last_update = datetime.now()
+ dbpkg.save()
+
+def db_update(archname, pkgs, options):
"""
Parses a list and updates the Arch dev database accordingly.
@@ -178,6 +194,8 @@ def db_update(archname, pkgs, force):
"""
logger.info('Updating Arch: %s' % archname)
+ force = options.get('force', False)
+ filesonly = options.get('filesonly', False)
repository = Repo.objects.get(name__iexact=pkgs[0].repo)
architecture = Arch.objects.get(name__iexact=archname)
dbpkgs = Package.objects.filter(arch=architecture, repo=repository)
@@ -217,19 +235,22 @@ def db_update(archname, pkgs, force):
if dbpercent < 75.0:
logger.warning(".db.tar.gz has %.1f%% the number of packages in the web database." % dbpercent)
-
- for p in [x for x in pkgs if x.name in in_sync_not_db]:
- logger.info("Adding package %s", p.name)
- pkg = Package(pkgname = p.name, arch = architecture, repo = repository)
- populate_pkg(pkg, p, timestamp=datetime.now())
-
- # packages in database and not in syncdb (remove from database)
- logger.debug("Set theory: Packages in database not in syncdb")
- in_db_not_sync = dbset - syncset
- for p in in_db_not_sync:
- logger.info("Removing package %s from database", p)
- Package.objects.get(
- pkgname=p, arch=architecture, repo=repository).delete()
+
+ if not filesonly:
+ # packages in syncdb and not in database (add to database)
+ logger.debug("Set theory: Packages in syncdb not in database")
+ for p in [x for x in pkgs if x.name in in_sync_not_db]:
+ logger.info("Adding package %s", p.name)
+ pkg = Package(pkgname = p.name, arch = architecture, repo = repository)
+ populate_pkg(pkg, p, timestamp=datetime.now())
+
+ # packages in database and not in syncdb (remove from database)
+ logger.debug("Set theory: Packages in database not in syncdb")
+ in_db_not_sync = dbset - syncset
+ for p in in_db_not_sync:
+ logger.info("Removing package %s from database", p)
+ Package.objects.get(
+ pkgname=p, arch=architecture, repo=repository).delete()
# packages in both database and in syncdb (update in database)
logger.debug("Set theory: Packages in database and syncdb")
@@ -240,15 +261,21 @@ def db_update(archname, pkgs, force):
timestamp = None
# for a force, we don't want to update the timestamp.
# for a non-force, we don't want to do anything at all.
- if ''.join((p.ver,p.rel)) == ''.join((dbp.pkgver,dbp.pkgrel)):
+ if filesonly:
+ pass
+ elif ''.join((p.ver,p.rel)) == ''.join((dbp.pkgver,dbp.pkgrel)):
if not force:
continue
else:
timestamp = datetime.now()
- logger.info("Updating package %s in database", p.name)
pkg = Package.objects.get(
pkgname=p.name,arch=architecture, repo=repository)
- populate_pkg(pkg, p, timestamp=timestamp)
+ if filesonly:
+ logger.info("Possibly populating files for package %s in database", p.name)
+ populate_files(pkg, p)
+ else:
+ logger.info("Updating package %s in database", p.name)
+ populate_pkg(pkg, p, force=force, timestamp=timestamp)
logger.info('Finished updating Arch: %s' % archname)
@@ -297,13 +324,18 @@ def parse_repo(repopath):
logger.info("Reading repo tarfile %s", repopath)
filename = os.path.split(repopath)[1]
- rindex = filename.rindex('.db.tar.gz')
- reponame = filename[:rindex]
-
+ m = re.match(r"^(.*)\.(db|files)\.tar\.(.*)$", filename)
+ if m:
+ reponame = m.group(1)
+ else:
+ logger.error("File does not have the proper extension")
+ raise SomethingFishyException("File does not have the proper extension")
+
repodb = tarfile.open(repopath,"r:gz")
## assuming well formed tar, with dir first then files after
## repo-add enforces this
logger.debug("Starting package parsing")
+ dbfiles = ('desc', 'depends', 'files')
pkgs = []
tpkg = None
while True:
@@ -321,7 +353,8 @@ def parse_repo(repopath):
# set new tpkg
tpkg = StringIO()
if tarinfo.isreg():
- if os.path.split(tarinfo.name)[1] in ('desc','depends'):
+ fname = os.path.split(tarinfo.name)[1]
+ if fname in dbfiles:
tpkg.write(repodb.extractfile(tarinfo).read())
tpkg.write('\n') # just in case
repodb.close()
@@ -353,11 +386,10 @@ def read_repo(primary_arch, file, options):
logger.warning("Package %s arch = %s" % (
package.name,package.arch))
#package.arch = primary_arch
- f = options.get('force', False)
logger.info('Starting database updates.')
for (arch, pkgs) in packages_arches.items():
if len(pkgs) > 0:
- db_update(arch, pkgs, f)
+ db_update(arch, pkgs, options)
logger.info('Finished database updates.')
return 0
diff --git a/main/migrations/0007_add_files_last_update.py b/main/migrations/0007_add_files_last_update.py
new file mode 100644
index 00000000..36f99c26
--- /dev/null
+++ b/main/migrations/0007_add_files_last_update.py
@@ -0,0 +1,193 @@
+from south.db import db
+from django.db import models
+from main.models import *
+
+class Migration:
+ def forwards(self, orm):
+ # Adding field 'Package.files_last_update'
+ db.add_column('packages', 'files_last_update', orm['main.package:files_last_update'])
+
+ def backwards(self, orm):
+ # Deleting field 'Package.files_last_update'
+ db.delete_column('packages', 'files_last_update')
+
+ models = {
+ 'auth.group': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'unique_together': "(('content_type', 'codename'),)"},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'unique_together': "(('app_label', 'model'),)", 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'main.altforum': {
+ 'Meta': {'db_table': "'alt_forums'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'language': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.arch': {
+ 'Meta': {'db_table': "'arches'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.donor': {
+ 'Meta': {'db_table': "'donors'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.externalproject': {
+ 'description': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'main.mirror': {
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'admin_email': ('django.db.models.fields.EmailField', [], {'max_length': '255', 'blank': 'True'}),
+ 'country': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'isos': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'notes': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'public': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'})
+ },
+ 'main.mirrorprotocol': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'protocol': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '10'})
+ },
+ 'main.mirrorrsync': {
+ 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip': ('django.db.models.fields.CharField', [], {'max_length': '24'}),
+ 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'rsync_ips'", 'to': "orm['main.Mirror']"})
+ },
+ 'main.mirrorurl': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mirror': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.Mirror']"}),
+ 'protocol': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'urls'", 'to': "orm['main.MirrorProtocol']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.news': {
+ 'Meta': {'db_table': "'news'"},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'news_author'", 'to': "orm['auth.User']"}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'postdate': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.package': {
+ 'Meta': {'db_table': "'packages'"},
+ 'arch': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Arch']"}),
+ 'build_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'compressed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'files_last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'installed_size': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True'}),
+ 'last_update': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'license': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'maintainer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'maintained_packages'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'needupdate': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'pkgbase': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'pkgdesc': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'repo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'packages'", 'to': "orm['main.Repo']"}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.packagedepend': {
+ 'Meta': {'db_table': "'package_depends'"},
+ 'depname': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'depvcmp': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.packagefile': {
+ 'Meta': {'db_table': "'package_files'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'path': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.press': {
+ 'Meta': {'db_table': "'press'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.repo': {
+ 'Meta': {'db_table': "'repos'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'})
+ },
+ 'main.signoff': {
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'packager': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"}),
+ 'pkgrel': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
+ 'pkgver': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.todolist': {
+ 'Meta': {'db_table': "'todolists'"},
+ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'description': ('django.db.models.fields.TextField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'main.todolistpkg': {
+ 'Meta': {'unique_together': "(('list', 'pkg'),)", 'db_table': "'todolist_pkgs'"},
+ 'complete': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'list': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Todolist']"}),
+ 'pkg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Package']"})
+ },
+ 'main.userprofile': {
+ 'Meta': {'db_table': "'user_profiles'"},
+ 'alias': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'allowed_repos': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Repo']", 'blank': 'True'}),
+ 'favorite_distros': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'interests': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'languages': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'notify': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'blank': 'True'}),
+ 'occupation': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'other_contact': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'picture': ('django.db.models.fields.files.FileField', [], {'default': "'devs/silhouette.png'", 'max_length': '100'}),
+ 'public_email': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'roles': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'userprofile_user'", 'unique': 'True', 'to': "orm['auth.User']"}),
+ 'website': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'yob': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['main']
diff --git a/main/models.py b/main/models.py
index 373c3e00..dd37f885 100644
--- a/main/models.py
+++ b/main/models.py
@@ -174,6 +174,7 @@ class Package(models.Model):
installed_size = models.PositiveIntegerField(null=True)
build_date = models.DateTimeField(null=True)
last_update = models.DateTimeField(null=True, blank=True)
+ files_last_update = models.DateTimeField(null=True, blank=True)
license = models.CharField(max_length=255)
objects = PackageManager()
class Meta:
diff --git a/packages/views.py b/packages/views.py
index 97929ed3..8a2b4ec3 100644
--- a/packages/views.py
+++ b/packages/views.py
@@ -7,6 +7,7 @@ from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
from django.contrib.auth.decorators import permission_required
from django.contrib.admin.widgets import AdminDateWidget
+from django.views.decorators.vary import vary_on_headers
from django.views.generic import list_detail
from django.db.models import Q
@@ -60,7 +61,7 @@ def update(request):
def details(request, name='', repo='', arch=''):
if all([name, repo, arch]):
- pkg= get_object_or_404(Package,
+ pkg = get_object_or_404(Package,
pkgname=name, repo__name__iexact=repo, arch__name=arch)
return render_to_response('packages/details.html', RequestContext(
request, {'pkg': pkg, }))
@@ -178,10 +179,15 @@ def search(request, page=None):
template_object_name="package",
extra_context=page_dict)
-def files(request, pkgid):
- pkg = get_object_or_404(Package, id=pkgid)
- files = PackageFile.objects.filter(pkg=pkgid)
- return render_to_response('packages/files.html', RequestContext(request, {'pkg':pkg,'files':files}))
+@vary_on_headers('X-Requested-With')
+def files(request, name='', repo='', arch=''):
+ pkg = get_object_or_404(Package,
+ pkgname=name, repo__name__iexact=repo, arch__name=arch)
+ files = PackageFile.objects.filter(pkg=pkg).order_by('path')
+ template = 'packages/files.html'
+ if request.is_ajax():
+ template = 'packages/files-list.html'
+ return render_to_response(template, RequestContext(request, {'pkg':pkg,'files':files}))
@permission_required('main.change_package')
def unflag(request, pkgid):
diff --git a/templates/packages/details.html b/templates/packages/details.html
index 5c3c9497..94e9f161 100644
--- a/templates/packages/details.html
+++ b/templates/packages/details.html
@@ -1,6 +1,5 @@
{% extends "base.html" %}
-{% load package_extras %}
-{% block title %}Pkg: {{ pkg.pkgname }} - Arch Linux Package Details{% endblock %}
+{% block title %}Arch Linux - Package Details - {{ pkg.pkgname }}{% endblock %}
{% block content %}
<div class="box">
<h2 class="title">{{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }}</h2>
@@ -9,7 +8,6 @@
<li><a href="{{ pkg.get_arch_svn_link }}">SVN Entries ({{pkg.repo|lower}}-{{pkg.arch}})</a></li>
<li><a href="{{ pkg.get_trunk_svn_link }}">SVN Entries (trunk)</a></li>
<li><a href="{{ pkg.get_bugs_link }}">Bug Reports</a></li>
- <!-- <li><a href="/packages/files/{{ pkg.id }}/">View File List</a></li> -->
<li>
{% if pkg.needupdate %}
<span style="font-size:x-small"><em>This package has been flagged out-of-date</em></span>
@@ -103,6 +101,24 @@
</td>
</tr>
</table>
+ <div class="listing" id="filelist">
+ <h4>Files:</h4>
+ <p style="padding: 10px 20px;">
+ <a id="filelink" href="files/">View File List</a>
+ </p>
+ </div>
</div>
+<script type="text/javascript" src="/media/jquery-1.4.1.min.js"></script>
+<script type="text/javascript">
+function ajaxifyFiles() {
+ $('#filelink').click(function(event) {
+ event.preventDefault();
+ $.get(this.href, function(data) {
+ $('#filelist').html(data);
+ });
+ });
+}
+$(document).ready(ajaxifyFiles);
+</script>
{% endblock %}
diff --git a/templates/packages/files-list.html b/templates/packages/files-list.html
new file mode 100644
index 00000000..d26a11e9
--- /dev/null
+++ b/templates/packages/files-list.html
@@ -0,0 +1,12 @@
+<div class="listing" id="filelist">
+ <h4>Files:</h4>
+ {% if files.count %}
+ <ul style="font-size:small;list-style:none">
+ {% for file in files %}
+ <li>{{ file.path }}</li>
+ {% endfor %}
+ </ul>
+ {% else %}
+ <p style="padding: 10px 20px;">No filelist available.</p>
+ {% endif %}
+</div>
diff --git a/templates/packages/files.html b/templates/packages/files.html
index 145bcf24..1d87246c 100644
--- a/templates/packages/files.html
+++ b/templates/packages/files.html
@@ -1,11 +1,9 @@
{% extends "base.html" %}
-{% block title %}Pkg: {{ pkg.pkgname }} - Arch Linux Package File List{% endblock %}
+{% block title %}Arch Linux - Package File List - {{ pkg.pkgname }}{% endblock %}
{% block content %}
<div class="box">
- <h3>Viewing Files: {{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }}</h3>
- {% for file in files %}
- {{ file.path }}<br />
- {% endfor %}
+ <h2 class="title">{{ pkg.pkgname }} {{ pkg.pkgver }}-{{ pkg.pkgrel }}</h2>
+ {% include "packages/files-list.html" %}
</div>
{% endblock %}
diff --git a/todolists/views.py b/todolists/views.py
index a38ec0d7..8358e4c6 100644
--- a/todolists/views.py
+++ b/todolists/views.py
@@ -5,6 +5,7 @@ from django.template import RequestContext
from django.core.mail import send_mail
from django.shortcuts import get_object_or_404, render_to_response
from django.contrib.auth.decorators import login_required, permission_required
+from django.views.decorators.vary import vary_on_headers
from django.views.generic.create_update import delete_object
from django.template import Context, loader
from django.utils import simplejson
@@ -31,6 +32,7 @@ class TodoListForm(forms.Form):
@login_required
+@vary_on_headers('X-Requested-With')
def flag(request, listid, pkgid):
list = get_object_or_404(Todolist, id=listid)
pkg = get_object_or_404(TodolistPkg, id=pkgid)
diff --git a/urls.py b/urls.py
index ec04edce..e53d918a 100644
--- a/urls.py
+++ b/urls.py
@@ -27,7 +27,6 @@ urlpatterns = patterns('',
(r'^packages/flag/(\d+)/$', 'packages.views.flag'),
(r'^packages/flaghelp/$', 'packages.views.flaghelp'),
(r'^packages/unflag/(\d+)/$', 'packages.views.unflag'),
- (r'^packages/files/(\d+)/$', 'packages.views.files'),
(r'^packages/signoffs/$', 'packages.views.signoffs'),
(r'^packages/signoff_package/(?P<arch>[A-z0-9]+)/(?P<pkgname>[A-z0-9\-+.]+)/$',
'packages.views.signoff_package'),
@@ -46,6 +45,8 @@ urlpatterns = patterns('',
'packages.views.details'),
(r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/$',
'packages.views.details'),
+ (r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/files/$',
+ 'packages.views.files'),
(r'^packages/(?P<repo>[A-z0-9\-]+)/(?P<arch>[A-z0-9]+)/(?P<name>[A-z0-9\-+.]+)/maintainer/$',
'packages.views.getmaintainer'),