1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
# Copyright (c) 2007-2008 Infrae. All rights reserved.
# $Id: Common.py 33243 2009-01-29 10:59:47Z sylvain $
from sets import Set # For python 2.3 compatibility
import os.path
import os
import re
import zc.buildout
def ignoredFile(file):
"""Return true if the file should be ignored while checking for
added/changed/modified files.
"""
for suffix in ['.pyc', '.pyo', '.egg-info']:
if file.endswith(suffix):
return True
return False
def reportInvalidFiles(path, name, badfiles):
"""Report invalid files.
"""
badfiles = [file for file in badfiles if not ignoredFile(file)]
if not badfiles:
return
raise ValueError("""\
In '%s':
local modifications detected while uninstalling %r: Uninstall aborted!
Please check for local modifications and make sure these are checked
in.
If you sure that these modifications can be ignored, remove the
checkout manually:
rm -rf %s
Or if applicable, add the file to the 'svn:ignore' property of the
file's container directory. Alternatively, add an ignore glob pattern
to your subversion client's 'global-ignores' configuration variable.
""" % (path, name, """
rm -rf """.join(badfiles)))
def checkExistPath(path, warning=True):
"""Check that a path exist.
"""
status = os.path.exists(path)
if not status and warning:
print "-------- WARNING --------"
print "Directory %s have been removed." % os.path.abspath(path)
print "Changes might be lost."
print "-------- WARNING --------"
return status
def checkAddedPaths(location, urls):
"""Check that no path have been added to that location.
"""
current_paths = Set([os.path.join(location, s) for s in
os.listdir(location)])
recipe_paths = Set(urls.keys())
added_paths = list(current_paths - recipe_paths)
for path in added_paths[:]:
if path.endswith('.svn'):
added_paths.remove(path)
if added_paths:
msg = "New path have been added to the location: %s."
raise ValueError(msg % ', '.join(added_paths))
def prepareURLs(location, urls):
"""Given a list of urls/path, and a location, prepare a list of
tuple with url, full path.
"""
def prepareEntry(line):
link, path = line.split()
return os.path.join(location, path), link
return dict([prepareEntry(l) for l in urls.splitlines() if l.strip()])
def extractNames(urls):
"""Return just the target names of the urls (used for egg names)"""
def extractName(line):
link, name = line.split()
return name
return [extractName(line) for line in urls.splitlines() if line.strip()]
class BaseRecipe(object):
"""infrae.subversion recipe. Base class.
"""
def __init__(self, buildout, name, options):
self.buildout = buildout
self.name = name
self.options = options
# location is overridable if desired.
location = options.get('location', None)
if location:
self.location = os.path.abspath(os.path.join(
buildout['buildout']['directory'], location))
else:
self.location = os.path.join(
buildout['buildout']['parts-directory'], self.name)
options['location'] = self.location
self.revisions = {} # Store revision information for each link
self.updated = [] # Store updated links
self.urls = prepareURLs(self.location, options['urls'])
self.export = options.get('export')
self.offline = buildout['buildout'].get('offline', 'false') == 'true'
self.eggify = options.get('as_eggs', False)
self.eggs = self.eggify and extractNames(options['urls']) or []
self.newest = (
not self.offline and
buildout['buildout'].get('newest', 'true') == 'true'
)
self.verbose = buildout['buildout'].get('verbosity', 0)
self.warning = not (options.get('no_warnings', 'false') == 'true')
def _exportInformationToOptions(self):
"""Export revision and changed information to options.
Options can only contains strings.
"""
if self.options.get('export_info', False):
self.options['updated'] = str('\n'.join(self.updated))
str_revisions = ['%s %s' % r for r in self.revisions.items()
if r[1]]
self.options['revisions'] = str('\n'.join(sorted(str_revisions)))
# Always export egg list
self.options['eggs'] = '\n'.join(sorted(self.eggs))
def _updateAllRevisionInformation(self):
"""Update all revision information for defined urls.
"""
for path, link in self.urls.items():
if os.path.exists(path):
self._updateRevisionInformation(link, path)
def _updateRevisionInformation(self, link, revision):
"""Update revision information on a path.
"""
old_revision = self.revisions.get(link, None)
self.revisions[link] = revision
if not (old_revision is None):
self.updated.append(link)
def _updatePath(self, link, path):
"""Update a single path.
"""
raise NotImplementedError
def _updateAllPaths(self):
"""Update the checkouts.
"""
ignore = self.options.get('ignore_updates', False) or self.export
num_release = re.compile('.*@[0-9]+$')
for path, link in self.urls.items():
if not checkExistPath(path, warning=self.warning):
if self.verbose:
print "Entry %s missing, checkout a new version ..." % link
self._installPath(link, path)
continue
if ignore:
continue
if num_release.match(link):
if self.verbose:
print "Given num release for %s, skipping." % link
continue
if self.verbose:
print "Updating %s" % path
self._updatePath(link, path)
def update(self):
"""Update the recipe.
Does not update SVN path if the buildout is in offline mode,
but still eggify and export information.
"""
if self.newest:
self._updateAllPaths()
if self.eggify:
self._eggify()
self._exportInformationToOptions()
return self.location
def _installPath(self, link, path):
"""Checkout a single entry.
"""
raise NotImplementedError
def _installPathVerbose(self, link, path):
"""Checkout a single entry with verbose.
"""
if self.verbose:
print "%s %s to %s" % (self.export and 'Export' or 'Fetch',
link, path)
self._installPath(link, path)
def _eggify(self):
"""Install everything as development eggs if eggs=true"""
if self.eggify:
target = self.buildout['buildout']['develop-eggs-directory']
for path in self.urls.keys():
# If we update the recipe, and we don't have newest,
# and that some path have been deleted, all of them
# might not be there.
if checkExistPath(path, warning=self.warning):
zc.buildout.easy_install.develop(path, target)
def install(self):
"""Checkout the checkouts.
Fails if buildout is running in offline mode.
"""
for path, link in self.urls.items():
self._installPathVerbose(link, path)
installed = [self.location]
if self.eggify:
self._eggify()
# And also return the develop-eggs/*.egg-link files that are
# ours so that an uninstall automatically zaps them.
dev_dir = self.buildout['buildout']['develop-eggs-directory']
egg_links = ['%s.egg-link' % egg for egg in self.eggs]
egg_links = [os.path.join(dev_dir, link) for link in egg_links]
installed += egg_links
self._exportInformationToOptions()
return installed
|