From 3123152454873855d5f11b26b6e463825d44be28 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sat, 21 Mar 2015 16:06:10 +0000 Subject: [PATCH] Moved to https://github.com/0install/0compile --- 0compile | 101 ----- 0compile.1 | 170 -------- 0compile.xml | 58 --- COPYING | 510 ------------------------ INSTALL | 11 - autocompile.py | 588 ---------------------------- bugs.py | 40 -- build.py | 670 -------------------------------- clean.py | 20 - copysrc.py | 63 --- gui.py | 53 --- gui_support.py | 362 ----------------- include_deps.py | 44 --- publish.py | 76 ---- setup.py | 72 ---- support.py | 369 ------------------ tests/0compile-coverage | 30 -- tests/bad-version.xml | 12 - tests/build-deps.xml | 17 - tests/cprog/Makefile | 14 - tests/cprog/cprog-command.xml | 24 -- tests/cprog/cprog.xml | 16 - tests/cprog/main.c | 6 - tests/hello2/hello2 | 7 - tests/hello2/hello2.xml | 26 -- tests/pinned-version/main.py | 4 - tests/pinned-version/pinned-version.xml | 25 -- tests/runall.py | 44 --- tests/selections.xml | 1 - tests/testcompile.py | 285 -------------- tests/top-build-deps.xml | 11 - tests/top.xml | 15 - 32 files changed, 3744 deletions(-) delete mode 100755 0compile delete mode 100644 0compile.1 delete mode 100644 0compile.xml delete mode 100644 COPYING delete mode 100644 INSTALL delete mode 100644 autocompile.py delete mode 100644 bugs.py delete mode 100644 build.py delete mode 100644 clean.py delete mode 100644 copysrc.py delete mode 100644 gui.py delete mode 100644 gui_support.py delete mode 100644 include_deps.py delete mode 100644 publish.py delete mode 100644 setup.py delete mode 100644 support.py delete mode 100755 tests/0compile-coverage delete mode 100644 tests/bad-version.xml delete mode 100644 tests/build-deps.xml delete mode 100644 tests/cprog/Makefile delete mode 100644 tests/cprog/cprog-command.xml delete mode 100644 tests/cprog/cprog.xml delete mode 100644 tests/cprog/main.c delete mode 100755 tests/hello2/hello2 delete mode 100644 tests/hello2/hello2.xml delete mode 100755 tests/pinned-version/main.py delete mode 100644 tests/pinned-version/pinned-version.xml delete mode 100755 tests/runall.py delete mode 100644 tests/selections.xml delete mode 100755 tests/testcompile.py delete mode 100644 tests/top-build-deps.xml delete mode 100644 tests/top.xml diff --git a/0compile b/0compile deleted file mode 100755 index 92afb2f..0000000 --- a/0compile +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2006, Thomas Leonard -# See the README file for details, or visit http://0install.net. - -__builtins__._ = lambda x: x - -import locale -from optparse import OptionParser -import os, sys -from logging import warn -import gobject; gobject.threads_init() - -zeroinstall_dir = os.environ.get('0COMPILE_ZEROINSTALL', None) -if zeroinstall_dir: - sys.path.insert(1, zeroinstall_dir) - -from zeroinstall import SafeException - -class UsageError(SafeException): pass - -commands = [] - -import autocompile, setup, clean, copysrc, build, publish, gui, bugs, include_deps -import support - -version = '1.4' - -try: - locale.setlocale(locale.LC_ALL, '') -except locale.Error: - warn('Error setting locale (eg. Invalid locale)') - -parser = OptionParser(usage="usage: %prog " + - '\n %prog '.join([c.__doc__ for c in commands])) - -parser.add_option("-c", "--console", help="never use GUI", action='store_true') -parser.add_option("-v", "--verbose", help="more verbose output", action='count') -parser.add_option("-V", "--version", help="display version information", action='store_true') - -parser.disable_interspersed_args() - -(options, args) = parser.parse_args() - -if options.version: - print "0compile (zero-install) " + version - print "Copyright (C) 2006 Thomas Leonard" - print "This program comes with ABSOLUTELY NO WARRANTY," - print "to the extent permitted by law." - print "You may redistribute copies of this program" - print "under the terms of the GNU General Public License." - print "For more information about these matters, see the file named COPYING." - sys.exit(0) - -if options.verbose: - import logging - logger = logging.getLogger() - if options.verbose == 1: - logger.setLevel(logging.INFO) - else: - logger.setLevel(logging.DEBUG) - -if options.console: - support.install_prog.append('--console') - -if len(args) < 1: - parser.print_help() - sys.exit(1) - -try: - pattern = args[0].lower() - matches = [c for c in commands if c.__name__[3:].replace('_', '-').startswith(pattern)] - if len(matches) == 0: - parser.print_help() - sys.exit(1) - if len(matches) > 1: - raise SafeException("What do you mean by '%s'?\n%s" % - (pattern, '\n'.join(['- ' + x.__name__[3:] for x in matches]))) - matches[0](args[1:]) -except KeyboardInterrupt, ex: - print >>sys.stderr, "Interrupted" - sys.exit(1) -except OSError, ex: - if options.verbose: raise - print >>sys.stderr, str(ex) - sys.exit(1) -except IOError, ex: - if options.verbose: raise - print >>sys.stderr, str(ex) - sys.exit(1) -except UsageError, ex: - print >>sys.stderr, str(ex) - print >>sys.stderr, "usage: " + os.path.basename(sys.argv[0]) + " " + matches[0].__doc__ - sys.exit(1) -except SafeException, ex: - if options.verbose: raise - try: - print >>sys.stderr, unicode(ex) - except: - print >>sys.stderr, repr(ex) - sys.exit(1) - diff --git a/0compile.1 b/0compile.1 deleted file mode 100644 index a8f5620..0000000 --- a/0compile.1 +++ /dev/null @@ -1,170 +0,0 @@ -.TH 0COMPILE 1 "2009" "Thomas Leonard" "" -.SH NAME -0compile \- create a Zero Install binary package from source - -.SH SYNOPSIS - -.B 0compile autocompile -[\fB--gui\fP] SOURCE-URI - -.B 0compile setup -[\fB--no-prompt\fP] [\fBSOURCE-URI\fP [\fBDIR\fP] ] - -.B 0compile build -[\fB--nosandbox\fP ] [\fB--shell\fP] - -.B 0compile publish -[\fBDOWNLOAD-BASE-URL\fP] - -.B 0compile clean - -.B 0compile copy-src - -.B 0compile diff - -.B 0compile gui -[\fB--no-prompt\fP] [\fBSOURCE-URI\fP] - -.B 0compile include-deps - -.B 0compile report-bug - -.SH DESCRIPTION -.PP -0compile can be used to compile a Zero Install package from its source code. - -.SH AUTOCOMPILE - -.PP -Download and build the source code for the given program. Also download and build -any missing dependencies, recursively. The resulting binaries will be placed in the -Zero Install implementation cache (just like normal binary downloads). A feed file -describing each new binary is created under $XDG_CONFIG_DIRS/0install.net/0compile/builds/ -and registered with Zero Install (using "0launch --feed"). - -.PP -On error, 0compile will display the name of the temporary directory in which it was -compiling the component which failed. You can cd to this directory and fix the problem -using the other 0compile commands. - -.SH SETUP - -.PP -To set up a build environment for the GNU Hello World example: - -.B 0compile setup http://0install.net/tests/GNU-Hello.xml GNU-Hello - -.PP -This downloads the source and any build dependencies into the Zero Install -cache, and creates a new directory called GNU-Hello. - -.PP -If the name is "." then it uses the current directory instead of creating a new one. - -.SH BUILD - -.PP -To compile the code, cd to the directory created by "setup" above, and then: - -.B 0compile build - -.PP -The resulting package will be in a new gnu-hello-1.3 subdirectory (or whatever version you downloaded). -Temporary build files will be in a new "build" subdirectory. These are kept to make rebuilds faster, but -you can delete them if you don't plan to recompile. - -.SH PUBLISH - -.PP -To create an archive that other people can download: - -.B 0compile publish http://mysite/downloads - -The will archive the target directory. Upload the resulting tarball to the downloads directory on your web-server. -The command will also create an XML file which can be used to download and run this version. - -.SH CLEAN - -Deletes the 'build' and distribution directories, if present. - -.SH COPY-SRC - -.PP -To make changes to the code before compiling: - -.B 0compile copy-src - -This copies the source code from the cache into a new "src" subdirectory. Edit to taste and then "build". - -.SH DIFF - -To see the differences between the original (cached) source code and the copy in your "src" directory: - -.B 0compile diff - -.SH INCLUDE-DEPS - -To create a self-contained bundle with the source code and build dependencies: - -.B 0compile include-deps - -This copies all required items from the Zero Install cache to a new "dependencies" subdirectory. The whole -directory tree (including the "dependencies" subdirectory) can then be copied to the build machine. This is -useful if the build machine doesn't have network access, and so can't download them itself. - -.PP -Note that this doesn't include the 0compile program itself. - -.SH GUI - -To bring up the GTK interface, which offers an newbie-friendly interface to some of the features above: - -.B 0compile gui - -Note, if you want a more automatic compile-and-register operation, your probably want this instead: - -.B 0compile autocompile --gui URI - -.SH REPORT-BUG - -To send a bug-report about a failed build: - -.B 0compile report-bug - - -.SH COMMAND-LINE OPTIONS - -.TP -\fB-h\fP, \fB--help\fP -Show the built-in help text. - -.TP -\fB-v\fP, \fB--verbose\fP -More verbose output. Use twice for even more verbose output. - -.TP -\fB-V\fP, \fB--version\fP -Display version information. - -.SH LICENSE -.PP -Copyright (C) 2009 Thomas Leonard. - -.PP -You may redistribute copies of this program under the terms of the GNU General Public License. -.SH BUGS -.PP -Please report bugs to the developer mailing list: - -http://0install.net/support.html - -.SH AUTHOR -.PP -The Zero Install Injector was created by Thomas Leonard. - -.SH SEE ALSO -0launch(1), 0store(1) -.PP -The Zero Install web-site: - -.B http://0install.net/0compile.html diff --git a/0compile.xml b/0compile.xml deleted file mode 100644 index 3373b64..0000000 --- a/0compile.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - 0compile - create a binary release from source code - -0compile creates a binary from source code, either for your own use or ready for -publishing on the web through Zero Install. It can use Zero Install to download -any build dependencies (compilers, header files, build tools, etc). - -This is useful if there is no binary for your platform, or if you wish to modify -the program in some way. - -If plash is installed, it can be used to sandbox the build so that it can't -accidentally modify any files outside of the build directory. - -For a full tutorial, see 0compile's homepage. - http://0install.net/0compile.html - - - - - - sed -i "s/^version = '.*'$/version = '$RELEASE_VERSION'/" 0compile - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/COPYING b/COPYING deleted file mode 100644 index cf9b6b9..0000000 --- a/COPYING +++ /dev/null @@ -1,510 +0,0 @@ - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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. -^L - 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 -^L - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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/INSTALL b/INSTALL deleted file mode 100644 index ae1922d..0000000 --- a/INSTALL +++ /dev/null @@ -1,11 +0,0 @@ -Don't be confused by the setup.py... that's for the "0compile setup" subcommand! - -If you got this by cloning a GIT repository, register the feed like this: - -$ 0launch --feed 0compile.xml - -To check this version is selected by default, use: - -$ 0launch -g http://0install.net/2006/interfaces/0compile.xml - -In the Preferences box ensure "Help test new versions" is enabled. diff --git a/autocompile.py b/autocompile.py deleted file mode 100644 index 650a062..0000000 --- a/autocompile.py +++ /dev/null @@ -1,588 +0,0 @@ -# Copyright (C) 2009, Thomas Leonard -# See http://0install.net/0compile.html - -import sys, os, __main__, tempfile, subprocess, signal, shutil -from xml.dom import minidom -from optparse import OptionParser -from logging import warn - -from zeroinstall import SafeException -from zeroinstall.injector import arch, handler, driver, requirements, model, iface_cache, namespaces, writer, reader, qdom -from zeroinstall.injector.config import load_config -from zeroinstall.zerostore import manifest, NotStored -from zeroinstall.support import tasks, basedir, ro_rmtree - -from support import BuildEnv, canonicalize_machine, XMLNS_0COMPILE -import support - -build_target_machine_type = canonicalize_machine(support.uname[4]) -assert build_target_machine_type in arch.machine_ranks, "Build target machine type '{build_target_machine_type}' is not supported on this platform; expected one of {types}".format( - build_target_machine_type = build_target_machine_type, - types = list(arch.machine_ranks.keys())) - -# This is a bit hacky... -# -# We invent a new CPU type which is compatible with the host but worse than -# every existing type, and we use * for the OS type so that we don't beat 'Any' -# binaries either. This means that we always prefer an existing binary of the -# desired version to compiling a new one, but we'll compile a new version from source -# rather than use an older binary. -arch.machine_groups['newbuild'] = arch.machine_groups.get(build_target_machine_type, 0) -arch.machine_ranks['newbuild'] = max(arch.machine_ranks.values()) + 1 -host_arch = '*-newbuild' - -class ImplRestriction(model.Restriction): - reason = "Not the source we're trying to build" - - def __init__(self, impl_id): - self.impl_id = impl_id - - def meets_restriction(self, impl): - return impl.id == self.impl_id - - def __str__(self): - return _("implementation {impl}").format(impl = self.impl_id) - -class NewBuildImplementation(model.ZeroInstallImplementation): - # Assume that this (potential) binary is available so that we can select it as a - # dependency. - def is_available(self, stores): - return True - -def get_commands(src_impl): - """Estimate the commands that the generated binary would have.""" - cmd = src_impl.commands.get('compile', None) - if cmd is None: - warn("Source has no compile command! %s", src_impl) - return [] - - for elem in cmd.qdom.childNodes: - if elem.uri == XMLNS_0COMPILE and elem.name == 'implementation': - # Assume there's always a run command. Doesn't do any harm to have extra ones, - # and there are various ways this might get created. - commands = ['run'] - for e in elem.childNodes: - if e.uri == namespaces.XMLNS_IFACE and e.name == 'command': - commands.append(e.getAttribute('name')) - return commands - return [] - -def add_binary_deps(src_impl, binary_impl): - # If src_impl contains a template, add those dependencies to the potential binary. - # Note: probably we should add "include-binary" dependencies here too... - - compile_command = src_impl.commands['compile'] - - for elem in compile_command.qdom.childNodes: - if elem.uri == XMLNS_0COMPILE and elem.name == 'implementation': - template = elem - break - else: - return # No template - - for elem in template.childNodes: - if elem.uri == namespaces.XMLNS_IFACE and elem.name in ('requires', 'restricts', 'runner'): - dep = model.process_depends(elem, local_feed_dir = None) - binary_impl.requires.append(dep) - -class AutocompileCache(iface_cache.IfaceCache): - def __init__(self): - iface_cache.IfaceCache.__init__(self) - self.done = set() - - def get_feed(self, url, force = False): - feed = iface_cache.IfaceCache.get_feed(self, url, force) - if not feed: return None - - if feed not in self.done: - self.done.add(feed) - - # For each source impl, add a corresponding binary - # (the binary has no dependencies as we can't predict them here, - # but they're not the same as the source's dependencies) - - srcs = [x for x in feed.implementations.itervalues() if x.arch and x.arch.endswith('-src')] - for x in srcs: - new_id = '0compile=' + x.id - if not new_id in feed.implementations: - new = NewBuildImplementation(feed, new_id, None) - feed.implementations[new_id] = new - new.set_arch(host_arch) - new.version = x.version - - # Give it some dummy commands in case we're using it as a , etc (otherwise it can't be selected) - for cmd_name in get_commands(x): - cmd = qdom.Element(namespaces.XMLNS_IFACE, 'command', {'path': 'new-build', 'name': cmd_name}) - new.commands[cmd_name] = model.Command(cmd, None) - - # Find the - add_binary_deps(x, new) - - return feed - -class AutoCompiler: - # If (due to a bug) we get stuck in a loop, we use this to abort with a sensible error. - seen = None # ((iface, source_id) -> new_binary_id) - - def __init__(self, config, iface_uri, options): - self.iface_uri = iface_uri - self.options = options - self.config = config - - def pretty_print_plan(self, solver, root, indent = '- '): - """Display a tree showing the selected implementations.""" - iface = self.config.iface_cache.get_interface(root) - impl = solver.selections[iface] - if impl is None: - msg = 'Failed to select any suitable version (source or binary)' - elif impl.id.startswith('0compile='): - real_impl_id = impl.id.split('=', 1)[1] - real_impl = impl.feed.implementations[real_impl_id] - msg = 'Compile %s (%s)' % (real_impl.get_version(), real_impl.id) - elif impl.arch and impl.arch.endswith('-src'): - msg = 'Compile %s (%s)' % (impl.get_version(), impl.id) - else: - if impl.arch: - msg = 'Use existing binary %s (%s)' % (impl.get_version(), impl.arch) - else: - msg = 'Use existing architecture-independent package %s' % impl.get_version() - self.note("%s%s: %s" % (indent, iface.get_name(), msg)) - - if impl: - indent = ' ' + indent - for x in solver.requires[iface]: - self.pretty_print_plan(solver, x.interface, indent) - - def print_details(self, solver): - """Dump debugging details.""" - self.note("\nFailed. Details of all components and versions considered:") - for iface in solver.details: - self.note('\n%s\n' % iface.get_name()) - for impl, note in solver.details[iface]: - self.note('%s (%s) : %s' % (impl.get_version(), impl.arch or '*-*', note or 'OK')) - self.note("\nEnd details\n") - - @tasks.async - def compile_and_register(self, sels, forced_iface_uri = None): - """If forced_iface_uri, register as an implementation of this interface, - ignoring the any , etc.""" - - buildenv = BuildEnv(need_config = False) - buildenv.config.set('compile', 'interface', sels.interface) - buildenv.config.set('compile', 'selections', 'selections.xml') - - # Download any required packages now, so we can use the GUI to request confirmation, etc - download_missing = sels.download_missing(self.config, include_packages = True) - if download_missing: - yield download_missing - tasks.check(download_missing) - - tmpdir = tempfile.mkdtemp(prefix = '0compile-') - try: - os.chdir(tmpdir) - - # Write configuration for build... - - buildenv.save() - - sel_file = open('selections.xml', 'w') - try: - doc = sels.toDOM() - doc.writexml(sel_file) - sel_file.write('\n') - finally: - sel_file.close() - - # Do the build... - - build = self.spawn_build(buildenv.iface_name) - if build: - yield build - tasks.check(build) - - # Register the result... - dom = minidom.parse(buildenv.local_iface_file) - - feed_for_elem, = dom.getElementsByTagNameNS(namespaces.XMLNS_IFACE, 'feed-for') - claimed_iface = feed_for_elem.getAttribute('interface') - - if forced_iface_uri is not None: - if forced_iface_uri != claimed_iface: - self.note("WARNING: registering as feed for {forced}, though feed claims to be for {claimed}".format( - forced = forced_iface_uri, - claimed = claimed_iface)) - else: - forced_iface_uri = claimed_iface # (the top-level interface being built) - - version = sels.selections[sels.interface].version - - site_package_versions_dir = basedir.save_data_path('0install.net', 'site-packages', - *model.escape_interface_uri(forced_iface_uri)) - leaf = '%s-%s' % (version, build_target_machine_type) - site_package_dir = os.path.join(site_package_versions_dir, leaf) - self.note("Storing build in %s" % site_package_dir) - - # 1. Copy new version in under a temporary name. Names starting with '.' are ignored by 0install. - tmp_distdir = os.path.join(site_package_versions_dir, '.new-' + leaf) - shutil.copytree(buildenv.distdir, tmp_distdir, symlinks = True) - - # 2. Rename the previous build to .old-VERSION (deleting that if it already existed) - if os.path.exists(site_package_dir): - self.note("(moving previous build out of the way)") - previous_build_dir = os.path.join(site_package_versions_dir, '.old-' + leaf) - if os.path.exists(previous_build_dir): - shutil.rmtree(previous_build_dir) - os.rename(site_package_dir, previous_build_dir) - else: - previous_build_dir = None - - # 3. Rename the new version immediately after renaming away the old one to minimise time when there's - # no version. - os.rename(tmp_distdir, site_package_dir) - - # 4. Delete the old version. - if previous_build_dir: - self.note("(deleting previous build)") - shutil.rmtree(previous_build_dir) - - local_feed = os.path.join(site_package_dir, '0install', 'feed.xml') - assert os.path.exists(local_feed), "Feed %s not found!" % local_feed - - # Reload - our 0install will detect the new feed automatically - iface = self.config.iface_cache.get_interface(forced_iface_uri) - reader.update_from_cache(iface, iface_cache = self.config.iface_cache) - self.config.iface_cache.get_feed(local_feed, force = True) - - # Write it out - 0install will add the feed so that older 0install versions can find it - writer.save_interface(iface) - - seen_key = (forced_iface_uri, sels.selections[sels.interface].id) - assert seen_key not in self.seen, seen_key - self.seen[seen_key] = site_package_dir - except: - self.note("\nBuild failed: leaving build directory %s for inspection...\n" % tmpdir) - raise - else: - # Can't delete current directory on Windows, so move to parent first - os.chdir(os.path.join(tmpdir, os.path.pardir)) - - ro_rmtree(tmpdir) - - @tasks.async - def recursive_build(self, iface_uri, source_impl_id = None): - """Build an implementation of iface_uri and register it as a feed. - @param source_impl_id: the version to build, or None to build any version - @type source_impl_id: str - """ - r = requirements.Requirements(iface_uri) - r.source = True - r.command = 'compile' - - d = driver.Driver(self.config, r) - iface = self.config.iface_cache.get_interface(iface_uri) - d.solver.record_details = True - if source_impl_id is not None: - d.solver.extra_restrictions[iface] = [ImplRestriction(source_impl_id)] - - # For testing... - #p.target_arch = arch.Architecture(os_ranks = {'FreeBSD': 0, None: 1}, machine_ranks = {'i386': 0, None: 1, 'newbuild': 2}) - - while True: - self.heading(iface_uri) - self.note("\nSelecting versions for %s..." % iface.get_name()) - solved = d.solve_with_downloads() - if solved: - yield solved - tasks.check(solved) - - if not d.solver.ready: - self.print_details(d.solver) - raise d.solver.get_failure_reason() - self.note("Selection done.") - - self.note("\nPlan:\n") - self.pretty_print_plan(d.solver, r.interface_uri) - self.note('') - - needed = [] - for dep_iface_uri, dep_sel in d.solver.selections.selections.iteritems(): - if dep_sel.id.startswith('0compile='): - if not needed: - self.note("Build dependencies that need to be compiled first:\n") - self.note("- {iface} {version}".format(iface = dep_iface_uri, version = dep_sel.version)) - needed.append((dep_iface_uri, dep_sel)) - - if not needed: - self.note("No dependencies need compiling... compile %s itself..." % iface.get_name()) - build = self.compile_and_register(d.solver.selections, - # force the interface in the recursive case - iface_uri if iface_uri != self.iface_uri else None) - yield build - tasks.check(build) - return - - # Compile the first missing build dependency... - dep_iface_uri, dep_sel = needed[0] - - self.note("") - - #details = d.solver.details[self.config.iface_cache.get_interface(dep_iface.uri)] - #for de in details: - # print de - - dep_source_id = dep_sel.id.split('=', 1)[1] - seen_key = (dep_iface_uri, dep_source_id) - if seen_key in self.seen: - self.note_error("BUG: Stuck in an auto-compile loop: already built {key}!".format(key = seen_key)) - # Try to find out why the previous build couldn't be used... - dep_iface = self.config.iface_cache.get_interface(dep_iface_uri) - previous_build = self.seen[seen_key] - previous_build_feed = os.path.join(previous_build, '0install', 'feed.xml') - previous_feed = self.config.iface_cache.get_feed(previous_build_feed) - previous_binary_impl = previous_feed.implementations.values()[0] - raise SafeException("BUG: auto-compile loop: expected to select previously-build binary {binary}:\n\n{reason}".format( - binary = previous_binary_impl, - reason = d.solver.justify_decision(r, dep_iface, previous_binary_impl))) - - build = self.recursive_build(dep_iface_uri, dep_source_id) - yield build - tasks.check(build) - - assert seen_key in self.seen, (seen_key, self.seen) # Must have been built by now - - # Try again with that dependency built... - - def spawn_build(self, iface_name): - try: - subprocess.check_call([sys.executable, sys.argv[0], 'build']) - except subprocess.CalledProcessError as ex: - raise SafeException(str(ex)) - - def build(self): - self.seen = {} - tasks.wait_for_blocker(self.recursive_build(self.iface_uri)) - - def heading(self, msg): - self.note((' %s ' % msg).center(76, '=')) - - def note(self, msg): - print msg - - def note_error(self, msg): - print msg - -class GUIHandler(handler.Handler): - def downloads_changed(self): - self.compiler.downloads_changed() - - def confirm_import_feed(self, pending, valid_sigs): - return handler.Handler.confirm_import_feed(self, pending, valid_sigs) - - @tasks.async - def confirm_install(self, message): - from zeroinstall.injector.download import DownloadAborted - from zeroinstall.gtkui import gtkutils - import gtk - box = gtk.MessageDialog(self.compiler.dialog, - gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, gtk.BUTTONS_CANCEL, - message) - box.set_position(gtk.WIN_POS_CENTER) - - install = gtkutils.MixedButton('Install', gtk.STOCK_OK) - install.set_flags(gtk.CAN_DEFAULT) - box.add_action_widget(install, gtk.RESPONSE_OK) - install.show_all() - box.set_default_response(gtk.RESPONSE_OK) - box.show() - - response = gtkutils.DialogResponse(box) - yield response - box.destroy() - - if response.response != gtk.RESPONSE_OK: - raise DownloadAborted() - -class GTKAutoCompiler(AutoCompiler): - def __init__(self, config, iface_uri, options): - config.handler.compiler = self - - AutoCompiler.__init__(self, config, iface_uri, options) - self.child = None - - import pygtk; pygtk.require('2.0') - import gtk - - w = gtk.Dialog('Autocompile %s' % iface_uri, None, 0, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OK, gtk.RESPONSE_OK)) - self.dialog = w - - w.set_default_size(int(gtk.gdk.screen_width() * 0.8), - int(gtk.gdk.screen_height() * 0.8)) - - vpaned = gtk.VPaned() - w.vbox.add(vpaned) - w.set_response_sensitive(gtk.RESPONSE_OK, False) - - class AutoScroller: - def __init__(self): - tv = gtk.TextView() - tv.set_property('left-margin', 8) - tv.set_wrap_mode(gtk.WRAP_WORD_CHAR) - tv.set_editable(False) - swin = gtk.ScrolledWindow() - swin.add(tv) - swin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - buffer = tv.get_buffer() - - heading = buffer.create_tag('heading') - heading.set_property('scale', 1.5) - - error = buffer.create_tag('error') - error.set_property('background', 'white') - error.set_property('foreground', 'red') - - self.tv = tv - self.widget = swin - self.buffer = buffer - - def insert_at_end_and_scroll(self, data, *tags): - vscroll = self.widget.get_vadjustment() - if not vscroll: - # Widget has been destroyed - print data, - return - near_end = vscroll.upper - vscroll.page_size * 1.5 < vscroll.value - end = self.buffer.get_end_iter() - self.buffer.insert_with_tags_by_name(end, data, *tags) - if near_end: - cursor = self.buffer.get_insert() - self.buffer.move_mark(cursor, end) - self.tv.scroll_to_mark(cursor, 0, False, 0, 0) - - def set_text(self, text): - self.buffer.set_text(text) - - self.overall = AutoScroller() - self.details = AutoScroller() - - vpaned.pack1(self.overall.widget, True, False) - vpaned.pack2(self.details.widget, True, False) - - self.closed = tasks.Blocker('Window closed') - - w.show_all() - w.connect('destroy', lambda wd: self.closed.trigger()) - - def response(wd, resp): - if self.child is not None: - self.note_error('Sending TERM signal to build process group %d...' % self.child.pid) - os.kill(-self.child.pid, signal.SIGTERM) - else: - self.closed.trigger() - w.connect('response', response) - - def downloads_changed(self): - if self.config.handler.monitored_downloads: - msg = 'Downloads in progress:\n' - for x in self.config.handler.monitored_downloads: - msg += '- {url}\n'.format(url = x.url) - else: - msg = '' - self.details.set_text(msg) - - def heading(self, msg): - self.overall.insert_at_end_and_scroll(msg + '\n', 'heading') - - def note(self, msg): - self.overall.insert_at_end_and_scroll(msg + '\n') - - def note_error(self, msg): - self.overall.insert_at_end_and_scroll(msg + '\n', 'error') - - def build(self): - self.seen = {} - import gtk - try: - tasks.wait_for_blocker(self.recursive_build(self.iface_uri)) - except SafeException, ex: - self.note_error(str(ex)) - else: - self.heading('All builds completed successfully!') - self.dialog.set_response_sensitive(gtk.RESPONSE_CANCEL, False) - self.dialog.set_response_sensitive(gtk.RESPONSE_OK, True) - - tasks.wait_for_blocker(self.closed) - - @tasks.async - def spawn_build(self, iface_name): - assert self.child is None - - self.details.insert_at_end_and_scroll('Building %s\n' % iface_name, 'heading') - - # Group all the child processes so we can kill them easily - def become_group_leader(): - os.setpgid(0, 0) - devnull = os.open(os.devnull, os.O_RDONLY) - try: - self.child = subprocess.Popen([sys.executable, '-u', sys.argv[0], 'build'], - stdin = devnull, - stdout = subprocess.PIPE, stderr = subprocess.STDOUT, - preexec_fn = become_group_leader) - finally: - os.close(devnull) - - import codecs - decoder = codecs.getincrementaldecoder('utf-8')(errors = 'replace') - - while True: - yield tasks.InputBlocker(self.child.stdout, 'output from child') - got = os.read(self.child.stdout.fileno(), 100) - chars = decoder.decode(got, final = not got) - self.details.insert_at_end_and_scroll(chars) - if not got: break - - self.child.wait() - code = self.child.returncode - self.child = None - if code: - self.details.insert_at_end_and_scroll('Build process exited with error status %d\n' % code, 'error') - raise SafeException('Build process exited with error status %d' % code) - self.details.insert_at_end_and_scroll('Build completed successfully\n', 'heading') - - @tasks.async - def confirm_import_feed(self, pending, valid_sigs): - from zeroinstall.gtkui import trust_box - box = trust_box.TrustBox(pending, valid_sigs, parent = self.dialog) - box.show() - yield box.closed - -def do_autocompile(args): - """autocompile [--gui] URI""" - - parser = OptionParser(usage="usage: %prog autocompile [options]") - - parser.add_option('', "--gui", help="graphical interface", action='store_true') - (options, args2) = parser.parse_args(args) - if len(args2) != 1: - raise __main__.UsageError() - - if options.gui: - h = GUIHandler() - elif os.isatty(1): - h = handler.ConsoleHandler() - else: - h = handler.Handler() - config = load_config(handler = h) - config._iface_cache = AutocompileCache() - - iface_uri = model.canonical_iface_uri(args2[0]) - if options.gui: - compiler = GTKAutoCompiler(config, iface_uri, options) - else: - compiler = AutoCompiler(config, iface_uri, options) - - compiler.build() - -__main__.commands += [do_autocompile] diff --git a/bugs.py b/bugs.py deleted file mode 100644 index fcade0b..0000000 --- a/bugs.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import os, __main__, codecs -from os.path import join - -from support import BuildEnv - -def do_report_bug(args): - """report-bug""" - buildenv = BuildEnv() - - log_name = join('build', 'build-failure.log') - build_log = codecs.open(log_name, 'r', 'utf-8') - log_text = build_log.read() - build_log.close() - - build_env_xml_file = join(buildenv.metadir, 'build-environment.xml') - if os.path.exists(build_env_xml_file): - build_env_xml = file(build_env_xml_file) - log_text += '\n\nSelected versions:\n' + build_env_xml.read() - build_env_xml.close() - else: - log_text += '\n\n"%s" file not found' % build_env_xml_file - - log_text = codecs.encode(log_text, 'utf-8') - - import urllib - from urllib2 import urlopen - - print "Sending contents of %s file to default bug reporting site..." % log_name - - stream = urlopen('http://0install.net/api/report-bug/', - urllib.urlencode({ - 'uri': buildenv.interface, - 'body': log_text})) - print stream.read() - stream.close() - -__main__.commands.append(do_report_bug) diff --git a/build.py b/build.py deleted file mode 100644 index 8813474..0000000 --- a/build.py +++ /dev/null @@ -1,670 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import sys, os, __main__, time, shutil, glob, codecs, subprocess -from os.path import join -from logging import info, warn -from xml.dom import minidom, XMLNS_NAMESPACE -from optparse import OptionParser -import tempfile -import itertools - -from zeroinstall import SafeException -from zeroinstall.injector import model, namespaces, run -from zeroinstall.injector.iface_cache import iface_cache - -from support import BuildEnv, ensure_dir, XMLNS_0COMPILE, is_package_impl, parse_bool, depth, uname -from support import spawn_and_check, find_in_path, ENV_FILE, lookup, spawn_and_check_maybe_sandboxed, Prefixes - -# If we have to modify any pkg-config files, we put the new versions in $TMPDIR/PKG_CONFIG_OVERRIDES -PKG_CONFIG_OVERRIDES = 'pkg-config-overrides' - -def env(name, value): - os.environ[name] = value - print "%s=%s" % (name, value) - -def do_env_binding(binding, path): - if binding.insert is not None and path is None: - # Skip insert bindings for package implementations - return - env(binding.name, binding.get_value(path, os.environ.get(binding.name, None))) - -def correct_for_64bit(base, rel_path): - """If rel_path starts lib or usr/lib and doesn't exist, try with lib64 instead.""" - if os.path.exists(os.path.join(base, rel_path)): - return rel_path - - if rel_path.startswith('lib/') or rel_path.startswith('usr/lib/'): - new_rel_path = rel_path.replace('lib/', 'lib64/', 1) - if os.path.exists(os.path.join(base, new_rel_path)): - return new_rel_path - - return rel_path - -def write_pc(name, lines): - overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES) - if not os.path.isdir(overrides_dir): - os.mkdir(overrides_dir) - stream = open(os.path.join(overrides_dir, name), 'w') - stream.write(''.join(lines)) - stream.close() - -def do_pkg_config_binding(binding, impl): - if impl.id.startswith('package:'): - return # No bindings needed for native packages - feed_name = impl.feed.split('/')[-1] - path = lookup(impl) - new_insert = correct_for_64bit(path, binding.insert) - if new_insert != binding.insert: - print "PKG_CONFIG_PATH dir <%s>/%s not found; using %s instead" % (feed_name, binding.insert, new_insert) - binding = model.EnvironmentBinding(binding.name, - new_insert, - binding.default, - binding.mode) - - orig_path = os.path.join(path, binding.insert) - if os.path.isdir(orig_path): - for pc in os.listdir(orig_path): - stream = open(os.path.join(orig_path, pc)) - lines = stream.readlines() - stream.close() - for i, line in enumerate(lines): - if '=' not in line: continue - name, value = [x.strip() for x in line.split('=', 1)] - if name == 'prefix' and os.path.isabs(value): - print "Absolute prefix=%s in %s; overriding..." % (value, feed_name) - lines[i] = 'prefix=' + os.path.join( - path, os.path.splitdrive(value)[1][1:]) +'\n' - write_pc(pc, lines) - break - do_env_binding(binding, path) - -def shorten_dynamic_library_install_name(dylib_file): - # Only need to change actual library, not links to it - if os.path.islink(dylib_file): - return - otool_args = ['/usr/bin/otool', '-D', dylib_file] - process = subprocess.Popen(otool_args, stdout=subprocess.PIPE) - output, error = process.communicate() - retcode = process.poll() - for line in output.split('\n'): - if not line.endswith(':'): - value = line.strip() - print "Absolute install name=%s in %s; fixing..." % (value, dylib_file) - break - shortname = os.path.basename(dylib_file) - subprocess.check_call(['install_name_tool', '-id', shortname, dylib_file]) - -# After doing a build, remove the (dist) directory component from dynamic libraries -def shorten_dynamic_library_install_names(): - for root, dirs, files in os.walk(os.environ['DISTDIR']): - if os.path.basename(root) == 'lib': - for f in files: - if f.endswith('.dylib'): - info("Checking dynamic library '%s'", f) - shorten_dynamic_library_install_name(os.path.join(root, f)) - -def fixup_generated_pkgconfig_file(pc_file): - stream = open(pc_file) - lines = stream.readlines() - stream.close() - for i, line in enumerate(lines): - if '=' not in line: continue - name, value = [x.strip() for x in line.split('=', 1)] - if name == 'prefix' and os.path.isabs(value): - print "Absolute prefix=%s in %s; fixing..." % (value, pc_file) - rel_path = os.path.relpath(value, os.path.dirname(pc_file)) - lines[i] = 'prefix=' + os.path.join( - '${pcfiledir}', rel_path) + '\n' - write_pc(pc_file, lines) - break - -# After doing a build, check that we didn't generate pkgconfig files with absolute paths -# Rewrite if so -def fixup_generated_pkgconfig_files(): - for root, dirs, files in os.walk(os.environ['DISTDIR']): - if os.path.basename(root) == 'pkgconfig': - for f in files: - if f.endswith('.pc'): - info("Checking generated pkgconfig file '%s'", f) - fixup_generated_pkgconfig_file(os.path.join(root, f)) - -def remove_la_file(path): - # Read the contents... - stream = open(path) - data = stream.read() - stream.close() - - # Check it really is a libtool archive... - if 'Please DO NOT delete this file' not in data: - warn("Ignoring %s; doesn't look like a libtool archive", path) - return - - os.unlink(path) - print "Removed %s (.la files contain absolute paths)" % path - -# libtool archives contain hard-coded paths. Lucky, modern systems don't need them, so remove -# them. -def remove_la_files(): - for root, dirs, files in os.walk(os.environ['DISTDIR']): - if os.path.basename(root) == 'lib': - for f in files: - if f.endswith('.la'): - remove_la_file(os.path.join(root, f)) - if f.endswith('.a'): - warn("Found static archive '%s'; maybe build with --disable-static?", f) - -class CompileSetup(run.Setup): - def do_binding(self, impl, b, iface): - if isinstance(b, model.EnvironmentBinding): - if b.name == 'PKG_CONFIG_PATH': - do_pkg_config_binding(b, impl) - else: - do_env_binding(b, lookup(impl)) - else: - run.Setup.do_binding(self, impl, b, iface) - -def do_build_internal(options, args): - """build-internal""" - # If a sandbox is being used, we're in it now. - import getpass, socket - - buildenv = BuildEnv() - sels = buildenv.get_selections() - - builddir = os.path.realpath('build') - ensure_dir(buildenv.metadir) - - build_env_xml = join(buildenv.metadir, 'build-environment.xml') - - buildenv_doc = sels.toDOM() - - # Create build-environment.xml file - root = buildenv_doc.documentElement - info = buildenv_doc.createElementNS(XMLNS_0COMPILE, 'build-info') - root.appendChild(info) - info.setAttributeNS(None, 'time', time.strftime('%Y-%m-%d %H:%M').strip()) - info.setAttributeNS(None, 'host', socket.getfqdn()) - info.setAttributeNS(None, 'user', getpass.getuser()) - info.setAttributeNS(None, 'arch', '%s-%s' % (uname[0], uname[4])) - stream = file(build_env_xml, 'w') - buildenv_doc.writexml(stream, addindent=" ", newl="\n") - stream.close() - - # Create local binary interface file. - # We use the main feed for the interface as the template for the name, - # summary, etc (note: this is not necessarily the feed that contained - # the source code). - master_feed = iface_cache.get_feed(buildenv.interface) - src_impl = buildenv.chosen_impl(buildenv.interface) - write_sample_feed(buildenv, master_feed, src_impl) - - # Check 0compile is new enough - min_version = model.parse_version(src_impl.attrs.get(XMLNS_0COMPILE + ' min-version', None)) - if min_version and min_version > model.parse_version(__main__.version): - raise SafeException("%s-%s requires 0compile >= %s, but we are only version %s" % - (master_feed.get_name(), src_impl.version, model.format_version(min_version), __main__.version)) - - # Create the patch - patch_file = join(buildenv.metadir, 'from-%s.patch' % src_impl.version) - if buildenv.user_srcdir: - with open(patch_file, 'w') as stream: - # (ignore errors; will already be shown on stderr) - try: - subprocess.call(["diff", "-urN", buildenv.orig_srcdir, 'src'], stdout = stream) - except OSError as ex: - print >>sys.stderr, "WARNING: Failed to run 'diff': ", ex - if os.path.getsize(patch_file) == 0: - os.unlink(patch_file) - elif os.path.exists(patch_file): - os.unlink(patch_file) - - env('BUILDDIR', builddir) - env('DISTDIR', buildenv.distdir) - env('SRCDIR', buildenv.user_srcdir or buildenv.orig_srcdir) - env('BINARYFEED', buildenv.local_iface_file) - os.chdir(builddir) - print "cd", builddir - - setup = CompileSetup(iface_cache.stores, sels) - setup.prepare_env() - - # These mappings are needed when mixing Zero Install -dev packages with - # native package binaries. - mappings = {} - for impl in sels.selections.values(): - # Add mappings that have been set explicitly... - new_mappings = impl.attrs.get(XMLNS_0COMPILE + ' lib-mappings', '') - if new_mappings: - new_mappings = new_mappings.split(' ') - for mapping in new_mappings: - assert ':' in mapping, "lib-mappings missing ':' in '%s' from '%s'" % (mapping, impl.feed) - name, major_version = mapping.split(':', 1) - assert '/' not in mapping, "lib-mappings '%s' contains a / in the version number (from '%s')!" % (mapping, impl.feed) - if sys.platform == 'darwin': - mappings[name] = 'lib%s.%s.dylib' % (name, major_version) - else: - mappings[name] = 'lib%s.so.%s' % (name, major_version) - # Auto-detect required mappings where possible... - # (if the -dev package is native, the symlinks will be OK) - if not is_package_impl(impl): - impl_path = lookup(impl) - for libdirname in ['lib', 'usr/lib', 'lib64', 'usr/lib64']: - libdir = os.path.join(impl_path, libdirname) - if os.path.isdir(libdir): - find_broken_version_symlinks(libdir, mappings) - - if mappings: - set_up_mappings(mappings) - - overrides_dir = os.path.join(os.environ['TMPDIR'], PKG_CONFIG_OVERRIDES) - if os.path.isdir(overrides_dir): - add_overrides = model.EnvironmentBinding('PKG_CONFIG_PATH', PKG_CONFIG_OVERRIDES) - do_env_binding(add_overrides, os.environ['TMPDIR']) - - # Some programs want to put temporary build files in the source directory. - # Make a copy of the source if needed. - dup_src_type = src_impl.attrs.get(XMLNS_0COMPILE + ' dup-src', None) - if dup_src_type == 'true': - dup_src(copy_file) - env('SRCDIR', builddir) - elif dup_src_type: - raise Exception("Unknown dup-src value '%s'" % dup_src_type) - - if options.shell: - spawn_and_check(find_in_path('cmd' if os.name == 'nt' else 'sh'), []) - else: - command = sels.commands[0].qdom.attrs.get('shell-command', None) - if command is None: - # New style - prog_args = setup.build_command(sels.interface, sels.command) + args - else: - # Old style shell-command='...' - if os.name == 'nt': - prog_args = [os.environ['0COMPILE_BASH'], '-eux', '-c', command] + args - else: - prog_args = ['/bin/sh', '-c', command + ' "$@"', '-'] + args - assert len(sels.commands) == 1 - - # Remove any existing log files - for log in ['build.log', 'build-success.log', 'build-failure.log']: - if os.path.exists(log): - os.unlink(log) - - # Run the command, copying output to a new log - with open('build.log', 'w') as log: - print >>log, "Build log for %s-%s" % (master_feed.get_name(), - src_impl.version) - print >>log, "\nBuilt using 0compile-%s" % __main__.version - print >>log, "\nBuild system: " + ', '.join(uname) - print >>log, "\n%s:\n" % ENV_FILE - with open(os.path.join(os.pardir, ENV_FILE)) as properties_file: - shutil.copyfileobj(properties_file, log) - - log.write('\n') - - if os.path.exists(patch_file): - print >>log, "\nPatched with:\n" - shutil.copyfileobj(file(patch_file), log) - log.write('\n') - - if command: - print "Executing: " + command, args - print >>log, "Executing: " + command, args - else: - print "Executing: " + str(prog_args) - print >>log, "Executing: " + str(prog_args) - - # Tee the output to the console and to the log - child = subprocess.Popen(prog_args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) - while True: - data = os.read(child.stdout.fileno(), 100) - if not data: break - sys.stdout.write(data) - log.write(data) - status = child.wait() - failure = None - if status == 0: - print >>log, "Build successful" - shorten_dynamic_library_install_names() - fixup_generated_pkgconfig_files() - remove_la_files() - elif status > 0: - failure = "Build failed with exit code %d" % status - else: - failure = "Build failure: exited due to signal %d" % (-status) - if failure: - print >>log, failure - - if failure: - os.rename('build.log', 'build-failure.log') - raise SafeException("Command '%s': %s" % (prog_args, failure)) - else: - os.rename('build.log', 'build-success.log') - -def do_build(args): - """build [ --no-sandbox ] [ --shell | --force | --clean ]""" - buildenv = BuildEnv() - sels = buildenv.get_selections() - - parser = OptionParser(usage="usage: %prog build [options]") - - parser.add_option('', "--no-sandbox", help="disable use of sandboxing", action='store_true') - parser.add_option("-s", "--shell", help="run a shell instead of building", action='store_true') - parser.add_option("-c", "--clean", help="remove the build directories", action='store_true') - parser.add_option("-f", "--force", help="build even if dependencies have changed", action='store_true') - - parser.disable_interspersed_args() - - (options, args2) = parser.parse_args(args) - - builddir = os.path.realpath('build') - - changes = buildenv.get_build_changes() - if changes: - if not (options.force or options.clean): - raise SafeException("Build dependencies have changed:\n" + - '\n'.join(changes) + "\n\n" + - "To build anyway, use: 0compile build --force\n" + - "To do a clean build: 0compile build --clean") - if not options.no_sandbox: - print "Build dependencies have changed:\n" + '\n'.join(changes) - - ensure_dir(builddir, options.clean) - ensure_dir(buildenv.distdir, options.clean) - - if options.no_sandbox: - return do_build_internal(options, args2) - - tmpdir = tempfile.mkdtemp(prefix = '0compile-') - try: - my_dir = os.path.dirname(__file__) - readable = ['.', my_dir] - writable = ['build', buildenv.distdir, tmpdir] - env('TMPDIR', tmpdir) - - for selection in sels.selections.values(): - if not is_package_impl(selection): - readable.append(lookup(selection)) - - options = [] - if __main__.options.verbose: - options.append('--verbose') - - readable.append('/etc') # /etc/ld.* - - spawn_and_check_maybe_sandboxed(readable, writable, tmpdir, sys.executable, ['-u', sys.argv[0]] + options + ['build', '--no-sandbox'] + args) - finally: - info("Deleting temporary directory '%s'" % tmpdir) - shutil.rmtree(tmpdir) - -def find_feed_for(master_feed): - """Determine the interface for the new binary's feed. - remote feed (http://...) => the binary is a feed for the interface with this URI - local feed (/feed.xml) => copy from feed.xml (e.g. for a Git clone) - local copy of remote feed (no feed-for) => feed's uri attribute - """ - if hasattr(master_feed, 'local_path'): - is_local = master_feed.local_path is not None # 0install >= 1.7 - else: - is_local = os.path.isabs(master_feed.url) - - uri = master_feed.url - - if is_local: - print "Note: source %s is a local feed" % uri - for feed_uri in master_feed.feed_for or []: - uri = feed_uri - print "Will use instead..." % uri - break - else: - master_feed = minidom.parse(uri).documentElement - if master_feed.hasAttribute('uri'): - uri = master_feed.getAttribute('uri') - print "Will use instead..." % uri - - return uri - -# Convert compile:if-0install-version attributes to plain if-0install-version -def arm_if_0install_attrs(elem): - key = XMLNS_0COMPILE + ' if-0install-version' - old = elem.attrs.get(key, None) - if old: - del elem.attrs[key] - elem.attrs['if-0install-version'] = old - for child in elem.childNodes: - arm_if_0install_attrs(child) - -def write_sample_feed(buildenv, master_feed, src_impl): - path = buildenv.local_iface_file - - old_path = os.path.join(buildenv.metadir, buildenv.iface_name + '.xml') - if os.path.exists(old_path): - warn("Removing old %s file: use %s instead now", old_path, path) - os.unlink(old_path) - - impl = minidom.getDOMImplementation() - - XMLNS_IFACE = namespaces.XMLNS_IFACE - - doc = impl.createDocument(XMLNS_IFACE, "interface", None) - - root = doc.documentElement - root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns', XMLNS_IFACE) - prefixes = Prefixes(XMLNS_IFACE) - - def addSimple(parent, name, text = None): - elem = doc.createElementNS(XMLNS_IFACE, name) - - parent.appendChild(doc.createTextNode('\n' + ' ' * (1 + depth(parent)))) - parent.appendChild(elem) - if text: - elem.appendChild(doc.createTextNode(text)) - return elem - - def close(element): - element.appendChild(doc.createTextNode('\n' + ' ' * depth(element))) - - addSimple(root, 'name', master_feed.name) - addSimple(root, 'summary', master_feed.summary) - addSimple(root, 'description', master_feed.description) - feed_for = addSimple(root, 'feed-for') - - feed_for.setAttributeNS(None, 'interface', find_feed_for(master_feed)) - - group = addSimple(root, 'group') - main = src_impl.attrs.get(XMLNS_0COMPILE + ' binary-main', None) - if main: - group.setAttributeNS(None, 'main', main) - - lib_mappings = src_impl.attrs.get(XMLNS_0COMPILE + ' binary-lib-mappings', None) - if lib_mappings: - prefixes.setAttributeNS(group, XMLNS_0COMPILE, 'lib-mappings', lib_mappings) - - for d in src_impl.dependencies: - if parse_bool(d.metadata.get(XMLNS_0COMPILE + ' include-binary', 'false')): - requires = d.qdom.toDOM(doc, prefixes) - requires.removeAttributeNS(XMLNS_0COMPILE, 'include-binary') - group.appendChild(requires) - set_arch = True - - impl_elem = addSimple(group, 'implementation') - impl_template = buildenv.get_binary_template() - if impl_template: - arm_if_0install_attrs(impl_template) - - # Copy attributes from template - for fullname, value in impl_template.attrs.iteritems(): - if fullname == 'arch': - set_arch = False - if value == '*-*': - continue - if ' ' in fullname: - ns, localName = fullname.split(' ', 1) - else: - ns, localName = None, fullname - prefixes.setAttributeNS(impl_elem, ns, localName, value) - # Copy child nodes - for child in impl_template.childNodes: - impl_elem.appendChild(child.toDOM(doc, prefixes)) - if impl_template.content: - impl_elem.appendChild(doc.createTextNode(impl_template.content)) - - for version_elem in itertools.chain( - impl_elem.getElementsByTagName('version'), - ): - pin_components = version_elem.getAttributeNS(XMLNS_0COMPILE, "pin-components") - if pin_components: - pin_components = int(pin_components) - iface = version_elem.parentNode.getAttribute("interface") - assert iface - dep_impl = buildenv.chosen_impl(iface) - impl_version = model.parse_version(dep_impl.attrs.get('version')) - - pinned_components = [impl_version[0][:pin_components]] - # (for -pre versions) - min_version = min(pinned_components, impl_version) - - # clone and increment - max_version = [pinned_components[0][:]] - max_version[0][-1] += 1 - - version_elem.setAttribute("not-before", model.format_version(min_version)) - version_elem.setAttribute("before", model.format_version(max_version)) - - if set_arch: - group.setAttributeNS(None, 'arch', buildenv.target_arch) - - impl_elem.setAttributeNS(None, 'version', src_impl.version) - - if not impl_elem.hasAttribute('license'): - license = src_impl.attrs.get('license') - if license: - impl_elem.setAttributeNS(None, 'license', license) - - version_modifier = buildenv.version_modifier - if version_modifier: - impl_elem.setAttributeNS(None, 'version-modifier', version_modifier) - - impl_elem.setAttributeNS(None, 'id', '..') - impl_elem.setAttributeNS(None, 'released', time.strftime('%Y-%m-%d')) - close(group) - close(root) - - for ns, prefix in prefixes.prefixes.items(): - root.setAttributeNS(XMLNS_NAMESPACE, 'xmlns:' + prefix, ns) - - stream = codecs.open(path, 'w', encoding = 'utf-8') - try: - doc.writexml(stream) - finally: - stream.close() - -def find_broken_version_symlinks(libdir, mappings): - """libdir may be a legacy -devel package containing lib* symlinks whose - targets would be provided by the corresponding runtime package. If so, - create fixed symlinks under $TMPDIR with the real location.""" - prefix = 'lib' - if sys.platform == 'darwin': - extension = '.dylib' - else: - extension = '.so' - - for x in os.listdir(libdir): - if x.startswith(prefix) and x.endswith(extension): - path = os.path.join(libdir, x) - if os.path.islink(path): - target = os.readlink(path) - if '/' not in target and not os.path.exists(os.path.join(libdir, target)): - print "Broken link %s -> %s; will relocate..." % (x, target) - mappings[x[len(prefix):-len(extension)]] = target - -def set_up_mappings(mappings): - """Create a temporary directory with symlinks for each of the library mappings.""" - libdirs = [] - if sys.platform == 'darwin': - LD_LIBRARY_PATH='DYLD_LIBRARY_PATH' - else: - LD_LIBRARY_PATH='LD_LIBRARY_PATH' - for d in os.environ.get(LD_LIBRARY_PATH, '').split(':'): - if d: libdirs.append(d) - libdirs += ['/lib', '/usr/lib'] - - def add_ldconf(config_file): - if not os.path.isfile(config_file): - return - for line in file(config_file): - d = line.strip() - if d.startswith('include '): - glob_pattern = d.split(' ', 1)[1] - for conf in glob.glob(glob_pattern): - add_ldconf(conf) - elif d and not d.startswith('#'): - libdirs.append(d) - add_ldconf('/etc/ld.so.conf') - - def find_library(name, wanted): - # Takes a short-name and target name of a library and returns - # the full path of the library. - for d in libdirs: - path = os.path.join(d, wanted) - if os.path.exists(path): - return path - print "WARNING: library '%s' not found (searched '%s')!" % (wanted, libdirs) - return None - - mappings_dir = os.path.join(os.environ['TMPDIR'], 'lib-mappings') - os.mkdir(mappings_dir) - - old_path = os.environ.get('LIBRARY_PATH', '') - if old_path: old_path = ':' + old_path - os.environ['LIBRARY_PATH'] = mappings_dir + old_path - - if sys.platform == 'darwin': - soext='.dylib' - else: - soext='.so' - for name, wanted in mappings.items(): - target = find_library(name, wanted) - if target: - print "Adding mapping lib%s%s -> %s" % (name, soext, target) - os.symlink(target, os.path.join(mappings_dir, 'lib' + name + soext)) - -def copy_file(src, target): - if os.path.islink(src): - os.symlink(os.readlink(src), target) - else: - shutil.copy2(src, target) - -def dup_src(fn): - srcdir = os.path.join(os.environ['SRCDIR'], '') - builddir = os.environ['BUILDDIR'] - - build_in_src = srcdir + 'build' == builddir - - for root, dirs, files in os.walk(srcdir): - assert root.startswith(srcdir) - reldir = root[len(srcdir):] - - if '.git' in dirs: - print "dup-src: skipping", reldir - dirs.remove('.git') - - if (reldir == 'build' and build_in_src) or \ - ('0compile.properties' in files and not build_in_src): - print "dup-src: skipping", reldir - dirs[:] = [] - continue - - for f in files: - target = os.path.join(reldir, f) - #print "Copy %s -> %s" % (os.path.join(root, f), target) - if os.path.exists(target): - os.unlink(target) - fn(os.path.join(root, f), target) - for d in dirs: - target = os.path.join(reldir, d) - if not os.path.isdir(target): - os.mkdir(target) - -__main__.commands.append(do_build) diff --git a/clean.py b/clean.py deleted file mode 100644 index f9ab771..0000000 --- a/clean.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright (C) 2009, Thomas Leonard -# See http://0install.net/0compile.html - -import __main__, shutil, os - -from support import BuildEnv - -def do_clean(args): - """clean""" - if args: - raise __main__.UsageError() - - buildenv = BuildEnv() - - for x in ['build', buildenv.distdir]: - if os.path.exists(x): - print "Removing '%s'" % os.path.basename(x) - shutil.rmtree(x) - -__main__.commands.append(do_clean) diff --git a/copysrc.py b/copysrc.py deleted file mode 100644 index b00d8ee..0000000 --- a/copysrc.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import os, __main__ -import shutil - -from zeroinstall import SafeException - -from support import BuildEnv, lookup, find_in_path - -def do_copy_src(args): - """copy-src""" - if args: - raise __main__.UsageError() - - buildenv = BuildEnv() - - src_impl = buildenv.chosen_impl(buildenv.interface) - assert src_impl - path = lookup(src_impl) - assert path - - new_src = os.path.realpath('src') # Just for better messages - if os.path.exists(new_src): - raise SafeException("Directory '%s' already exists!" % new_src) - shutil.copytree(path, 'src', symlinks = True) - # Make all files writable by the owner - for root, dirs, files in os.walk('src'): - os.chmod(root, os.stat(root).st_mode | 0200) - for f in files: - path = os.path.join(root, f) - if not os.path.islink(path): - os.chmod(path, os.stat(path).st_mode | 0200) - - print "Copied as '%s'" % new_src - -def do_diff(args): - """diff""" - if args: - raise __main__.UsageError() - buildenv = BuildEnv() - - if not os.path.isdir('src'): - raise SafeException('No local src directory to diff against!') - new_src = os.path.realpath('src') - - src_impl = buildenv.chosen_impl(buildenv.interface) - assert src_impl - - prog = find_in_path('diff') - args = ['-ur', lookup(src_impl), new_src] - - status = os.spawnv(os.P_WAIT, prog, [prog] + args) - if status == 0: - return False - elif status == 1: - return True - elif status > 1: - raise SafeException("Program '%s' failed with exit code %d" % (prog, status)) - elif status < 0: - raise SafeException("Program '%s' failed with signal %d" % (prog, -status)) - -__main__.commands += [do_copy_src, do_diff] diff --git a/gui.py b/gui.py deleted file mode 100644 index a212472..0000000 --- a/gui.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -# This is normally called by 0launch's GUI. - -import sys, __main__ - -from zeroinstall import SafeException - -from support import BuildEnv, _ - -def do_gui(args): - "gui [--no-prompt] [SOURCE-URI]" - if args and args[0] == '--no-prompt': - del args[0] - # This option no longer has any effect, since it is the default. - # However, old versions of 0launch's GUI pass it (< 0.52) - - import gui_support - import gtk - - try: - if len(args) == 0: - pass - elif len(args) == 1: - import setup - def get_dir_callback(default_dir): - compile_dir = gui_support.choose_dir(_('Create build directory'), default_dir) - if compile_dir: - return compile_dir - raise SafeException("Cancelled at user's request") - setup.do_setup(args, get_dir_callback) - else: - raise SafeException("usage: 0compile gui URI") - - buildenv = BuildEnv() - box = gui_support.CompileBox(buildenv.interface) - box.connect('destroy', lambda b: gtk.main_quit()) - box.show() - - gtk.main() - except KeyboardInterrupt: - pass - except SafeException, ex: - gui_support.alert(None, '%s' % ex) - sys.exit(1) - except Exception, ex: - import traceback - traceback.print_exc() - gui_support.alert(None, '%s: %s' % (ex.__class__, ex)) - sys.exit(1) - -__main__.commands.append(do_gui) diff --git a/gui_support.py b/gui_support.py deleted file mode 100644 index 46b3225..0000000 --- a/gui_support.py +++ /dev/null @@ -1,362 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import sys, os, __main__ -import pygtk; pygtk.require('2.0') -import gtk, gobject - -from zeroinstall.injector import reader, writer, model -from zeroinstall.injector.iface_cache import iface_cache - -from support import BuildEnv, _ - -RESPONSE_SETUP = 1 -RESPONSE_BUILD = 2 -RESPONSE_PUBLISH = 3 -RESPONSE_REGISTER = 4 - -action_responses = [RESPONSE_SETUP, RESPONSE_BUILD, RESPONSE_PUBLISH, RESPONSE_REGISTER] - -main_path = os.path.abspath(__main__.__file__) - -class CompileBox(gtk.Dialog): - child = None - - def __init__(self, interface): - assert interface - gtk.Dialog.__init__(self, _("Compile '%s'") % interface.split('/')[-1]) # No rsplit on Python 2.3 - self.set_has_separator(False) - self.set_default_size(gtk.gdk.screen_width() / 2, gtk.gdk.screen_height() / 2) - - def add_action(stock, name, resp): - if not hasattr(gtk, stock): - stock = 'STOCK_YES' - button = ButtonMixed(getattr(gtk, stock), name) - button.set_flags(gtk.CAN_DEFAULT) - self.add_action_widget(button, resp) - return button - - add_action('STOCK_PROPERTIES', '_Setup', RESPONSE_SETUP) - add_action('STOCK_CONVERT', '_Build', RESPONSE_BUILD) - add_action('STOCK_ADD', '_Register', RESPONSE_REGISTER) - add_action('STOCK_NETWORK', '_Publish', RESPONSE_PUBLISH) - - self.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CANCEL) - - self.set_default_response(RESPONSE_BUILD) - - self.buffer = gtk.TextBuffer() - self.tv = gtk.TextView(self.buffer) - self.tv.set_left_margin(4) - self.tv.set_right_margin(4) - self.tv.set_wrap_mode(gtk.WRAP_WORD) - swin = gtk.ScrolledWindow() - swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) - swin.add(self.tv) - swin.set_shadow_type(gtk.SHADOW_IN) - self.vscroll = swin.get_vadjustment() - self.tv.set_editable(False) - self.tv.set_cursor_visible(False) - self.vbox.pack_start(swin, True, True, 0) - - self.vbox.show_all() - - self.connect('delete-event', lambda box, dev: True) - - def response(box, resp): - if resp == RESPONSE_SETUP: - def done_setup(): - self.add_msg('Now use Build to compile the chosen source code.') - self.run_command((sys.executable, main_path, 'setup'), done_setup) - elif resp == RESPONSE_BUILD: - def done_build(): - self.add_msg('\nBuild successful. Now register or publish the build.') - def build_failed(): - self.add_msg('\nIf the messages displayed above indicate a missing dependency (e.g. no C compiler ' - "or a library that isn't available through Zero Install) then install it using your " - 'normal package manager and click on Build again. Note that for libraries you often ' - 'need the -dev version of the package. ' - '\nOtherwise, please notify the developers of this problem (this will transmit ' - 'the contents of the build/build-failure.log file):') - end = self.buffer.get_end_iter() - anchor = self.buffer.create_child_anchor(end) - align = gtk.Alignment(0.0, 0.0, 1.0, 1.0) - button = ButtonMixed(gtk.STOCK_YES, 'Notify developers') - align.add(button) - align.set_padding(8, 8, 8, 8) - align.show_all() - self.tv.add_child_at_anchor(align, anchor) - self.add_msg('\n') - def report_bug(button): - def done_notify(): - self.add_msg("\nReport sent. Thank you! (note: you won't get a reply, as " - "no contact details were sent; write to the project's mailing " - "list if you want to discuss the problem)") - self.run_command((sys.executable, main_path, 'report-bug'), done_notify) - button.connect('clicked', report_bug) - buildenv = BuildEnv() - changes = buildenv.get_build_changes() - if changes: - options = get_build_options(box, '\n'.join(changes) + '\n\nIt would be best to do a clean (full) build.') - else: - options = [] - if options is not None: - box.run_command([sys.executable, main_path, 'build'] + options, done_build, build_failed) - elif resp == RESPONSE_REGISTER: - buildenv = BuildEnv() - - iface = iface_cache.get_interface(interface) - reader.update_from_cache(iface) - - # Register using the feed-for, if available - real_iface = iface - for uri in iface.feed_for or []: - real_iface = iface_cache.get_interface(uri) - self.add_msg("Registering as a feed for %s" % real_iface.uri) - break - else: - if os.path.isabs(iface.uri): - self.add_msg("Warning: no in local feed %s!" % iface.uri) - - feed = buildenv.local_iface_file - for f in real_iface.feeds or []: - if f.uri == feed: - self.add_msg("Feed '%s' is already registered for interface '%s'!\n" % (feed, real_iface.uri)) - return - box.buffer.insert_at_cursor("Registering feed '%s'\n" % feed) - real_iface.extra_feeds.append(model.Feed(feed, arch = None, user_override = True)) - writer.save_interface(real_iface) - box.buffer.insert_at_cursor("Done. You can now close this window.\n") - elif resp == RESPONSE_PUBLISH: - buildenv = BuildEnv() - box = PublishBox(self, buildenv) - resp = box.run() - box.destroy() - if resp == gtk.RESPONSE_OK: - def done_publish(): - self.add_msg("\nYou can use '0publish --local' to add this " - "into the main feed. If you don't have a main feed then this " - "will create one. See " - "http://0install.net/injector-packagers.html for more information.") - self.run_command((sys.executable, main_path, - 'publish', box.archive_dir.get_text()), done_publish) - elif resp == gtk.RESPONSE_CANCEL or resp == gtk.RESPONSE_DELETE_EVENT: - if self.kill_child(): return - self.destroy() - else: - self.add_msg('Unknown response: %s' % resp) - - self.connect('response', response) - - self.system_tag = self.buffer.create_tag('system', foreground = 'blue', background = 'white') - self.add_msg(instructions) - self.set_responses_sensitive() - - def kill_child(self): - if self.child is None: return False - - import signal - self.killed = True - self.add_msg('\nSending SIGTERM to process...') - os.kill(-self.child, signal.SIGTERM) - return True - - def add_msg(self, msg): - self.insert_at_end_and_scroll(msg + '\n', self.system_tag) - - """Run command in a sub-process. - Calls success() if the command exits with status zero. - Calls failure() if it fails for other reasons. - (neither is called if the user aborts the command)""" - def run_command(self, command, success, failure = None): - assert self.child is None - self.killed = False - self.success = success - self.failure = failure - self.add_msg("Running: " + ' '.join(command) + "\n") - - r, w = os.pipe() - try: - try: - self.child = os.fork() - if not self.child: - # We are the child - try: - try: - os.close(r) - os.dup2(w, 1) - os.dup2(w, 2) - os.close(w) - os.setpgrp() # Become group leader - os.execvp(command[0], command) - except: - import traceback - traceback.print_exc() - finally: - os._exit(1) - finally: - os.close(w) - except: - os.close(r) - raise - - for resp in action_responses: - self.set_response_sensitive(resp, False) - - # We are the parent - gobject.io_add_watch(r, gobject.IO_IN | gobject.IO_HUP, self.got_data) - - def set_responses_sensitive(self): - self.set_response_sensitive(RESPONSE_SETUP, True) - self.set_response_sensitive(RESPONSE_BUILD, True) - - buildenv = BuildEnv() - have_binary = os.path.exists(buildenv.local_iface_file) - self.set_response_sensitive(RESPONSE_REGISTER, have_binary) - self.set_response_sensitive(RESPONSE_PUBLISH, have_binary) - - def insert_at_end_and_scroll(self, data, *tags): - near_end = self.vscroll.upper - self.vscroll.page_size * 1.5 < self.vscroll.value - end = self.buffer.get_end_iter() - self.buffer.insert_with_tags(end, data, *tags) - if near_end: - cursor = self.buffer.get_insert() - self.buffer.move_mark(cursor, end) - self.tv.scroll_to_mark(cursor, 0, False, 0, 0) - - def got_data(self, src, cond): - data = os.read(src, 100) - if data: - # TODO: only insert complete UTF-8 sequences, not half sequences - self.insert_at_end_and_scroll(data) - return True - else: - pid, status = os.waitpid(self.child, 0) - assert pid == self.child - self.child = None - - self.set_responses_sensitive() - - if os.WIFEXITED(status) and os.WEXITSTATUS(status) == 0: - self.success() - elif self.killed: - self.add_msg("\nCommand terminated at user's request.") - else: - self.add_msg("\nCommand failed.") - if self.failure: - self.failure() - return False - - -def choose_dir(title, default): - sel = gtk.FileSelection(title) - sel.set_has_separator(False) - sel.set_filename(default) - while True: - resp = sel.run() - if resp == gtk.RESPONSE_OK: - build_dir = sel.get_filename() - if not os.path.exists(build_dir): - sel.destroy() - return build_dir - alert(sel, _("'%s' already exists") % build_dir) - else: - sel.destroy() - return None - -def alert(parent, msg): - d = gtk.MessageDialog(parent, - gtk.DIALOG_MODAL, - gtk.MESSAGE_ERROR, - gtk.BUTTONS_OK, - msg) - d.run() - d.destroy() - -class ButtonMixed(gtk.Button): - """A button with a standard stock icon, but any label. This is useful - when you want to express a concept similar to one of the stock ones.""" - def __init__(self, stock, message): - """Specify the icon and text for the new button. The text - may specify the mnemonic for the widget by putting a _ before - the letter, eg: - button = ButtonMixed(gtk.STOCK_DELETE, '_Delete message').""" - gtk.Button.__init__(self) - - label = gtk.Label('') - label.set_text_with_mnemonic(message) - label.set_mnemonic_widget(self) - - image = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_BUTTON) - box = gtk.HBox(False, 2) - align = gtk.Alignment(0.5, 0.5, 0.0, 0.0) - - box.pack_start(image, False, False, 0) - box.pack_end(label, False, False, 0) - - self.add(align) - align.add(box) - align.show_all() - -def get_build_options(parent, message): - box = gtk.MessageDialog(parent, 0, gtk.MESSAGE_QUESTION, - gtk.BUTTONS_CANCEL, message) - - button = ButtonMixed(gtk.STOCK_GO_FORWARD, 'Force') - button.show() - box.add_action_widget(button, 2) - - button = ButtonMixed(gtk.STOCK_CLEAR, 'Clean') - button.set_flags(gtk.CAN_DEFAULT) - button.show() - box.add_action_widget(button, 1) - - box.set_position(gtk.WIN_POS_CENTER) - box.set_title(_('Confirm:')) - box.set_default_response(1) - resp = box.run() - box.destroy() - - if resp == 1: - return ['--clean'] - elif resp == 2: - return ['--force'] - return None - -class PublishBox(gtk.MessageDialog): - def __init__(self, parent, buildenv): - gtk.MessageDialog.__init__(self, parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL, - 'Enter the directory on your HTTP or FTP server to which ' - 'the archive file will be uploaded:') - vbox = gtk.VBox(True, 4) - self.vbox.pack_start(vbox, False, True, 0) - vbox.set_border_width(8) - - self.archive_dir = gtk.Entry() - self.archive_dir.set_activates_default(True) - self.set_default_response(gtk.RESPONSE_OK) - - if buildenv.download_base_url: - self.archive_dir.set_text(buildenv.download_base_url) - else: - self.archive_dir.set_text('http://myserver.com/archives') - - vbox.pack_start(self.archive_dir, False, True, 0) - vbox.show_all() - -instructions = """Instructions - -Compiling a program takes the program's human readable source code, and generates a binary which a computer can run. - -To choose a different version of the source code, or the versions of any other programs needed to compile, use Setup. - -To compile the chosen source code into a binary, use Build. - -To add the new binary to the list of available versions for the program, use Register. - -To publish the binary on the web, so that other people can run it, use Publish. - -For further information, including details of how to make changes to the source code before compiling, visit: http://0install.net/0compile.html -""" diff --git a/include_deps.py b/include_deps.py deleted file mode 100644 index bed0113..0000000 --- a/include_deps.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2007, Thomas Leonard -# See http://0install.net/0compile.html - -import os, __main__ -import shutil - -from zeroinstall import SafeException -from zeroinstall.zerostore import manifest - -from support import BuildEnv, ensure_dir, lookup - -def do_include_deps(args): - """include-deps""" - buildenv = BuildEnv() - - depdir = os.path.realpath('dependencies') - ensure_dir(depdir) - - dirs_to_copy = [] - - sels = buildenv.get_selections() - for needed_iface in sels.selections: - impl = buildenv.chosen_impl(needed_iface) - assert impl - if impl.local_path is not None: - raise SafeException("Can't export '%s' as it's a local implementation (not supported yet; sorry)" % impl) - if not impl.id.startswith('package:'): - dirs_to_copy.append(lookup(impl)) - - copied = 0 - for cached in dirs_to_copy: - required_digest = os.path.basename(cached) - target_impl_dir = os.path.join(depdir, required_digest) - if not os.path.isdir(target_impl_dir): - if required_digest.startswith('sha1='): - shutil.copytree(cached, target_impl_dir) - else: - manifest_data = file(os.path.join(cached, '.manifest')).read() - manifest.copy_tree_with_verify(cached, depdir, manifest_data, required_digest) - copied += 1 - - print "Copied %d dependencies to %s (%d already there)" % (copied, depdir, len(dirs_to_copy) - copied) - -__main__.commands.append(do_include_deps) diff --git a/publish.py b/publish.py deleted file mode 100644 index 94f9aa1..0000000 --- a/publish.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import os, sys, __main__ -from logging import info -from optparse import OptionParser -import shutil - -from zeroinstall import SafeException - -from support import BuildEnv, spawn_and_check - -pubish_command = os.environ["0COMPILE_0PUBLISH"] - -def do_publish(args): - """publish [ DOWNLOAD-BASE-URL ]""" - - parser = OptionParser(usage="usage: %prog publish [options] [ DOWNLOAD-BASE-URL ]") - - parser.add_option('', "--target-feed", help="name of output feed file to create", metavar='FILE') - (options, args2) = parser.parse_args(args) - - buildenv = BuildEnv() - if len(args2) == 1: - buildenv.config.set('compile', 'download-base-url', args2[0]) - buildenv.save() - elif len(args2) > 1: - parser.print_help() - sys.exit(1) - - download_base_url = buildenv.download_base_url or None - - if download_base_url: - info("Using download base URL: %s", download_base_url) - - if not os.path.isdir(buildenv.distdir): - raise SafeException("Directory '%s' does not exist. Try 'compile build'." % buildenv.distdir) - - distdir = os.path.basename(buildenv.distdir) - archive_name = buildenv.archive_stem + '.tar.bz2' - - # Make all directories in the archive user writable - for main, dirs, files in os.walk(distdir): - os.chmod(main, os.stat(main).st_mode | 0200) - - import tarfile - archive = tarfile.open(archive_name, mode = 'w:bz2') - archive.add(distdir, buildenv.archive_stem) - archive.close() - - target_feed = options.target_feed or buildenv.local_download_iface - - if download_base_url: - download_url = os.path.join(download_base_url, archive_name) - else: - download_url = archive_name - shutil.copyfile(buildenv.local_iface_file, target_feed) - - # XXX: we're assuming that 0publish requires the same version of Python as - # 0compile. This is currently needed for Arch Linux, but long-term we need to - # use the . - spawn_and_check(sys.executable, [ - pubish_command, - target_feed, - '--archive-url', download_url, - '--archive-extract', buildenv.archive_stem]) - - if options.target_feed is None: - # If --target-feed is used this is probably a script, so don't print - # out hints. - print "Now upload '%s' as:\n%s\n" % (archive_name, download_url) - - print "Once uploaded, you can download and run with:" - print "$ 0launch %s" % target_feed - -__main__.commands.append(do_publish) diff --git a/setup.py b/setup.py deleted file mode 100644 index f014684..0000000 --- a/setup.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import os, sys, __main__ - -from zeroinstall.injector import model, namespaces, qdom -from zeroinstall import SafeException - -from support import BuildEnv - -def do_setup(args, get_dir_callback = None): - "setup [ SOURCE-URI [ DIR ] ]" - if len(args) == 0: - assert get_dir_callback is None - buildenv = BuildEnv() - interface = buildenv.interface - assert interface - create_dir = None - buildenv.get_selections(prompt = True) - else: - buildenv = BuildEnv(need_config = False) - interface = args[0] - if get_dir_callback: - assert len(args) == 1 - if len(args) == 1: - create_dir = os.path.basename(interface) - if create_dir.endswith('.xml'): - create_dir = create_dir[:-4] - if create_dir.startswith('alias:'): - create_dir = create_dir.split(':', 1)[1] - assert os.path.dirname(create_dir) == '' - assert create_dir != os.path.curdir - if get_dir_callback: - create_dir = get_dir_callback(create_dir) - elif len(args) == 2: - create_dir = args[1] - if create_dir == '.': - create_dir = None - else: - raise __main__.UsageError() - - iface_uri = model.canonical_iface_uri(args[0]) - if os.path.isabs(iface_uri): - # Use a relative path if the feed is inside the current directory. - # This is useful if the properties file is shared with other users. - rel_iface_uri = os.path.relpath(iface_uri, create_dir or ".") - if not rel_iface_uri.startswith("."): - iface_uri = rel_iface_uri - - root = qdom.parse(file(iface_uri)) - if root.uri == namespaces.XMLNS_IFACE and root.name == 'selections': - # Looks like this is a selections file, not an interface. - buildenv.config.set('compile', 'selections', iface_uri) - iface_uri = root.getAttribute('interface') - buildenv.config.set('compile', 'interface', iface_uri) - - if create_dir and os.path.exists(create_dir): - raise SafeException("Directory '%s' already exists." % create_dir) - buildenv.get_selections() - - if create_dir: - try: - os.mkdir(create_dir) - except: - print >>sys.stderr, "Failed to create new directory '%s'" % os.path.abspath(create_dir) - raise - os.chdir(create_dir) - print "Created directory %s" % create_dir - - buildenv.save() - -__main__.commands.append(do_setup) diff --git a/support.py b/support.py deleted file mode 100644 index 85d6d3d..0000000 --- a/support.py +++ /dev/null @@ -1,369 +0,0 @@ -# Copyright (C) 2006, Thomas Leonard -# See http://0install.net/0compile.html - -import os, sys, shutil -import subprocess -from os.path import join -from logging import info -import ConfigParser - -from zeroinstall.injector import model, selections, qdom, arch -from zeroinstall.injector.arch import canonicalize_os, canonicalize_machine - -from zeroinstall.injector.iface_cache import iface_cache -from zeroinstall import SafeException -from zeroinstall.zerostore import Store, NotStored -from zeroinstall.support import find_in_path - -Prefixes = qdom.Prefixes - -def _(x): return x - - -# This is An os.uname() substitute that uses as much of ZI's -# arch._uname as is available and yet has all four elements one -# normally expects from os.uname() on Posix (on Windows, arch._uname -# has only two elements). -import platform -uname = arch._uname + platform.uname()[len(arch._uname):] - -ENV_FILE = '0compile.properties' -XMLNS_0COMPILE = 'http://zero-install.sourceforge.net/2006/namespaces/0compile' - -install_path = os.environ.get("0COMPILE_0INSTALL", None) -if install_path is None: - zeroinstall_dir = os.environ.get('0COMPILE_ZEROINSTALL', None) - if zeroinstall_dir: - # We've been run by an old version of 0install. - # We assuming that, if installed through 0install, 0launch requires - # the same version of Python as 0compile. - install_prog = [sys.executable, os.path.join(zeroinstall_dir, '0install')] - if not os.path.exists(install_prog[1]): - # For the Windows version... - install_prog[1] = os.path.join(zeroinstall_dir, 'zeroinstall', 'scripts', 'install.py') - else: - install_prog = ['0install'] -else: - install_prog = [install_path] - -if os.path.isdir('dependencies'): - dep_dir = os.path.realpath('dependencies') - iface_cache.stores.stores.append(Store(dep_dir)) - install_prog.append('--with-store='+ dep_dir) - -class NoImpl: - id = "none" - version = "none" -no_impl = NoImpl() - -def is_package_impl(impl): - return impl.id.startswith("package:") - -def lookup(impl_or_sel): - id = impl_or_sel.id - if id.startswith('package:'): - return None - local_path = impl_or_sel.local_path - if local_path is not None: - if os.path.isdir(local_path): - return local_path - raise SafeException("Directory '%s' no longer exists. Try '0compile setup'" % local_path) - try: - return iface_cache.stores.lookup_any(impl_or_sel.digests) - except NotStored, ex: - raise NotStored(str(ex) + "\nHint: try '0compile setup'") - -def ensure_dir(d, clean = False): - if os.path.isdir(d): - if clean: - print "Removing", d - shutil.rmtree(d) - else: - return - if os.path.exists(d): - raise SafeException("'%s' exists, but is not a directory!" % d) - os.mkdir(d) - -def spawn_and_check(prog, args): - status = os.spawnv(os.P_WAIT, prog, [prog] + args) - if status > 0: - raise SafeException("Program '%s' failed with exit code %d" % (prog, status)) - elif status < 0: - raise SafeException("Program '%s' failed with signal %d" % (prog, -status)) - -def spawn_and_check_maybe_sandboxed(readable, writable, tmpdir, prog, args): - child = spawn_maybe_sandboxed(readable, writable, tmpdir, prog, args) - status = child.wait() - if status > 0: - raise SafeException('Command failed with exit status %d' % status) - elif status < 0: - raise SafeException('Command failed with signal %d' % -status) - -def spawn_maybe_sandboxed(readable, writable, tmpdir, prog, args): - """spawn prog, with (only) the 'writable' directories writable if sandboxing is available. - The readable directories will be readable, as well as various standard locations. - If no sandbox is available, run without a sandbox.""" - - USE_PLASH = 'USE_PLASH_0COMPILE' - - assert os.path.isabs(prog) - _pola_run = find_in_path('pola-run') - - if _pola_run is None: - #print "Not using sandbox (plash not installed)" - use_plash = False - else: - use_plash = os.environ.get(USE_PLASH, '').lower() or 'not set' - if use_plash in ('not set', 'false'): - print "Not using plash: $%s is %s" % (USE_PLASH, use_plash) - use_plash = False - elif use_plash == 'true': - use_plash = True - else: - raise Exception('$%s must be "true" or "false", not "%s"' % (USE_PLASH, use_plash)) - - if not use_plash: - return subprocess.Popen([prog] + args) - - print "Using plash to sandbox the build..." - - # We have pola-shell :-) - pola_args = ['--prog', prog, '-B'] - for a in args: - pola_args += ['-a', a] - for r in readable: - pola_args += ['-f', r] - for w in writable: - pola_args += ['-fw', w] - pola_args += ['-tw', '/tmp', tmpdir] - os.environ['TMPDIR'] = '/tmp' - return subprocess.Popen([_pola_run] + pola_args) - -def get_arch_name(): - target_os = canonicalize_os(uname[0]) - target_machine = canonicalize_machine(uname[4]) - if target_os == 'Darwin' and target_machine == 'i386': - # this system detection shell script comes from config.guess (20090918): - CC = os.getenv("CC_FOR_BUILD") or os.getenv("CC") or os.getenv("HOST_CC") or "cc" - process = subprocess.Popen("(echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | " + - "(CCOPTS= %s -E - 2>/dev/null) | " % CC + - "grep IS_64BIT_ARCH >/dev/null", stdout=subprocess.PIPE, shell=True) - output, error = process.communicate() - retcode = process.poll() - if retcode == 0: - target_machine='x86_64' - if target_machine in ('i585', 'i686'): - target_machine = 'i486' # (sensible default) - return target_os + '-' + target_machine - -class BuildEnv: - def __init__(self, need_config = True): - if need_config and not os.path.isfile(ENV_FILE): - raise SafeException("Run 0compile from a directory containing a '%s' file" % ENV_FILE) - - self.config = ConfigParser.RawConfigParser() - self.config.add_section('compile') - self.config.set('compile', 'download-base-url', '') - self.config.set('compile', 'version-modifier', '') - self.config.set('compile', 'interface', '') - self.config.set('compile', 'selections', '') - self.config.set('compile', 'metadir', '0install') - self.config.set('compile', 'distdir', '') - - self.config.read(ENV_FILE) - - self._selections = None - - return - - @property - def iface_name(self): - iface_name = os.path.basename(self.interface) - if iface_name.endswith('.xml'): - iface_name = iface_name[:-4] - iface_name = iface_name.replace(' ', '-') - if iface_name.endswith('-src'): - iface_name = iface_name[:-4] - return iface_name - - interface = property(lambda self: model.canonical_iface_uri(self.config.get('compile', 'interface'))) - - @property - def distdir(self): - distdir_name = self.config.get('compile', 'distdir') - if not distdir_name: - arch = self.target_arch.replace('*', 'any') - distdir_name = self.iface_name.lower() - distdir_name += '-' + arch.lower() - assert os.path.dirname(distdir_name) == '' - return os.path.realpath(distdir_name) - - def get_binary_template(self): - """Find the element for the selected compile command, if any""" - sels = self.get_selections() - if sels.commands: - for elem in sels.commands[0].qdom.childNodes: - if elem.uri == XMLNS_0COMPILE and elem.name == 'implementation': - return elem - return None - - @property - def metadir(self): - metadir = self.config.get('compile', 'metadir') - assert not os.path.isabs(metadir) - return join(self.distdir, metadir) - - @property - def local_iface_file(self): - return join(self.metadir, 'feed.xml') - - @property - def target_arch(self): - temp = self.get_binary_template() - arch = temp and temp.getAttribute('arch') - return arch or get_arch_name() - - @property - def version_modifier(self): - vm = self.config.get('compile', 'version-modifier') - if vm: return vm - if self.user_srcdir: - return '-1' - return '' - - @property - def archive_stem(self): - # Use the version that we actually built, not the version we would build now - feed = self.load_built_feed() - assert len(feed.implementations) == 1 - version = feed.implementations.values()[0].get_version() - - # Don't use the feed's name, as it may contain the version number - name = feed.get_name().lower().replace(' ', '-') - arch = self.target_arch.lower().replace('*-*', 'bin').replace('*', 'any') - - return '%s-%s-%s' % (name, arch, version) - - def load_built_feed(self): - path = self.local_iface_file - stream = file(path) - try: - feed = model.ZeroInstallFeed(qdom.parse(stream), local_path = path) - finally: - stream.close() - return feed - - def load_built_selections(self): - path = join(self.metadir, 'build-environment.xml') - if os.path.exists(path): - stream = file(path) - try: - return selections.Selections(qdom.parse(stream)) - finally: - stream.close() - return None - - @property - def download_base_url(self): - return self.config.get('compile', 'download-base-url') - - def chosen_impl(self, uri): - sels = self.get_selections() - assert uri in sels.selections - return sels.selections[uri] - - @property - def local_download_iface(self): - impl, = self.load_built_feed().implementations.values() - return '%s-%s.xml' % (self.iface_name, impl.get_version()) - - def save(self): - stream = file(ENV_FILE, 'w') - try: - self.config.write(stream) - finally: - stream.close() - - def get_selections(self, prompt = False): - if self._selections: - assert not prompt - return self._selections - - selections_file = self.config.get('compile', 'selections') - if selections_file: - if prompt: - raise SafeException("Selections are fixed by %s" % selections_file) - stream = file(selections_file) - try: - self._selections = selections.Selections(qdom.parse(stream)) - finally: - stream.close() - from zeroinstall.injector import handler - from zeroinstall.injector.config import load_config - if os.isatty(1): - h = handler.ConsoleHandler() - else: - h = handler.Handler() - config = load_config(h) - blocker = self._selections.download_missing(config) - if blocker: - print "Waiting for selected implementations to be downloaded..." - h.wait_for_blocker(blocker) - else: - command = install_prog + ['download', '--source', '--xml'] - if prompt and '--console' not in install_prog: - if os.name == 'nt': - command[0] += '-win' - command.append('--gui') - command.append(self.interface) - child = subprocess.Popen(command, stdout = subprocess.PIPE) - try: - self._selections = selections.Selections(qdom.parse(child.stdout)) - finally: - if child.wait(): - raise SafeException(' '.join(repr(x) for x in command) + " failed (exit code %d)" % child.returncode) - - self.root_impl = self._selections.selections[self.interface] - - self.orig_srcdir = os.path.realpath(lookup(self.root_impl)) - self.user_srcdir = None - - if os.path.isdir('src'): - self.user_srcdir = os.path.realpath('src') - if self.user_srcdir == self.orig_srcdir or \ - self.user_srcdir.startswith(os.path.join(self.orig_srcdir, '')) or \ - self.orig_srcdir.startswith(os.path.join(self.user_srcdir, '')): - info("Ignoring 'src' directory because it coincides with %s", - self.orig_srcdir) - self.user_srcdir = None - - return self._selections - - def get_build_changes(self): - sels = self.get_selections() - old_sels = self.load_built_selections() - changes = [] - if old_sels: - # See if things have changed since the last build - all_ifaces = set(sels.selections) | set(old_sels.selections) - for x in all_ifaces: - old_impl = old_sels.selections.get(x, no_impl) - new_impl = sels.selections.get(x, no_impl) - if old_impl.version != new_impl.version: - changes.append("Version change for %s: %s -> %s" % (x, old_impl.version, new_impl.version)) - elif old_impl.id != new_impl.id: - changes.append("Version change for %s: %s -> %s" % (x, old_impl.id, new_impl.id)) - return changes - -def depth(node): - root = node.ownerDocument.documentElement - depth = 0 - while node and node is not root: - node = node.parentNode - depth += 1 - return depth - -def parse_bool(s): - if s == 'true': return True - if s == 'false': return False - raise SafeException('Expected "true" or "false" but got "%s"' % s) diff --git a/tests/0compile-coverage b/tests/0compile-coverage deleted file mode 100755 index 9ce902a..0000000 --- a/tests/0compile-coverage +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python -import sys, imp, os -tests_dir = os.path.dirname(os.path.abspath(__file__)) -compile_dir = os.path.dirname(tests_dir) -sys.path.insert(0, compile_dir) -cwd = os.path.realpath(os.getcwd()) -try: - import coverage - coverage.the_coverage.parallel_mode = True - coverage.start() -except: - coverage = None -os.chdir(cwd) -compile_code = os.path.join(compile_dir, '0compile') -try: - class DummyStream(): - def read(self): - pass - def close(self): - pass - import urllib2 - def cb(*args): - print >>sys.stderr, "urlopen called with arguments %s" % (args,) - return DummyStream() - urllib2.urlopen = cb - imp.load_module('__main__', file(compile_code), compile_code, - ('.py', 'r', imp.PY_SOURCE)) -finally: - if coverage: - coverage.stop() diff --git a/tests/bad-version.xml b/tests/bad-version.xml deleted file mode 100644 index 50230f8..0000000 --- a/tests/bad-version.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - hello2 - testing - - Test compiling a program with a minimum required version of 0compile. - - - - - - diff --git a/tests/build-deps.xml b/tests/build-deps.xml deleted file mode 100644 index b1c3429..0000000 --- a/tests/build-deps.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - build-deps - must take into account binary dependencies - - - - - - - - - - - - - diff --git a/tests/cprog/Makefile b/tests/cprog/Makefile deleted file mode 100644 index 938e9c4..0000000 --- a/tests/cprog/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -LIB_DIR=${DISTDIR}/lib -PC_DIR=${DISTDIR}/pkgconfig - -all: main - ls -ld "${CPROG_SELF}" - ./main - cp main "${DISTDIR}/" - [ -d "${PC_DIR}" ] || mkdir "${PC_DIR}" - echo "prefix=${DISTDIR}" > "${PC_DIR}/cprog.pc" - [ -d "${LIB_DIR}" ] || mkdir "${LIB_DIR}" - echo "# Please DO NOT delete this file!" >> "${LIB_DIR}/bad.la" - echo "# Innocent file" >> "${LIB_DIR}/good.la" - echo "# Please DO NOT delete this file!" >> "${LIB_DIR}/nice.ok" - [ "${runnerVarsSet}" = "yes" ] || exit 1 diff --git a/tests/cprog/cprog-command.xml b/tests/cprog/cprog-command.xml deleted file mode 100644 index 6bb3e35..0000000 --- a/tests/cprog/cprog-command.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - cprog - testing - - Test compiling a C program which needs to write to its own src dir. - - - - - - - - - - - - - - - - - - diff --git a/tests/cprog/cprog.xml b/tests/cprog/cprog.xml deleted file mode 100644 index 192dee8..0000000 --- a/tests/cprog/cprog.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - cprog - testing - - Test compiling a C program which needs to write to its own src dir. - - - - - - - - - diff --git a/tests/cprog/main.c b/tests/cprog/main.c deleted file mode 100644 index 1b44643..0000000 --- a/tests/cprog/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int main(int argc, char **argv) { - printf("Hello from C!\n"); - return 0; -} diff --git a/tests/hello2/hello2 b/tests/hello2/hello2 deleted file mode 100755 index 0d024c1..0000000 --- a/tests/hello2/hello2 +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python -import sys, os -print "hello2" -with open(os.path.join(os.environ['ROXLIB'], 'rox', '__init__.py'), 'r') as stream: - for line in stream: - if line.startswith('roxlib_version = '): - print "Using ROX-Lib: " + line diff --git a/tests/hello2/hello2.xml b/tests/hello2/hello2.xml deleted file mode 100644 index 2b16827..0000000 --- a/tests/hello2/hello2.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - hello2 - testing - - Test compiling a program with a runtime dependency. - - - - - - - - - - - - - - - - - - - diff --git a/tests/pinned-version/main.py b/tests/pinned-version/main.py deleted file mode 100755 index 019b902..0000000 --- a/tests/pinned-version/main.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python -from __future__ import print_function -import sys -print('.'.join(map(str, sys.version_info[:2]))) diff --git a/tests/pinned-version/pinned-version.xml b/tests/pinned-version/pinned-version.xml deleted file mode 100644 index 8a2e50e..0000000 --- a/tests/pinned-version/pinned-version.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - pinned-version - testing - - Test compiling a program with a pinned dependency. - - - - - - - - - - - - - - - - - - diff --git a/tests/runall.py b/tests/runall.py deleted file mode 100755 index a14baea..0000000 --- a/tests/runall.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -import unittest, os, sys, tempfile, shutil, atexit - -my_dir = os.path.abspath(os.path.dirname(sys.argv[0])) - -coverdir = tempfile.mkdtemp(prefix='0compile-coverage-') -atexit.register(shutil.rmtree, coverdir) - -os.environ["COVERAGE_FILE"] = os.path.join(coverdir, 'coverage') - -try: - import coverage - coverage.erase() -except ImportError: - coverage = None - print "Coverage module not found. Skipping coverage report." - -sys.argv.append('-v') - -suite_names = [f[:-3] for f in os.listdir(my_dir) - if f.startswith('test') and f.endswith('.py')] -suite_names.sort() - -alltests = unittest.TestSuite() - -for name in suite_names: - m = __import__(name, globals(), locals(), []) - alltests.addTest(m.suite) - -a = unittest.TextTestRunner(verbosity=2).run(alltests) - -print "\nResult", a -if not a.wasSuccessful(): - sys.exit(1) - -if coverage: - coverage.the_coverage.collect() - all_sources = [] - def incl(d): - for x in os.listdir(d): - if x.endswith('.py'): - all_sources.append(os.path.join(d, x)) - incl(os.path.join(my_dir, '..')) - coverage.report(all_sources) diff --git a/tests/selections.xml b/tests/selections.xml deleted file mode 100644 index 2d36d0b..0000000 --- a/tests/selections.xml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/tests/testcompile.py b/tests/testcompile.py deleted file mode 100755 index 2896756..0000000 --- a/tests/testcompile.py +++ /dev/null @@ -1,285 +0,0 @@ -#!/usr/bin/env python -import sys, tempfile, os, shutil, tempfile, subprocess -from StringIO import StringIO -import unittest -from zeroinstall.injector import model, qdom, config -from zeroinstall.support import ro_rmtree, basedir -from zeroinstall.zerostore import Stores - -stores = Stores() - -mydir = os.path.abspath(os.path.dirname(__file__)) -sys.path.insert(0, os.path.dirname(mydir)) -import support - -hello_uri = 'http://0install.net/tests/GNU-Hello.xml' - -mydir = os.path.realpath(os.path.dirname(__file__)) - -hello_selections = os.path.join(mydir, 'selections.xml') -local_bad_version = os.path.join(mydir, 'bad-version.xml') -local_hello_path = os.path.join(mydir, 'hello2', 'hello2.xml') -local_cprog_command_path = os.path.join(mydir, 'cprog', 'cprog-command.xml') -local_cprog_path = os.path.join(mydir, 'cprog', 'cprog.xml') -local_pinned_path = os.path.join(mydir, 'pinned-version', 'pinned-version.xml') -top_build_deps = os.path.join(mydir, 'top-build-deps.xml') - -compile_bin = os.path.join(mydir, '0compile-coverage') -assert os.path.exists(compile_bin) - -if 'DISPLAY' in os.environ: - del os.environ['DISPLAY'] - -launch_command = [os.environ['0COMPILE_0LAUNCH']] - -# Ensure it's cached now, to avoid extra output during the tests -if subprocess.call(launch_command + ['--source', '-c', '--download-only', hello_uri]): - raise Exception("Failed to download hello world test program") - -def compile(*args, **kwargs): - run(*([sys.executable, compile_bin] + list(args)), **kwargs) - -def run(*args, **kwargs): - if not isinstance(args[0], basestring): - args = args[0] + list(args[1:]) - child = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.STDOUT) - got, unused = child.communicate() - code = child.wait() - if code != kwargs.get('expect_status', 0): - raise Exception("Exit status %d:\n%s" % (code, got)) - - expected = kwargs.get('expect', '') - if expected is not None: # pass None to explicily suppress check - if expected: - if expected.lower() not in got.lower(): - raise Exception("Expected '%s', got '%s'" % (expected, got)) - elif got: - raise Exception("Expected nothing, got '%s'" % got) - -# Detect accidental network access -os.environ['http_proxy'] = 'localhost:1111' - -for x in ['GNUPGHOME', 'XDG_CONFIG_HOME', 'XDG_CACHE_HOME', 'XDG_DATA_HOME']: - if x in os.environ: - del os.environ[x] -user_cache_dir = os.environ['XDG_CACHE_DIRS'] = basedir.xdg_cache_home - -class TestCompile(unittest.TestCase): - def setUp(self): - os.chdir('/') - self.tmpdir = tempfile.mkdtemp(prefix = '0compile-test-') - self.hello_dir = os.path.join(self.tmpdir, 'hello') - - os.environ['HOME'] = self.tmpdir - reload(basedir) - - config_dir = basedir.save_config_path('0install.net', 'injector') - stream = open(os.path.join(config_dir, 'implementation-dirs'), 'w') - for x in stores.stores: - stream.write(x.dir + '\n') - stream.close() - - stream = open(os.path.join(config_dir, 'global'), 'w') - stream.write('[global]\n' - 'freshness = -1\n' - 'help_with_testing = True\n' - 'network_use = off-line\n') - stream.close() - - def tearDown(self): - os.chdir(os.path.join(self.tmpdir, os.path.pardir)) - ro_rmtree(self.tmpdir) - - def testBadCommand(self): - compile('foo', expect = 'usage: 0compile', expect_status = 1) - compile('setup', hello_uri, self.tmpdir, expect = 'already exists', expect_status = 1) - os.chdir(self.tmpdir) - compile('setup', expect = 'Run 0compile from a directory containing', expect_status = 1) - compile('build', expect = 'Run 0compile from a directory containing', expect_status = 1) - compile('publish', expect = 'Run 0compile from a directory containing', expect_status = 1) - - def testCompileNoDir(self): - os.chdir(self.tmpdir) - compile('setup', hello_uri, expect = 'Created directory') - os.chdir('GNU-Hello') - - def testCompile(self): - compile('setup', hello_uri, self.hello_dir, expect = 'Created directory') - os.chdir(self.hello_dir) - - compile('build', expect = 'Executing: "%s"' % os.path.join('$SRCDIR','configure')) - - target_dir = 'gnu-hello-%s' % support.get_arch_name().lower() - archive_stem = 'gnu-hello-%s-1.3' % support.get_arch_name().lower() - assert os.path.isdir(target_dir), '%s not a directory' % target_dir - - run(os.path.join(target_dir,'bin','hello'), expect = 'Hello, world!') - run(launch_command, os.path.join(target_dir,'0install', 'feed.xml'), expect = 'Hello, world!') - compile('publish', 'http://localhost/downloads', expect = "Now upload '%s.tar.bz2'" % archive_stem) - - def testAutocompile(self): - compile('autocompile', hello_uri, expect = "site-packages/http/0install.net/tests__GNU-Hello.xml") - run(launch_command, hello_uri, expect = 'Hello, world!') - - def testRecursive(self): - top = os.path.join(mydir, 'top.xml') - compile('autocompile', top, expect = "No dependencies need compiling... compile cprog itself...") - - # Dependency was registered against its local path, since that was how we depended on it: - run(launch_command, os.path.join(mydir, 'cprog/cprog-command.xml'), expect = 'Hello from C') - - # But the top-level feed was registered against its : - c = config.load_config() - i = c.iface_cache.get_interface('http://example.com/top.xml') - self.assertEquals(1, len(i.extra_feeds)) - - def testLocal(self): - compile('setup', local_hello_path, self.hello_dir, expect = 'Created directory') - os.chdir(self.hello_dir) - compile('build', expect = 'Executing: ls -l') - target_dir = 'hello2-any-any' - assert os.path.isdir(target_dir), '%s not a directory' % target_dir - - run(launch_command, os.path.join(target_dir, '0install', 'feed.xml'), expect = 'ROX-Lib') - - def testBadVersion(self): - compile('setup', local_bad_version, self.hello_dir, expect = 'Created directory') - os.chdir(self.hello_dir) - compile('build', expect = 'hello2-0.1 requires 0compile >= 300000', expect_status = 1) - - def testCommand(self): - comp_dir = os.path.join(self.tmpdir, 'cprog-command') - compile('setup', local_cprog_command_path, comp_dir, expect = 'Created directory') - os.chdir(comp_dir) - compile('build', expect = 'Hello from C!') - target_dir = 'cprog-command-%s' % support.get_arch_name().lower() - binary_feed = os.path.join(target_dir, '0install', 'feed.xml') - run(launch_command, binary_feed, expect = 'Hello from C!') - s = open(binary_feed, 'r') - feed = model.ZeroInstallFeed(qdom.parse(s), binary_feed) - s.close() - impl, = feed.implementations.values() - assert impl.arch, "Missing arch on %s" % impl - self.assertEqual("Public Domain", str(impl.metadata['license'])) - - def testCopySrc(self): - comp_dir = os.path.join(self.tmpdir, 'cprog') - compile('setup', local_cprog_path, comp_dir, expect = 'Created directory') - os.chdir(comp_dir) - compile('diff', expect = "No local src directory to diff against", expect_status = 1) - compile('diff', 'foo', expect = 'usage', expect_status = 1) - compile('copy-src', 'foo', expect = 'usage', expect_status = 1) - compile('copy-src', expect = 'Copied as') - compile('copy-src', expect = "Directory '", expect_status = 1) - - # 'src' exists, but no changes - compile('diff') - compile('--verbose', 'build', expect = 'Hello from C') - target_dir = 'cprog-%s' % support.get_arch_name().lower() - patch_file = os.path.join(target_dir, '0install', 'from-0.1.patch') - assert not os.path.exists(patch_file) - - # 'src' contains a change - prog = file(os.path.join('src','main.c')).read() - prog = prog.replace('Hello', 'Goodbye') - stream = file(os.path.join('src','main.c'), 'w') - stream.write(prog) - stream.close() - compile('diff', expect = 'diff') - shutil.rmtree('build') - compile('build', expect = 'Goodbye from C') - assert os.path.exists(patch_file) - - # Test dup-src's unlinking while we're here - compile('build', expect = 'Goodbye from C') - - # 'src' contains an error - stream = file(os.path.join('src','main.c'), 'w') - stream.write('this is not valid C!') - stream.close() - shutil.rmtree('build') - compile('build', expect = 'Build failed', expect_status = 1) - assert os.path.exists(os.path.join('build', 'build-failure.log')) - - # 'src' does not exist - shutil.rmtree('src') - shutil.rmtree('build') - compile('build', expect = 'Hello from C') - assert not os.path.exists(patch_file) - - # Check we fixed the .pc files... - pc_data = open(os.path.join(target_dir, 'pkgconfig', 'cprog.pc')).read() - assert pc_data == "prefix=" + os.path.join("${pcfiledir}",os.path.pardir) + "\n", `pc_data` - - # Check we removed the bad .la files... - assert not os.path.exists(os.path.join(target_dir, 'lib', 'bad.la')) # libtool - bad - assert os.path.exists(os.path.join(target_dir, 'lib', 'good.la')) # Ends in .la, but not a libtool archive - assert os.path.exists(os.path.join(target_dir, 'lib', 'nice.ok')) # Doesn't end in .la - - def testInlcudeDeps(self): - compile('setup', hello_uri, self.hello_dir, expect = 'Created directory') - os.chdir(self.hello_dir) - os.unlink('0compile.properties') - compile('setup', hello_uri, '.') - compile('include-deps', expect = 'dependencies to') - compile('include-deps', expect = 'Copied 0 depend') - - def testSetup(self): - compile('setup', hello_selections, self.hello_dir, - expect = 'Created directory') - compile('setup', hello_selections, self.hello_dir, - expect = "Directory '", expect_status = 1) - compile('setup', hello_selections, '.', 'foo', - expect = "usage", expect_status = 1) - os.chdir(self.hello_dir) - compile('setup', expect = "Selections are fixed", expect_status = 1) - - def testReportBug(self): - broken_src = os.path.join(self.hello_dir, "broken.xml") - os.mkdir(self.hello_dir) - shutil.copy(local_hello_path, broken_src) - os.chdir(self.hello_dir) - compile('setup', broken_src, '.') - compile('build', expect = 'Build failed with exit code', expect_status = 1) - compile('report-bug', expect = "http://0install.net/api/report-bug") - - env = support.BuildEnv() - os.unlink(os.path.join(env.metadir, "build-environment.xml")) - compile('report-bug', expect = "file+not+found") - - def testBuildDeps(self): - compile('autocompile', top_build_deps, expect = "build-deps.xml 0.1 requires 3 <= version < 3", expect_status = 1) - - def testPinVersions(self): - dest = os.path.join(self.tmpdir, 'pinned_version') - compile('setup', local_pinned_path, dest, expect = 'Created directory') - os.chdir(dest) - compile('build', expect=None) - env = support.BuildEnv() - python_version = subprocess.check_output(launch_command + [env.local_iface_file]).strip() - major, minor = map(int, python_version.split(".")) - version_limit = "%d.%d" % (major, minor+1) - - def check_feed(path): - ''' - Check that the feed has the restriction: - - ''' - from xml.dom import minidom - with open(path) as f: - dom = minidom.parse(f) - version_tags = dom.documentElement.getElementsByTagName('version') - assert len(version_tags) == 1, version_tags - version_tag = version_tags[0] - - self.assertEquals(version_tag.getAttribute("not-before"), python_version) - self.assertEquals(version_tag.getAttribute("before"), version_limit) - - check_feed(env.local_iface_file) - - compile('publish', 'http://localhost/downloads', expect=None) - check_feed('pinned-version-0.1.xml') - -suite = unittest.makeSuite(TestCompile) -if __name__ == '__main__': - unittest.main() diff --git a/tests/top-build-deps.xml b/tests/top-build-deps.xml deleted file mode 100644 index 2d7d795..0000000 --- a/tests/top-build-deps.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - top-build-dep - top-level target for an autocompile - - - - - - - diff --git a/tests/top.xml b/tests/top.xml deleted file mode 100644 index e81c985..0000000 --- a/tests/top.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - top - top-level target for an autocompile - - - - - - - - - - - -- 2.11.4.GIT