diff options
-rw-r--r-- | devel/management/commands/reporead.py | 90 | ||||
-rw-r--r-- | main/migrations/0007_add_files_last_update.py | 193 | ||||
-rw-r--r-- | main/models.py | 1 | ||||
-rw-r--r-- | packages/views.py | 16 | ||||
-rw-r--r-- | templates/packages/details.html | 22 | ||||
-rw-r--r-- | templates/packages/files-list.html | 12 | ||||
-rw-r--r-- | templates/packages/files.html | 8 | ||||
-rw-r--r-- | todolists/views.py | 2 | ||||
-rw-r--r-- | urls.py | 3 |
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) @@ -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'), |