aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAsk Solem <askh@opera.com>2009-05-04 10:58:37 +0200
committerAsk Solem <askh@opera.com>2009-05-04 10:58:37 +0200
commitceec24d114f2f5da74179c8a4b4abccb8ef86adf (patch)
treef8811ac94924e46be524d40146e5eae995837c8d
parent76d401adcdfc846124daaa1e186e982cb6be415d (diff)
parent1804d0cfb72d766f16aaa1e11f48084f179fc16c (diff)
downloadchishop-ceec24d114f2f5da74179c8a4b4abccb8ef86adf.tar.bz2
chishop-ceec24d114f2f5da74179c8a4b4abccb8ef86adf.tar.xz
chishop-ceec24d114f2f5da74179c8a4b4abccb8ef86adf.zip
Merge branch 'runeh/master'
-rw-r--r--buildout.cfg4
-rw-r--r--djangopypi/management/__init__.py0
-rw-r--r--djangopypi/management/commands/__init__.py0
-rw-r--r--djangopypi/management/commands/ppadd.py143
-rw-r--r--djangopypi/models.py10
5 files changed, 152 insertions, 5 deletions
diff --git a/buildout.cfg b/buildout.cfg
index 925ed6a..fc36b3c 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -1,6 +1,6 @@
1[buildout] 1[buildout]
2parts = django 2parts = django
3eggs = 3eggs = pkginfo
4 4
5[django] 5[django]
6recipe = djangorecipe 6recipe = djangorecipe
@@ -8,4 +8,4 @@ version = 1.0.2
8settings = development 8settings = development
9eggs = ${buildout:eggs} 9eggs = ${buildout:eggs}
10project = chishop 10project = chishop
11wsgi = true \ No newline at end of file 11wsgi = true
diff --git a/djangopypi/management/__init__.py b/djangopypi/management/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/djangopypi/management/__init__.py
diff --git a/djangopypi/management/commands/__init__.py b/djangopypi/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/djangopypi/management/commands/__init__.py
diff --git a/djangopypi/management/commands/ppadd.py b/djangopypi/management/commands/ppadd.py
new file mode 100644
index 0000000..78eb2cf
--- /dev/null
+++ b/djangopypi/management/commands/ppadd.py
@@ -0,0 +1,143 @@
1"""
2Management command for adding a package to the repository. Supposed to be the
3equivelant of calling easy_install, but the install target is the chishop.
4"""
5
6from __future__ import with_statement
7import os
8import tempfile
9import shutil
10import urllib
11
12import pkginfo
13
14from django.core.files.base import File
15from django.core.management.base import LabelCommand
16from optparse import make_option
17from contextlib import contextmanager
18from urlparse import urlsplit
19from setuptools.package_index import PackageIndex
20from django.contrib.auth.models import User
21from djangopypi.models import Project, Release, Classifier
22
23
24
25
26
27@contextmanager
28def tempdir():
29 """Simple context that provides a temporary directory that is deleted
30 when the context is exited."""
31 d = tempfile.mkdtemp(".tmp", "djangopypi.")
32 yield d
33 shutil.rmtree(d)
34
35class Command(LabelCommand):
36 option_list = LabelCommand.option_list + (
37 make_option("-o", "--owner", help="add packages as OWNER",
38 metavar="OWNER", default=None),
39 )
40 help = """Add one or more packages to the repository. Each argument can
41be a package name or a URL to an archive or egg. Package names honour
42the same rules as easy_install with regard to indicating versions etc.
43
44If a version of the package exists, but is older than what we want to install,
45the owner remains the same.
46
47For new packages there needs to be an owner. If the --owner option is present
48we use that value. If not, we try to match the maintainer of the package, form
49the metadata, with a user in out database, based on the If it's a new package
50and the maintainer emailmatches someone in our user list, we use that. If not,
51the package can not be
52added"""
53
54 def __init__(self, *args, **kwargs):
55 self.pypi = PackageIndex()
56 LabelCommand.__init__(self, *args, **kwargs)
57
58 def handle_label(self, label, **options):
59 with tempdir() as tmp:
60 path = self.pypi.download(label, tmp)
61 if path:
62 self._save_package(path, options["owner"])
63 else:
64 print "Could not add %s. Not found." % label
65
66 def _save_package(self, path, ownerid):
67 meta = self._get_meta(path)
68
69 try:
70 # can't use get_or_create as that demands there be an owner
71 project = Project.objects.get(name=meta.name)
72 isnewproject = False
73 except Project.DoesNotExist:
74 project = Project(name=meta.name)
75 isnewproject = True
76
77 release = project.get_release(meta.version)
78 if not isnewproject and release and release.version == meta.version:
79 print "%s-%s already added" % (meta.name, meta.version)
80 return
81
82 # algorithm as follows: If owner is given, try to grab user with that
83 # username from db. If doesn't exist, bail. If no owner set look at
84 # mail address from metadata and try to get that user. If it exists
85 # use it. If not, bail.
86 owner = None
87
88 if ownerid:
89 try:
90 if "@" in ownerid:
91 owner = User.objects.get(email=ownerid)
92 else:
93 owner = User.objects.get(username=ownerid)
94 except User.DoesNotExist:
95 pass
96 else:
97 try:
98 owner = User.objects.get(email=meta.author_email)
99 except User.DoesNotExist:
100 pass
101
102 if not owner:
103 print "No owner defined. Use --owner to force one"
104 return
105
106 # at this point we have metadata and an owner, can safely add it.
107
108 project.owner = owner
109 # Some packages don't have proper licence, seems to be a problem
110 # with setup.py upload. Use "UNKNOWN"
111 project.license = meta.license or "Unknown"
112 project.metadata_version = meta.metadata_version
113 project.author = meta.author
114 project.home_page = meta.home_page
115 project.download_url = meta.download_url
116 project.summary = meta.summary
117 project.description = meta.description
118 project.author_email = meta.author_email
119
120 project.save()
121
122 for classifier in meta.classifiers:
123 project.classifiers.add(
124 Classifier.objects.get_or_create(name=classifier)[0])
125
126 release = Release()
127 release.version = meta.version
128 release.project = project
129 filename = os.path.basename(path)
130
131 file = File(open(path, "rb"))
132 release.distribution.save(filename, file)
133 release.save()
134 print "%s-%s added" % (meta.name, meta.version)
135
136 def _get_meta(self, path):
137 if path.endswith((".zip", ".tar.gz")):
138 return pkginfo.SDist(path)
139 elif path.endswith(".egg"):
140 return pkginfo.BDist(path)
141 else:
142 print "Couldn't get metadata from %s. Not added to chishop" % os.path.basename(path)
143 return None
diff --git a/djangopypi/models.py b/djangopypi/models.py
index 4821237..1eee0e9 100644
--- a/djangopypi/models.py
+++ b/djangopypi/models.py
@@ -14,7 +14,7 @@ modification, are permitted provided that the following conditions are met:
14 14
15Neither the name of Ask Solem nor the names of its contributors may be used 15Neither the name of Ask Solem nor the names of its contributors may be used
16to endorse or promote products derived from this software without specific 16to endorse or promote products derived from this software without specific
17prior written permission. 17prior written permission.
18 18
19THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
@@ -107,6 +107,12 @@ class Project(models.Model):
107 def get_pypi_absolute_url(self): 107 def get_pypi_absolute_url(self):
108 return ('djangopypi-pypi_show_links', (), {'dist_name': self.name}) 108 return ('djangopypi-pypi_show_links', (), {'dist_name': self.name})
109 109
110 def get_release(self, version):
111 """Return the release object for version, or None"""
112 try:
113 self.releases.get(version=version)
114 except Release.DoesNotExist:
115 return None
110 116
111class Release(models.Model): 117class Release(models.Model):
112 version = models.CharField(max_length=128) 118 version = models.CharField(max_length=128)
@@ -155,5 +161,3 @@ class Release(models.Model):
155 161
156 def get_dl_url(self): 162 def get_dl_url(self):
157 return "%s#md5=%s" % (self.distribution.url, self.md5_digest) 163 return "%s#md5=%s" % (self.distribution.url, self.md5_digest)
158
159