diff options
author | Rune Halvorsen <runeh@vorkosigan.(none)> | 2009-05-03 21:41:11 +0200 |
---|---|---|
committer | Rune Halvorsen <runeh@vorkosigan.(none)> | 2009-05-03 21:41:11 +0200 |
commit | 1804d0cfb72d766f16aaa1e11f48084f179fc16c (patch) | |
tree | 341f6fea72017f497785381e6b05f25267091905 | |
parent | 846251f44cee277f5f35e7374cf2755e0e57a4ca (diff) | |
download | chishop-1804d0cfb72d766f16aaa1e11f48084f179fc16c.tar.bz2 chishop-1804d0cfb72d766f16aaa1e11f48084f179fc16c.tar.xz chishop-1804d0cfb72d766f16aaa1e11f48084f179fc16c.zip |
Added management command for easy_installing into the chishop
-rw-r--r-- | buildout.cfg | 4 | ||||
-rw-r--r-- | djangopypi/management/__init__.py | 0 | ||||
-rw-r--r-- | djangopypi/management/commands/__init__.py | 0 | ||||
-rw-r--r-- | djangopypi/management/commands/ppadd.py | 143 | ||||
-rw-r--r-- | djangopypi/models.py | 10 |
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] |
2 | parts = django | 2 | parts = django |
3 | eggs = | 3 | eggs = pkginfo |
4 | 4 | ||
5 | [django] | 5 | [django] |
6 | recipe = djangorecipe | 6 | recipe = djangorecipe |
@@ -8,4 +8,4 @@ version = 1.0.2 | |||
8 | settings = development | 8 | settings = development |
9 | eggs = ${buildout:eggs} | 9 | eggs = ${buildout:eggs} |
10 | project = chishop | 10 | project = chishop |
11 | wsgi = true \ No newline at end of file | 11 | wsgi = 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 | """ | ||
2 | Management command for adding a package to the repository. Supposed to be the | ||
3 | equivelant of calling easy_install, but the install target is the chishop. | ||
4 | """ | ||
5 | |||
6 | from __future__ import with_statement | ||
7 | import os | ||
8 | import tempfile | ||
9 | import shutil | ||
10 | import urllib | ||
11 | |||
12 | import pkginfo | ||
13 | |||
14 | from django.core.files.base import File | ||
15 | from django.core.management.base import LabelCommand | ||
16 | from optparse import make_option | ||
17 | from contextlib import contextmanager | ||
18 | from urlparse import urlsplit | ||
19 | from setuptools.package_index import PackageIndex | ||
20 | from django.contrib.auth.models import User | ||
21 | from djangopypi.models import Project, Release, Classifier | ||
22 | |||
23 | |||
24 | |||
25 | |||
26 | |||
27 | @contextmanager | ||
28 | def 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 | |||
35 | class 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 | ||
41 | be a package name or a URL to an archive or egg. Package names honour | ||
42 | the same rules as easy_install with regard to indicating versions etc. | ||
43 | |||
44 | If a version of the package exists, but is older than what we want to install, | ||
45 | the owner remains the same. | ||
46 | |||
47 | For new packages there needs to be an owner. If the --owner option is present | ||
48 | we use that value. If not, we try to match the maintainer of the package, form | ||
49 | the metadata, with a user in out database, based on the If it's a new package | ||
50 | and the maintainer emailmatches someone in our user list, we use that. If not, | ||
51 | the package can not be | ||
52 | added""" | ||
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 d6df975..8ebed5e 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 | ||
15 | Neither the name of Ask Solem nor the names of its contributors may be used | 15 | Neither the name of Ask Solem nor the names of its contributors may be used |
16 | to endorse or promote products derived from this software without specific | 16 | to endorse or promote products derived from this software without specific |
17 | prior written permission. | 17 | prior written permission. |
18 | 18 | ||
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
@@ -104,6 +104,12 @@ class Project(models.Model): | |||
104 | def get_pypi_absolute_url(self): | 104 | def get_pypi_absolute_url(self): |
105 | return ('djangopypi-pypi_show_links', (), {'dist_name': self.name}) | 105 | return ('djangopypi-pypi_show_links', (), {'dist_name': self.name}) |
106 | 106 | ||
107 | def get_release(self, version): | ||
108 | """Return the release object for version, or None""" | ||
109 | try: | ||
110 | self.releases.get(version=version) | ||
111 | except Release.DoesNotExist: | ||
112 | return None | ||
107 | 113 | ||
108 | class Release(models.Model): | 114 | class Release(models.Model): |
109 | version = models.CharField(max_length=128) | 115 | version = models.CharField(max_length=128) |
@@ -152,5 +158,3 @@ class Release(models.Model): | |||
152 | 158 | ||
153 | def get_dl_url(self): | 159 | def get_dl_url(self): |
154 | return "%s#md5=%s" % (self.distribution.url, self.md5_digest) | 160 | return "%s#md5=%s" % (self.distribution.url, self.md5_digest) |
155 | |||
156 | |||