├── COPYING ├── Makefile ├── README.md ├── VERSION ├── osm4routing.py ├── osmreader.cc ├── osmreader.h ├── parameters.cc ├── parse.cc ├── parse.h ├── parse.i ├── setup.py └── virtualenv.py /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX=g++ 2 | CXXFLAGS=-W -Wall -ansi -pedantic -O3 -Wno-deprecated 3 | LDFLAGS=-lexpat -lbz2 -lpq -lboost_program_options -lboost_filesystem 4 | EXEC=osm4routing 5 | 6 | all: $(EXEC) 7 | 8 | osm4routing: parameters.o main.o osmreader.o bz2reader.o stdinreader.o csvwriter.o pqwriter.o 9 | $(CXX) -o $@ $^ $(LDFLAGS) 10 | 11 | main.o: main.cc main.h 12 | $(CXX) -o $@ -c $< $(CXXFLAGS) 13 | 14 | parameters.o: parameters.cc main.h 15 | $(CXX) -o $@ -c $< $(CXXFLAGS) 16 | 17 | osmreader.o: osmreader.cc osmreader.h reader.h 18 | $(CXX) -o $@ -c $< $(CXXFLAGS) 19 | 20 | bz2reader.o: bz2reader.cc bz2reader.h reader.h 21 | $(CXX) -o $@ -c $< $(CXXFLAGS) 22 | 23 | stdinreader.o: stdinreader.cc stdinreader.h reader.h 24 | $(CXX) -o $@ -c $< $(CXXFLAGS) 25 | 26 | csvwriter.o: csvwriter.cc csvwriter.h writer.h 27 | $(CXX) -o $@ -c $< $(CXXFLAGS) 28 | 29 | pqwriter.o: pqwriter.cc pqwriter.h writer.h 30 | $(CXX) -o $@ -c $< $(CXXFLAGS) 31 | 32 | clean: 33 | rm -rf *.o 34 | 35 | mrproper: clean 36 | rm -rf $(EXEC) 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This project is DEPRECATED 2 | 3 | Please have a look at https://github.com/Tristramg/osm4routing2 4 | 5 | --- 6 | 7 | This tool provides an OpenStreetMap data parser to turn them into a nodes-edges 8 | adapted for routing applications. 9 | 10 | # INPUT FORMAT 11 | The input is an OpenStreetMap XML file. The file can be read: 12 | * from a plain .osm file 13 | * from a bzip2 file 14 | * from a gzip file 15 | 16 | # OUTPUT FORMAT 17 | The output can be: 18 | * a csv file 19 | * database (postgres, mysql, sqlite, postgis) 20 | 21 | In both output you'll get two files/tables: 22 | * nodes that contain 23 | * id (64 bit integer) 24 | * longitude (decimal real) 25 | * latitude (decimal real) 26 | * geometry (only in postgis) 27 | 28 | * edges that contain 29 | * id (64 bit integer) 30 | * source node id (64 bit integer) 31 | * target node id (64 bit integer) 32 | * length (real in meters), 33 | * car accessibility (integer) 34 | * car reverse accessibility (integer) 35 | * bike accessibility (integer) 36 | * bike reverse accessibility (integer) 37 | * foot accessibility (integer) 38 | * geometry (string representing a linestring in the WKT format) 39 | 40 | The accessibility is an integer describing the edge for every mean of transport. 41 | As for cars an bikes the driving direction might change those properties, the 42 | are direct (source->target direction) an reverse (target->source direction) 43 | information. 44 | 45 | The integers mean: 46 | * cars 47 | * 0 forbiden 48 | * 1 residential street 49 | * 2 tertiary road 50 | * 3 secondary road 51 | * 4 primary road 52 | * 5 trunk 53 | * 6 motorway 54 | * bike 55 | * 0 forbiden 56 | * 1 cycling lane in the opposite direction of the car flow 57 | * 2 allowed without specific equipment 58 | * 3 cycling lane 59 | * 4 bus lane allowed for cycles 60 | * 5 cycling track 61 | * foot (no distinction in made on the direction) 62 | * 0 forbiden 63 | * 1 allowed 64 | 65 | 66 | # INSTALL 67 | You need: 68 | * Boost (only for unordered_map that will be included in C++1X) 69 | Read bellow if you have troubles with it 70 | * expat (XML parser) (Ubuntu users install libexpat1-dev) 71 | * python (Ubunut users install python-dev) 72 | * swig 73 | * Python connectors for the database you wan 74 | * sqlite and text output is by default 75 | * python-psycopy2 for postgresql 76 | 77 | ``` 78 | # Just run the following command 79 | sudo python setup.py install 80 | # Run it 81 | osm4routing --help 82 | ``` 83 | 84 | ## Alternative: 85 | ``` 86 | # If you don't have the rights to install it system-wide, or don't want to, use virtualenv: 87 | # Create a virtual environment and activate it 88 | python virtualenv.py env 89 | source env/bin/activate 90 | python setup.py install 91 | osm4routing --help 92 | ``` 93 | 94 | * Installing boost: 95 | You only need the headers. If you have a linux distribution, just install it. 96 | Under windows or macOSX, grab the sources and unzip them. Place the boost directory 97 | containing the headers in the same directory as setup.py 98 | An alternative is to edit setup.py to tell where the directory is located. 99 | 100 | # USAGE 101 | Get the .osm XML file of the region that interests you. 102 | For limited regions, use the export tools from the web interface. 103 | For bigger regions you might find what you want at http://download.geofabrik.de/osm/ 104 | Osmosis can help you to have a smaller region from a big dump http://wiki.openstreetmap.org/wiki/Osmosis 105 | 106 | To know the options, run: 107 | osm4routing --help 108 | 109 | # PERFORMANCE 110 | OSM data can get very big and can be very consuming, don't try to parse the whole world ;) 111 | On my laptop from 2006 (core2duo 1.66Ghz, 2Gb Ram, slow hard drive), 112 | it takes 20 minutes to parse 8Gb uncompressed (0.5Gb as bzip2) and represents France in June 2010 113 | 114 | # Postgis output 115 | Only if you want to use the spatial abilities of postgis, please read those extra informations 116 | in order to a have spatial database 117 | The usual way to get is to execute the following commands (the location of 118 | lwpostgis.sql and spatial_ref_sys.sql depend on your installation). 119 | 120 | ``` 121 | createdb yourdatabase 122 | createlang plpgsql yourdatabase 123 | psql -d yourdatabase -f lwpostgis.sql 124 | psql -d yourdatabase -f spatial_ref_sys.sql 125 | ``` 126 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | * 0.0 2 | First public release 3 | -------------------------------------------------------------------------------- /osm4routing.py: -------------------------------------------------------------------------------- 1 | from osm4routing_xml import * 2 | import os 3 | import bz2, gzip 4 | import sys 5 | from optparse import OptionParser 6 | from sqlalchemy import Table, Column, MetaData, Integer, BigInteger, String, Float, SmallInteger, create_engine 7 | from sqlalchemy.orm import mapper, sessionmaker 8 | from geoalchemy import * 9 | 10 | class Node(object): 11 | def __init__(self, id, lon, lat, elevation = 0, the_geom = 0, spatial=False): 12 | wkt_geom = 'POINT({0} {1})'.format(lon, lat) 13 | self.original_id = id 14 | self.lon = lon 15 | self.lat = lat 16 | self.elevation = elevation 17 | if spatial: 18 | self.the_geom = WKTSpatialElement(wkt_geom) 19 | else: 20 | self.the_geom = wkt_geom 21 | 22 | class Edge(object): 23 | def __init__(self, id, source, target, length, car, car_rev, bike, bike_rev, foot, the_geom, spatial=False): 24 | wkt_geom = 'LINESTRING({0})'.format(the_geom) 25 | self.id = id 26 | self.source = source 27 | self.target = target 28 | self.length = length 29 | self.car = car 30 | self.car_rev = car_rev 31 | self.bike = bike 32 | self.bike_rev = bike 33 | self.foot = foot 34 | if spatial: 35 | self.the_geom = WKTSpatialElement(wkt_geom) 36 | else: 37 | self.the_geom = wkt_geom 38 | 39 | 40 | def parse(file, output="csv", edges_name="edges", nodes_name="nodes", spatial=False): 41 | if not os.path.exists(file): 42 | raise IOError("File {0} not found".format(file)) 43 | 44 | if output != "csv": 45 | metadata = MetaData() 46 | if(spatial): 47 | node_geom = Point(2) 48 | edge_geom = LineString(2) 49 | else: 50 | node_geom = String 51 | edge_geom = String 52 | 53 | nodes_table = Table(nodes_name, metadata, 54 | Column('id', Integer, primary_key = True), 55 | Column('original_id', BigInteger, index = True), 56 | Column('elevation', Integer), 57 | Column('lon', Float, index = True), 58 | Column('lat', Float, index = True), 59 | Column('the_geom', node_geom) 60 | ) 61 | 62 | edges_table = Table(edges_name, metadata, 63 | Column('id', Integer, primary_key=True), 64 | Column('source', BigInteger, index=True), 65 | Column('target', BigInteger, index=True), 66 | Column('length', Float), 67 | Column('car', SmallInteger), 68 | Column('car_rev', SmallInteger), 69 | Column('bike', SmallInteger), 70 | Column('bike_rev', SmallInteger), 71 | Column('foot', SmallInteger), 72 | Column('the_geom', edge_geom) 73 | ) 74 | 75 | GeometryDDL(nodes_table) 76 | GeometryDDL(edges_table) 77 | 78 | 79 | engine = create_engine(output) 80 | metadata.drop_all(engine) 81 | metadata.create_all(engine) 82 | mapper(Node, nodes_table) 83 | mapper(Edge, edges_table) 84 | Session = sessionmaker(bind=engine) 85 | session = Session() 86 | 87 | extension = os.path.splitext(file)[1] 88 | if extension == '.bz2': 89 | print "Recognized as bzip2 file" 90 | f = bz2.BZ2File(file, 'r') 91 | 92 | elif extension == '.gz': 93 | print "Recognized as gzip2 file" 94 | f = gzip.open(file, 'r') 95 | 96 | else: 97 | print "Supposing OSM/xml file" 98 | filesize = os.path.getsize(file) 99 | f = open(file, 'r') 100 | 101 | buffer_size = 4096 102 | p = Parser() 103 | eof = False 104 | print "Step 1: reading file {0}".format(file) 105 | read = 0 106 | while not eof: 107 | s = f.read(buffer_size) 108 | eof = len(s) != buffer_size 109 | p.read(s, len(s), eof) 110 | read += len(s) 111 | 112 | print " Read {0} nodes and {1} ways\n".format(p.get_osm_nodes(), p.get_osm_ways()) 113 | 114 | print "Step 2: saving the nodes" 115 | nodes = p.get_nodes() 116 | if output == "csv": 117 | n = open(nodes_name + '.csv', 'w') 118 | n.write('"node_id","longitude","latitude"\n') 119 | 120 | count = 0 121 | for node in nodes: 122 | if output == "csv": 123 | n.write("{0},{1},{2}\n".format(node.id, node.lon, node.lat)) 124 | else: 125 | session.add(Node(node.id, node.lon, node.lat, spatial=spatial)) 126 | count += 1 127 | if output == "csv": 128 | n.close() 129 | else: 130 | session.commit() 131 | 132 | print " Wrote {0} nodes\n".format(count) 133 | 134 | print "Step 3: saving the edges" 135 | edges = p.get_edges() 136 | count = 0 137 | if output == "csv": 138 | e = open(edges_name + '.csv', 'w') 139 | e.write('"edge_id","source","target","length","car","car reverse","bike","bike reverse","foot","WKT"\n') 140 | for edge in edges: 141 | if output == "csv": 142 | e.write('{0},{1},{2},{3},{4},{5},{6},{7},{8},LINESTRING({9})\n'.format(edge.edge_id, edge.source, edge.target, edge.length, edge.car, edge.car_d, edge.bike, edge.bike_d, edge.foot, edge.geom)) 143 | else: 144 | session.add(Edge(edge.edge_id, edge.source, edge.target, edge.length, edge.car, edge.car_d, edge.bike, edge.bike_d, edge.foot, edge.geom, spatial=spatial)) 145 | count += 1 146 | if output == "csv": 147 | e.close() 148 | else: 149 | session.commit() 150 | print " Wrote {0} edges\n".format(count) 151 | 152 | print "Happy routing :) and please give some feedback!" 153 | 154 | def main(): 155 | usage = """Usage: %prog [options] input_file 156 | 157 | input_file must be an OSM/XML file. It can be compressed with gzip (.gz) or bzip2 (.bz2)""" 158 | 159 | 160 | parser = OptionParser(usage) 161 | parser.add_option("-o", "--output", dest="output", default="csv", 162 | help="""'csv' if you want a simple file, 163 | a connection string to use a database (Example: sqlite:///foo.db postgresql://john@localhost/my_database) 164 | [default: %default]""") 165 | parser.add_option("-n", "--nodes_name", dest="nodes_name", default="nodes", help="Name of the file or table where nodes are stored [default: %default]") 166 | parser.add_option("-e", "--edges_name", dest="edges_name", default="edges", help="Name of the file or table where edges are stored [default: %default]") 167 | parser.add_option("-s", "--spatial", dest="spatial", default=False, action="store_true", help="Is the database spatial? If yes, it creates spatial indexes on the column the_geom. Read about geoalchemy to know what databases are supported (only spatial was tested)") 168 | (options, args) = parser.parse_args() 169 | 170 | if len(args) != 1: 171 | sys.stderr.write("Wrong number of arguments. Expected 1, got {0}\n".format(len(args))) 172 | sys.exit(1) 173 | 174 | try: 175 | parse(args[0], options.output, options.edges_name, options.nodes_name, options.spatial) 176 | except IOError as e: 177 | sys.stderr.write("I/O error: {0}\n".format(e)) 178 | except Exception as e: 179 | sys.stderr.write("Woops... an error occured: {0}\n".format(e)) 180 | 181 | if __name__ == "__main__": 182 | main() 183 | -------------------------------------------------------------------------------- /osmreader.cc: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of osm4routing. 3 | 4 | osm4routing is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Mumoro is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with osm4routing. If not, see . 16 | */ 17 | 18 | #include "osmreader.h" 19 | #include 20 | #include 21 | 22 | using namespace std; 23 | 24 | OsmReader::OsmReader(const std::string & filename) 25 | { 26 | file.open(filename.c_str(), ifstream::in); 27 | if( !file.good() ) 28 | { 29 | std::cout << endl; 30 | std::cerr << "Unable to open file " << filename << std::endl; 31 | exit(1); 32 | } 33 | } 34 | 35 | int OsmReader::read(char * buff, int buffsize) 36 | { 37 | file.read(buff, buffsize); 38 | return file.gcount(); 39 | } 40 | 41 | bool OsmReader::eof() const 42 | { 43 | return file.eof(); 44 | } 45 | -------------------------------------------------------------------------------- /osmreader.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of osm4routing. 3 | 4 | osm4routing is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Mumoro is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with osm4routing. If not, see . 16 | */ 17 | 18 | #include "reader.h" 19 | #include 20 | 21 | #ifndef _OSMREADER_H 22 | #define _OSMREADER_H 23 | class OsmReader : public Reader 24 | { 25 | std::ifstream file; 26 | public: 27 | OsmReader(const std::string & filename); 28 | int read(char * buff, int buffsize); 29 | bool eof() const; 30 | }; 31 | #endif 32 | -------------------------------------------------------------------------------- /parameters.cc: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of osm4routing. 3 | 4 | osm4routing is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | Mumoro is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with osm4routing. If not, see . 16 | */ 17 | 18 | #include "parse.h" 19 | #include 20 | Edge_property::Edge_property() : 21 | car_direct(unknown), 22 | car_reverse(unknown), 23 | bike_direct(unknown), 24 | bike_reverse(unknown), 25 | foot(unknown) 26 | { 27 | } 28 | 29 | bool Edge_property::accessible() 30 | { 31 | return direct_accessible() || reverse_accessible(); 32 | } 33 | 34 | bool Edge_property::direct_accessible() 35 | { 36 | return car_direct > 0 || bike_direct > 0 || foot > 0; 37 | } 38 | 39 | bool Edge_property::reverse_accessible() 40 | { 41 | return car_reverse > 0 || bike_reverse > 0 || foot > 0; 42 | } 43 | 44 | 45 | 46 | void Edge_property::reset() 47 | { 48 | car_direct = unknown; 49 | car_reverse = unknown; 50 | bike_direct = unknown; 51 | bike_reverse = unknown; 52 | foot = unknown; 53 | } 54 | 55 | void Edge_property::normalize() 56 | { 57 | if(car_reverse == unknown && car_direct != unknown) 58 | car_reverse = car_direct; 59 | if(bike_reverse == unknown && bike_direct != unknown) 60 | bike_reverse = bike_direct; 61 | if(car_direct == unknown) car_direct = car_forbiden; 62 | if(bike_direct == unknown) bike_direct = bike_forbiden; 63 | if(car_reverse == unknown) car_reverse = car_forbiden; 64 | if(bike_reverse == unknown) bike_reverse = bike_forbiden; 65 | if(foot == unknown) foot = foot_forbiden; 66 | } 67 | 68 | bool Edge_property::update(const std::string & key, const std::string & val) 69 | { 70 | if(key == "highway") 71 | { 72 | if(val == "cycleway" || val == "path" || val == "footway" || 73 | val == "steps" || val == "pedestrian") 74 | { 75 | bike_direct = bike_track; 76 | foot = foot_allowed; 77 | } 78 | else if(val == "primary" || val == "primary_link") 79 | { 80 | car_direct = car_primary; 81 | foot = foot_allowed; 82 | bike_direct = bike_allowed; 83 | } 84 | else if(val == "secondary") 85 | { 86 | car_direct = car_secondary; 87 | foot = foot_allowed; 88 | bike_direct = bike_allowed; 89 | } 90 | else if(val == "tertiary") 91 | { 92 | car_direct = car_tertiary; 93 | foot = foot_allowed; 94 | bike_direct = bike_allowed; 95 | } 96 | else if(val == "unclassified" || val == "residential" || val == "living_street" || 97 | val == "road" || val == "service" || val == "track") 98 | { 99 | car_direct = car_residential; 100 | foot = foot_allowed; 101 | bike_direct = bike_allowed; 102 | } 103 | else if(val == "motorway" || val == "motorway_link") 104 | { 105 | car_direct = car_motorway; 106 | foot = foot_forbiden; 107 | bike_direct = bike_forbiden; 108 | } 109 | else if(val == "trunk" || val == "trunk_link") 110 | { 111 | car_direct = car_trunk; 112 | foot = foot_forbiden; 113 | bike_direct = bike_forbiden; 114 | } 115 | } 116 | 117 | else if(key == "pedestrian" || key == "foot") 118 | { 119 | if(val == "yes" || val == "designated" || val == "permissive") 120 | foot = foot_allowed; 121 | else if(val == "no") 122 | foot = foot_forbiden; 123 | else 124 | std::cerr << "I don't know what to do with: " << key << "=" << val << std::endl; 125 | } 126 | 127 | // http://wiki.openstreetmap.org/wiki/Cycleway 128 | // http://wiki.openstreetmap.org/wiki/Map_Features#Cycleway 129 | else if(key == "cycleway") 130 | { 131 | if(val == "lane" || val == "yes" || val == "true" || val == "lane_in_the_middle") 132 | bike_direct = bike_lane; 133 | else if(val == "track") 134 | bike_direct = bike_track; 135 | else if(val == "opposite_lane") 136 | bike_reverse = bike_lane; 137 | else if(val == "opposite_track") 138 | bike_reverse = bike_track; 139 | else if(val == "opposite") 140 | bike_reverse = bike_allowed; 141 | else if(val == "share_busway") 142 | bike_direct = bike_busway; 143 | else if(val == "lane_left") 144 | bike_reverse = bike_lane; 145 | else 146 | bike_direct = bike_lane; 147 | } 148 | 149 | else if(key == "bicycle") 150 | { 151 | if(val == "yes" || val == "permissive" || val == "destination" || val == "designated" || val == "private" || val == "true") 152 | bike_direct = bike_allowed; 153 | else if(val == "no" || val == "true") 154 | bike_direct = bike_forbiden; 155 | else 156 | std::cerr << "I don't know what to do with: " << key << "=" << val << std::endl; 157 | } 158 | 159 | else if(key == "busway") 160 | { 161 | if(val == "yes" || val == "track" || val == "lane") 162 | bike_direct = bike_busway; 163 | else if(val == "opposite_lane" || val == "opposite_track") 164 | bike_reverse = bike_busway; 165 | else 166 | bike_direct = bike_busway; 167 | } 168 | 169 | else if(key == "oneway") 170 | { 171 | if(val == "yes" || val == "true" || val == "1") 172 | { 173 | car_reverse = car_forbiden; 174 | if(bike_reverse == unknown) 175 | bike_reverse = bike_forbiden; 176 | } 177 | } 178 | 179 | else if(key == "junction") 180 | { 181 | if(val == "roundabout") 182 | { 183 | car_reverse = car_forbiden; 184 | if(bike_reverse == unknown) 185 | bike_reverse = bike_forbiden; 186 | } 187 | } 188 | return this->accessible(); 189 | } 190 | -------------------------------------------------------------------------------- /parse.cc: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include "cmath" 3 | 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | typedef boost::unordered_map NodeMapType; 9 | 10 | 11 | double rad(double deg) 12 | { 13 | return deg * 3.14159265 / 180; 14 | } 15 | 16 | double distance(double lon1, double lat1, double lon2, double lat2) 17 | { 18 | const double r = 6371000; 19 | 20 | return acos( sin( rad(lat1) ) * sin( rad(lat2) ) + 21 | cos( rad(lat1) ) * cos( rad(lat2) ) * cos( rad(lon2-lon1 ) ) 22 | ) * r; 23 | } 24 | 25 | void 26 | start(void * data, const char *el, const char **attr) 27 | { 28 | Parser * d = (Parser*) data; 29 | if (strcmp(el, "node") == 0) 30 | { 31 | node_t id = 0; 32 | double lat = 0, lon = 0; 33 | while (*attr != NULL) 34 | { 35 | const char* name = *attr++; 36 | const char* value = *attr++; 37 | 38 | if (strcmp(name, "id") == 0) 39 | { 40 | id = atoll(value); 41 | } 42 | else if (strcmp(name, "lat") == 0) 43 | { 44 | lat = atof(value); 45 | } 46 | else if (strcmp(name, "lon") == 0) 47 | { 48 | lon = atof(value); 49 | } 50 | } 51 | d->nodes[id] = Node(lon, lat, id); 52 | } 53 | 54 | else if (strcmp(el, "nd") == 0) 55 | { 56 | const char* name = *attr++; 57 | const char* value = *attr++; 58 | if (strcmp(name, "ref") == 0) 59 | { 60 | node_t node_id = atoll(value); 61 | d->way_nodes.push_back(node_id); 62 | } 63 | } 64 | 65 | else if(strcmp(el, "way") == 0) 66 | { 67 | d->way_nodes.clear(); 68 | d->ep.reset(); 69 | const char* name = *attr++; 70 | const char* value = *attr++; 71 | if( !strcmp(name, "id") == 0 ) 72 | { 73 | cout << "fuck" << std::endl; 74 | } 75 | else 76 | { 77 | d->current_way = atoll(value); 78 | } 79 | d->ways_count++; 80 | } 81 | 82 | else if(strcmp(el, "tag") == 0) 83 | { 84 | string key; 85 | while (*attr != NULL) 86 | { 87 | const char* name = *attr++; 88 | const char* value = *attr++; 89 | 90 | if ( strcmp(name, "k") == 0 ) 91 | key = value; 92 | else if ( strcmp(name, "v") == 0 ) 93 | { 94 | d->ep.update(key, value); 95 | } 96 | } 97 | } 98 | 99 | } 100 | 101 | void end(void * data, const char * el) 102 | { 103 | Parser * d = (Parser*) data; 104 | if(strcmp(el, "way") == 0) 105 | { 106 | if(d->ep.accessible()) 107 | { 108 | d->ep.normalize(); 109 | vector::const_iterator it; 110 | d->temp_edges << d->ep.foot << " " 111 | << d->ep.car_direct << " " << d->ep.car_reverse << " " 112 | << d->ep.bike_direct << " " << d->ep.bike_reverse << " " 113 | << d->way_nodes.size(); 114 | for(it = d->way_nodes.begin(); it < d->way_nodes.end(); ++it) 115 | { 116 | d->nodes[*it].uses++; 117 | d->temp_edges << " " << *it; 118 | } 119 | d->temp_edges << endl; 120 | 121 | d->nodes[d->way_nodes.front()].uses++; 122 | d->nodes[d->way_nodes.back()].uses++; 123 | } 124 | } 125 | } 126 | 127 | 128 | Parser::Parser() 129 | { 130 | temp_edges.open("temp_ways"); 131 | parser = XML_ParserCreate(NULL); 132 | XML_SetElementHandler(parser, start, end); 133 | // ios_base::sync_with_stdio(false); 134 | XML_SetUserData(parser, this); 135 | } 136 | 137 | void Parser::read(char * buf, int size, bool end) 138 | { 139 | if( !XML_Parse(parser, buf, size, end) ) 140 | { 141 | cerr << XML_ErrorString(XML_GetErrorCode(parser)) << 142 | " at line " << 143 | XML_GetCurrentLineNumber(parser) << endl; 144 | } 145 | 146 | if(end) 147 | { 148 | XML_ParserFree(parser); 149 | temp_edges.close(); 150 | } 151 | } 152 | 153 | vector Parser::get_nodes() const 154 | { 155 | vector ret; 156 | ret.reserve(nodes.size()/5); //Simply heuristical... 157 | for(NodeMapType::const_iterator i = nodes.begin(); i != nodes.end(); ++i) 158 | { 159 | if( (*i).second.uses > 1 ) 160 | { 161 | ret.push_back(Node((*i).second.lon, (*i).second.lat, (*i).first)); 162 | } 163 | } 164 | return ret; 165 | 166 | } 167 | 168 | vector Parser::get_edges() const 169 | { 170 | vector ret; 171 | ret.reserve(nodes.size()/5); //Simply heuristical... 172 | ifstream tmp; 173 | tmp.open("temp_ways"); 174 | node_t id, source=0; 175 | stringstream geom; 176 | geom.precision(10); 177 | double length = 0, pred_lon = 0, pred_lat = 0; 178 | char car_direct, car_rev, foot, bike_direct, bike_rev; 179 | int nb; 180 | int edges_inserted = 0; 181 | Node n; 182 | string line; 183 | 184 | 185 | while(getline(tmp, line)) 186 | { 187 | stringstream way(line); 188 | way >> foot >> car_direct >> car_rev >> bike_direct >> bike_rev >> nb; 189 | bool first_node = true; 190 | 191 | // We skip the edge if there is an invalid node 192 | bool skip_edge = false; 193 | for(int i=0; i> id; 196 | n = nodes.at(id); 197 | 198 | if(n.valid) 199 | { 200 | if(first_node) 201 | { 202 | geom.str(""); 203 | source = id; 204 | first_node = false; 205 | } 206 | else 207 | { 208 | length += distance(n.lon, n.lat, pred_lon, pred_lat); 209 | if(geom.str() != "") 210 | geom << ","; 211 | } 212 | 213 | pred_lon = n.lon; 214 | pred_lat = n.lat; 215 | 216 | geom << n.lon << " " << n.lat; 217 | if( !first_node && n.uses > 1 && id != source) 218 | { 219 | if(!skip_edge) 220 | { 221 | ret.push_back(Edge(edges_inserted, source, id, length, car_direct, car_rev, bike_direct, bike_rev, foot, geom.str())); 222 | } 223 | 224 | edges_inserted++; 225 | length = 0; 226 | geom.str(""); 227 | geom << n.lon << " " << n.lat; 228 | source = id; 229 | skip_edge = false; 230 | } 231 | } 232 | else 233 | { 234 | skip_edge = true; 235 | } 236 | } 237 | } 238 | 239 | tmp.close(); 240 | return ret; 241 | } 242 | 243 | unsigned long Parser::get_osm_nodes() const 244 | { 245 | return nodes.size(); 246 | } 247 | 248 | unsigned long long Parser::get_osm_ways() const 249 | { 250 | return ways_count; 251 | } 252 | -------------------------------------------------------------------------------- /parse.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | typedef uint64_t node_t; 9 | const int unknown = -1; 10 | const int foot_forbiden = 0; 11 | const int foot_allowed = 1; 12 | 13 | const int car_forbiden = 0; 14 | const int car_residential = 1; 15 | const int car_tertiary = 2; 16 | const int car_secondary = 3; 17 | const int car_primary = 4; 18 | const int car_trunk = 5; 19 | const int car_motorway = 6; 20 | 21 | const int bike_forbiden = 0; 22 | const int bike_opposite_lane = 1; 23 | const int bike_allowed = 2; 24 | const int bike_lane = 3; 25 | const int bike_busway = 4; 26 | const int bike_track = 5; 27 | 28 | class Edge_property 29 | { 30 | public: 31 | int car_direct; 32 | int car_reverse; 33 | int bike_direct; 34 | int bike_reverse; 35 | int foot; 36 | 37 | Edge_property(); 38 | 39 | // Can at least one mean use that edge 40 | bool accessible(); 41 | bool direct_accessible(); 42 | bool reverse_accessible(); 43 | 44 | // Update the properties given new information 45 | bool update(const std::string & tag, const std::string & val); 46 | 47 | // Infer unknown data 48 | void normalize(); 49 | 50 | void reset(); 51 | }; 52 | 53 | struct Node 54 | { 55 | node_t id; 56 | double lon; 57 | double lat; 58 | 59 | // By how many ways has this node been used 60 | // This allows to detect a street intersection 61 | char uses; 62 | 63 | // Is this node valid: 64 | // In some exports, a way references a node that isn’t in the data 65 | // This causes bad coordinates 66 | bool valid; 67 | 68 | Node() : uses(0), valid(false) {}; 69 | 70 | Node(double _lon, double _lat, node_t _id) : 71 | id(_id), lon(_lon), lat(_lat), uses(0), valid(true) 72 | {}; 73 | }; 74 | 75 | struct Edge 76 | { 77 | node_t edge_id; 78 | node_t source; 79 | node_t target; 80 | float length; 81 | char car; 82 | char car_d; 83 | char bike; 84 | char bike_d; 85 | char foot; 86 | std::string geom; 87 | Edge() {} 88 | Edge(node_t e, node_t s, node_t t, float l, char c, char cd, char b, char bd, char f, const std::string & str) : 89 | edge_id(e), source(s), target(t), length(l), 90 | car(c), car_d(cd), bike(b), bike_d(bd), foot(f), 91 | geom(str) 92 | {} 93 | }; 94 | 95 | 96 | typedef boost::unordered_map NodeMapType; 97 | 98 | struct Parser 99 | { 100 | Node * source; 101 | Node * prev; 102 | NodeMapType nodes; 103 | node_t ways_count; 104 | int edge_length; 105 | node_t ways_progress; 106 | Edge_property ep; 107 | double length; 108 | XML_Parser parser; 109 | std::ofstream temp_edges; 110 | std::vector way_nodes; 111 | node_t current_way; 112 | 113 | Parser(); 114 | void read(char *, int, bool); 115 | std::vector get_nodes() const; 116 | std::vector get_edges() const; 117 | unsigned long get_osm_nodes() const; 118 | unsigned long long get_osm_ways() const; 119 | 120 | }; 121 | -------------------------------------------------------------------------------- /parse.i: -------------------------------------------------------------------------------- 1 | %module osm4routing_xml 2 | %include "std_vector.i" 3 | %include "std_string.i" 4 | %{ 5 | #include "parse.h" 6 | %} 7 | 8 | %template(Nodes) std::vector; 9 | %template(Edges) std::vector; 10 | 11 | class Edge_property 12 | { 13 | public: 14 | int car_direct; 15 | int car_reverse; 16 | int bike_direct; 17 | int bike_reverse; 18 | int foot; 19 | 20 | Edge_property(); 21 | 22 | // Can at least one mean use that edge 23 | bool accessible(); 24 | bool direct_accessible(); 25 | bool reverse_accessible(); 26 | 27 | // Update the properties given new information 28 | bool update(const std::string & tag, const std::string & val); 29 | 30 | // Infer unknown data 31 | void normalize(); 32 | 33 | void reset(); 34 | }; 35 | 36 | struct Edge 37 | { 38 | unsigned long long edge_id; 39 | unsigned long long source; 40 | unsigned long long target; 41 | float length; 42 | char car; 43 | char car_d; 44 | char bike; 45 | char bike_d; 46 | char foot; 47 | std::string geom; 48 | }; 49 | 50 | struct Node 51 | { 52 | unsigned long id; 53 | double lon; 54 | double lat; 55 | char uses; 56 | }; 57 | 58 | 59 | struct Parser 60 | { 61 | Parser(); 62 | void read(char *, int, bool); 63 | std::vector get_nodes() const; 64 | std::vector get_edges() const; 65 | int get_osm_nodes() const; 66 | int get_osm_ways() const; 67 | }; 68 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Update this if needed 2 | # It has to point to the directory containing the boost headers 3 | boost_path = "." 4 | 5 | 6 | from setuptools import setup, find_packages, Extension 7 | setup(name='Osm4routing', 8 | version='1.0.6', 9 | author= 'Tristram Graebener', 10 | author_email = 'tristramg@gmail.com', 11 | description = 'A simple tool to parse OpenStreetMap data to use them for routing', 12 | license = 'GPLv3', 13 | url = 'http://github.com/Tristramg/osm4routing/', 14 | install_requires = ['sqlalchemy <0.9', 'setuptools-git', 'geoalchemy'], 15 | py_modules = ['osm4routing', 'osm4routing_xml'], 16 | 17 | ext_modules = [ 18 | Extension("_osm4routing_xml", 19 | sources=["parse.cc", "parameters.cc", "parse.i"], 20 | swig_opts=['-c++'], 21 | include_dirs=[boost_path], 22 | libraries=['expat']) 23 | ], 24 | entry_points = { 25 | 'console_scripts': ['osm4routing = osm4routing:main'], 26 | } 27 | 28 | ) 29 | 30 | -------------------------------------------------------------------------------- /virtualenv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Create a "virtual" Python installation 3 | """ 4 | 5 | virtualenv_version = "1.4.8" 6 | 7 | import sys 8 | import os 9 | import optparse 10 | import re 11 | import shutil 12 | import logging 13 | import distutils.sysconfig 14 | try: 15 | import subprocess 16 | except ImportError, e: 17 | if sys.version_info <= (2, 3): 18 | print 'ERROR: %s' % e 19 | print 'ERROR: this script requires Python 2.4 or greater; or at least the subprocess module.' 20 | print 'If you copy subprocess.py from a newer version of Python this script will probably work' 21 | sys.exit(101) 22 | else: 23 | raise 24 | try: 25 | set 26 | except NameError: 27 | from sets import Set as set 28 | 29 | join = os.path.join 30 | py_version = 'python%s.%s' % (sys.version_info[0], sys.version_info[1]) 31 | is_jython = sys.platform.startswith('java') 32 | expected_exe = is_jython and 'jython' or 'python' 33 | 34 | REQUIRED_MODULES = ['os', 'posix', 'posixpath', 'nt', 'ntpath', 'genericpath', 35 | 'fnmatch', 'locale', 'encodings', 'codecs', 36 | 'stat', 'UserDict', 'readline', 'copy_reg', 'types', 37 | 're', 'sre', 'sre_parse', 'sre_constants', 'sre_compile', 38 | 'lib-dynload', 'config', 'zlib'] 39 | 40 | if sys.version_info[:2] >= (2, 6): 41 | REQUIRED_MODULES.extend(['warnings', 'linecache', '_abcoll', 'abc']) 42 | if sys.version_info[:2] <= (2, 3): 43 | REQUIRED_MODULES.extend(['sets', '__future__']) 44 | 45 | class Logger(object): 46 | 47 | """ 48 | Logging object for use in command-line script. Allows ranges of 49 | levels, to avoid some redundancy of displayed information. 50 | """ 51 | 52 | DEBUG = logging.DEBUG 53 | INFO = logging.INFO 54 | NOTIFY = (logging.INFO+logging.WARN)/2 55 | WARN = WARNING = logging.WARN 56 | ERROR = logging.ERROR 57 | FATAL = logging.FATAL 58 | 59 | LEVELS = [DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL] 60 | 61 | def __init__(self, consumers): 62 | self.consumers = consumers 63 | self.indent = 0 64 | self.in_progress = None 65 | self.in_progress_hanging = False 66 | 67 | def debug(self, msg, *args, **kw): 68 | self.log(self.DEBUG, msg, *args, **kw) 69 | def info(self, msg, *args, **kw): 70 | self.log(self.INFO, msg, *args, **kw) 71 | def notify(self, msg, *args, **kw): 72 | self.log(self.NOTIFY, msg, *args, **kw) 73 | def warn(self, msg, *args, **kw): 74 | self.log(self.WARN, msg, *args, **kw) 75 | def error(self, msg, *args, **kw): 76 | self.log(self.WARN, msg, *args, **kw) 77 | def fatal(self, msg, *args, **kw): 78 | self.log(self.FATAL, msg, *args, **kw) 79 | def log(self, level, msg, *args, **kw): 80 | if args: 81 | if kw: 82 | raise TypeError( 83 | "You may give positional or keyword arguments, not both") 84 | args = args or kw 85 | rendered = None 86 | for consumer_level, consumer in self.consumers: 87 | if self.level_matches(level, consumer_level): 88 | if (self.in_progress_hanging 89 | and consumer in (sys.stdout, sys.stderr)): 90 | self.in_progress_hanging = False 91 | sys.stdout.write('\n') 92 | sys.stdout.flush() 93 | if rendered is None: 94 | if args: 95 | rendered = msg % args 96 | else: 97 | rendered = msg 98 | rendered = ' '*self.indent + rendered 99 | if hasattr(consumer, 'write'): 100 | consumer.write(rendered+'\n') 101 | else: 102 | consumer(rendered) 103 | 104 | def start_progress(self, msg): 105 | assert not self.in_progress, ( 106 | "Tried to start_progress(%r) while in_progress %r" 107 | % (msg, self.in_progress)) 108 | if self.level_matches(self.NOTIFY, self._stdout_level()): 109 | sys.stdout.write(msg) 110 | sys.stdout.flush() 111 | self.in_progress_hanging = True 112 | else: 113 | self.in_progress_hanging = False 114 | self.in_progress = msg 115 | 116 | def end_progress(self, msg='done.'): 117 | assert self.in_progress, ( 118 | "Tried to end_progress without start_progress") 119 | if self.stdout_level_matches(self.NOTIFY): 120 | if not self.in_progress_hanging: 121 | # Some message has been printed out since start_progress 122 | sys.stdout.write('...' + self.in_progress + msg + '\n') 123 | sys.stdout.flush() 124 | else: 125 | sys.stdout.write(msg + '\n') 126 | sys.stdout.flush() 127 | self.in_progress = None 128 | self.in_progress_hanging = False 129 | 130 | def show_progress(self): 131 | """If we are in a progress scope, and no log messages have been 132 | shown, write out another '.'""" 133 | if self.in_progress_hanging: 134 | sys.stdout.write('.') 135 | sys.stdout.flush() 136 | 137 | def stdout_level_matches(self, level): 138 | """Returns true if a message at this level will go to stdout""" 139 | return self.level_matches(level, self._stdout_level()) 140 | 141 | def _stdout_level(self): 142 | """Returns the level that stdout runs at""" 143 | for level, consumer in self.consumers: 144 | if consumer is sys.stdout: 145 | return level 146 | return self.FATAL 147 | 148 | def level_matches(self, level, consumer_level): 149 | """ 150 | >>> l = Logger() 151 | >>> l.level_matches(3, 4) 152 | False 153 | >>> l.level_matches(3, 2) 154 | True 155 | >>> l.level_matches(slice(None, 3), 3) 156 | False 157 | >>> l.level_matches(slice(None, 3), 2) 158 | True 159 | >>> l.level_matches(slice(1, 3), 1) 160 | True 161 | >>> l.level_matches(slice(2, 3), 1) 162 | False 163 | """ 164 | if isinstance(level, slice): 165 | start, stop = level.start, level.stop 166 | if start is not None and start > consumer_level: 167 | return False 168 | if stop is not None or stop <= consumer_level: 169 | return False 170 | return True 171 | else: 172 | return level >= consumer_level 173 | 174 | #@classmethod 175 | def level_for_integer(cls, level): 176 | levels = cls.LEVELS 177 | if level < 0: 178 | return levels[0] 179 | if level >= len(levels): 180 | return levels[-1] 181 | return levels[level] 182 | 183 | level_for_integer = classmethod(level_for_integer) 184 | 185 | def mkdir(path): 186 | if not os.path.exists(path): 187 | logger.info('Creating %s', path) 188 | os.makedirs(path) 189 | else: 190 | logger.info('Directory %s already exists', path) 191 | 192 | def copyfile(src, dest, symlink=True): 193 | if not os.path.exists(src): 194 | # Some bad symlink in the src 195 | logger.warn('Cannot find file %s (bad symlink)', src) 196 | return 197 | if os.path.exists(dest): 198 | logger.debug('File %s already exists', dest) 199 | return 200 | if not os.path.exists(os.path.dirname(dest)): 201 | logger.info('Creating parent directories for %s' % os.path.dirname(dest)) 202 | os.makedirs(os.path.dirname(dest)) 203 | if symlink and hasattr(os, 'symlink'): 204 | logger.info('Symlinking %s', dest) 205 | os.symlink(os.path.abspath(src), dest) 206 | else: 207 | logger.info('Copying to %s', dest) 208 | if os.path.isdir(src): 209 | shutil.copytree(src, dest, True) 210 | else: 211 | shutil.copy2(src, dest) 212 | 213 | def writefile(dest, content, overwrite=True): 214 | if not os.path.exists(dest): 215 | logger.info('Writing %s', dest) 216 | f = open(dest, 'wb') 217 | f.write(content) 218 | f.close() 219 | return 220 | else: 221 | f = open(dest, 'rb') 222 | c = f.read() 223 | f.close() 224 | if c != content: 225 | if not overwrite: 226 | logger.notify('File %s exists with different content; not overwriting', dest) 227 | return 228 | logger.notify('Overwriting %s with new content', dest) 229 | f = open(dest, 'wb') 230 | f.write(content) 231 | f.close() 232 | else: 233 | logger.info('Content %s already in place', dest) 234 | 235 | def rmtree(dir): 236 | if os.path.exists(dir): 237 | logger.notify('Deleting tree %s', dir) 238 | shutil.rmtree(dir) 239 | else: 240 | logger.info('Do not need to delete %s; already gone', dir) 241 | 242 | def make_exe(fn): 243 | if hasattr(os, 'chmod'): 244 | oldmode = os.stat(fn).st_mode & 07777 245 | newmode = (oldmode | 0555) & 07777 246 | os.chmod(fn, newmode) 247 | logger.info('Changed mode of %s to %s', fn, oct(newmode)) 248 | 249 | def _find_file(filename, dirs): 250 | for dir in dirs: 251 | if os.path.exists(join(dir, filename)): 252 | return join(dir, filename) 253 | return filename 254 | 255 | def _install_req(py_executable, unzip=False, distribute=False): 256 | if not distribute: 257 | setup_fn = 'setuptools-0.6c11-py%s.egg' % sys.version[:3] 258 | project_name = 'setuptools' 259 | bootstrap_script = EZ_SETUP_PY 260 | source = None 261 | else: 262 | setup_fn = None 263 | source = 'distribute-0.6.8.tar.gz' 264 | project_name = 'distribute' 265 | bootstrap_script = DISTRIBUTE_SETUP_PY 266 | try: 267 | # check if the global Python has distribute installed or plain 268 | # setuptools 269 | import pkg_resources 270 | if not hasattr(pkg_resources, '_distribute'): 271 | location = os.path.dirname(pkg_resources.__file__) 272 | logger.notify("A globally installed setuptools was found (in %s)" % location) 273 | logger.notify("Use the --no-site-packages option to use distribute in " 274 | "the virtualenv.") 275 | except ImportError: 276 | pass 277 | 278 | search_dirs = file_search_dirs() 279 | 280 | if setup_fn is not None: 281 | setup_fn = _find_file(setup_fn, search_dirs) 282 | 283 | if source is not None: 284 | source = _find_file(source, search_dirs) 285 | 286 | if is_jython and os._name == 'nt': 287 | # Jython's .bat sys.executable can't handle a command line 288 | # argument with newlines 289 | import tempfile 290 | fd, ez_setup = tempfile.mkstemp('.py') 291 | os.write(fd, bootstrap_script) 292 | os.close(fd) 293 | cmd = [py_executable, ez_setup] 294 | else: 295 | cmd = [py_executable, '-c', bootstrap_script] 296 | if unzip: 297 | cmd.append('--always-unzip') 298 | env = {} 299 | if logger.stdout_level_matches(logger.DEBUG): 300 | cmd.append('-v') 301 | 302 | old_chdir = os.getcwd() 303 | if setup_fn is not None and os.path.exists(setup_fn): 304 | logger.info('Using existing %s egg: %s' % (project_name, setup_fn)) 305 | cmd.append(setup_fn) 306 | if os.environ.get('PYTHONPATH'): 307 | env['PYTHONPATH'] = setup_fn + os.path.pathsep + os.environ['PYTHONPATH'] 308 | else: 309 | env['PYTHONPATH'] = setup_fn 310 | else: 311 | # the source is found, let's chdir 312 | if source is not None and os.path.exists(source): 313 | os.chdir(os.path.dirname(source)) 314 | else: 315 | logger.info('No %s egg found; downloading' % project_name) 316 | cmd.extend(['--always-copy', '-U', project_name]) 317 | logger.start_progress('Installing %s...' % project_name) 318 | logger.indent += 2 319 | cwd = None 320 | if project_name == 'distribute': 321 | env['DONT_PATCH_SETUPTOOLS'] = 'true' 322 | 323 | def _filter_ez_setup(line): 324 | return filter_ez_setup(line, project_name) 325 | 326 | if not os.access(os.getcwd(), os.W_OK): 327 | cwd = '/tmp' 328 | if source is not None and os.path.exists(source): 329 | # the current working dir is hostile, let's copy the 330 | # tarball to /tmp 331 | target = os.path.join(cwd, os.path.split(source)[-1]) 332 | shutil.copy(source, target) 333 | try: 334 | call_subprocess(cmd, show_stdout=False, 335 | filter_stdout=_filter_ez_setup, 336 | extra_env=env, 337 | cwd=cwd) 338 | finally: 339 | logger.indent -= 2 340 | logger.end_progress() 341 | if os.getcwd() != old_chdir: 342 | os.chdir(old_chdir) 343 | if is_jython and os._name == 'nt': 344 | os.remove(ez_setup) 345 | 346 | def file_search_dirs(): 347 | here = os.path.dirname(os.path.abspath(__file__)) 348 | dirs = ['.', here, 349 | join(here, 'virtualenv_support')] 350 | if os.path.splitext(os.path.dirname(__file__))[0] != 'virtualenv': 351 | # Probably some boot script; just in case virtualenv is installed... 352 | try: 353 | import virtualenv 354 | except ImportError: 355 | pass 356 | else: 357 | dirs.append(os.path.join(os.path.dirname(virtualenv.__file__), 'virtualenv_support')) 358 | return [d for d in dirs if os.path.isdir(d)] 359 | 360 | def install_setuptools(py_executable, unzip=False): 361 | _install_req(py_executable, unzip) 362 | 363 | def install_distribute(py_executable, unzip=False): 364 | _install_req(py_executable, unzip, distribute=True) 365 | 366 | _pip_re = re.compile(r'^pip-.*(zip|tar.gz|tar.bz2|tgz|tbz)$', re.I) 367 | def install_pip(py_executable): 368 | filenames = [] 369 | for dir in file_search_dirs(): 370 | filenames.extend([join(dir, fn) for fn in os.listdir(dir) 371 | if _pip_re.search(fn)]) 372 | filenames.sort(key=lambda x: os.path.basename(x).lower()) 373 | if not filenames: 374 | filename = 'pip' 375 | else: 376 | filename = filenames[-1] 377 | easy_install_script = 'easy_install' 378 | if sys.platform == 'win32': 379 | easy_install_script = 'easy_install-script.py' 380 | cmd = [py_executable, join(os.path.dirname(py_executable), easy_install_script), filename] 381 | if filename == 'pip': 382 | logger.info('Installing pip from network...') 383 | else: 384 | logger.info('Installing %s' % os.path.basename(filename)) 385 | logger.indent += 2 386 | def _filter_setup(line): 387 | return filter_ez_setup(line, 'pip') 388 | try: 389 | call_subprocess(cmd, show_stdout=False, 390 | filter_stdout=_filter_setup) 391 | finally: 392 | logger.indent -= 2 393 | 394 | def filter_ez_setup(line, project_name='setuptools'): 395 | if not line.strip(): 396 | return Logger.DEBUG 397 | if project_name == 'distribute': 398 | for prefix in ('Extracting', 'Now working', 'Installing', 'Before', 399 | 'Scanning', 'Setuptools', 'Egg', 'Already', 400 | 'running', 'writing', 'reading', 'installing', 401 | 'creating', 'copying', 'byte-compiling', 'removing', 402 | 'Processing'): 403 | if line.startswith(prefix): 404 | return Logger.DEBUG 405 | return Logger.DEBUG 406 | for prefix in ['Reading ', 'Best match', 'Processing setuptools', 407 | 'Copying setuptools', 'Adding setuptools', 408 | 'Installing ', 'Installed ']: 409 | if line.startswith(prefix): 410 | return Logger.DEBUG 411 | return Logger.INFO 412 | 413 | def main(): 414 | parser = optparse.OptionParser( 415 | version=virtualenv_version, 416 | usage="%prog [OPTIONS] DEST_DIR") 417 | 418 | parser.add_option( 419 | '-v', '--verbose', 420 | action='count', 421 | dest='verbose', 422 | default=0, 423 | help="Increase verbosity") 424 | 425 | parser.add_option( 426 | '-q', '--quiet', 427 | action='count', 428 | dest='quiet', 429 | default=0, 430 | help='Decrease verbosity') 431 | 432 | parser.add_option( 433 | '-p', '--python', 434 | dest='python', 435 | metavar='PYTHON_EXE', 436 | help='The Python interpreter to use, e.g., --python=python2.5 will use the python2.5 ' 437 | 'interpreter to create the new environment. The default is the interpreter that ' 438 | 'virtualenv was installed with (%s)' % sys.executable) 439 | 440 | parser.add_option( 441 | '--clear', 442 | dest='clear', 443 | action='store_true', 444 | help="Clear out the non-root install and start from scratch") 445 | 446 | parser.add_option( 447 | '--no-site-packages', 448 | dest='no_site_packages', 449 | action='store_true', 450 | help="Don't give access to the global site-packages dir to the " 451 | "virtual environment") 452 | 453 | parser.add_option( 454 | '--unzip-setuptools', 455 | dest='unzip_setuptools', 456 | action='store_true', 457 | help="Unzip Setuptools or Distribute when installing it") 458 | 459 | parser.add_option( 460 | '--relocatable', 461 | dest='relocatable', 462 | action='store_true', 463 | help='Make an EXISTING virtualenv environment relocatable. ' 464 | 'This fixes up scripts and makes all .pth files relative') 465 | 466 | parser.add_option( 467 | '--distribute', 468 | dest='use_distribute', 469 | action='store_true', 470 | help='Use Distribute instead of Setuptools. Set environ variable' 471 | 'VIRTUALENV_USE_DISTRIBUTE to make it the default ') 472 | 473 | if 'extend_parser' in globals(): 474 | extend_parser(parser) 475 | 476 | options, args = parser.parse_args() 477 | 478 | global logger 479 | 480 | if 'adjust_options' in globals(): 481 | adjust_options(options, args) 482 | 483 | verbosity = options.verbose - options.quiet 484 | logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)]) 485 | 486 | if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'): 487 | env = os.environ.copy() 488 | interpreter = resolve_interpreter(options.python) 489 | if interpreter == sys.executable: 490 | logger.warn('Already using interpreter %s' % interpreter) 491 | else: 492 | logger.notify('Running virtualenv with interpreter %s' % interpreter) 493 | env['VIRTUALENV_INTERPRETER_RUNNING'] = 'true' 494 | file = __file__ 495 | if file.endswith('.pyc'): 496 | file = file[:-1] 497 | os.execvpe(interpreter, [interpreter, file] + sys.argv[1:], env) 498 | 499 | if not args: 500 | print 'You must provide a DEST_DIR' 501 | parser.print_help() 502 | sys.exit(2) 503 | if len(args) > 1: 504 | print 'There must be only one argument: DEST_DIR (you gave %s)' % ( 505 | ' '.join(args)) 506 | parser.print_help() 507 | sys.exit(2) 508 | 509 | home_dir = args[0] 510 | 511 | if os.environ.get('WORKING_ENV'): 512 | logger.fatal('ERROR: you cannot run virtualenv while in a workingenv') 513 | logger.fatal('Please deactivate your workingenv, then re-run this script') 514 | sys.exit(3) 515 | 516 | if 'PYTHONHOME' in os.environ: 517 | logger.warn('PYTHONHOME is set. You *must* activate the virtualenv before using it') 518 | del os.environ['PYTHONHOME'] 519 | 520 | if options.relocatable: 521 | make_environment_relocatable(home_dir) 522 | return 523 | 524 | create_environment(home_dir, site_packages=not options.no_site_packages, clear=options.clear, 525 | unzip_setuptools=options.unzip_setuptools, 526 | use_distribute=options.use_distribute) 527 | if 'after_install' in globals(): 528 | after_install(options, home_dir) 529 | 530 | def call_subprocess(cmd, show_stdout=True, 531 | filter_stdout=None, cwd=None, 532 | raise_on_returncode=True, extra_env=None): 533 | cmd_parts = [] 534 | for part in cmd: 535 | if len(part) > 40: 536 | part = part[:30]+"..."+part[-5:] 537 | if ' ' in part or '\n' in part or '"' in part or "'" in part: 538 | part = '"%s"' % part.replace('"', '\\"') 539 | cmd_parts.append(part) 540 | cmd_desc = ' '.join(cmd_parts) 541 | if show_stdout: 542 | stdout = None 543 | else: 544 | stdout = subprocess.PIPE 545 | logger.debug("Running command %s" % cmd_desc) 546 | if extra_env: 547 | env = os.environ.copy() 548 | env.update(extra_env) 549 | else: 550 | env = None 551 | try: 552 | proc = subprocess.Popen( 553 | cmd, stderr=subprocess.STDOUT, stdin=None, stdout=stdout, 554 | cwd=cwd, env=env) 555 | except Exception, e: 556 | logger.fatal( 557 | "Error %s while executing command %s" % (e, cmd_desc)) 558 | raise 559 | all_output = [] 560 | if stdout is not None: 561 | stdout = proc.stdout 562 | while 1: 563 | line = stdout.readline() 564 | if not line: 565 | break 566 | line = line.rstrip() 567 | all_output.append(line) 568 | if filter_stdout: 569 | level = filter_stdout(line) 570 | if isinstance(level, tuple): 571 | level, line = level 572 | logger.log(level, line) 573 | if not logger.stdout_level_matches(level): 574 | logger.show_progress() 575 | else: 576 | logger.info(line) 577 | else: 578 | proc.communicate() 579 | proc.wait() 580 | if proc.returncode: 581 | if raise_on_returncode: 582 | if all_output: 583 | logger.notify('Complete output from command %s:' % cmd_desc) 584 | logger.notify('\n'.join(all_output) + '\n----------------------------------------') 585 | raise OSError( 586 | "Command %s failed with error code %s" 587 | % (cmd_desc, proc.returncode)) 588 | else: 589 | logger.warn( 590 | "Command %s had error code %s" 591 | % (cmd_desc, proc.returncode)) 592 | 593 | 594 | def create_environment(home_dir, site_packages=True, clear=False, 595 | unzip_setuptools=False, use_distribute=False): 596 | """ 597 | Creates a new environment in ``home_dir``. 598 | 599 | If ``site_packages`` is true (the default) then the global 600 | ``site-packages/`` directory will be on the path. 601 | 602 | If ``clear`` is true (default False) then the environment will 603 | first be cleared. 604 | """ 605 | home_dir, lib_dir, inc_dir, bin_dir = path_locations(home_dir) 606 | 607 | py_executable = os.path.abspath(install_python( 608 | home_dir, lib_dir, inc_dir, bin_dir, 609 | site_packages=site_packages, clear=clear)) 610 | 611 | install_distutils(lib_dir, home_dir) 612 | 613 | if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'): 614 | install_distribute(py_executable, unzip=unzip_setuptools) 615 | else: 616 | install_setuptools(py_executable, unzip=unzip_setuptools) 617 | 618 | install_pip(py_executable) 619 | 620 | install_activate(home_dir, bin_dir) 621 | 622 | def path_locations(home_dir): 623 | """Return the path locations for the environment (where libraries are, 624 | where scripts go, etc)""" 625 | # XXX: We'd use distutils.sysconfig.get_python_inc/lib but its 626 | # prefix arg is broken: http://bugs.python.org/issue3386 627 | if sys.platform == 'win32': 628 | # Windows has lots of problems with executables with spaces in 629 | # the name; this function will remove them (using the ~1 630 | # format): 631 | mkdir(home_dir) 632 | if ' ' in home_dir: 633 | try: 634 | import win32api 635 | except ImportError: 636 | print 'Error: the path "%s" has a space in it' % home_dir 637 | print 'To handle these kinds of paths, the win32api module must be installed:' 638 | print ' http://sourceforge.net/projects/pywin32/' 639 | sys.exit(3) 640 | home_dir = win32api.GetShortPathName(home_dir) 641 | lib_dir = join(home_dir, 'Lib') 642 | inc_dir = join(home_dir, 'Include') 643 | bin_dir = join(home_dir, 'Scripts') 644 | elif is_jython: 645 | lib_dir = join(home_dir, 'Lib') 646 | inc_dir = join(home_dir, 'Include') 647 | bin_dir = join(home_dir, 'bin') 648 | else: 649 | lib_dir = join(home_dir, 'lib', py_version) 650 | inc_dir = join(home_dir, 'include', py_version) 651 | bin_dir = join(home_dir, 'bin') 652 | return home_dir, lib_dir, inc_dir, bin_dir 653 | 654 | def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear): 655 | """Install just the base environment, no distutils patches etc""" 656 | if sys.executable.startswith(bin_dir): 657 | print 'Please use the *system* python to run this script' 658 | return 659 | 660 | if clear: 661 | rmtree(lib_dir) 662 | ## FIXME: why not delete it? 663 | ## Maybe it should delete everything with #!/path/to/venv/python in it 664 | logger.notify('Not deleting %s', bin_dir) 665 | 666 | if hasattr(sys, 'real_prefix'): 667 | logger.notify('Using real prefix %r' % sys.real_prefix) 668 | prefix = sys.real_prefix 669 | else: 670 | prefix = sys.prefix 671 | mkdir(lib_dir) 672 | fix_lib64(lib_dir) 673 | stdlib_dirs = [os.path.dirname(os.__file__)] 674 | if sys.platform == 'win32': 675 | stdlib_dirs.append(join(os.path.dirname(stdlib_dirs[0]), 'DLLs')) 676 | elif sys.platform == 'darwin': 677 | stdlib_dirs.append(join(stdlib_dirs[0], 'site-packages')) 678 | for stdlib_dir in stdlib_dirs: 679 | if not os.path.isdir(stdlib_dir): 680 | continue 681 | if hasattr(os, 'symlink'): 682 | logger.info('Symlinking Python bootstrap modules') 683 | else: 684 | logger.info('Copying Python bootstrap modules') 685 | logger.indent += 2 686 | try: 687 | for fn in os.listdir(stdlib_dir): 688 | if fn != 'site-packages' and os.path.splitext(fn)[0] in REQUIRED_MODULES: 689 | copyfile(join(stdlib_dir, fn), join(lib_dir, fn)) 690 | finally: 691 | logger.indent -= 2 692 | mkdir(join(lib_dir, 'site-packages')) 693 | writefile(join(lib_dir, 'site.py'), SITE_PY) 694 | writefile(join(lib_dir, 'orig-prefix.txt'), prefix) 695 | site_packages_filename = join(lib_dir, 'no-global-site-packages.txt') 696 | if not site_packages: 697 | writefile(site_packages_filename, '') 698 | else: 699 | if os.path.exists(site_packages_filename): 700 | logger.info('Deleting %s' % site_packages_filename) 701 | os.unlink(site_packages_filename) 702 | 703 | stdinc_dir = join(prefix, 'include', py_version) 704 | if os.path.exists(stdinc_dir): 705 | copyfile(stdinc_dir, inc_dir) 706 | else: 707 | logger.debug('No include dir %s' % stdinc_dir) 708 | 709 | if sys.exec_prefix != prefix: 710 | if sys.platform == 'win32': 711 | exec_dir = join(sys.exec_prefix, 'lib') 712 | elif is_jython: 713 | exec_dir = join(sys.exec_prefix, 'Lib') 714 | else: 715 | exec_dir = join(sys.exec_prefix, 'lib', py_version) 716 | for fn in os.listdir(exec_dir): 717 | copyfile(join(exec_dir, fn), join(lib_dir, fn)) 718 | 719 | if is_jython: 720 | # Jython has either jython-dev.jar and javalib/ dir, or just 721 | # jython.jar 722 | for name in 'jython-dev.jar', 'javalib', 'jython.jar': 723 | src = join(prefix, name) 724 | if os.path.exists(src): 725 | copyfile(src, join(home_dir, name)) 726 | # XXX: registry should always exist after Jython 2.5rc1 727 | src = join(prefix, 'registry') 728 | if os.path.exists(src): 729 | copyfile(src, join(home_dir, 'registry'), symlink=False) 730 | copyfile(join(prefix, 'cachedir'), join(home_dir, 'cachedir'), 731 | symlink=False) 732 | 733 | mkdir(bin_dir) 734 | py_executable = join(bin_dir, os.path.basename(sys.executable)) 735 | if 'Python.framework' in prefix: 736 | if re.search(r'/Python(?:-32|-64)*$', py_executable): 737 | # The name of the python executable is not quite what 738 | # we want, rename it. 739 | py_executable = os.path.join( 740 | os.path.dirname(py_executable), 'python') 741 | 742 | logger.notify('New %s executable in %s', expected_exe, py_executable) 743 | if sys.executable != py_executable: 744 | ## FIXME: could I just hard link? 745 | executable = sys.executable 746 | if sys.platform == 'cygwin' and os.path.exists(executable + '.exe'): 747 | # Cygwin misreports sys.executable sometimes 748 | executable += '.exe' 749 | py_executable += '.exe' 750 | logger.info('Executable actually exists in %s' % executable) 751 | shutil.copyfile(executable, py_executable) 752 | make_exe(py_executable) 753 | if sys.platform == 'win32' or sys.platform == 'cygwin': 754 | pythonw = os.path.join(os.path.dirname(sys.executable), 'pythonw.exe') 755 | if os.path.exists(pythonw): 756 | logger.info('Also created pythonw.exe') 757 | shutil.copyfile(pythonw, os.path.join(os.path.dirname(py_executable), 'pythonw.exe')) 758 | 759 | if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe: 760 | secondary_exe = os.path.join(os.path.dirname(py_executable), 761 | expected_exe) 762 | py_executable_ext = os.path.splitext(py_executable)[1] 763 | if py_executable_ext == '.exe': 764 | # python2.4 gives an extension of '.4' :P 765 | secondary_exe += py_executable_ext 766 | if os.path.exists(secondary_exe): 767 | logger.warn('Not overwriting existing %s script %s (you must use %s)' 768 | % (expected_exe, secondary_exe, py_executable)) 769 | else: 770 | logger.notify('Also creating executable in %s' % secondary_exe) 771 | shutil.copyfile(sys.executable, secondary_exe) 772 | make_exe(secondary_exe) 773 | 774 | if 'Python.framework' in prefix: 775 | logger.debug('MacOSX Python framework detected') 776 | 777 | # Make sure we use the the embedded interpreter inside 778 | # the framework, even if sys.executable points to 779 | # the stub executable in ${sys.prefix}/bin 780 | # See http://groups.google.com/group/python-virtualenv/ 781 | # browse_thread/thread/17cab2f85da75951 782 | shutil.copy( 783 | os.path.join( 784 | prefix, 'Resources/Python.app/Contents/MacOS/%s' % os.path.basename(sys.executable)), 785 | py_executable) 786 | 787 | # Copy the framework's dylib into the virtual 788 | # environment 789 | virtual_lib = os.path.join(home_dir, '.Python') 790 | 791 | if os.path.exists(virtual_lib): 792 | os.unlink(virtual_lib) 793 | copyfile( 794 | os.path.join(prefix, 'Python'), 795 | virtual_lib) 796 | 797 | # And then change the install_name of the copied python executable 798 | try: 799 | call_subprocess( 800 | ["install_name_tool", "-change", 801 | os.path.join(prefix, 'Python'), 802 | '@executable_path/../.Python', 803 | py_executable]) 804 | except: 805 | logger.fatal( 806 | "Could not call install_name_tool -- you must have Apple's development tools installed") 807 | raise 808 | 809 | # Some tools depend on pythonX.Y being present 810 | py_executable_version = '%s.%s' % ( 811 | sys.version_info[0], sys.version_info[1]) 812 | if not py_executable.endswith(py_executable_version): 813 | # symlinking pythonX.Y > python 814 | pth = py_executable + '%s.%s' % ( 815 | sys.version_info[0], sys.version_info[1]) 816 | if os.path.exists(pth): 817 | os.unlink(pth) 818 | os.symlink('python', pth) 819 | else: 820 | # reverse symlinking python -> pythonX.Y (with --python) 821 | pth = join(bin_dir, 'python') 822 | if os.path.exists(pth): 823 | os.unlink(pth) 824 | os.symlink(os.path.basename(py_executable), pth) 825 | 826 | if sys.platform == 'win32' and ' ' in py_executable: 827 | # There's a bug with subprocess on Windows when using a first 828 | # argument that has a space in it. Instead we have to quote 829 | # the value: 830 | py_executable = '"%s"' % py_executable 831 | cmd = [py_executable, '-c', 'import sys; print sys.prefix'] 832 | logger.info('Testing executable with %s %s "%s"' % tuple(cmd)) 833 | proc = subprocess.Popen(cmd, 834 | stdout=subprocess.PIPE) 835 | proc_stdout, proc_stderr = proc.communicate() 836 | proc_stdout = os.path.normcase(os.path.abspath(proc_stdout.strip())) 837 | if proc_stdout != os.path.normcase(os.path.abspath(home_dir)): 838 | logger.fatal( 839 | 'ERROR: The executable %s is not functioning' % py_executable) 840 | logger.fatal( 841 | 'ERROR: It thinks sys.prefix is %r (should be %r)' 842 | % (proc_stdout, os.path.normcase(os.path.abspath(home_dir)))) 843 | logger.fatal( 844 | 'ERROR: virtualenv is not compatible with this system or executable') 845 | if sys.platform == 'win32': 846 | logger.fatal( 847 | 'Note: some Windows users have reported this error when they installed Python for "Only this user". The problem may be resolvable if you install Python "For all users". (See https://bugs.launchpad.net/virtualenv/+bug/352844)') 848 | sys.exit(100) 849 | else: 850 | logger.info('Got sys.prefix result: %r' % proc_stdout) 851 | 852 | pydistutils = os.path.expanduser('~/.pydistutils.cfg') 853 | if os.path.exists(pydistutils): 854 | logger.notify('Please make sure you remove any previous custom paths from ' 855 | 'your %s file.' % pydistutils) 856 | ## FIXME: really this should be calculated earlier 857 | return py_executable 858 | 859 | def install_activate(home_dir, bin_dir): 860 | if sys.platform == 'win32' or is_jython and os._name == 'nt': 861 | files = {'activate.bat': ACTIVATE_BAT, 862 | 'deactivate.bat': DEACTIVATE_BAT} 863 | if os.environ.get('OS') == 'Windows_NT' and os.environ.get('OSTYPE') == 'cygwin': 864 | files['activate'] = ACTIVATE_SH 865 | else: 866 | files = {'activate': ACTIVATE_SH} 867 | files['activate_this.py'] = ACTIVATE_THIS 868 | for name, content in files.items(): 869 | content = content.replace('__VIRTUAL_ENV__', os.path.abspath(home_dir)) 870 | content = content.replace('__VIRTUAL_NAME__', os.path.basename(os.path.abspath(home_dir))) 871 | content = content.replace('__BIN_NAME__', os.path.basename(bin_dir)) 872 | writefile(os.path.join(bin_dir, name), content) 873 | 874 | def install_distutils(lib_dir, home_dir): 875 | distutils_path = os.path.join(lib_dir, 'distutils') 876 | mkdir(distutils_path) 877 | ## FIXME: maybe this prefix setting should only be put in place if 878 | ## there's a local distutils.cfg with a prefix setting? 879 | home_dir = os.path.abspath(home_dir) 880 | ## FIXME: this is breaking things, removing for now: 881 | #distutils_cfg = DISTUTILS_CFG + "\n[install]\nprefix=%s\n" % home_dir 882 | writefile(os.path.join(distutils_path, '__init__.py'), DISTUTILS_INIT) 883 | writefile(os.path.join(distutils_path, 'distutils.cfg'), DISTUTILS_CFG, overwrite=False) 884 | 885 | def fix_lib64(lib_dir): 886 | """ 887 | Some platforms (particularly Gentoo on x64) put things in lib64/pythonX.Y 888 | instead of lib/pythonX.Y. If this is such a platform we'll just create a 889 | symlink so lib64 points to lib 890 | """ 891 | if [p for p in distutils.sysconfig.get_config_vars().values() 892 | if isinstance(p, basestring) and 'lib64' in p]: 893 | logger.debug('This system uses lib64; symlinking lib64 to lib') 894 | assert os.path.basename(lib_dir) == 'python%s' % sys.version[:3], ( 895 | "Unexpected python lib dir: %r" % lib_dir) 896 | lib_parent = os.path.dirname(lib_dir) 897 | assert os.path.basename(lib_parent) == 'lib', ( 898 | "Unexpected parent dir: %r" % lib_parent) 899 | copyfile(lib_parent, os.path.join(os.path.dirname(lib_parent), 'lib64')) 900 | 901 | def resolve_interpreter(exe): 902 | """ 903 | If the executable given isn't an absolute path, search $PATH for the interpreter 904 | """ 905 | if os.path.abspath(exe) != exe: 906 | paths = os.environ.get('PATH', '').split(os.pathsep) 907 | for path in paths: 908 | if os.path.exists(os.path.join(path, exe)): 909 | exe = os.path.join(path, exe) 910 | break 911 | if not os.path.exists(exe): 912 | logger.fatal('The executable %s (from --python=%s) does not exist' % (exe, exe)) 913 | sys.exit(3) 914 | return exe 915 | 916 | ############################################################ 917 | ## Relocating the environment: 918 | 919 | def make_environment_relocatable(home_dir): 920 | """ 921 | Makes the already-existing environment use relative paths, and takes out 922 | the #!-based environment selection in scripts. 923 | """ 924 | activate_this = os.path.join(home_dir, 'bin', 'activate_this.py') 925 | if not os.path.exists(activate_this): 926 | logger.fatal( 927 | 'The environment doesn\'t have a file %s -- please re-run virtualenv ' 928 | 'on this environment to update it' % activate_this) 929 | fixup_scripts(home_dir) 930 | fixup_pth_and_egg_link(home_dir) 931 | ## FIXME: need to fix up distutils.cfg 932 | 933 | OK_ABS_SCRIPTS = ['python', 'python%s' % sys.version[:3], 934 | 'activate', 'activate.bat', 'activate_this.py'] 935 | 936 | def fixup_scripts(home_dir): 937 | # This is what we expect at the top of scripts: 938 | shebang = '#!%s/bin/python' % os.path.normcase(os.path.abspath(home_dir)) 939 | # This is what we'll put: 940 | new_shebang = '#!/usr/bin/env python%s' % sys.version[:3] 941 | activate = "import os; activate_this=os.path.join(os.path.dirname(__file__), 'activate_this.py'); execfile(activate_this, dict(__file__=activate_this)); del os, activate_this" 942 | bin_dir = os.path.join(home_dir, 'bin') 943 | for filename in os.listdir(bin_dir): 944 | filename = os.path.join(bin_dir, filename) 945 | if not os.path.isfile(filename): 946 | # ignore subdirs, e.g. .svn ones. 947 | continue 948 | f = open(filename, 'rb') 949 | lines = f.readlines() 950 | f.close() 951 | if not lines: 952 | logger.warn('Script %s is an empty file' % filename) 953 | continue 954 | if not lines[0].strip().startswith(shebang): 955 | if os.path.basename(filename) in OK_ABS_SCRIPTS: 956 | logger.debug('Cannot make script %s relative' % filename) 957 | elif lines[0].strip() == new_shebang: 958 | logger.info('Script %s has already been made relative' % filename) 959 | else: 960 | logger.warn('Script %s cannot be made relative (it\'s not a normal script that starts with %s)' 961 | % (filename, shebang)) 962 | continue 963 | logger.notify('Making script %s relative' % filename) 964 | lines = [new_shebang+'\n', activate+'\n'] + lines[1:] 965 | f = open(filename, 'wb') 966 | f.writelines(lines) 967 | f.close() 968 | 969 | def fixup_pth_and_egg_link(home_dir, sys_path=None): 970 | """Makes .pth and .egg-link files use relative paths""" 971 | home_dir = os.path.normcase(os.path.abspath(home_dir)) 972 | if sys_path is None: 973 | sys_path = sys.path 974 | for path in sys_path: 975 | if not path: 976 | path = '.' 977 | if not os.path.isdir(path): 978 | continue 979 | path = os.path.normcase(os.path.abspath(path)) 980 | if not path.startswith(home_dir): 981 | logger.debug('Skipping system (non-environment) directory %s' % path) 982 | continue 983 | for filename in os.listdir(path): 984 | filename = os.path.join(path, filename) 985 | if filename.endswith('.pth'): 986 | if not os.access(filename, os.W_OK): 987 | logger.warn('Cannot write .pth file %s, skipping' % filename) 988 | else: 989 | fixup_pth_file(filename) 990 | if filename.endswith('.egg-link'): 991 | if not os.access(filename, os.W_OK): 992 | logger.warn('Cannot write .egg-link file %s, skipping' % filename) 993 | else: 994 | fixup_egg_link(filename) 995 | 996 | def fixup_pth_file(filename): 997 | lines = [] 998 | prev_lines = [] 999 | f = open(filename) 1000 | prev_lines = f.readlines() 1001 | f.close() 1002 | for line in prev_lines: 1003 | line = line.strip() 1004 | if (not line or line.startswith('#') or line.startswith('import ') 1005 | or os.path.abspath(line) != line): 1006 | lines.append(line) 1007 | else: 1008 | new_value = make_relative_path(filename, line) 1009 | if line != new_value: 1010 | logger.debug('Rewriting path %s as %s (in %s)' % (line, new_value, filename)) 1011 | lines.append(new_value) 1012 | if lines == prev_lines: 1013 | logger.info('No changes to .pth file %s' % filename) 1014 | return 1015 | logger.notify('Making paths in .pth file %s relative' % filename) 1016 | f = open(filename, 'w') 1017 | f.write('\n'.join(lines) + '\n') 1018 | f.close() 1019 | 1020 | def fixup_egg_link(filename): 1021 | f = open(filename) 1022 | link = f.read().strip() 1023 | f.close() 1024 | if os.path.abspath(link) != link: 1025 | logger.debug('Link in %s already relative' % filename) 1026 | return 1027 | new_link = make_relative_path(filename, link) 1028 | logger.notify('Rewriting link %s in %s as %s' % (link, filename, new_link)) 1029 | f = open(filename, 'w') 1030 | f.write(new_link) 1031 | f.close() 1032 | 1033 | def make_relative_path(source, dest, dest_is_directory=True): 1034 | """ 1035 | Make a filename relative, where the filename is dest, and it is 1036 | being referred to from the filename source. 1037 | 1038 | >>> make_relative_path('/usr/share/something/a-file.pth', 1039 | ... '/usr/share/another-place/src/Directory') 1040 | '../another-place/src/Directory' 1041 | >>> make_relative_path('/usr/share/something/a-file.pth', 1042 | ... '/home/user/src/Directory') 1043 | '../../../home/user/src/Directory' 1044 | >>> make_relative_path('/usr/share/a-file.pth', '/usr/share/') 1045 | './' 1046 | """ 1047 | source = os.path.dirname(source) 1048 | if not dest_is_directory: 1049 | dest_filename = os.path.basename(dest) 1050 | dest = os.path.dirname(dest) 1051 | dest = os.path.normpath(os.path.abspath(dest)) 1052 | source = os.path.normpath(os.path.abspath(source)) 1053 | dest_parts = dest.strip(os.path.sep).split(os.path.sep) 1054 | source_parts = source.strip(os.path.sep).split(os.path.sep) 1055 | while dest_parts and source_parts and dest_parts[0] == source_parts[0]: 1056 | dest_parts.pop(0) 1057 | source_parts.pop(0) 1058 | full_parts = ['..']*len(source_parts) + dest_parts 1059 | if not dest_is_directory: 1060 | full_parts.append(dest_filename) 1061 | if not full_parts: 1062 | # Special case for the current directory (otherwise it'd be '') 1063 | return './' 1064 | return os.path.sep.join(full_parts) 1065 | 1066 | 1067 | 1068 | ############################################################ 1069 | ## Bootstrap script creation: 1070 | 1071 | def create_bootstrap_script(extra_text, python_version=''): 1072 | """ 1073 | Creates a bootstrap script, which is like this script but with 1074 | extend_parser, adjust_options, and after_install hooks. 1075 | 1076 | This returns a string that (written to disk of course) can be used 1077 | as a bootstrap script with your own customizations. The script 1078 | will be the standard virtualenv.py script, with your extra text 1079 | added (your extra text should be Python code). 1080 | 1081 | If you include these functions, they will be called: 1082 | 1083 | ``extend_parser(optparse_parser)``: 1084 | You can add or remove options from the parser here. 1085 | 1086 | ``adjust_options(options, args)``: 1087 | You can change options here, or change the args (if you accept 1088 | different kinds of arguments, be sure you modify ``args`` so it is 1089 | only ``[DEST_DIR]``). 1090 | 1091 | ``after_install(options, home_dir)``: 1092 | 1093 | After everything is installed, this function is called. This 1094 | is probably the function you are most likely to use. An 1095 | example would be:: 1096 | 1097 | def after_install(options, home_dir): 1098 | subprocess.call([join(home_dir, 'bin', 'easy_install'), 1099 | 'MyPackage']) 1100 | subprocess.call([join(home_dir, 'bin', 'my-package-script'), 1101 | 'setup', home_dir]) 1102 | 1103 | This example immediately installs a package, and runs a setup 1104 | script from that package. 1105 | 1106 | If you provide something like ``python_version='2.4'`` then the 1107 | script will start with ``#!/usr/bin/env python2.4`` instead of 1108 | ``#!/usr/bin/env python``. You can use this when the script must 1109 | be run with a particular Python version. 1110 | """ 1111 | filename = __file__ 1112 | if filename.endswith('.pyc'): 1113 | filename = filename[:-1] 1114 | f = open(filename, 'rb') 1115 | content = f.read() 1116 | f.close() 1117 | py_exe = 'python%s' % python_version 1118 | content = (('#!/usr/bin/env %s\n' % py_exe) 1119 | + '## WARNING: This file is generated\n' 1120 | + content) 1121 | return content.replace('##EXT' 'END##', extra_text) 1122 | 1123 | ##EXTEND## 1124 | 1125 | ##file site.py 1126 | SITE_PY = """ 1127 | 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 1257 | yBXo8FFND74JkgILcmKn2vJbYxD8H2/QG9E= 1258 | """.decode("base64").decode("zlib") 1259 | 1260 | ##file ez_setup.py 1261 | EZ_SETUP_PY = """ 1262 | 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 1328 | 178BYnMUkw== 1329 | """.decode("base64").decode("zlib") 1330 | 1331 | ##file distribute_setup.py 1332 | DISTRIBUTE_SETUP_PY = """ 1333 | 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 1410 | """.decode("base64").decode("zlib") 1411 | 1412 | ##file activate.sh 1413 | ACTIVATE_SH = """ 1414 | eJytVFFv2jAQfs+vuIU+QDWK+tqKB6oigdRC1bBOW1sZk1yIpWAj2yGj0/77ziFAUijStPIA2Hc+ 1415 | f/7u+64Bk0QYiEWKsMiMhRlCZjCCXNgEfKMyHSLMhOzw0IoVt+jDeazVAmbcJOdeA9Yqg5BLqSzo 1416 | TIKwEAmNoU3Xnhfh9hQ0W/DbA/o0QKNBCyqNAOVKaCUXKC2suBZ8lqIpskQMz9CW4J+x8d0texo+ 1417 | Tr717thDbzLw4RWuwSYoi0z3cdvdY6m7DPy1VNoWibu9TDocB4eKeCxOwvgxGYxHg/F9/xiYXfAA 1418 | 0v7YAbBd6CS8ehaBLCktmmgSlRGpEVqiv+gPcBnBm0m+Qp6IMIGErxA4/VAoVIuFC9uE26L1ZSkS 1419 | QMjTlCRgFcwJAXWU/sVKu8WSk0bKo+YC4DvJRGW2DFsh52WZWqIjCM4cuRAmXM7RQE5645H7WoPT 1420 | Dl1LulgScozeUX/TC6jpbbVZ/QwG7Kn/GAzHoyPkF09r6xo9HzUxuDzWveDyoG2UeNCv4PJko8rw 1421 | FsImZRvtj572wL4QLgLSBV8qGaGxOnOewXfYGhBgGsM24cu729sutDXb9uo/HvlzExdaY0rdrxmt 1422 | Ys/63Z5Xgdr1GassGfO9koTqe7wDHxGNGw+Wi0p2h7Gb4YiNevd9xq7KtKpFd7j3inds0Q5FrBN7 1423 | LtIUYi5St1/NMi7LKdZpDhdLuwZ6FwkTmhsTUMaMR2SNdc7XLaoXFrahqQdTqtUs6Myu4YoUu6vb 1424 | guspCFm4ytsL6sNB8IFtu7UjFWlUnO00s7nhDWqssdth0Lu567OHx/H9w+TkjYWKd8ItyvlTAo+S 1425 | LxBeanVf/GmhP+rsoR8a4EwpeEpTgRgin0OPdiQZdy7CctYrLcq5XR5BhMTa5VWnk+f5xRtasvrq 1426 | gsZBx6jY5lxjh7sqnbrvnisQp1T6KNiX6fQV9m/D1GC9SvPEQ1v7g+WIrxjaMf9Js/QT5uh/ztB/ 1427 | n5/b2Uk0/AXm/2MV 1428 | """.decode("base64").decode("zlib") 1429 | 1430 | ##file activate.bat 1431 | ACTIVATE_BAT = """ 1432 | eJyFUssKgzAQvAfyD3swYH+hItSiVKlGsalQKOyhauvFHOr/U+MzFcWc9jEzO7vkVLw+EmRZUvIt 1433 | GsiCVNydED2e2YhahkgJJVUJtWwgL8qqLnJI0jhKBJiUQPsUv6/YRmJcKDkMlBGOcehOmptctgJj 1434 | e2IP4cfcjyNvFOwVp/JSdWqMygq+MthmkwHNojmfhjuRh3iAGffncsPYhpl2mm5sbY+9QzjC7ylt 1435 | sFy6LTEL3rKRcLsGicrXV++4HVz1jzN4Vta+BnsingM+nMLSiB53KfkBsnmnEA== 1436 | """.decode("base64").decode("zlib") 1437 | 1438 | ##file deactivate.bat 1439 | DEACTIVATE_BAT = """ 1440 | eJxzSE3OyFfIT0vj4spMU0hJTcvMS01RiPf3cYkP8wwKCXX0iQ8I8vcNCFHQ4FIAguLUEgWIgK0q 1441 | FlWqXJpcICVYpGzx2BAZ4uHv5+Hv6wq1BWINXBTdKriEKkI1DhW2QAfhttcxxANiFZCBbglQSJUL 1442 | i2dASrm4rFz9XLgAwJNbyQ== 1443 | """.decode("base64").decode("zlib") 1444 | 1445 | ##file distutils-init.py 1446 | DISTUTILS_INIT = """ 1447 | eJytVl2L6zYQffevGBKK7XavKe3bhVBo78uFSyml0IdlEVpbTtR1JCMpm6S/vjOSY0v+uO1DDbs4 1448 | 0tF8nJk5sjz32jjQNpPhzd7H1ys3SqqjhcfCL1q18vgbN1YY2Kc/pQWlHXB4l8ZdeCfUO5x1c+nE 1449 | E1gNVwE1V3CxAqQDp6GVqgF3EmBd08nXLGukUfws4IDBVD13p2pYoS3rLk52ltF6hPhLS1XM4EUc 1450 | VsVYKzvBWPkE+WgmLzPZjkaUNmd6KVI3JRwWoRSLM6P98mMG+Dw4q+il8Ev07P7ATCNmRlfQ8/qN 1451 | HwVwB99Y4H0vMHAi6BWZUoEhoqXTNXdSK+A2LN6tE+fJ0E+7MhOdFSEM5lNgrJIKWXDF908wy87D 1452 | xE3UoHsxkegZTaHIHGNSSYfm+ntelpURvCnK7NEWBI/ap/b8Z1m232N2rj7B60V2DRM3B5NpaLSw 1453 | KnfwpvQVTviHOR+F88lhQyBAGlE7be6DoRNg9ldsG3218IHa6MRNU+tGBEYIggwafRk6yzsXDcVU 1454 | 9Ua08kYxt+F3x12LRaQi52j0xx/ywFxrdMRqVevzmaummlIYEp0WsCAaX8cFb6buuLUTqEgQQ6/Q 1455 | 04iWRoF38m/BdE8VtlBY0bURiB6KG1crpMZwc2fIjqWh+1UrkSLpWUIP8PySwLKv4qPGSVqDuMPy 1456 | dywQ+gS7L1irXVkm5pJsq3l+Ib1lMOvUrxI+/mBBY4KB+WpUtcO06RtzckNvQ6vYj1lGoZM2sdDG 1457 | fryJPYJVn/Cfka8XSqNaoLKhmOlqXMzW9+YBVp1EtIThZtOwzCRvMaARa+0xD0b2kcaJGwJsMbc7 1458 | hLUfY4vKvsCOBdvDnyfuRbzmXRdGTZgPF7oGQkJACWVD22IMQdhx0npt5S2f+pXO+OwH6d+hwiS5 1459 | 7IJOjcK2emj1zBy1aONHByfAMoraw6WlrSIFTbGghqASoRCjVncYROFpXM4uYSqhGnuVeGvks4jz 1460 | cjnCoR5GnPW7KOh4maVbdFeoplgJ3wh3MSrAsv/QuMjOspnTKRl1fTYqqNisv7uTVnhF1GhoBFbp 1461 | lh+OcXN2riA5ZrYXtWxlfcDuC8U5kLoN3CCJYXGpesO6dx6rU0zGMtjU6cNlmW0Fid8Sja4ZG+Z3 1462 | fTPbyj+mZnZ2wSQK8RaT9Km0ySRuLpm0DkUUL0ra3WQ2BgGJ7v9I9SKqNKZ/IR4R28RHm+vEz5ic 1463 | nZ2IH7bfub8pU1PR3gr10W7xLTfHh6Z6bgZ7K14G7Mj/1z5J6MFo6V5e07H0Ou78dTyeI+mxKOpI 1464 | eC2KMSj6HKxd6Uudf/n886fPv+f++x1lbASlmjQuPz8OvGA0j7j2eCu/4bcW6SFeCuNJ0W1GQHI5 1465 | iwC9Ey0bjtHd9P4dPA++XxLnZDVuxvFEtlm3lf5a2c02u2LRYXHH/AOs8pIa 1466 | """.decode("base64").decode("zlib") 1467 | 1468 | ##file distutils.cfg 1469 | DISTUTILS_CFG = """ 1470 | eJxNj00KwkAMhfc9xYNuxe4Ft57AjYiUtDO1wXSmNJnK3N5pdSEEAu8nH6lxHVlRhtDHMPATA4uH 1471 | xJ4EFmGbvfJiicSHFRzUSISMY6hq3GLCRLnIvSTnEefN0FIjw5tF0Hkk9Q5dRunBsVoyFi24aaLg 1472 | 9FDOlL0FPGluf4QjcInLlxd6f6rqkgPu/5nHLg0cXCscXoozRrP51DRT3j9QNl99AP53T2Q= 1473 | """.decode("base64").decode("zlib") 1474 | 1475 | ##file activate_this.py 1476 | ACTIVATE_THIS = """ 1477 | eJyNUk2L3DAMvftXiCxLEphmSvc2MIcu9NaWHnopwxCcRNlRN7GD7clM/n0lp5mPZQs1JLb8pKcn 1478 | WUmSPE9w9GReAM9Yt9RhFg7kSzmtoKE6ZGU0ynJ7AfIcJnuEE3Wd0nWgUQcEQWEkF466QzMCf+Ss 1479 | 6dGEQqmfgtbaQIWcDxs4HdBElv7og1wBg3gmH0TMjykcrAEyAd3gkP8rMDaocMDbHBWZ9RBdVZIk 1480 | SgU3bRTwWjQrPNc4BPiue/zinHUz7DRxws/eowtkTUSyiMhKfi2y3NHMdXX0itcOpYMOh3Ww61g8 1481 | luJSDFP6tmH3ftyki2eeJ7mifrAugJ/8crReqUqztC0fC4kuGnKGxWf/snXlZb8kzXMmboW0GDod 1482 | Wut62G4hPZF5+pTO5XtiKYOuX/UL+ptcvy2ZTPKvIP1KFdeTiuuHxTXNFXYe/5+km0nmJ3r0KTxG 1483 | YSM6z23fbZ7276Tg9x5LdiuFjok7noks1sP2tWscpeRX6KaRnRuT3WnKlQQ51F3JlC2dmSvSRENd 1484 | j3wvetUDfLOjDDLPYtPwjDJb7yHYeNXyMPMLtdEQKRtl8HQrdLdX3O4YxZP7RvfcNH6ZCPMsi8td 1485 | qZvLAN7yFnoY0DSZhOUXj4WWy+tZ8190ud1tPu5Zzy2N+gOGaVfA 1486 | """.decode("base64").decode("zlib") 1487 | 1488 | if __name__ == '__main__': 1489 | main() 1490 | 1491 | ## TODO: 1492 | ## Copy python.exe.manifest 1493 | ## Monkeypatch distutils.sysconfig 1494 | --------------------------------------------------------------------------------