Mercurial > hg > PaInt
annotate paint/package.py @ 29:59524b6d25c0
implementing making pypi directory strcuture from a package
author | Jeff Hammel <jhammel@mozilla.com> |
---|---|
date | Fri, 30 Mar 2012 11:41:04 -0700 |
parents | c44fb4b6918b |
children | fe5f282dca9b |
rev | line source |
---|---|
4 | 1 """ |
2 package model for python PAckage INTrospection | |
3 """ | |
4 | |
7 | 5 import os |
28 | 6 import pip |
29
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
7 import pypi |
9
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
8 import shutil |
19 | 9 import subprocess |
10 import sys | |
7 | 11 import tarfile |
5 | 12 import tempfile |
7 | 13 import urllib2 |
21
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
14 import urlparse |
7 | 15 import utils |
5 | 16 |
19 | 17 try: |
18 from subprocess import check_call as call | |
19 except ImportError: | |
20 from subporcess import call | |
21 | |
10 | 22 __all__ = ['Package'] |
23 | |
4 | 24 class Package(object): |
25 | |
26 def __init__(self, src): | |
27 self.src = src | |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
28 |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
29 # ephemeral data |
5 | 30 self._tmppath = None |
28 | 31 self._egg_info_path = None |
5 | 32 |
33 def path(self): | |
34 """filesystem path to package""" | |
7 | 35 |
36 # return cached copy if it exists | |
37 if self._tmppath: | |
38 return self._tmppath | |
39 | |
40 # fetch from the web if a URL | |
41 tmpfile = None | |
42 src = self.src | |
5 | 43 if utils.isURL(self.src): |
8 | 44 tmpfile = src = self.fetch() |
7 | 45 |
46 # unpack if an archive | |
28 | 47 if self._is_archive(src): |
8 | 48 try: |
49 self.unpack(src) | |
50 finally: | |
51 if tmpfile: | |
52 os.remove(tmpfile) | |
7 | 53 return self._tmppath |
54 | |
5 | 55 return self.src |
56 | |
57 def fetch(self): | |
8 | 58 """fetch from remote source to a temporary file""" |
15
8c8b7482772f
fix a few failures but still failing
Jeff Hammel <jhammel@mozilla.com>
parents:
14
diff
changeset
|
59 resource = urllib2.urlopen(self.src) |
11 | 60 fd, filename = tempfile.mkstemp() |
7 | 61 os.write(fd, resource.read()) |
62 os.close(fd) | |
63 return filename | |
64 | |
65 def unpack(self, archive): | |
66 """unpack the archive to a temporary destination""" | |
67 # TODO: should handle zipfile additionally at least | |
68 # Ideally, this would be pluggable, etc | |
8 | 69 assert tarfile.is_tarfile(archive), "%s is not an archive" % self.src |
9
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
70 tf = tarfile.TarFile.open(archive) |
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
71 self._tmppath = tempfile.mkdtemp() |
19 | 72 members = tf.getmembers() |
73 | |
74 # cut off the top level directory | |
75 assert not [i for i in members if not os.path.sep in i.name] | |
76 tld = set() | |
77 for member in members: | |
78 directory, member.name = member.name.split(os.path.sep, 1) | |
79 tld.add(directory) | |
80 assert len(tld) == 1 | |
81 | |
82 # extract | |
83 for member in members: | |
84 tf.extract(member, path=self._tmppath) | |
85 tf.close() | |
7 | 86 |
28 | 87 def _is_archive(self, path): |
7 | 88 """returns if the filesystem path is an archive""" |
89 # TODO: should handle zipfile additionally at least | |
90 # Ideally, this would be pluggable, etc | |
91 return tarfile.is_tarfile(path) | |
9
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
92 |
28 | 93 def _cleanup(self): |
9
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
94 if self._tmppath: |
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
95 shutil.rmtree(self._tmppath) |
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
96 self._tmppath = None |
562230cc2e86
now the package class should at least extracts things. it doesnt actually do anything useful
Jeff Hammel <jhammel@mozilla.com>
parents:
8
diff
changeset
|
97 |
18
4c4d1e194bf7
leave in debugging code for now
Jeff Hammel <jhammel@mozilla.com>
parents:
17
diff
changeset
|
98 # __del__ = cleanup |
11 | 99 |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
100 ### python-package-specific functionality |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
101 |
28 | 102 def _egg_info(self): |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
103 """build the egg_info directory""" |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
104 |
28 | 105 if self._egg_info_path: |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
106 # return cached copy |
28 | 107 return self._egg_info_path |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
108 |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
109 directory = self.path() |
16 | 110 setup_py = os.path.join(directory, 'setup.py') |
111 if not os.path.exists(setup_py): | |
17 | 112 raise AssertionError("%s does not exist" % setup_py) |
11 | 113 |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
114 # setup the egg info |
19 | 115 call([sys.executable, 'setup.py', 'egg_info'], cwd=directory, stdout=subprocess.PIPE) |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
116 |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
117 # get the .egg-info directory |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
118 egg_info = [i for i in os.listdir(directory) |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
119 if i.endswith('.egg-info')] |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
120 assert len(egg_info) == 1, 'Expected one .egg-info directory in %s, got: %s' % (directory, egg_info) |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
121 egg_info = os.path.join(directory, egg_info[0]) |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
122 assert os.path.isdir(egg_info), "%s is not a directory" % egg_info |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
123 |
14
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
124 # cache it |
28 | 125 self._egg_info_path = egg_info |
126 return self._egg_info_path | |
14
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
127 |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
128 def info(self): |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
129 """return info dictionary for package""" |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
130 # could use pkginfo |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
131 |
28 | 132 egg_info = self._egg_info() |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
133 |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
134 # read the package information |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
135 pkg_info = os.path.join(egg_info, 'PKG-INFO') |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
136 info_dict = {} |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
137 for line in file(pkg_info).readlines(): |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
138 if not line or line[0].isspace(): |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
139 continue # XXX neglects description |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
140 assert ':' in line |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
141 key, value = [i.strip() for i in line.split(':', 1)] |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
142 info_dict[key] = value |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
143 |
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
144 # return the information |
20
11bc01a089e7
return only the dictionary
Jeff Hammel <jhammel@mozilla.com>
parents:
19
diff
changeset
|
145 return info_dict |
13
0dd1f8f83be2
moving towards some sort of organization
Jeff Hammel <jhammel@mozilla.com>
parents:
12
diff
changeset
|
146 |
11 | 147 def dependencies(self): |
14
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
148 """return the dependencies""" |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
149 |
21
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
150 # get the egg_info directory |
28 | 151 egg_info = self._egg_info() |
14
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
152 |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
153 # read the dependencies |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
154 requires = os.path.join(egg_info, 'requires.txt') |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
155 if os.path.exists(requires): |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
156 dependencies = [i.strip() for i in file(requires).readlines() if i.strip()] |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
157 else: |
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
158 dependencies = [] |
21
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
159 dependencies = dict([(i, None) for i in dependencies]) |
14
6d27c2136163
a decent structure; need to reuse more
Jeff Hammel <jhammel@mozilla.com>
parents:
13
diff
changeset
|
160 |
21
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
161 # read the dependency links |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
162 dependency_links = os.path.join(egg_info, 'dependency_links.txt') |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
163 if os.path.exists(dependency_links): |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
164 links = [i.strip() for i in file(dependency_links).readlines() if i.strip()] |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
165 for link in links: |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
166 # XXX pretty ghetto |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
167 assert '#egg=' in link |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
168 url, dep = link.split('#egg=', 1) |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
169 if dep in dependencies: |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
170 dependencies[dep] = link |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
171 |
4df3e715817d
now have passing tests again
Jeff Hammel <jhammel@mozilla.com>
parents:
20
diff
changeset
|
172 return dependencies |
24 | 173 |
174 def download(self, directory): | |
175 """download a package and all its dependencies using pip""" | |
28 | 176 if not os.path.exists(directory): |
177 os.makedirs(directory) | |
178 assert os.path.isdir(directory) | |
179 pip.main(['install', '--download', directory, self.src]) | |
180 | |
181 def pypi(self, directory): | |
182 """ | |
183 download packages for a pypi directory structure | |
184 http://k0s.org/portfolio/pypi.html | |
185 """ | |
29
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
186 if not os.path.exists(directory): |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
187 os.makedirs(directory) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
188 assert os.path.isdir(directory) |
28 | 189 tempdir = tempfile.mkdtemp() |
190 try: | |
29
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
191 self.download(tempdir) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
192 for package in os.listdir(tempdir): |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
193 |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
194 # full path |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
195 src = os.path.join(tempdir, package) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
196 |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
197 # get destination dirname, filename |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
198 dirname, filename = pypi.pypi_path(src) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
199 |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
200 # make the directory if it doesn't exist |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
201 subdir = os.path.join(directory, dirname) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
202 if not os.path.exists(subdir): |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
203 os.path.makedirs(subdir) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
204 assert os.path.isdir(subdir) |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
205 |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
206 # move the file |
59524b6d25c0
implementing making pypi directory strcuture from a package
Jeff Hammel <jhammel@mozilla.com>
parents:
28
diff
changeset
|
207 shutil.move(src, os.path.join(subdir, filename)) |
28 | 208 finally: |
209 shutil.rmtree(tempdir) |