Merge lp:~jelmer/ubuntu/oneiric/bzr-builder/oneiric into lp:ubuntu/oneiric/bzr-builder
- Oneiric (11.10)
- oneiric
- Merge into oneiric
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Merge reported by: | James Westby |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/ubuntu/oneiric/bzr-builder/oneiric |
Merge into: | lp:ubuntu/oneiric/bzr-builder |
Diff against target: |
10319 lines (+54/-4428) 19 files modified
.bzr-builddeb/default.conf (+3/-0) COPYING (+0/-674) TODO (+0/-5) __init__.py (+0/-165) bzrlibbackports.py (+0/-227) cmds.py (+0/-507) debian/changelog (+10/-0) debian/control (+5/-3) debian/patches/01_broken_test (+24/-0) debian/patches/series (+1/-0) debian/rules (+10/-0) debian/source/format (+1/-0) ppa.py (+0/-124) recipe.py (+0/-1189) setup.py (+0/-17) tests/__init__.py (+0/-29) tests/test_blackbox.py (+0/-286) tests/test_ppa.py (+0/-28) tests/test_recipe.py (+0/-1174) |
To merge this branch: | bzr merge lp:~jelmer/ubuntu/oneiric/bzr-builder/oneiric |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+64579@code.launchpad.net |
Commit message
Description of the change
Update bzr-builder to the next version.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory '.bzr-builddeb' |
2 | === added file '.bzr-builddeb/default.conf' |
3 | --- .bzr-builddeb/default.conf 1970-01-01 00:00:00 +0000 |
4 | +++ .bzr-builddeb/default.conf 2011-06-14 17:23:32 +0000 |
5 | @@ -0,0 +1,3 @@ |
6 | +[BUILDDEB] |
7 | +upstream-branch = lp:bzr-builder |
8 | +export-upstream-revision = tag:$UPSTREAM_VERSION |
9 | |
10 | === added file 'COPYING' |
11 | --- COPYING 1970-01-01 00:00:00 +0000 |
12 | +++ COPYING 2011-06-14 17:23:32 +0000 |
13 | @@ -0,0 +1,674 @@ |
14 | + GNU GENERAL PUBLIC LICENSE |
15 | + Version 3, 29 June 2007 |
16 | + |
17 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
18 | + Everyone is permitted to copy and distribute verbatim copies |
19 | + of this license document, but changing it is not allowed. |
20 | + |
21 | + Preamble |
22 | + |
23 | + The GNU General Public License is a free, copyleft license for |
24 | +software and other kinds of works. |
25 | + |
26 | + The licenses for most software and other practical works are designed |
27 | +to take away your freedom to share and change the works. By contrast, |
28 | +the GNU General Public License is intended to guarantee your freedom to |
29 | +share and change all versions of a program--to make sure it remains free |
30 | +software for all its users. We, the Free Software Foundation, use the |
31 | +GNU General Public License for most of our software; it applies also to |
32 | +any other work released this way by its authors. You can apply it to |
33 | +your programs, too. |
34 | + |
35 | + When we speak of free software, we are referring to freedom, not |
36 | +price. Our General Public Licenses are designed to make sure that you |
37 | +have the freedom to distribute copies of free software (and charge for |
38 | +them if you wish), that you receive source code or can get it if you |
39 | +want it, that you can change the software or use pieces of it in new |
40 | +free programs, and that you know you can do these things. |
41 | + |
42 | + To protect your rights, we need to prevent others from denying you |
43 | +these rights or asking you to surrender the rights. Therefore, you have |
44 | +certain responsibilities if you distribute copies of the software, or if |
45 | +you modify it: responsibilities to respect the freedom of others. |
46 | + |
47 | + For example, if you distribute copies of such a program, whether |
48 | +gratis or for a fee, you must pass on to the recipients the same |
49 | +freedoms that you received. You must make sure that they, too, receive |
50 | +or can get the source code. And you must show them these terms so they |
51 | +know their rights. |
52 | + |
53 | + Developers that use the GNU GPL protect your rights with two steps: |
54 | +(1) assert copyright on the software, and (2) offer you this License |
55 | +giving you legal permission to copy, distribute and/or modify it. |
56 | + |
57 | + For the developers' and authors' protection, the GPL clearly explains |
58 | +that there is no warranty for this free software. For both users' and |
59 | +authors' sake, the GPL requires that modified versions be marked as |
60 | +changed, so that their problems will not be attributed erroneously to |
61 | +authors of previous versions. |
62 | + |
63 | + Some devices are designed to deny users access to install or run |
64 | +modified versions of the software inside them, although the manufacturer |
65 | +can do so. This is fundamentally incompatible with the aim of |
66 | +protecting users' freedom to change the software. The systematic |
67 | +pattern of such abuse occurs in the area of products for individuals to |
68 | +use, which is precisely where it is most unacceptable. Therefore, we |
69 | +have designed this version of the GPL to prohibit the practice for those |
70 | +products. If such problems arise substantially in other domains, we |
71 | +stand ready to extend this provision to those domains in future versions |
72 | +of the GPL, as needed to protect the freedom of users. |
73 | + |
74 | + Finally, every program is threatened constantly by software patents. |
75 | +States should not allow patents to restrict development and use of |
76 | +software on general-purpose computers, but in those that do, we wish to |
77 | +avoid the special danger that patents applied to a free program could |
78 | +make it effectively proprietary. To prevent this, the GPL assures that |
79 | +patents cannot be used to render the program non-free. |
80 | + |
81 | + The precise terms and conditions for copying, distribution and |
82 | +modification follow. |
83 | + |
84 | + TERMS AND CONDITIONS |
85 | + |
86 | + 0. Definitions. |
87 | + |
88 | + "This License" refers to version 3 of the GNU General Public License. |
89 | + |
90 | + "Copyright" also means copyright-like laws that apply to other kinds of |
91 | +works, such as semiconductor masks. |
92 | + |
93 | + "The Program" refers to any copyrightable work licensed under this |
94 | +License. Each licensee is addressed as "you". "Licensees" and |
95 | +"recipients" may be individuals or organizations. |
96 | + |
97 | + To "modify" a work means to copy from or adapt all or part of the work |
98 | +in a fashion requiring copyright permission, other than the making of an |
99 | +exact copy. The resulting work is called a "modified version" of the |
100 | +earlier work or a work "based on" the earlier work. |
101 | + |
102 | + A "covered work" means either the unmodified Program or a work based |
103 | +on the Program. |
104 | + |
105 | + To "propagate" a work means to do anything with it that, without |
106 | +permission, would make you directly or secondarily liable for |
107 | +infringement under applicable copyright law, except executing it on a |
108 | +computer or modifying a private copy. Propagation includes copying, |
109 | +distribution (with or without modification), making available to the |
110 | +public, and in some countries other activities as well. |
111 | + |
112 | + To "convey" a work means any kind of propagation that enables other |
113 | +parties to make or receive copies. Mere interaction with a user through |
114 | +a computer network, with no transfer of a copy, is not conveying. |
115 | + |
116 | + An interactive user interface displays "Appropriate Legal Notices" |
117 | +to the extent that it includes a convenient and prominently visible |
118 | +feature that (1) displays an appropriate copyright notice, and (2) |
119 | +tells the user that there is no warranty for the work (except to the |
120 | +extent that warranties are provided), that licensees may convey the |
121 | +work under this License, and how to view a copy of this License. If |
122 | +the interface presents a list of user commands or options, such as a |
123 | +menu, a prominent item in the list meets this criterion. |
124 | + |
125 | + 1. Source Code. |
126 | + |
127 | + The "source code" for a work means the preferred form of the work |
128 | +for making modifications to it. "Object code" means any non-source |
129 | +form of a work. |
130 | + |
131 | + A "Standard Interface" means an interface that either is an official |
132 | +standard defined by a recognized standards body, or, in the case of |
133 | +interfaces specified for a particular programming language, one that |
134 | +is widely used among developers working in that language. |
135 | + |
136 | + The "System Libraries" of an executable work include anything, other |
137 | +than the work as a whole, that (a) is included in the normal form of |
138 | +packaging a Major Component, but which is not part of that Major |
139 | +Component, and (b) serves only to enable use of the work with that |
140 | +Major Component, or to implement a Standard Interface for which an |
141 | +implementation is available to the public in source code form. A |
142 | +"Major Component", in this context, means a major essential component |
143 | +(kernel, window system, and so on) of the specific operating system |
144 | +(if any) on which the executable work runs, or a compiler used to |
145 | +produce the work, or an object code interpreter used to run it. |
146 | + |
147 | + The "Corresponding Source" for a work in object code form means all |
148 | +the source code needed to generate, install, and (for an executable |
149 | +work) run the object code and to modify the work, including scripts to |
150 | +control those activities. However, it does not include the work's |
151 | +System Libraries, or general-purpose tools or generally available free |
152 | +programs which are used unmodified in performing those activities but |
153 | +which are not part of the work. For example, Corresponding Source |
154 | +includes interface definition files associated with source files for |
155 | +the work, and the source code for shared libraries and dynamically |
156 | +linked subprograms that the work is specifically designed to require, |
157 | +such as by intimate data communication or control flow between those |
158 | +subprograms and other parts of the work. |
159 | + |
160 | + The Corresponding Source need not include anything that users |
161 | +can regenerate automatically from other parts of the Corresponding |
162 | +Source. |
163 | + |
164 | + The Corresponding Source for a work in source code form is that |
165 | +same work. |
166 | + |
167 | + 2. Basic Permissions. |
168 | + |
169 | + All rights granted under this License are granted for the term of |
170 | +copyright on the Program, and are irrevocable provided the stated |
171 | +conditions are met. This License explicitly affirms your unlimited |
172 | +permission to run the unmodified Program. The output from running a |
173 | +covered work is covered by this License only if the output, given its |
174 | +content, constitutes a covered work. This License acknowledges your |
175 | +rights of fair use or other equivalent, as provided by copyright law. |
176 | + |
177 | + You may make, run and propagate covered works that you do not |
178 | +convey, without conditions so long as your license otherwise remains |
179 | +in force. You may convey covered works to others for the sole purpose |
180 | +of having them make modifications exclusively for you, or provide you |
181 | +with facilities for running those works, provided that you comply with |
182 | +the terms of this License in conveying all material for which you do |
183 | +not control copyright. Those thus making or running the covered works |
184 | +for you must do so exclusively on your behalf, under your direction |
185 | +and control, on terms that prohibit them from making any copies of |
186 | +your copyrighted material outside their relationship with you. |
187 | + |
188 | + Conveying under any other circumstances is permitted solely under |
189 | +the conditions stated below. Sublicensing is not allowed; section 10 |
190 | +makes it unnecessary. |
191 | + |
192 | + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
193 | + |
194 | + No covered work shall be deemed part of an effective technological |
195 | +measure under any applicable law fulfilling obligations under article |
196 | +11 of the WIPO copyright treaty adopted on 20 December 1996, or |
197 | +similar laws prohibiting or restricting circumvention of such |
198 | +measures. |
199 | + |
200 | + When you convey a covered work, you waive any legal power to forbid |
201 | +circumvention of technological measures to the extent such circumvention |
202 | +is effected by exercising rights under this License with respect to |
203 | +the covered work, and you disclaim any intention to limit operation or |
204 | +modification of the work as a means of enforcing, against the work's |
205 | +users, your or third parties' legal rights to forbid circumvention of |
206 | +technological measures. |
207 | + |
208 | + 4. Conveying Verbatim Copies. |
209 | + |
210 | + You may convey verbatim copies of the Program's source code as you |
211 | +receive it, in any medium, provided that you conspicuously and |
212 | +appropriately publish on each copy an appropriate copyright notice; |
213 | +keep intact all notices stating that this License and any |
214 | +non-permissive terms added in accord with section 7 apply to the code; |
215 | +keep intact all notices of the absence of any warranty; and give all |
216 | +recipients a copy of this License along with the Program. |
217 | + |
218 | + You may charge any price or no price for each copy that you convey, |
219 | +and you may offer support or warranty protection for a fee. |
220 | + |
221 | + 5. Conveying Modified Source Versions. |
222 | + |
223 | + You may convey a work based on the Program, or the modifications to |
224 | +produce it from the Program, in the form of source code under the |
225 | +terms of section 4, provided that you also meet all of these conditions: |
226 | + |
227 | + a) The work must carry prominent notices stating that you modified |
228 | + it, and giving a relevant date. |
229 | + |
230 | + b) The work must carry prominent notices stating that it is |
231 | + released under this License and any conditions added under section |
232 | + 7. This requirement modifies the requirement in section 4 to |
233 | + "keep intact all notices". |
234 | + |
235 | + c) You must license the entire work, as a whole, under this |
236 | + License to anyone who comes into possession of a copy. This |
237 | + License will therefore apply, along with any applicable section 7 |
238 | + additional terms, to the whole of the work, and all its parts, |
239 | + regardless of how they are packaged. This License gives no |
240 | + permission to license the work in any other way, but it does not |
241 | + invalidate such permission if you have separately received it. |
242 | + |
243 | + d) If the work has interactive user interfaces, each must display |
244 | + Appropriate Legal Notices; however, if the Program has interactive |
245 | + interfaces that do not display Appropriate Legal Notices, your |
246 | + work need not make them do so. |
247 | + |
248 | + A compilation of a covered work with other separate and independent |
249 | +works, which are not by their nature extensions of the covered work, |
250 | +and which are not combined with it such as to form a larger program, |
251 | +in or on a volume of a storage or distribution medium, is called an |
252 | +"aggregate" if the compilation and its resulting copyright are not |
253 | +used to limit the access or legal rights of the compilation's users |
254 | +beyond what the individual works permit. Inclusion of a covered work |
255 | +in an aggregate does not cause this License to apply to the other |
256 | +parts of the aggregate. |
257 | + |
258 | + 6. Conveying Non-Source Forms. |
259 | + |
260 | + You may convey a covered work in object code form under the terms |
261 | +of sections 4 and 5, provided that you also convey the |
262 | +machine-readable Corresponding Source under the terms of this License, |
263 | +in one of these ways: |
264 | + |
265 | + a) Convey the object code in, or embodied in, a physical product |
266 | + (including a physical distribution medium), accompanied by the |
267 | + Corresponding Source fixed on a durable physical medium |
268 | + customarily used for software interchange. |
269 | + |
270 | + b) Convey the object code in, or embodied in, a physical product |
271 | + (including a physical distribution medium), accompanied by a |
272 | + written offer, valid for at least three years and valid for as |
273 | + long as you offer spare parts or customer support for that product |
274 | + model, to give anyone who possesses the object code either (1) a |
275 | + copy of the Corresponding Source for all the software in the |
276 | + product that is covered by this License, on a durable physical |
277 | + medium customarily used for software interchange, for a price no |
278 | + more than your reasonable cost of physically performing this |
279 | + conveying of source, or (2) access to copy the |
280 | + Corresponding Source from a network server at no charge. |
281 | + |
282 | + c) Convey individual copies of the object code with a copy of the |
283 | + written offer to provide the Corresponding Source. This |
284 | + alternative is allowed only occasionally and noncommercially, and |
285 | + only if you received the object code with such an offer, in accord |
286 | + with subsection 6b. |
287 | + |
288 | + d) Convey the object code by offering access from a designated |
289 | + place (gratis or for a charge), and offer equivalent access to the |
290 | + Corresponding Source in the same way through the same place at no |
291 | + further charge. You need not require recipients to copy the |
292 | + Corresponding Source along with the object code. If the place to |
293 | + copy the object code is a network server, the Corresponding Source |
294 | + may be on a different server (operated by you or a third party) |
295 | + that supports equivalent copying facilities, provided you maintain |
296 | + clear directions next to the object code saying where to find the |
297 | + Corresponding Source. Regardless of what server hosts the |
298 | + Corresponding Source, you remain obligated to ensure that it is |
299 | + available for as long as needed to satisfy these requirements. |
300 | + |
301 | + e) Convey the object code using peer-to-peer transmission, provided |
302 | + you inform other peers where the object code and Corresponding |
303 | + Source of the work are being offered to the general public at no |
304 | + charge under subsection 6d. |
305 | + |
306 | + A separable portion of the object code, whose source code is excluded |
307 | +from the Corresponding Source as a System Library, need not be |
308 | +included in conveying the object code work. |
309 | + |
310 | + A "User Product" is either (1) a "consumer product", which means any |
311 | +tangible personal property which is normally used for personal, family, |
312 | +or household purposes, or (2) anything designed or sold for incorporation |
313 | +into a dwelling. In determining whether a product is a consumer product, |
314 | +doubtful cases shall be resolved in favor of coverage. For a particular |
315 | +product received by a particular user, "normally used" refers to a |
316 | +typical or common use of that class of product, regardless of the status |
317 | +of the particular user or of the way in which the particular user |
318 | +actually uses, or expects or is expected to use, the product. A product |
319 | +is a consumer product regardless of whether the product has substantial |
320 | +commercial, industrial or non-consumer uses, unless such uses represent |
321 | +the only significant mode of use of the product. |
322 | + |
323 | + "Installation Information" for a User Product means any methods, |
324 | +procedures, authorization keys, or other information required to install |
325 | +and execute modified versions of a covered work in that User Product from |
326 | +a modified version of its Corresponding Source. The information must |
327 | +suffice to ensure that the continued functioning of the modified object |
328 | +code is in no case prevented or interfered with solely because |
329 | +modification has been made. |
330 | + |
331 | + If you convey an object code work under this section in, or with, or |
332 | +specifically for use in, a User Product, and the conveying occurs as |
333 | +part of a transaction in which the right of possession and use of the |
334 | +User Product is transferred to the recipient in perpetuity or for a |
335 | +fixed term (regardless of how the transaction is characterized), the |
336 | +Corresponding Source conveyed under this section must be accompanied |
337 | +by the Installation Information. But this requirement does not apply |
338 | +if neither you nor any third party retains the ability to install |
339 | +modified object code on the User Product (for example, the work has |
340 | +been installed in ROM). |
341 | + |
342 | + The requirement to provide Installation Information does not include a |
343 | +requirement to continue to provide support service, warranty, or updates |
344 | +for a work that has been modified or installed by the recipient, or for |
345 | +the User Product in which it has been modified or installed. Access to a |
346 | +network may be denied when the modification itself materially and |
347 | +adversely affects the operation of the network or violates the rules and |
348 | +protocols for communication across the network. |
349 | + |
350 | + Corresponding Source conveyed, and Installation Information provided, |
351 | +in accord with this section must be in a format that is publicly |
352 | +documented (and with an implementation available to the public in |
353 | +source code form), and must require no special password or key for |
354 | +unpacking, reading or copying. |
355 | + |
356 | + 7. Additional Terms. |
357 | + |
358 | + "Additional permissions" are terms that supplement the terms of this |
359 | +License by making exceptions from one or more of its conditions. |
360 | +Additional permissions that are applicable to the entire Program shall |
361 | +be treated as though they were included in this License, to the extent |
362 | +that they are valid under applicable law. If additional permissions |
363 | +apply only to part of the Program, that part may be used separately |
364 | +under those permissions, but the entire Program remains governed by |
365 | +this License without regard to the additional permissions. |
366 | + |
367 | + When you convey a copy of a covered work, you may at your option |
368 | +remove any additional permissions from that copy, or from any part of |
369 | +it. (Additional permissions may be written to require their own |
370 | +removal in certain cases when you modify the work.) You may place |
371 | +additional permissions on material, added by you to a covered work, |
372 | +for which you have or can give appropriate copyright permission. |
373 | + |
374 | + Notwithstanding any other provision of this License, for material you |
375 | +add to a covered work, you may (if authorized by the copyright holders of |
376 | +that material) supplement the terms of this License with terms: |
377 | + |
378 | + a) Disclaiming warranty or limiting liability differently from the |
379 | + terms of sections 15 and 16 of this License; or |
380 | + |
381 | + b) Requiring preservation of specified reasonable legal notices or |
382 | + author attributions in that material or in the Appropriate Legal |
383 | + Notices displayed by works containing it; or |
384 | + |
385 | + c) Prohibiting misrepresentation of the origin of that material, or |
386 | + requiring that modified versions of such material be marked in |
387 | + reasonable ways as different from the original version; or |
388 | + |
389 | + d) Limiting the use for publicity purposes of names of licensors or |
390 | + authors of the material; or |
391 | + |
392 | + e) Declining to grant rights under trademark law for use of some |
393 | + trade names, trademarks, or service marks; or |
394 | + |
395 | + f) Requiring indemnification of licensors and authors of that |
396 | + material by anyone who conveys the material (or modified versions of |
397 | + it) with contractual assumptions of liability to the recipient, for |
398 | + any liability that these contractual assumptions directly impose on |
399 | + those licensors and authors. |
400 | + |
401 | + All other non-permissive additional terms are considered "further |
402 | +restrictions" within the meaning of section 10. If the Program as you |
403 | +received it, or any part of it, contains a notice stating that it is |
404 | +governed by this License along with a term that is a further |
405 | +restriction, you may remove that term. If a license document contains |
406 | +a further restriction but permits relicensing or conveying under this |
407 | +License, you may add to a covered work material governed by the terms |
408 | +of that license document, provided that the further restriction does |
409 | +not survive such relicensing or conveying. |
410 | + |
411 | + If you add terms to a covered work in accord with this section, you |
412 | +must place, in the relevant source files, a statement of the |
413 | +additional terms that apply to those files, or a notice indicating |
414 | +where to find the applicable terms. |
415 | + |
416 | + Additional terms, permissive or non-permissive, may be stated in the |
417 | +form of a separately written license, or stated as exceptions; |
418 | +the above requirements apply either way. |
419 | + |
420 | + 8. Termination. |
421 | + |
422 | + You may not propagate or modify a covered work except as expressly |
423 | +provided under this License. Any attempt otherwise to propagate or |
424 | +modify it is void, and will automatically terminate your rights under |
425 | +this License (including any patent licenses granted under the third |
426 | +paragraph of section 11). |
427 | + |
428 | + However, if you cease all violation of this License, then your |
429 | +license from a particular copyright holder is reinstated (a) |
430 | +provisionally, unless and until the copyright holder explicitly and |
431 | +finally terminates your license, and (b) permanently, if the copyright |
432 | +holder fails to notify you of the violation by some reasonable means |
433 | +prior to 60 days after the cessation. |
434 | + |
435 | + Moreover, your license from a particular copyright holder is |
436 | +reinstated permanently if the copyright holder notifies you of the |
437 | +violation by some reasonable means, this is the first time you have |
438 | +received notice of violation of this License (for any work) from that |
439 | +copyright holder, and you cure the violation prior to 30 days after |
440 | +your receipt of the notice. |
441 | + |
442 | + Termination of your rights under this section does not terminate the |
443 | +licenses of parties who have received copies or rights from you under |
444 | +this License. If your rights have been terminated and not permanently |
445 | +reinstated, you do not qualify to receive new licenses for the same |
446 | +material under section 10. |
447 | + |
448 | + 9. Acceptance Not Required for Having Copies. |
449 | + |
450 | + You are not required to accept this License in order to receive or |
451 | +run a copy of the Program. Ancillary propagation of a covered work |
452 | +occurring solely as a consequence of using peer-to-peer transmission |
453 | +to receive a copy likewise does not require acceptance. However, |
454 | +nothing other than this License grants you permission to propagate or |
455 | +modify any covered work. These actions infringe copyright if you do |
456 | +not accept this License. Therefore, by modifying or propagating a |
457 | +covered work, you indicate your acceptance of this License to do so. |
458 | + |
459 | + 10. Automatic Licensing of Downstream Recipients. |
460 | + |
461 | + Each time you convey a covered work, the recipient automatically |
462 | +receives a license from the original licensors, to run, modify and |
463 | +propagate that work, subject to this License. You are not responsible |
464 | +for enforcing compliance by third parties with this License. |
465 | + |
466 | + An "entity transaction" is a transaction transferring control of an |
467 | +organization, or substantially all assets of one, or subdividing an |
468 | +organization, or merging organizations. If propagation of a covered |
469 | +work results from an entity transaction, each party to that |
470 | +transaction who receives a copy of the work also receives whatever |
471 | +licenses to the work the party's predecessor in interest had or could |
472 | +give under the previous paragraph, plus a right to possession of the |
473 | +Corresponding Source of the work from the predecessor in interest, if |
474 | +the predecessor has it or can get it with reasonable efforts. |
475 | + |
476 | + You may not impose any further restrictions on the exercise of the |
477 | +rights granted or affirmed under this License. For example, you may |
478 | +not impose a license fee, royalty, or other charge for exercise of |
479 | +rights granted under this License, and you may not initiate litigation |
480 | +(including a cross-claim or counterclaim in a lawsuit) alleging that |
481 | +any patent claim is infringed by making, using, selling, offering for |
482 | +sale, or importing the Program or any portion of it. |
483 | + |
484 | + 11. Patents. |
485 | + |
486 | + A "contributor" is a copyright holder who authorizes use under this |
487 | +License of the Program or a work on which the Program is based. The |
488 | +work thus licensed is called the contributor's "contributor version". |
489 | + |
490 | + A contributor's "essential patent claims" are all patent claims |
491 | +owned or controlled by the contributor, whether already acquired or |
492 | +hereafter acquired, that would be infringed by some manner, permitted |
493 | +by this License, of making, using, or selling its contributor version, |
494 | +but do not include claims that would be infringed only as a |
495 | +consequence of further modification of the contributor version. For |
496 | +purposes of this definition, "control" includes the right to grant |
497 | +patent sublicenses in a manner consistent with the requirements of |
498 | +this License. |
499 | + |
500 | + Each contributor grants you a non-exclusive, worldwide, royalty-free |
501 | +patent license under the contributor's essential patent claims, to |
502 | +make, use, sell, offer for sale, import and otherwise run, modify and |
503 | +propagate the contents of its contributor version. |
504 | + |
505 | + In the following three paragraphs, a "patent license" is any express |
506 | +agreement or commitment, however denominated, not to enforce a patent |
507 | +(such as an express permission to practice a patent or covenant not to |
508 | +sue for patent infringement). To "grant" such a patent license to a |
509 | +party means to make such an agreement or commitment not to enforce a |
510 | +patent against the party. |
511 | + |
512 | + If you convey a covered work, knowingly relying on a patent license, |
513 | +and the Corresponding Source of the work is not available for anyone |
514 | +to copy, free of charge and under the terms of this License, through a |
515 | +publicly available network server or other readily accessible means, |
516 | +then you must either (1) cause the Corresponding Source to be so |
517 | +available, or (2) arrange to deprive yourself of the benefit of the |
518 | +patent license for this particular work, or (3) arrange, in a manner |
519 | +consistent with the requirements of this License, to extend the patent |
520 | +license to downstream recipients. "Knowingly relying" means you have |
521 | +actual knowledge that, but for the patent license, your conveying the |
522 | +covered work in a country, or your recipient's use of the covered work |
523 | +in a country, would infringe one or more identifiable patents in that |
524 | +country that you have reason to believe are valid. |
525 | + |
526 | + If, pursuant to or in connection with a single transaction or |
527 | +arrangement, you convey, or propagate by procuring conveyance of, a |
528 | +covered work, and grant a patent license to some of the parties |
529 | +receiving the covered work authorizing them to use, propagate, modify |
530 | +or convey a specific copy of the covered work, then the patent license |
531 | +you grant is automatically extended to all recipients of the covered |
532 | +work and works based on it. |
533 | + |
534 | + A patent license is "discriminatory" if it does not include within |
535 | +the scope of its coverage, prohibits the exercise of, or is |
536 | +conditioned on the non-exercise of one or more of the rights that are |
537 | +specifically granted under this License. You may not convey a covered |
538 | +work if you are a party to an arrangement with a third party that is |
539 | +in the business of distributing software, under which you make payment |
540 | +to the third party based on the extent of your activity of conveying |
541 | +the work, and under which the third party grants, to any of the |
542 | +parties who would receive the covered work from you, a discriminatory |
543 | +patent license (a) in connection with copies of the covered work |
544 | +conveyed by you (or copies made from those copies), or (b) primarily |
545 | +for and in connection with specific products or compilations that |
546 | +contain the covered work, unless you entered into that arrangement, |
547 | +or that patent license was granted, prior to 28 March 2007. |
548 | + |
549 | + Nothing in this License shall be construed as excluding or limiting |
550 | +any implied license or other defenses to infringement that may |
551 | +otherwise be available to you under applicable patent law. |
552 | + |
553 | + 12. No Surrender of Others' Freedom. |
554 | + |
555 | + If conditions are imposed on you (whether by court order, agreement or |
556 | +otherwise) that contradict the conditions of this License, they do not |
557 | +excuse you from the conditions of this License. If you cannot convey a |
558 | +covered work so as to satisfy simultaneously your obligations under this |
559 | +License and any other pertinent obligations, then as a consequence you may |
560 | +not convey it at all. For example, if you agree to terms that obligate you |
561 | +to collect a royalty for further conveying from those to whom you convey |
562 | +the Program, the only way you could satisfy both those terms and this |
563 | +License would be to refrain entirely from conveying the Program. |
564 | + |
565 | + 13. Use with the GNU Affero General Public License. |
566 | + |
567 | + Notwithstanding any other provision of this License, you have |
568 | +permission to link or combine any covered work with a work licensed |
569 | +under version 3 of the GNU Affero General Public License into a single |
570 | +combined work, and to convey the resulting work. The terms of this |
571 | +License will continue to apply to the part which is the covered work, |
572 | +but the special requirements of the GNU Affero General Public License, |
573 | +section 13, concerning interaction through a network will apply to the |
574 | +combination as such. |
575 | + |
576 | + 14. Revised Versions of this License. |
577 | + |
578 | + The Free Software Foundation may publish revised and/or new versions of |
579 | +the GNU General Public License from time to time. Such new versions will |
580 | +be similar in spirit to the present version, but may differ in detail to |
581 | +address new problems or concerns. |
582 | + |
583 | + Each version is given a distinguishing version number. If the |
584 | +Program specifies that a certain numbered version of the GNU General |
585 | +Public License "or any later version" applies to it, you have the |
586 | +option of following the terms and conditions either of that numbered |
587 | +version or of any later version published by the Free Software |
588 | +Foundation. If the Program does not specify a version number of the |
589 | +GNU General Public License, you may choose any version ever published |
590 | +by the Free Software Foundation. |
591 | + |
592 | + If the Program specifies that a proxy can decide which future |
593 | +versions of the GNU General Public License can be used, that proxy's |
594 | +public statement of acceptance of a version permanently authorizes you |
595 | +to choose that version for the Program. |
596 | + |
597 | + Later license versions may give you additional or different |
598 | +permissions. However, no additional obligations are imposed on any |
599 | +author or copyright holder as a result of your choosing to follow a |
600 | +later version. |
601 | + |
602 | + 15. Disclaimer of Warranty. |
603 | + |
604 | + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
605 | +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
606 | +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
607 | +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
608 | +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
609 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
610 | +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
611 | +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
612 | + |
613 | + 16. Limitation of Liability. |
614 | + |
615 | + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
616 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
617 | +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
618 | +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
619 | +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
620 | +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
621 | +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
622 | +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
623 | +SUCH DAMAGES. |
624 | + |
625 | + 17. Interpretation of Sections 15 and 16. |
626 | + |
627 | + If the disclaimer of warranty and limitation of liability provided |
628 | +above cannot be given local legal effect according to their terms, |
629 | +reviewing courts shall apply local law that most closely approximates |
630 | +an absolute waiver of all civil liability in connection with the |
631 | +Program, unless a warranty or assumption of liability accompanies a |
632 | +copy of the Program in return for a fee. |
633 | + |
634 | + END OF TERMS AND CONDITIONS |
635 | + |
636 | + How to Apply These Terms to Your New Programs |
637 | + |
638 | + If you develop a new program, and you want it to be of the greatest |
639 | +possible use to the public, the best way to achieve this is to make it |
640 | +free software which everyone can redistribute and change under these terms. |
641 | + |
642 | + To do so, attach the following notices to the program. It is safest |
643 | +to attach them to the start of each source file to most effectively |
644 | +state the exclusion of warranty; and each file should have at least |
645 | +the "copyright" line and a pointer to where the full notice is found. |
646 | + |
647 | + <one line to give the program's name and a brief idea of what it does.> |
648 | + Copyright (C) <year> <name of author> |
649 | + |
650 | + This program is free software: you can redistribute it and/or modify |
651 | + it under the terms of the GNU General Public License as published by |
652 | + the Free Software Foundation, either version 3 of the License, or |
653 | + (at your option) any later version. |
654 | + |
655 | + This program is distributed in the hope that it will be useful, |
656 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
657 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
658 | + GNU General Public License for more details. |
659 | + |
660 | + You should have received a copy of the GNU General Public License |
661 | + along with this program. If not, see <http://www.gnu.org/licenses/>. |
662 | + |
663 | +Also add information on how to contact you by electronic and paper mail. |
664 | + |
665 | + If the program does terminal interaction, make it output a short |
666 | +notice like this when it starts in an interactive mode: |
667 | + |
668 | + <program> Copyright (C) <year> <name of author> |
669 | + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
670 | + This is free software, and you are welcome to redistribute it |
671 | + under certain conditions; type `show c' for details. |
672 | + |
673 | +The hypothetical commands `show w' and `show c' should show the appropriate |
674 | +parts of the General Public License. Of course, your program's commands |
675 | +might be different; for a GUI interface, you would use an "about box". |
676 | + |
677 | + You should also get your employer (if you work as a programmer) or school, |
678 | +if any, to sign a "copyright disclaimer" for the program, if necessary. |
679 | +For more information on this, and how to apply and follow the GNU GPL, see |
680 | +<http://www.gnu.org/licenses/>. |
681 | + |
682 | + The GNU General Public License does not permit incorporating your program |
683 | +into proprietary programs. If your program is a subroutine library, you |
684 | +may consider it more useful to permit linking proprietary applications with |
685 | +the library. If this is what you want to do, use the GNU Lesser General |
686 | +Public License instead of this License. But first, please read |
687 | +<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
688 | |
689 | === removed file 'COPYING' |
690 | --- COPYING 2009-08-25 23:59:46 +0000 |
691 | +++ COPYING 1970-01-01 00:00:00 +0000 |
692 | @@ -1,674 +0,0 @@ |
693 | - GNU GENERAL PUBLIC LICENSE |
694 | - Version 3, 29 June 2007 |
695 | - |
696 | - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
697 | - Everyone is permitted to copy and distribute verbatim copies |
698 | - of this license document, but changing it is not allowed. |
699 | - |
700 | - Preamble |
701 | - |
702 | - The GNU General Public License is a free, copyleft license for |
703 | -software and other kinds of works. |
704 | - |
705 | - The licenses for most software and other practical works are designed |
706 | -to take away your freedom to share and change the works. By contrast, |
707 | -the GNU General Public License is intended to guarantee your freedom to |
708 | -share and change all versions of a program--to make sure it remains free |
709 | -software for all its users. We, the Free Software Foundation, use the |
710 | -GNU General Public License for most of our software; it applies also to |
711 | -any other work released this way by its authors. You can apply it to |
712 | -your programs, too. |
713 | - |
714 | - When we speak of free software, we are referring to freedom, not |
715 | -price. Our General Public Licenses are designed to make sure that you |
716 | -have the freedom to distribute copies of free software (and charge for |
717 | -them if you wish), that you receive source code or can get it if you |
718 | -want it, that you can change the software or use pieces of it in new |
719 | -free programs, and that you know you can do these things. |
720 | - |
721 | - To protect your rights, we need to prevent others from denying you |
722 | -these rights or asking you to surrender the rights. Therefore, you have |
723 | -certain responsibilities if you distribute copies of the software, or if |
724 | -you modify it: responsibilities to respect the freedom of others. |
725 | - |
726 | - For example, if you distribute copies of such a program, whether |
727 | -gratis or for a fee, you must pass on to the recipients the same |
728 | -freedoms that you received. You must make sure that they, too, receive |
729 | -or can get the source code. And you must show them these terms so they |
730 | -know their rights. |
731 | - |
732 | - Developers that use the GNU GPL protect your rights with two steps: |
733 | -(1) assert copyright on the software, and (2) offer you this License |
734 | -giving you legal permission to copy, distribute and/or modify it. |
735 | - |
736 | - For the developers' and authors' protection, the GPL clearly explains |
737 | -that there is no warranty for this free software. For both users' and |
738 | -authors' sake, the GPL requires that modified versions be marked as |
739 | -changed, so that their problems will not be attributed erroneously to |
740 | -authors of previous versions. |
741 | - |
742 | - Some devices are designed to deny users access to install or run |
743 | -modified versions of the software inside them, although the manufacturer |
744 | -can do so. This is fundamentally incompatible with the aim of |
745 | -protecting users' freedom to change the software. The systematic |
746 | -pattern of such abuse occurs in the area of products for individuals to |
747 | -use, which is precisely where it is most unacceptable. Therefore, we |
748 | -have designed this version of the GPL to prohibit the practice for those |
749 | -products. If such problems arise substantially in other domains, we |
750 | -stand ready to extend this provision to those domains in future versions |
751 | -of the GPL, as needed to protect the freedom of users. |
752 | - |
753 | - Finally, every program is threatened constantly by software patents. |
754 | -States should not allow patents to restrict development and use of |
755 | -software on general-purpose computers, but in those that do, we wish to |
756 | -avoid the special danger that patents applied to a free program could |
757 | -make it effectively proprietary. To prevent this, the GPL assures that |
758 | -patents cannot be used to render the program non-free. |
759 | - |
760 | - The precise terms and conditions for copying, distribution and |
761 | -modification follow. |
762 | - |
763 | - TERMS AND CONDITIONS |
764 | - |
765 | - 0. Definitions. |
766 | - |
767 | - "This License" refers to version 3 of the GNU General Public License. |
768 | - |
769 | - "Copyright" also means copyright-like laws that apply to other kinds of |
770 | -works, such as semiconductor masks. |
771 | - |
772 | - "The Program" refers to any copyrightable work licensed under this |
773 | -License. Each licensee is addressed as "you". "Licensees" and |
774 | -"recipients" may be individuals or organizations. |
775 | - |
776 | - To "modify" a work means to copy from or adapt all or part of the work |
777 | -in a fashion requiring copyright permission, other than the making of an |
778 | -exact copy. The resulting work is called a "modified version" of the |
779 | -earlier work or a work "based on" the earlier work. |
780 | - |
781 | - A "covered work" means either the unmodified Program or a work based |
782 | -on the Program. |
783 | - |
784 | - To "propagate" a work means to do anything with it that, without |
785 | -permission, would make you directly or secondarily liable for |
786 | -infringement under applicable copyright law, except executing it on a |
787 | -computer or modifying a private copy. Propagation includes copying, |
788 | -distribution (with or without modification), making available to the |
789 | -public, and in some countries other activities as well. |
790 | - |
791 | - To "convey" a work means any kind of propagation that enables other |
792 | -parties to make or receive copies. Mere interaction with a user through |
793 | -a computer network, with no transfer of a copy, is not conveying. |
794 | - |
795 | - An interactive user interface displays "Appropriate Legal Notices" |
796 | -to the extent that it includes a convenient and prominently visible |
797 | -feature that (1) displays an appropriate copyright notice, and (2) |
798 | -tells the user that there is no warranty for the work (except to the |
799 | -extent that warranties are provided), that licensees may convey the |
800 | -work under this License, and how to view a copy of this License. If |
801 | -the interface presents a list of user commands or options, such as a |
802 | -menu, a prominent item in the list meets this criterion. |
803 | - |
804 | - 1. Source Code. |
805 | - |
806 | - The "source code" for a work means the preferred form of the work |
807 | -for making modifications to it. "Object code" means any non-source |
808 | -form of a work. |
809 | - |
810 | - A "Standard Interface" means an interface that either is an official |
811 | -standard defined by a recognized standards body, or, in the case of |
812 | -interfaces specified for a particular programming language, one that |
813 | -is widely used among developers working in that language. |
814 | - |
815 | - The "System Libraries" of an executable work include anything, other |
816 | -than the work as a whole, that (a) is included in the normal form of |
817 | -packaging a Major Component, but which is not part of that Major |
818 | -Component, and (b) serves only to enable use of the work with that |
819 | -Major Component, or to implement a Standard Interface for which an |
820 | -implementation is available to the public in source code form. A |
821 | -"Major Component", in this context, means a major essential component |
822 | -(kernel, window system, and so on) of the specific operating system |
823 | -(if any) on which the executable work runs, or a compiler used to |
824 | -produce the work, or an object code interpreter used to run it. |
825 | - |
826 | - The "Corresponding Source" for a work in object code form means all |
827 | -the source code needed to generate, install, and (for an executable |
828 | -work) run the object code and to modify the work, including scripts to |
829 | -control those activities. However, it does not include the work's |
830 | -System Libraries, or general-purpose tools or generally available free |
831 | -programs which are used unmodified in performing those activities but |
832 | -which are not part of the work. For example, Corresponding Source |
833 | -includes interface definition files associated with source files for |
834 | -the work, and the source code for shared libraries and dynamically |
835 | -linked subprograms that the work is specifically designed to require, |
836 | -such as by intimate data communication or control flow between those |
837 | -subprograms and other parts of the work. |
838 | - |
839 | - The Corresponding Source need not include anything that users |
840 | -can regenerate automatically from other parts of the Corresponding |
841 | -Source. |
842 | - |
843 | - The Corresponding Source for a work in source code form is that |
844 | -same work. |
845 | - |
846 | - 2. Basic Permissions. |
847 | - |
848 | - All rights granted under this License are granted for the term of |
849 | -copyright on the Program, and are irrevocable provided the stated |
850 | -conditions are met. This License explicitly affirms your unlimited |
851 | -permission to run the unmodified Program. The output from running a |
852 | -covered work is covered by this License only if the output, given its |
853 | -content, constitutes a covered work. This License acknowledges your |
854 | -rights of fair use or other equivalent, as provided by copyright law. |
855 | - |
856 | - You may make, run and propagate covered works that you do not |
857 | -convey, without conditions so long as your license otherwise remains |
858 | -in force. You may convey covered works to others for the sole purpose |
859 | -of having them make modifications exclusively for you, or provide you |
860 | -with facilities for running those works, provided that you comply with |
861 | -the terms of this License in conveying all material for which you do |
862 | -not control copyright. Those thus making or running the covered works |
863 | -for you must do so exclusively on your behalf, under your direction |
864 | -and control, on terms that prohibit them from making any copies of |
865 | -your copyrighted material outside their relationship with you. |
866 | - |
867 | - Conveying under any other circumstances is permitted solely under |
868 | -the conditions stated below. Sublicensing is not allowed; section 10 |
869 | -makes it unnecessary. |
870 | - |
871 | - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
872 | - |
873 | - No covered work shall be deemed part of an effective technological |
874 | -measure under any applicable law fulfilling obligations under article |
875 | -11 of the WIPO copyright treaty adopted on 20 December 1996, or |
876 | -similar laws prohibiting or restricting circumvention of such |
877 | -measures. |
878 | - |
879 | - When you convey a covered work, you waive any legal power to forbid |
880 | -circumvention of technological measures to the extent such circumvention |
881 | -is effected by exercising rights under this License with respect to |
882 | -the covered work, and you disclaim any intention to limit operation or |
883 | -modification of the work as a means of enforcing, against the work's |
884 | -users, your or third parties' legal rights to forbid circumvention of |
885 | -technological measures. |
886 | - |
887 | - 4. Conveying Verbatim Copies. |
888 | - |
889 | - You may convey verbatim copies of the Program's source code as you |
890 | -receive it, in any medium, provided that you conspicuously and |
891 | -appropriately publish on each copy an appropriate copyright notice; |
892 | -keep intact all notices stating that this License and any |
893 | -non-permissive terms added in accord with section 7 apply to the code; |
894 | -keep intact all notices of the absence of any warranty; and give all |
895 | -recipients a copy of this License along with the Program. |
896 | - |
897 | - You may charge any price or no price for each copy that you convey, |
898 | -and you may offer support or warranty protection for a fee. |
899 | - |
900 | - 5. Conveying Modified Source Versions. |
901 | - |
902 | - You may convey a work based on the Program, or the modifications to |
903 | -produce it from the Program, in the form of source code under the |
904 | -terms of section 4, provided that you also meet all of these conditions: |
905 | - |
906 | - a) The work must carry prominent notices stating that you modified |
907 | - it, and giving a relevant date. |
908 | - |
909 | - b) The work must carry prominent notices stating that it is |
910 | - released under this License and any conditions added under section |
911 | - 7. This requirement modifies the requirement in section 4 to |
912 | - "keep intact all notices". |
913 | - |
914 | - c) You must license the entire work, as a whole, under this |
915 | - License to anyone who comes into possession of a copy. This |
916 | - License will therefore apply, along with any applicable section 7 |
917 | - additional terms, to the whole of the work, and all its parts, |
918 | - regardless of how they are packaged. This License gives no |
919 | - permission to license the work in any other way, but it does not |
920 | - invalidate such permission if you have separately received it. |
921 | - |
922 | - d) If the work has interactive user interfaces, each must display |
923 | - Appropriate Legal Notices; however, if the Program has interactive |
924 | - interfaces that do not display Appropriate Legal Notices, your |
925 | - work need not make them do so. |
926 | - |
927 | - A compilation of a covered work with other separate and independent |
928 | -works, which are not by their nature extensions of the covered work, |
929 | -and which are not combined with it such as to form a larger program, |
930 | -in or on a volume of a storage or distribution medium, is called an |
931 | -"aggregate" if the compilation and its resulting copyright are not |
932 | -used to limit the access or legal rights of the compilation's users |
933 | -beyond what the individual works permit. Inclusion of a covered work |
934 | -in an aggregate does not cause this License to apply to the other |
935 | -parts of the aggregate. |
936 | - |
937 | - 6. Conveying Non-Source Forms. |
938 | - |
939 | - You may convey a covered work in object code form under the terms |
940 | -of sections 4 and 5, provided that you also convey the |
941 | -machine-readable Corresponding Source under the terms of this License, |
942 | -in one of these ways: |
943 | - |
944 | - a) Convey the object code in, or embodied in, a physical product |
945 | - (including a physical distribution medium), accompanied by the |
946 | - Corresponding Source fixed on a durable physical medium |
947 | - customarily used for software interchange. |
948 | - |
949 | - b) Convey the object code in, or embodied in, a physical product |
950 | - (including a physical distribution medium), accompanied by a |
951 | - written offer, valid for at least three years and valid for as |
952 | - long as you offer spare parts or customer support for that product |
953 | - model, to give anyone who possesses the object code either (1) a |
954 | - copy of the Corresponding Source for all the software in the |
955 | - product that is covered by this License, on a durable physical |
956 | - medium customarily used for software interchange, for a price no |
957 | - more than your reasonable cost of physically performing this |
958 | - conveying of source, or (2) access to copy the |
959 | - Corresponding Source from a network server at no charge. |
960 | - |
961 | - c) Convey individual copies of the object code with a copy of the |
962 | - written offer to provide the Corresponding Source. This |
963 | - alternative is allowed only occasionally and noncommercially, and |
964 | - only if you received the object code with such an offer, in accord |
965 | - with subsection 6b. |
966 | - |
967 | - d) Convey the object code by offering access from a designated |
968 | - place (gratis or for a charge), and offer equivalent access to the |
969 | - Corresponding Source in the same way through the same place at no |
970 | - further charge. You need not require recipients to copy the |
971 | - Corresponding Source along with the object code. If the place to |
972 | - copy the object code is a network server, the Corresponding Source |
973 | - may be on a different server (operated by you or a third party) |
974 | - that supports equivalent copying facilities, provided you maintain |
975 | - clear directions next to the object code saying where to find the |
976 | - Corresponding Source. Regardless of what server hosts the |
977 | - Corresponding Source, you remain obligated to ensure that it is |
978 | - available for as long as needed to satisfy these requirements. |
979 | - |
980 | - e) Convey the object code using peer-to-peer transmission, provided |
981 | - you inform other peers where the object code and Corresponding |
982 | - Source of the work are being offered to the general public at no |
983 | - charge under subsection 6d. |
984 | - |
985 | - A separable portion of the object code, whose source code is excluded |
986 | -from the Corresponding Source as a System Library, need not be |
987 | -included in conveying the object code work. |
988 | - |
989 | - A "User Product" is either (1) a "consumer product", which means any |
990 | -tangible personal property which is normally used for personal, family, |
991 | -or household purposes, or (2) anything designed or sold for incorporation |
992 | -into a dwelling. In determining whether a product is a consumer product, |
993 | -doubtful cases shall be resolved in favor of coverage. For a particular |
994 | -product received by a particular user, "normally used" refers to a |
995 | -typical or common use of that class of product, regardless of the status |
996 | -of the particular user or of the way in which the particular user |
997 | -actually uses, or expects or is expected to use, the product. A product |
998 | -is a consumer product regardless of whether the product has substantial |
999 | -commercial, industrial or non-consumer uses, unless such uses represent |
1000 | -the only significant mode of use of the product. |
1001 | - |
1002 | - "Installation Information" for a User Product means any methods, |
1003 | -procedures, authorization keys, or other information required to install |
1004 | -and execute modified versions of a covered work in that User Product from |
1005 | -a modified version of its Corresponding Source. The information must |
1006 | -suffice to ensure that the continued functioning of the modified object |
1007 | -code is in no case prevented or interfered with solely because |
1008 | -modification has been made. |
1009 | - |
1010 | - If you convey an object code work under this section in, or with, or |
1011 | -specifically for use in, a User Product, and the conveying occurs as |
1012 | -part of a transaction in which the right of possession and use of the |
1013 | -User Product is transferred to the recipient in perpetuity or for a |
1014 | -fixed term (regardless of how the transaction is characterized), the |
1015 | -Corresponding Source conveyed under this section must be accompanied |
1016 | -by the Installation Information. But this requirement does not apply |
1017 | -if neither you nor any third party retains the ability to install |
1018 | -modified object code on the User Product (for example, the work has |
1019 | -been installed in ROM). |
1020 | - |
1021 | - The requirement to provide Installation Information does not include a |
1022 | -requirement to continue to provide support service, warranty, or updates |
1023 | -for a work that has been modified or installed by the recipient, or for |
1024 | -the User Product in which it has been modified or installed. Access to a |
1025 | -network may be denied when the modification itself materially and |
1026 | -adversely affects the operation of the network or violates the rules and |
1027 | -protocols for communication across the network. |
1028 | - |
1029 | - Corresponding Source conveyed, and Installation Information provided, |
1030 | -in accord with this section must be in a format that is publicly |
1031 | -documented (and with an implementation available to the public in |
1032 | -source code form), and must require no special password or key for |
1033 | -unpacking, reading or copying. |
1034 | - |
1035 | - 7. Additional Terms. |
1036 | - |
1037 | - "Additional permissions" are terms that supplement the terms of this |
1038 | -License by making exceptions from one or more of its conditions. |
1039 | -Additional permissions that are applicable to the entire Program shall |
1040 | -be treated as though they were included in this License, to the extent |
1041 | -that they are valid under applicable law. If additional permissions |
1042 | -apply only to part of the Program, that part may be used separately |
1043 | -under those permissions, but the entire Program remains governed by |
1044 | -this License without regard to the additional permissions. |
1045 | - |
1046 | - When you convey a copy of a covered work, you may at your option |
1047 | -remove any additional permissions from that copy, or from any part of |
1048 | -it. (Additional permissions may be written to require their own |
1049 | -removal in certain cases when you modify the work.) You may place |
1050 | -additional permissions on material, added by you to a covered work, |
1051 | -for which you have or can give appropriate copyright permission. |
1052 | - |
1053 | - Notwithstanding any other provision of this License, for material you |
1054 | -add to a covered work, you may (if authorized by the copyright holders of |
1055 | -that material) supplement the terms of this License with terms: |
1056 | - |
1057 | - a) Disclaiming warranty or limiting liability differently from the |
1058 | - terms of sections 15 and 16 of this License; or |
1059 | - |
1060 | - b) Requiring preservation of specified reasonable legal notices or |
1061 | - author attributions in that material or in the Appropriate Legal |
1062 | - Notices displayed by works containing it; or |
1063 | - |
1064 | - c) Prohibiting misrepresentation of the origin of that material, or |
1065 | - requiring that modified versions of such material be marked in |
1066 | - reasonable ways as different from the original version; or |
1067 | - |
1068 | - d) Limiting the use for publicity purposes of names of licensors or |
1069 | - authors of the material; or |
1070 | - |
1071 | - e) Declining to grant rights under trademark law for use of some |
1072 | - trade names, trademarks, or service marks; or |
1073 | - |
1074 | - f) Requiring indemnification of licensors and authors of that |
1075 | - material by anyone who conveys the material (or modified versions of |
1076 | - it) with contractual assumptions of liability to the recipient, for |
1077 | - any liability that these contractual assumptions directly impose on |
1078 | - those licensors and authors. |
1079 | - |
1080 | - All other non-permissive additional terms are considered "further |
1081 | -restrictions" within the meaning of section 10. If the Program as you |
1082 | -received it, or any part of it, contains a notice stating that it is |
1083 | -governed by this License along with a term that is a further |
1084 | -restriction, you may remove that term. If a license document contains |
1085 | -a further restriction but permits relicensing or conveying under this |
1086 | -License, you may add to a covered work material governed by the terms |
1087 | -of that license document, provided that the further restriction does |
1088 | -not survive such relicensing or conveying. |
1089 | - |
1090 | - If you add terms to a covered work in accord with this section, you |
1091 | -must place, in the relevant source files, a statement of the |
1092 | -additional terms that apply to those files, or a notice indicating |
1093 | -where to find the applicable terms. |
1094 | - |
1095 | - Additional terms, permissive or non-permissive, may be stated in the |
1096 | -form of a separately written license, or stated as exceptions; |
1097 | -the above requirements apply either way. |
1098 | - |
1099 | - 8. Termination. |
1100 | - |
1101 | - You may not propagate or modify a covered work except as expressly |
1102 | -provided under this License. Any attempt otherwise to propagate or |
1103 | -modify it is void, and will automatically terminate your rights under |
1104 | -this License (including any patent licenses granted under the third |
1105 | -paragraph of section 11). |
1106 | - |
1107 | - However, if you cease all violation of this License, then your |
1108 | -license from a particular copyright holder is reinstated (a) |
1109 | -provisionally, unless and until the copyright holder explicitly and |
1110 | -finally terminates your license, and (b) permanently, if the copyright |
1111 | -holder fails to notify you of the violation by some reasonable means |
1112 | -prior to 60 days after the cessation. |
1113 | - |
1114 | - Moreover, your license from a particular copyright holder is |
1115 | -reinstated permanently if the copyright holder notifies you of the |
1116 | -violation by some reasonable means, this is the first time you have |
1117 | -received notice of violation of this License (for any work) from that |
1118 | -copyright holder, and you cure the violation prior to 30 days after |
1119 | -your receipt of the notice. |
1120 | - |
1121 | - Termination of your rights under this section does not terminate the |
1122 | -licenses of parties who have received copies or rights from you under |
1123 | -this License. If your rights have been terminated and not permanently |
1124 | -reinstated, you do not qualify to receive new licenses for the same |
1125 | -material under section 10. |
1126 | - |
1127 | - 9. Acceptance Not Required for Having Copies. |
1128 | - |
1129 | - You are not required to accept this License in order to receive or |
1130 | -run a copy of the Program. Ancillary propagation of a covered work |
1131 | -occurring solely as a consequence of using peer-to-peer transmission |
1132 | -to receive a copy likewise does not require acceptance. However, |
1133 | -nothing other than this License grants you permission to propagate or |
1134 | -modify any covered work. These actions infringe copyright if you do |
1135 | -not accept this License. Therefore, by modifying or propagating a |
1136 | -covered work, you indicate your acceptance of this License to do so. |
1137 | - |
1138 | - 10. Automatic Licensing of Downstream Recipients. |
1139 | - |
1140 | - Each time you convey a covered work, the recipient automatically |
1141 | -receives a license from the original licensors, to run, modify and |
1142 | -propagate that work, subject to this License. You are not responsible |
1143 | -for enforcing compliance by third parties with this License. |
1144 | - |
1145 | - An "entity transaction" is a transaction transferring control of an |
1146 | -organization, or substantially all assets of one, or subdividing an |
1147 | -organization, or merging organizations. If propagation of a covered |
1148 | -work results from an entity transaction, each party to that |
1149 | -transaction who receives a copy of the work also receives whatever |
1150 | -licenses to the work the party's predecessor in interest had or could |
1151 | -give under the previous paragraph, plus a right to possession of the |
1152 | -Corresponding Source of the work from the predecessor in interest, if |
1153 | -the predecessor has it or can get it with reasonable efforts. |
1154 | - |
1155 | - You may not impose any further restrictions on the exercise of the |
1156 | -rights granted or affirmed under this License. For example, you may |
1157 | -not impose a license fee, royalty, or other charge for exercise of |
1158 | -rights granted under this License, and you may not initiate litigation |
1159 | -(including a cross-claim or counterclaim in a lawsuit) alleging that |
1160 | -any patent claim is infringed by making, using, selling, offering for |
1161 | -sale, or importing the Program or any portion of it. |
1162 | - |
1163 | - 11. Patents. |
1164 | - |
1165 | - A "contributor" is a copyright holder who authorizes use under this |
1166 | -License of the Program or a work on which the Program is based. The |
1167 | -work thus licensed is called the contributor's "contributor version". |
1168 | - |
1169 | - A contributor's "essential patent claims" are all patent claims |
1170 | -owned or controlled by the contributor, whether already acquired or |
1171 | -hereafter acquired, that would be infringed by some manner, permitted |
1172 | -by this License, of making, using, or selling its contributor version, |
1173 | -but do not include claims that would be infringed only as a |
1174 | -consequence of further modification of the contributor version. For |
1175 | -purposes of this definition, "control" includes the right to grant |
1176 | -patent sublicenses in a manner consistent with the requirements of |
1177 | -this License. |
1178 | - |
1179 | - Each contributor grants you a non-exclusive, worldwide, royalty-free |
1180 | -patent license under the contributor's essential patent claims, to |
1181 | -make, use, sell, offer for sale, import and otherwise run, modify and |
1182 | -propagate the contents of its contributor version. |
1183 | - |
1184 | - In the following three paragraphs, a "patent license" is any express |
1185 | -agreement or commitment, however denominated, not to enforce a patent |
1186 | -(such as an express permission to practice a patent or covenant not to |
1187 | -sue for patent infringement). To "grant" such a patent license to a |
1188 | -party means to make such an agreement or commitment not to enforce a |
1189 | -patent against the party. |
1190 | - |
1191 | - If you convey a covered work, knowingly relying on a patent license, |
1192 | -and the Corresponding Source of the work is not available for anyone |
1193 | -to copy, free of charge and under the terms of this License, through a |
1194 | -publicly available network server or other readily accessible means, |
1195 | -then you must either (1) cause the Corresponding Source to be so |
1196 | -available, or (2) arrange to deprive yourself of the benefit of the |
1197 | -patent license for this particular work, or (3) arrange, in a manner |
1198 | -consistent with the requirements of this License, to extend the patent |
1199 | -license to downstream recipients. "Knowingly relying" means you have |
1200 | -actual knowledge that, but for the patent license, your conveying the |
1201 | -covered work in a country, or your recipient's use of the covered work |
1202 | -in a country, would infringe one or more identifiable patents in that |
1203 | -country that you have reason to believe are valid. |
1204 | - |
1205 | - If, pursuant to or in connection with a single transaction or |
1206 | -arrangement, you convey, or propagate by procuring conveyance of, a |
1207 | -covered work, and grant a patent license to some of the parties |
1208 | -receiving the covered work authorizing them to use, propagate, modify |
1209 | -or convey a specific copy of the covered work, then the patent license |
1210 | -you grant is automatically extended to all recipients of the covered |
1211 | -work and works based on it. |
1212 | - |
1213 | - A patent license is "discriminatory" if it does not include within |
1214 | -the scope of its coverage, prohibits the exercise of, or is |
1215 | -conditioned on the non-exercise of one or more of the rights that are |
1216 | -specifically granted under this License. You may not convey a covered |
1217 | -work if you are a party to an arrangement with a third party that is |
1218 | -in the business of distributing software, under which you make payment |
1219 | -to the third party based on the extent of your activity of conveying |
1220 | -the work, and under which the third party grants, to any of the |
1221 | -parties who would receive the covered work from you, a discriminatory |
1222 | -patent license (a) in connection with copies of the covered work |
1223 | -conveyed by you (or copies made from those copies), or (b) primarily |
1224 | -for and in connection with specific products or compilations that |
1225 | -contain the covered work, unless you entered into that arrangement, |
1226 | -or that patent license was granted, prior to 28 March 2007. |
1227 | - |
1228 | - Nothing in this License shall be construed as excluding or limiting |
1229 | -any implied license or other defenses to infringement that may |
1230 | -otherwise be available to you under applicable patent law. |
1231 | - |
1232 | - 12. No Surrender of Others' Freedom. |
1233 | - |
1234 | - If conditions are imposed on you (whether by court order, agreement or |
1235 | -otherwise) that contradict the conditions of this License, they do not |
1236 | -excuse you from the conditions of this License. If you cannot convey a |
1237 | -covered work so as to satisfy simultaneously your obligations under this |
1238 | -License and any other pertinent obligations, then as a consequence you may |
1239 | -not convey it at all. For example, if you agree to terms that obligate you |
1240 | -to collect a royalty for further conveying from those to whom you convey |
1241 | -the Program, the only way you could satisfy both those terms and this |
1242 | -License would be to refrain entirely from conveying the Program. |
1243 | - |
1244 | - 13. Use with the GNU Affero General Public License. |
1245 | - |
1246 | - Notwithstanding any other provision of this License, you have |
1247 | -permission to link or combine any covered work with a work licensed |
1248 | -under version 3 of the GNU Affero General Public License into a single |
1249 | -combined work, and to convey the resulting work. The terms of this |
1250 | -License will continue to apply to the part which is the covered work, |
1251 | -but the special requirements of the GNU Affero General Public License, |
1252 | -section 13, concerning interaction through a network will apply to the |
1253 | -combination as such. |
1254 | - |
1255 | - 14. Revised Versions of this License. |
1256 | - |
1257 | - The Free Software Foundation may publish revised and/or new versions of |
1258 | -the GNU General Public License from time to time. Such new versions will |
1259 | -be similar in spirit to the present version, but may differ in detail to |
1260 | -address new problems or concerns. |
1261 | - |
1262 | - Each version is given a distinguishing version number. If the |
1263 | -Program specifies that a certain numbered version of the GNU General |
1264 | -Public License "or any later version" applies to it, you have the |
1265 | -option of following the terms and conditions either of that numbered |
1266 | -version or of any later version published by the Free Software |
1267 | -Foundation. If the Program does not specify a version number of the |
1268 | -GNU General Public License, you may choose any version ever published |
1269 | -by the Free Software Foundation. |
1270 | - |
1271 | - If the Program specifies that a proxy can decide which future |
1272 | -versions of the GNU General Public License can be used, that proxy's |
1273 | -public statement of acceptance of a version permanently authorizes you |
1274 | -to choose that version for the Program. |
1275 | - |
1276 | - Later license versions may give you additional or different |
1277 | -permissions. However, no additional obligations are imposed on any |
1278 | -author or copyright holder as a result of your choosing to follow a |
1279 | -later version. |
1280 | - |
1281 | - 15. Disclaimer of Warranty. |
1282 | - |
1283 | - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
1284 | -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
1285 | -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
1286 | -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
1287 | -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
1288 | -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
1289 | -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
1290 | -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
1291 | - |
1292 | - 16. Limitation of Liability. |
1293 | - |
1294 | - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
1295 | -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
1296 | -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
1297 | -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
1298 | -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
1299 | -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
1300 | -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
1301 | -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
1302 | -SUCH DAMAGES. |
1303 | - |
1304 | - 17. Interpretation of Sections 15 and 16. |
1305 | - |
1306 | - If the disclaimer of warranty and limitation of liability provided |
1307 | -above cannot be given local legal effect according to their terms, |
1308 | -reviewing courts shall apply local law that most closely approximates |
1309 | -an absolute waiver of all civil liability in connection with the |
1310 | -Program, unless a warranty or assumption of liability accompanies a |
1311 | -copy of the Program in return for a fee. |
1312 | - |
1313 | - END OF TERMS AND CONDITIONS |
1314 | - |
1315 | - How to Apply These Terms to Your New Programs |
1316 | - |
1317 | - If you develop a new program, and you want it to be of the greatest |
1318 | -possible use to the public, the best way to achieve this is to make it |
1319 | -free software which everyone can redistribute and change under these terms. |
1320 | - |
1321 | - To do so, attach the following notices to the program. It is safest |
1322 | -to attach them to the start of each source file to most effectively |
1323 | -state the exclusion of warranty; and each file should have at least |
1324 | -the "copyright" line and a pointer to where the full notice is found. |
1325 | - |
1326 | - <one line to give the program's name and a brief idea of what it does.> |
1327 | - Copyright (C) <year> <name of author> |
1328 | - |
1329 | - This program is free software: you can redistribute it and/or modify |
1330 | - it under the terms of the GNU General Public License as published by |
1331 | - the Free Software Foundation, either version 3 of the License, or |
1332 | - (at your option) any later version. |
1333 | - |
1334 | - This program is distributed in the hope that it will be useful, |
1335 | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
1336 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1337 | - GNU General Public License for more details. |
1338 | - |
1339 | - You should have received a copy of the GNU General Public License |
1340 | - along with this program. If not, see <http://www.gnu.org/licenses/>. |
1341 | - |
1342 | -Also add information on how to contact you by electronic and paper mail. |
1343 | - |
1344 | - If the program does terminal interaction, make it output a short |
1345 | -notice like this when it starts in an interactive mode: |
1346 | - |
1347 | - <program> Copyright (C) <year> <name of author> |
1348 | - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
1349 | - This is free software, and you are welcome to redistribute it |
1350 | - under certain conditions; type `show c' for details. |
1351 | - |
1352 | -The hypothetical commands `show w' and `show c' should show the appropriate |
1353 | -parts of the General Public License. Of course, your program's commands |
1354 | -might be different; for a GUI interface, you would use an "about box". |
1355 | - |
1356 | - You should also get your employer (if you work as a programmer) or school, |
1357 | -if any, to sign a "copyright disclaimer" for the program, if necessary. |
1358 | -For more information on this, and how to apply and follow the GNU GPL, see |
1359 | -<http://www.gnu.org/licenses/>. |
1360 | - |
1361 | - The GNU General Public License does not permit incorporating your program |
1362 | -into proprietary programs. If your program is a subroutine library, you |
1363 | -may consider it more useful to permit linking proprietary applications with |
1364 | -the library. If this is what you want to do, use the GNU Lesser General |
1365 | -Public License instead of this License. But first, please read |
1366 | -<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
1367 | |
1368 | === added file 'TODO' |
1369 | --- TODO 1970-01-01 00:00:00 +0000 |
1370 | +++ TODO 2011-06-14 17:23:32 +0000 |
1371 | @@ -0,0 +1,5 @@ |
1372 | +- Documentation. |
1373 | +- Work out how to get tarballs for non-native packages if we want that. |
1374 | +- Decide on error on existing target directory vs. re-use and pull changes. |
1375 | +- Decide what should happen if you nest in to a directory that exists in |
1376 | + the branch that you are nesting in to. |
1377 | |
1378 | === removed file 'TODO' |
1379 | --- TODO 2010-10-21 21:17:28 +0000 |
1380 | +++ TODO 1970-01-01 00:00:00 +0000 |
1381 | @@ -1,5 +0,0 @@ |
1382 | -- Documentation. |
1383 | -- Work out how to get tarballs for non-native packages if we want that. |
1384 | -- Decide on error on existing target directory vs. re-use and pull changes. |
1385 | -- Decide what should happen if you nest in to a directory that exists in |
1386 | - the branch that you are nesting in to. |
1387 | |
1388 | === added file '__init__.py' |
1389 | --- __init__.py 1970-01-01 00:00:00 +0000 |
1390 | +++ __init__.py 2011-06-14 17:23:32 +0000 |
1391 | @@ -0,0 +1,166 @@ |
1392 | +# bzr-builder: a bzr plugin to constuct trees based on recipes |
1393 | +# Copyright 2009 Canonical Ltd. |
1394 | + |
1395 | +# This program is free software: you can redistribute it and/or modify it |
1396 | +# under the terms of the GNU General Public License version 3, as published |
1397 | +# by the Free Software Foundation. |
1398 | + |
1399 | +# This program is distributed in the hope that it will be useful, but |
1400 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1401 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1402 | +# PURPOSE. See the GNU General Public License for more details. |
1403 | + |
1404 | +# You should have received a copy of the GNU General Public License along |
1405 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1406 | + |
1407 | +"""The bzr-builder plugin allows you to construct a branch from a 'recipe'. |
1408 | + |
1409 | +The recipe is a series of pointers to branches and instructions for how they |
1410 | +should be combined. There are two ways to combine branches, by merging, and |
1411 | +by nesting, allowing much flexibility. |
1412 | + |
1413 | +A recipe is just a text file that starts with a line such as:: |
1414 | + |
1415 | + # bzr-builder format 0.3 deb-version 1.0+{revno}-{revno:packaging} |
1416 | + |
1417 | +The format specifier is there to allow the syntax to be changed in later |
1418 | +versions, and the meaning of "deb-version" will be explained later. |
1419 | + |
1420 | +The next step is the define the base branch, this is the branch that will |
1421 | +be places at the root, e.g. just put:: |
1422 | + |
1423 | + lp:foo |
1424 | + |
1425 | +to use the trunk of "foo" hosted on Launchpad. |
1426 | + |
1427 | +Next comes any number of lines of other branches to be merged in, but using |
1428 | +a slightly different format. To merge a branch in to the base specify |
1429 | +something like:: |
1430 | + |
1431 | + merge packaging lp:~foo-dev/foo/packaging |
1432 | + |
1433 | +which specifies we are merging a branch we will refer to as "packaging", which |
1434 | +can be found at the given URI. The name you give to the branch as the second |
1435 | +item doesn't have to match anything else, it's just an identifier specific |
1436 | +to the recipe. |
1437 | + |
1438 | +If you wish to nest a branch then you use a similar line:: |
1439 | + |
1440 | + nest artwork lp:foo-images images |
1441 | + |
1442 | +This specifies that we are nesting the branch at lp:foo-images, which we will |
1443 | +call "artwork", and we will place it locally in to the "images" directory. |
1444 | + |
1445 | +You can then continue in this fashion for as many branches as you like. It |
1446 | +is also possible to nest and merge branches into nested branches. For example |
1447 | +to merge a branch in to the "artwork" branch we put the following on the line |
1448 | +below that one, indented by two spaces:: |
1449 | + |
1450 | + merge artwork-fixes lp:~bob/foo-images/fix-12345 |
1451 | + |
1452 | +which will merge Bob's fixes branch into the "artwork" branch which we nested |
1453 | +at "images". |
1454 | + |
1455 | +It is also possible to specify a particular revision of a branch by appending |
1456 | +a revisionspec to the line. For instance:: |
1457 | + |
1458 | + nest docs lp:foo-docs doc tag:1.0 |
1459 | + |
1460 | +will nest the revision pointed to by the "1.0" tag of that branch. The format |
1461 | +for the revisionspec is identical to that taken by the "--revision" argument |
1462 | +to many bzr commands. See "bzr help revisionspec" for details. |
1463 | + |
1464 | +You can also merge specific subdirectories from a branch with a "nest-part" |
1465 | +line like |
1466 | + |
1467 | + nest-part packaging lp:~foo-dev/foo/packaging debian |
1468 | + |
1469 | +which specifies that the only the debian/ subdirectory should be merged. This |
1470 | +works even if the branches share no revision history. You can optionally |
1471 | +specify the subdirectory and revision in the target with a line like |
1472 | + |
1473 | + nest-part libfoo lp:libfoo src lib/foo tag:release-1.2 |
1474 | + |
1475 | +which will put the "src" directory of libfoo in "lib/foo", using the revision |
1476 | +of libfoo tagged "release-1.2". |
1477 | + |
1478 | +It is also possible to run an arbitrary command at a particular point in the |
1479 | +construction process. For example:: |
1480 | + |
1481 | + run autoreconf -i |
1482 | + |
1483 | +will run autotools at a particular point. Doing things with branches is usually |
1484 | +preferred, but sometimes it is the easier or only way to achieve something. |
1485 | +Note that you usually shouldn't rely on having general Internet access when |
1486 | +assembling the recipe, so commands that require it should be avoided. |
1487 | + |
1488 | +You can then build this branch by running:: |
1489 | + |
1490 | + bzr build foo.recipe working-dir |
1491 | + |
1492 | +(assuming you saved it as foo.recipe in your current directory). |
1493 | + |
1494 | +Once the command finished it will have placed the result in "working-dir". |
1495 | + |
1496 | +It is also possible to produce Debian source packages from a recipe, assuming |
1497 | +that one of the branches in the recipe contains some appropriate packaging. |
1498 | +You can do this using the "bzr dailydeb" command, which takes the same |
1499 | +arguments as "build". Only this time in the working dir you will find a source |
1500 | +package and a directory containing the code that the packages was built from |
1501 | +once it is done. Also take a look at the "--key-id" and "--dput" arguments to |
1502 | +have "bzr dailydeb" sign and upload the source package somewhere. |
1503 | + |
1504 | +To build Debian source package that you desire you should make sure that |
1505 | +"deb-version" is set to an appropriate value on the first line of your |
1506 | +recipe. This will be used as the version number of the package. The |
1507 | +value you put there also allows for substitution of values in to it based |
1508 | +on various things when the recipe is processed: |
1509 | + |
1510 | + * {time} will be substituted with the current date and time, such as |
1511 | + 200908191512. |
1512 | + * {date} will be substituted with just the current date, such as |
1513 | + 20090819. |
1514 | + * {revno} will be the revno of the base branch (the first specified). |
1515 | + * {revno:<branch name>} will be substituted with the revno for the |
1516 | + branch named <branch name> in the recipe. |
1517 | + * {debupstream} will be replaced by the upstream portion of the version |
1518 | + number taken from debian/changelog in the final tree. If when the |
1519 | + tree is built the top of debian/changelog has a version number of |
1520 | + "1.0-1" then this would evaluate to "1.0". |
1521 | + |
1522 | +Instruction syntax summary: |
1523 | + |
1524 | + * nest NAME BRANCH TARGET-DIR [REVISION] |
1525 | + * merge NAME BRANCH [REVISION] |
1526 | + * nest-part NAME BRANCH SUBDIR [TARGET-DIR [REVISION]] |
1527 | + * run COMMAND |
1528 | + |
1529 | +Format versions: |
1530 | + |
1531 | + 0.1 - original format. |
1532 | + 0.2 - added "run" instruction. |
1533 | + 0.3 - added "nest-part" instruction. |
1534 | + 0.4 - made "deb-version" optional, added several new substitution variables |
1535 | +""" |
1536 | + |
1537 | +if __name__ == '__main__': |
1538 | + import os |
1539 | + import subprocess |
1540 | + import sys |
1541 | + dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "plugins") |
1542 | + retcode = subprocess.call("bzr selftest -s bzrlib.plugins.builder", |
1543 | + shell=True, env={"BZR_PLUGIN_PATH": dir}) |
1544 | + sys.exit(retcode) |
1545 | + |
1546 | + |
1547 | +from bzrlib.commands import plugin_cmds |
1548 | +plugin_cmds.register_lazy("cmd_build", [], "bzrlib.plugins.builder.cmds") |
1549 | +plugin_cmds.register_lazy("cmd_dailydeb", [], "bzrlib.plugins.builder.cmds") |
1550 | + |
1551 | + |
1552 | +def test_suite(): |
1553 | + from unittest import TestSuite |
1554 | + from bzrlib.plugins.builder import tests |
1555 | + result = TestSuite() |
1556 | + result.addTest(tests.test_suite()) |
1557 | + return result |
1558 | |
1559 | === removed file '__init__.py' |
1560 | --- __init__.py 2010-10-21 21:17:28 +0000 |
1561 | +++ __init__.py 1970-01-01 00:00:00 +0000 |
1562 | @@ -1,165 +0,0 @@ |
1563 | -# bzr-builder: a bzr plugin to constuct trees based on recipes |
1564 | -# Copyright 2009 Canonical Ltd. |
1565 | - |
1566 | -# This program is free software: you can redistribute it and/or modify it |
1567 | -# under the terms of the GNU General Public License version 3, as published |
1568 | -# by the Free Software Foundation. |
1569 | - |
1570 | -# This program is distributed in the hope that it will be useful, but |
1571 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1572 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1573 | -# PURPOSE. See the GNU General Public License for more details. |
1574 | - |
1575 | -# You should have received a copy of the GNU General Public License along |
1576 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1577 | - |
1578 | -"""The bzr-builder plugin allows you to construct a branch from a 'recipe'. |
1579 | - |
1580 | -The recipe is a series of pointers to branches and instructions for how they |
1581 | -should be combined. There are two ways to combine branches, by merging, and |
1582 | -by nesting, allowing much flexibility. |
1583 | - |
1584 | -A recipe is just a text file that starts with a line such as:: |
1585 | - |
1586 | - # bzr-builder format 0.3 deb-version 1.0+{revno}-{revno:packaging} |
1587 | - |
1588 | -The format specifier is there to allow the syntax to be changed in later |
1589 | -versions, and the meaning of "deb-version" will be explained later. |
1590 | - |
1591 | -The next step is the define the base branch, this is the branch that will |
1592 | -be places at the root, e.g. just put:: |
1593 | - |
1594 | - lp:foo |
1595 | - |
1596 | -to use the trunk of "foo" hosted on Launchpad. |
1597 | - |
1598 | -Next comes any number of lines of other branches to be merged in, but using |
1599 | -a slightly different format. To merge a branch in to the base specify |
1600 | -something like:: |
1601 | - |
1602 | - merge packaging lp:~foo-dev/foo/packaging |
1603 | - |
1604 | -which specifies we are merging a branch we will refer to as "packaging", which |
1605 | -can be found at the given URI. The name you give to the branch as the second |
1606 | -item doesn't have to match anything else, it's just an identifier specific |
1607 | -to the recipe. |
1608 | - |
1609 | -If you wish to nest a branch then you use a similar line:: |
1610 | - |
1611 | - nest artwork lp:foo-images images |
1612 | - |
1613 | -This specifies that we are nesting the branch at lp:foo-images, which we will |
1614 | -call "artwork", and we will place it locally in to the "images" directory. |
1615 | - |
1616 | -You can then continue in this fashion for as many branches as you like. It |
1617 | -is also possible to nest and merge branches into nested branches. For example |
1618 | -to merge a branch in to the "artwork" branch we put the following on the line |
1619 | -below that one, indented by two spaces:: |
1620 | - |
1621 | - merge artwork-fixes lp:~bob/foo-images/fix-12345 |
1622 | - |
1623 | -which will merge Bob's fixes branch into the "artwork" branch which we nested |
1624 | -at "images". |
1625 | - |
1626 | -It is also possible to specify a particular revision of a branch by appending |
1627 | -a revisionspec to the line. For instance:: |
1628 | - |
1629 | - nest docs lp:foo-docs doc tag:1.0 |
1630 | - |
1631 | -will nest the revision pointed to by the "1.0" tag of that branch. The format |
1632 | -for the revisionspec is identical to that taken by the "--revision" argument |
1633 | -to many bzr commands. See "bzr help revisionspec" for details. |
1634 | - |
1635 | -You can also merge specific subdirectories from a branch with a "nest-part" |
1636 | -line like |
1637 | - |
1638 | - nest-part packaging lp:~foo-dev/foo/packaging debian |
1639 | - |
1640 | -which specifies that the only the debian/ subdirectory should be merged. This |
1641 | -works even if the branches share no revision history. You can optionally |
1642 | -specify the subdirectory and revision in the target with a line like |
1643 | - |
1644 | - nest-part libfoo lp:libfoo src lib/foo tag:release-1.2 |
1645 | - |
1646 | -which will put the "src" directory of libfoo in "lib/foo", using the revision |
1647 | -of libfoo tagged "release-1.2". |
1648 | - |
1649 | -It is also possible to run an arbitrary command at a particular point in the |
1650 | -construction process. For example:: |
1651 | - |
1652 | - run autoreconf -i |
1653 | - |
1654 | -will run autotools at a particular point. Doing things with branches is usually |
1655 | -preferred, but sometimes it is the easier or only way to achieve something. |
1656 | -Note that you usually shouldn't rely on having general Internet access when |
1657 | -assembling the recipe, so commands that require it should be avoided. |
1658 | - |
1659 | -You can then build this branch by running:: |
1660 | - |
1661 | - bzr build foo.recipe working-dir |
1662 | - |
1663 | -(assuming you saved it as foo.recipe in your current directory). |
1664 | - |
1665 | -Once the command finished it will have placed the result in "working-dir". |
1666 | - |
1667 | -It is also possible to produce Debian source packages from a recipe, assuming |
1668 | -that one of the branches in the recipe contains some appropriate packaging. |
1669 | -You can do this using the "bzr dailydeb" command, which takes the same |
1670 | -arguments as "build". Only this time in the working dir you will find a source |
1671 | -package and a directory containing the code that the packages was built from |
1672 | -once it is done. Also take a look at the "--key-id" and "--dput" arguments to |
1673 | -have "bzr dailydeb" sign and upload the source package somewhere. |
1674 | - |
1675 | -To build Debian source package that you desire you should make sure that |
1676 | -"deb-version" is set to an appropriate value on the first line of your |
1677 | -recipe. This will be used as the version number of the package. The |
1678 | -value you put there also allows for substitution of values in to it based |
1679 | -on various things when the recipe is processed: |
1680 | - |
1681 | - * {time} will be substituted with the current date and time, such as |
1682 | - 200908191512. |
1683 | - * {date} will be substituted with just the current date, such as |
1684 | - 20090819. |
1685 | - * {revno} will be the revno of the base branch (the first specified). |
1686 | - * {revno:<branch name>} will be substituted with the revno for the |
1687 | - branch named <branch name> in the recipe. |
1688 | - * {debupstream} will be replaced by the upstream portion of the version |
1689 | - number taken from debian/changelog in the final tree. If when the |
1690 | - tree is built the top of debian/changelog has a version number of |
1691 | - "1.0-1" then this would evaluate to "1.0". |
1692 | - |
1693 | -Instruction syntax summary: |
1694 | - |
1695 | - * nest NAME BRANCH TARGET-DIR [REVISION] |
1696 | - * merge NAME BRANCH [REVISION] |
1697 | - * nest-part NAME BRANCH SUBDIR [TARGET-DIR [REVISION]] |
1698 | - * run COMMAND |
1699 | - |
1700 | -Format versions: |
1701 | - |
1702 | - 0.1 - original format. |
1703 | - 0.2 - added "run" instruction. |
1704 | - 0.3 - added "nest-part" instruction. |
1705 | -""" |
1706 | - |
1707 | -if __name__ == '__main__': |
1708 | - import os |
1709 | - import subprocess |
1710 | - import sys |
1711 | - dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "plugins") |
1712 | - retcode = subprocess.call("bzr selftest -s bzrlib.plugins.builder", |
1713 | - shell=True, env={"BZR_PLUGIN_PATH": dir}) |
1714 | - sys.exit(retcode) |
1715 | - |
1716 | - |
1717 | -from bzrlib.commands import plugin_cmds |
1718 | -plugin_cmds.register_lazy("cmd_build", [], "bzrlib.plugins.builder.cmds") |
1719 | -plugin_cmds.register_lazy("cmd_dailydeb", [], "bzrlib.plugins.builder.cmds") |
1720 | - |
1721 | - |
1722 | -def test_suite(): |
1723 | - from unittest import TestSuite |
1724 | - from bzrlib.plugins.builder import tests |
1725 | - result = TestSuite() |
1726 | - result.addTest(tests.test_suite()) |
1727 | - return result |
1728 | |
1729 | === added file 'bzrlibbackports.py' |
1730 | --- bzrlibbackports.py 1970-01-01 00:00:00 +0000 |
1731 | +++ bzrlibbackports.py 2011-06-14 17:23:32 +0000 |
1732 | @@ -0,0 +1,227 @@ |
1733 | +# bzr-builder: a bzr plugin to constuct trees based on recipes |
1734 | +# Copyright 2010 Canonical Ltd. |
1735 | + |
1736 | +# This program is free software: you can redistribute it and/or modify it |
1737 | +# under the terms of the GNU General Public License version 3, as published |
1738 | +# by the Free Software Foundation. |
1739 | + |
1740 | +# This program is distributed in the hope that it will be useful, but |
1741 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
1742 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1743 | +# PURPOSE. See the GNU General Public License for more details. |
1744 | + |
1745 | +# You should have received a copy of the GNU General Public License along |
1746 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
1747 | + |
1748 | +"""Copies/backports features from recent bzrlib versions. |
1749 | + |
1750 | +This allows bzr-builder to continue to work with older bzrlib versions while |
1751 | +using features from newer versions. |
1752 | +""" |
1753 | + |
1754 | +# NOTE FOR DEVELOPERS: with each backport please include a comment saying which |
1755 | +# version of bzr you are backporting from, to make it easier to copy bugfixes |
1756 | +# made in bzr (and so that we know which things we can drop from this module if |
1757 | +# bzr-builder ever raises which version of bzr it depends on). |
1758 | + |
1759 | +from bzrlib.merge import ( |
1760 | + Merger, |
1761 | + Merge3Merger, |
1762 | + ) |
1763 | +from bzrlib import ( |
1764 | + errors, |
1765 | + generate_ids, |
1766 | + osutils, |
1767 | + revision as _mod_revision, |
1768 | + transform, |
1769 | + ui, |
1770 | + ) |
1771 | + |
1772 | +# Backport of bzrlib.merge.MergeIntoMerger, introduced in bzr 2.2rc1. |
1773 | +# (Also backports PathNotInTree, _MergeTypeParameterizer, MergeIntoMergeType) |
1774 | +class PathNotInTree(errors.BzrError): |
1775 | + |
1776 | + _fmt = """Merge-into failed because %(tree)s does not contain %(path)s.""" |
1777 | + |
1778 | + def __init__(self, path, tree): |
1779 | + errors.BzrError.__init__(self, path=path, tree=tree) |
1780 | + |
1781 | + |
1782 | +class MergeIntoMerger(Merger): |
1783 | + """Merger that understands other_tree will be merged into a subdir. |
1784 | + |
1785 | + This also changes the Merger api so that it uses real Branch, revision_id, |
1786 | + and RevisonTree objects, rather than using revision specs. |
1787 | + """ |
1788 | + |
1789 | + def __init__(self, this_tree, other_branch, other_tree, target_subdir, |
1790 | + source_subpath, other_rev_id=None): |
1791 | + """Create a new MergeIntoMerger object. |
1792 | + |
1793 | + source_subpath in other_tree will be effectively copied to |
1794 | + target_subdir in this_tree. |
1795 | + |
1796 | + :param this_tree: The tree that we will be merging into. |
1797 | + :param other_branch: The Branch we will be merging from. |
1798 | + :param other_tree: The RevisionTree object we want to merge. |
1799 | + :param target_subdir: The relative path where we want to merge |
1800 | + other_tree into this_tree |
1801 | + :param source_subpath: The relative path specifying the subtree of |
1802 | + other_tree to merge into this_tree. |
1803 | + """ |
1804 | + # It is assumed that we are merging a tree that is not in our current |
1805 | + # ancestry, which means we are using the "EmptyTree" as our basis. |
1806 | + null_ancestor_tree = this_tree.branch.repository.revision_tree( |
1807 | + _mod_revision.NULL_REVISION) |
1808 | + super(MergeIntoMerger, self).__init__( |
1809 | + this_branch=this_tree.branch, |
1810 | + this_tree=this_tree, |
1811 | + other_tree=other_tree, |
1812 | + base_tree=null_ancestor_tree, |
1813 | + ) |
1814 | + self._target_subdir = target_subdir |
1815 | + self._source_subpath = source_subpath |
1816 | + self.other_branch = other_branch |
1817 | + if other_rev_id is None: |
1818 | + other_rev_id = other_tree.get_revision_id() |
1819 | + self.other_rev_id = self.other_basis = other_rev_id |
1820 | + self.base_is_ancestor = True |
1821 | + self.backup_files = True |
1822 | + self.merge_type = Merge3Merger |
1823 | + self.show_base = False |
1824 | + self.reprocess = False |
1825 | + self.interesting_ids = None |
1826 | + self.merge_type = _MergeTypeParameterizer(MergeIntoMergeType, |
1827 | + target_subdir=self._target_subdir, |
1828 | + source_subpath=self._source_subpath) |
1829 | + if self._source_subpath != '': |
1830 | + # If this isn't a partial merge make sure the revisions will be |
1831 | + # present. |
1832 | + self._maybe_fetch(self.other_branch, self.this_branch, |
1833 | + self.other_basis) |
1834 | + |
1835 | + def set_pending(self): |
1836 | + if self._source_subpath != '': |
1837 | + return |
1838 | + Merger.set_pending(self) |
1839 | + |
1840 | + |
1841 | +class _MergeTypeParameterizer(object): |
1842 | + """Wrap a merge-type class to provide extra parameters. |
1843 | + |
1844 | + This is hack used by MergeIntoMerger to pass some extra parameters to its |
1845 | + merge_type. Merger.do_merge() sets up its own set of parameters to pass to |
1846 | + the 'merge_type' member. It is difficult override do_merge without |
1847 | + re-writing the whole thing, so instead we create a wrapper which will pass |
1848 | + the extra parameters. |
1849 | + """ |
1850 | + |
1851 | + def __init__(self, merge_type, **kwargs): |
1852 | + self._extra_kwargs = kwargs |
1853 | + self._merge_type = merge_type |
1854 | + |
1855 | + def __call__(self, *args, **kwargs): |
1856 | + kwargs.update(self._extra_kwargs) |
1857 | + return self._merge_type(*args, **kwargs) |
1858 | + |
1859 | + def __getattr__(self, name): |
1860 | + return getattr(self._merge_type, name) |
1861 | + |
1862 | + |
1863 | +class MergeIntoMergeType(Merge3Merger): |
1864 | + """Merger that incorporates a tree (or part of a tree) into another.""" |
1865 | + |
1866 | + # Backport note: the definition of _finish_computing_transform is copied |
1867 | + # from Merge3Merger in bzr 2.2 (it is supposed to be inherited from |
1868 | + # Merge3Merger, but was only introduced in 2.2). |
1869 | + def _finish_computing_transform(self): |
1870 | + """Finalize the transform and report the changes. |
1871 | + |
1872 | + This is the second half of _compute_transform. |
1873 | + """ |
1874 | + child_pb = ui.ui_factory.nested_progress_bar() |
1875 | + try: |
1876 | + fs_conflicts = transform.resolve_conflicts(self.tt, child_pb, |
1877 | + lambda t, c: transform.conflict_pass(t, c, self.other_tree)) |
1878 | + finally: |
1879 | + child_pb.finished() |
1880 | + if self.change_reporter is not None: |
1881 | + from bzrlib import delta |
1882 | + delta.report_changes( |
1883 | + self.tt.iter_changes(), self.change_reporter) |
1884 | + self.cook_conflicts(fs_conflicts) |
1885 | + from bzrlib import trace |
1886 | + for conflict in self.cooked_conflicts: |
1887 | + trace.warning(conflict) |
1888 | + |
1889 | + def __init__(self, *args, **kwargs): |
1890 | + """Initialize the merger object. |
1891 | + |
1892 | + :param args: See Merge3Merger.__init__'s args. |
1893 | + :param kwargs: See Merge3Merger.__init__'s keyword args, except for |
1894 | + source_subpath and target_subdir. |
1895 | + :keyword source_subpath: The relative path specifying the subtree of |
1896 | + other_tree to merge into this_tree. |
1897 | + :keyword target_subdir: The relative path where we want to merge |
1898 | + other_tree into this_tree |
1899 | + """ |
1900 | + # All of the interesting work happens during Merge3Merger.__init__(), |
1901 | + # so we have have to hack in to get our extra parameters set. |
1902 | + self._source_subpath = kwargs.pop('source_subpath') |
1903 | + self._target_subdir = kwargs.pop('target_subdir') |
1904 | + super(MergeIntoMergeType, self).__init__(*args, **kwargs) |
1905 | + |
1906 | + def _compute_transform(self): |
1907 | + child_pb = ui.ui_factory.nested_progress_bar() |
1908 | + try: |
1909 | + entries = self._entries_to_incorporate() |
1910 | + entries = list(entries) |
1911 | + for num, (entry, parent_id) in enumerate(entries): |
1912 | + child_pb.update('Preparing file merge', num, len(entries)) |
1913 | + parent_trans_id = self.tt.trans_id_file_id(parent_id) |
1914 | + trans_id = transform.new_by_entry(self.tt, entry, |
1915 | + parent_trans_id, self.other_tree) |
1916 | + finally: |
1917 | + child_pb.finished() |
1918 | + self._finish_computing_transform() |
1919 | + |
1920 | + def _entries_to_incorporate(self): |
1921 | + """Yields pairs of (inventory_entry, new_parent).""" |
1922 | + other_inv = self.other_tree.inventory |
1923 | + subdir_id = other_inv.path2id(self._source_subpath) |
1924 | + if subdir_id is None: |
1925 | + # XXX: The error would be clearer if it gave the URL of the source |
1926 | + # branch, but we don't have a reference to that here. |
1927 | + raise PathNotInTree(self._source_subpath, "Source tree") |
1928 | + subdir = other_inv[subdir_id] |
1929 | + parent_in_target = osutils.dirname(self._target_subdir) |
1930 | + target_id = self.this_tree.inventory.path2id(parent_in_target) |
1931 | + if target_id is None: |
1932 | + raise PathNotInTree(self._target_subdir, "Target tree") |
1933 | + name_in_target = osutils.basename(self._target_subdir) |
1934 | + merge_into_root = subdir.copy() |
1935 | + merge_into_root.name = name_in_target |
1936 | + if merge_into_root.file_id in self.this_tree.inventory: |
1937 | + # Give the root a new file-id. |
1938 | + # This can happen fairly easily if the directory we are |
1939 | + # incorporating is the root, and both trees have 'TREE_ROOT' as |
1940 | + # their root_id. Users will expect this to Just Work, so we |
1941 | + # change the file-id here. |
1942 | + # Non-root file-ids could potentially conflict too. That's really |
1943 | + # an edge case, so we don't do anything special for those. We let |
1944 | + # them cause conflicts. |
1945 | + merge_into_root.file_id = generate_ids.gen_file_id(name_in_target) |
1946 | + yield (merge_into_root, target_id) |
1947 | + if subdir.kind != 'directory': |
1948 | + # No children, so we are done. |
1949 | + return |
1950 | + for ignored_path, entry in other_inv.iter_entries_by_dir(subdir_id): |
1951 | + parent_id = entry.parent_id |
1952 | + if parent_id == subdir.file_id: |
1953 | + # The root's parent ID has changed, so make sure children of |
1954 | + # the root refer to the new ID. |
1955 | + parent_id = merge_into_root.file_id |
1956 | + yield (entry, parent_id) |
1957 | + |
1958 | + |
1959 | + |
1960 | |
1961 | === removed file 'bzrlibbackports.py' |
1962 | --- bzrlibbackports.py 2010-10-21 21:17:28 +0000 |
1963 | +++ bzrlibbackports.py 1970-01-01 00:00:00 +0000 |
1964 | @@ -1,227 +0,0 @@ |
1965 | -# bzr-builder: a bzr plugin to constuct trees based on recipes |
1966 | -# Copyright 2010 Canonical Ltd. |
1967 | - |
1968 | -# This program is free software: you can redistribute it and/or modify it |
1969 | -# under the terms of the GNU General Public License version 3, as published |
1970 | -# by the Free Software Foundation. |
1971 | - |
1972 | -# This program is distributed in the hope that it will be useful, but |
1973 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
1974 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1975 | -# PURPOSE. See the GNU General Public License for more details. |
1976 | - |
1977 | -# You should have received a copy of the GNU General Public License along |
1978 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
1979 | - |
1980 | -"""Copies/backports features from recent bzrlib versions. |
1981 | - |
1982 | -This allows bzr-builder to continue to work with older bzrlib versions while |
1983 | -using features from newer versions. |
1984 | -""" |
1985 | - |
1986 | -# NOTE FOR DEVELOPERS: with each backport please include a comment saying which |
1987 | -# version of bzr you are backporting from, to make it easier to copy bugfixes |
1988 | -# made in bzr (and so that we know which things we can drop from this module if |
1989 | -# bzr-builder ever raises which version of bzr it depends on). |
1990 | - |
1991 | -from bzrlib.merge import ( |
1992 | - Merger, |
1993 | - Merge3Merger, |
1994 | - ) |
1995 | -from bzrlib import ( |
1996 | - errors, |
1997 | - generate_ids, |
1998 | - osutils, |
1999 | - revision as _mod_revision, |
2000 | - transform, |
2001 | - ui, |
2002 | - ) |
2003 | - |
2004 | -# Backport of bzrlib.merge.MergeIntoMerger, introduced in bzr 2.2rc1. |
2005 | -# (Also backports PathNotInTree, _MergeTypeParameterizer, MergeIntoMergeType) |
2006 | -class PathNotInTree(errors.BzrError): |
2007 | - |
2008 | - _fmt = """Merge-into failed because %(tree)s does not contain %(path)s.""" |
2009 | - |
2010 | - def __init__(self, path, tree): |
2011 | - errors.BzrError.__init__(self, path=path, tree=tree) |
2012 | - |
2013 | - |
2014 | -class MergeIntoMerger(Merger): |
2015 | - """Merger that understands other_tree will be merged into a subdir. |
2016 | - |
2017 | - This also changes the Merger api so that it uses real Branch, revision_id, |
2018 | - and RevisonTree objects, rather than using revision specs. |
2019 | - """ |
2020 | - |
2021 | - def __init__(self, this_tree, other_branch, other_tree, target_subdir, |
2022 | - source_subpath, other_rev_id=None): |
2023 | - """Create a new MergeIntoMerger object. |
2024 | - |
2025 | - source_subpath in other_tree will be effectively copied to |
2026 | - target_subdir in this_tree. |
2027 | - |
2028 | - :param this_tree: The tree that we will be merging into. |
2029 | - :param other_branch: The Branch we will be merging from. |
2030 | - :param other_tree: The RevisionTree object we want to merge. |
2031 | - :param target_subdir: The relative path where we want to merge |
2032 | - other_tree into this_tree |
2033 | - :param source_subpath: The relative path specifying the subtree of |
2034 | - other_tree to merge into this_tree. |
2035 | - """ |
2036 | - # It is assumed that we are merging a tree that is not in our current |
2037 | - # ancestry, which means we are using the "EmptyTree" as our basis. |
2038 | - null_ancestor_tree = this_tree.branch.repository.revision_tree( |
2039 | - _mod_revision.NULL_REVISION) |
2040 | - super(MergeIntoMerger, self).__init__( |
2041 | - this_branch=this_tree.branch, |
2042 | - this_tree=this_tree, |
2043 | - other_tree=other_tree, |
2044 | - base_tree=null_ancestor_tree, |
2045 | - ) |
2046 | - self._target_subdir = target_subdir |
2047 | - self._source_subpath = source_subpath |
2048 | - self.other_branch = other_branch |
2049 | - if other_rev_id is None: |
2050 | - other_rev_id = other_tree.get_revision_id() |
2051 | - self.other_rev_id = self.other_basis = other_rev_id |
2052 | - self.base_is_ancestor = True |
2053 | - self.backup_files = True |
2054 | - self.merge_type = Merge3Merger |
2055 | - self.show_base = False |
2056 | - self.reprocess = False |
2057 | - self.interesting_ids = None |
2058 | - self.merge_type = _MergeTypeParameterizer(MergeIntoMergeType, |
2059 | - target_subdir=self._target_subdir, |
2060 | - source_subpath=self._source_subpath) |
2061 | - if self._source_subpath != '': |
2062 | - # If this isn't a partial merge make sure the revisions will be |
2063 | - # present. |
2064 | - self._maybe_fetch(self.other_branch, self.this_branch, |
2065 | - self.other_basis) |
2066 | - |
2067 | - def set_pending(self): |
2068 | - if self._source_subpath != '': |
2069 | - return |
2070 | - Merger.set_pending(self) |
2071 | - |
2072 | - |
2073 | -class _MergeTypeParameterizer(object): |
2074 | - """Wrap a merge-type class to provide extra parameters. |
2075 | - |
2076 | - This is hack used by MergeIntoMerger to pass some extra parameters to its |
2077 | - merge_type. Merger.do_merge() sets up its own set of parameters to pass to |
2078 | - the 'merge_type' member. It is difficult override do_merge without |
2079 | - re-writing the whole thing, so instead we create a wrapper which will pass |
2080 | - the extra parameters. |
2081 | - """ |
2082 | - |
2083 | - def __init__(self, merge_type, **kwargs): |
2084 | - self._extra_kwargs = kwargs |
2085 | - self._merge_type = merge_type |
2086 | - |
2087 | - def __call__(self, *args, **kwargs): |
2088 | - kwargs.update(self._extra_kwargs) |
2089 | - return self._merge_type(*args, **kwargs) |
2090 | - |
2091 | - def __getattr__(self, name): |
2092 | - return getattr(self._merge_type, name) |
2093 | - |
2094 | - |
2095 | -class MergeIntoMergeType(Merge3Merger): |
2096 | - """Merger that incorporates a tree (or part of a tree) into another.""" |
2097 | - |
2098 | - # Backport note: the definition of _finish_computing_transform is copied |
2099 | - # from Merge3Merger in bzr 2.2 (it is supposed to be inherited from |
2100 | - # Merge3Merger, but was only introduced in 2.2). |
2101 | - def _finish_computing_transform(self): |
2102 | - """Finalize the transform and report the changes. |
2103 | - |
2104 | - This is the second half of _compute_transform. |
2105 | - """ |
2106 | - child_pb = ui.ui_factory.nested_progress_bar() |
2107 | - try: |
2108 | - fs_conflicts = transform.resolve_conflicts(self.tt, child_pb, |
2109 | - lambda t, c: transform.conflict_pass(t, c, self.other_tree)) |
2110 | - finally: |
2111 | - child_pb.finished() |
2112 | - if self.change_reporter is not None: |
2113 | - from bzrlib import delta |
2114 | - delta.report_changes( |
2115 | - self.tt.iter_changes(), self.change_reporter) |
2116 | - self.cook_conflicts(fs_conflicts) |
2117 | - from bzrlib import trace |
2118 | - for conflict in self.cooked_conflicts: |
2119 | - trace.warning(conflict) |
2120 | - |
2121 | - def __init__(self, *args, **kwargs): |
2122 | - """Initialize the merger object. |
2123 | - |
2124 | - :param args: See Merge3Merger.__init__'s args. |
2125 | - :param kwargs: See Merge3Merger.__init__'s keyword args, except for |
2126 | - source_subpath and target_subdir. |
2127 | - :keyword source_subpath: The relative path specifying the subtree of |
2128 | - other_tree to merge into this_tree. |
2129 | - :keyword target_subdir: The relative path where we want to merge |
2130 | - other_tree into this_tree |
2131 | - """ |
2132 | - # All of the interesting work happens during Merge3Merger.__init__(), |
2133 | - # so we have have to hack in to get our extra parameters set. |
2134 | - self._source_subpath = kwargs.pop('source_subpath') |
2135 | - self._target_subdir = kwargs.pop('target_subdir') |
2136 | - super(MergeIntoMergeType, self).__init__(*args, **kwargs) |
2137 | - |
2138 | - def _compute_transform(self): |
2139 | - child_pb = ui.ui_factory.nested_progress_bar() |
2140 | - try: |
2141 | - entries = self._entries_to_incorporate() |
2142 | - entries = list(entries) |
2143 | - for num, (entry, parent_id) in enumerate(entries): |
2144 | - child_pb.update('Preparing file merge', num, len(entries)) |
2145 | - parent_trans_id = self.tt.trans_id_file_id(parent_id) |
2146 | - trans_id = transform.new_by_entry(self.tt, entry, |
2147 | - parent_trans_id, self.other_tree) |
2148 | - finally: |
2149 | - child_pb.finished() |
2150 | - self._finish_computing_transform() |
2151 | - |
2152 | - def _entries_to_incorporate(self): |
2153 | - """Yields pairs of (inventory_entry, new_parent).""" |
2154 | - other_inv = self.other_tree.inventory |
2155 | - subdir_id = other_inv.path2id(self._source_subpath) |
2156 | - if subdir_id is None: |
2157 | - # XXX: The error would be clearer if it gave the URL of the source |
2158 | - # branch, but we don't have a reference to that here. |
2159 | - raise PathNotInTree(self._source_subpath, "Source tree") |
2160 | - subdir = other_inv[subdir_id] |
2161 | - parent_in_target = osutils.dirname(self._target_subdir) |
2162 | - target_id = self.this_tree.inventory.path2id(parent_in_target) |
2163 | - if target_id is None: |
2164 | - raise PathNotInTree(self._target_subdir, "Target tree") |
2165 | - name_in_target = osutils.basename(self._target_subdir) |
2166 | - merge_into_root = subdir.copy() |
2167 | - merge_into_root.name = name_in_target |
2168 | - if merge_into_root.file_id in self.this_tree.inventory: |
2169 | - # Give the root a new file-id. |
2170 | - # This can happen fairly easily if the directory we are |
2171 | - # incorporating is the root, and both trees have 'TREE_ROOT' as |
2172 | - # their root_id. Users will expect this to Just Work, so we |
2173 | - # change the file-id here. |
2174 | - # Non-root file-ids could potentially conflict too. That's really |
2175 | - # an edge case, so we don't do anything special for those. We let |
2176 | - # them cause conflicts. |
2177 | - merge_into_root.file_id = generate_ids.gen_file_id(name_in_target) |
2178 | - yield (merge_into_root, target_id) |
2179 | - if subdir.kind != 'directory': |
2180 | - # No children, so we are done. |
2181 | - return |
2182 | - for ignored_path, entry in other_inv.iter_entries_by_dir(subdir_id): |
2183 | - parent_id = entry.parent_id |
2184 | - if parent_id == subdir.file_id: |
2185 | - # The root's parent ID has changed, so make sure children of |
2186 | - # the root refer to the new ID. |
2187 | - parent_id = merge_into_root.file_id |
2188 | - yield (entry, parent_id) |
2189 | - |
2190 | - |
2191 | - |
2192 | |
2193 | === added file 'cmds.py' |
2194 | --- cmds.py 1970-01-01 00:00:00 +0000 |
2195 | +++ cmds.py 2011-06-14 17:23:32 +0000 |
2196 | @@ -0,0 +1,778 @@ |
2197 | +# bzr-builder: a bzr plugin to constuct trees based on recipes |
2198 | +# Copyright 2009 Canonical Ltd. |
2199 | + |
2200 | +# This program is free software: you can redistribute it and/or modify it |
2201 | +# under the terms of the GNU General Public License version 3, as published |
2202 | +# by the Free Software Foundation. |
2203 | + |
2204 | +# This program is distributed in the hope that it will be useful, but |
2205 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
2206 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2207 | +# PURPOSE. See the GNU General Public License for more details. |
2208 | + |
2209 | +# You should have received a copy of the GNU General Public License along |
2210 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
2211 | + |
2212 | +"""Subcommands provided by bzr-builder.""" |
2213 | + |
2214 | +from base64 import standard_b64decode |
2215 | +from StringIO import StringIO |
2216 | +import datetime |
2217 | +from email import utils |
2218 | +import errno |
2219 | +import os |
2220 | +import pwd |
2221 | +import re |
2222 | +import signal |
2223 | +import socket |
2224 | +import shutil |
2225 | +import subprocess |
2226 | +import tempfile |
2227 | + |
2228 | +try: |
2229 | + from debian import changelog, deb822 |
2230 | +except ImportError: |
2231 | + # In older versions of python-debian the main package was named |
2232 | + # debian_bundle |
2233 | + from debian_bundle import changelog, deb822 |
2234 | + |
2235 | +from bzrlib import ( |
2236 | + errors, |
2237 | + export as _mod_export, |
2238 | + lazy_regex, |
2239 | + trace, |
2240 | + transport as _mod_transport, |
2241 | + urlutils, |
2242 | + ) |
2243 | +from bzrlib.branch import Branch |
2244 | +from bzrlib.commands import Command |
2245 | +from bzrlib.option import Option |
2246 | + |
2247 | +from bzrlib.plugins.builder.recipe import ( |
2248 | + BaseRecipeBranch, |
2249 | + build_tree, |
2250 | + RecipeParser, |
2251 | + resolve_revisions, |
2252 | + SAFE_INSTRUCTIONS, |
2253 | + ) |
2254 | + |
2255 | + |
2256 | +# The default distribution used by add_autobuild_changelog_entry() |
2257 | +DEFAULT_UBUNTU_DISTRIBUTION = "lucid" |
2258 | + |
2259 | + |
2260 | +class MissingDependency(errors.BzrError): |
2261 | + pass |
2262 | + |
2263 | + |
2264 | +def write_manifest_to_transport(location, base_branch, |
2265 | + possible_transports=None): |
2266 | + """Write a manifest to disk. |
2267 | + |
2268 | + :param location: Location to write to |
2269 | + :param base_branch: Recipe base branch |
2270 | + """ |
2271 | + child_transport = _mod_transport.get_transport(location, |
2272 | + possible_transports=possible_transports) |
2273 | + base_transport = child_transport.clone('..') |
2274 | + base_transport.create_prefix() |
2275 | + basename = base_transport.relpath(child_transport.base) |
2276 | + base_transport.put_bytes(basename, str(base_branch)) |
2277 | + |
2278 | + |
2279 | +def get_branch_from_recipe_location(recipe_location, safe=False, |
2280 | + possible_transports=None): |
2281 | + """Return the base branch for the specified recipe. |
2282 | + |
2283 | + :param recipe_location: The URL of the recipe file to retrieve. |
2284 | + :param safe: if True, reject recipes that would cause arbitrary code |
2285 | + execution. |
2286 | + """ |
2287 | + if safe: |
2288 | + permitted_instructions = SAFE_INSTRUCTIONS |
2289 | + else: |
2290 | + permitted_instructions = None |
2291 | + try: |
2292 | + (basename, f) = get_recipe_from_location(recipe_location, possible_transports) |
2293 | + except errors.NoSuchFile: |
2294 | + raise errors.BzrCommandError("Specified recipe does not exist: " |
2295 | + "%s" % recipe_location) |
2296 | + try: |
2297 | + parser = RecipeParser(f, filename=recipe_location) |
2298 | + finally: |
2299 | + f.close() |
2300 | + return parser.parse(permitted_instructions=permitted_instructions) |
2301 | + |
2302 | + |
2303 | +def get_branch_from_branch_location(branch_location, possible_transports=None, |
2304 | + revspec=None): |
2305 | + """Return the base branch for the branch location. |
2306 | + |
2307 | + :param branch_location: The URL of the branch to retrieve. |
2308 | + """ |
2309 | + # Make sure it's actually a branch |
2310 | + Branch.open(branch_location) |
2311 | + return BaseRecipeBranch(branch_location, None, |
2312 | + RecipeParser.NEWEST_VERSION, revspec=revspec) |
2313 | + |
2314 | + |
2315 | +def get_old_recipe(if_changed_from, possible_transports=None): |
2316 | + try: |
2317 | + (basename, f) = get_recipe_from_location(if_changed_from, possible_transports) |
2318 | + except errors.NoSuchFile: |
2319 | + return None |
2320 | + try: |
2321 | + old_recipe = RecipeParser(f, |
2322 | + filename=if_changed_from).parse() |
2323 | + finally: |
2324 | + f.close() |
2325 | + return old_recipe |
2326 | + |
2327 | + |
2328 | +def get_maintainer(): |
2329 | + """Create maintainer string using the same algorithm as in dch. |
2330 | + """ |
2331 | + env = os.environ |
2332 | + regex = re.compile(r"^(.*)\s+<(.*)>$") |
2333 | + |
2334 | + # Split email and name |
2335 | + if 'DEBEMAIL' in env: |
2336 | + match_obj = regex.match(env['DEBEMAIL']) |
2337 | + if match_obj: |
2338 | + if not 'DEBFULLNAME' in env: |
2339 | + env['DEBFULLNAME'] = match_obj.group(1) |
2340 | + env['DEBEMAIL'] = match_obj.group(2) |
2341 | + if 'DEBEMAIL' not in env or 'DEBFULLNAME' not in env: |
2342 | + if 'EMAIL' in env: |
2343 | + match_obj = regex.match(env['EMAIL']) |
2344 | + if match_obj: |
2345 | + if not 'DEBFULLNAME' in env: |
2346 | + env['DEBFULLNAME'] = match_obj.group(1) |
2347 | + env['EMAIL'] = match_obj.group(2) |
2348 | + |
2349 | + # Get maintainer's name |
2350 | + if 'DEBFULLNAME' in env: |
2351 | + maintainer = env['DEBFULLNAME'] |
2352 | + elif 'NAME' in env: |
2353 | + maintainer = env['NAME'] |
2354 | + else: |
2355 | + # Use password database if no data in environment variables |
2356 | + try: |
2357 | + maintainer = re.sub(r',.*', '', pwd.getpwuid(os.getuid()).pw_gecos) |
2358 | + except (KeyError, AttributeError): |
2359 | + # TBD: Use last changelog entry value |
2360 | + maintainer = "bzr-builder" |
2361 | + |
2362 | + # Get maintainer's mail address |
2363 | + if 'DEBEMAIL' in env: |
2364 | + email = env['DEBEMAIL'] |
2365 | + elif 'EMAIL' in env: |
2366 | + email = env['EMAIL'] |
2367 | + else: |
2368 | + addr = None |
2369 | + if os.path.exists('/etc/mailname'): |
2370 | + f = open('/etc/mailname') |
2371 | + try: |
2372 | + addr = f.readline().strip() |
2373 | + finally: |
2374 | + f.close() |
2375 | + if not addr: |
2376 | + addr = socket.getfqdn() |
2377 | + if addr: |
2378 | + user = pwd.getpwuid(os.getuid()).pw_name |
2379 | + if not user: |
2380 | + addr = None |
2381 | + else: |
2382 | + addr = "%s@%s" % (user, addr) |
2383 | + |
2384 | + if addr: |
2385 | + email = addr |
2386 | + else: |
2387 | + # TBD: Use last changelog entry value |
2388 | + email = "none@example.org" |
2389 | + |
2390 | + return (maintainer, email) |
2391 | + |
2392 | + |
2393 | +def add_autobuild_changelog_entry(base_branch, basedir, package, |
2394 | + distribution=None, author_name=None, author_email=None, |
2395 | + append_version=None): |
2396 | + """Add a new changelog entry for an autobuild. |
2397 | + |
2398 | + :param base_branch: Recipe base branch |
2399 | + :param basedir: Base working directory |
2400 | + :param package: package name |
2401 | + :param distribution: Optional distribution (defaults to last entry |
2402 | + distribution) |
2403 | + :param author_name: Name of the build requester |
2404 | + :param author_email: Email of the build requester |
2405 | + :param append_version: Optional version suffix to add |
2406 | + """ |
2407 | + debian_dir = os.path.join(basedir, "debian") |
2408 | + if not os.path.exists(debian_dir): |
2409 | + os.makedirs(debian_dir) |
2410 | + cl_path = os.path.join(debian_dir, "changelog") |
2411 | + file_found = False |
2412 | + if os.path.exists(cl_path): |
2413 | + file_found = True |
2414 | + cl_f = open(cl_path) |
2415 | + try: |
2416 | + contents = cl_f.read() |
2417 | + finally: |
2418 | + cl_f.close() |
2419 | + cl = changelog.Changelog(file=contents) |
2420 | + else: |
2421 | + cl = changelog.Changelog() |
2422 | + if len(cl._blocks) > 0: |
2423 | + if distribution is None: |
2424 | + distribution = cl._blocks[0].distributions.split()[0] |
2425 | + else: |
2426 | + if file_found: |
2427 | + if len(contents.strip()) > 0: |
2428 | + reason = ("debian/changelog didn't contain any " |
2429 | + "parseable stanzas") |
2430 | + else: |
2431 | + reason = "debian/changelog was empty" |
2432 | + else: |
2433 | + reason = "debian/changelog was not present" |
2434 | + if distribution is None: |
2435 | + distribution = DEFAULT_UBUNTU_DISTRIBUTION |
2436 | + # Use debian packaging environment variables |
2437 | + # or default values if they don't exist |
2438 | + if author_name is None or author_email is None: |
2439 | + author_name, author_email = get_maintainer() |
2440 | + author = "%s <%s>" % (author_name, author_email) |
2441 | + |
2442 | + date = utils.formatdate(localtime=True) |
2443 | + version = base_branch.deb_version |
2444 | + if append_version is not None: |
2445 | + version += append_version |
2446 | + try: |
2447 | + changelog.Version(version) |
2448 | + except (changelog.VersionError, ValueError), e: |
2449 | + raise errors.BzrCommandError("Invalid deb-version: %s: %s" |
2450 | + % (version, e)) |
2451 | + cl.new_block(package=package, version=version, |
2452 | + distributions=distribution, urgency="low", |
2453 | + changes=['', ' * Auto build.', ''], |
2454 | + author=author, date=date) |
2455 | + cl_f = open(cl_path, 'wb') |
2456 | + try: |
2457 | + cl.write_to_open_file(cl_f) |
2458 | + finally: |
2459 | + cl_f.close() |
2460 | + |
2461 | + |
2462 | +def calculate_package_dir(package_name, package_version, working_basedir): |
2463 | + """Calculate the directory name that should be used while debuilding. |
2464 | + |
2465 | + :param base_branch: Recipe base branch |
2466 | + :param package_version: Version of the package |
2467 | + :param package_name: Package name |
2468 | + :param working_basedir: Base directory |
2469 | + """ |
2470 | + package_basedir = "%s-%s" % (package_name, package_version.upstream_version) |
2471 | + package_dir = os.path.join(working_basedir, package_basedir) |
2472 | + return package_dir |
2473 | + |
2474 | + |
2475 | +def _run_command(command, basedir, msg, error_msg, |
2476 | + not_installed_msg=None, env=None, success_exit_codes=None, indata=None): |
2477 | + """ Run a command in a subprocess. |
2478 | + |
2479 | + :param command: list with command and parameters |
2480 | + :param msg: message to display to the user |
2481 | + :param error_msg: message to display if something fails. |
2482 | + :param not_installed_msg: the message to display if the command |
2483 | + isn't available. |
2484 | + :param env: Optional environment to use rather than os.environ. |
2485 | + :param success_exit_codes: Exit codes to consider succesfull, defaults to [0]. |
2486 | + :param indata: Data to write to standard input |
2487 | + """ |
2488 | + def subprocess_setup(): |
2489 | + signal.signal(signal.SIGPIPE, signal.SIG_DFL) |
2490 | + trace.note(msg) |
2491 | + # Hide output if -q is in use. |
2492 | + quiet = trace.is_quiet() |
2493 | + if quiet: |
2494 | + kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE} |
2495 | + else: |
2496 | + kwargs = {} |
2497 | + if env is not None: |
2498 | + kwargs["env"] = env |
2499 | + trace.mutter("running: %r", command) |
2500 | + try: |
2501 | + proc = subprocess.Popen(command, cwd=basedir, |
2502 | + stdin=subprocess.PIPE, preexec_fn=subprocess_setup, **kwargs) |
2503 | + except OSError, e: |
2504 | + if e.errno != errno.ENOENT: |
2505 | + raise |
2506 | + if not_installed_msg is None: |
2507 | + raise |
2508 | + raise MissingDependency(msg=not_installed_msg) |
2509 | + output = proc.communicate(indata) |
2510 | + if success_exit_codes is None: |
2511 | + success_exit_codes = [0] |
2512 | + if proc.returncode not in success_exit_codes: |
2513 | + if quiet: |
2514 | + raise errors.BzrCommandError("%s: %s" % (error_msg, output)) |
2515 | + else: |
2516 | + raise errors.BzrCommandError(error_msg) |
2517 | + |
2518 | + |
2519 | +def build_source_package(basedir, tgz_check=True): |
2520 | + command = ["/usr/bin/debuild"] |
2521 | + if tgz_check: |
2522 | + command.append("--tgz-check") |
2523 | + else: |
2524 | + command.append("--no-tgz-check") |
2525 | + command.extend(["-i", "-I", "-S", "-uc", "-us"]) |
2526 | + _run_command(command, basedir, |
2527 | + "Building the source package", |
2528 | + "Failed to build the source package", |
2529 | + not_installed_msg="debuild is not installed, please install " |
2530 | + "the devscripts package.") |
2531 | + |
2532 | + |
2533 | +def get_source_format(path): |
2534 | + """Retrieve the source format name from a package. |
2535 | + |
2536 | + :param path: Path to the package |
2537 | + :return: String with package format |
2538 | + """ |
2539 | + source_format_path = os.path.join(path, "debian", "source", "format") |
2540 | + if not os.path.exists(source_format_path): |
2541 | + return "1.0" |
2542 | + f = open(source_format_path, 'r') |
2543 | + try: |
2544 | + return f.read().strip() |
2545 | + finally: |
2546 | + f.close() |
2547 | + |
2548 | + |
2549 | +def convert_3_0_quilt_to_native(path): |
2550 | + """Convert a package in 3.0 (quilt) format to 3.0 (native). |
2551 | + |
2552 | + This applies all patches in the package and updates the |
2553 | + debian/source/format file. |
2554 | + |
2555 | + :param path: Path to the package on disk |
2556 | + """ |
2557 | + path = os.path.abspath(path) |
2558 | + patches_dir = os.path.join(path, "debian", "patches") |
2559 | + series_file = os.path.join(patches_dir, "series") |
2560 | + if os.path.exists(series_file): |
2561 | + _run_command(["quilt", "push", "-a", "-v"], path, |
2562 | + "Applying quilt patches", |
2563 | + "Failed to apply quilt patches", |
2564 | + not_installed_msg="quilt is not installed, please install it.", |
2565 | + env={"QUILT_SERIES": series_file, "QUILT_PATCHES": patches_dir}, |
2566 | + success_exit_codes=(0, 2)) |
2567 | + if os.path.exists(patches_dir): |
2568 | + shutil.rmtree(patches_dir) |
2569 | + f = open(os.path.join(path, "debian", "source", "format"), 'w') |
2570 | + try: |
2571 | + f.write("3.0 (native)\n") |
2572 | + finally: |
2573 | + f.close() |
2574 | + |
2575 | + |
2576 | +def force_native_format(working_tree_path): |
2577 | + """Make sure a package is a format that supports native packages. |
2578 | + |
2579 | + :param working_tree_path: Path to the package |
2580 | + """ |
2581 | + current_format = get_source_format(working_tree_path) |
2582 | + if current_format == "3.0 (quilt)": |
2583 | + convert_3_0_quilt_to_native(working_tree_path) |
2584 | + elif current_format not in ("1.0", "3.0 (native)"): |
2585 | + raise errors.BzrCommandError("Unknown source format %s" % |
2586 | + current_format) |
2587 | + |
2588 | + |
2589 | +def sign_source_package(basedir, key_id): |
2590 | + command = ["/usr/bin/debsign", "-S", "-k%s" % key_id] |
2591 | + _run_command(command, basedir, |
2592 | + "Signing the source package", |
2593 | + "Signing the package failed", |
2594 | + not_installed_msg="debsign is not installed, please install " |
2595 | + "the devscripts package.") |
2596 | + |
2597 | + |
2598 | +def dput_source_package(basedir, target): |
2599 | + command = ["/usr/bin/debrelease", "-S", "--dput", target] |
2600 | + _run_command(command, basedir, |
2601 | + "Uploading the source package", |
2602 | + "Uploading the package failed", |
2603 | + not_installed_msg="debrelease is not installed, please " |
2604 | + "install the devscripts package.") |
2605 | + |
2606 | + |
2607 | +launchpad_recipe_re = lazy_regex.lazy_compile( |
2608 | + r'^https://code.launchpad.net/~(.*)/\+recipe/(.*)$') |
2609 | + |
2610 | + |
2611 | +def get_recipe_from_launchpad(username, recipe_name, location): |
2612 | + """Load a recipe from Launchpad. |
2613 | + |
2614 | + :param username: The launchpad user name |
2615 | + :param recipe_name: Recipe name |
2616 | + :param location: Original location (used for error reporting) |
2617 | + :return: Text of the recipe |
2618 | + """ |
2619 | + from launchpadlib.launchpad import Launchpad |
2620 | + lp = Launchpad.login_with("bzr-builder", "production") |
2621 | + try: |
2622 | + person = lp.people[username] |
2623 | + except KeyError: |
2624 | + raise errors.NoSuchFile(location, |
2625 | + "No such Launchpad user %s" % username) |
2626 | + recipe = person.getRecipe(name=recipe_name) |
2627 | + if recipe is None: |
2628 | + raise errors.NoSuchFile(location, |
2629 | + "Launchpad user %s has no recipe %s" % ( |
2630 | + username, recipe_name)) |
2631 | + return recipe.recipe_text |
2632 | + |
2633 | + |
2634 | +def get_recipe_from_location(location, possible_transports=None): |
2635 | + """Open a recipe as a file-like object from a URL. |
2636 | + |
2637 | + :param location: The recipe location |
2638 | + :param possible_transports: Possible transports to use |
2639 | + :return: Tuple with basename and file-like object |
2640 | + """ |
2641 | + m = launchpad_recipe_re.match(location) |
2642 | + if m: |
2643 | + (username, recipe_name) = m.groups() |
2644 | + text = get_recipe_from_launchpad(username, recipe_name, |
2645 | + location) |
2646 | + return (recipe_name, StringIO(text)) |
2647 | + child_transport = _mod_transport.get_transport(location, |
2648 | + possible_transports=possible_transports) |
2649 | + recipe_transport = child_transport.clone('..') |
2650 | + basename = recipe_transport.relpath(child_transport.base) |
2651 | + return basename, recipe_transport.get(basename) |
2652 | + |
2653 | + |
2654 | +class cmd_build(Command): |
2655 | + """Build a tree based on a branch or a recipe. |
2656 | + |
2657 | + Pass the path of a recipe file or a branch to build and the directory to |
2658 | + work in. |
2659 | + |
2660 | + See "bzr help builder" for more information on what a recipe is. |
2661 | + """ |
2662 | + takes_args = ["location", "working_directory"] |
2663 | + takes_options = [ |
2664 | + Option('manifest', type=str, argname="path", |
2665 | + help="Path to write the manifest to."), |
2666 | + Option('if-changed-from', type=str, argname="path", |
2667 | + help="Only build if the outcome would be different " |
2668 | + "to that specified in the specified manifest."), |
2669 | + 'revision', |
2670 | + ] |
2671 | + |
2672 | + def _get_prepared_branch_from_location(self, location, |
2673 | + if_changed_from=None, safe=False, possible_transports=None, |
2674 | + revspec=None): |
2675 | + """Common code to prepare a branch and do substitutions. |
2676 | + |
2677 | + :param location: a path to a recipe file or branch to work from. |
2678 | + :param if_changed_from: an optional location of a manifest to |
2679 | + compare the recipe against. |
2680 | + :param safe: if True, reject recipes that would cause arbitrary code |
2681 | + execution. |
2682 | + :return: A tuple with (retcode, base_branch). If retcode is None |
2683 | + then the command execution should continue. |
2684 | + """ |
2685 | + try: |
2686 | + base_branch = get_branch_from_recipe_location(location, safe=safe, |
2687 | + possible_transports=possible_transports) |
2688 | + except (_mod_transport.LateReadError, errors.ReadError): |
2689 | + # Presume unable to read means location is a directory rather than a file |
2690 | + base_branch = get_branch_from_branch_location(location, |
2691 | + possible_transports=possible_transports) |
2692 | + else: |
2693 | + if revspec is not None: |
2694 | + raise errors.BzrCommandError("--revision only supported when " |
2695 | + "building from branch") |
2696 | + time = datetime.datetime.utcnow() |
2697 | + base_branch.substitute_time(time) |
2698 | + old_recipe = None |
2699 | + if if_changed_from is not None: |
2700 | + old_recipe = get_old_recipe(if_changed_from, possible_transports) |
2701 | + # Save the unsubstituted version for dailydeb. |
2702 | + self._template_version = base_branch.deb_version |
2703 | + changed = resolve_revisions(base_branch, if_changed_from=old_recipe) |
2704 | + if not changed: |
2705 | + trace.note("Unchanged") |
2706 | + return 0, base_branch |
2707 | + return None, base_branch |
2708 | + |
2709 | + def run(self, location, working_directory, manifest=None, |
2710 | + if_changed_from=None, revision=None): |
2711 | + if revision is not None and len(revision) > 0: |
2712 | + if len(revision) != 1: |
2713 | + raise errors.BzrCommandError("only a single revision can be " |
2714 | + "specified") |
2715 | + revspec = revision[0] |
2716 | + else: |
2717 | + revspec = None |
2718 | + possible_transports = [] |
2719 | + result, base_branch = self._get_prepared_branch_from_location(location, |
2720 | + if_changed_from=if_changed_from, |
2721 | + possible_transports=possible_transports, revspec=revspec) |
2722 | + if result is not None: |
2723 | + return result |
2724 | + manifest_path = manifest or os.path.join(working_directory, |
2725 | + "bzr-builder.manifest") |
2726 | + build_tree(base_branch, working_directory) |
2727 | + write_manifest_to_transport(manifest_path, base_branch, |
2728 | + possible_transports) |
2729 | + |
2730 | + |
2731 | +def debian_source_package_name(control_path): |
2732 | + """Open a debian control file and extract the package name. |
2733 | + |
2734 | + """ |
2735 | + with open(control_path, 'r') as f: |
2736 | + control = deb822.Deb822(f) |
2737 | + return control["Source"] |
2738 | + |
2739 | + |
2740 | +def reconstruct_pristine_tar(dest, delta, dest_filename): |
2741 | + """Reconstruct a pristine tarball from a directory and a delta. |
2742 | + |
2743 | + :param dest: Directory to pack |
2744 | + :param delta: pristine-tar delta |
2745 | + :param dest_filename: Destination filename |
2746 | + """ |
2747 | + command = ["pristine-tar", "gentar", "-", |
2748 | + os.path.abspath(dest_filename)] |
2749 | + _run_command(command, dest, |
2750 | + "Reconstructing pristine tarball", |
2751 | + "Generating tar from delta failed", |
2752 | + not_installed_msg="pristine-tar is not installed", |
2753 | + indata=delta) |
2754 | + |
2755 | + |
2756 | +def extract_upstream_tarball(branch, package, version, dest_dir): |
2757 | + """Extract the upstream tarball from a branch. |
2758 | + |
2759 | + :param branch: Branch with the upstream pristine tar data |
2760 | + :param package: Package name |
2761 | + :param version: Package version |
2762 | + :param dest_dir: Destination directory |
2763 | + """ |
2764 | + tag_name = "upstream-%s" % version |
2765 | + revid = branch.tags.lookup_tag(tag_name) |
2766 | + tree = branch.repository.revision_tree(revid) |
2767 | + rev = branch.repository.get_revision(revid) |
2768 | + if 'deb-pristine-delta' in rev.properties: |
2769 | + uuencoded = rev.properties['deb-pristine-delta'] |
2770 | + dest_filename = "%s_%s.orig.tar.gz" % (package, version) |
2771 | + elif 'deb-pristine-delta-bz2' in rev.properties: |
2772 | + uuencoded = rev.properties['deb-pristine-delta-bz2'] |
2773 | + dest_filename = "%s_%s.orig.tar.bz2" % (package, version) |
2774 | + else: |
2775 | + uuencoded = None |
2776 | + if uuencoded is not None: |
2777 | + delta = standard_b64decode(uuencoded) |
2778 | + dest = os.path.join(dest_dir, "orig") |
2779 | + try: |
2780 | + _mod_export.export(tree, dest, format='dir') |
2781 | + reconstruct_pristine_tar(dest, delta, |
2782 | + os.path.join(dest_dir, dest_filename)) |
2783 | + finally: |
2784 | + if os.path.exists(dest): |
2785 | + shutil.rmtree(dest) |
2786 | + else: |
2787 | + # Default to .tar.gz |
2788 | + dest_filename = "%s_%s.orig.tar.gz" % (package, version) |
2789 | + _mod_export.export(tree, os.path.join(dest_dir, dest_filename), |
2790 | + per_file_timestamps=True) |
2791 | + |
2792 | + |
2793 | +class cmd_dailydeb(cmd_build): |
2794 | + """Build a deb based on a 'recipe' or from a branch. |
2795 | + |
2796 | + See "bzr help builder" for more information on what a recipe is. |
2797 | + |
2798 | + If you do not specify a working directory then a temporary |
2799 | + directory will be used and it will be removed when the command |
2800 | + finishes. |
2801 | + """ |
2802 | + |
2803 | + takes_options = cmd_build.takes_options + [ |
2804 | + Option("package", type=str, |
2805 | + help="The package name to use in the changelog entry. " |
2806 | + "If not specified then the package from the " |
2807 | + "previous changelog entry will be used, so it " |
2808 | + "must be specified if there is no changelog."), |
2809 | + Option("distribution", type=str, |
2810 | + help="The distribution to target. If not specified " |
2811 | + "then the same distribution as the last entry " |
2812 | + "in debian/changelog will be used."), |
2813 | + Option("dput", type=str, argname="target", |
2814 | + help="dput the built package to the specified " |
2815 | + "dput target."), |
2816 | + Option("key-id", type=str, short_name="k", |
2817 | + help="Sign the packages with the specified GnuPG key. " |
2818 | + "Must be specified if you use --dput."), |
2819 | + Option("no-build", |
2820 | + help="Just ready the source package and don't " |
2821 | + "actually build it."), |
2822 | + Option("watch-ppa", help="Watch the PPA the package was " |
2823 | + "dput to and exit with 0 only if it builds and " |
2824 | + "publishes successfully."), |
2825 | + Option("append-version", type=str, help="Append the " |
2826 | + "specified string to the end of the version used " |
2827 | + "in debian/changelog."), |
2828 | + Option("safe", help="Error if the recipe would cause" |
2829 | + " arbitrary code execution."), |
2830 | + Option("allow-fallback-to-native", |
2831 | + help="Allow falling back to a native package if the upstream " |
2832 | + "tarball can not be found."), |
2833 | + ] |
2834 | + |
2835 | + takes_args = ["location", "working_basedir?"] |
2836 | + |
2837 | + def run(self, location, working_basedir=None, manifest=None, |
2838 | + if_changed_from=None, package=None, distribution=None, |
2839 | + dput=None, key_id=None, no_build=None, watch_ppa=False, |
2840 | + append_version=None, safe=False, allow_fallback_to_native=False): |
2841 | + |
2842 | + if dput is not None and key_id is None: |
2843 | + raise errors.BzrCommandError("You must specify --key-id if you " |
2844 | + "specify --dput.") |
2845 | + if watch_ppa: |
2846 | + if not dput: |
2847 | + raise errors.BzrCommandError( |
2848 | + "cannot watch a ppa without doing dput.") |
2849 | + else: |
2850 | + # Check we can calculate a PPA url. |
2851 | + target_from_dput(dput) |
2852 | + |
2853 | + possible_transports = [] |
2854 | + result, base_branch = self._get_prepared_branch_from_location(location, |
2855 | + if_changed_from=if_changed_from, safe=safe, |
2856 | + possible_transports=possible_transports) |
2857 | + if result is not None: |
2858 | + return result |
2859 | + if working_basedir is None: |
2860 | + temp_dir = tempfile.mkdtemp(prefix="bzr-builder-") |
2861 | + working_basedir = temp_dir |
2862 | + else: |
2863 | + temp_dir = None |
2864 | + if not os.path.exists(working_basedir): |
2865 | + os.makedirs(working_basedir) |
2866 | + package_name = self._calculate_package_name(location, package) |
2867 | + if self._template_version is None: |
2868 | + working_directory = os.path.join(working_basedir, |
2869 | + "%s-direct" % (package_name,)) |
2870 | + else: |
2871 | + working_directory = os.path.join(working_basedir, |
2872 | + "%s-%s" % (package_name, self._template_version)) |
2873 | + try: |
2874 | + # we want to use a consistent package_dir always to support |
2875 | + # updates in place, but debuild etc want PACKAGE-UPSTREAMVERSION |
2876 | + # on disk, so we build_tree with the unsubstituted version number |
2877 | + # and do a final rename-to step before calling into debian build |
2878 | + # tools. We then rename the working dir back. |
2879 | + manifest_path = os.path.join(working_directory, "debian", |
2880 | + "bzr-builder.manifest") |
2881 | + build_tree(base_branch, working_directory) |
2882 | + control_path = os.path.join(working_directory, "debian", "control") |
2883 | + if not os.path.exists(control_path): |
2884 | + if package is None: |
2885 | + raise errors.BzrCommandError("No control file to " |
2886 | + "take the package name from, and --package not " |
2887 | + "specified.") |
2888 | + else: |
2889 | + package = debian_source_package_name(control_path) |
2890 | + write_manifest_to_transport(manifest_path, base_branch, |
2891 | + possible_transports) |
2892 | + autobuild = (base_branch.deb_version is not None) |
2893 | + if autobuild: |
2894 | + # Add changelog also substitutes {debupstream}. |
2895 | + add_autobuild_changelog_entry(base_branch, working_directory, |
2896 | + package, distribution=distribution, |
2897 | + append_version=append_version) |
2898 | + else: |
2899 | + if append_version: |
2900 | + raise errors.BzrCommandError("--append-version only " |
2901 | + "supported for autobuild recipes (with a 'deb-version' " |
2902 | + "header)") |
2903 | + with open(os.path.join(working_directory, "debian", "changelog")) as cl_f: |
2904 | + contents = cl_f.read() |
2905 | + cl = changelog.Changelog(file=contents) |
2906 | + package_name = cl.package |
2907 | + package_version = cl.version |
2908 | + package_dir = calculate_package_dir(package_name, package_version, |
2909 | + working_basedir) |
2910 | + # working_directory -> package_dir: after this debian stuff works. |
2911 | + os.rename(working_directory, package_dir) |
2912 | + if no_build: |
2913 | + if manifest is not None: |
2914 | + write_manifest_to_transport(manifest, base_branch, |
2915 | + possible_transports) |
2916 | + return 0 |
2917 | + if package_version.debian_revision is not None: |
2918 | + # Non-native package |
2919 | + try: |
2920 | + extract_upstream_tarball(base_branch.branch, package_name, |
2921 | + package_version.upstream_version, working_basedir) |
2922 | + except errors.NoSuchTag: |
2923 | + if not allow_fallback_to_native: |
2924 | + raise |
2925 | + if allow_fallback_to_native: |
2926 | + force_native_format(package_dir) |
2927 | + try: |
2928 | + build_source_package(package_dir, |
2929 | + tgz_check=not allow_fallback_to_native) |
2930 | + if key_id is not None: |
2931 | + sign_source_package(package_dir, key_id) |
2932 | + if dput is not None: |
2933 | + dput_source_package(package_dir, dput) |
2934 | + finally: |
2935 | + # package_dir -> working_directory |
2936 | + # FIXME: may fail in error unwind, masking the original exception. |
2937 | + os.rename(package_dir, working_directory) |
2938 | + # Note that this may write a second manifest. |
2939 | + if manifest is not None: |
2940 | + write_manifest_to_transport(manifest, base_branch, |
2941 | + possible_transports) |
2942 | + finally: |
2943 | + if temp_dir is not None: |
2944 | + shutil.rmtree(temp_dir) |
2945 | + if watch_ppa: |
2946 | + from bzrlib.plugins.builder.ppa import watch |
2947 | + (owner, archive) = target_from_dput(dput) |
2948 | + if not watch(owner, archive, package_name, base_branch.deb_version): |
2949 | + return 2 |
2950 | + |
2951 | + def _calculate_package_name(self, recipe_location, package): |
2952 | + """Calculate the directory name that should be used while debuilding.""" |
2953 | + recipe_name = urlutils.basename(recipe_location) |
2954 | + if recipe_name.endswith(".recipe"): |
2955 | + recipe_name = recipe_name[:-len(".recipe")] |
2956 | + return package or recipe_name |
2957 | + |
2958 | + |
2959 | +def target_from_dput(dput): |
2960 | + """Convert a dput specification to a LP API specification. |
2961 | + |
2962 | + :param dput: A dput command spec like ppa:team-name. |
2963 | + :return: A LP API target like team-name/ppa. |
2964 | + """ |
2965 | + ppa_prefix = 'ppa:' |
2966 | + if not dput.startswith(ppa_prefix): |
2967 | + raise errors.BzrCommandError('%r does not appear to be a PPA. ' |
2968 | + 'A dput target like \'%suser[/name]\' must be used.' |
2969 | + % (dput, ppa_prefix)) |
2970 | + base, _, suffix = dput[len(ppa_prefix):].partition('/') |
2971 | + if not suffix: |
2972 | + suffix = 'ppa' |
2973 | + return base, suffix |
2974 | + |
2975 | |
2976 | === removed file 'cmds.py' |
2977 | --- cmds.py 2010-10-21 21:17:28 +0000 |
2978 | +++ cmds.py 1970-01-01 00:00:00 +0000 |
2979 | @@ -1,507 +0,0 @@ |
2980 | -# bzr-builder: a bzr plugin to constuct trees based on recipes |
2981 | -# Copyright 2009 Canonical Ltd. |
2982 | - |
2983 | -# This program is free software: you can redistribute it and/or modify it |
2984 | -# under the terms of the GNU General Public License version 3, as published |
2985 | -# by the Free Software Foundation. |
2986 | - |
2987 | -# This program is distributed in the hope that it will be useful, but |
2988 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
2989 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
2990 | -# PURPOSE. See the GNU General Public License for more details. |
2991 | - |
2992 | -# You should have received a copy of the GNU General Public License along |
2993 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
2994 | - |
2995 | -"""Subcommands provided by bzr-builder.""" |
2996 | - |
2997 | -import datetime |
2998 | -from email import utils |
2999 | -import errno |
3000 | -import os |
3001 | -import pwd |
3002 | -import re |
3003 | -import socket |
3004 | -import shutil |
3005 | -import subprocess |
3006 | -import tempfile |
3007 | - |
3008 | -try: |
3009 | - from debian import changelog |
3010 | -except ImportError: |
3011 | - # In older versions of python-debian the main package was named |
3012 | - # debian_bundle |
3013 | - from debian_bundle import changelog |
3014 | - |
3015 | -from bzrlib import ( |
3016 | - errors, |
3017 | - trace, |
3018 | - transport, |
3019 | - ) |
3020 | -from bzrlib.commands import Command |
3021 | -from bzrlib.option import Option |
3022 | - |
3023 | -from bzrlib.plugins.builder.recipe import ( |
3024 | - build_tree, |
3025 | - DEBUPSTREAM_VAR, |
3026 | - RecipeParser, |
3027 | - resolve_revisions, |
3028 | - SAFE_INSTRUCTIONS, |
3029 | - ) |
3030 | - |
3031 | - |
3032 | -# The default distribution used by add_changelog_entry() |
3033 | -DEFAULT_UBUNTU_DISTRIBUTION = "lucid" |
3034 | - |
3035 | - |
3036 | -class MissingDependency(errors.BzrError): |
3037 | - pass |
3038 | - |
3039 | - |
3040 | -def write_manifest_to_path(path, base_branch): |
3041 | - parent_dir = os.path.dirname(path) |
3042 | - if parent_dir != '' and not os.path.exists(parent_dir): |
3043 | - os.makedirs(parent_dir) |
3044 | - manifest_f = open(path, 'wb') |
3045 | - try: |
3046 | - manifest_f.write(str(base_branch)) |
3047 | - finally: |
3048 | - manifest_f.close() |
3049 | - |
3050 | - |
3051 | -def get_branch_from_recipe_file(recipe_file, safe=False): |
3052 | - """Return the base branch for the specified recipe. |
3053 | - |
3054 | - :param recipe_file: The URL of the recipe file to retrieve. |
3055 | - :param safe: if True, reject recipes that would cause arbitrary code |
3056 | - execution. |
3057 | - """ |
3058 | - recipe_transport = transport.get_transport(os.path.dirname(recipe_file)) |
3059 | - try: |
3060 | - recipe_contents = recipe_transport.get_bytes( |
3061 | - os.path.basename(recipe_file)) |
3062 | - except errors.NoSuchFile: |
3063 | - raise errors.BzrCommandError("Specified recipe does not exist: " |
3064 | - "%s" % recipe_file) |
3065 | - if safe: |
3066 | - permitted_instructions = SAFE_INSTRUCTIONS |
3067 | - else: |
3068 | - permitted_instructions = None |
3069 | - parser = RecipeParser(recipe_contents, filename=recipe_file) |
3070 | - return parser.parse(permitted_instructions=permitted_instructions) |
3071 | - |
3072 | - |
3073 | -def get_old_recipe(if_changed_from): |
3074 | - old_manifest_transport = transport.get_transport(os.path.dirname( |
3075 | - if_changed_from)) |
3076 | - try: |
3077 | - old_manifest_contents = old_manifest_transport.get_bytes( |
3078 | - os.path.basename(if_changed_from)) |
3079 | - except errors.NoSuchFile: |
3080 | - return None |
3081 | - old_recipe = RecipeParser(old_manifest_contents, |
3082 | - filename=if_changed_from).parse() |
3083 | - return old_recipe |
3084 | - |
3085 | - |
3086 | -def get_maintainer(): |
3087 | - """Create maintainer string using the same algorithm as in dch. |
3088 | - """ |
3089 | - env = os.environ |
3090 | - regex = re.compile(r"^(.*)\s+<(.*)>$") |
3091 | - |
3092 | - # Split email and name |
3093 | - if 'DEBEMAIL' in env: |
3094 | - match_obj = regex.match(env['DEBEMAIL']) |
3095 | - if match_obj: |
3096 | - if not 'DEBFULLNAME' in env: |
3097 | - env['DEBFULLNAME'] = match_obj.group(1) |
3098 | - env['DEBEMAIL'] = match_obj.group(2) |
3099 | - if 'DEBEMAIL' not in env or 'DEBFULLNAME' not in env: |
3100 | - if 'EMAIL' in env: |
3101 | - match_obj = regex.match(env['EMAIL']) |
3102 | - if match_obj: |
3103 | - if not 'DEBFULLNAME' in env: |
3104 | - env['DEBFULLNAME'] = match_obj.group(1) |
3105 | - env['EMAIL'] = match_obj.group(2) |
3106 | - |
3107 | - # Get maintainer's name |
3108 | - if 'DEBFULLNAME' in env: |
3109 | - maintainer = env['DEBFULLNAME'] |
3110 | - elif 'NAME' in env: |
3111 | - maintainer = env['NAME'] |
3112 | - else: |
3113 | - # Use password database if no data in environment variables |
3114 | - try: |
3115 | - maintainer = re.sub(r',.*', '', pwd.getpwuid(os.getuid()).pw_gecos) |
3116 | - except (KeyError, AttributeError): |
3117 | - # TBD: Use last changelog entry value |
3118 | - maintainer = "bzr-builder" |
3119 | - |
3120 | - # Get maintainer's mail address |
3121 | - if 'DEBEMAIL' in env: |
3122 | - email = env['DEBEMAIL'] |
3123 | - elif 'EMAIL' in env: |
3124 | - email = env['EMAIL'] |
3125 | - else: |
3126 | - addr = None |
3127 | - if os.path.exists('/etc/mailname'): |
3128 | - f = open('/etc/mailname') |
3129 | - try: |
3130 | - addr = f.readline().strip() |
3131 | - finally: |
3132 | - f.close() |
3133 | - if not addr: |
3134 | - addr = socket.getfqdn() |
3135 | - if addr: |
3136 | - user = pwd.getpwuid(os.getuid()).pw_name |
3137 | - if not user: |
3138 | - addr = None |
3139 | - else: |
3140 | - addr = "%s@%s" % (user, addr) |
3141 | - |
3142 | - if addr: |
3143 | - email = addr |
3144 | - else: |
3145 | - # TBD: Use last changelog entry value |
3146 | - email = "none@example.org" |
3147 | - |
3148 | - return (maintainer, email) |
3149 | - |
3150 | - |
3151 | -def add_changelog_entry(base_branch, basedir, distribution=None, |
3152 | - package=None, author_name=None, author_email=None, |
3153 | - append_version=None): |
3154 | - debian_dir = os.path.join(basedir, "debian") |
3155 | - if not os.path.exists(debian_dir): |
3156 | - os.makedirs(debian_dir) |
3157 | - cl_path = os.path.join(debian_dir, "changelog") |
3158 | - file_found = False |
3159 | - if os.path.exists(cl_path): |
3160 | - file_found = True |
3161 | - cl_f = open(cl_path) |
3162 | - try: |
3163 | - contents = cl_f.read() |
3164 | - finally: |
3165 | - cl_f.close() |
3166 | - cl = changelog.Changelog(file=contents) |
3167 | - else: |
3168 | - cl = changelog.Changelog() |
3169 | - if len(cl._blocks) > 0: |
3170 | - if distribution is None: |
3171 | - distribution = cl._blocks[0].distributions.split()[0] |
3172 | - if package is None: |
3173 | - package = cl._blocks[0].package |
3174 | - if DEBUPSTREAM_VAR in base_branch.deb_version: |
3175 | - cl_version = cl._blocks[0].version |
3176 | - base_branch.substitute_debupstream(cl_version) |
3177 | - else: |
3178 | - if file_found: |
3179 | - if len(contents.strip()) > 0: |
3180 | - reason = ("debian/changelog didn't contain any " |
3181 | - "parseable stanzas") |
3182 | - else: |
3183 | - reason = "debian/changelog was empty" |
3184 | - else: |
3185 | - reason = "debian/changelog was not present" |
3186 | - if package is None: |
3187 | - raise errors.BzrCommandError("No previous changelog to " |
3188 | - "take the package name from, and --package not " |
3189 | - "specified: %s." % reason) |
3190 | - if DEBUPSTREAM_VAR in base_branch.deb_version: |
3191 | - raise errors.BzrCommandError("No previous changelog to " |
3192 | - "take the upstream version from as %s was " |
3193 | - "used: %s." % (DEBUPSTREAM_VAR, reason)) |
3194 | - if distribution is None: |
3195 | - distribution = DEFAULT_UBUNTU_DISTRIBUTION |
3196 | - # Use debian packaging environment variables |
3197 | - # or default values if they don't exist |
3198 | - if author_name is None or author_email is None: |
3199 | - author_name, author_email = get_maintainer() |
3200 | - author = "%s <%s>" % (author_name, author_email) |
3201 | - |
3202 | - date = utils.formatdate(localtime=True) |
3203 | - version = base_branch.deb_version |
3204 | - if append_version is not None: |
3205 | - version += append_version |
3206 | - try: |
3207 | - changelog.Version(version) |
3208 | - except (changelog.VersionError, ValueError), e: |
3209 | - raise errors.BzrCommandError("Invalid deb-version: %s: %s" |
3210 | - % (version, e)) |
3211 | - cl.new_block(package=package, version=version, |
3212 | - distributions=distribution, urgency="low", |
3213 | - changes=['', ' * Auto build.', ''], |
3214 | - author=author, date=date) |
3215 | - cl_f = open(cl_path, 'wb') |
3216 | - try: |
3217 | - cl.write_to_open_file(cl_f) |
3218 | - finally: |
3219 | - cl_f.close() |
3220 | - |
3221 | - |
3222 | -def calculate_package_dir(base_branch, package_name, working_basedir): |
3223 | - """Calculate the directory name that should be used while debuilding.""" |
3224 | - version = base_branch.deb_version |
3225 | - if "-" in version: |
3226 | - version = version[:version.rindex("-")] |
3227 | - package_basedir = "%s-%s" % (package_name, version) |
3228 | - package_dir = os.path.join(working_basedir, package_basedir) |
3229 | - return package_dir |
3230 | - |
3231 | - |
3232 | -def _run_command(command, basedir, msg, error_msg, |
3233 | - not_installed_msg=None): |
3234 | - """ Run a command in a subprocess. |
3235 | - |
3236 | - :param command: list with command and parameters |
3237 | - :param msg: message to display to the user |
3238 | - :param error_msg: message to display if something fails. |
3239 | - :param not_installed_msg: the message to display if the command |
3240 | - isn't available. |
3241 | - """ |
3242 | - trace.note(msg) |
3243 | - # Hide output if -q is in use. |
3244 | - quiet = trace.is_quiet() |
3245 | - if quiet: |
3246 | - kwargs = {"stderr": subprocess.STDOUT, "stdout": subprocess.PIPE} |
3247 | - else: |
3248 | - kwargs = {} |
3249 | - try: |
3250 | - proc = subprocess.Popen(command, cwd=basedir, |
3251 | - stdin=subprocess.PIPE, **kwargs) |
3252 | - except OSError, e: |
3253 | - if e.errno != errno.ENOENT: |
3254 | - raise |
3255 | - if not_installed_msg is None: |
3256 | - raise |
3257 | - raise MissingDependency(msg=not_installed_msg) |
3258 | - output = proc.communicate() |
3259 | - if proc.returncode != 0: |
3260 | - if quiet: |
3261 | - raise errors.BzrCommandError("%s: %s" % (error_msg, output)) |
3262 | - else: |
3263 | - raise errors.BzrCommandError(error_msg) |
3264 | - |
3265 | - |
3266 | -def build_source_package(basedir): |
3267 | - command = ["/usr/bin/debuild", "--no-tgz-check", "-i", "-I", "-S", |
3268 | - "-uc", "-us"] |
3269 | - _run_command(command, basedir, |
3270 | - "Building the source package", |
3271 | - "Failed to build the source package", |
3272 | - not_installed_msg="debuild is not installed, please install " |
3273 | - "the devscripts package.") |
3274 | - |
3275 | - |
3276 | -def sign_source_package(basedir, key_id): |
3277 | - command = ["/usr/bin/debsign", "-S", "-k%s" % key_id] |
3278 | - _run_command(command, basedir, |
3279 | - "Signing the source package", |
3280 | - "Signing the package failed", |
3281 | - not_installed_msg="debsign is not installed, please install " |
3282 | - "the devscripts package.") |
3283 | - |
3284 | - |
3285 | -def dput_source_package(basedir, target): |
3286 | - command = ["/usr/bin/debrelease", "-S", "--dput", target] |
3287 | - _run_command(command, basedir, |
3288 | - "Uploading the source package", |
3289 | - "Uploading the package failed", |
3290 | - not_installed_msg="debrelease is not installed, please " |
3291 | - "install the devscripts package.") |
3292 | - |
3293 | - |
3294 | -class cmd_build(Command): |
3295 | - """Build a tree based on a 'recipe'. |
3296 | - |
3297 | - Pass the name of the recipe file and the directory to work in. |
3298 | - |
3299 | - See "bzr help builder" for more information on what a recipe is. |
3300 | - """ |
3301 | - takes_args = ["recipe_file", "working_directory"] |
3302 | - takes_options = [ |
3303 | - Option('manifest', type=str, argname="path", |
3304 | - help="Path to write the manifest to."), |
3305 | - Option('if-changed-from', type=str, argname="path", |
3306 | - help="Only build if the outcome would be different " |
3307 | - "to that specified in the specified manifest."), |
3308 | - ] |
3309 | - |
3310 | - def _get_prepared_branch_from_recipe(self, recipe_file, |
3311 | - if_changed_from=None, safe=False): |
3312 | - """Common code to prepare a branch and do substitutions. |
3313 | - |
3314 | - :param recipe_file: a path to a recipe file to work from. |
3315 | - :param if_changed_from: an optional path to a manifest to |
3316 | - compare the recipe against. |
3317 | - :param safe: if True, reject recipes that would cause arbitrary code |
3318 | - execution. |
3319 | - :return: A tuple with (retcode, base_branch). If retcode is None |
3320 | - then the command execution should continue. |
3321 | - """ |
3322 | - base_branch = get_branch_from_recipe_file(recipe_file, safe=safe) |
3323 | - time = datetime.datetime.utcnow() |
3324 | - base_branch.substitute_time(time) |
3325 | - old_recipe = None |
3326 | - if if_changed_from is not None: |
3327 | - old_recipe = get_old_recipe(if_changed_from) |
3328 | - # Save the unsubstituted version for dailydeb. |
3329 | - self._template_version = base_branch.deb_version |
3330 | - changed = resolve_revisions(base_branch, if_changed_from=old_recipe) |
3331 | - if not changed: |
3332 | - trace.note("Unchanged") |
3333 | - return 0, base_branch |
3334 | - return None, base_branch |
3335 | - |
3336 | - def run(self, recipe_file, working_directory, manifest=None, |
3337 | - if_changed_from=None): |
3338 | - result, base_branch = self._get_prepared_branch_from_recipe(recipe_file, |
3339 | - if_changed_from=if_changed_from) |
3340 | - if result is not None: |
3341 | - return result |
3342 | - manifest_path = manifest or os.path.join(working_directory, |
3343 | - "bzr-builder.manifest") |
3344 | - build_tree(base_branch, working_directory) |
3345 | - write_manifest_to_path(manifest_path, base_branch) |
3346 | - |
3347 | - |
3348 | -class cmd_dailydeb(cmd_build): |
3349 | - """Build a deb based on a 'recipe'. |
3350 | - |
3351 | - See "bzr help builder" for more information on what a recipe is. |
3352 | - |
3353 | - If you do not specify a working directory then a temporary |
3354 | - directory will be used and it will be removed when the command |
3355 | - finishes. |
3356 | - """ |
3357 | - |
3358 | - takes_options = cmd_build.takes_options + [ |
3359 | - Option("package", type=str, |
3360 | - help="The package name to use in the changelog entry. " |
3361 | - "If not specified then the package from the " |
3362 | - "previous changelog entry will be used, so it " |
3363 | - "must be specified if there is no changelog."), |
3364 | - Option("distribution", type=str, |
3365 | - help="The distribution to target. If not specified " |
3366 | - "then the same distribution as the last entry " |
3367 | - "in debian/changelog will be used."), |
3368 | - Option("dput", type=str, argname="target", |
3369 | - help="dput the built package to the specified " |
3370 | - "dput target."), |
3371 | - Option("key-id", type=str, short_name="k", |
3372 | - help="Sign the packages with the specified GnuPG key. " |
3373 | - "Must be specified if you use --dput."), |
3374 | - Option("no-build", |
3375 | - help="Just ready the source package and don't " |
3376 | - "actually build it."), |
3377 | - Option("watch-ppa", help="Watch the PPA the package was " |
3378 | - "dput to and exit with 0 only if it builds and " |
3379 | - "publishes successfully."), |
3380 | - Option("append-version", type=str, help="Append the " |
3381 | - "specified string to the end of the version used " |
3382 | - "in debian/changelog."), |
3383 | - Option("safe", help="Error if the recipe would cause" |
3384 | - " arbitrary code execution.") |
3385 | - ] |
3386 | - |
3387 | - takes_args = ["recipe_file", "working_basedir?"] |
3388 | - |
3389 | - def run(self, recipe_file, working_basedir=None, manifest=None, |
3390 | - if_changed_from=None, package=None, distribution=None, |
3391 | - dput=None, key_id=None, no_build=None, watch_ppa=False, |
3392 | - append_version=None, safe=False): |
3393 | - |
3394 | - if dput is not None and key_id is None: |
3395 | - raise errors.BzrCommandError("You must specify --key-id if you " |
3396 | - "specify --dput.") |
3397 | - if watch_ppa: |
3398 | - if not dput: |
3399 | - raise errors.BzrCommandError( |
3400 | - "cannot watch a ppa without doing dput.") |
3401 | - else: |
3402 | - # Check we can calculate a PPA url. |
3403 | - target_from_dput(dput) |
3404 | - |
3405 | - result, base_branch = self._get_prepared_branch_from_recipe(recipe_file, |
3406 | - if_changed_from=if_changed_from, safe=safe) |
3407 | - if result is not None: |
3408 | - return result |
3409 | - if working_basedir is None: |
3410 | - temp_dir = tempfile.mkdtemp(prefix="bzr-builder-") |
3411 | - working_basedir = temp_dir |
3412 | - else: |
3413 | - temp_dir = None |
3414 | - if not os.path.exists(working_basedir): |
3415 | - os.makedirs(working_basedir) |
3416 | - package_name = self._calculate_package_name(recipe_file, package) |
3417 | - working_directory = os.path.join(working_basedir, |
3418 | - "%s-%s" % (package_name, self._template_version)) |
3419 | - try: |
3420 | - # we want to use a consistent package_dir always to support |
3421 | - # updates in place, but debuild etc want PACKAGE-UPSTREAMVERSION |
3422 | - # on disk, so we build_tree with the unsubstituted version number |
3423 | - # and do a final rename-to step before calling into debian build |
3424 | - # tools. We then rename the working dir back. |
3425 | - manifest_path = os.path.join(working_directory, "debian", |
3426 | - "bzr-builder.manifest") |
3427 | - build_tree(base_branch, working_directory) |
3428 | - write_manifest_to_path(manifest_path, base_branch) |
3429 | - # Add changelog also substitutes {debupstream}. |
3430 | - add_changelog_entry(base_branch, working_directory, |
3431 | - distribution=distribution, package=package, |
3432 | - append_version=append_version) |
3433 | - package_dir = calculate_package_dir(base_branch, |
3434 | - package_name, working_basedir) |
3435 | - # working_directory -> package_dir: after this debian stuff works. |
3436 | - os.rename(working_directory, package_dir) |
3437 | - if no_build: |
3438 | - if manifest is not None: |
3439 | - write_manifest_to_path(manifest, base_branch) |
3440 | - return 0 |
3441 | - try: |
3442 | - build_source_package(package_dir) |
3443 | - if key_id is not None: |
3444 | - sign_source_package(package_dir, key_id) |
3445 | - if dput is not None: |
3446 | - dput_source_package(package_dir, dput) |
3447 | - finally: |
3448 | - # package_dir -> working_directory |
3449 | - # FIXME: may fail in error unwind, masking the original exception. |
3450 | - os.rename(package_dir, working_directory) |
3451 | - # Note that this may write a second manifest. |
3452 | - if manifest is not None: |
3453 | - write_manifest_to_path(manifest, base_branch) |
3454 | - finally: |
3455 | - if temp_dir is not None: |
3456 | - shutil.rmtree(temp_dir) |
3457 | - if watch_ppa: |
3458 | - from bzrlib.plugins.builder.ppa import watch |
3459 | - target = target_from_dput(dput) |
3460 | - if not watch(target, self.package, base_branch.deb_version): |
3461 | - return 2 |
3462 | - |
3463 | - def _calculate_package_name(self, recipe_file, package): |
3464 | - """Calculate the directory name that should be used while debuilding.""" |
3465 | - recipe_name = os.path.basename(recipe_file) |
3466 | - if recipe_name.endswith(".recipe"): |
3467 | - recipe_name = recipe_name[:-len(".recipe")] |
3468 | - return package or recipe_name |
3469 | - |
3470 | - |
3471 | -def target_from_dput(dput): |
3472 | - """Convert a dput specification to a LP API specification. |
3473 | - |
3474 | - :param dput: A dput command spec like ppa:team-name. |
3475 | - :return: A LP API target like team-name/ppa. |
3476 | - """ |
3477 | - ppa_prefix = 'ppa:' |
3478 | - if not dput.startswith(ppa_prefix): |
3479 | - raise errors.BzrCommandError('%r does not appear to be a PPA. ' |
3480 | - 'A dput target like \'%suser[/name]\' must be used.' |
3481 | - % (dput, ppa_prefix)) |
3482 | - base, _, suffix = dput[len(ppa_prefix):].partition('/') |
3483 | - if not suffix: |
3484 | - suffix = 'ppa' |
3485 | - return base + '/' + suffix |
3486 | - |
3487 | |
3488 | === modified file 'debian/changelog' |
3489 | --- debian/changelog 2011-06-10 17:46:25 +0000 |
3490 | +++ debian/changelog 2011-06-14 17:23:32 +0000 |
3491 | @@ -1,3 +1,13 @@ |
3492 | +bzr-builder (0.7-0ubuntu1) oneiric; urgency=low |
3493 | + |
3494 | + * New upstream release. |
3495 | + + Fixes attribute error in "bzr dailydeb". LP: #744087 |
3496 | + * Bump standards version to 3.9.2 (no changes). |
3497 | + * Run test suite during build. |
3498 | + * Switch to source format 3. |
3499 | + |
3500 | + -- Jelmer Vernooij <jelmer@ubuntu.com> Tue, 14 Jun 2011 15:29:07 +0200 |
3501 | + |
3502 | bzr-builder (0.6-0ubuntu2) oneiric; urgency=low |
3503 | |
3504 | * Convert to dh_python2 from deprecated py-central. |
3505 | |
3506 | === modified file 'debian/control' |
3507 | --- debian/control 2011-06-10 17:46:25 +0000 |
3508 | +++ debian/control 2011-06-14 17:23:32 +0000 |
3509 | @@ -3,18 +3,20 @@ |
3510 | Priority: optional |
3511 | Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> |
3512 | XSBC-Original-Maintainer: James Westby <james.westby@ubuntu.com> |
3513 | -Build-Depends: debhelper (>= 7), python (>= 2.6.6-3~) |
3514 | -Build-Depends-Indep: bzr, python-debian |
3515 | +Build-Depends: debhelper (>= 7.0.50~), python (>= 2.6.6-3~) |
3516 | +Build-Depends-Indep: bzr, python-debian, python-subunit, python-testtools, python-bzrlib.tests | bzr (<< 2.4.0~beta1-2), devscripts, quilt |
3517 | X-Python-Version: >= 2.4 |
3518 | -Standards-Version: 3.9.1 |
3519 | +Standards-Version: 3.9.2 |
3520 | Homepage: http://launchpad.net/bzr-builder |
3521 | |
3522 | Package: bzr-builder |
3523 | Architecture: all |
3524 | +Recommends: pristine-tar |
3525 | Depends: bzr, |
3526 | devscripts, |
3527 | dput, |
3528 | python-debian, |
3529 | + quilt, |
3530 | ${misc:Depends}, |
3531 | ${python:Depends} |
3532 | Description: construct a bzr branch from a recipe |
3533 | |
3534 | === added directory 'debian/patches' |
3535 | === added file 'debian/patches/01_broken_test' |
3536 | --- debian/patches/01_broken_test 1970-01-01 00:00:00 +0000 |
3537 | +++ debian/patches/01_broken_test 2011-06-14 17:23:32 +0000 |
3538 | @@ -0,0 +1,24 @@ |
3539 | +Author: Jelmer Vernooij <jelmer@ubuntu.com> |
3540 | +Description: Disable known broken test |
3541 | +Status: Not applicable for upstream (test will be fixed instead) |
3542 | + |
3543 | +=== modified file 'tests/test_recipe.py' |
3544 | +--- old/tests/test_recipe.py 2011-06-14 12:58:17 +0000 |
3545 | ++++ new/tests/test_recipe.py 2011-06-14 13:26:29 +0000 |
3546 | +@@ -23,6 +23,7 @@ |
3547 | + workingtree, |
3548 | + ) |
3549 | + from bzrlib.tests import ( |
3550 | ++ KnownFailure, |
3551 | + TestCase, |
3552 | + TestCaseInTempDir, |
3553 | + TestCaseWithTransport, |
3554 | +@@ -1334,6 +1335,7 @@ |
3555 | + self.assertEqual("1-19700101", base_branch.deb_version) |
3556 | + |
3557 | + def test_substitute_branch_vars(self): |
3558 | ++ raise KnownFailure("Known broken test") |
3559 | + base_branch = BaseRecipeBranch("base_url", "1", 0.2) |
3560 | + base_branch.substitute_branch_vars(None, None, None) |
3561 | + self.assertEqual("1", base_branch.deb_version) |
3562 | + |
3563 | |
3564 | === added file 'debian/patches/series' |
3565 | --- debian/patches/series 1970-01-01 00:00:00 +0000 |
3566 | +++ debian/patches/series 2011-06-14 17:23:32 +0000 |
3567 | @@ -0,0 +1,1 @@ |
3568 | +01_broken_test |
3569 | |
3570 | === modified file 'debian/rules' |
3571 | --- debian/rules 2011-06-10 17:46:25 +0000 |
3572 | +++ debian/rules 2011-06-14 17:23:32 +0000 |
3573 | @@ -2,3 +2,13 @@ |
3574 | |
3575 | %: |
3576 | dh $@ --with python2 |
3577 | + |
3578 | +ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) |
3579 | +CONCURRENCY = BZR_CONCURRENCY=$(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) |
3580 | +endif |
3581 | + |
3582 | +ifeq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS))) |
3583 | +override_dh_auto_test: |
3584 | + $(CONCURRENCY) BZR_PLUGINS_AT=builder@$(CURDIR) /usr/bin/bzr selftest \ |
3585 | + --parallel=fork -v -s bp.builder |
3586 | +endif |
3587 | |
3588 | === added directory 'debian/source' |
3589 | === added file 'debian/source/format' |
3590 | --- debian/source/format 1970-01-01 00:00:00 +0000 |
3591 | +++ debian/source/format 2011-06-14 17:23:32 +0000 |
3592 | @@ -0,0 +1,1 @@ |
3593 | +3.0 (quilt) |
3594 | |
3595 | === removed directory 'plugins' |
3596 | === removed symlink 'plugins/builder' |
3597 | === target was u'..' |
3598 | === added file 'ppa.py' |
3599 | --- ppa.py 1970-01-01 00:00:00 +0000 |
3600 | +++ ppa.py 2011-06-14 17:23:32 +0000 |
3601 | @@ -0,0 +1,100 @@ |
3602 | +# ppa support for bzr builder. |
3603 | +# |
3604 | +# Copyright: Canonical Ltd. (C) 2009 |
3605 | +# |
3606 | +# This program is free software: you can redistribute it and/or modify it |
3607 | +# under the terms of the GNU General Public License version 3, as published |
3608 | +# by the Free Software Foundation. |
3609 | + |
3610 | +# This program is distributed in the hope that it will be useful, but |
3611 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
3612 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3613 | +# PURPOSE. See the GNU General Public License for more details. |
3614 | + |
3615 | +# You should have received a copy of the GNU General Public License along |
3616 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
3617 | + |
3618 | +import time |
3619 | + |
3620 | +from bzrlib import ( |
3621 | + errors, |
3622 | + trace, |
3623 | + ) |
3624 | +from launchpadlib.launchpad import Launchpad |
3625 | + |
3626 | + |
3627 | +def get_lp(): |
3628 | + return Launchpad.login_with('bzr-builder', 'production') |
3629 | + |
3630 | + |
3631 | +def watch(owner_name, archive_name, package_name, version): |
3632 | + """Watch a package build. |
3633 | + |
3634 | + :return: True once the package built and published, or False if it fails |
3635 | + or there is a timeout waiting. |
3636 | + """ |
3637 | + version = str(version) |
3638 | + trace.note("Logging into Launchpad") |
3639 | + |
3640 | + launchpad = get_lp() |
3641 | + owner = launchpad.people[owner_name] |
3642 | + archive = owner.getPPAByName(name=archive_name) |
3643 | + end_states = ['FAILEDTOBUILD', 'FULLYBUILT'] |
3644 | + important_arches = ['amd64', 'i386', 'armel'] |
3645 | + trace.note("Waiting for version %s of %s to build." % (version, package_name)) |
3646 | + start = time.time() |
3647 | + while True: |
3648 | + sourceRecords = list(archive.getPublishedSources( |
3649 | + source_name=package_name, version=version)) |
3650 | + if not sourceRecords: |
3651 | + if time.time() - 900 > start: |
3652 | + # Over 15 minutes and no source yet, upload FAIL. |
3653 | + raise errors.BzrCommandError("No source record in %s/%s for " |
3654 | + "package %s=%s after 15 minutes." % (owner_name, |
3655 | + archive_name, package_name, version)) |
3656 | + return False |
3657 | + trace.note("Source not available yet - waiting.") |
3658 | + time.sleep(60) |
3659 | + continue |
3660 | + pkg = sourceRecords[0] |
3661 | + if pkg.status.lower() not in ('published', 'pending'): |
3662 | + trace.note("Package status: %s" % (pkg.status,)) |
3663 | + time.sleep(60) |
3664 | + continue |
3665 | + # FIXME: LP should export this as an attribute. |
3666 | + source_id = pkg.self_link.rsplit('/', 1)[1] |
3667 | + buildSummaries = archive.getBuildSummariesForSourceIds( |
3668 | + source_ids=[source_id])[source_id] |
3669 | + if buildSummaries['status'] in end_states: |
3670 | + break |
3671 | + if buildSummaries['status'] == 'NEEDSBUILD': |
3672 | + # We ignore non-virtual PPA architectures that are sparsely |
3673 | + # supplied with buildds. |
3674 | + missing = [] |
3675 | + for build in buildSummaries['builds']: |
3676 | + arch = build['arch_tag'] |
3677 | + if arch in important_arches: |
3678 | + missing.append(arch) |
3679 | + if not missing: |
3680 | + break |
3681 | + extra = ' on ' + ', '.join(missing) |
3682 | + else: |
3683 | + extra = '' |
3684 | + trace.note("%s is still in %s%s" % (pkg.display_name, |
3685 | + buildSummaries['status'], extra)) |
3686 | + time.sleep(60) |
3687 | + trace.note("%s is now %s" % (pkg.display_name, buildSummaries['status'])) |
3688 | + result = True |
3689 | + if pkg.status.lower() != 'published': |
3690 | + result = False # should this perhaps keep waiting? |
3691 | + if buildSummaries['status'] != 'FULLYBUILT': |
3692 | + if buildSummaries['status'] == 'NEEDSBUILD': |
3693 | + # We're stopping early cause the important_arches are built. |
3694 | + builds = pkg.getBuilds() |
3695 | + for build in builds: |
3696 | + if build.arch_tag in important_arches: |
3697 | + if build.buildstate != 'Successfully built': |
3698 | + result = False |
3699 | + else: |
3700 | + result = False |
3701 | + return result |
3702 | |
3703 | === removed file 'ppa.py' |
3704 | --- ppa.py 2010-10-21 21:17:28 +0000 |
3705 | +++ ppa.py 1970-01-01 00:00:00 +0000 |
3706 | @@ -1,124 +0,0 @@ |
3707 | -# ppa support for bzr builder. |
3708 | -# |
3709 | -# Copyright: Canonical Ltd. (C) 2009 |
3710 | -# |
3711 | -# This program is free software: you can redistribute it and/or modify it |
3712 | -# under the terms of the GNU General Public License version 3, as published |
3713 | -# by the Free Software Foundation. |
3714 | - |
3715 | -# This program is distributed in the hope that it will be useful, but |
3716 | -# WITHOUT ANY WARRANTY; without even the implied warranties of |
3717 | -# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3718 | -# PURPOSE. See the GNU General Public License for more details. |
3719 | - |
3720 | -# You should have received a copy of the GNU General Public License along |
3721 | -# with this program. If not, see <http://www.gnu.org/licenses/>. |
3722 | - |
3723 | -import os |
3724 | -import time |
3725 | - |
3726 | - |
3727 | -from launchpadlib.launchpad import ( |
3728 | - Launchpad, |
3729 | - EDGE_SERVICE_ROOT, |
3730 | - ) |
3731 | -from launchpadlib.credentials import Credentials |
3732 | - |
3733 | -from bzrlib import ( |
3734 | - errors, |
3735 | - trace, |
3736 | - ) |
3737 | - |
3738 | - |
3739 | -def get_lp(): |
3740 | - credentials = Credentials() |
3741 | - oauth_file = os.path.expanduser('~/.cache/launchpadlib/bzr-builder') |
3742 | - if os.path.exists(oauth_file): |
3743 | - f = open(oauth_file) |
3744 | - try: |
3745 | - credentials.load(f) |
3746 | - finally: |
3747 | - f.close() |
3748 | - launchpad = Launchpad(credentials, EDGE_SERVICE_ROOT) |
3749 | - else: |
3750 | - launchpad = Launchpad.get_token_and_login('bzr-builder', |
3751 | - EDGE_SERVICE_ROOT) |
3752 | - f = open(oauth_file, 'wb') |
3753 | - try: |
3754 | - launchpad.credentials.save(f) |
3755 | - finally: |
3756 | - f.close() |
3757 | - return launchpad |
3758 | - |
3759 | - |
3760 | -def watch(owner_name, archive_name, package_name, version): |
3761 | - """Watch a package build. |
3762 | - |
3763 | - :return: True once the package built and published, or False if it fails |
3764 | - or there is a timeout waiting. |
3765 | - """ |
3766 | - version = str(version) |
3767 | - trace.note("Logging into Launchpad") |
3768 | - |
3769 | - launchpad = get_lp() |
3770 | - owner = launchpad.people[owner_name] |
3771 | - archive = owner.getPPAByName(name=archive_name) |
3772 | - end_states = ['FAILEDTOBUILD', 'FULLYBUILT'] |
3773 | - important_arches = ['amd64', 'i386', 'armel'] |
3774 | - trace.note("Waiting for version %s of %s to build." % (version, package_name)) |
3775 | - start = time.time() |
3776 | - while True: |
3777 | - sourceRecords = list(archive.getPublishedSources( |
3778 | - source_name=package_name, version=version)) |
3779 | - if not sourceRecords: |
3780 | - if time.time() - 900 > start: |
3781 | - # Over 15 minutes and no source yet, upload FAIL. |
3782 | - raise errors.BzrCommandError("No source record in %s/%s for " |
3783 | - "package %s=%s after 15 minutes." % (owner_name, |
3784 | - archive_name, package_name, version)) |
3785 | - return False |
3786 | - trace.note("Source not available yet - waiting.") |
3787 | - time.sleep(60) |
3788 | - continue |
3789 | - pkg = sourceRecords[0] |
3790 | - if pkg.status.lower() not in ('published', 'pending'): |
3791 | - trace.note("Package status: %s" % (pkg.status,)) |
3792 | - time.sleep(60) |
3793 | - continue |
3794 | - # FIXME: LP should export this as an attribute. |
3795 | - source_id = pkg.self_link.rsplit('/', 1)[1] |
3796 | - buildSummaries = archive.getBuildSummariesForSourceIds( |
3797 | - source_ids=[source_id])[source_id] |
3798 | - if buildSummaries['status'] in end_states: |
3799 | - break |
3800 | - if buildSummaries['status'] == 'NEEDSBUILD': |
3801 | - # We ignore non-virtual PPA architectures that are sparsely |
3802 | - # supplied with buildds. |
3803 | - missing = [] |
3804 | - for build in buildSummaries['builds']: |
3805 | - arch = build['arch_tag'] |
3806 | - if arch in important_arches: |
3807 | - missing.append(arch) |
3808 | - if not missing: |
3809 | - break |
3810 | - extra = ' on ' + ', '.join(missing) |
3811 | - else: |
3812 | - extra = '' |
3813 | - trace.note("%s is still in %s%s" % (pkg.display_name, |
3814 | - buildSummaries['status'], extra)) |
3815 | - time.sleep(60) |
3816 | - trace.note("%s is now %s" % (pkg.display_name, buildSummaries['status'])) |
3817 | - result = True |
3818 | - if pkg.status.lower() != 'published': |
3819 | - result = False # should this perhaps keep waiting? |
3820 | - if buildSummaries['status'] != 'FULLYBUILT': |
3821 | - if buildSummaries['status'] == 'NEEDSBUILD': |
3822 | - # We're stopping early cause the important_arches are built. |
3823 | - builds = pkg.getBuilds() |
3824 | - for build in builds: |
3825 | - if build.arch_tag in important_arches: |
3826 | - if build.buildstate != 'Successfully built': |
3827 | - result = False |
3828 | - else: |
3829 | - result = False |
3830 | - return result |
3831 | |
3832 | === added file 'recipe.py' |
3833 | --- recipe.py 1970-01-01 00:00:00 +0000 |
3834 | +++ recipe.py 2011-06-14 17:23:32 +0000 |
3835 | @@ -0,0 +1,1535 @@ |
3836 | +# bzr-builder: a bzr plugin to constuct trees based on recipes |
3837 | +# Copyright 2009 Canonical Ltd. |
3838 | + |
3839 | +# This program is free software: you can redistribute it and/or modify it |
3840 | +# under the terms of the GNU General Public License version 3, as published |
3841 | +# by the Free Software Foundation. |
3842 | + |
3843 | +# This program is distributed in the hope that it will be useful, but |
3844 | +# WITHOUT ANY WARRANTY; without even the implied warranties of |
3845 | +# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
3846 | +# PURPOSE. See the GNU General Public License for more details. |
3847 | + |
3848 | +# You should have received a copy of the GNU General Public License along |
3849 | +# with this program. If not, see <http://www.gnu.org/licenses/>. |
3850 | + |
3851 | +import os |
3852 | +import signal |
3853 | +import subprocess |
3854 | +import time |
3855 | + |
3856 | +from bzrlib import ( |
3857 | + branch as _mod_branch, |
3858 | + bzrdir, |
3859 | + errors, |
3860 | + lazy_regex, |
3861 | + merge, |
3862 | + revision, |
3863 | + revisionspec, |
3864 | + tag, |
3865 | + trace, |
3866 | + transport, |
3867 | + urlutils, |
3868 | + version_info as bzr_version_info, |
3869 | + ) |
3870 | + |
3871 | +try: |
3872 | + from bzrlib.errors import NoWhoami |
3873 | +except ImportError: |
3874 | + NoWhoami = object() |
3875 | + |
3876 | + |
3877 | +try: |
3878 | + from debian import changelog |
3879 | +except ImportError: |
3880 | + from debian_bundle import changelog |
3881 | + |
3882 | +try: |
3883 | + MergeIntoMerger = merge.MergeIntoMerger |
3884 | +except (AttributeError, NameError): |
3885 | + from bzrlib.plugins.builder.bzrlibbackports import MergeIntoMerger |
3886 | + |
3887 | + |
3888 | +def subprocess_setup(): |
3889 | + signal.signal(signal.SIGPIPE, signal.SIG_DFL) |
3890 | + |
3891 | + |
3892 | +MERGE_INSTRUCTION = "merge" |
3893 | +NEST_PART_INSTRUCTION = "nest-part" |
3894 | +NEST_INSTRUCTION = "nest" |
3895 | +RUN_INSTRUCTION = "run" |
3896 | +USAGE = { |
3897 | + MERGE_INSTRUCTION: 'merge NAME BRANCH [REVISION]', |
3898 | + NEST_INSTRUCTION: 'nest NAME BRANCH TARGET-DIR [REVISION]', |
3899 | + NEST_PART_INSTRUCTION: |
3900 | + 'nest-part NAME BRANCH SUBDIR [TARGET-DIR [REVISION]]', |
3901 | + RUN_INSTRUCTION: 'run COMMAND', |
3902 | + } |
3903 | + |
3904 | +SAFE_INSTRUCTIONS = [ |
3905 | + MERGE_INSTRUCTION, NEST_PART_INSTRUCTION, NEST_INSTRUCTION] |
3906 | + |
3907 | + |
3908 | +class SubstitutionUnavailable(errors.BzrError): |
3909 | + _fmt = """Substitution for %(name)s not available: %(reason)s""" |
3910 | + |
3911 | + def __init__(self, name, reason): |
3912 | + errors.BzrError.__init__(self, name=name, reason=reason) |
3913 | + |
3914 | + |
3915 | +class SubstitutionVariable(object): |
3916 | + """A substitution variable for a version string.""" |
3917 | + |
3918 | + def replace(self, value): |
3919 | + """Replace name with value.""" |
3920 | + raise NotImplementedError(self.replace) |
3921 | + |
3922 | + |
3923 | +class SimpleSubstitutionVariable(SubstitutionVariable): |
3924 | + |
3925 | + name = None |
3926 | + |
3927 | + def replace(self, value): |
3928 | + if not self.name in value: |
3929 | + return value |
3930 | + return value.replace(self.name, self.get()) |
3931 | + |
3932 | + def get(self): |
3933 | + raise NotImplementedError(self.value) |
3934 | + |
3935 | + |
3936 | +class BranchSubstitutionVariable(SimpleSubstitutionVariable): |
3937 | + |
3938 | + basename = None |
3939 | + |
3940 | + def __init__(self, branch_name=None): |
3941 | + super(BranchSubstitutionVariable, self).__init__() |
3942 | + self.branch_name = branch_name |
3943 | + |
3944 | + @classmethod |
3945 | + def determine_name(cls, branch_name): |
3946 | + if branch_name is None: |
3947 | + return "{%s}" % cls.basename |
3948 | + else: |
3949 | + return "{%s:%s}" % (cls.basename, branch_name) |
3950 | + |
3951 | + @property |
3952 | + def name(self): |
3953 | + return self.determine_name(self.branch_name) |
3954 | + |
3955 | + |
3956 | +class TimeVariable(SimpleSubstitutionVariable): |
3957 | + |
3958 | + name = "{time}" |
3959 | + |
3960 | + def __init__(self, time): |
3961 | + self._time = time |
3962 | + |
3963 | + def get(self): |
3964 | + return self._time.strftime("%Y%m%d%H%M") |
3965 | + |
3966 | + |
3967 | +class DateVariable(SimpleSubstitutionVariable): |
3968 | + |
3969 | + name = "{date}" |
3970 | + |
3971 | + def __init__(self, time): |
3972 | + self._time = time |
3973 | + |
3974 | + def get(self): |
3975 | + return self._time.strftime("%Y%m%d") |
3976 | + |
3977 | + |
3978 | +class DebUpstreamVariable(BranchSubstitutionVariable): |
3979 | + |
3980 | + basename = "debupstream" |
3981 | + |
3982 | + def __init__(self, branch_name, version): |
3983 | + super(DebUpstreamVariable, self).__init__(branch_name) |
3984 | + self._version = version |
3985 | + |
3986 | + @classmethod |
3987 | + def from_changelog(cls, branch_name, changelog): |
3988 | + if len(changelog._blocks) > 0: |
3989 | + return cls(branch_name, changelog._blocks[0].version) |
3990 | + else: |
3991 | + return cls(branch_name, None) |
3992 | + |
3993 | + def get(self): |
3994 | + if self._version is None: |
3995 | + raise SubstitutionUnavailable(self.name, |
3996 | + "No previous changelog to take the upstream version from") |
3997 | + # Should we include the epoch? |
3998 | + return self._version.upstream_version |
3999 | + |
4000 | + |
4001 | +class DebVersionVariable(BranchSubstitutionVariable): |
4002 | + |
4003 | + basename = "debversion" |
4004 | + |
4005 | + def __init__(self, branch_name, version): |
4006 | + super(DebVersionVariable, self).__init__(branch_name) |
4007 | + self._version = version |
4008 | + |
4009 | + @classmethod |
4010 | + def from_changelog(cls, branch_name, changelog): |
4011 | + if len(changelog._blocks) > 0: |
4012 | + return cls(branch_name, changelog._blocks[0].version) |
4013 | + else: |
4014 | + return cls(branch_name, None) |
4015 | + |
4016 | + def get(self): |
4017 | + if self._version is None: |
4018 | + raise SubstitutionUnavailable(self.name, |
4019 | + "No previous changelog to take the version from") |
4020 | + return str(self._version) |
4021 | + |
4022 | + |
4023 | +class DebUpstreamBaseVariable(DebUpstreamVariable): |
4024 | + |
4025 | + basename = "{debupstream-base}" |
4026 | + version_regex = lazy_regex.lazy_compile(r'([~+])(svn[0-9]+|bzr[0-9]+|git[0-9a-f]+)') |
4027 | + |
4028 | + def get(self): |
4029 | + version = super(DebUpstreamBaseVariable, self).get() |
4030 | + version = self.version_regex.sub("\\1", version) |
4031 | + if version[-1] not in ("~", "+"): |
4032 | + version += "+" |
4033 | + return version |
4034 | + |
4035 | + |
4036 | +class RevisionVariable(BranchSubstitutionVariable): |
4037 | + |
4038 | + def __init__(self, branch_name, branch, revid): |
4039 | + super(RevisionVariable, self).__init__(branch_name) |
4040 | + self.branch = branch |
4041 | + self.revid = revid |
4042 | + |
4043 | + |
4044 | +class RevnoVariable(RevisionVariable): |
4045 | + |
4046 | + basename = "revno" |
4047 | + |
4048 | + def get_revno(self): |
4049 | + try: |
4050 | + revno = self.branch.revision_id_to_revno(self.revid) |
4051 | + return str(revno) |
4052 | + except errors.NoSuchRevision: |
4053 | + # We need to load and use the full revno map after all |
4054 | + result = self.branch.get_revision_id_to_revno_map().get( |
4055 | + self.revid) |
4056 | + if result is None: |
4057 | + return result |
4058 | + return ".".join(result) |
4059 | + |
4060 | + def get(self): |
4061 | + revno = self.get_revno() |
4062 | + if revno is None: |
4063 | + raise errors.BzrCommandError("Can't substitute revno of " |
4064 | + "branch %s in deb-version, as it's revno can't be " |
4065 | + "determined" % revno) |
4066 | + return revno |
4067 | + |
4068 | + |
4069 | +class RevtimeVariable(RevisionVariable): |
4070 | + |
4071 | + basename = "revtime" |
4072 | + |
4073 | + def get(self): |
4074 | + rev = self.branch.repository.get_revision(self.revid) |
4075 | + return time.strftime("%Y%m%d%H%M", time.gmtime(rev.timestamp)) |
4076 | + |
4077 | + |
4078 | +class RevdateVariable(RevisionVariable): |
4079 | + |
4080 | + basename = "revdate" |
4081 | + |
4082 | + def get(self): |
4083 | + rev = self.branch.repository.get_revision(self.revid) |
4084 | + return time.strftime("%Y%m%d", time.gmtime(rev.timestamp)) |
4085 | + |
4086 | + |
4087 | +def extract_svn_revnum(rev): |
4088 | + try: |
4089 | + foreign_revid = rev.foreign_revid |
4090 | + except AttributeError: |
4091 | + try: |
4092 | + (mapping_name, uuid, bp, srevnum) = rev.revision_id.split(":", 3) |
4093 | + except ValueError: |
4094 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4095 | + if not mapping_name.startswith("svn-"): |
4096 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4097 | + return int(srevnum) |
4098 | + else: |
4099 | + if rev.mapping.vcs.abbreviation == "svn": |
4100 | + return foreign_revid[2] |
4101 | + else: |
4102 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4103 | + |
4104 | + |
4105 | +class SubversionRevnumVariable(RevisionVariable): |
4106 | + |
4107 | + basename = "svn-revno" |
4108 | + |
4109 | + def get(self): |
4110 | + rev = self.branch.repository.get_revision(self.revid) |
4111 | + try: |
4112 | + revno = extract_svn_revnum(rev) |
4113 | + except errors.InvalidRevisionId: |
4114 | + raise errors.BzrCommandError("unable to expand %s for %r in %r: " |
4115 | + "not a Subversion revision" % ( |
4116 | + self.name, self.revid, self.branch)) |
4117 | + return str(revno) |
4118 | + |
4119 | + |
4120 | +def extract_git_foreign_revid(rev): |
4121 | + try: |
4122 | + foreign_revid = rev.foreign_revid |
4123 | + except AttributeError: |
4124 | + try: |
4125 | + (mapping_name, foreign_revid) = rev.revision_id.split(":", 1) |
4126 | + except ValueError: |
4127 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4128 | + if not mapping_name.startswith("git-"): |
4129 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4130 | + return foreign_revid |
4131 | + else: |
4132 | + if rev.mapping.vcs.abbreviation == "git": |
4133 | + return foreign_revid |
4134 | + else: |
4135 | + raise errors.InvalidRevisionId(rev.revision_id, None) |
4136 | + |
4137 | + |
4138 | +class GitCommitVariable(RevisionVariable): |
4139 | + |
4140 | + basename = "git-commit" |
4141 | + |
4142 | + def get(self): |
4143 | + rev = self.branch.repository.get_revision(self.revid) |
4144 | + try: |
4145 | + commit_sha = extract_git_foreign_revid(rev) |
4146 | + except errors.InvalidRevisionId: |
4147 | + raise errors.BzrCommandError("unable to expand %s for %r in %r: " |
4148 | + "not a Git revision" % ( |
4149 | + self.name, self.revid, self.branch)) |
4150 | + return commit_sha[:7] |
4151 | + |
4152 | + |
4153 | +class LatestTagVariable(RevisionVariable): |
4154 | + |
4155 | + basename = "latest-tag" |
4156 | + |
4157 | + def get(self): |
4158 | + reverse_tag_dict = self.branch.tags.get_reverse_tag_dict() |
4159 | + for revid in self.branch.repository.iter_reverse_revision_history(self.revid): |
4160 | + if revid in reverse_tag_dict: |
4161 | + return reverse_tag_dict[revid][0] |
4162 | + else: |
4163 | + raise errors.BzrCommandError("No tags set on branch %s mainline" % |
4164 | + self.branch_name) |
4165 | + |
4166 | + |
4167 | +ok_to_preserve = [DebUpstreamVariable, DebUpstreamBaseVariable, |
4168 | + DebVersionVariable] |
4169 | +# The variables that don't require substitution in their name |
4170 | +simple_vars = [TimeVariable, DateVariable] |
4171 | +branch_vars = [RevnoVariable, SubversionRevnumVariable, |
4172 | + GitCommitVariable, LatestTagVariable, DebVersionVariable, |
4173 | + DebUpstreamBaseVariable, DebUpstreamVariable, RevdateVariable, |
4174 | + RevtimeVariable] |
4175 | + |
4176 | + |
4177 | +def check_expanded_deb_version(base_branch): |
4178 | + checked_version = base_branch.deb_version |
4179 | + if checked_version is None: |
4180 | + return |
4181 | + for token in ok_to_preserve: |
4182 | + if issubclass(token, BranchSubstitutionVariable): |
4183 | + for name in base_branch.list_branch_names(): |
4184 | + checked_version = checked_version.replace( |
4185 | + token.determine_name(name), "") |
4186 | + checked_version = checked_version.replace( |
4187 | + token.determine_name(None), "") |
4188 | + else: |
4189 | + checked_version = checked_version.replace( |
4190 | + token.name, "") |
4191 | + if "{" in checked_version: |
4192 | + available_tokens = [var.name for var in simple_vars] |
4193 | + for var_kls in branch_vars: |
4194 | + for name in base_branch.list_branch_names(): |
4195 | + available_tokens.append(var_kls.determine_name(name)) |
4196 | + available_tokens.append(var_kls.determine_name(None)) |
4197 | + raise errors.BzrCommandError("deb-version not fully " |
4198 | + "expanded: %s. Valid substitutions are: %s" |
4199 | + % (base_branch.deb_version, available_tokens)) |
4200 | + |
4201 | + |
4202 | +class CommandFailedError(errors.BzrError): |
4203 | + |
4204 | + _fmt = "The command \"%(command)s\" failed." |
4205 | + |
4206 | + def __init__(self, command): |
4207 | + super(CommandFailedError, self).__init__() |
4208 | + self.command = command |
4209 | + |
4210 | + |
4211 | +def ensure_basedir(to_transport): |
4212 | + """Ensure that the basedir of to_transport exists. |
4213 | + |
4214 | + It is allowed to already exist currently, to reuse directories. |
4215 | + |
4216 | + :param to_transport: The Transport to ensure that the basedir of |
4217 | + exists. |
4218 | + """ |
4219 | + try: |
4220 | + to_transport.mkdir('.') |
4221 | + except errors.FileExists: |
4222 | + pass |
4223 | + except errors.NoSuchFile: |
4224 | + raise errors.BzrCommandError('Parent of "%s" does not exist.' |
4225 | + % to_transport.base) |
4226 | + |
4227 | + |
4228 | +def pull_or_branch(tree_to, br_to, br_from, to_transport, revision_id, |
4229 | + accelerator_tree=None, possible_transports=None): |
4230 | + """Either pull or branch from a branch. |
4231 | + |
4232 | + Depending on whether the target branch and tree exist already this |
4233 | + will either pull from the source branch, or branch from it. If it |
4234 | + returns this function will return a branch and tree for the target, |
4235 | + after creating either if necessary. |
4236 | + |
4237 | + :param tree_to: The WorkingTree to pull in to, or None. If not None then |
4238 | + br_to must not be None. |
4239 | + :param br_to: The Branch to pull in to, or None to branch. |
4240 | + :param br_from: The Branch to pull/branch from. |
4241 | + :param to_transport: A Transport for the root of the target. |
4242 | + :param revision_id: the revision id to pull/branch. |
4243 | + :param accelerator_tree: A tree to take contents from that is faster than |
4244 | + extracting from br_from, or None. |
4245 | + :param possible_transports: A list of transports that can be reused, or |
4246 | + None. |
4247 | + :return: A tuple of (target tree, target branch) which are the updated |
4248 | + tree and branch, created if necessary. They are locked, and you |
4249 | + should use these instead of tree_to and br_to if they were passed |
4250 | + in, including for unlocking. |
4251 | + """ |
4252 | + created_tree_to = False |
4253 | + created_br_to = False |
4254 | + if br_to is None: |
4255 | + # We do a "branch" |
4256 | + ensure_basedir(to_transport) |
4257 | + dir = br_from.bzrdir.sprout(to_transport.base, revision_id, |
4258 | + possible_transports=possible_transports, |
4259 | + accelerator_tree=accelerator_tree, |
4260 | + source_branch=br_from, |
4261 | + stacked=(bzr_version_info >= (2, 3, 0))) |
4262 | + try: |
4263 | + tree_to = dir.open_workingtree() |
4264 | + except errors.NoWorkingTree: |
4265 | + # There's no working tree, so it's probably in a no-trees repo, |
4266 | + # but the whole point of this is to create trees, so we should |
4267 | + # forcibly create one. |
4268 | + tree_to = dir.create_workingtree() |
4269 | + br_to = tree_to.branch |
4270 | + created_br_to = True |
4271 | + tag._merge_tags_if_possible(br_from, br_to) |
4272 | + created_tree_to = True |
4273 | + else: |
4274 | + # We do a "pull" |
4275 | + if tree_to is not None: |
4276 | + # FIXME: should these pulls overwrite? |
4277 | + tree_to.pull(br_from, stop_revision=revision_id, |
4278 | + possible_transports=possible_transports) |
4279 | + else: |
4280 | + br_to.pull(br_from, stop_revision=revision_id, |
4281 | + possible_transports=possible_transports) |
4282 | + tree_to = br_to.bzrdir.create_workingtree() |
4283 | + # Ugh, we have to assume that the caller replaces their reference |
4284 | + # to the branch with the one we return. |
4285 | + br_to.unlock() |
4286 | + br_to = tree_to.branch |
4287 | + br_to.lock_write() |
4288 | + created_tree_to = True |
4289 | + if created_tree_to: |
4290 | + tree_to.lock_write() |
4291 | + try: |
4292 | + if created_br_to: |
4293 | + br_to.lock_write() |
4294 | + try: |
4295 | + conflicts = tree_to.conflicts() |
4296 | + if len(conflicts) > 0: |
4297 | + # FIXME: better reporting |
4298 | + raise errors.BzrCommandError("Conflicts... aborting.") |
4299 | + except: |
4300 | + if created_br_to: |
4301 | + br_to.unlock() |
4302 | + raise |
4303 | + except: |
4304 | + if created_tree_to: |
4305 | + tree_to.unlock() |
4306 | + raise |
4307 | + return tree_to, br_to |
4308 | + |
4309 | + |
4310 | +def merge_branch(child_branch, tree_to, br_to, possible_transports=None): |
4311 | + """Merge the branch specified by child_branch. |
4312 | + |
4313 | + :param child_branch: the RecipeBranch to retrieve the branch and revision to |
4314 | + merge from. |
4315 | + :param tree_to: the WorkingTree to merge in to. |
4316 | + :param br_to: the Branch to merge in to. |
4317 | + """ |
4318 | + if child_branch.branch is None: |
4319 | + child_branch.branch = _mod_branch.Branch.open(child_branch.url, |
4320 | + possible_transports=possible_transports) |
4321 | + child_branch.branch.lock_read() |
4322 | + try: |
4323 | + tag._merge_tags_if_possible(child_branch.branch, br_to) |
4324 | + if child_branch.revspec is not None: |
4325 | + merge_revspec = revisionspec.RevisionSpec.from_string( |
4326 | + child_branch.revspec) |
4327 | + try: |
4328 | + merge_revid = merge_revspec.as_revision_id( |
4329 | + child_branch.branch) |
4330 | + except errors.InvalidRevisionSpec, e: |
4331 | + # Give the user a hint if they didn't mean to speciy |
4332 | + # a revspec. |
4333 | + e.extra = (". Did you not mean to specify a revspec " |
4334 | + "at the end of the merge line?") |
4335 | + raise e |
4336 | + else: |
4337 | + merge_revid = child_branch.branch.last_revision() |
4338 | + child_branch.revid = merge_revid |
4339 | + try: |
4340 | + merger = merge.Merger.from_revision_ids(None, tree_to, merge_revid, |
4341 | + other_branch=child_branch.branch, tree_branch=br_to) |
4342 | + except errors.UnrelatedBranches: |
4343 | + # Let's just try and hope for the best. |
4344 | + merger = merge.Merger.from_revision_ids(None, tree_to, merge_revid, |
4345 | + other_branch=child_branch.branch, tree_branch=br_to, |
4346 | + base=revision.NULL_REVISION) |
4347 | + merger.merge_type = merge.Merge3Merger |
4348 | + if (merger.base_rev_id == merger.other_rev_id and |
4349 | + merger.other_rev_id is not None): |
4350 | + # Nothing to do. |
4351 | + return |
4352 | + conflict_count = merger.do_merge() |
4353 | + |
4354 | + merger.set_pending() |
4355 | + if conflict_count: |
4356 | + # FIXME: better reporting |
4357 | + raise errors.BzrCommandError("Conflicts from merge") |
4358 | + config = br_to.get_config() |
4359 | + try: |
4360 | + committer = config.username() |
4361 | + except NoWhoami: |
4362 | + committer = "bzr-builder <nobody@example.com>" |
4363 | + tree_to.commit("Merge %s" % |
4364 | + urlutils.unescape_for_display(child_branch.url, 'utf-8'), |
4365 | + committer=committer) |
4366 | + finally: |
4367 | + child_branch.branch.unlock() |
4368 | + |
4369 | + |
4370 | +def nest_part_branch(child_branch, tree_to, br_to, subpath, target_subdir=None): |
4371 | + """Merge the branch subdirectory specified by child_branch. |
4372 | + |
4373 | + :param child_branch: the RecipeBranch to retrieve the branch and revision to |
4374 | + merge from. |
4375 | + :param tree_to: the WorkingTree to merge in to. |
4376 | + :param br_to: the Branch to merge in to. |
4377 | + :param subpath: only merge files from branch that are from this path. |
4378 | + e.g. subpath='/debian' will only merge changes from that directory. |
4379 | + :param target_subdir: (optional) directory in target to merge that |
4380 | + subpath into. Defaults to basename of subpath. |
4381 | + """ |
4382 | + child_branch.branch = _mod_branch.Branch.open(child_branch.url) |
4383 | + child_branch.branch.lock_read() |
4384 | + try: |
4385 | + child_branch.resolve_revision_id() |
4386 | + other_tree = child_branch.branch.basis_tree() |
4387 | + other_tree.lock_read() |
4388 | + try: |
4389 | + if target_subdir is None: |
4390 | + target_subdir = os.path.basename(subpath) |
4391 | + merger = MergeIntoMerger(this_tree=tree_to, other_tree=other_tree, |
4392 | + other_branch=child_branch.branch, target_subdir=target_subdir, |
4393 | + source_subpath=subpath, other_rev_id=child_branch.revid) |
4394 | + merger.set_base_revision(revision.NULL_REVISION, child_branch.branch) |
4395 | + conflict_count = merger.do_merge() |
4396 | + merger.set_pending() |
4397 | + finally: |
4398 | + other_tree.unlock() |
4399 | + finally: |
4400 | + child_branch.branch.unlock() |
4401 | + |
4402 | + if conflict_count: |
4403 | + # FIXME: better reporting |
4404 | + raise errors.BzrCommandError("Conflicts from merge") |
4405 | + tree_to.commit("Merge %s of %s" % |
4406 | + (subpath, urlutils.unescape_for_display(child_branch.url, 'utf-8'))) |
4407 | + |
4408 | + |
4409 | +def update_branch(base_branch, tree_to, br_to, to_transport, |
4410 | + possible_transports=None): |
4411 | + if base_branch.branch is None: |
4412 | + base_branch.branch = _mod_branch.Branch.open(base_branch.url, |
4413 | + possible_transports=possible_transports) |
4414 | + base_branch.branch.lock_read() |
4415 | + try: |
4416 | + base_branch.resolve_revision_id() |
4417 | + tree_to, br_to = pull_or_branch(tree_to, br_to, base_branch.branch, |
4418 | + to_transport, base_branch.revid, |
4419 | + possible_transports=possible_transports) |
4420 | + finally: |
4421 | + base_branch.branch.unlock() |
4422 | + return tree_to, br_to |
4423 | + |
4424 | + |
4425 | +def _resolve_revisions_recurse(new_branch, substitute_branch_vars, |
4426 | + if_changed_from=None): |
4427 | + changed = False |
4428 | + new_branch.branch = _mod_branch.Branch.open(new_branch.url) |
4429 | + new_branch.branch.lock_read() |
4430 | + try: |
4431 | + new_branch.resolve_revision_id() |
4432 | + substitute_branch_vars(new_branch.name, new_branch.branch, new_branch.revid) |
4433 | + if (if_changed_from is not None |
4434 | + and (new_branch.revspec is not None |
4435 | + or if_changed_from.revspec is not None)): |
4436 | + if if_changed_from.revspec is not None: |
4437 | + changed_revspec = revisionspec.RevisionSpec.from_string( |
4438 | + if_changed_from.revspec) |
4439 | + changed_revision_id = changed_revspec.as_revision_id( |
4440 | + new_branch.branch) |
4441 | + else: |
4442 | + changed_revision_id = new_branch.branch.last_revision() |
4443 | + if new_branch.revid != changed_revision_id: |
4444 | + changed = True |
4445 | + for index, instruction in enumerate(new_branch.child_branches): |
4446 | + child_branch = instruction.recipe_branch |
4447 | + if_changed_child = None |
4448 | + if if_changed_from is not None: |
4449 | + if_changed_child = if_changed_from.child_branches[index].recipe_branch |
4450 | + if child_branch is not None: |
4451 | + child_changed = _resolve_revisions_recurse(child_branch, |
4452 | + substitute_branch_vars, |
4453 | + if_changed_from=if_changed_child) |
4454 | + if child_changed: |
4455 | + changed = child_changed |
4456 | + return changed |
4457 | + finally: |
4458 | + new_branch.branch.unlock() |
4459 | + |
4460 | + |
4461 | +def resolve_revisions(base_branch, if_changed_from=None): |
4462 | + """Resolve all the unknowns in base_branch. |
4463 | + |
4464 | + This walks the RecipeBranch and substitutes in revnos and deb_version. |
4465 | + |
4466 | + If if_changed_from is not None then it should be a second RecipeBranch |
4467 | + to compare base_branch against. If the shape, or the revision ids differ |
4468 | + then the function will return True. |
4469 | + |
4470 | + :param base_branch: the RecipeBranch we plan to build. |
4471 | + :param if_changed_from: the RecipeBranch that we want to compare against. |
4472 | + :return: False if if_changed_from is not None, and the shape and revisions |
4473 | + of the two branches don't differ. True otherwise. |
4474 | + """ |
4475 | + changed = False |
4476 | + if if_changed_from is not None: |
4477 | + changed = base_branch.different_shape_to(if_changed_from) |
4478 | + if_changed_from_revisions = if_changed_from |
4479 | + if changed: |
4480 | + if_changed_from_revisions = None |
4481 | + changed_revisions = _resolve_revisions_recurse(base_branch, |
4482 | + base_branch.substitute_branch_vars, |
4483 | + if_changed_from=if_changed_from_revisions) |
4484 | + if not changed: |
4485 | + changed = changed_revisions |
4486 | + check_expanded_deb_version(base_branch) |
4487 | + if if_changed_from is not None and not changed: |
4488 | + return False |
4489 | + return True |
4490 | + |
4491 | + |
4492 | +def _build_inner_tree(base_branch, target_path, possible_transports=None): |
4493 | + revision_of = "" |
4494 | + if base_branch.revspec is not None: |
4495 | + revision_of = "revision '%s' of " % base_branch.revspec |
4496 | + trace.note("Retrieving %s'%s' to put at '%s'." |
4497 | + % (revision_of, base_branch.url, target_path)) |
4498 | + to_transport = transport.get_transport(target_path, |
4499 | + possible_transports=possible_transports) |
4500 | + try: |
4501 | + tree_to, br_to = bzrdir.BzrDir.open_tree_or_branch(target_path) |
4502 | + # Should we commit any changes in the tree here? If we don't |
4503 | + # then they will get folded up in to the first merge. |
4504 | + except errors.NotBranchError: |
4505 | + tree_to = None |
4506 | + br_to = None |
4507 | + if tree_to is not None: |
4508 | + tree_to.lock_write() |
4509 | + try: |
4510 | + if br_to is not None: |
4511 | + br_to.lock_write() |
4512 | + try: |
4513 | + tree_to, br_to = update_branch(base_branch, tree_to, br_to, |
4514 | + to_transport, possible_transports=possible_transports) |
4515 | + for instruction in base_branch.child_branches: |
4516 | + instruction.apply(target_path, tree_to, br_to) |
4517 | + finally: |
4518 | + # Is this ok if tree_to is created by pull_or_branch? |
4519 | + if br_to is not None: |
4520 | + br_to.unlock() |
4521 | + finally: |
4522 | + if tree_to is not None: |
4523 | + tree_to.unlock() |
4524 | + |
4525 | + |
4526 | +def build_tree(base_branch, target_path, possible_transports=None): |
4527 | + """Build the RecipeBranch at a path. |
4528 | + |
4529 | + Follow the instructions embodied in RecipeBranch and build a tree |
4530 | + based on them rooted at target_path. If target_path exists and |
4531 | + is the root of the branch then the branch will be updated based on |
4532 | + what the RecipeBranch requires. |
4533 | + |
4534 | + :param base_branch: a RecipeBranch to build. |
4535 | + :param target_path: the path to the base of the desired output. |
4536 | + """ |
4537 | + trace.note("Building tree.") |
4538 | + _build_inner_tree(base_branch, target_path, |
4539 | + possible_transports=possible_transports) |
4540 | + |
4541 | + |
4542 | +class ChildBranch(object): |
4543 | + """A child branch in a recipe. |
4544 | + |
4545 | + If the nest path is not None it is the path relative to the recipe branch |
4546 | + where the child branch should be placed. If it is None then the child |
4547 | + branch should be merged instead of nested. |
4548 | + """ |
4549 | + |
4550 | + can_have_children = False |
4551 | + |
4552 | + def __init__(self, recipe_branch, nest_path=None): |
4553 | + self.recipe_branch = recipe_branch |
4554 | + self.nest_path = nest_path |
4555 | + |
4556 | + def apply(self, target_path, tree_to, br_to, possible_transports=None): |
4557 | + raise NotImplementedError(self.apply) |
4558 | + |
4559 | + def as_tuple(self): |
4560 | + return (self.recipe_branch, self.nest_path) |
4561 | + |
4562 | + def _get_revid_part(self): |
4563 | + if self.recipe_branch.revid is not None: |
4564 | + revid_part = " revid:%s" % self.recipe_branch.revid |
4565 | + elif self.recipe_branch.revspec is not None: |
4566 | + revid_part = " %s" % self.recipe_branch.revspec |
4567 | + else: |
4568 | + revid_part = "" |
4569 | + return revid_part |
4570 | + |
4571 | + def __repr__(self): |
4572 | + return "<%s %r>" % (self.__class__.__name__, self.nest_path) |
4573 | + |
4574 | + |
4575 | +class CommandInstruction(ChildBranch): |
4576 | + |
4577 | + def apply(self, target_path, tree_to, br_to, possible_transports=None): |
4578 | + # it's a command |
4579 | + trace.note("Running '%s' in '%s'." % (self.nest_path, target_path)) |
4580 | + proc = subprocess.Popen(self.nest_path, cwd=target_path, |
4581 | + preexec_fn=subprocess_setup, shell=True, stdin=subprocess.PIPE) |
4582 | + proc.communicate() |
4583 | + if proc.returncode != 0: |
4584 | + raise CommandFailedError(self.nest_path) |
4585 | + |
4586 | + def as_text(self): |
4587 | + return "%s %s" % (RUN_INSTRUCTION, self.nest_path) |
4588 | + |
4589 | + |
4590 | +class MergeInstruction(ChildBranch): |
4591 | + |
4592 | + def apply(self, target_path, tree_to, br_to, possible_transports=None): |
4593 | + revision_of = "" |
4594 | + if self.recipe_branch.revspec is not None: |
4595 | + revision_of = "revision '%s' of " % self.recipe_branch.revspec |
4596 | + trace.note("Merging %s'%s' in to '%s'." |
4597 | + % (revision_of, self.recipe_branch.url, target_path)) |
4598 | + merge_branch(self.recipe_branch, tree_to, br_to, |
4599 | + possible_transports=possible_transports) |
4600 | + |
4601 | + def as_text(self): |
4602 | + revid_part = self._get_revid_part() |
4603 | + return "%s %s %s%s" % ( |
4604 | + MERGE_INSTRUCTION, self.recipe_branch.name, |
4605 | + self.recipe_branch.url, revid_part) |
4606 | + |
4607 | + def __repr__(self): |
4608 | + return "<%s %r>" % (self.__class__.__name__, self.recipe_branch.name) |
4609 | + |
4610 | + |
4611 | +class NestPartInstruction(ChildBranch): |
4612 | + |
4613 | + def __init__(self, recipe_branch, subpath, target_subdir): |
4614 | + ChildBranch.__init__(self, recipe_branch) |
4615 | + self.subpath = subpath |
4616 | + self.target_subdir = target_subdir |
4617 | + |
4618 | + def apply(self, target_path, tree_to, br_to): |
4619 | + nest_part_branch(self.recipe_branch, tree_to, br_to, self.subpath, |
4620 | + self.target_subdir) |
4621 | + |
4622 | + def as_text(self): |
4623 | + revid_part = self._get_revid_part() |
4624 | + if revid_part: |
4625 | + target_subdir = self.target_subdir |
4626 | + if target_subdir is None: |
4627 | + target_subdir = self.subpath |
4628 | + target_revid_part = " %s%s" % ( |
4629 | + target_subdir, revid_part) |
4630 | + elif self.target_subdir is not None: |
4631 | + target_revid_part = " %s" % self.target_subdir |
4632 | + else: |
4633 | + target_revid_part = "" |
4634 | + return "%s %s %s %s%s" % ( |
4635 | + NEST_PART_INSTRUCTION, self.recipe_branch.name, |
4636 | + self.recipe_branch.url, self.subpath, target_revid_part) |
4637 | + |
4638 | + |
4639 | +class NestInstruction(ChildBranch): |
4640 | + |
4641 | + can_have_children = True |
4642 | + |
4643 | + def apply(self, target_path, tree_to, br_to, possible_transports=None): |
4644 | + _build_inner_tree(self.recipe_branch, |
4645 | + target_path=os.path.join(target_path, self.nest_path), |
4646 | + possible_transports=possible_transports) |
4647 | + |
4648 | + def as_text(self): |
4649 | + revid_part = self._get_revid_part() |
4650 | + return "%s %s %s %s%s" % ( |
4651 | + NEST_INSTRUCTION, self.recipe_branch.name, |
4652 | + self.recipe_branch.url, self.nest_path, revid_part) |
4653 | + |
4654 | + def __repr__(self): |
4655 | + return "<%s %r>" % (self.__class__.__name__, |
4656 | + self.recipe_branch.name) |
4657 | + |
4658 | + |
4659 | +class RecipeBranch(object): |
4660 | + """A nested structure that represents a Recipe. |
4661 | + |
4662 | + A RecipeBranch has a name and a url (the name can be None for the |
4663 | + root branch), and optionally child branches that are either merged |
4664 | + or nested. |
4665 | + |
4666 | + The child_branches attribute is a list of tuples of ChildBranch objects. |
4667 | + The revid attribute records the revid that the url and revspec resolved |
4668 | + to when the RecipeBranch was built, or None if it has not been built. |
4669 | + |
4670 | + :ivar revid: after this recipe branch has been built this is set to the |
4671 | + revision ID that was merged/nested from the branch at self.url. |
4672 | + """ |
4673 | + |
4674 | + def __init__(self, name, url, revspec=None): |
4675 | + """Create a RecipeBranch. |
4676 | + |
4677 | + :param name: the name for the branch, or None if it is the root. |
4678 | + :param url: the URL from which to retrieve the branch. |
4679 | + :param revspec: a revision specifier for the revision of the branch |
4680 | + to use, or None (the default) to use the last revision. |
4681 | + """ |
4682 | + self.name = name |
4683 | + self.url = url |
4684 | + self.revspec = revspec |
4685 | + self.child_branches = [] |
4686 | + self.revid = None |
4687 | + self.branch = None |
4688 | + |
4689 | + def resolve_revision_id(self): |
4690 | + """Resolve the revision id for this branch. |
4691 | + """ |
4692 | + if self.revspec is not None: |
4693 | + revspec = revisionspec.RevisionSpec.from_string(self.revspec) |
4694 | + revision_id = revspec.as_revision_id(self.branch) |
4695 | + else: |
4696 | + revision_id = self.branch.last_revision() |
4697 | + self.revid = revision_id |
4698 | + |
4699 | + def merge_branch(self, branch): |
4700 | + """Merge a child branch in to this one. |
4701 | + |
4702 | + :param branch: the RecipeBranch to merge. |
4703 | + """ |
4704 | + self.child_branches.append(MergeInstruction(branch)) |
4705 | + |
4706 | + def nest_part_branch(self, branch, subpath=None, target_subdir=None): |
4707 | + """Merge subdir of a child branch into this one. |
4708 | + |
4709 | + :param branch: the RecipeBranch to merge. |
4710 | + :param subpath: only merge files from branch that are from this path. |
4711 | + e.g. subpath='/debian' will only merge changes from that directory. |
4712 | + :param target_subdir: (optional) directory in target to merge that |
4713 | + subpath into. Defaults to basename of subpath. |
4714 | + """ |
4715 | + self.child_branches.append( |
4716 | + NestPartInstruction(branch, subpath, target_subdir)) |
4717 | + |
4718 | + def nest_branch(self, location, branch): |
4719 | + """Nest a child branch in to this one. |
4720 | + |
4721 | + :param location: the relative path at which this branch should be nested. |
4722 | + :param branch: the RecipeBranch to nest. |
4723 | + """ |
4724 | + assert location not in [b.nest_path for b in self.child_branches],\ |
4725 | + "%s already has branch nested there" % location |
4726 | + self.child_branches.append(NestInstruction(branch, location)) |
4727 | + |
4728 | + def run_command(self, command): |
4729 | + """Set a command to be run. |
4730 | + |
4731 | + :param command: the command to be run |
4732 | + """ |
4733 | + self.child_branches.append(CommandInstruction(None, command)) |
4734 | + |
4735 | + def different_shape_to(self, other_branch): |
4736 | + """Tests whether the name, url and child_branches are the same""" |
4737 | + if self.name != other_branch.name: |
4738 | + return True |
4739 | + if self.url != other_branch.url: |
4740 | + return True |
4741 | + if len(self.child_branches) != len(other_branch.child_branches): |
4742 | + return True |
4743 | + for index, instruction in enumerate(self.child_branches): |
4744 | + child_branch = instruction.recipe_branch |
4745 | + nest_location = instruction.nest_path |
4746 | + other_instruction = other_branch.child_branches[index] |
4747 | + other_child_branch = other_instruction.recipe_branch |
4748 | + other_nest_location = other_instruction.nest_path |
4749 | + if nest_location != other_nest_location: |
4750 | + return True |
4751 | + if ((child_branch is None and other_child_branch is not None) |
4752 | + or (child_branch is not None and other_child_branch is None)): |
4753 | + return True |
4754 | + # if child_branch is None then other_child_branch must be |
4755 | + # None too, meaning that they are both run instructions, |
4756 | + # we would compare their nest locations (commands), but |
4757 | + # that has already been done, so just guard |
4758 | + if (child_branch is not None |
4759 | + and child_branch.different_shape_to(other_child_branch)): |
4760 | + return True |
4761 | + return False |
4762 | + |
4763 | + def iter_all_instructions(self): |
4764 | + """Iter over all instructions under this branch.""" |
4765 | + for instruction in self.child_branches: |
4766 | + yield instruction |
4767 | + child_branch = instruction.recipe_branch |
4768 | + if child_branch is None: |
4769 | + continue |
4770 | + for instruction in child_branch.iter_all_instructions(): |
4771 | + yield instruction |
4772 | + |
4773 | + def iter_all_branches(self): |
4774 | + """Iterate over all branches.""" |
4775 | + yield self |
4776 | + for instruction in self.child_branches: |
4777 | + child_branch = instruction.recipe_branch |
4778 | + if child_branch is None: |
4779 | + continue |
4780 | + for subbranch in child_branch.iter_all_branches(): |
4781 | + yield subbranch |
4782 | + |
4783 | + def lookup_branch(self, name): |
4784 | + """Lookup a branch by its name.""" |
4785 | + for branch in self.iter_all_branches(): |
4786 | + if branch.name == name: |
4787 | + return branch |
4788 | + else: |
4789 | + raise KeyError(name) |
4790 | + |
4791 | + def list_branch_names(self): |
4792 | + """List all of the branch names under this one. |
4793 | + |
4794 | + :return: a list of the branch names. |
4795 | + :rtype: list(str) |
4796 | + """ |
4797 | + return [branch.name for branch in self.iter_all_branches() |
4798 | + if branch.name is not None] |
4799 | + |
4800 | + def __repr__(self): |
4801 | + return "<%s %r>" % (self.__class__.__name__, self.name) |
4802 | + |
4803 | + |
4804 | +class BaseRecipeBranch(RecipeBranch): |
4805 | + """The RecipeBranch that is at the root of a recipe.""" |
4806 | + |
4807 | + def __init__(self, url, deb_version, format, revspec=None): |
4808 | + """Create a BaseRecipeBranch. |
4809 | + |
4810 | + :param deb_version: the template to use for the version number. |
4811 | + Should be None for anything except the root branch. |
4812 | + """ |
4813 | + super(BaseRecipeBranch, self).__init__(None, url, revspec=revspec) |
4814 | + self.deb_version = deb_version |
4815 | + self.format = format |
4816 | + |
4817 | + def substitute_branch_vars(self, branch_name, branch, revid): |
4818 | + """Substitute the branch variables for the given branch name in deb_version. |
4819 | + |
4820 | + Where deb_version has a place to substitute the revno for a branch |
4821 | + this will substitute it for the given branch name. |
4822 | + |
4823 | + :param branch_name: the name of the RecipeBranch to substitute. |
4824 | + :param branch: Branch object for the branch |
4825 | + :param revid: Revision id in the branch for which to return the revno |
4826 | + """ |
4827 | + if self.deb_version is None: |
4828 | + return |
4829 | + revno_var = RevnoVariable(branch_name, branch, revid) |
4830 | + self.deb_version = revno_var.replace(self.deb_version) |
4831 | + svn_revno_var = SubversionRevnumVariable(branch_name, branch, revid) |
4832 | + self.deb_version = svn_revno_var.replace(self.deb_version) |
4833 | + git_commit_var = GitCommitVariable(branch_name, branch, revid) |
4834 | + self.deb_version = git_commit_var.replace(self.deb_version) |
4835 | + latest_tag_var = LatestTagVariable(branch_name, branch, revid) |
4836 | + self.deb_version = latest_tag_var.replace(self.deb_version) |
4837 | + revdate_var = RevdateVariable(branch_name, branch, revid) |
4838 | + self.deb_version = revdate_var.replace(self.deb_version) |
4839 | + revtime_var = RevtimeVariable(branch_name, branch, revid) |
4840 | + self.deb_version = revtime_var.replace(self.deb_version) |
4841 | + tree = branch.repository.revision_tree(revid) |
4842 | + cl_file_id = tree.path2id("debian/changelog") |
4843 | + if cl_file_id is not None: |
4844 | + cl = changelog.Changelog(tree.get_file(cl_file_id)) |
4845 | + debupstream_var = DebUpstreamVariable.from_changelog(branch_name, cl) |
4846 | + self.deb_version = debupstream_var.replace(self.deb_version) |
4847 | + debupstreambase_var = DebUpstreamBaseVariable.from_changelog( |
4848 | + branch_name, cl) |
4849 | + self.deb_version = debupstreambase_var.replace(self.deb_version) |
4850 | + pkgversion_var = DebVersionVariable.from_changelog(branch_name, cl) |
4851 | + self.deb_version = pkgversion_var.replace(self.deb_version) |
4852 | + |
4853 | + def substitute_time(self, time): |
4854 | + """Substitute the time in to deb_version if needed. |
4855 | + |
4856 | + :param time: a datetime.datetime with the desired time. |
4857 | + """ |
4858 | + if self.deb_version is None: |
4859 | + return |
4860 | + self.deb_version = TimeVariable(time).replace(self.deb_version) |
4861 | + self.deb_version = DateVariable(time).replace(self.deb_version) |
4862 | + |
4863 | + def _add_child_branches_to_manifest(self, child_branches, indent_level): |
4864 | + manifest = "" |
4865 | + for instruction in child_branches: |
4866 | + manifest += "%s%s\n" % ( |
4867 | + " " * indent_level, instruction.as_text()) |
4868 | + if instruction.can_have_children: |
4869 | + manifest += self._add_child_branches_to_manifest( |
4870 | + instruction.recipe_branch.child_branches, |
4871 | + indent_level+1) |
4872 | + return manifest |
4873 | + |
4874 | + def __str__(self): |
4875 | + return self.get_recipe_text(validate=True) |
4876 | + |
4877 | + def get_recipe_text(self, validate=False): |
4878 | + manifest = "# bzr-builder format %s" % str(self.format) |
4879 | + if self.deb_version is not None: |
4880 | + # TODO: should we store the expanded version that was used? |
4881 | + manifest += " deb-version %s" % (self.deb_version,) |
4882 | + manifest += "\n" |
4883 | + if self.revid is not None: |
4884 | + manifest += "%s revid:%s\n" % (self.url, self.revid) |
4885 | + elif self.revspec is not None: |
4886 | + manifest += "%s %s\n" % (self.url, self.revspec) |
4887 | + else: |
4888 | + manifest += "%s\n" % (self.url,) |
4889 | + manifest += self._add_child_branches_to_manifest(self.child_branches, |
4890 | + 0) |
4891 | + if validate: |
4892 | + # Sanity check. |
4893 | + # TODO: write a function that compares the result of this parse with |
4894 | + # the branch that we built it from. |
4895 | + RecipeParser(manifest).parse() |
4896 | + return manifest |
4897 | + |
4898 | + |
4899 | +class RecipeParseError(errors.BzrError): |
4900 | + _fmt = "Error parsing %(filename)s:%(line)s:%(char)s: %(problem)s." |
4901 | + |
4902 | + def __init__(self, filename, line, char, problem): |
4903 | + errors.BzrError.__init__(self, filename=filename, line=line, char=char, |
4904 | + problem=problem) |
4905 | + |
4906 | + |
4907 | +class InstructionParseError(RecipeParseError): |
4908 | + _fmt = RecipeParseError._fmt + "\nUsage: %(usage)s" |
4909 | + |
4910 | + def __init__(self, filename, line, char, problem, instruction): |
4911 | + RecipeParseError.__init__(self, filename, line, char, problem) |
4912 | + self.usage = USAGE[instruction] |
4913 | + |
4914 | + |
4915 | +class ForbiddenInstructionError(RecipeParseError): |
4916 | + |
4917 | + def __init__(self, filename, line, char, problem, instruction_name=None): |
4918 | + RecipeParseError.__init__(self, filename, line, char, problem) |
4919 | + self.instruction_name = instruction_name |
4920 | + |
4921 | + |
4922 | +class RecipeParser(object): |
4923 | + """Parse a recipe. |
4924 | + |
4925 | + The parse() method is probably the only one that interests you. |
4926 | + """ |
4927 | + |
4928 | + whitespace_chars = " \t" |
4929 | + eol_char = "\n" |
4930 | + digit_chars = ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9") |
4931 | + |
4932 | + NEWEST_VERSION = 0.4 |
4933 | + |
4934 | + def __init__(self, f, filename=None): |
4935 | + """Create a RecipeParser. |
4936 | + |
4937 | + :param f: either the recipe as a string, or a file like object to |
4938 | + take it from. |
4939 | + :param filename: the filename of the recipe if known (for error |
4940 | + reporting). |
4941 | + """ |
4942 | + if getattr(f, "read", None) is not None: |
4943 | + self.text = f.read() |
4944 | + else: |
4945 | + self.text = f |
4946 | + self.filename = filename |
4947 | + if filename is None: |
4948 | + self.filename = "recipe" |
4949 | + |
4950 | + def parse(self, permitted_instructions=None): |
4951 | + """Parse the recipe. |
4952 | + |
4953 | + :param permitted_instructions: a list of instructions that you |
4954 | + want to allow. Defaults to None allowing them all. |
4955 | + :type permitted_instructions: list(str) or None |
4956 | + :return: a RecipeBranch representing the recipe. |
4957 | + """ |
4958 | + self.lines = self.text.split("\n") |
4959 | + self.index = 0 |
4960 | + self.line_index = 0 |
4961 | + self.current_line = self.lines[self.line_index] |
4962 | + self.current_indent_level = 0 |
4963 | + self.seen_nicks = set() |
4964 | + self.seen_paths = {".": 1} |
4965 | + (version, deb_version) = self.parse_header() |
4966 | + self.version = version |
4967 | + last_instruction = None |
4968 | + active_branches = [] |
4969 | + last_branch = None |
4970 | + while self.line_index < len(self.lines): |
4971 | + if self.is_blankline(): |
4972 | + self.new_line() |
4973 | + continue |
4974 | + comment = self.parse_comment_line() |
4975 | + if comment is not None: |
4976 | + self.new_line() |
4977 | + continue |
4978 | + old_indent_level = self.parse_indent() |
4979 | + if old_indent_level is not None: |
4980 | + if (old_indent_level < self.current_indent_level |
4981 | + and last_instruction != NEST_INSTRUCTION): |
4982 | + self.throw_parse_error("Not allowed to indent unless " |
4983 | + "after a '%s' line" % NEST_INSTRUCTION) |
4984 | + if old_indent_level < self.current_indent_level: |
4985 | + active_branches.append(last_branch) |
4986 | + else: |
4987 | + unindent = self.current_indent_level - old_indent_level |
4988 | + active_branches = active_branches[:unindent] |
4989 | + if last_instruction is None: |
4990 | + url = self.take_to_whitespace("branch to start from") |
4991 | + revspec = self.parse_optional_revspec() |
4992 | + self.new_line() |
4993 | + last_branch = BaseRecipeBranch(url, deb_version, |
4994 | + self.version, revspec=revspec) |
4995 | + active_branches = [last_branch] |
4996 | + last_instruction = "" |
4997 | + else: |
4998 | + instruction = self.parse_instruction( |
4999 | + permitted_instructions=permitted_instructions) |
5000 | + if instruction == RUN_INSTRUCTION: |
The diff has been truncated for viewing.