From: admin Date: Tue, 17 May 2016 15:30:59 +0000 (+0800) Subject: Python-support Source Code X-Git-Tag: submit/trunk/20200612.182210~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fheads%2Fspin-release-latest;p=tools%2Fpython-support.git Python-support Source Code --- diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..2d2d780 --- /dev/null +++ b/COPYING @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/README b/README new file mode 100644 index 0000000..d12cd16 --- /dev/null +++ b/README @@ -0,0 +1,225 @@ +Python-support is a tool to handle byte-compilation of python modules +when there are several python versions installed on the system. + +QUICK GUIDE FOR MAINTAINERS +=========================== + + * If necessary, describe the supported versions in debian/pyversions. + * If your package is arch-all: + - Build it using its standard build system. + - Build-depend on python and python-support. + * If your package is arch-any: + - Build it once for every supported Python version (loop over + `pyversions -vr`). + - Build-depend on python-all-dev and python-support. + * Install files to the *standard* locations. + * Call dh_pysupport in the binary-* target. + * Add ${python:Depends} to the dependencies. + +And that’s all. Anything else is likely superfluous. If your package +works correctly by doing that (and this is the case of 99% packages), +you can stop reading this file here. + + +How does it work? +================= +Python-support looks for modules in /usr/share/python-support. + * Private modules (.py files that shouldn't be installed in the default + sys.path) are handled through a foo.private file, which contains a list + of files to bytecompile. If the header of the foo.private file contains + a "pyversion=..." field, they will be bytecompiled with the Python + version described here, otherwise the current Python version will be + used. + * Public modules (.py files that should be installed in the default + sys.path) are handled through a foo.public file, which contains a + list of files to install. The files are normally installed in + /usr/share/pyshared/. They will be installed and bytecompiled in each + Python specific directory: /usr/lib/pymodules/pythonX.Y/. If the header + of the foo.public file contains a "pyversions=..." field, it will be + parsed for the list of python versions the module supports. It should + look like e.g.: + 2.2,2.4- + for a package supporting python2.2, and all versions starting from + python2.4. + * Public extensions (.so files) are handled just like public modules: + they are listed in the foo.public file. However, extensions for each + pythonX.Y will be located in /usr/lib/pyshared/pythonX.Y/, while they + are installed in /usr/lib/pymodules/pythonX.Y together with the + corresponding modules. + +How to make a package using it? +=============================== +All the work is done using dh_pysupport. For most packages, using the +standard build system then calling dh_pysupport should be enough. +However, if the package builds binary extensions, it should be changed +to build the extensions for all python versions in a single package. +While not mandatory, it is highly recommended. + +*** You don't need X[BS]-Python-Version fields. You don't need *** +*** debian/pycompat. You don't need to call dh_python after *** +*** dh_pysupport. Just remove all of these. *** + +Of course, don't forget the dependency fields: + Build-Depends: python-support (>= 0.90), debhelper(>= 5) + Depends: ${python:Depends} + +If you're including public modules or extensions *and* if some other +packages are expected to need them for a specific (non-default) Python +version, you can also add the field: + Provides: ${python:Provides} + +However, if you do that, you need to be very careful. Especially, if +you're depending on another python module, you should not declare it in +the Depends field, but like this: + Python-Depends: python-bar (>= some.version) +The appropriate dependencies on python2.X-bar will automatically be +added. + + For a package with only private modules + --------------------------------------- +In this case, the rules file will probably look like this: + +build: + make ... + +install: + make install DESTDIR=debian/foo/ + +binary-indep: + ... + dh_pysupport + dh_installdeb + ... + +If the private modules are not in a default directory (like +/usr/share/$package or /usr/lib/$package) you should pass the directory +to dh_pysupport: + dh_pysupport /usr/share/someframework/foo + +If the modules need a specific python version (like e.g. for Zope), you can +pass the -V argument to dh_pysupport. + dh_pysupport -V2.4 + + For a package with public modules + --------------------------------- +If the module doesn't work with all python versions, you should setup a +debian/pyversions file. If the package needs python >= 2.3, it will look +like : + 2.3- + +The rules file will look like this: + +build: + ... + python setup.py build + +install: + ... + python setup.py install --root=$(CURDIR)/debian/python-foo + +binary-indep: + ... + dh_pysupport + dh_installdeb + ... + + For a package with public C extensions: + --------------------------------------- +First of all, you should build-depend on python-all-dev. + +If you want to build the extension only for some python versions, you +should create a debian/pyversions file as described earlier, and set in +the rules file: +PYVERS=$(shell pyversions -vr) +You need to build-depend on python (>= 2.3.5-11) for this to work. + +Otherwise, you can just build the extensions for all supported python +versions: +PYVERS=$(shell pyversions -vs) + +The rest of the rules file will look like: + +build: $(PYVERS:%=build-python%) + touch $@ +build-python%: + python$* setup.py build + touch $@ + +install: build $(PYVERS:%=install-python%) +install-python%: + python$* setup.py install --root $(CURDIR)/debian/python-foo + +binary-arch: + ... + dh_pysupport + dh_installdeb + ... + +Specific cases +============== + Packages hardcoding the path to their modules + --------------------------------------------- +Some packages installing their modules in /usr/lib/python2.X expect +to find them explicitly at that place at runtime. Fortunately this is +uncommon as distutils doesn't allow that, but in this case the module +will stop functioning with python-support. The solution is to install +the files explicitly to /usr/lib/pymodules. Python-support will then +automatically move them to the appropriate place. + +build-%/configure-stamp: + mkdir build-$* + cd build-$* && PYTHON=/usr/bin/python$* ../configure --prefix=/usr + touch $@ + +build: $(PYVERS:%=build-%/build-stamp) +build-%/build-stamp: build-%/configure-stamp + $(MAKE) -C build-$* pyexecdir=/usr/lib/pymodules/python$* + touch $@ + +install: build $(PYVERS:%=install-%) +install-%: build-%/build-stamp + $(MAKE) -C build-$* install pyexecdir=/usr/lib/pymodules/python$* DESTDIR=$(CURDIR)/debian/tmp + +binary-arch: + ... + dh_pysupport + dh_installdeb + + Namespace packages + ------------------ +Namespace packages are empty __init__.py files that are necessary for +other .py files to be considered as Python modules by the interpreter. +To avoid this being a problem, python-support will add them automatically +as needed. However, this will be done later than the update-python-modules +call when dpkg installs the package, because this is, like +byte-compilation, a time-consuming operation. + +What this means is, if you need a namespace package or depend on a +package that needs it, *and* that you need to use it during the +postinst phase (e.g. for a daemon), you will have to add the following +command in the postinst before starting your daemon: + update-python-modules -p + + Namespace packages and broken modules + ------------------------------------- +Some Python modules like Twisted rely on the fact that there is no +__init__.py file in some directories. THESE PACKAGES ARE BROKEN. You +should try to fix the package first to not rely on such implementation +details. + +However, if it turns out not to be possible, you can, as a workaround, +create a file named ".noinit" in the directories where you don't want +__init__.py to be created. In this case, update-python-modules will not +create the namespace package. + + +Note : Legacy locations +======================= +Packages used to ship files in the following way: + * /usr/share/python-support/$package contained the public modules. + * /usr/lib/python-support/pythonX.Y/$package contained the public + extensions. + * /usr/share/python-support/$package.dirs contained a list of directories + to handle for byte-compilation (for private modules). +These locations are still supported, but deprecated. New packages should +not be using them. diff --git a/debhelper/dh_pysupport b/debhelper/dh_pysupport new file mode 100644 index 0000000..606510c --- /dev/null +++ b/debhelper/dh_pysupport @@ -0,0 +1,384 @@ +#!/usr/bin/perl -w + +=head1 NAME + +dh_pysupport - use the python-support framework to handle Python modules + +=cut + +use strict; +use File::Find; +use Debian::Debhelper::Dh_Lib; + +=head1 SYNOPSIS + +B [I] [-V I] [-X I [...]] [-n] [I] + +=head1 DESCRIPTION + +dh_pysupport is a debhelper program that will scan your package, detect +public modules in I, and move them to +the shared Python modules location. It will generate appropriate +postinst/prerm scripts to byte-compile modules installed there for all +available python versions. + +It will also look for private Python modules and will byte-compile them +with the current Python version. You may have to list the directories +containing private Python modules. + +If a file named I exists, it is used to determine the +python versions with which the package can work. + +Appropriate dependencies on python-support, python and pythonI are +put in ${python:Depends}. The ${python:Versions} and ${python:Provides} +optional substitution variables are made available as well. + +=head1 OPTIONS + +=over 4 + +=item I + +If your package installs private python modules in non-standard directories, you +can make dh_pysupport check those directories by passing their names on the +command line. By default, it will check /usr/lib/$PACKAGE, +/usr/share/$PACKAGE, /usr/lib/games/$PACKAGE and /usr/share/games/$PACKAGE + +=item B<-n>, B<--noscripts> + +Do not modify postinst/postrm scripts. + +=item B<-d> + +This option is deprecated. + +=item B<-V> I + +Force private modules to be bytecompiled with the specific I python version, regardless of the default python version on the system. + +=item B<-X> I, B<--exclude=>I + +Exclude files that contain "item" anywhere in their filename from being +taken into account to generate the python dependency. It also excludes +them from byte-compilation. You may use this option multiple times to +build up a list of things to exclude. + +=back + +=head1 CONFORMS TO + +Python policy as of 2006-08-10 + +=cut + +init(); + +warning("This program is deprecated, you should use dh_python2 instead. Migration guide: http://deb.li/dhs2p"); + +sub next_minor_version { + my $version = shift; + # Handles 2.10 -> 2.11 gracefully + my @items = split(/\./, $version); + $items[1] += 1; + $version = join(".", @items); + return $version; +} + +sub specified_deps_in_package { + my $package = shift; + my $curpackage = 0; + my @deps = (); + open (CONTROL, 'debian/control') || error("cannot read debian/control: $!\n"); + while () { + chomp; + s/\s+$//; + if (/^Package:\s*(.*)$/ && $package eq $1) { + $curpackage = 1; + } + if ($curpackage == 2) { + if (/^\s+(.*)$/) { + push @deps, split ",",$1; + if ($1 !~ /,$/) { + return @deps; + } + } else { + return @deps; + } + } + if ($curpackage && /^Python-Depends:\s*(.*)$/) { + @deps = split ",",$1; + if ($1 =~ /,$/) { + $curpackage = 2; + } else { + return @deps; + } + } + } + return @deps; +} + +sub trim { + my $tmp = shift; + $tmp =~ s/^\s+//; + $tmp =~ s/\s+$//; + return $tmp; +} + +# The current default python version +my $default=`readlink /usr/bin/python`; +$default =~ s/^python//; +chomp $default; + +# Versions supported by python-defaults +my @debian_pysupported = split(/ /, `/usr/bin/pyversions -sv`); +chomp @debian_pysupported; + +my $privdir="/usr/share/python-support/private"; +# All supported versions +my $allversions_string=`$privdir/parseversions --all`; +chomp $allversions_string; +my @allversions=split " ", $allversions_string; + +if (! grep { $_ eq $default } @allversions) { + error("Cannot detect default Python version"); +} + +# Use a specific version for private modules (doesn't affect public modules) +my $useversion; +if($dh{V_FLAG_SET}) { + $useversion = $dh{V_FLAG}; + if (! grep { $_ eq $useversion } @allversions) { + error("Unknown python version $useversion"); + } +} + +foreach my $package (@{$dh{DOPACKAGES}}) { + next if ($package =~ /^python3-/); # ignore Python 3 packages + my $tmp = tmpdir($package); + my $need_pydep=0; # This variable tells whether we need a Python dependency + # regardless of the rest + my $have_pydep=0; # This variable tells whether we have added some dependency + # on python one way or another. + my @specified_deps = specified_deps_in_package ($package); + my $do_scripts = ""; + + # 1) Handle public python modules + # Move them to the python-support directories + my $verfile = "debian/pyversions"; + my $versions = ""; + if (open (VERFILE, $verfile)) { + # read first non-empty line + local $/ = ""; + $versions = ; + chomp $versions; + close (VERFILE); + $versions = trim $versions; + # TODO: debian/package.pyversions ? + } else { + my $doko_versions=`$privdir/parseversions --raw --pycentral debian/control`; + chomp $doko_versions; + if ($doko_versions !~ /not found/) { + $versions=$doko_versions; + } + } + if ($versions) { + doit (("$privdir/movemodules","-V", $versions, $tmp)) + } else { + doit (("$privdir/movemodules",$tmp)); + } + + # Then look for what the script found + foreach my $list_file (glob("$tmp/usr/share/python-support/*.public")) { + if (-f $list_file) { + my $supported=`$privdir/parseversions --minmax $list_file`; + + # Add the packages explicitly asked by the maintainer + foreach my $dep (@specified_deps) { + $dep = trim $dep; + addsubstvar($package, "python:Depends", $dep); + } + my @ar=split "\n",$supported; + my @provides=split " ",$ar[0]; + foreach my $pyversion (@provides) { + # Skip the substvars part for versions that might not + # be provided by packages depended upon. + next if (! grep { $_ eq $pyversion } @debian_pysupported); + + # Generate the useless versions field + addsubstvar($package, "python:Versions", $pyversion); + # ... and the provides field + if ($package =~ /^python-/) { + my $virtual = $package; + $virtual =~ s/^python-/python$pyversion-/; + addsubstvar($package, "python:Provides", $virtual); + } + # Use the provides fields in packages dependended upon + foreach my $dep (@specified_deps) { + $dep = trim $dep; + # I have no idea why this wouldn't be the case, but well + if ($dep =~ /^python-(\S+)/) { + addsubstvar($package, "python:Depends", "python$pyversion-$1"); + } + } + } + my @minmax=split " ",$ar[1]; + my $minversion=$minmax[0]; + if ( grep { $_ eq $default } @provides ) { + # The default version is in the supported versions + if ($minversion ne "None") { + addsubstvar($package, "python:Depends", "python (>= $minversion)"); + $have_pydep=1; + } + } elsif ($minversion ne "None") { + # The default version is less than all supported versions + addsubstvar($package, "python:Depends", "python (>= $minversion) | python$minversion"); + $have_pydep=1; + } else { + error("The default python version is greater than all supported versions"); + } + my $maxversion=$minmax[1]; + if ($maxversion ne "None") { + $maxversion = next_minor_version($maxversion); + addsubstvar($package, "python:Depends", "python (<< $maxversion)"); + $have_pydep=1; + } + $list_file =~ s,^.*/,,; + $do_scripts = "$do_scripts $list_file"; + + $need_pydep = 1; + } + } + + # 2) Look for private python modules + my @dirs = ("/usr/lib/$package", "/usr/share/$package", + "/usr/lib/games/$package", "/usr/share/games/$package", @ARGV ); + @dirs = grep -d, map "$tmp$_", @dirs; + my @filelist; + my $file; + my $has_module = 0; + my $has_extension = 0; + my $strong_pydep=0; + my %need_verdep = (); + foreach (@allversions) { + $need_verdep{$_} = 0; + } + if (@dirs) { + foreach my $curdir (@dirs) { + find sub { + return unless -f; + return if excludefile($File::Find::name); + if (/\.py$/) { + $has_module=1; + doit(("rm","-f",$_."c",$_."o")); + ( $file=$File::Find::name ) =~ s%^$tmp%%; + if (! grep { $_ eq $file } @filelist) { + push @filelist, $file; + } + } + if (/\.so$/ && + `nm -Du "$_" | grep "U Py_InitModule"` && + ! `objdump -p "$_" | grep "NEEDED *libpython"`) { + $has_extension=1; + } + }, $curdir ; + } + } + + if ( ($has_module or $has_extension) ) { + if ( $useversion ) { + $need_verdep{$useversion}=1; + } else { + $need_pydep=1; + $strong_pydep=1 if $has_extension; + } + } + + if (@filelist) { + # We have private python modules + # Use python-support to ensure that they are always + # byte-compiled for the current version + doit("mkdir", "-p", "-m", "755", "$tmp/usr/share/python-support"); + open(FILELIST, "> $tmp/usr/share/python-support/$package.private") || + error("Can't create $tmp/usr/share/python-support/$package.private: $!"); + if ( $useversion ) { + print FILELIST "pyversion=$useversion\n\n"; + } + print FILELIST map "$_\n", @filelist; + close(FILELIST); + $do_scripts = "$do_scripts $package.private"; + } + + # 3) Add python-support dependency depending on what we found + if (-d "$tmp/usr/share/python-support") { + addsubstvar($package, "python:Depends", "python-support (>= 0.90.0)"); + } + + # 4) Look for python scripts + find sub { + return unless -f and -x; + return if excludefile($File::Find::name); + local *F; + return unless open F, $_; + if (read F, local $_, 32 and m%^#!\s*/usr/bin/(env\s+)?(python(\d+\.\d+)?)\s%) { + if ( "python" eq $2 ) { + $need_pydep=1; + } elsif (defined $need_verdep{$3}) { + $need_verdep{$3}=1; + } + } + close F; + }, $tmp; + + # 5) Generate remaining dependencies + foreach my $version (@allversions) { + if ($need_verdep{$version}) { + addsubstvar($package, "python:Depends", "python$version"); + } + } + if (not $have_pydep) { + if ($strong_pydep) { + addsubstvar($package, "python:Depends", "python (>= $default)"); + my $maxversion = next_minor_version($default); + addsubstvar($package, "python:Depends", "python (<< $maxversion)"); + $have_pydep=1; + } elsif ($need_pydep and $versions) { + my $supported=`echo $versions | $privdir/parseversions --minmax`; + my @ar=split "\n",$supported; + my @minmax=split " ",$ar[1]; + my $minversion=$minmax[0]; + if ($minversion ne "None") { + addsubstvar($package, "python:Depends", "python (>= $minversion)"); + $have_pydep=1; + } + my $maxversion=$minmax[1]; + if ($maxversion ne "None") { + $maxversion = next_minor_version($maxversion); + addsubstvar($package, "python:Depends", "python (<< $maxversion)"); + $have_pydep=1; + } + } + } + # If nothing has added a python dependency yet, add it + if ($need_pydep and not $have_pydep) { + addsubstvar($package, "python:Depends", "python"); + } + + # 6) Generate the scripts + if ($do_scripts && ! $dh{NOSCRIPTS}) { + autoscript($package, "postinst", "postinst-python-support", "s,#ARGS#,$do_scripts,"); + autoscript($package, "prerm", "prerm-python-support", "s,#ARGS#,$do_scripts,"); + } +} + +=head1 SEE ALSO + +L + +This program is a part of python-support but is made to work with debhelper. + +=head1 AUTHORS + +Josselin Mouette , +Raphael Hertzog + +=cut diff --git a/debhelper/postinst-python-support b/debhelper/postinst-python-support new file mode 100644 index 0000000..0969b1d --- /dev/null +++ b/debhelper/postinst-python-support @@ -0,0 +1,3 @@ +if which update-python-modules >/dev/null 2>&1; then + update-python-modules #ARGS# +fi diff --git a/debhelper/prerm-python-support b/debhelper/prerm-python-support new file mode 100644 index 0000000..f0a39a5 --- /dev/null +++ b/debhelper/prerm-python-support @@ -0,0 +1,3 @@ +if which update-python-modules >/dev/null 2>&1; then + update-python-modules -c #ARGS# +fi diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..b55737b --- /dev/null +++ b/debian/changelog @@ -0,0 +1,776 @@ +python-support (1.0.15) unstable; urgency=low + + [ Jakub Wilk ] + * parseversions: + + Make comparison of field names case-insensitive. + + Recognize X-Python-Version. + + [ Piotr Ożarowski ] + * update-python-modules manpage: fix --install option's description + (closes: #671942) + * movemodules: + - doesn't raise string exceptions anymore (closes: #585332) + * Standards version is 3.9.3, no changes required + + -- Piotr Ożarowski Sat, 30 Jun 2012 19:20:00 +0200 + +python-support (1.0.14) unstable; urgency=low + + * update-python-modules: remove directory if it's replaced with a file + (often happens with .egg-info file/dirs) + * Add deprecation warning: dh_python2 (from python package) should be used + instead. Migration guide is available on wiki page: + http://wiki.debian.org/Python/PythonSupportToDHPython2 + * Vcs-* fields now point to anonscm.debian.org + * Standards version is 3.9.2, no changes required. + + -- Piotr Ożarowski Mon, 27 Jun 2011 20:22:56 +0200 + +python-support (1.0.13) unstable; urgency=low + + [ Loïc Minier ] + * tests/testparseversions.py: don't hardcode expected versions; instead, + compare with pyversions' output. + * pysupport.py: don't hardcode supported and old versions; instead, parse + debian_defaults; NB: this removes some very old python versions from the + list (2.1 and 2.2), but these weren't ever support and aren't supported in + the previous stable release anyway. Depend on python-minimal as + debian_defaults is accessed directly. + + [ Piotr Ożarowski ] + * Upload to unstable (closes: #622906) + * Add lintian override for depends-on-python-minimal + + -- Piotr Ożarowski Fri, 15 Apr 2011 21:14:04 +0200 + +python-support (1.0.12) experimental; urgency=low + + * Add support for python2.7. + * Move python2.4 to old versions. + + -- Piotr Ożarowski Mon, 18 Oct 2010 19:51:21 +0200 + +python-support (1.0.11) unstable; urgency=low + + * Move python2.4 to old versions. + + -- Piotr Ożarowski Tue, 19 Oct 2010 17:20:22 +0200 + +python-support (1.0.10) unstable; urgency=low + + * Binary packages with name starting with "python3-" are now ignored by + dh_pysupport + * Standards version is 3.9.1, no changes required. + + -- Piotr Ożarowski Tue, 14 Sep 2010 19:05:58 +0200 + +python-support (1.0.9) unstable; urgency=low + + * dh_pysupport: generates correct dependencies if multiple packages need + pythonX.Y (closes: #576517, thanks to Jakub Wilk for the patch) + * update-python-modules: + - remove /usr/lib/pymodules files symlinked to /usr/share/pyshared that + no longer belong to any python-support based package + - doesn't raise string exceptions anymore (closes: #585332) + + -- Piotr Ożarowski Sun, 27 Jun 2010 15:12:52 +0200 + +python-support (1.0.8) unstable; urgency=low + + [ Jakub Wilk ] + * movemodules: ignore indentation and trailing whitespace when comparing + PKG-INFO and *.egg-info files. This is work-around for bug #575377. + + [ Piotr Ożarowski ] + * Standards version is 3.8.4, no changes required. + * Use 3.0 (native) source package format + + -- Piotr Ożarowski Tue, 20 Apr 2010 20:11:54 +0200 + +python-support (1.0.7) unstable; urgency=low + + [ Loïc Minier ] + * Fix stripping of empty lines in debian/pyversions; LP: #437593; + closes: #568171. + * Only search for XS-Python-Version in the debian/control general paragraph + (the first one, for the source package); see Debian #567941; + closes: #568173. + * Add tests for parseversions. + * Use ./parseversions --all --long to list supported versions during build + instead of poking pysupport.py_supported directly. + * Cleanup shell snippet / tabs in rules. + * Explicitly strip spaces after parsing debian/pyversions. + + [ Josselin Mouette ] + * dh_pysupport: fix syntax errors in previous patch. + * README: document that only python is required for arch: all + packages, not python-dev. Also talk about python-support itself. + Closes: #563749. + * dh_pysupport: print an error if the default Python version cannot be + found. Closes: #572155. + * parseversions: I hate regexes. + * dh_pysupport: ensure there is a Python dependency even when no + specific versions are required. Closes: #568811. + + -- Josselin Mouette Thu, 11 Mar 2010 23:17:19 +0100 + +python-support (1.0.6.1) unstable; urgency=low + + * Non-maintainer upload. + * update-python-modules: set umask to 022. Closes: #567811. + + -- Matt Kraai Tue, 23 Feb 2010 03:14:38 -0800 + +python-support (1.0.6) unstable; urgency=low + + * movemodules: do not touch symlinks that merely point to another + place in the module tree. Closes: #539187. + + -- Josselin Mouette Fri, 04 Dec 2009 09:26:17 +0100 + +python-support (1.0.5) unstable; urgency=low + + [ Piotr Ożarowski ] + * Rename .egg-info files the same way .egg-info directories are renamed + + [ Josselin Mouette ] + * dh_pysupport: use mkdir -p instead of the Perl mkdir function. + Closes: #558392. + + -- Josselin Mouette Sat, 28 Nov 2009 20:17:55 +0100 + +python-support (1.0.4) unstable; urgency=low + + [ Josselin Mouette ] + * README: fix small but confusing mistake about public extensions. + * update-python-modules.8: fix typo, thanks Nacho Barrientos. + * Add Bernd and Piotr to uploaders. + * dh_pysupport: fix a variable getting included in a regexp. + Closes: #549283. + * dh_pysupport: patch by Luca Falavigna to not generate substvars for + Python versions not supported by python-defaults. Closes: #549713. + + [ Piotr Ożarowski ] + * control: add Vcs-Browser and Vcs-Svn fields + + -- Josselin Mouette Thu, 08 Oct 2009 22:39:22 +0200 + +python-support (1.0.3) unstable; urgency=low + + * update-python-modules: be resilient against broken directories in + /usr/share/python-support. Closes: #528130. + + -- Josselin Mouette Tue, 12 May 2009 21:46:05 +0200 + +python-support (1.0.2) unstable; urgency=low + + * dh_pysupport: remove warning about compatibility mode. + * movemodules: list files in /usr/share/pyshared, so that this place + can be used as a destination for stuff installed by hand. + * Switch to debhelper compatibility mode 7. + + -- Josselin Mouette Wed, 15 Apr 2009 16:25:13 +0200 + +python-support (1.0.1) unstable; urgency=low + + * update-python-modules: + + Use the warning() function for all warnings. Closes: #522856. + * movemodules: + + Read links destinations instead of their contents, so that we can + support dangling symbolic links. Closes: #523033. + + -- Josselin Mouette Wed, 08 Apr 2009 12:23:23 +0200 + +python-support (1.0.0) unstable; urgency=low + + * Upload to unstable. + + -- Josselin Mouette Mon, 06 Apr 2009 13:22:14 +0200 + +python-support (0.90.5) experimental; urgency=low + + * movemodules: + + Better handling of files from multiple sources, used for files + being installed in different directories for python2.5 and 2.6. + + Add /usr/local/lib/pythonX.Y/dist-packages as a source for + modules. + + Use hashlib instead of md5. Closes: #519189. + * Require python 2.5 for the hashlib module. + + -- Josselin Mouette Thu, 26 Mar 2009 19:09:31 +0100 + +python-support (0.90.4) experimental; urgency=low + + * movemodules: + + When moving relative symbolic links, handle the case where we move + several of them. + + Support dist-packages as a source for modules. + * rules: install the .pth in dist-packages for python2.6. + Closes: #518826. + * update-python-modules: fix a crash occurring when a package drops + some supported versions. Closes: #518973. + + -- Josselin Mouette Tue, 24 Mar 2009 16:24:12 +0100 + +python-support (0.90.3) experimental; urgency=low + + * Add a quick guide for maintainers on top of the README. Maybe it + will prevent maintainers from doing useless things they thought were + necessary by reading the rest. + * movemodules: + + Now that we have the /var/lib/python-support symlink, also move + files from that directory at build time, this will avoid to change + a couple of packages. + + Preserve relative symbolic links when moving them to a different + level + + -- Josselin Mouette Fri, 27 Feb 2009 00:39:41 +0100 + +python-support (0.90.2) experimental; urgency=low + + * dh_pysupport: match /\.py$/ instead of /.py$/. + * movemodules: completely remove empty __init__.py files, they are + added at installation time by update-python-modules. + * post{inst,rm}: add a symbolic link in /var/lib/python-support, + otherwise the upgrade will be a big failure for several packages. + + -- Josselin Mouette Fri, 20 Feb 2009 16:42:52 +0100 + +python-support (0.90.1) experimental; urgency=low + + * Update priority to match the override. + * update-python-modules: add a consistency check for the case when no + packages using python-support are installed. + * dh_pysupport: avoid duplicates when handling private modules. + * movemodules: correctly support the case where + /usr/lib/pyshared/pythonX.Y is used but more Python versions are + supported. + + -- Josselin Mouette Thu, 19 Feb 2009 19:16:49 +0100 + +python-support (0.90.0) experimental; urgency=low + + * Major changes to the installed packages format. The old format is + still supported at runtime, but will not be generated anymore. + * Private modules now ship foo.private files, containing the metadata + and file listing for the package. + * Public modules now ship foo.public files for metadata and listing, + and files go to /usr/{share,lib}/pyshared. Closes: #478178. + * The modules installation path was changed to /usr/lib/pymodules. + * The private directory has moved to + /usr/share/python-support/private. The specific scripts are now + installed in here. + * Important documentation updates. + * copyright: point to the correct LGPL location. + * Add support for python2.6. + + -- Josselin Mouette Wed, 18 Feb 2009 21:44:25 +0100 + +python-support (0.8.7) unstable; urgency=low + + * update-python-modules (install_modules): + + Make the error message more useful. + + -- Josselin Mouette Mon, 27 Oct 2008 09:02:41 +0100 + +python-support (0.8.6) unstable; urgency=low + + * update-python-modules (create_dotpath): + + Completely ignore lines starting with "import", as they would be + executed by python upon startup. + + -- Josselin Mouette Fri, 29 Aug 2008 22:31:43 +0200 + +python-support (0.8.5) unstable; urgency=low + + * update-python-modules (post_change_stuff): + + Don't create a namespace package if there is a file named .noinit + in the same directory. Closes: #459468. + * dh_pysupport: add correct dependencies when there is such a file. + * README: document how to do that and that you shouldn't. + + -- Josselin Mouette Thu, 24 Jul 2008 14:30:01 +0200 + +python-support (0.8.4) unstable; urgency=medium + + * update-python-modules (post_change_stuff): + + Remove symbolic links to files in packages not supported by the + current python version anymore. Closes: #485740 + * Standards version is 3.8.0, no changes required. + + -- Josselin Mouette Mon, 30 Jun 2008 13:07:07 +0200 + +python-support (0.8.3) unstable; urgency=low + + * update-python-modules: + + Integrate a part of the Ubuntu change for LP#208961, fixes a + crash that might occur if a dangling symbolic link to an old + version of the file in a removed package is found. + * README: + + Document the specific case of daemons needing namespace packages. + This should be very rare, but you never know. + + -- Josselin Mouette Mon, 23 Jun 2008 11:07:50 +0200 + +python-support (0.8.2) unstable; urgency=low + + * Fix typo in 0.8.1 changelog entry. + * update-python-modules: + + Call dpkg-trigger explicitly when we need it. This should prevent + the trigger from being run *before* the actual installation. + Closes: #486516. + * triggers: declare interest on the "pysupport" trigger. + + -- Josselin Mouette Mon, 23 Jun 2008 02:35:41 +0200 + +python-support (0.8.1) unstable; urgency=low + + * update-python-modules: + + Handle the case where a daemon package uses a module that ships a + .pth file. In this case, it is needed at once and we cannot wait + for the trigger. + * Depend on dpkg 1.14.19 to not get hit by #479850. + * Fix minor issue in README. + + -- Josselin Mouette Tue, 13 May 2008 10:48:00 +0200 + +python-support (0.8.0) experimental; urgency=low + + * update-python-modules: + + Don't do anything when called with -c for public modules. This + will allow modules to remain available while being upgraded. + + Don't byte-compile public modules when called without -p, either. + This should reduce the time consumed during upgrades. + + Support a new --post-install/-p option, that byte-compiles public + modules and removes any dangling symbolic links left by a package + removal or upgrade. + + Indentation fixes. + * triggers: register triggers on /usr/share/python-support and + /usr/lib/python-support. + * postinst: + + Always byte-compile python-support.dirs. + + Launch update-python-support --post-install to enforce + byte-compilation. + + Launch only this command when triggered. + * control: build-depend on debhelper 5.0.59 for triggers support. + * pysupport.py: deprecate python2.3. + * control: depend on python >= 2.4 to match the change. + + -- Josselin Mouette Wed, 07 May 2008 00:18:55 +0200 + +python-support (0.7.7) unstable; urgency=low + + * update-python-modules: + + Correctly handle the clean mode when called with an unknown + directory as argument. Closes: #468848. + + Fail when a package tries to provide an extension provided by + another one (the previous code only worked for modules). + * README: document that you shouldn't remove the + /usr/share/python-support/foo directory. + * control: properly capitalize Python. + + -- Josselin Mouette Wed, 12 Mar 2008 00:07:04 +0100 + +python-support (0.7.6) unstable; urgency=low + + * dh_pysupport: allow the Python-Depends field to be wrapped. + Closes: #458737. + * Standards version is 3.7.3; no changes. + + -- Josselin Mouette Sat, 05 Jan 2008 13:04:30 +0100 + +python-support (0.7.5) unstable; urgency=low + + * dh_pysupport: + + Cut out some unused code. + + Unify script generation, cutting obsolete -i and -b options. + * {postinst,prerm}-python-support: + + Update snippets accordingly. + + Launch the postinst in all cases, not only in the configure case. + Closes: #446730. + + -- Josselin Mouette Wed, 31 Oct 2007 18:51:10 +0100 + +python-support (0.7.4) unstable; urgency=low + + * dh_pysupport: don't treat .so files linking to libpython* as + extensions. This will avoid adding spurious dependencies. + * Fix some wrong changelog entries talking about dh_python. + + -- Josselin Mouette Thu, 04 Oct 2007 14:22:36 +0200 + +python-support (0.7.3) unstable; urgency=low + + * dh_pysupport: fix an annoying bug sometimes leading to an invalid + substvars file when using Python-Depends. + + -- Josselin Mouette Sat, 22 Sep 2007 12:15:34 +0200 + +python-support (0.7.2) unstable; urgency=low + + * Upload to unstable. + * dh_pysupport: bump the generated dependencies to version 0.7.1. Modules + which need namespace packages will need to build-depend on that + version, and will get a dependency on it. + + -- Josselin Mouette Thu, 20 Sep 2007 23:07:44 +0200 + +python-support (0.7.1) experimental; urgency=low + + * update-python-modules: + + Exclude __init__.py files already provided by the package by + looking at whether they are symbolic links. + + Minor cleanups. + + Use shutil.rmtree instead of rm -rf. + + -- Josselin Mouette Wed, 27 Jun 2007 19:13:32 +0200 + +python-support (0.7) experimental; urgency=low + + * Make the package priority standard. + * update-python-modules: add support for namespace packages, by + creating and removing automatically empty __init__.py files where + appropriate. Thanks Gustavo Noronha Silva for the initial idea and + precious input. + + -- Josselin Mouette Sun, 10 Jun 2007 00:45:37 +0200 + +python-support (0.6.4) unstable; urgency=low + + * update-python-modules: only warn on missing files if we're in + cleaning mode (prerm). Closes: #422568. + * pysupport-movemodules: merge .egg-info directories by stripping the + -py$vers part from them. Based on a patch by Cyril Brulebois, + closes: #422436. + + -- Josselin Mouette Tue, 08 May 2007 18:48:31 +0200 + +python-support (0.6.3) unstable; urgency=low + + * dh_pysupport: trim strings in the Python-Depends field. + + -- Josselin Mouette Wed, 28 Mar 2007 22:50:41 +0200 + +python-support (0.6.2) unstable; urgency=low + + * pysupport-movemodules: remove .a and .la files, which are useless + cruft generated by libtool (closes: #412477). + * Upload to unstable. + + -- Josselin Mouette Wed, 21 Mar 2007 22:16:20 +0100 + +python-support (0.6.1) experimental; urgency=low + + * pysupport-movemodules: + + Fix a case where the original installation directory was not + removed. + + Move modules from /var/lib/python-support as well. This allows + to handle packages that hardcode the path to the modules + (closes: #397895). + * README: + + Document the procedure for such packages. + + Also document the Python-Depends field. + + -- Josselin Mouette Sat, 24 Feb 2007 13:04:23 +0100 + +python-support (0.6) experimental; urgency=low + + * dh_pysupport: + + Generate the useless ${python:Versions} field (closes: #403366). + + Parse a new control field, Python-Depends, which contains + dependencies on other python packages. Add to ${python:Depends} + the virtual dependencies needed for all python versions. + + Remove useless spaces at the end of python-support dependencies. + + -- Josselin Mouette Sat, 17 Feb 2007 13:10:27 +0100 + +python-support (0.5.6) unstable; urgency=medium + + * pysupport-parseversions, dh_pysupport: remove the remaining calls to + pyversions, thanks Pawel Tecza. + * This allows to loosen dependencies on python to 2.3. + * update-python-modules: only show a warning when byte-compilation + fails, but don't stop the whole process, thanks Raphaël Hertzog + (closes: #400001). + * pysupport-parseversions: fix parsing of XS-Python-Version field. + + -- Josselin Mouette Thu, 23 Nov 2006 22:34:58 +0100 + +python-support (0.5.5) unstable; urgency=high + + * dh_pysupport, pysupport-movemodules, debian/rules, + pysupport-parseversions, pysupport.py: do not rely on pyversions to + obtain the list of installed python versions, because it is not a + reliable way to do so, see #396840. + * This brings back support for python2.3, and allows support for + python2.5. + + -- Josselin Mouette Tue, 14 Nov 2006 21:25:16 +0100 + +python-support (0.5.4) unstable; urgency=high + + * dh_pysupport: patch from Raphaël Hertzog to correctly depend on + python when there is no minimum nor maximum version + (closes: #391689). + + -- Josselin Mouette Thu, 12 Oct 2006 19:38:41 +0200 + +python-support (0.5.3) unstable; urgency=low + + * dh_pysupport: always generate dependencies. + * Conflict with debhelper (<< 5.0.38). + + -- Josselin Mouette Sun, 1 Oct 2006 19:58:09 +0200 + +python-support (0.5.2) unstable; urgency=low + + * update-python-modules: + + Remove some useless code. + + Small fix in short help. + + Handle the case of broken symlinks needing to be overwritten. + * dh_pysupport.1: reference README and policy, thanks Tomas Pospisek + (closes: #388171). + + -- Josselin Mouette Fri, 22 Sep 2006 21:14:15 +0200 + +python-support (0.5.1) unstable; urgency=low + + * dh_pysupport: + + Generate ${python:Provides} when no debian/pyversions file exists. + + Barf when /usr/lib/python-support/$package is lacking an existing + python version (closes: #387040). + + -- Josselin Mouette Mon, 11 Sep 2006 23:51:49 +0200 + +python-support (0.5) unstable; urgency=low + + * update-python-modules: be much stricter in what is accepted on the + command line. Only .dirs files are accepted with the -i option, + while directories in /usr/share/python-support are accepted with the + -b option. It is now possible to pass both kinds of arguments on the + command line. Closes: #386830. + * update-python-modules: abandon compatibility with version 0.1 + entirely. The warnings have been prominent enough. + + -- Josselin Mouette Sun, 10 Sep 2006 19:39:21 +0200 + +python-support (0.4.3) unstable; urgency=medium + + * update-python-modules: check for .path presence when checking for + newly installed python versions, otherwise stuff might not be + compiled for it (closes: #383799, medium-urgency fix). + * update-python-modules: handle symbolic links to directories + (closes: #378853). + + -- Josselin Mouette Thu, 31 Aug 2006 21:11:19 +0200 + +python-support (0.4.2) unstable; urgency=low + + * dh_pysupport: add a python dependency even when there is already a + dependency on python-support (closes: #383958). + * pysupport.py: strip all unnecessary whitespace (closes: #385105). + * pysupport-movemodules: force the umask to avoid getting wrong + permissions in the final package (closes: #382755). + + -- Josselin Mouette Thu, 31 Aug 2006 20:01:10 +0200 + +python-support (0.4.1) unstable; urgency=low + + * dh_pysupport: + + Implement the -X option to exclude files from being searched to + generate the dependencies. + + Detect private extensions as .so files calling Py_InitModule*. In + this case, a strict dependency on python (>= X.Y), python (<< + X.Y+1) is generated. + + -- Josselin Mouette Thu, 10 Aug 2006 14:03:48 +0200 + +python-support (0.4.0) unstable; urgency=low + + * dh_pysupport: + + Handle dependencies for packages that only ship modules for + non-default python versions. + + Always generate dependencies when debian/pycompat isn't found. + + Add missing newline at the end of the .dirs files. + + Avoid obtaining a double leading / in .dirs files. + + Avoid duplicate entries in .dirs files. + + Create .pyversion in private module directories when the -V option + is used. Require python-support 0.4 in this case. + + Handle python dependencies for private modules. + + Handle script dependencies. + + Improve comments in the code. + + Remove .py[co] files in the private module directories. + * update-python-modules: + + Don't call compileall.py on non-existing directories + (closes: #378773). + + Bytecompilation of private modules for non-default python + versions, using the .pyversion file. + * README: + + Document all these changes. + + Document that using dh_python is not recommended. + + -- Josselin Mouette Wed, 9 Aug 2006 00:26:42 +0200 + +python-support (0.3.9) unstable; urgency=low + + * python-support.rtupdate: only run the script when called with the + "rtupdate" argument. + * pysupport-movemodules: keep foo.so.3 files in /usr/lib, but print a + warning. + * dh_pysupport: + + Fix typo in documentation (closes: #375934). + + Fix --noscripts usage (closes: #378421). + * README: a few clarifications from Cédric Delfosse + (closes: #378161). + + -- Josselin Mouette Wed, 2 Aug 2006 13:23:44 +0200 + +python-support (0.3.8) unstable; urgency=low + + * update-python-modules: fix upgrade path from pre-0.3.4 versions + (closes: #375608). + + -- Josselin Mouette Tue, 27 Jun 2006 10:00:38 +0200 + +python-support (0.3.7) unstable; urgency=low + + * debian/prerm: in the case update-python-modules fails, cleanup by + hand and exit gracefully. This should make upgrades from broken + versions work. + + -- Josselin Mouette Sun, 25 Jun 2006 15:50:47 +0200 + +python-support (0.3.6) unstable; urgency=low + + * update-python-modules: Fix a case where the .path file wasn't + cleaned up automatically upon package removal. + + -- Josselin Mouette Sun, 25 Jun 2006 15:17:56 +0200 + +python-support (0.3.5) unstable; urgency=low + + * update-python-modules: don't try to generate a .path file if the + directory doesn't exist. Thanks Bastian Blank for noticing this. + + -- Josselin Mouette Sun, 25 Jun 2006 15:08:12 +0200 + +python-support (0.3.4) unstable; urgency=low + + * update-python-modules: handle .pth files correctly, by concatenating + them into ".path". + * rules: python-support.pth is now a symbolic link to this .path. + * dh_pysupport: make packages depend on python-support 0.3.4 to avoid + hitting the bug. + + -- Josselin Mouette Sat, 24 Jun 2006 18:23:21 +0200 + +python-support (0.3.3) unstable; urgency=low + + * pysupport-movemodules: fix directory creation in the case there is + no .py at all in the package. + + -- Josselin Mouette Sat, 24 Jun 2006 11:54:24 +0200 + +python-support (0.3.2) unstable; urgency=low + + * dh_pysupport: fix typo affecting dependency generation. + * README: recommend using pyversions -vr now it works. + + -- Josselin Mouette Fri, 23 Jun 2006 19:46:53 +0200 + +python-support (0.3.1) unstable; urgency=low + + * README: add correct documentation (closes: #370515). + * pysupport-movemodules: remove .pyc and .pyo files if some are + generated. + + -- Josselin Mouette Wed, 21 Jun 2006 10:41:19 +0200 + +python-support (0.3.0) unstable; urgency=low + + * Acknowledge NMU (closes: #372774). + * Increase minimal dependency to 0.2 in the helper script. + + Make it 0.3 in the case where /usr/lib/python-support exists. + * rules: cdbs already provides DEB_VERSION, no need to re-compute it. + * install: install dh_pysupport in /usr/bin. + * Don't build-depend on perl. + + * Standards-version is 3.7.2. + * Add more warnings and errors for package making wrong uses of + python-support or using the python-support 0.1 compatibility mode. + * Use "pyversions -s to get the list of python versions. + + Depend on python 2.3.5-6. + * Improve a bit the manual page. + * Fail if a package tries to overwrite a file provided by another + package (closes: #373753). + * Support extensions, by searching + /usr/lib/python-support/$package/$version for files specific to a + python version. + * New command: pysupport-movemodules, to move modules from + /usr/lib/python2.X trees to the python-support hierarchies. + * Call this command in dh_pysupport. + * Add the ability to generate a .version in dh_pysupport, by copying + debian/pyversions. + * Add the possibility for automatic generation of ${python:Depends} + and ${python:Provides}, when calling dh_pysupport -d. + * Provide python-support.rt* scripts to provide hooks when python + versions are installed or removed. + + The dependency on python (<< 2.4) can be removed. + * New command: pysupport-parseversions. It parses + debian/package.pyversions files to display the list of supported + versions that are included in the version list described here. + + -- Josselin Mouette Mon, 19 Jun 2006 14:18:29 +0200 + +python-support (0.2.3) unstable; urgency=low + + * Non-maintainer upload. + * Integrate dh_pysupport and generate the corresponding man-page. + Closes: #372774 + + -- Raphael Hertzog Mon, 12 Jun 2006 17:59:47 +0200 + +python-support (0.2.2) unstable; urgency=low + + * Rewrite the version parser to correctly handle the "-2.x" version + string. + * Remove support for python2.1 and python2.2. + * Purge directories for old python versions. + * Standards-version is 3.7.0. + + -- Josselin Mouette Wed, 3 May 2006 18:54:10 +0200 + +python-support (0.2.1) unstable; urgency=low + + * Include /usr/share/python-support in the package (closes: #365550). + + -- Josselin Mouette Mon, 1 May 2006 04:26:25 +0200 + +python-support (0.2) unstable; urgency=low + + * Link the .py files (closes: #365111, #348596, #363505). + * Support /usr/share/python-support/foo/.version to list the python + versions for which the package is known to work. + * Make python-support entirely stateless. We now rely on + /usr/share/python-support/*/ for directories to install and on + /usr/share/python-support/*.dirs for directories to bytecompile in + situ. + * Improve performance by byte-compiling for non-default python + versions in a single run. + * Treat relative paths in arguments as belonging to + /usr/share/python-support. + * Support python 2.5. + + -- Josselin Mouette Sat, 29 Apr 2006 23:29:40 +0200 + +python-support (0.1.1) unstable; urgency=low + + * Create /var/lib/python-support first. + + -- Josselin Mouette Fri, 6 Jan 2006 11:25:20 +0100 + +python-support (0.1) unstable; urgency=low + + * Initial release (closes: #345638). + + -- Josselin Mouette Mon, 2 Jan 2006 14:52:42 +0100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7f8f011 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +7 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..9e1f36b --- /dev/null +++ b/debian/control @@ -0,0 +1,24 @@ +Source: python-support +Section: python +Priority: optional +Maintainer: Josselin Mouette +Uploaders: Bernd Zeimetz , Piotr Ożarowski +Build-Depends: debhelper (>= 7), cdbs +Build-Depends-Indep: python (>= 2.5) +Standards-Version: 3.9.3 +Vcs-Svn: svn://anonscm.debian.org/collab-maint/deb-maint/python-support/trunk +Vcs-Browser: http://anonscm.debian.org/viewvc/collab-maint/deb-maint/python-support/trunk/ + +Package: python-support +Architecture: all +Depends: python (>= 2.5), python-minimal, dpkg (>= 1.14.19), ${misc:Depends} +Conflicts: debhelper (<< 5.0.38) +Description: automated rebuilding support for Python modules + This package contains the 'update-python-modules' script, which takes + care of byte-compilation of Python-only modules. + . + Private modules are automatically rebuilt upon major Python upgrades, + avoiding the need for strong dependencies. + . + Public modules are automatically made available for all installed + Python versions. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..785f205 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,26 @@ +This is python-support, written and maintained by Josselin Mouette + on Mon, 2 Jan 2006 14:57:00 +0100. + +The original source can always be found at: + ftp://ftp.debian.org/debian/pool/main/p/python-support/ + +Copyright (c) 2006 Josselin Mouette + +License: + + This package is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License. + + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +On Debian systems, the complete text of the GNU Lesser General +Public License can be found in `/usr/share/common-licenses/LGPL-2.1'. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..e0103bd --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +/usr/share/python-support +/usr/lib/pymodules diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..f021cbb --- /dev/null +++ b/debian/install @@ -0,0 +1,7 @@ +update-python-modules /usr/sbin/ +movemodules parseversions /usr/share/python-support/private/ +*.py /usr/share/python-support/private/ +python-support.private /usr/share/python-support/ +debhelper/dh_pysupport /usr/bin/ +debhelper/*-python-support /usr/share/debhelper/autoscripts/ +runtime/* /usr/share/python/runtime.d/ diff --git a/debian/manpages b/debian/manpages new file mode 100644 index 0000000..afe6099 --- /dev/null +++ b/debian/manpages @@ -0,0 +1,3 @@ +update-python-modules.8 +debhelper/*.1 +pysupport-*.1 diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..e0364ac --- /dev/null +++ b/debian/postinst @@ -0,0 +1,20 @@ +#! /bin/sh +set -e + +if [ "$1" = "triggered" ]; then + update-python-modules --post-install + exit 0 +fi + +# Remove the old directory. +if [ "$1" = configure ] && dpkg --compare-versions "$2" lt-nl 0.90; then + rm -rf /var/lib/python-support +fi + +if ! [ -e /var/lib/python-support ]; then + ln -sf /usr/lib/pymodules /var/lib/python-support +fi + +#DEBHELPER# + +update-python-modules --post-install python-support.private diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..84e953d --- /dev/null +++ b/debian/postrm @@ -0,0 +1,12 @@ +#! /bin/sh +set -e + +#DEBHELPER# + +if [ -L /var/lib/python-support ]; then + rm -f /var/lib/python-support +fi + +if [ "$1" = "purge" ]; then + rm -rf /usr/lib/pymodules +fi diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 0000000..ccde9c3 --- /dev/null +++ b/debian/prerm @@ -0,0 +1,9 @@ +#! /bin/sh +set -e + +#DEBHELPER# + +# Don't fail if this command fails, it's not important enough. +# In this case, make the cleanup by hand. +update-python-modules -c -b python-support.private || \ + rm -f /usr/share/python-support/private/*.pyc diff --git a/debian/python-support.lintian-overrides b/debian/python-support.lintian-overrides new file mode 100644 index 0000000..84c72ac --- /dev/null +++ b/debian/python-support.lintian-overrides @@ -0,0 +1 @@ +python-support: depends-on-python-minimal depends diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..5a373a0 --- /dev/null +++ b/debian/rules @@ -0,0 +1,28 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk + +SUPP := $(shell ./parseversions --all --long) + +clean:: + rm -f debhelper/dh_pysupport.1 *.pyc + +check: + dh_testdir + cd tests && PATH=$(CURDIR):$$PATH ./testparseversions.py + +maybe_check = $(if $(findstring nocheck,$(DEB_BUILD_OPTIONS)),,check) + +build/python-support:: + cd debhelper && pod2man -c "python-support" -r "$(DEB_VERSION)" dh_pysupport dh_pysupport.1 + +binary-install/python-support:: $(maybe_check) + for ver in $(SUPP); do \ + subdir=dist-packages; \ + if dpkg --compare-versions $$ver lt python2.6; then \ + subdir=site-packages; \ + fi; \ + mkdir -p debian/python-support/usr/lib/$$ver/$$subdir; \ + ln -s ../../pymodules/$$ver/.path debian/python-support/usr/lib/$$ver/$$subdir/python-support.pth; \ + done + diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/debian/triggers b/debian/triggers new file mode 100644 index 0000000..cd4df7c --- /dev/null +++ b/debian/triggers @@ -0,0 +1 @@ +interest pysupport diff --git a/movemodules b/movemodules new file mode 100755 index 0000000..61a6e4f --- /dev/null +++ b/movemodules @@ -0,0 +1,237 @@ +#! /usr/bin/python +# +# copyright (c) 2006 Josselin Mouette +# Licensed under the GNU Lesser General Public License, version 2.1 +# See COPYING for details + +from optparse import OptionParser +import os,os.path,re,sys +from hashlib import md5 + +sourcepath='usr/share/python-support' +modulepath='usr/share/pyshared' +extensionpath='usr/lib/pyshared' +installedpath='usr/lib/pymodules' + +parser = OptionParser(usage="usage: %prog [options] [directory [...]]") + +parser.add_option("-v", "--verbose", action="store_true", dest="verbose", + help="verbose output", default=False) +parser.add_option("-p", "--package", dest="package") +parser.add_option("-V", "--version-info", dest="version") + +(options, args) = parser.parse_args() + +sys.path.append("/usr/share/python-support/private/") +from pysupport import py_supported,py_supported_short + +# Set the umask so that directories are created with correct permissions +os.umask(022) + +if not args: + parser.error("No directory to process.") + +for basedir in args: + if not os.path.isdir(basedir): + parser.error("%s is not a directory."%basedir) + +class filelist: + def __init__(self): + self.d={} + self.pylist=set() + def addsum(self,file,pyver,sum): + if file not in self.d: + self.d[file]={} + elif pyver in self.d[file] and self.d[file][pyver] != sum: + sys.stderr.write("WARNING: %s exists in multiple versions\n"%file) + self.d[file][pyver]=sum + def addpyver(self,pyver): + self.pylist.add(pyver) + def isallthesame(self,file): + if file.endswith(".so"): + # If there is a .so, no need to even check, it must be moved + return False + elif re.search('\.so(?:\.\d+){0,3}$', file): + sys.stderr.write("WARNING: %s: versioned shared object\n"%file) + return False + try: + s=[ self.d[file][pyver] for pyver in self.pylist ] + except KeyError: + return False + return (s.count(s[0]) == len(self.pylist)) + def list(self,file): + return self.d[file].keys() + def __iter__(self): + return iter(self.d) + +# Rename by preserving relative links +def rename_subtle (source, destination, sourcedir): + if os.path.islink (source): + linkdest = os.readlink (source) + if not os.path.isabs (linkdest): + linkdest = os.path.normpath(os.path.join(os.path.dirname(source),linkdest)) + if not linkdest.startswith(sourcedir+'/'): + prefix = os.path.dirname(os.path.commonprefix((linkdest, destination))) + linkdest = os.path.normpath(destination)[len(prefix)+1:].count('/') * '../' + \ + linkdest[len(prefix)+1:] + destdir = os.path.dirname(destination) + if not os.path.isdir (destdir): + os.makedirs (destdir) + if os.path.lexists (destination): + os.remove (destination) + os.symlink (linkdest, destination) + os.remove (source) + try: + os.removedirs(os.path.dirname(source)) + except OSError: + pass + return + os.renames (source, destination) + +def do_simple_move (basedir, sourcedir): + fileset = set() + absdir=os.path.join(basedir, sourcedir) + for dir, dirs, files in os.walk (absdir): + reldir = dir[len(absdir):].lstrip("/") + for curfile in files: + rename_subtle (os.path.join(absdir, reldir, curfile), os.path.join(basedir, modulepath, reldir, curfile), absdir) + fileset.add(os.path.join("/", modulepath, reldir, curfile)) + return fileset + +def do_move (basedir, tuples): + file_dict=filelist() + for (pybasedir, suffixdir) in tuples: + for pyvers in py_supported: + pydir=os.path.join(basedir,pybasedir,pyvers,suffixdir) + if not os.path.isdir(pydir): + continue + file_dict.addpyver(pyvers) + for dir, dirs, files in os.walk(pydir): + reldir = dir[len(pydir):].lstrip('/') + for curfile in files: + relfile = os.path.join(reldir,curfile) + absfile = os.path.join(pydir,relfile) + # remove bytecompiled files and libtool cruft + if relfile.split('.')[-1] in ["pyc", "pyo", "a", "la"]: + os.remove(absfile) + elif os.path.islink(absfile): + file_dict.addsum(relfile,pyvers,os.readlink(absfile)) + elif absfile.endswith('/PKG-INFO') or absfile.endswith('.egg-info'): + # work-around for bug #575377 + file_dict.addsum(relfile,pyvers,md5(''.join(line.strip()+'\n' for line in file(absfile))).digest()) + else: + file_dict.addsum(relfile,pyvers,md5(file(absfile).read()).digest()) + + files = set() + pyversions = set() + for relfile in file_dict: + splitfile=not file_dict.isallthesame(relfile) + destdir=modulepath + for pyver in file_dict.list(relfile): + for (pybasedir, suffixdir) in tuples: + sourcedir=os.path.join(basedir,pybasedir,pyver,suffixdir) + sourcefile=os.path.join(sourcedir,relfile) + if not os.path.lexists(sourcefile): + continue + if splitfile: + destdir=os.path.join(extensionpath,pyver) + pyversions.add(pyver) + if sourcefile.endswith("/__init__.py") and not os.path.getsize(sourcefile): + # Remove namespace packages, they will be added automatically + # by update-python-modules. + # This will avoid file conflicts at the dpkg level. + os.remove(sourcefile) + try: + os.removedirs(os.path.dirname(sourcefile)) + except OSError: + pass + else: + rename_subtle(sourcefile,os.path.join(basedir,destdir,relfile),sourcedir) + files.add(os.path.join("/",destdir,relfile)) + if pyversions: + # If we have some versions that appear in the extension path + # BUT that more versions were originally supported + # We must add these versions to the list of supported versions + pyversions.update(file_dict.pylist) + return files, pyversions + +def do_listonly (basedir): + fileset = set() + absdir=os.path.join(basedir, modulepath) + for dir, dirs, files in os.walk (absdir): + reldir = dir[len(basedir):].lstrip("/") + for curfile in files: + fileset.add(os.path.join("/",reldir,curfile)) + return fileset + +# Remove the -py$(VERSION) part of the egg directories +def do_eggrename (basedir, pybasedir, suffixdir=""): + for vers in py_supported_short: + pydir=os.path.join(basedir,pybasedir,"python"+vers,suffixdir) + suffix="-py"+vers+".egg-info" + if not os.path.isdir(pydir): + continue + for item in os.listdir(pydir): + item=os.path.join(pydir,item) + if item.endswith(suffix): + new_item = item[:-len(suffix)]+".egg-info" + if not os.path.exists(new_item): # You never know + os.rename(item, new_item) + +for basedir in args: + basedir=basedir.rstrip('/') + package=options.package + if not package: + package=os.path.split(basedir)[1] + if not package: + raise Exception("Unable to extract the package name.") + + public_file = os.path.join(basedir,sourcepath,package+".public") + if os.path.isfile (public_file): + # movemodules was already run, do nothing + sys.exit(0) + + # /usr/share/pyshared (files installed by hand) + files = do_listonly (basedir) + + # /usr/lib/pythonX.Y/site-packages (python <= 2.5) + # /usr/lib/pythonX.Y/dist-packages (python >= 2.6 with deb layout) + # /usr/local/lib/pythonX.Y/dist-packages (python >= 2.6 without deb layout) + do_eggrename (basedir, "usr/lib", "site-packages") + do_eggrename (basedir, "usr/lib", "dist-packages") + do_eggrename (basedir, "usr/local/lib", "dist-packages") + files2, pyversions = do_move (basedir, [("usr/lib", "site-packages"), + ("usr/lib", "dist-packages"), + ("usr/local/lib", "dist-packages")]) + files.update(files2) + + # /var/lib/python-support/pythonX.Y + do_eggrename (basedir, "var/lib/python-support") + files2, pyversions2 = do_move (basedir, [("var/lib/python-support", "")]) + files.update(files2) + pyversions.update(pyversions2) + + # /usr/lib/pymodules/pythonX.Y + do_eggrename (basedir, extensionpath) + files2, pyversions2 = do_move (basedir, [(installedpath, "")]) + files.update(files2) + pyversions.update(pyversions2) + + # /usr/share/python-support/$package + if os.path.isdir(os.path.join(basedir,"usr/share/python-support")): + for ent in os.listdir(os.path.join(basedir,"usr/share/python-support")): + if os.path.isdir(os.path.join(basedir, "usr/share/python-support", ent)): + files.update(do_simple_move(basedir, os.path.join("usr/share/python-support", ent))) + + if files: + if not os.path.isdir(os.path.join(basedir,sourcepath)): + os.makedirs(os.path.join(basedir,sourcepath)) + out=file(public_file, "w") + if pyversions: + out.write("pyversions=%s\n\n"%(','.join(x.replace('python','') for x in sorted(pyversions)))) + elif options.version: + out.write("pyversions=%s\n\n"%options.version) + for filename in sorted(files): + out.write(filename+"\n") + out.close() + diff --git a/parseversions b/parseversions new file mode 100755 index 0000000..896d129 --- /dev/null +++ b/parseversions @@ -0,0 +1,103 @@ +#! /usr/bin/python +# +# copyright (c) 2006 Josselin Mouette +# Licensed under the GNU Lesser General Public License, version 2.1 +# See COPYING for details + +from optparse import OptionParser +import sys,os.path +sys.path.append("/usr/share/python-support/private/") +import pysupport + +parser = OptionParser(usage="usage: %prog [options] file.pyversions") + +parser.add_option ("--minmax", action="store_true", dest="minmax", help="display minimum and maximum python versions described by the file", default=False) +parser.add_option ("-l", "--long", action="store_true", dest="long", help='prepend versions with "python"',default=False) +parser.add_option ("--pycentral", action="store_true", dest="pycentral", help="Parse a pycentral-type version string instead",default=False) +parser.add_option ("--raw", action="store_true", dest="raw", help="Output the raw input string (useful with --pycentral)",default=False) +parser.add_option ("--all", action="store_true", dest="all", help="List all supported versions instead of parsing a file",default=False) + +(options, args) = parser.parse_args() + +if options.all: + f=iter(['-']) +else: + if len(args) < 1: + f=sys.stdin + else: + f=file(args[0]) + +if options.pycentral: + import re + l=None + paraborder=True + for line in f: + line=line.strip() + if line.startswith('#') or not line: # Empty line or comment + if paraborder==True: + # We're at the beginning of debian/control + continue + # We reached the end of the first paragraph, don't keep on reading + break + paraborder=False + if line.lower().startswith(("xs-python-version:", "x-python-version:")): + l=line.split(':')[1] + break + if not l: + print "X(S)-Python-Version header not found." + sys.exit(1) + min=max="" + out=[] + for elem in l.split(','): + elem=elem.strip() + if elem=="all": + min=max="" + out=["-"] + break + if elem=="current": + out.append(os.readlink("/usr/bin/python")[6:]) + continue + a=re.match(">=\s*([\d\.]+)",elem) + if a: + min=a.group(1) + continue + a=re.match("<<\s*([\d\.]+)",elem) + if a: + try: + max=a.group(1).split(".") + max[1]=`int(max[1])-1` + max='.'.join(max) + except IndexError: + max="" + continue + a=re.match("^[\d\.]+$",elem) + if a: + out.append(elem) + if min or max: + out.append(min+"-"+max) + stringtoparse=','.join(out) +else: + stringtoparse=f.next() + if stringtoparse.startswith("pyversions") and "=" in stringtoparse: + # Case of a .public file with version info + stringtoparse = stringtoparse.split("=",1)[1] + elif stringtoparse.startswith("/"): + # Case of a .public file without version info + stringtoparse = "-" + +if options.raw: + print stringtoparse.rstrip('\n') + sys.exit(0) + +v=pysupport.version_list(stringtoparse) +if options.long: + print ' '.join(v) +else: + print ' '.join(v.verlist) + +if options.minmax: + min=v.min + if options.long and min: min="python"+min + max=v.max + if options.long and max: max="python"+max + print min, max diff --git a/pysupport.py b/pysupport.py new file mode 100644 index 0000000..4666f4b --- /dev/null +++ b/pysupport.py @@ -0,0 +1,55 @@ +import os +from ConfigParser import SafeConfigParser + +config = SafeConfigParser() +config.readfp(file('/usr/share/python/debian_defaults')) +versions = config.get('DEFAULT', 'supported-versions') +py_supported = [s.strip() for s in versions.split(',')] +versions = config.get('DEFAULT', 'old-versions') +py_oldversions = [s.strip() for s in versions.split(',')] + +py_installed = [ ver for ver in py_supported if os.access('/usr/bin/'+ver,os.X_OK) ] +py_supported_short = [ a.replace("python","") for a in py_supported ] + +def version_cmp(ver1,ver2): + v1=[int(i) for i in ver1.split('.')] + v2=[int(i) for i in ver2.split('.')] + return cmp(v1,v2) + +# Parse the version format from .version files +class version_list(list): + def __init__(self,version_info): + self.verlist=[] + dummylist=[] + for item in version_info.rstrip('\n').split(','): + v=[i.strip() for i in item.split('-')] + if len(v)>1: + if v[0]: + dummylist.append(v[0]) + else: + v[0] = py_supported_short[0] + dummylist.append("0") + if v[1]: + dummylist.append(v[1]) + else: + v[1] = py_supported_short[-1] + dummylist.append("100") + for ver in py_supported_short: + try: + if version_cmp(ver,v[0]) >= 0 and version_cmp(ver,v[1]) <= 0: + self.verlist.append(ver) + except ValueError: + pass + else: + dummylist.append(v[0]) + if v[0] in py_supported_short: + self.verlist.append(v[0]) + self.verlist.sort(version_cmp) + dummylist.sort(version_cmp) + self.min=dummylist[0] + if self.min=="0": self.min=None + self.max=dummylist[-1] + if self.max=="100": self.max=None + for i in self.verlist: + self.append('python'+i) + diff --git a/python-support.private b/python-support.private new file mode 100644 index 0000000..030ce0b --- /dev/null +++ b/python-support.private @@ -0,0 +1 @@ +/usr/share/python-support/private/pysupport.py diff --git a/runtime/python-support.rtinstall b/runtime/python-support.rtinstall new file mode 100755 index 0000000..a84f8fc --- /dev/null +++ b/runtime/python-support.rtinstall @@ -0,0 +1,3 @@ +#! /bin/sh +set -e +exec /usr/sbin/update-python-modules diff --git a/runtime/python-support.rtremove b/runtime/python-support.rtremove new file mode 100755 index 0000000..692ff1c --- /dev/null +++ b/runtime/python-support.rtremove @@ -0,0 +1,6 @@ +#! /bin/sh +set -e + +pyversion="$2" + +rm -rf /usr/lib/pymodules/"$2" diff --git a/runtime/python-support.rtupdate b/runtime/python-support.rtupdate new file mode 100755 index 0000000..4f1b431 --- /dev/null +++ b/runtime/python-support.rtupdate @@ -0,0 +1,6 @@ +#! /bin/sh +set -e + +if [ "$1" = rtupdate ]; then + exec /usr/sbin/update-python-modules -a +fi diff --git a/tests/testparseversions.leading-newline.control b/tests/testparseversions.leading-newline.control new file mode 100644 index 0000000..b0b5a10 --- /dev/null +++ b/tests/testparseversions.leading-newline.control @@ -0,0 +1,6 @@ +# comment + +Source: source +XS-Python-Version: >= 2.6 + +Package: package diff --git a/tests/testparseversions.missing.control b/tests/testparseversions.missing.control new file mode 100644 index 0000000..cf6b7fc --- /dev/null +++ b/tests/testparseversions.missing.control @@ -0,0 +1,3 @@ +Source: source + +Package: package diff --git a/tests/testparseversions.nonexported.control b/tests/testparseversions.nonexported.control new file mode 100644 index 0000000..a8681ff --- /dev/null +++ b/tests/testparseversions.nonexported.control @@ -0,0 +1,4 @@ +Source: source +X-Python-Version: >= 2.6 + +Package: package diff --git a/tests/testparseversions.py b/tests/testparseversions.py new file mode 100755 index 0000000..4da7084 --- /dev/null +++ b/tests/testparseversions.py @@ -0,0 +1,40 @@ +#!/usr/bin/python + +import unittest +import subprocess + +class TestParseVersions(unittest.TestCase): + @staticmethod + def get_output(args): + subp = subprocess.Popen(args, stdout=subprocess.PIPE) + output = subp.communicate()[0] + if subp.returncode != 0: + raise RuntimeError, subp.returncode + return output + + def pv_output(self, control): + return TestParseVersions.get_output(["parseversions", "--pycentral", control]) + + def test_regular(self): + self.assertEqual(self.pv_output('testparseversions.regular.control'), + TestParseVersions.get_output(['pyversions', '--supported', '-v'])) + + def test_nonexported(self): + self.assertEqual(self.pv_output('testparseversions.nonexported.control'), + TestParseVersions.get_output(['pyversions', '--supported', '-v'])) + + def test_leading_newline(self): + self.assertEqual(self.pv_output('testparseversions.leading-newline.control'), + TestParseVersions.get_output(['pyversions', '--supported', '-v'])) + + def test_missing(self): + self.assertRaises(RuntimeError, self.pv_output, 'testparseversions.missing.control') + + def test_second_paragraph(self): + self.assertRaises(RuntimeError, self.pv_output, 'testparseversions.second-paragraph.control') + + def test_spaces(self): + self.assertRaises(RuntimeError, self.pv_output, 'testparseversions.spaces.control') + +if __name__ == '__main__': + unittest.main() diff --git a/tests/testparseversions.pyc b/tests/testparseversions.pyc new file mode 100644 index 0000000..a67f9bc Binary files /dev/null and b/tests/testparseversions.pyc differ diff --git a/tests/testparseversions.regular.control b/tests/testparseversions.regular.control new file mode 100644 index 0000000..549d386 --- /dev/null +++ b/tests/testparseversions.regular.control @@ -0,0 +1,4 @@ +Source: source +XS-Python-Version: >= 2.6 + +Package: package diff --git a/tests/testparseversions.second-paragraph.control b/tests/testparseversions.second-paragraph.control new file mode 100644 index 0000000..6d205a6 --- /dev/null +++ b/tests/testparseversions.second-paragraph.control @@ -0,0 +1,4 @@ +Source: source + +Package: package +XS-Python-Version: >= 2.6 diff --git a/tests/testparseversions.spaces.control b/tests/testparseversions.spaces.control new file mode 100644 index 0000000..f19eea3 --- /dev/null +++ b/tests/testparseversions.spaces.control @@ -0,0 +1,4 @@ +Source: source + +XS-Python-Version: >= 2.4 +Package: package diff --git a/update-python-modules b/update-python-modules new file mode 100755 index 0000000..ddbeaab --- /dev/null +++ b/update-python-modules @@ -0,0 +1,502 @@ +#! /usr/bin/python +# +# copyright (c) 2006 Josselin Mouette +# Licensed under the GNU Lesser General Public License, version 2.1 +# See COPYING for details + +# Everything prefixed by old_ is compatibility code with older versions +# Modules used to lie in /usr/{lib,share}/python-support/$package +# They now lie in /usr/{lib,share}/pyshared + +import sys,os,shutil +from optparse import OptionParser +from subprocess import call +from py_compile import compile, PyCompileError +sys.path.append("/usr/share/python-support/private/") +import pysupport +from pysupport import py_supported,py_installed,py_oldversions + +basepath='/usr/lib/pymodules' +sourcepath='/usr/share/python-support' +old_extensionpath='/usr/lib/python-support' +shared_path='/usr/share/pyshared' +shared_extensionpath='/usr/lib/pyshared' + +parser = OptionParser(usage="usage: %prog [-v] [-c] package_directory [...]\n"+ + " %prog [-v] [-c] package.dirs [...]\n"+ + " %prog [-v] [-a|-f|-p]") +parser.add_option("-v", "--verbose", action="store_true", dest="verbose", + help="verbose output", default=False) +parser.add_option("-c", "--clean", action="store_true", dest="clean_mode", + help="clean modules instead of compiling them", + default=False) +parser.add_option("-a", "--rebuild-all", action="store_true", + dest="rebuild_all", default=False, + help="rebuild all private modules for a new default python version") +parser.add_option("-f", "--force-rebuild-all", action="store_true", + dest="rebuild_everything", default=False, + help="rebuild all modules, including public modules for all python versions") +parser.add_option("-p", "--post-install", action="store_true", dest="post_install", + help="run post-installation operations, common to many packages", + default=False) +parser.add_option("-b", "--bytecompile", action="store_true", dest="force_private", + help="[deprecated] byte-compilation mode: only handle private modules", + default=False) +parser.add_option("-i", "--install", action="store_true", dest="force_public", + help="[deprecated] installation mode: only handle public modules", + default=False) +(options, args) = parser.parse_args() + +def debug(x): + if(options.verbose): + print x + +def warning(x): + sys.stderr.write("WARNING: %s\n"%x) + +def isect(l1,l2): + return [i for i in l1 if i in l2] + +def concat(l1,l2): + return l1 + [i for i in l2 if i not in l1] + + +# Abstract class implementing the methods related to public modules +class _PublicList (list): + pyversions = py_supported + def install (self, versions): + versions = isect (self.pyversions, versions) + for filename in self: + version = None + rng = versions + try: + if filename.startswith (shared_path+"/"): + # New layout, module + relname = filename[len(shared_path)+1:] + elif filename.startswith (shared_extensionpath+"/python"): + # New layout, extension + [ version, relname ] = filename[len(shared_extensionpath)+1:].split("/", 1) + elif filename.startswith (sourcepath+"/"): + [ package, relname ] = filename[len(sourcepath)+1:].split("/",1) + elif filename.startswith (old_extensionpath+"/"): + [ package, version, relname ] = filename[len(old_extensionpath)+1:].split("/",2) + else: + raise ValueError + except ValueError: + warning ("%s contains an invalid filename (%s)"%(self.name, filename)) + continue + if version: + if version not in versions: + continue + rng = [version] + for pyversion in rng: + destpath = os.path.join (basepath, pyversion, relname) + try: + os.makedirs(os.path.dirname(destpath)) + except OSError: + pass + if filename[-4:] not in ['.pyc', '.pyo']: + debug("link "+destpath) + # os.path.exists returns False for broken symbolic links + if os.path.exists(destpath) or os.path.islink(destpath): + if file!="__init__.py" or (os.path.exists(destpath) and os.path.getsize(destpath)): + # The file is already here, probably from the previous version. + # No need to check for conflicts, dpkg catches them earlier now + debug("overwrite "+destpath) + else: + debug("overwrite namespace "+destpath) + if os.path.isdir(destpath): + shutil.rmtree(destpath) + else: + os.remove(destpath) + os.symlink(filename,destpath) + + +# Abstract class implementing the methods related to private modules +class _PrivateList (list): + pyversion = None + def bytecompile (self): + if self.pyversion: + debug("Byte-compilation of whole %s with python%s..."%(self.name,self.pyversion)) + call(['/usr/bin/python'+self.pyversion, + os.path.join('/usr/lib','python'+self.pyversion,'py_compile.py')] + + self) + else: + for filename in self: + debug("compile "+filename+'c') + try: + # Note that compile doesn't raise PyCompileError by default + compile(filename, doraise=True) + except IOError, (errno, strerror): + warning("I/O error while trying to byte-compile %s (%s): %s" % (filename, errno, strerror)) + except PyCompileError, inst: + warning("compile error while trying to byte-compile %s: %s" % (filename, inst.msg)) + except: + warning("unexpected error while trying to byte-compile %s: %s" % (filename, sys.exc_info()[0])) + def clean(self): + for filename in self: + for ext in ['c', 'o']: + fullpath=filename+ext + if os.path.exists(fullpath): + debug("remove "+fullpath) + os.remove(fullpath) + + +# Abstract class for PrivateFileList and SharedFileList +class _FileList(list): + def __init__ (self, path): + self.name = path + for line in file(path): + line = line.strip() + if (not line) or line.startswith('#'): + continue + if line.startswith('/'): + self.append(line) + continue + line = [x.strip() for x in line.split('=',1)] + if len(line) != 2: + warning("Parse error in %s"%path) + continue + self.parse_option(*line) + +# This class represents a file list as provided in the /usr/share/python-support/$package.public +# Useful for public modules and extensions +class SharedFileList(_FileList, _PublicList): + def parse_option (self, arg, value): + if arg=='pyversions': + self.pyversions = pysupport.version_list(value) + # Ignore unknown arguments for extensivity + +# This class represents a file list as provided in the /usr/share/python-support/$package.private +# Useful for private modules +class PrivateFileList(_FileList, _PrivateList): + def parse_option (self, arg, value): + if arg=='pyversion': + self.pyversion = value + +# This is a helper generator that goes through files of interest in a given directory +def allfiles(path, onlypy=False): + for root, dirs, files in os.walk(path): + for f in files: + if (onlypy and not f.endswith(".py")) or f== ".version": + continue + yield os.path.join(root,f) + if not onlypy: + for d in dirs: + d = os.path.join(root, d) + if os.path.islink(d): + yield d + +# This class emulates the file listing as provided by /usr/share/python-support/$package.public +# with the deprecated layout /usr/{lib,share}/python-support/$package/ +class SharedDirList(_PublicList): + def __init__ (self, path): + self.name = path + # Add all files to the file listing + self.extend(allfiles(path)) + verfile=os.path.join(path,'.version') + extdir=path.replace(sourcepath,old_extensionpath,1) + if os.path.isfile(verfile): + # If we have a .version, use it + self.pyversions = pysupport.version_list(file(verfile).readline()) + elif os.path.isdir(extdir): + # Try to obtain the list of supported versions + # from the extensions in /usr/lib + self.pyversions = isect(py_supported,os.listdir(extdir)) + else: + # Otherwise, support all versions + pass + + if os.path.isdir(extdir): + # Add the extensions to the file listing + for version in self.pyversions: + self.extend(allfiles(os.path.join(extdir,version))) + +# This class emulates the file listing as provided by /usr/share/python-support/$package.private +# with the deprecated layout /usr/share/python-support/$package.dirs +class PrivateDirList(_PrivateList): + def __init__ (self, path): + self.name = path + self.extend(allfiles(path, onlypy=True)) + versionfile = os.path.join(path, ".pyversion") + if os.path.isfile(versionfile): + self.pyversion = file(versionfile).readline().strip() + + +class CachedFileList(dict): + def __getitem__ (self, name): + if name in self and dict.__getitem__(self, name) == None: + if name.startswith("/"): + # The case of old-style private directories + self[name] = PrivateDirList (name) + else: + path = os.path.join (sourcepath, name) + if name.endswith(".public"): + self[name] = SharedFileList (path) + elif name.endswith(".private"): + self[name] = PrivateFileList (path) + elif os.path.isdir(path): + self[name] = SharedDirList (path) + else: + raise Exception("[Internal Error] I don't know what to do with this path: %s"%path) + return dict.__getitem__(self, name) + + +def bytecompile_all(py,path=None): + if not path: + path=os.path.join(basepath,py) + if not os.path.isdir(path): + return + debug("Byte-compilation of whole %s..."%path) + os.spawnl(os.P_WAIT, '/usr/bin/'+py, py, + os.path.join('/usr/lib/',py,'compileall.py'), '-q', path) + +# A function to create the ".path" at the root of the installed directory +# Returns the list of affected directories +def create_dotpath(py): + path=os.path.join(basepath,py) + if not os.path.isdir(path): + return + pathfile=os.path.join(path,".path") + debug("Generation of %s..."%pathfile) + pathlist=[path] + ret=[] + for f in os.listdir(path): + f=os.path.join(path,f) + if f.endswith(".pth") and os.path.isfile(f): + for l in file(f): + l=l.rstrip('\n') + if l.startswith('import'): + # Do not ship lines starting with "import", they are executed! (complete WTF) + continue + pathlist.append(l) + l2=os.path.join(path,l) + pathlist.append(l2) + ret.append(l2) + fd=file(pathfile,"w") + fd.writelines([l+'\n' for l in pathlist]) + fd.close() + return ret + +def post_change_stuff(py): + # All the changes that need to be done after anything has changed + # in a /usr/lib/pymodules/pythonX.Y directory + # * Cleanup of all dangling symlinks that are left out after a package + # is upgraded/removed. + # * The namespace packages are here because python doesn't consider a + # directory to be able to contain packages if there is no __init__.py + # file (yes, this is completely stupid). + # * The .path file must be created by concatenating all those .pth + # files that extend sys.path (this also badly sucks). + # * Byte-compilation of all .py files that haven't already been + path=os.path.join(basepath,py) + if not os.path.isdir(path): + return + # First, remove any dangling symlinks. + # In the same loop, we find which directories may need a namespace package + dirhash={} + for dir, dirs, files in os.walk(path): + dirhash[dir]=False + files.sort() # We need the .py to appear before the .pyc + for f in files+dirs: + # We also examine dirs as some symlinks are dirs + abspath=os.path.join(dir,f) + islink=os.path.islink(abspath) + if islink: + if not os.path.exists(abspath): + # We refer to a file that was removed + debug("remove "+abspath) + os.remove(abspath) + continue + srcfile = os.readlink (abspath) + # Remove links left here after a change in the supported python versions for a package + removed = False + for package in public_packages: + if srcfile in public_packages[package]: + if py not in public_packages[package].pyversions: + debug("remove "+abspath) + os.remove(abspath) + removed = True + break + else: + # Remove files provided by packages that do not use python-support anymore + debug("remove "+abspath) + os.remove(abspath) + removed = True + if removed: + # Do not go further, the file was removed + continue + if f[-4:] in ['.pyc', '.pyo']: + if not os.path.exists(abspath[:-1]): + debug("remove "+abspath) + os.remove(abspath) + continue + elif f[-3:] in ['.py', '.so']: + if islink or f!='__init__.py': + # List the directory as maybe needing a namespace packages + d=dir + while dirhash.has_key(d) and not dirhash[d]: + dirhash[d]=True + d=os.path.dirname(d) + # Remove the directory if it is empty after our crazy removals + try: + os.removedirs(dir) + except OSError: + pass + dirhash[path]=False + # Then, find which directories belong in a .pth file + # These directories don't need a namespace package, so we + # set them to False in dirhash + for p in create_dotpath (py): + dirhash[p] = False + # Finally, create/remove namespace packages + for dir in dirhash: + initfile=os.path.join(dir,"__init__.py") + noinitfile=os.path.join(dir,".noinit") + if dirhash[dir] and not os.path.exists(noinitfile): + if not os.path.exists(initfile): + debug("create namespace "+initfile) + file(initfile,"w").close() + else: + for e in ['','c','o']: + if os.path.exists(initfile+e): + debug('remove namespace '+initfile+e) + os.remove(initfile+e) + try: + os.removedirs(dir) + except OSError: + pass + bytecompile_all(py) + + +# A helper function for older $package.dirs files +def dirlist_file(f): + return [ l.rstrip('\n') for l in file(f) if len(l)>1 ] + +# End of function definitions - Start of the script itself + +# Ensure that the umask is sane +os.umask(022) + +# Read all modules listing +public_packages = CachedFileList() +private_packages = CachedFileList() +dirlisting = os.listdir(sourcepath) +for name in dirlisting: + path=os.path.join(sourcepath,name) + if name == "private": + continue + ext = name.split(".")[-1] + if os.path.isdir(path): + if ext in ["public", "private", "dirs"]: + # Presumably a bogus directory, see #528130 + warning("%s is a directory"%name) + else: + public_packages[name] = None + continue + if not os.path.isfile(path): + # Ignore whatever is not a file, like dangling symlinks + continue + if ext == "public": + public_packages[name] = None + elif ext == "private": + private_packages[name] = None + elif ext == "dirs": + for dirname in dirlist_file (path): + private_packages[dirname] = None + # Just ignore all other files + +# Parse arguments +do_public=[] +do_private=[] +for arg in args: + if arg.startswith(sourcepath): + arg = arg[len(sourcepath):].lstrip("/") + if arg.endswith(".dirs") and arg in dirlisting: + for dirname in dirlist_file(os.path.join(sourcepath, arg)): + do_private.append(private_packages[dirname]) + elif arg in public_packages: + do_public.append(public_packages[arg]) + elif arg in private_packages: + do_private.append(private_packages[arg]) + else: + if options.clean_mode: + warning("%s does not exist.\n Some bytecompiled files may be left behind."%arg) + else: + parser.error("%s is not a recognized python-support module."%arg) + +# Check consistency options (although these ones should not exist anymore) +if do_private and options.force_public: + parser.error("Option -i cannot be used with a .private module file.") +if do_public and options.force_private: + parser.error("Option -b cannot be used with a .public module file.") + +if options.rebuild_everything: + options.rebuild_all = True + for pyver in py_supported: + dir = os.path.join(basepath,pyver) + if os.path.isdir(dir): + shutil.rmtree(dir) + +# Check for changes in installed python versions +need_postinstall = [] +for pyver in py_oldversions+py_supported: + dir = os.path.join(basepath,pyver) + # Check for ".path" because sometimes the directory already exists + # while the python version isn't installed, because of some .so's. + if pyver not in py_installed and os.path.isdir(dir): + debug("Removing obsolete directory %s..."%(dir)) + shutil.rmtree(dir) + if pyver in py_installed and not os.path.isfile(os.path.join(dir,".path")): + need_postinstall.append(pyver) +if need_postinstall: + debug("Building all modules for %s..."%(" ".join(need_postinstall))) + for package in public_packages: + public_packages[package].install(need_postinstall) + for pyver in need_postinstall: + # Here we need to launch create_dotpath because otherwise we could + # end up without the .path file that is checked 6 lines earlier + create_dotpath(pyver) + +if options.rebuild_all: + for package in private_packages: + private_packages[package].bytecompile() + + +# Now for the processing of what was handed on the command line +for package in do_private: + if not options.clean_mode: + package.bytecompile() + else: + package.clean() + +need_dotpath = False +for package in do_public: + need_postinstall = concat (need_postinstall, isect(package.pyversions,py_installed)) + if options.clean_mode: + continue + package.install(py_installed) + for f in package: + if f.endswith(".pth"): + need_dotpath = True + +# Only do the funny and time-consuming things when the -p option is +# given, e.g when python-support is triggered. +if need_postinstall and 'DPKG_RUNNING_VERSION' in os.environ and not options.post_install: + ret = os.spawnlp(os.P_WAIT, 'dpkg-trigger', 'dpkg-trigger', '--no-await', 'pysupport') + if ret: + sys.stderr.write("ERROR: dpkg-trigger failed\n") + sys.exit(1) + if need_dotpath: + for py in need_postinstall: + create_dotpath (py) + need_postinstall = [] + +if options.post_install: + # The trigger has been activated; do it for all installed versions + need_postinstall = py_installed +if need_postinstall: + need_dotpath = False + for py in need_postinstall: + post_change_stuff(py) + diff --git a/update-python-modules.8 b/update-python-modules.8 new file mode 100644 index 0000000..ca8f269 --- /dev/null +++ b/update-python-modules.8 @@ -0,0 +1,84 @@ +.TH UPDATE-PYTHON-MODULES 8 "18 Feb 2009" +.\" Please adjust this date whenever revising the manpage. +.SH NAME +update-python-modules \- byte-compile python modules +.SH SYNOPSIS +.B update-python-modules +.RI [ options "] [" package.public " [...]]" +.SH DESCRIPTION +The +.B update-python-modules +command is part of the +.B python-support +bundle. +.PP +.B update-python-modules +is responsible for the byte-compilation of python modules. When used in +byte-compilation mode, it will byte-compile modules references in the +files given on the command line. When used in installation mode, it will +byte-compile them once for each installed python version, and will make +them available for all of them. +.PP +At each invocation, with or without arguments, +.B update-python-modules +will check for installed python versions, and will build or remove +modules according to new or removed versions since the last time it was +run. +.SH ARGUMENTS +Arguments must be files or directories located in the +.I /usr/share/python-support +directory. Depending on their extension, they are treated differently. +.TP +.IR package .public +A file listing public modules to install for each version. These modules +must lie in +.I /usr/share/pyshared +or +.IR /usr/lib/pyshared . +.TP +.IR package .private +A file listing private modules to byte-compile for one Python version. +.TP +.IR package / +A legacy directory hierarchy of public modules. The C extensions and +portions that change with the Python version are to be found in +.IR /usr/lib/python-support/python X.Y / package / . +.TP +.IR package.dirs +A legacy file listing directories where to find private modules. +.SH OPTIONS +.TP +.B \-h, \-\-help +Show summary of options. +.TP +.B \-v, \-\-verbose +Detail all actions while they are performed. +.TP +.B \-b, \-\-bytecompile +Only accept to work on private modules. When given this option, +.B update-python-modules +will fail if passed references to public modules. +.TP +.B \-i, \-\-install +Only accept to work on public modules. When given this option, +.B update-python-modules +will fail if passed references to public modules. +.TP +.B \-c, \-\-clean +Clean modules instead of installing them. +.TP +.B \-a, \-\-rebuild\-all +Rebuild all private modules. This is necessary when the default python +version was changed, for example. +\.TP +.B \-f, \-\-force\-rebuild\-all +Clean all modules (public and private), and rebuild them. +.SH FILES +.TP +.IR /usr/lib/pymodules/python X.Y / +These directories contain the byte-compiled modules for version +.RI python X.Y . +.SH SEE ALSO +/usr/share/doc/python-support/README.gz +.SH AUTHOR +Josselin Mouette .