diff options
author | Ask Solem <askh@modwheel.net> | 2009-03-17 10:24:12 +0100 |
---|---|---|
committer | Ask Solem Hoel <askh@opera.com> | 2009-03-17 10:24:12 +0100 |
commit | bce41a16d3e2004c9ecefedb7cff94ebf2955755 (patch) | |
tree | aecfc1fb44463a22de7226be9ffedbc43c7a34f1 | |
download | chishop-bce41a16d3e2004c9ecefedb7cff94ebf2955755.tar.bz2 chishop-bce41a16d3e2004c9ecefedb7cff94ebf2955755.tar.xz chishop-bce41a16d3e2004c9ecefedb7cff94ebf2955755.zip |
Initial checkin
-rw-r--r-- | __init__.py | 0 | ||||
-rw-r--r-- | djangopypi/__init__.py | 0 | ||||
-rw-r--r-- | djangopypi/admin.py | 5 | ||||
-rw-r--r-- | djangopypi/forms.py | 35 | ||||
-rw-r--r-- | djangopypi/models.py | 85 | ||||
-rw-r--r-- | djangopypi/templates/djangopypi/show_links.html | 8 | ||||
-rw-r--r-- | djangopypi/templates/djangopypi/show_version.html | 6 | ||||
-rw-r--r-- | djangopypi/templates/djangopypi/simple.html | 5 | ||||
-rw-r--r-- | djangopypi/views.py | 85 | ||||
-rw-r--r-- | manage.py | 11 | ||||
-rwxr-xr-x | media/_ | 0 | ||||
-rwxr-xr-x | media/dists/django-greystripe-0.1.tar.gz | bin | 0 -> 4653 bytes | |||
-rwxr-xr-x | media/foo.txt | 0 | ||||
-rw-r--r-- | settings.py | 91 | ||||
-rw-r--r-- | urls.py | 33 |
15 files changed, 364 insertions, 0 deletions
diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/__init__.py | |||
diff --git a/djangopypi/__init__.py b/djangopypi/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/djangopypi/__init__.py | |||
diff --git a/djangopypi/admin.py b/djangopypi/admin.py new file mode 100644 index 0000000..6e20fd3 --- /dev/null +++ b/djangopypi/admin.py | |||
@@ -0,0 +1,5 @@ | |||
1 | from django.contrib import admin | ||
2 | from djangopypi.models import Project, Release | ||
3 | |||
4 | admin.site.register(Project) | ||
5 | admin.site.register(Release) | ||
diff --git a/djangopypi/forms.py b/djangopypi/forms.py new file mode 100644 index 0000000..922301b --- /dev/null +++ b/djangopypi/forms.py | |||
@@ -0,0 +1,35 @@ | |||
1 | from django import forms | ||
2 | from djangopypi.models import Project, Classifier, Release | ||
3 | |||
4 | class ProjectRegisterForm(forms.Form): | ||
5 | name = forms.CharField() | ||
6 | license = forms.CharField(required=False) | ||
7 | metadata_version = forms.CharField(initial="1.0") | ||
8 | author = forms.CharField(required=False) | ||
9 | home_page = forms.CharField(required=False) | ||
10 | download_url = forms.CharField(required=False) | ||
11 | summary = forms.CharField(required=False) | ||
12 | description = forms.CharField(required=False) | ||
13 | author_email = forms.CharField(required=False) | ||
14 | version = forms.CharField() | ||
15 | platform = forms.CharField(required=False) | ||
16 | |||
17 | def save(self, classifiers, file=None): | ||
18 | values = dict(self.cleaned_data) | ||
19 | name = values.pop("name") | ||
20 | version = values.pop("version") | ||
21 | platform = values.pop("platform") | ||
22 | project, c = Project.objects.get_or_create(name=name, defaults=values) | ||
23 | for classifier in classifiers: | ||
24 | project.classifiers.add( | ||
25 | Classifier.objects.get_or_create(name=classifier)[0]) | ||
26 | release, c = Release.objects.get_or_create(version=version, | ||
27 | platform=platform, project=project) | ||
28 | if file: | ||
29 | release.distribution.save(file.name, file, save=True) | ||
30 | release.save() | ||
31 | |||
32 | |||
33 | |||
34 | |||
35 | |||
diff --git a/djangopypi/models.py b/djangopypi/models.py new file mode 100644 index 0000000..34276a5 --- /dev/null +++ b/djangopypi/models.py | |||
@@ -0,0 +1,85 @@ | |||
1 | import os | ||
2 | from django.db import models | ||
3 | from django.utils.translation import ugettext_lazy as _ | ||
4 | |||
5 | OS_NAMES = ( | ||
6 | ("aix", "AIX"), | ||
7 | ("beos", "BeOS"), | ||
8 | ("debian", "Debian Linux"), | ||
9 | ("dos", "DOS"), | ||
10 | ("freebsd", "FreeBSD"), | ||
11 | ("hpux", "HP/UX"), | ||
12 | ("mac", "Mac System x."), | ||
13 | ("macos", "MacOS X"), | ||
14 | ("mandrake", "Mandrake Linux"), | ||
15 | ("netbsd", "NetBSD"), | ||
16 | ("openbsd", "OpenBSD"), | ||
17 | ("qnx", "QNX"), | ||
18 | ("redhat", "RedHat Linux"), | ||
19 | ("solaris", "SUN Solaris"), | ||
20 | ("suse", "SuSE Linux"), | ||
21 | ("yellowdog", "Yellow Dog Linux"), | ||
22 | ) | ||
23 | |||
24 | ARCHITECTURES = ( | ||
25 | ("alpha", "Alpha"), | ||
26 | ("hppa", "HPPA"), | ||
27 | ("ix86", "Intel"), | ||
28 | ("powerpc", "PowerPC"), | ||
29 | ("sparc", "Sparc"), | ||
30 | ("ultrasparc", "UltraSparc"), | ||
31 | ) | ||
32 | |||
33 | class Classifier(models.Model): | ||
34 | name = models.CharField(max_length=255, unique=True) | ||
35 | |||
36 | class Meta: | ||
37 | verbose_name = _(u"classifier") | ||
38 | verbose_name_plural = _(u"classifiers") | ||
39 | |||
40 | def __unicode__(self): | ||
41 | return self.name | ||
42 | |||
43 | class Project(models.Model): | ||
44 | name = models.CharField(max_length=255, unique=True) | ||
45 | license = models.CharField(max_length=255, blank=True) | ||
46 | metadata_version = models.CharField(max_length=64, default=1.0) | ||
47 | author = models.CharField(max_length=128, blank=True) | ||
48 | home_page = models.URLField(verify_exists=False, blank=True, null=True) | ||
49 | download_url = models.URLField(verify_exists=False, blank=True, null=True) | ||
50 | summary = models.TextField(blank=True) | ||
51 | description = models.TextField(blank=True) | ||
52 | author_email = models.CharField(max_length=255, blank=True) | ||
53 | classifiers = models.ManyToManyField(Classifier) | ||
54 | |||
55 | class Meta: | ||
56 | verbose_name = _(u"project") | ||
57 | verbose_name_plural = _(u"projects") | ||
58 | |||
59 | def __unicode__(self): | ||
60 | return self.name | ||
61 | |||
62 | class Release(models.Model): | ||
63 | version = models.CharField(max_length=128) | ||
64 | distribution = models.FileField(upload_to="dists") | ||
65 | dist_md5sum = models.CharField(max_length=255, blank=True) | ||
66 | platform = models.CharField(max_length=255, blank=True) | ||
67 | signature = models.CharField(max_length=128, blank=True) | ||
68 | project = models.ForeignKey(Project, related_name="releases") | ||
69 | |||
70 | class Meta: | ||
71 | unique_together = ('version', 'platform') | ||
72 | verbose_name = _(u"release") | ||
73 | verbose_name_plural = _(u"releases") | ||
74 | |||
75 | def __unicode__(self): | ||
76 | return self.version | ||
77 | |||
78 | @property | ||
79 | def filename(self): | ||
80 | return os.path.basename(self.distribution.name) | ||
81 | |||
82 | @property | ||
83 | def path(self): | ||
84 | return self.distribution.name | ||
85 | |||
diff --git a/djangopypi/templates/djangopypi/show_links.html b/djangopypi/templates/djangopypi/show_links.html new file mode 100644 index 0000000..b805f47 --- /dev/null +++ b/djangopypi/templates/djangopypi/show_links.html | |||
@@ -0,0 +1,8 @@ | |||
1 | <html><head><title>Links for {{ dist_name }}</title></head><body> | ||
2 | <h1>Links for {{ dist_name }}</h1> | ||
3 | |||
4 | {% for release in releases %} | ||
5 | <a href="/media/{{ release.path }}#md5=release.dist_md5sum" | ||
6 | >{{ release.filename }}</a><br /> | ||
7 | {% endfor %} | ||
8 | </body></html> | ||
diff --git a/djangopypi/templates/djangopypi/show_version.html b/djangopypi/templates/djangopypi/show_version.html new file mode 100644 index 0000000..f0c9d75 --- /dev/null +++ b/djangopypi/templates/djangopypi/show_version.html | |||
@@ -0,0 +1,6 @@ | |||
1 | <html><head><title>Links for {{ dist_name }} {{ version }}</title></head><body> | ||
2 | <h1>Links for {{ dist_name }} {{ version }}</h1> | ||
3 | |||
4 | <a href="/media/{{ release.path }}#md5=release.dist_md5sum" | ||
5 | >{{ release.filename }}</a><br /> | ||
6 | </body></html> | ||
diff --git a/djangopypi/templates/djangopypi/simple.html b/djangopypi/templates/djangopypi/simple.html new file mode 100644 index 0000000..de761a5 --- /dev/null +++ b/djangopypi/templates/djangopypi/simple.html | |||
@@ -0,0 +1,5 @@ | |||
1 | <html><head><title>Simple Index</title></head></body> | ||
2 | {% for dist in dists %} | ||
3 | <a href="{{ dist.name }}"/>{{ dist.name }}</a><br /> | ||
4 | {% endfor %} | ||
5 | </body></html> | ||
diff --git a/djangopypi/views.py b/djangopypi/views.py new file mode 100644 index 0000000..90a9846 --- /dev/null +++ b/djangopypi/views.py | |||
@@ -0,0 +1,85 @@ | |||
1 | # Create your views here. | ||
2 | from django.http import HttpResponse, HttpResponseBadRequest, QueryDict | ||
3 | from django.shortcuts import render_to_response | ||
4 | from djangopypi.models import Project | ||
5 | from djangopypi.forms import ProjectRegisterForm | ||
6 | from django.template import RequestContext | ||
7 | from yadayada.utils import template_path_builder | ||
8 | from django.utils.datastructures import MultiValueDict | ||
9 | from django.core.files.uploadedfile import SimpleUploadedFile | ||
10 | |||
11 | T = template_path_builder("djangopypi") | ||
12 | |||
13 | |||
14 | def parse_weird_post_data(data): | ||
15 | sep = data.splitlines()[1] | ||
16 | items = data.split(sep) | ||
17 | post_data = {} | ||
18 | files = {} | ||
19 | for part in items: | ||
20 | if not part.strip(): | ||
21 | continue | ||
22 | item = part.splitlines() | ||
23 | if len(item) < 2: continue | ||
24 | header = item[1].replace("Content-Disposition: form-data; ", "") | ||
25 | kvpairs = header.split(";") | ||
26 | headers = {} | ||
27 | for kvpair in kvpairs: | ||
28 | if not kvpair: continue | ||
29 | key, value = kvpair.split("=") | ||
30 | headers[key] = value.strip('"') | ||
31 | if not "name" in headers: continue | ||
32 | content = part[len("\n".join(item[0:2]))+2:len(part)-1] | ||
33 | if "filename" in headers: | ||
34 | file = SimpleUploadedFile(headers["filename"], content, | ||
35 | content_type="application/gzip") | ||
36 | files[headers["name"]] = file | ||
37 | elif headers["name"] in post_data: | ||
38 | post_data[headers["name"]].append(content) | ||
39 | else: | ||
40 | post_data[headers["name"]] = [content] | ||
41 | |||
42 | return MultiValueDict(post_data), files | ||
43 | |||
44 | |||
45 | def simple(request, template_name=T("simple")): | ||
46 | if request.method == "POST": | ||
47 | post_data, files = parse_weird_post_data(request.raw_post_data) | ||
48 | action = post_data.get(":action") | ||
49 | classifiers = post_data.getlist("classifiers") | ||
50 | register_form = ProjectRegisterForm(post_data.copy()) | ||
51 | if register_form.is_valid(): | ||
52 | return HttpResponse(register_form.save(classifiers, | ||
53 | file=files.get("content"))) | ||
54 | return HttpResponse("Successfully registered.") | ||
55 | return HttpResponse("ERRORS: %s" % register_form.errors) | ||
56 | |||
57 | dists = Project.objects.all() | ||
58 | context = RequestContext(request, { | ||
59 | "dists": dists, | ||
60 | }) | ||
61 | |||
62 | return render_to_response(template_name, context_instance=context) | ||
63 | |||
64 | def show_links(request, dist_name, template_name=T("show_links")): | ||
65 | releases = Project.objects.get(name=dist_name) \ | ||
66 | .releases.all().order_by('-version') | ||
67 | |||
68 | context = RequestContext(request, { | ||
69 | "dist_name": dist_name, | ||
70 | "releases": releases, | ||
71 | }) | ||
72 | |||
73 | return render_to_response(template_name, context_instance=context) | ||
74 | |||
75 | def show_version(request, dist_name, version, template_name=T("show_version")): | ||
76 | release = Project.objects.get(name=dist_name).releases \ | ||
77 | .get(version=version) | ||
78 | |||
79 | context = RequestContext(request, { | ||
80 | "dist_name": dist_name, | ||
81 | "version": version, | ||
82 | "release": release, | ||
83 | }) | ||
84 | |||
85 | return render_to_response(template_name, context_instance=context) | ||
diff --git a/manage.py b/manage.py new file mode 100644 index 0000000..5e78ea9 --- /dev/null +++ b/manage.py | |||
@@ -0,0 +1,11 @@ | |||
1 | #!/usr/bin/env python | ||
2 | from django.core.management import execute_manager | ||
3 | try: | ||
4 | import settings # Assumed to be in the same directory. | ||
5 | except ImportError: | ||
6 | import sys | ||
7 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) | ||
8 | sys.exit(1) | ||
9 | |||
10 | if __name__ == "__main__": | ||
11 | execute_manager(settings) | ||
diff --git a/media/dists/django-greystripe-0.1.tar.gz b/media/dists/django-greystripe-0.1.tar.gz new file mode 100755 index 0000000..bef3dd7 --- /dev/null +++ b/media/dists/django-greystripe-0.1.tar.gz | |||
Binary files differ | |||
diff --git a/media/foo.txt b/media/foo.txt new file mode 100755 index 0000000..e69de29 --- /dev/null +++ b/media/foo.txt | |||
diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..8c18760 --- /dev/null +++ b/settings.py | |||
@@ -0,0 +1,91 @@ | |||
1 | # Django settings for djangopypi project. | ||
2 | import os | ||
3 | |||
4 | DEBUG = True | ||
5 | TEMPLATE_DEBUG = DEBUG | ||
6 | LOCAL_DEVELOPMENT = True | ||
7 | |||
8 | if LOCAL_DEVELOPMENT: | ||
9 | import os | ||
10 | import sys | ||
11 | sys.path.append(os.path.dirname(__file__)) | ||
12 | |||
13 | ADMINS = ( | ||
14 | # ('Your Name', 'your_email@domain.com'), | ||
15 | ) | ||
16 | |||
17 | MANAGERS = ADMINS | ||
18 | |||
19 | DATABASE_ENGINE = 'sqlite3' | ||
20 | DATABASE_NAME = 'devdatabase.db' | ||
21 | DATABASE_USER = '' | ||
22 | DATABASE_PASSWORD = '' | ||
23 | DATABASE_HOST = '' | ||
24 | DATABASE_PORT = '' | ||
25 | |||
26 | # Local time zone for this installation. Choices can be found here: | ||
27 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name | ||
28 | # although not all choices may be available on all operating systems. | ||
29 | # If running in a Windows environment this must be set to the same as your | ||
30 | # system time zone. | ||
31 | TIME_ZONE = 'America/Chicago' | ||
32 | |||
33 | # Language code for this installation. All choices can be found here: | ||
34 | # http://www.i18nguy.com/unicode/language-identifiers.html | ||
35 | LANGUAGE_CODE = 'en-us' | ||
36 | |||
37 | SITE_ID = 1 | ||
38 | |||
39 | # If you set this to False, Django will make some optimizations so as not | ||
40 | # to load the internationalization machinery. | ||
41 | USE_I18N = True | ||
42 | |||
43 | # Absolute path to the directory that holds media. | ||
44 | # Example: "/home/media/media.lawrence.com/" | ||
45 | here = os.path.abspath(os.path.dirname(__file__)) | ||
46 | MEDIA_ROOT = os.path.join(here, 'media') | ||
47 | |||
48 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a | ||
49 | # trailing slash if there is a path component (optional in other cases). | ||
50 | # Examples: "http://media.lawrence.com", "http://example.com/media/" | ||
51 | MEDIA_URL = 'media/' | ||
52 | |||
53 | MEDIA_PREFIX = "/media/" | ||
54 | |||
55 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a | ||
56 | # trailing slash. | ||
57 | # Examples: "http://foo.com/media/", "/media/". | ||
58 | ADMIN_MEDIA_PREFIX = '/admin-media/' | ||
59 | |||
60 | # Make this unique, and don't share it with anybody. | ||
61 | SECRET_KEY = 'w_#0r2hh)=!zbynb*gg&969@)sy#^-^ia3m*+sd4@lst$zyaxu' | ||
62 | |||
63 | # List of callables that know how to import templates from various sources. | ||
64 | TEMPLATE_LOADERS = ( | ||
65 | 'django.template.loaders.filesystem.load_template_source', | ||
66 | 'django.template.loaders.app_directories.load_template_source', | ||
67 | # 'django.template.loaders.eggs.load_template_source', | ||
68 | ) | ||
69 | |||
70 | MIDDLEWARE_CLASSES = ( | ||
71 | 'django.middleware.common.CommonMiddleware', | ||
72 | 'django.contrib.sessions.middleware.SessionMiddleware', | ||
73 | 'django.contrib.auth.middleware.AuthenticationMiddleware', | ||
74 | ) | ||
75 | |||
76 | ROOT_URLCONF = 'urls' | ||
77 | |||
78 | TEMPLATE_DIRS = ( | ||
79 | # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". | ||
80 | # Always use forward slashes, even on Windows. | ||
81 | # Don't forget to use absolute paths, not relative paths. | ||
82 | ) | ||
83 | |||
84 | INSTALLED_APPS = ( | ||
85 | 'django.contrib.auth', | ||
86 | 'django.contrib.contenttypes', | ||
87 | 'django.contrib.sessions', | ||
88 | 'django.contrib.sites', | ||
89 | 'django.contrib.admin', | ||
90 | 'djangopypi', | ||
91 | ) | ||
@@ -0,0 +1,33 @@ | |||
1 | # -*- coding: utf-8 -*- | ||
2 | from django.conf.urls.defaults import patterns, url, include | ||
3 | from django.conf import settings | ||
4 | from django.contrib import admin | ||
5 | |||
6 | admin.autodiscover() | ||
7 | |||
8 | urlpatterns = patterns('') | ||
9 | |||
10 | # Serve static pages. | ||
11 | if settings.LOCAL_DEVELOPMENT: | ||
12 | urlpatterns += patterns("django.views", | ||
13 | url(r"%s(?P<path>.*)$" % settings.MEDIA_URL[1:], "static.serve", { | ||
14 | "document_root": settings.MEDIA_ROOT})) | ||
15 | urlpatterns += patterns("", | ||
16 | # Admin interface | ||
17 | url(r'^admin/doc/', include("django.contrib.admindocs.urls")), | ||
18 | url(r'^admin/(.*)', admin.site.root), | ||
19 | |||
20 | # Simple PyPI | ||
21 | url(r'^/?$', "djangopypi.views.simple", | ||
22 | name="djangopypi-simple"), | ||
23 | |||
24 | url(r'^(?P<dist_name>[\w\d_\-]+)/(?P<version>[\w\.\d\-_]+)/?', | ||
25 | "djangopypi.views.show_version", | ||
26 | name="djangopypi-show_version"), | ||
27 | |||
28 | url(r'^(?P<dist_name>[\w\d_\-]+)/?', "djangopypi.views.show_links", | ||
29 | name="djangopypi-show_links"), | ||
30 | |||
31 | |||
32 | ) | ||
33 | |||