Merge lp:~mwhudson/launchpad/lp-serve-report-branch-access-bug-532210 into lp:launchpad
- lp-serve-report-branch-access-bug-532210
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Tim Penhey |
Approved revision: | no longer in the source branch. |
Merged at revision: | not available |
Proposed branch: | lp:~mwhudson/launchpad/lp-serve-report-branch-access-bug-532210 |
Merge into: | lp:launchpad |
Diff against target: |
326 lines (+154/-11) 8 files modified
bzrplugins/lpserve.py (+3/-2) lib/lp/codehosting/vfs/branchfs.py (+14/-6) lib/lp/codehosting/vfs/branchfsclient.py (+9/-1) lib/lp/codehosting/vfs/hooks.py (+25/-0) lib/lp/codehosting/vfs/tests/test_branchfsclient.py (+37/-1) lib/lp/codehosting/vfs/tests/test_hooks.py (+63/-0) setup.py (+2/-1) versions.cfg (+1/-0) |
To merge this branch: | bzr merge lp:~mwhudson/launchpad/lp-serve-report-branch-access-bug-532210 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tim Penhey (community) | Approve | ||
Review via email:
|
Commit message
Report the branch being accessed in the lp-serve process' process name
Description of the change
Hi there,
This branch reports which branch an lp-serve accesses in its process title.
I didn't have a pre-imp call for this, and if I did I probably wouldn't be so worried that the code in lp.codehosting.
Cheers,
mwh
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Jonathan Lange (jml) wrote : | # |
Cool! At first I thought this was about logging branch access to a file, but it's still great news.
This might be a silly question, but have you run this locally?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Michael Hudson-Doyle (mwhudson) wrote : | # |
On 23/03/10 23:29, Jonathan Lange wrote:
> Cool! At first I thought this was about logging branch access to a file, but it's still great news.
Yeah, we should probably do that, but multiprocess synchronization argh.
What I'd like is to have bzr lp-serve processes log to ~/.bzr.log.$pid
rather than all smearing into ~/.bzr.log but that was annoying last time
I looked into it.
> This might be a silly question, but have you run this locally?
Yes I have. It seems to work :)
Cheers,
mwh
Preview Diff
1 | === modified file 'bzrplugins/lpserve.py' | |||
2 | --- bzrplugins/lpserve.py 2010-03-16 19:01:26 +0000 | |||
3 | +++ bzrplugins/lpserve.py 2010-03-24 00:47:00 +0000 | |||
4 | @@ -88,13 +88,14 @@ | |||
5 | 88 | def run(self, user_id, port=None, upload_directory=None, | 88 | def run(self, user_id, port=None, upload_directory=None, |
6 | 89 | mirror_directory=None, branchfs_endpoint_url=None, inet=False): | 89 | mirror_directory=None, branchfs_endpoint_url=None, inet=False): |
7 | 90 | from lp.codehosting.bzrutils import install_oops_handler | 90 | from lp.codehosting.bzrutils import install_oops_handler |
9 | 91 | from lp.codehosting.vfs import get_lp_server | 91 | from lp.codehosting.vfs import get_lp_server, hooks |
10 | 92 | install_oops_handler(user_id) | 92 | install_oops_handler(user_id) |
11 | 93 | four_gig = int(4e9) | 93 | four_gig = int(4e9) |
12 | 94 | resource.setrlimit(resource.RLIMIT_AS, (four_gig, four_gig)) | 94 | resource.setrlimit(resource.RLIMIT_AS, (four_gig, four_gig)) |
13 | 95 | seen_new_branch = hooks.SetProcTitleHook() | ||
14 | 95 | lp_server = get_lp_server( | 96 | lp_server = get_lp_server( |
15 | 96 | int(user_id), branchfs_endpoint_url, | 97 | int(user_id), branchfs_endpoint_url, |
17 | 97 | upload_directory, mirror_directory) | 98 | upload_directory, mirror_directory, seen_new_branch.seen) |
18 | 98 | lp_server.start_server() | 99 | lp_server.start_server() |
19 | 99 | 100 | ||
20 | 100 | old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS | 101 | old_lockdir_timeout = lockdir._DEFAULT_TIMEOUT_SECONDS |
21 | 101 | 102 | ||
22 | === modified file 'lib/lp/codehosting/vfs/branchfs.py' | |||
23 | --- lib/lp/codehosting/vfs/branchfs.py 2010-02-14 23:02:37 +0000 | |||
24 | +++ lib/lp/codehosting/vfs/branchfs.py 2010-03-24 00:47:00 +0000 | |||
25 | @@ -368,16 +368,20 @@ | |||
26 | 368 | path on that transport. | 368 | path on that transport. |
27 | 369 | """ | 369 | """ |
28 | 370 | 370 | ||
30 | 371 | def __init__(self, scheme, authserver, user_id): | 371 | def __init__(self, scheme, authserver, user_id, |
31 | 372 | seen_new_branch_hook=None): | ||
32 | 372 | """Construct a LaunchpadServer. | 373 | """Construct a LaunchpadServer. |
33 | 373 | 374 | ||
34 | 374 | :param scheme: The URL scheme to use. | 375 | :param scheme: The URL scheme to use. |
35 | 375 | :param authserver: An XML-RPC client that implements callRemote. | 376 | :param authserver: An XML-RPC client that implements callRemote. |
36 | 376 | :param user_id: The database ID for the user who is accessing | 377 | :param user_id: The database ID for the user who is accessing |
37 | 377 | branches. | 378 | branches. |
38 | 379 | :param seen_new_branch_hook: A callable that will be called once for | ||
39 | 380 | each branch accessed via this server. | ||
40 | 378 | """ | 381 | """ |
41 | 379 | AsyncVirtualServer.__init__(self, scheme) | 382 | AsyncVirtualServer.__init__(self, scheme) |
43 | 380 | self._authserver = BranchFileSystemClient(authserver, user_id) | 383 | self._authserver = BranchFileSystemClient( |
44 | 384 | authserver, user_id, seen_new_branch_hook=seen_new_branch_hook) | ||
45 | 381 | self._is_start_server = False | 385 | self._is_start_server = False |
46 | 382 | 386 | ||
47 | 383 | def translateVirtualPath(self, virtual_url_fragment): | 387 | def translateVirtualPath(self, virtual_url_fragment): |
48 | @@ -556,7 +560,7 @@ | |||
49 | 556 | asyncTransportFactory = AsyncLaunchpadTransport | 560 | asyncTransportFactory = AsyncLaunchpadTransport |
50 | 557 | 561 | ||
51 | 558 | def __init__(self, authserver, user_id, hosted_transport, | 562 | def __init__(self, authserver, user_id, hosted_transport, |
53 | 559 | mirror_transport): | 563 | mirror_transport, seen_new_branch_hook=None): |
54 | 560 | """Construct a `LaunchpadServer`. | 564 | """Construct a `LaunchpadServer`. |
55 | 561 | 565 | ||
56 | 562 | See `_BaseLaunchpadServer` for more information. | 566 | See `_BaseLaunchpadServer` for more information. |
57 | @@ -575,9 +579,12 @@ | |||
58 | 575 | :param mirror_transport: A Bazaar `Transport` that points to the | 579 | :param mirror_transport: A Bazaar `Transport` that points to the |
59 | 576 | "mirrored" area of Launchpad. See module docstring for more | 580 | "mirrored" area of Launchpad. See module docstring for more |
60 | 577 | information. | 581 | information. |
61 | 582 | :param seen_new_branch_hook: A callable that will be called once for | ||
62 | 583 | each branch accessed via this server. | ||
63 | 578 | """ | 584 | """ |
64 | 579 | scheme = 'lp-%d:///' % id(self) | 585 | scheme = 'lp-%d:///' % id(self) |
66 | 580 | super(LaunchpadServer, self).__init__(scheme, authserver, user_id) | 586 | super(LaunchpadServer, self).__init__( |
67 | 587 | scheme, authserver, user_id, seen_new_branch_hook) | ||
68 | 581 | mirror_transport = get_readonly_transport(mirror_transport) | 588 | mirror_transport = get_readonly_transport(mirror_transport) |
69 | 582 | self._transport_dispatch = TransportDispatch( | 589 | self._transport_dispatch = TransportDispatch( |
70 | 583 | hosted_transport, mirror_transport) | 590 | hosted_transport, mirror_transport) |
71 | @@ -641,7 +648,7 @@ | |||
72 | 641 | 648 | ||
73 | 642 | 649 | ||
74 | 643 | def get_lp_server(user_id, branchfs_endpoint_url=None, hosted_directory=None, | 650 | def get_lp_server(user_id, branchfs_endpoint_url=None, hosted_directory=None, |
76 | 644 | mirror_directory=None): | 651 | mirror_directory=None, seen_new_branch_hook=None): |
77 | 645 | """Create a Launchpad server. | 652 | """Create a Launchpad server. |
78 | 646 | 653 | ||
79 | 647 | :param user_id: A unique database ID of the user whose branches are | 654 | :param user_id: A unique database ID of the user whose branches are |
80 | @@ -649,6 +656,7 @@ | |||
81 | 649 | :param branchfs_endpoint_url: URL for the branch file system end-point. | 656 | :param branchfs_endpoint_url: URL for the branch file system end-point. |
82 | 650 | :param hosted_directory: Where the branches are uploaded to. | 657 | :param hosted_directory: Where the branches are uploaded to. |
83 | 651 | :param mirror_directory: Where all Launchpad branches are mirrored. | 658 | :param mirror_directory: Where all Launchpad branches are mirrored. |
84 | 659 | :param seen_new_branch_hook: | ||
85 | 652 | :return: A `LaunchpadServer`. | 660 | :return: A `LaunchpadServer`. |
86 | 653 | """ | 661 | """ |
87 | 654 | # Get the defaults from the config. | 662 | # Get the defaults from the config. |
88 | @@ -667,7 +675,7 @@ | |||
89 | 667 | mirror_transport = get_chrooted_transport(mirror_url) | 675 | mirror_transport = get_chrooted_transport(mirror_url) |
90 | 668 | lp_server = LaunchpadServer( | 676 | lp_server = LaunchpadServer( |
91 | 669 | BlockingProxy(branchfs_client), user_id, | 677 | BlockingProxy(branchfs_client), user_id, |
93 | 670 | hosted_transport, mirror_transport) | 678 | hosted_transport, mirror_transport, seen_new_branch_hook) |
94 | 671 | return lp_server | 679 | return lp_server |
95 | 672 | 680 | ||
96 | 673 | 681 | ||
97 | 674 | 682 | ||
98 | === modified file 'lib/lp/codehosting/vfs/branchfsclient.py' | |||
99 | --- lib/lp/codehosting/vfs/branchfsclient.py 2009-06-25 04:06:00 +0000 | |||
100 | +++ lib/lp/codehosting/vfs/branchfsclient.py 2010-03-24 00:47:00 +0000 | |||
101 | @@ -46,18 +46,24 @@ | |||
102 | 46 | """ | 46 | """ |
103 | 47 | 47 | ||
104 | 48 | def __init__(self, branchfs_endpoint, user_id, expiry_time=None, | 48 | def __init__(self, branchfs_endpoint, user_id, expiry_time=None, |
106 | 49 | _now=time.time): | 49 | seen_new_branch_hook=None, _now=time.time): |
107 | 50 | """Construct a caching branchfs_endpoint. | 50 | """Construct a caching branchfs_endpoint. |
108 | 51 | 51 | ||
109 | 52 | :param branchfs_endpoint: An XML-RPC proxy that implements callRemote. | 52 | :param branchfs_endpoint: An XML-RPC proxy that implements callRemote. |
110 | 53 | :param user_id: The database ID of the user who will be making these | 53 | :param user_id: The database ID of the user who will be making these |
111 | 54 | requests. An integer. | 54 | requests. An integer. |
112 | 55 | :param expiry_time: If supplied, only cache the results of | ||
113 | 56 | translatePath for this many seconds. If not supplied, cache the | ||
114 | 57 | results of translatePath for as long as this instance exists. | ||
115 | 58 | :param seen_new_branch_hook: A callable that will be called with the | ||
116 | 59 | unique_name of each new branch that is accessed. | ||
117 | 55 | """ | 60 | """ |
118 | 56 | self._branchfs_endpoint = branchfs_endpoint | 61 | self._branchfs_endpoint = branchfs_endpoint |
119 | 57 | self._cache = {} | 62 | self._cache = {} |
120 | 58 | self._user_id = user_id | 63 | self._user_id = user_id |
121 | 59 | self.expiry_time = expiry_time | 64 | self.expiry_time = expiry_time |
122 | 60 | self._now = _now | 65 | self._now = _now |
123 | 66 | self.seen_new_branch_hook = seen_new_branch_hook | ||
124 | 61 | 67 | ||
125 | 62 | def _getMatchedPart(self, path, transport_tuple): | 68 | def _getMatchedPart(self, path, transport_tuple): |
126 | 63 | """Return the part of 'path' that the endpoint actually matched.""" | 69 | """Return the part of 'path' that the endpoint actually matched.""" |
127 | @@ -77,6 +83,8 @@ | |||
128 | 77 | (transport_type, data, trailing_path) = transport_tuple | 83 | (transport_type, data, trailing_path) = transport_tuple |
129 | 78 | matched_part = self._getMatchedPart(path, transport_tuple) | 84 | matched_part = self._getMatchedPart(path, transport_tuple) |
130 | 79 | if transport_type == BRANCH_TRANSPORT: | 85 | if transport_type == BRANCH_TRANSPORT: |
131 | 86 | if self.seen_new_branch_hook: | ||
132 | 87 | self.seen_new_branch_hook(matched_part.strip('/')) | ||
133 | 80 | self._cache[matched_part] = (transport_type, data, self._now()) | 88 | self._cache[matched_part] = (transport_type, data, self._now()) |
134 | 81 | return transport_tuple | 89 | return transport_tuple |
135 | 82 | 90 | ||
136 | 83 | 91 | ||
137 | === added file 'lib/lp/codehosting/vfs/hooks.py' | |||
138 | --- lib/lp/codehosting/vfs/hooks.py 1970-01-01 00:00:00 +0000 | |||
139 | +++ lib/lp/codehosting/vfs/hooks.py 2010-03-24 00:47:00 +0000 | |||
140 | @@ -0,0 +1,25 @@ | |||
141 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | ||
142 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
143 | 3 | |||
144 | 4 | """Implementations for the `seen_new_branch_hook` of `BranchFileSystemClient`. | ||
145 | 5 | """ | ||
146 | 6 | |||
147 | 7 | __metaclass__ = type | ||
148 | 8 | __all__ = ['SetProcTitleHook'] | ||
149 | 9 | |||
150 | 10 | import setproctitle | ||
151 | 11 | |||
152 | 12 | |||
153 | 13 | class SetProcTitleHook: | ||
154 | 14 | """Use seen() as the hook to report branch access in ps(1) output.""" | ||
155 | 15 | |||
156 | 16 | def __init__(self, setproctitle_mod=None): | ||
157 | 17 | if setproctitle_mod is None: | ||
158 | 18 | setproctitle_mod = setproctitle | ||
159 | 19 | self.setproctitle_mod = setproctitle_mod | ||
160 | 20 | self.basename = setproctitle_mod.getproctitle() | ||
161 | 21 | |||
162 | 22 | def seen(self, branch_url): | ||
163 | 23 | branch_url = branch_url.strip('/') | ||
164 | 24 | self.setproctitle_mod.setproctitle( | ||
165 | 25 | self.basename + ' BRANCH:' + branch_url) | ||
166 | 0 | 26 | ||
167 | === modified file 'lib/lp/codehosting/vfs/tests/test_branchfsclient.py' | |||
168 | --- lib/lp/codehosting/vfs/tests/test_branchfsclient.py 2009-06-25 04:06:00 +0000 | |||
169 | +++ lib/lp/codehosting/vfs/tests/test_branchfsclient.py 2010-03-24 00:47:00 +0000 | |||
170 | @@ -36,13 +36,14 @@ | |||
171 | 36 | """ | 36 | """ |
172 | 37 | self.fake_time.advance(amount) | 37 | self.fake_time.advance(amount) |
173 | 38 | 38 | ||
175 | 39 | def makeClient(self, expiry_time=None): | 39 | def makeClient(self, expiry_time=None, seen_new_branch_hook=None): |
176 | 40 | """Make a `BranchFileSystemClient`. | 40 | """Make a `BranchFileSystemClient`. |
177 | 41 | 41 | ||
178 | 42 | The created client interacts with the InMemoryFrontend. | 42 | The created client interacts with the InMemoryFrontend. |
179 | 43 | """ | 43 | """ |
180 | 44 | return BranchFileSystemClient( | 44 | return BranchFileSystemClient( |
181 | 45 | self._xmlrpc_client, self.user.id, expiry_time=expiry_time, | 45 | self._xmlrpc_client, self.user.id, expiry_time=expiry_time, |
182 | 46 | seen_new_branch_hook=seen_new_branch_hook, | ||
183 | 46 | _now=self.fake_time.now) | 47 | _now=self.fake_time.now) |
184 | 47 | 48 | ||
185 | 48 | def test_translatePath(self): | 49 | def test_translatePath(self): |
186 | @@ -213,6 +214,41 @@ | |||
187 | 213 | return deferred.addCallbacks( | 214 | return deferred.addCallbacks( |
188 | 214 | translated_successfully, failed_translation) | 215 | translated_successfully, failed_translation) |
189 | 215 | 216 | ||
190 | 217 | def test_seen_new_branch_hook_called_for_new_branch(self): | ||
191 | 218 | # A callable passed as the seen_new_branch_hook when constructing a | ||
192 | 219 | # BranchFileSystemClient will be called with a previously unseen | ||
193 | 220 | # branch's unique_name when a path for a that branch is translated for | ||
194 | 221 | # the first time. | ||
195 | 222 | seen_branches = [] | ||
196 | 223 | client = self.makeClient(seen_new_branch_hook=seen_branches.append) | ||
197 | 224 | branch = self.factory.makeAnyBranch() | ||
198 | 225 | client.translatePath('/' + branch.unique_name + '/trailing') | ||
199 | 226 | self.assertEqual([branch.unique_name], seen_branches) | ||
200 | 227 | |||
201 | 228 | def test_seen_new_branch_hook_called_for_each_branch(self): | ||
202 | 229 | # The seen_new_branch_hook is called for a each branch that is | ||
203 | 230 | # accessed. | ||
204 | 231 | seen_branches = [] | ||
205 | 232 | client = self.makeClient(seen_new_branch_hook=seen_branches.append) | ||
206 | 233 | branch1 = self.factory.makeAnyBranch() | ||
207 | 234 | branch2 = self.factory.makeAnyBranch() | ||
208 | 235 | client.translatePath('/' + branch1.unique_name + '/trailing') | ||
209 | 236 | client.translatePath('/' + branch2.unique_name + '/trailing') | ||
210 | 237 | self.assertEqual( | ||
211 | 238 | [branch1.unique_name, branch2.unique_name], seen_branches) | ||
212 | 239 | |||
213 | 240 | def test_seen_new_branch_hook_called_once_for_a_new_branch(self): | ||
214 | 241 | # The seen_new_branch_hook is only called once for a given branch. | ||
215 | 242 | seen_branches = [] | ||
216 | 243 | client = self.makeClient(seen_new_branch_hook=seen_branches.append) | ||
217 | 244 | branch1 = self.factory.makeAnyBranch() | ||
218 | 245 | branch2 = self.factory.makeAnyBranch() | ||
219 | 246 | client.translatePath('/' + branch1.unique_name + '/trailing') | ||
220 | 247 | client.translatePath('/' + branch2.unique_name + '/trailing') | ||
221 | 248 | client.translatePath('/' + branch1.unique_name + '/different') | ||
222 | 249 | self.assertEqual( | ||
223 | 250 | [branch1.unique_name, branch2.unique_name], seen_branches) | ||
224 | 251 | |||
225 | 216 | 252 | ||
226 | 217 | class TestTrapFault(TestCase): | 253 | class TestTrapFault(TestCase): |
227 | 218 | """Tests for `trap_fault`.""" | 254 | """Tests for `trap_fault`.""" |
228 | 219 | 255 | ||
229 | === added file 'lib/lp/codehosting/vfs/tests/test_hooks.py' | |||
230 | --- lib/lp/codehosting/vfs/tests/test_hooks.py 1970-01-01 00:00:00 +0000 | |||
231 | +++ lib/lp/codehosting/vfs/tests/test_hooks.py 2010-03-24 00:47:00 +0000 | |||
232 | @@ -0,0 +1,63 @@ | |||
233 | 1 | # Copyright 2010 Canonical Ltd. This software is licensed under the | ||
234 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | ||
235 | 3 | |||
236 | 4 | """Tests for the hooks in lp.codehosting.vfs.hooks.""" | ||
237 | 5 | |||
238 | 6 | __metaclass__ = type | ||
239 | 7 | |||
240 | 8 | import unittest | ||
241 | 9 | |||
242 | 10 | from lp.codehosting.vfs.hooks import SetProcTitleHook | ||
243 | 11 | from lp.testing import TestCase | ||
244 | 12 | |||
245 | 13 | |||
246 | 14 | class FakeSetProcTitleModule: | ||
247 | 15 | """A fake for the setproctitle module. | ||
248 | 16 | |||
249 | 17 | The `setproctitle` module (obviously) has global effects, so can't really | ||
250 | 18 | be used in unit tests. Instances of this class can be used as a safe | ||
251 | 19 | replacement. | ||
252 | 20 | """ | ||
253 | 21 | |||
254 | 22 | def __init__(self, initial_title): | ||
255 | 23 | self.title = initial_title | ||
256 | 24 | |||
257 | 25 | def getproctitle(self): | ||
258 | 26 | return self.title | ||
259 | 27 | |||
260 | 28 | def setproctitle(self, new_title): | ||
261 | 29 | self.title = new_title | ||
262 | 30 | |||
263 | 31 | |||
264 | 32 | class TestSetProcTitleHook(TestCase): | ||
265 | 33 | """Tests for `SetProcTitleHook`.""" | ||
266 | 34 | |||
267 | 35 | def test_hook_once(self): | ||
268 | 36 | # Calling the hook once records the passed branch identifier in the | ||
269 | 37 | # process title. | ||
270 | 38 | initial_title = self.factory.getUniqueString() | ||
271 | 39 | setproctitle_mod = FakeSetProcTitleModule(initial_title) | ||
272 | 40 | branch_url = self.factory.getUniqueString() | ||
273 | 41 | hook = SetProcTitleHook(setproctitle_mod) | ||
274 | 42 | hook.seen(branch_url) | ||
275 | 43 | self.assertEqual( | ||
276 | 44 | initial_title + " BRANCH:" + branch_url, | ||
277 | 45 | setproctitle_mod.getproctitle()) | ||
278 | 46 | |||
279 | 47 | def test_hook_twice(self): | ||
280 | 48 | # Calling the hook twice replaces the first branch identifier in the | ||
281 | 49 | # process title. | ||
282 | 50 | initial_title = self.factory.getUniqueString() | ||
283 | 51 | setproctitle_mod = FakeSetProcTitleModule(initial_title) | ||
284 | 52 | branch_url1 = self.factory.getUniqueString() | ||
285 | 53 | branch_url2 = self.factory.getUniqueString() | ||
286 | 54 | hook = SetProcTitleHook(setproctitle_mod) | ||
287 | 55 | hook.seen(branch_url1) | ||
288 | 56 | hook.seen(branch_url2) | ||
289 | 57 | self.assertEqual( | ||
290 | 58 | initial_title + " BRANCH:" + branch_url2, | ||
291 | 59 | setproctitle_mod.getproctitle()) | ||
292 | 60 | |||
293 | 61 | |||
294 | 62 | def test_suite(): | ||
295 | 63 | return unittest.TestLoader().loadTestsFromName(__name__) | ||
296 | 0 | 64 | ||
297 | === modified file 'setup.py' | |||
298 | --- setup.py 2010-03-19 14:25:54 +0000 | |||
299 | +++ setup.py 2010-03-24 00:47:00 +0000 | |||
300 | @@ -54,12 +54,13 @@ | |||
301 | 54 | 'pytz', | 54 | 'pytz', |
302 | 55 | # This appears to be a broken indirect dependency from zope.security: | 55 | # This appears to be a broken indirect dependency from zope.security: |
303 | 56 | 'RestrictedPython', | 56 | 'RestrictedPython', |
304 | 57 | 'setproctitle', | ||
305 | 57 | 'setuptools', | 58 | 'setuptools', |
306 | 58 | 'sourcecodegen', | 59 | 'sourcecodegen', |
307 | 59 | 'storm', | 60 | 'storm', |
308 | 60 | 'testtools', | 61 | 'testtools', |
309 | 61 | 'transaction', | 62 | 'transaction', |
311 | 62 | 'Twisted', | 63 | 'Twisted', |
312 | 63 | 'wadllib', | 64 | 'wadllib', |
313 | 64 | 'z3c.pt', | 65 | 'z3c.pt', |
314 | 65 | 'z3c.ptcompat', | 66 | 'z3c.ptcompat', |
315 | 66 | 67 | ||
316 | === modified file 'versions.cfg' | |||
317 | --- versions.cfg 2010-03-23 18:27:27 +0000 | |||
318 | +++ versions.cfg 2010-03-24 00:47:00 +0000 | |||
319 | @@ -52,6 +52,7 @@ | |||
320 | 52 | pytz = 2009l | 52 | pytz = 2009l |
321 | 53 | RestrictedPython = 3.5.1 | 53 | RestrictedPython = 3.5.1 |
322 | 54 | roman = 1.4.0 | 54 | roman = 1.4.0 |
323 | 55 | setproctitle = 1.0 | ||
324 | 55 | setuptools = 0.6c9 | 56 | setuptools = 0.6c9 |
325 | 56 | simplejson = 2.0.9 | 57 | simplejson = 2.0.9 |
326 | 57 | simplesettings = 0.4 | 58 | simplesettings = 0.4 |
Looks good. I hope it works :-)