summaryrefslogtreecommitdiff
path: root/releng
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2011-04-28 18:01:01 -0500
committerDan McGee <dan@archlinux.org>2011-04-28 18:01:01 -0500
commitb87a2c4864db79b29df1e2ea3ac3c3c2759f05fa (patch)
tree97defc7569c5e52161681576296ba90bff47f62a /releng
parent174d04ad0334b1c441bc0237e3e2ed8f581575ef (diff)
parent461d27d75ffb36ad4e7f428b8b6722ae1d3afb98 (diff)
Merge branch 'releng'
Diffstat (limited to 'releng')
-rw-r--r--releng/__init__.py0
-rw-r--r--releng/admin.py18
-rw-r--r--releng/fixtures/architecture.json30
-rw-r--r--releng/fixtures/bootloaders.json23
-rw-r--r--releng/fixtures/boottype.json23
-rw-r--r--releng/fixtures/clockchoices.json23
-rw-r--r--releng/fixtures/filesystems.json23
-rw-r--r--releng/fixtures/hardware.json44
-rw-r--r--releng/fixtures/installtype.json30
-rw-r--r--releng/fixtures/isotypes.json16
-rw-r--r--releng/fixtures/modules.json86
-rw-r--r--releng/fixtures/source.json23
-rw-r--r--releng/management/__init__.py0
-rw-r--r--releng/management/commands/__init__.py0
-rw-r--r--releng/management/commands/syncisos.py48
-rw-r--r--releng/migrations/0001_initial.py258
-rw-r--r--releng/migrations/__init__.py0
-rw-r--r--releng/models.py121
-rw-r--r--releng/urls.py11
-rw-r--r--releng/views.py132
20 files changed, 909 insertions, 0 deletions
diff --git a/releng/__init__.py b/releng/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/releng/__init__.py
diff --git a/releng/admin.py b/releng/admin.py
new file mode 100644
index 00000000..10acaa98
--- /dev/null
+++ b/releng/admin.py
@@ -0,0 +1,18 @@
+from django.contrib import admin
+
+from .models import (Architecture, BootType, Bootloader, ClockChoice,
+ Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source)
+
+admin.site.register(Iso)
+admin.site.register(Architecture)
+admin.site.register(IsoType)
+admin.site.register(BootType)
+admin.site.register(HardwareType)
+admin.site.register(InstallType)
+admin.site.register(Source)
+admin.site.register(ClockChoice)
+admin.site.register(Filesystem)
+admin.site.register(Module)
+admin.site.register(Bootloader)
+
+# vim: set ts=4 sw=4 et:
diff --git a/releng/fixtures/architecture.json b/releng/fixtures/architecture.json
new file mode 100644
index 00000000..0bf9b8bf
--- /dev/null
+++ b/releng/fixtures/architecture.json
@@ -0,0 +1,30 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.architecture",
+ "fields": {
+ "name": "dual, option i686"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.architecture",
+ "fields": {
+ "name": "dual, option x86_64"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.architecture",
+ "fields": {
+ "name": "i686"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "releng.architecture",
+ "fields": {
+ "name": "x86_64"
+ }
+ }
+]
diff --git a/releng/fixtures/bootloaders.json b/releng/fixtures/bootloaders.json
new file mode 100644
index 00000000..bee02f2b
--- /dev/null
+++ b/releng/fixtures/bootloaders.json
@@ -0,0 +1,23 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.bootloader",
+ "fields": {
+ "name": "grub"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.bootloader",
+ "fields": {
+ "name": "syslinux"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.bootloader",
+ "fields": {
+ "name": "other/manual"
+ }
+ }
+]
diff --git a/releng/fixtures/boottype.json b/releng/fixtures/boottype.json
new file mode 100644
index 00000000..ed4636eb
--- /dev/null
+++ b/releng/fixtures/boottype.json
@@ -0,0 +1,23 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.boottype",
+ "fields": {
+ "name": "optical"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.boottype",
+ "fields": {
+ "name": "usb"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.boottype",
+ "fields": {
+ "name": "pxe"
+ }
+ }
+]
diff --git a/releng/fixtures/clockchoices.json b/releng/fixtures/clockchoices.json
new file mode 100644
index 00000000..f328801a
--- /dev/null
+++ b/releng/fixtures/clockchoices.json
@@ -0,0 +1,23 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.clockchoice",
+ "fields": {
+ "name": "unchanged"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.clockchoice",
+ "fields": {
+ "name": "configured manually"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.clockchoice",
+ "fields": {
+ "name": "NTP"
+ }
+ }
+]
diff --git a/releng/fixtures/filesystems.json b/releng/fixtures/filesystems.json
new file mode 100644
index 00000000..208f5c73
--- /dev/null
+++ b/releng/fixtures/filesystems.json
@@ -0,0 +1,23 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.filesystem",
+ "fields": {
+ "name": "autoprepare"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.filesystem",
+ "fields": {
+ "name": "manual"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.filesystem",
+ "fields": {
+ "name": "from config file"
+ }
+ }
+]
diff --git a/releng/fixtures/hardware.json b/releng/fixtures/hardware.json
new file mode 100644
index 00000000..a2bb9ec0
--- /dev/null
+++ b/releng/fixtures/hardware.json
@@ -0,0 +1,44 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "virtualbox"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "qemu"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "intel i686"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "intel x86_64"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "amd i686"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "releng.hardwaretype",
+ "fields": {
+ "name": "amd x86_64"
+ }
+ }
+]
diff --git a/releng/fixtures/installtype.json b/releng/fixtures/installtype.json
new file mode 100644
index 00000000..7fa21fc1
--- /dev/null
+++ b/releng/fixtures/installtype.json
@@ -0,0 +1,30 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.installtype",
+ "fields": {
+ "name": "interactive install"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.installtype",
+ "fields": {
+ "name": "automatic install generic example"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.installtype",
+ "fields": {
+ "name": "automatic install fancy example"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "releng.installtype",
+ "fields": {
+ "name": "automatic install custom config (specify in comments)"
+ }
+ }
+]
diff --git a/releng/fixtures/isotypes.json b/releng/fixtures/isotypes.json
new file mode 100644
index 00000000..a529b181
--- /dev/null
+++ b/releng/fixtures/isotypes.json
@@ -0,0 +1,16 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.isotype",
+ "fields": {
+ "name": "core"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.isotype",
+ "fields": {
+ "name": "net"
+ }
+ }
+]
diff --git a/releng/fixtures/modules.json b/releng/fixtures/modules.json
new file mode 100644
index 00000000..9cdf1a8d
--- /dev/null
+++ b/releng/fixtures/modules.json
@@ -0,0 +1,86 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.module",
+ "fields": {
+ "name": "lvm2"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.module",
+ "fields": {
+ "name": "dm_crypt"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.module",
+ "fields": {
+ "name": "softraid"
+ }
+ },
+ {
+ "pk": 4,
+ "model": "releng.module",
+ "fields": {
+ "name": "nilfs2"
+ }
+ },
+ {
+ "pk": 5,
+ "model": "releng.module",
+ "fields": {
+ "name": "btrfs"
+ }
+ },
+ {
+ "pk": 6,
+ "model": "releng.module",
+ "fields": {
+ "name": "ext2"
+ }
+ },
+ {
+ "pk": 7,
+ "model": "releng.module",
+ "fields": {
+ "name": "ext3"
+ }
+ },
+ {
+ "pk": 8,
+ "model": "releng.module",
+ "fields": {
+ "name": "ext4"
+ }
+ },
+ {
+ "pk": 9,
+ "model": "releng.module",
+ "fields": {
+ "name": "swap"
+ }
+ },
+ {
+ "pk": 10,
+ "model": "releng.module",
+ "fields": {
+ "name": "xfs"
+ }
+ },
+ {
+ "pk": 11,
+ "model": "releng.module",
+ "fields": {
+ "name": "jfs"
+ }
+ },
+ {
+ "pk": 12,
+ "model": "releng.module",
+ "fields": {
+ "name": "reiserFS"
+ }
+ }
+]
diff --git a/releng/fixtures/source.json b/releng/fixtures/source.json
new file mode 100644
index 00000000..2622f4c1
--- /dev/null
+++ b/releng/fixtures/source.json
@@ -0,0 +1,23 @@
+[
+ {
+ "pk": 1,
+ "model": "releng.source",
+ "fields": {
+ "name": "net install manual networking config (Check that it works + rc.conf, resolv.conf, mirrorlist)"
+ }
+ },
+ {
+ "pk": 2,
+ "model": "releng.source",
+ "fields": {
+ "name": "net install dhcp (Check that it works + rc.conf)"
+ }
+ },
+ {
+ "pk": 3,
+ "model": "releng.source",
+ "fields": {
+ "name": "core"
+ }
+ }
+]
diff --git a/releng/management/__init__.py b/releng/management/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/releng/management/__init__.py
diff --git a/releng/management/commands/__init__.py b/releng/management/commands/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/releng/management/commands/__init__.py
diff --git a/releng/management/commands/syncisos.py b/releng/management/commands/syncisos.py
new file mode 100644
index 00000000..247b01cd
--- /dev/null
+++ b/releng/management/commands/syncisos.py
@@ -0,0 +1,48 @@
+import re
+import urllib
+from HTMLParser import HTMLParser, HTMLParseError
+
+from django.conf import settings
+from django.core.management.base import BaseCommand, CommandError
+
+from releng.models import Iso
+
+class IsoListParser(HTMLParser):
+ def __init__(self):
+ HTMLParser.__init__(self)
+
+ self.hyperlinks = []
+ self.url_re = re.compile('(?!\.{2})/$')
+
+ def handle_starttag(self, tag, attrs):
+ if tag == 'a':
+ for name, value in attrs:
+ if name == "href":
+ if value != '../' and self.url_re.search(value) != None:
+ self.hyperlinks.append(value[:len(value)-1])
+
+ def parse(self, url):
+ try:
+ remote_file = urllib.urlopen(url)
+ data = remote_file.read()
+ remote_file.close()
+ self.feed(data)
+ self.close()
+ return self.hyperlinks
+ except HTMLParseError:
+ raise CommandError('Couldn\'t parse "%s"' % url)
+
+class Command(BaseCommand):
+ help = 'Gets new isos from %s' % settings.ISO_LIST_URL
+
+ def handle(self, *args, **options):
+ parser = IsoListParser()
+ isonames = Iso.objects.values_list('name', flat=True)
+ new_isos = parser.parse(settings.ISO_LIST_URL)
+
+ for iso in new_isos:
+ if iso not in isonames:
+ new = Iso(name=iso)
+ new.save()
+
+# vim: set ts=4 sw=4 et:
diff --git a/releng/migrations/0001_initial.py b/releng/migrations/0001_initial.py
new file mode 100644
index 00000000..91fab8b7
--- /dev/null
+++ b/releng/migrations/0001_initial.py
@@ -0,0 +1,258 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Iso'
+ db.create_table('releng_iso', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
+ ('created', self.gf('django.db.models.fields.DateTimeField')()),
+ ('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('releng', ['Iso'])
+
+ # Adding model 'Architecture'
+ db.create_table('releng_architecture', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['Architecture'])
+
+ # Adding model 'IsoType'
+ db.create_table('releng_isotype', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['IsoType'])
+
+ # Adding model 'BootType'
+ db.create_table('releng_boottype', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['BootType'])
+
+ # Adding model 'HardwareType'
+ db.create_table('releng_hardwaretype', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['HardwareType'])
+
+ # Adding model 'InstallType'
+ db.create_table('releng_installtype', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['InstallType'])
+
+ # Adding model 'Source'
+ db.create_table('releng_source', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['Source'])
+
+ # Adding model 'ClockChoice'
+ db.create_table('releng_clockchoice', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['ClockChoice'])
+
+ # Adding model 'Filesystem'
+ db.create_table('releng_filesystem', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['Filesystem'])
+
+ # Adding model 'Module'
+ db.create_table('releng_module', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['Module'])
+
+ # Adding model 'Bootloader'
+ db.create_table('releng_bootloader', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('name', self.gf('django.db.models.fields.CharField')(max_length=200)),
+ ))
+ db.send_create_signal('releng', ['Bootloader'])
+
+ # Adding model 'Test'
+ db.create_table('releng_test', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user_name', self.gf('django.db.models.fields.CharField')(max_length=500)),
+ ('user_email', self.gf('django.db.models.fields.EmailField')(max_length=75)),
+ ('ip_address', self.gf('django.db.models.fields.IPAddressField')(max_length=15)),
+ ('created', self.gf('django.db.models.fields.DateTimeField')()),
+ ('iso', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Iso'])),
+ ('architecture', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Architecture'])),
+ ('iso_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.IsoType'])),
+ ('boot_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.BootType'])),
+ ('hardware_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.HardwareType'])),
+ ('install_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.InstallType'])),
+ ('source', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Source'])),
+ ('clock_choice', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.ClockChoice'])),
+ ('filesystem', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Filesystem'])),
+ ('bootloader', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['releng.Bootloader'])),
+ ('rollback_filesystem', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='rollback_test_set', null=True, to=orm['releng.Filesystem'])),
+ ('success', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('comments', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('releng', ['Test'])
+
+ # Adding M2M table for field modules on 'Test'
+ db.create_table('releng_test_modules', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('test', models.ForeignKey(orm['releng.test'], null=False)),
+ ('module', models.ForeignKey(orm['releng.module'], null=False))
+ ))
+ db.create_unique('releng_test_modules', ['test_id', 'module_id'])
+
+ # Adding M2M table for field rollback_modules on 'Test'
+ db.create_table('releng_test_rollback_modules', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('test', models.ForeignKey(orm['releng.test'], null=False)),
+ ('module', models.ForeignKey(orm['releng.module'], null=False))
+ ))
+ db.create_unique('releng_test_rollback_modules', ['test_id', 'module_id'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'Iso'
+ db.delete_table('releng_iso')
+
+ # Deleting model 'Architecture'
+ db.delete_table('releng_architecture')
+
+ # Deleting model 'IsoType'
+ db.delete_table('releng_isotype')
+
+ # Deleting model 'BootType'
+ db.delete_table('releng_boottype')
+
+ # Deleting model 'HardwareType'
+ db.delete_table('releng_hardwaretype')
+
+ # Deleting model 'InstallType'
+ db.delete_table('releng_installtype')
+
+ # Deleting model 'Source'
+ db.delete_table('releng_source')
+
+ # Deleting model 'ClockChoice'
+ db.delete_table('releng_clockchoice')
+
+ # Deleting model 'Filesystem'
+ db.delete_table('releng_filesystem')
+
+ # Deleting model 'Module'
+ db.delete_table('releng_module')
+
+ # Deleting model 'Bootloader'
+ db.delete_table('releng_bootloader')
+
+ # Deleting model 'Test'
+ db.delete_table('releng_test')
+
+ # Removing M2M table for field modules on 'Test'
+ db.delete_table('releng_test_modules')
+
+ # Removing M2M table for field rollback_modules on 'Test'
+ db.delete_table('releng_test_rollback_modules')
+
+
+ models = {
+ 'releng.architecture': {
+ 'Meta': {'object_name': 'Architecture'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.bootloader': {
+ 'Meta': {'object_name': 'Bootloader'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.boottype': {
+ 'Meta': {'object_name': 'BootType'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.clockchoice': {
+ 'Meta': {'object_name': 'ClockChoice'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.filesystem': {
+ 'Meta': {'object_name': 'Filesystem'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.hardwaretype': {
+ 'Meta': {'object_name': 'HardwareType'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.installtype': {
+ 'Meta': {'object_name': 'InstallType'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.iso': {
+ 'Meta': {'object_name': 'Iso'},
+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'})
+ },
+ 'releng.isotype': {
+ 'Meta': {'object_name': 'IsoType'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.module': {
+ 'Meta': {'object_name': 'Module'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.source': {
+ 'Meta': {'object_name': 'Source'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'})
+ },
+ 'releng.test': {
+ 'Meta': {'object_name': 'Test'},
+ 'architecture': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Architecture']"}),
+ 'boot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.BootType']"}),
+ 'bootloader': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Bootloader']"}),
+ 'clock_choice': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.ClockChoice']"}),
+ 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'created': ('django.db.models.fields.DateTimeField', [], {}),
+ 'filesystem': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Filesystem']"}),
+ 'hardware_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.HardwareType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'install_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.InstallType']"}),
+ 'ip_address': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'iso': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Iso']"}),
+ 'iso_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.IsoType']"}),
+ 'modules': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['releng.Module']", 'null': 'True', 'blank': 'True'}),
+ 'rollback_filesystem': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'rollback_test_set'", 'null': 'True', 'to': "orm['releng.Filesystem']"}),
+ 'rollback_modules': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'rollback_test_set'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['releng.Module']"}),
+ 'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['releng.Source']"}),
+ 'success': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'user_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}),
+ 'user_name': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['releng']
diff --git a/releng/migrations/__init__.py b/releng/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/releng/migrations/__init__.py
diff --git a/releng/models.py b/releng/models.py
new file mode 100644
index 00000000..dc297d5b
--- /dev/null
+++ b/releng/models.py
@@ -0,0 +1,121 @@
+from datetime import datetime
+
+from django.db import models
+from django.db.models import Max
+
+class IsoOption(models.Model):
+ name = models.CharField(max_length=200)
+
+ def __unicode__(self):
+ return self.name
+
+ def get_test_result(self, success):
+ try:
+ return self.test_set.filter(success=success).select_related(
+ 'iso').latest('iso__id').iso
+ except Test.DoesNotExist:
+ return None
+
+ def get_last_success(self):
+ return self.get_test_result(True)
+
+ def get_last_failure(self):
+ return self.get_test_result(False)
+
+ class Meta:
+ abstract = True
+
+class RollbackOption(IsoOption):
+ def get_rollback_test_result(self, success):
+ try:
+ return self.rollback_test_set.filter(success=success).select_related(
+ 'iso').latest('iso__id').iso
+ except Test.DoesNotExist:
+ return None
+
+ def get_last_rollback_success(self):
+ return self.get_rollback_test_result(True)
+
+ def get_last_rollback_failure(self):
+ return self.get_rollback_test_result(False)
+
+ class Meta:
+ abstract = True
+
+class Iso(models.Model):
+ name = models.CharField(max_length=255)
+ created = models.DateTimeField(editable=False)
+ active = models.BooleanField(default=True)
+
+ def __unicode__(self):
+ return self.name
+
+class Architecture(IsoOption):
+ pass
+
+class IsoType(IsoOption):
+ pass
+
+class BootType(IsoOption):
+ pass
+
+class HardwareType(IsoOption):
+ pass
+
+class InstallType(IsoOption):
+ pass
+
+class Source(IsoOption):
+ pass
+
+class ClockChoice(IsoOption):
+ pass
+
+class Filesystem(RollbackOption):
+ pass
+
+class Module(RollbackOption):
+ pass
+
+class Bootloader(IsoOption):
+ pass
+
+class Test(models.Model):
+ user_name = models.CharField(max_length=500)
+ user_email = models.EmailField()
+ ip_address = models.IPAddressField()
+ created = models.DateTimeField(editable=False)
+
+ iso = models.ForeignKey(Iso)
+ architecture = models.ForeignKey(Architecture)
+ iso_type = models.ForeignKey(IsoType)
+ boot_type = models.ForeignKey(BootType)
+ hardware_type = models.ForeignKey(HardwareType)
+ install_type = models.ForeignKey(InstallType)
+ source = models.ForeignKey(Source)
+ clock_choice = models.ForeignKey(ClockChoice)
+ filesystem = models.ForeignKey(Filesystem)
+ modules = models.ManyToManyField(Module, null=True, blank=True)
+ bootloader = models.ForeignKey(Bootloader)
+ rollback_filesystem = models.ForeignKey(Filesystem,
+ related_name="rollback_test_set", null=True, blank=True)
+ rollback_modules = models.ManyToManyField(Module,
+ related_name="rollback_test_set", null=True, blank=True)
+
+ success = models.BooleanField()
+ comments = models.TextField(null=True, blank=True)
+
+def set_created_field(sender, **kwargs):
+ # We use this same callback for both Isos and Tests
+ obj = kwargs['instance']
+ if not obj.created:
+ obj.created = datetime.utcnow()
+
+from django.db.models.signals import pre_save
+
+pre_save.connect(set_created_field, sender=Iso,
+ dispatch_uid="releng.models")
+pre_save.connect(set_created_field, sender=Test,
+ dispatch_uid="releng.models")
+
+# vim: set ts=4 sw=4 et:
diff --git a/releng/urls.py b/releng/urls.py
new file mode 100644
index 00000000..f76a9593
--- /dev/null
+++ b/releng/urls.py
@@ -0,0 +1,11 @@
+from django.conf.urls.defaults import patterns
+
+urlpatterns = patterns('releng.views',
+ (r'^$', 'test_results_overview', {}, 'releng-test-overview'),
+ (r'^submit/$', 'submit_test_result', {}, 'releng-test-submit'),
+ (r'^thanks/$', 'submit_test_thanks', {}, 'releng-test-thanks'),
+ (r'^iso/(?P<iso_id>\d+)/$', 'test_results_iso', {}, 'releng-results-iso'),
+ (r'^(?P<option>.+)/(?P<value>\d+)/$','test_results_for', {}, 'releng-results-for'),
+)
+
+# vim: set ts=4 sw=4 et:
diff --git a/releng/views.py b/releng/views.py
new file mode 100644
index 00000000..5cffb2f5
--- /dev/null
+++ b/releng/views.py
@@ -0,0 +1,132 @@
+from django import forms
+from django.conf import settings
+from django.http import Http404
+from django.shortcuts import get_object_or_404, redirect
+from django.views.generic.simple import direct_to_template
+
+from .models import (Architecture, BootType, Bootloader, ClockChoice,
+ Filesystem, HardwareType, InstallType, Iso, IsoType, Module, Source,
+ Test)
+
+def standard_field(model, help_text=None):
+ return forms.ModelChoiceField(queryset=model.objects.all(),
+ widget=forms.RadioSelect(), empty_label=None, help_text=help_text)
+
+class TestForm(forms.ModelForm):
+ iso = forms.ModelChoiceField(queryset=Iso.objects.filter(active=True))
+ architecture = standard_field(Architecture)
+ iso_type = standard_field(IsoType)
+ boot_type = standard_field(BootType)
+ hardware_type = standard_field(HardwareType)
+ install_type = standard_field(InstallType)
+ source = standard_field(Source)
+ clock_choice = standard_field(ClockChoice)
+ filesystem = standard_field(Filesystem,
+ help_text="Check the installed system, including fstab.")
+ modules = forms.ModelMultipleChoiceField(queryset=Module.objects.all(),
+ help_text="", widget=forms.CheckboxSelectMultiple(), required=False)
+ bootloader = standard_field(Bootloader)
+ rollback_filesystem = forms.ModelChoiceField(queryset=Filesystem.objects.all(),
+ help_text="If you did a rollback followed by a new attempt to setup " \
+ "your lockdevices/filesystems, select which option you took here.",
+ widget=forms.RadioSelect(), required=False)
+ rollback_modules = forms.ModelMultipleChoiceField(queryset=Module.objects.all(),
+ help_text="If you did a rollback followed b a new attempt to setup " \
+ "your lockdevices/filesystems, select which option you took here.",
+ widget=forms.CheckboxSelectMultiple(), required=False)
+ success = forms.BooleanField(help_text="Only check this if everything went fine. " \
+ "If you you ran into any errors please specify them in the " \
+ "comments.", required=False)
+ website = forms.CharField(label='',
+ widget=forms.TextInput(attrs={'style': 'display:none;'}), required=False)
+
+ class Meta:
+ model = Test
+ fields = ("user_name", "user_email", "iso", "architecture",
+ "iso_type", "boot_type", "hardware_type",
+ "install_type", "source", "clock_choice", "filesystem",
+ "modules", "bootloader", "rollback_filesystem",
+ "rollback_modules", "success", "comments")
+ widgets = {
+ "modules": forms.CheckboxSelectMultiple(),
+ }
+
+def submit_test_result(request):
+ if request.POST:
+ form = TestForm(request.POST)
+ if form.is_valid() and request.POST['website'] == '':
+ test = form.save(commit=False)
+ test.ip_address = request.META.get("REMOTE_ADDR", None)
+ test.save()
+ return redirect('releng-test-thanks')
+ else:
+ form = TestForm()
+
+ context = {'form': form}
+ return direct_to_template(request, 'releng/add.html', context)
+
+def calculate_option_overview(model, is_rollback=False):
+ option = {
+ 'option': model,
+ 'name': model._meta.verbose_name,
+ 'is_rollback': is_rollback,
+ 'values': []
+ }
+ for value in model.objects.all():
+ data = { 'value': value }
+ if is_rollback:
+ data['success'] = value.get_last_rollback_success()
+ data['failure'] = value.get_last_rollback_failure()
+ else:
+ data['success'] = value.get_last_success()
+ data['failure'] = value.get_last_failure()
+ option['values'].append(data)
+
+ return option
+
+def test_results_overview(request):
+ # data structure produced:
+ # [ { option, name, is_rollback, values: [ { value, success, failure } ... ] } ... ]
+ all_options = []
+ models = [ Architecture, IsoType, BootType, HardwareType, InstallType,
+ Source, ClockChoice, Filesystem, Module, Bootloader ]
+ for model in models:
+ all_options.append(calculate_option_overview(model))
+ # now handle rollback options
+ for model in [ Filesystem, Module ]:
+ all_options.append(calculate_option_overview(model, True))
+
+ print all_options
+ context = {
+ 'options': all_options,
+ 'iso_url': settings.ISO_LIST_URL,
+ }
+ return direct_to_template(request, 'releng/results.html', context)
+
+def test_results_iso(request, iso_id):
+ iso = get_object_or_404(Iso, pk=iso_id)
+ test_list = iso.test_set.all()
+ context = {
+ 'iso_name': iso.name,
+ 'test_list': test_list
+ }
+ return direct_to_template(request, 'releng/result_list.html', context)
+
+def test_results_for(request, option, value):
+ if option not in Test._meta.get_all_field_names():
+ raise Http404
+ option_model = getattr(Test, option).field.rel.to
+ real_value = get_object_or_404(option_model, pk=value)
+ test_list = real_value.test_set.order_by("iso__name", "pk")
+ context = {
+ 'option': option,
+ 'value': real_value,
+ 'value_id': value,
+ 'test_list': test_list
+ }
+ return direct_to_template(request, 'releng/result_list.html', context)
+
+def submit_test_thanks(request):
+ return direct_to_template(request, "releng/thanks.html", None)
+
+# vim: set ts=4 sw=4 et: