diff options
Diffstat (limited to 'buildscripts/phing')
256 files changed, 47759 insertions, 0 deletions
diff --git a/buildscripts/phing/CREDITS b/buildscripts/phing/CREDITS new file mode 100644 index 00000000..0aff0706 --- /dev/null +++ b/buildscripts/phing/CREDITS @@ -0,0 +1,45 @@ +                         _________________________ +                         P     H     I     N     G + +  New PHP5 PHING/2 Development +  ---------------------------- +     +  Hans Lellelid <hans@xmpl.org> +  David Giffin <david@giffin.org> +  Michiel Rook <michiel@trendserver.nl> +  Sebastian Bergmann <sb@sebastian-bergmann.de> + +  If you've done work on phing and you are not listed here, please feel free +  to add yourself. +						  +  Original PHING/1 Development +  ----------------------------- + +  Andreas Aderhold <andi@binarycloud.com> +  Alex Black <enigma@turingstudio.com> +  Albert Lash <alash@plateauinnovation.com> +  Charlie Killian <charlie@tizac.com> +  Manuel Holtgrewe <grin@gmx.net> +  Andrzej Nowodworski <a.nowodworski@learn.pl> +  Jason Hines <jason@greenhell.com> +  Jesse Estevez <jesseestevez@earthlink.net> +  Andris Spruds <Andris.Spruds@stud.lba.lv> +  Ronald TAO <ronaldtao@hotmail.com> +  Yannick Lecaillez <yl@seasonfive.com> +  Hans Lellelid <hans@xmpl.org> +   +  Other libraries/contributions +  ------------------------------ + +  Apache ANT Project +  License: Apache 1.1 +  Phing is a port of the Apache ANT project. +  http://ant.apache.org/ + +  TAR Manager Class +  License: LGPL +  The Tar archive abstraction class +  (c) Josh Barger <joshb@npt.com> +  http://phpclasses.upperdesign.com/browse.html/package/529.html + +  --$Id: CREDITS,v 1.6 2005/02/03 13:41:52 mrook Exp $ diff --git a/buildscripts/phing/LICENSE b/buildscripts/phing/LICENSE new file mode 100644 index 00000000..9139d608 --- /dev/null +++ b/buildscripts/phing/LICENSE @@ -0,0 +1,1042 @@ +                         _________________________ + +                         P     H     I     N     G + + + + + +  Please, be sure to read the license header on any one of the phing core + +  files. It explains the licensing scheme. + + + +  Some files in phing are Perl Artistic, Apache, BSD, or just free. See + +  "CREDITS" for a list. + + + +  We've included a copy of the LGPL for convenience. + + + + + +  LGPL LICENSE + +  ------------ + + + +	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. + + + +	Finally, software patents pose a constant threat to the existence of + +	any free program.  We wish to make sure that a company cannot + +	effectively restrict the users of a free program by obtaining a + +	restrictive license from a patent holder.  Therefore, we insist that + +	any patent license obtained for a version of the library must be + +	consistent with the full freedom of use specified in this license. + + + +	Most GNU software, including some libraries, is covered by the + +	ordinary GNU General Public License.  This license, the GNU Lesser + +	General Public License, applies to certain designated libraries, and + +	is quite different from the ordinary General Public License.  We use + +	this license for certain libraries in order to permit linking those + +	libraries into non-free programs. + + + +	When a program is linked with a library, whether statically or using + +	a shared library, the combination of the two is legally speaking a + +	combined work, a derivative of the original library.  The ordinary + +	General Public License therefore permits such linking only if the + +	entire combination fits its criteria of freedom.  The Lesser General + +	Public License permits more lax criteria for linking other code with + +	the library. + + + +	We call this license the "Lesser" General Public License because it + +	does Less to protect the user's freedom than the ordinary General + +	Public License.  It also provides other free software developers Less + +	of an advantage over competing non-free programs.  These disadvantages + +	are the reason we use the ordinary General Public License for many + +	libraries.  However, the Lesser license provides advantages in certain + +	special circumstances. + + + +	For example, on rare occasions, there may be a special need to + +	encourage the widest possible use of a certain library, so that it + +	becomes a de-facto standard.  To achieve this, non-free programs must be + +	allowed to use the library.  A more frequent case is that a free + +	library does the same job as widely used non-free libraries.  In this + +	case, there is little to gain by limiting the free library to free + +	software only, so we use the Lesser General Public License. + + + +	In other cases, permission to use a particular library in non-free + +	programs enables a greater number of people to use a large body of + +	free software.  For example, permission to use the GNU C Library in + +	non-free programs enables many more people to use the whole GNU + +	operating system, as well as its variant, the GNU/Linux operating + +	system. + + + +	Although the Lesser General Public License is Less protective of the + +	users' freedom, it does ensure that the user of a program that is + +	linked with the Library has the freedom and the wherewithal to run + +	that program using a modified version of the Library. + + + +	The precise terms and conditions for copying, distribution and + +	modification follow.  Pay close attention to the difference between a + +	"work based on the library" and a "work that uses the library".  The + +	former contains code derived from the library, whereas the latter must + +	be combined with the library in order to run. + + + +	GNU LESSER GENERAL PUBLIC LICENSE + +	TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + + +	0. This License Agreement applies to any software library or other + +	program which contains a notice placed by the copyright holder or + +	other authorized party saying it may be distributed under the terms of + +	this Lesser General Public License (also called "this License"). + +	Each licensee is addressed as "you". + + + +	A "library" means a collection of software functions and/or data + +	prepared so as to be conveniently linked with application programs + +	(which use some of those functions and data) to form executables. + + + +	The "Library", below, refers to any such software library or work + +	which has been distributed under these terms.  A "work based on the + +	Library" means either the Library or any derivative work under + +	copyright law: that is to say, a work containing the Library or a + +	portion of it, either verbatim or with modifications and/or translated + +	straightforwardly into another language.  (Hereinafter, translation is + +	included without limitation in the term "modification".) + + + +	"Source code" for a work means the preferred form of the work for + +	making modifications to it.  For a library, complete source code means + +	all the source code for all modules it contains, plus any associated + +	interface definition files, plus the scripts used to control compilation + +	and installation of the library. + + + +	Activities other than copying, distribution and modification are not + +	covered by this License; they are outside its scope.  The act of + +	running a program using the Library is not restricted, and output from + +	such a program is covered only if its contents constitute a work based + +	on the Library (independent of the use of the Library in a tool for + +	writing it).  Whether that is true depends on what the Library does + +	and what the program that uses the Library does. + + + +	1. You may copy and distribute verbatim copies of the Library's + +	complete source code as you receive it, in any medium, provided that + +	you conspicuously and appropriately publish on each copy an + +	appropriate copyright notice and disclaimer of warranty; keep intact + +	all the notices that refer to this License and to the absence of any + +	warranty; and distribute a copy of this License along with the + +	Library. + + + +	You may charge a fee for the physical act of transferring a copy, + +	and you may at your option offer warranty protection in exchange for a + +	fee. + + + +	2. You may modify your copy or copies of the Library or any portion + +	of it, thus forming a work based on the Library, and copy and + +	distribute such modifications or work under the terms of Section 1 + +	above, provided that you also meet all of these conditions: + + + +	a) The modified work must itself be a software library. + + + +	b) You must cause the files modified to carry prominent notices + +	stating that you changed the files and the date of any change. + + + +	c) You must cause the whole of the work to be licensed at no + +	charge to all third parties under the terms of this License. + + + +	d) If a facility in the modified Library refers to a function or a + +	table of data to be supplied by an application program that uses + +	the facility, other than as an argument passed when the facility + +	is invoked, then you must make a good faith effort to ensure that, + +	in the event an application does not supply such function or + +	table, the facility still operates, and performs whatever part of + +	its purpose remains meaningful. + + + +	(For example, a function in a library to compute square roots has + +	a purpose that is entirely well-defined independent of the + +	application.  Therefore, Subsection 2d requires that any + +	application-supplied function or table used by this function must + +	be optional: if the application does not supply it, the square + +	root function must still compute square roots.) + + + +	These requirements apply to the modified work as a whole.  If + +	identifiable sections of that work are not derived from the Library, + +	and can be reasonably considered independent and separate works in + +	themselves, then this License, and its terms, do not apply to those + +	sections when you distribute them as separate works.  But when you + +	distribute the same sections as part of a whole which is a work based + +	on the Library, the distribution of the whole must be on the terms of + +	this License, whose permissions for other licensees extend to the + +	entire whole, and thus to each and every part regardless of who wrote + +	it. + + + +	Thus, it is not the intent of this section to claim rights or contest + +	your rights to work written entirely by you; rather, the intent is to + +	exercise the right to control the distribution of derivative or + +	collective works based on the Library. + + + +	In addition, mere aggregation of another work not based on the Library + +	with the Library (or with a work based on the Library) on a volume of + +	a storage or distribution medium does not bring the other work under + +	the scope of this License. + + + +	3. You may opt to apply the terms of the ordinary GNU General Public + +	License instead of this License to a given copy of the Library.  To do + +	this, you must alter all the notices that refer to this License, so + +	that they refer to the ordinary GNU General Public License, version 2, + +	instead of to this License.  (If a newer version than version 2 of the + +	ordinary GNU General Public License has appeared, then you can specify + +	that version instead if you wish.)  Do not make any other change in + +	these notices. + + + +	Once this change is made in a given copy, it is irreversible for + +	that copy, so the ordinary GNU General Public License applies to all + +	subsequent copies and derivative works made from that copy. + + + +	This option is useful when you wish to copy part of the code of + +	the Library into a program that is not a library. + + + +	4. You may copy and distribute the Library (or a portion or + +	derivative of it, under Section 2) in object code or executable form + +	under the terms of Sections 1 and 2 above provided that you accompany + +	it with the complete corresponding machine-readable source code, which + +	must be distributed under the terms of Sections 1 and 2 above on a + +	medium customarily used for software interchange. + + + +	If distribution of object code is made by offering access to copy + +	from a designated place, then offering equivalent access to copy the + +	source code from the same place satisfies the requirement to + +	distribute the source code, even though third parties are not + +	compelled to copy the source along with the object code. + + + +	5. A program that contains no derivative of any portion of the + +	Library, but is designed to work with the Library by being compiled or + +	linked with it, is called a "work that uses the Library".  Such a + +	work, in isolation, is not a derivative work of the Library, and + +	therefore falls outside the scope of this License. + + + +	However, linking a "work that uses the Library" with the Library + +	creates an executable that is a derivative of the Library (because it + +	contains portions of the Library), rather than a "work that uses the + +	library".  The executable is therefore covered by this License. + +	Section 6 states terms for distribution of such executables. + + + +	When a "work that uses the Library" uses material from a header file + +	that is part of the Library, the object code for the work may be a + +	derivative work of the Library even though the source code is not. + +	Whether this is true is especially significant if the work can be + +	linked without the Library, or if the work is itself a library.  The + +	threshold for this to be true is not precisely defined by law. + + + +	If such an object file uses only numerical parameters, data + +	structure layouts and accessors, and small macros and small inline + +	functions (ten lines or less in length), then the use of the object + +	file is unrestricted, regardless of whether it is legally a derivative + +	work.  (Executables containing this object code plus portions of the + +	Library will still fall under Section 6.) + + + +	Otherwise, if the work is a derivative of the Library, you may + +	distribute the object code for the work under the terms of Section 6. + +	Any executables containing that work also fall under Section 6, + +	whether or not they are linked directly with the Library itself. + + + +	6. As an exception to the Sections above, you may also combine or + +	link a "work that uses the Library" with the Library to produce a + +	work containing portions of the Library, and distribute that work + +	under terms of your choice, provided that the terms permit + +	modification of the work for the customer's own use and reverse + +	engineering for debugging such modifications. + + + +	You must give prominent notice with each copy of the work that the + +	Library is used in it and that the Library and its use are covered by + +	this License.  You must supply a copy of this License.  If the work + +	during execution displays copyright notices, you must include the + +	copyright notice for the Library among them, as well as a reference + +	directing the user to the copy of this License.  Also, you must do one + +	of these things: + + + +	a) Accompany the work with the complete corresponding + +	machine-readable source code for the Library including whatever + +	changes were used in the work (which must be distributed under + +	Sections 1 and 2 above); and, if the work is an executable linked + +	with the Library, with the complete machine-readable "work that + +	uses the Library", as object code and/or source code, so that the + +	user can modify the Library and then relink to produce a modified + +	executable containing the modified Library.  (It is understood + +	that the user who changes the contents of definitions files in the + +	Library will not necessarily be able to recompile the application + +	to use the modified definitions.) + + + +	b) Use a suitable shared library mechanism for linking with the + +	Library.  A suitable mechanism is one that (1) uses at run time a + +	copy of the library already present on the user's computer system, + +	rather than copying library functions into the executable, and (2) + +	will operate properly with a modified version of the library, if + +	the user installs one, as long as the modified version is + +	interface-compatible with the version that the work was made with. + + + +	c) Accompany the work with a written offer, valid for at + +	least three years, to give the same user the materials + +	specified in Subsection 6a, above, for a charge no more + +	than the cost of performing this distribution. + + + +	d) If distribution of the work is made by offering access to copy + +	from a designated place, offer equivalent access to copy the above + +	specified materials from the same place. + + + +	e) Verify that the user has already received a copy of these + +	materials or that you have already sent this user a copy. + + + +	For an executable, the required form of the "work that uses the + +	Library" must include any data and utility programs needed for + +	reproducing the executable from it.  However, as a special exception, + +	the materials to be distributed need not include anything that is + +	normally distributed (in either source or binary form) with the major + +	components (compiler, kernel, and so on) of the operating system on + +	which the executable runs, unless that component itself accompanies + +	the executable. + + + +	It may happen that this requirement contradicts the license + +	restrictions of other proprietary libraries that do not normally + +	accompany the operating system.  Such a contradiction means you cannot + +	use both them and the Library together in an executable that you + +	distribute. + + + +	7. You may place library facilities that are a work based on the + +	Library side-by-side in a single library together with other library + +	facilities not covered by this License, and distribute such a combined + +	library, provided that the separate distribution of the work based on + +	the Library and of the other library facilities is otherwise + +	permitted, and provided that you do these two things: + + + +	a) Accompany the combined library with a copy of the same work + +	based on the Library, uncombined with any other library + +	facilities.  This must be distributed under the terms of the + +	Sections above. + + + +	b) Give prominent notice with the combined library of the fact + +	that part of it is a work based on the Library, and explaining + +	where to find the accompanying uncombined form of the same work. + + + +	8. You may not copy, modify, sublicense, link with, or distribute + +	the Library except as expressly provided under this License.  Any + +	attempt otherwise to copy, modify, sublicense, link with, or + +	distribute the Library is void, and will automatically terminate your + +	rights under this License.  However, parties who have received copies, + +	or rights, from you under this License will not have their licenses + +	terminated so long as such parties remain in full compliance. + + + +	9. You are not required to accept this License, since you have not + +	signed it.  However, nothing else grants you permission to modify or + +	distribute the Library or its derivative works.  These actions are + +	prohibited by law if you do not accept this License.  Therefore, by + +	modifying or distributing the Library (or any work based on the + +	Library), you indicate your acceptance of this License to do so, and + +	all its terms and conditions for copying, distributing or modifying + +	the Library or works based on it. + + + +	10. Each time you redistribute the Library (or any work based on the + +	Library), the recipient automatically receives a license from the + +	original licensor to copy, distribute, link with or modify the Library + +	subject to these terms and conditions.  You may not impose any further + +	restrictions on the recipients' exercise of the rights granted herein. + +	You are not responsible for enforcing compliance by third parties with + +	this License. + + + +	11. If, as a consequence of a court judgment or allegation of patent + +	infringement or for any other reason (not limited to patent issues), + +	conditions are imposed on you (whether by court order, agreement or + +	otherwise) that contradict the conditions of this License, they do not + +	excuse you from the conditions of this License.  If you cannot + +	distribute so as to satisfy simultaneously your obligations under this + +	License and any other pertinent obligations, then as a consequence you + +	may not distribute the Library at all.  For example, if a patent + +	license would not permit royalty-free redistribution of the Library by + +	all those who receive copies directly or indirectly through you, then + +	the only way you could satisfy both it and this License would be to + +	refrain entirely from distribution of the Library. + + + +	If any portion of this section is held invalid or unenforceable under any + +	particular circumstance, the balance of the section is intended to apply, + +	and the section as a whole is intended to apply in other circumstances. + + + +	It is not the purpose of this section to induce you to infringe any + +	patents or other property right claims or to contest validity of any + +	such claims; this section has the sole purpose of protecting the + +	integrity of the free software distribution system which is + +	implemented by public license practices.  Many people have made + +	generous contributions to the wide range of software distributed + +	through that system in reliance on consistent application of that + +	system; it is up to the author/donor to decide if he or she is willing + +	to distribute software through any other system and a licensee cannot + +	impose that choice. + + + +	This section is intended to make thoroughly clear what is believed to + +	be a consequence of the rest of this License. + + + +	12. If the distribution and/or use of the Library is restricted in + +	certain countries either by patents or by copyrighted interfaces, the + +	original copyright holder who places the Library under this License may + +	add an explicit geographical distribution limitation excluding those + +	countries, so that distribution is permitted only in or among countries + +	not thus excluded.  In such case, this License incorporates the + +	limitation as if written in the body of this License. + + + +	13. The Free Software Foundation may publish revised and/or new + +	versions of the Lesser General Public License from time to time. + +	Such new versions will be similar in spirit to the present version, + +	but may differ in detail to address new problems or concerns. + + + +	Each version is given a distinguishing version number.  If the Library + +	specifies a version number of this License which applies to it and + +	"any later version", you have the option of following the terms and + +	conditions either of that version or of any later version published by + +	the Free Software Foundation.  If the Library does not specify a + +	license version number, you may choose any version ever published by + +	the Free Software Foundation. + + + +	14. If you wish to incorporate parts of the Library into other free + +	programs whose distribution conditions are incompatible with these, + +	write to the author to ask for permission.  For software which is + +	copyrighted by the Free Software Foundation, write to the Free + +	Software Foundation; we sometimes make exceptions for this.  Our + +	decision will be guided by the two goals of preserving the free status + +	of all derivatives of our free software and of promoting the sharing + +	and reuse of software generally. + + + +	NO WARRANTY + + + +	15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO + +	WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. + +	EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR + +	OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY + +	KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE + +	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + +	PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE + +	LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME + +	THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + + +	16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN + +	WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY + +	AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU + +	FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR + +	CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE + +	LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING + +	RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A + +	FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF + +	SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + +	DAMAGES. + + + +	END OF TERMS AND CONDITIONS + + + +	How to Apply These Terms to Your New Libraries + + + +	If you develop a new library, and you want it to be of the greatest + +	possible use to the public, we recommend making it free software that + +	everyone can redistribute and change.  You can do so by permitting + +	redistribution under these terms (or, alternatively, under the terms of the + +	ordinary General Public License). + + + +	To apply these terms, attach the following notices to the library.  It is + +	safest to attach them to the start of each source file to most effectively + +	convey the exclusion of warranty; and each file should have at least the + +	"copyright" line and a pointer to where the full notice is found. + + + +	<one line to give the library's name and a brief idea of what it does.> + +	Copyright (C) <year>  <name of author> + + + +	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. + + + +	<signature of Ty Coon>, 1 April 1990 + +	Ty Coon, President of Vice + + + +	That's all there is to it! + + + +  --$Id: LICENSE,v 1.3 2003/11/06 18:18:06 hlellelid Exp $ + + + diff --git a/buildscripts/phing/README b/buildscripts/phing/README new file mode 100644 index 00000000..c2b64302 --- /dev/null +++ b/buildscripts/phing/README @@ -0,0 +1,78 @@ +                         _________________________ +                         P     H     I     N     G + + + +  What is it? +  ----------- + +  Phing is a PHP based build tool. In theory it is kind of like "make" +  without makes drawbacks and with the full portability and performance +  of PHP. (PH)pmake (I)s (N)ot (G)numake +   +  Why? +  ---- + +  Why another build tool when there is already make, gnumake, nmake, jam, ant, +  and others? Because all those tools have limitations that the binarycloud +  development team could not live with when developing software across +  different platforms. Make-like tools are inherently shell-based: they +  evaluate a set of dependencies, then execute commands not unlike what you +  would issue on a shell. +   +  This means that you can easily extend these tools by using or writing any +  program for the OS that you are working on; however, this also means that +  you limit yourself to the OS, or at least the OS type, such as Unix, that +  you are working on. + +  Makefiles are inherently evil as well. Anybody who has worked on them for +  any time has run into the dreaded tab problem. "Is my command not executing +  because I have a space in front of my tab?!!". Tools like Jam took care of +  this to a great degree, but still have yet another format to use and +  remember. Of course there is the Java based build tool ant, that is very +  good approach to what now Phing is. But still based on Java you have to have +  at least a running JRE installation on your plattfrom. +  Great for Java projects but we thought this is very consistent way to build +  a PHP based project. Additionally ant does not support a autoconf tool that +  writes out proper buildfiles based on some simple rules prior defined in a +  XML Configuration file. + +  Phing is different. Instead of a model where it is extended with shell-based +  commands, Phing is extended using PHP classes. Instead of writing shell +  commands, the configuration files are XML-based, calling a target tree where +  various tasks get executed. Each task is run by an object that implements +  a particular Task action. +   +  Of course, this removes some of the expressive power that is inherent in +  being able to construct a shell command such as +    % `find . -name foo -exec rm {}` +  but it gives you the ability to be cross-platform - to work anywhere and +  everywhere. And if you really need to execute a shell command, Phing has an <exec> +  task that allows different commands to be executed based on the operating +  system it is executing on. + +  The Latest Version +  ------------------ + +  Details of the latest version can be found on the Phing homepage +  <http://phing.info/>. + +  Documentation +  ------------- + +  Documentation is available in XHTML format in the docs/ directory. In particular,  +  open the docs/phing_guide/book/index.html in a frames-compatible browser to see the  +  phing user guide. + +  For installing see INSTALL.<platform> files in the Phing root. + +  Licensing +  --------- + +  This software is licensed under the terms you may find in the file +  named "LICENSE" in this directory. + +  Thanks for using PHING. + + +  --$Id: README,v 1.4 2004/03/20 04:14:35 hlellelid Exp $ diff --git a/buildscripts/phing/bin/pear-phing b/buildscripts/phing/bin/pear-phing new file mode 100644 index 00000000..bf568c17 --- /dev/null +++ b/buildscripts/phing/bin/pear-phing @@ -0,0 +1,22 @@ +#!/bin/sh + +# ------------------------------------------------------------------------ +# The phing build script for Unix based systems +# $Id: pear-phing,v 1.3 2003/12/23 19:45:14 hlellelid Exp $ +# ------------------------------------------------------------------------ + +# Change this to reflect your environment if the default value doesn't work +PHP_COMMAND="@PHP-BIN@" +export PHP_COMMAND + +# ------------------------------------------------------------------------- +# Do not change anything below this line unless you know what you're doing. +# ------------------------------------------------------------------------- + +if (test -z "$PHP_COMMAND") ; then +	echo "WARNING: PHP_COMMAND environment not set. (Assuming php on PATH)" +	PHP_COMMAND=php +	export PHP_COMMAND +fi + +$PHP_COMMAND -d html_errors=off -qC @PEAR-DIR@/phing.php -logger phing.listener.AnsiColorLogger $* diff --git a/buildscripts/phing/bin/pear-phing.bat b/buildscripts/phing/bin/pear-phing.bat new file mode 100644 index 00000000..fba90772 --- /dev/null +++ b/buildscripts/phing/bin/pear-phing.bat @@ -0,0 +1,44 @@ +@ECHO OFF + +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: The phing build script for Windows based systems +:: $Id: pear-phing.bat,v 1.4 2005/12/22 13:12:33 hlellelid Exp $ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +::---------------------------------------------------------------------------------- +:: Please set following to PHP's CLI +:: NOTE: In PHP 4.2.x the PHP-CLI used to be named php-cli.exe.  +::       PHP 4.3.x names it php.exe but stores it in a subdir called /cli/php.exe +::       E.g. for PHP 4.2 C:\phpdev\php-4.2-Win32\php-cli.exe +::            for PHP 4.3 C:\phpdev\php-4.3-Win32\cli\php.exe +   +  SET phpCli=@PHP-BIN@ + +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- +:: Do not modify below this line!! (Unless you know what your doing :) +::--------------------------------------------------------------------------------- +::--------------------------------------------------------------------------------- + +:: Check existence of php.exe +IF EXIST "%phpCli%" ( +  SET doNothing= +) ELSE GOTO :NoPhpCli + +"%phpCli%" -d html_errors=off -qC "@PEAR-DIR@\phing.php" %* +GOTO :EOF + +:: +:: php.exe not found error   +GOTO :PAUSE_END +:NoPhpCli +ECHO ** ERROR ***************************************************************** +ECHO * Sorry, can't find the php.exe file. +ECHO * You must edit this file to point to your php.exe (CLI version!) +ECHO *    [Currently set to %phpCli%] +ECHO ************************************************************************** + +GOTO :PAUSE_END + +:PAUSE_END +PAUSE
\ No newline at end of file diff --git a/buildscripts/phing/bin/phing b/buildscripts/phing/bin/phing new file mode 100644 index 00000000..e24c6cfb --- /dev/null +++ b/buildscripts/phing/bin/phing @@ -0,0 +1,75 @@ +#!/bin/sh +# Shell wrapper for Phing +# $Id: phing,v 1.2 2006/01/23 21:51:16 mrook Exp $ +# +# This script will do the following: +# - check for PHP_COMMAND env, if found, use it. +#   - if not found assume php is on the path +# - check for PHING_HOME evn, if found use it +#   - if not look for it +# - check for PHP_CLASSPATH, if found use it +#   - if not found set it using PHING_HOME/classes + +if [ -z "$PHING_HOME" ] ; then + +  # echo "WARNING: PHING_HOME environment not set. Attempting to guess." + +  # try to find PHING +  if [ -d /opt/phing ] ; then  +    PHING_HOME=/opt/phing +  fi + +  if [ -d "${HOME}/opt/phing" ] ; then  +    PHING_HOME="${HOME}/opt/phing" +  fi + +  if [ -d "/usr/local/phing" ] ; then  +    PHING_HOME="/usr/local/phing" +  fi + +  if [ -d "${HOME}/usr/phing" ] ; then  +    PHING_HOME="${HOME}/usr/phing" +  fi +   +  ## resolve links - $0 may be a link to phing's home +  PRG="$0" +  progname=`basename "$0"` +  saveddir=`pwd` + +  # need this for relative symlinks +  dirname_prg=`dirname "$PRG"` +  cd "$dirname_prg" +   +  while [ -h "$PRG" ] ; do +    ls=`ls -ld "$PRG"` +    link=`expr "$ls" : '.*-> \(.*\)$'` +    if expr "$link" : '/.*' > /dev/null; then +	PRG="$link" +    else +	PRG=`dirname "$PRG"`"/$link" +    fi +  done +   +  PHING_HOME=`dirname "$PRG"`/.. + +  cd "$saveddir" + +  # make it fully qualified +  PHING_HOME=`cd "$PHING_HOME" && pwd` +   +  # make it available in PHP via getenv("PHING_HOME") +  export PHING_HOME +fi + +if (test -z "$PHP_COMMAND") ; then +	# echo "WARNING: PHP_COMMAND environment not set. (Assuming php on PATH)" +	PHP_COMMAND=php +	export PHP_COMMAND +fi + +if (test -z "$PHP_CLASSPATH") ; then +	PHP_CLASSPATH=$PHING_HOME/classes +	export PHP_CLASSPATH +fi + +$PHP_COMMAND -d html_errors=off -qC $PHING_HOME/bin/phing.php -logger phing.listener.AnsiColorLogger $@ diff --git a/buildscripts/phing/bin/phing.bat b/buildscripts/phing/bin/phing.bat new file mode 100644 index 00000000..c57c30dd --- /dev/null +++ b/buildscripts/phing/bin/phing.bat @@ -0,0 +1,58 @@ +@echo off + +rem ********************************************************************* +rem ** the phing build script for Windows based systems +rem ** $Id: phing.bat,v 1.5 2003/11/06 14:56:13 hlellelid Exp $ +rem ********************************************************************* + +rem This script will do the following: +rem - check for PHP_COMMAND env, if found, use it. +rem   - if not found detect php, if found use it, otherwise err and terminate +rem - check for PHING_HOME evn, if found use it +rem   - if not found error and leave +rem - check for PHP_CLASSPATH, if found use it +rem   - if not found set it using PHING_HOME/classes + +if "%OS%"=="Windows_NT" @setlocal + +rem %~dp0 is expanded pathname of the current script under NT +set DEFAULT_PHING_HOME=%~dp0.. + +goto init +goto cleanup + +:init + +if "%PHING_HOME%" == "" set PHING_HOME=%DEFAULT_PHING_HOME% +set DEFAULT_PHING_HOME= + +if "%PHP_COMMAND%" == "" goto no_phpcommand +if "%PHP_CLASSPATH%" == "" goto set_classpath + +goto run +goto cleanup + +:run +%PHP_COMMAND% -d html_errors=off -qC %PHING_HOME%\bin\phing.php %1 %2 %3 %4 %5 %6 %7 %8 %9 +goto cleanup + +:no_phpcommand +REM echo ------------------------------------------------------------------------ +REM echo WARNING: Set environment var PHP_COMMAND to the location of your php.exe +REM echo          executable (e.g. C:\PHP\php.exe).  (Assuming php.exe on Path) +REM echo ------------------------------------------------------------------------ +set PHP_COMMAND=php.exe +goto init + +:err_home +echo ERROR: Environment var PHING_HOME not set. Please point this +echo variable to your local phing installation! +goto cleanup + +:set_classpath +set PHP_CLASSPATH="%PHING_HOME%\classes" +goto init + +:cleanup +if "%OS%"=="Windows_NT" @endlocal +REM pause diff --git a/buildscripts/phing/bin/phing.php b/buildscripts/phing/bin/phing.php new file mode 100644 index 00000000..880adf41 --- /dev/null +++ b/buildscripts/phing/bin/phing.php @@ -0,0 +1,50 @@ +<?php + +/** + * This is the Phing command line launcher. It starts up the system evironment + * tests for all important paths and properties and kicks of the main command- + * line entry point of phing located in phing.Phing + * @version $Revision: 1.7 $ + */ + +// Set any INI options for PHP +// --------------------------- + +ini_set('track_errors', 1); + +/* set classpath */ +if (getenv('PHP_CLASSPATH')) { +//    define('PHP_CLASSPATH',  getenv('PHP_CLASSPATH') . PATH_SEPARATOR . get_include_path()); +    define('PHP_CLASSPATH',  realpath(dirname(__FILE__).'/../classes') . PATH_SEPARATOR . get_include_path()); +    ini_set('include_path', PHP_CLASSPATH); +} else { +    define('PHP_CLASSPATH',  get_include_path()); +} + +require_once 'phing/Phing.php'; + +/* Setup Phing environment */ +Phing::startup(); + +/* +  find phing home directory +   -- if Phing is installed from PEAR this will probably be null, +   which is fine (I think).  Nothing uses phing.home right now. +*/ +Phing::setProperty('phing.home', getenv('PHING_HOME')); + + +/* polish CLI arguments */ +$args = isset($argv) ? $argv : $_SERVER['argv']; // $_SERVER['argv'] seems not to work when argv is registered (PHP5b4) +array_shift($args); // 1st arg is script name, so drop it + +/* fire main application */ +Phing::fire($args); + +/* +  exit OO system if not already called by Phing +   -- basically we should not need this due to register_shutdown_function in Phing + */ + Phing::halt(0); + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/BuildEvent.php b/buildscripts/phing/classes/phing/BuildEvent.php new file mode 100644 index 00000000..d4e1ea79 --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildEvent.php @@ -0,0 +1,205 @@ +<?php +/* + *  $Id: BuildEvent.php,v 1.10 2005/12/22 22:44:46 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/system/lang/EventObject.php'; + +/** + * Encapsulates a build specific event. + * + * <p>We have three sources of events all handled by this class: + *  + * <ul> + *  <li>Project level events</li> + *  <li>Target level events</li> + *  <li>Task level events</li> + * </ul> + * + * <p> Events are all fired from the project class by creating an event object + * using this class and passing it to the listeners. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.10 $ + * @package   phing + */ +class BuildEvent extends EventObject { + +    /** +     *  A reference to the project +     *  @var Project +     */ +    protected $project; + +    /** +     *  A reference to the target +     *  @var Target +     */ +    protected $target; + +    /** +     *  A reference to the task +     * +     *  @var Task +     */ +    protected $task; + +    /** +     *  The message of this event, if the event is a message +     *  @var    string +     *  @access private +     */ +    protected $message = null; + +    /** +     *  The priority of the message +     * +     *  @var    string +     *  @see    $message +     *  @access private +     */ +    protected $priority = PROJECT_MSG_VERBOSE; + +    /** +     *  The execption that caused the event, if any +     * +     *  @var    object +     *  @access private +     */ +    protected $exception = null; + +    /** +     *  Construct a BuildEvent for a project, task or target source event +     * +     *  @param  object  project the project that emitted the event. +     *  @access public +     */ +    function __construct($source) { +        parent::__construct($source); +        if ($source instanceof Project) { +            $this->project = $source; +            $this->target = null; +            $this->task = null; +        } elseif ($source instanceof Target) { +            $this->project = $source->getProject(); +            $this->target = $source; +            $this->task = null; +        } elseif ($source instanceof Task) { +            $this->project = $source->getProject(); +            $this->target = $source->getOwningTarget(); +            $this->task = $source; +        } else { +            throw new Exception("Can not construct BuildEvent, unknown source given."); +        } +    } + +    /** +     *  Sets the message with details and the message priority for this event. +     * +     *  @param  string   The string message of the event +     *  @param  integer  The priority this message should have +     */ +    function setMessage($message, $priority) { +        $this->message = (string) $message; +        $this->priority = (int) $priority; +    } + +    /** +     *  Set the exception that was the cause of this event. +     * +     *  @param  Exception The exception that caused the event +     */ +    function setException($exception) { +        $this->exception = $exception; +    } + +    /** +     *  Returns the project instance that fired this event. +     * +     *  The reference to the project instance is set by the constructor if this +     *  event was fired from the project class. +     * +     *  @return  Project  The project instance that fired this event +     */ +    function getProject() { +        return $this->project; +    } + +    /** +     *  Returns the target instance that fired this event. +     * +     *  The reference to the target instance is set by the constructor if this +     *  event was fired from the target class. +     * +     *  @return  object  The target that fired this event +     *  @access  public +     */ +    function getTarget() { +        return $this->target; +    } + +    /** +     *  Returns the target instance that fired this event. +     * +     *  The reference to the task instance is set by the constructor if this +     *  event was fired within a task. +     * +     *  @return  object  The task that fired this event +     *  @access  public +     */ +    function getTask() { +        return $this->task; +    } + +    /** +     *  Returns the logging message. This field will only be set for +     *  "messageLogged" events. +     * +     *  @return  string   The log message +     *  @access  public +     */ +    function getMessage() { +        return $this->message; +    } + +    /** +     *  Returns the priority of the logging message. This field will only +     *  be set for "messageLogged" events. +     * +     *  @return  integer  The message priority +     *  @access  public +     */ +    function getPriority() { +        return $this->priority; +    } + +    /** +     *  Returns the exception that was thrown, if any. +     *  This field will only be set for "taskFinished", "targetFinished", and +     *  "buildFinished" events. +     * +     *  @see BuildListener::taskFinished() +     *  @see BuildListener::targetFinished() +     *  @see BuildListener::buildFinished() +     */ +    function getException() { +        return $this->exception; +    } +} diff --git a/buildscripts/phing/classes/phing/BuildException.php b/buildscripts/phing/classes/phing/BuildException.php new file mode 100644 index 00000000..8c108130 --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildException.php @@ -0,0 +1,100 @@ +<?php +/* + *  $Id: BuildException.php,v 1.12 2005/02/27 20:52:07 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * BuildException is for when things go wrong in a build execution. + * + * @author   Andreas Aderhold <andi@binarycloud.com> + * @version  $Revision: 1.12 $ + * @package  phing + */ +class BuildException extends Exception { + +    /** location in the xml file */ +    protected $location = null;  +             +    /** The nested "cause" exception. */ +    protected $cause; +     +    /** +     * Construct a BuildException. +     * Supported signatures: +     *         throw new BuildException($causeExc); +     *         throw new BuildException($msg); +     *         throw new Buildexception($causeExc, $loc); +     *         throw new BuildException($msg, $causeExc); +     *         throw new BuildException($msg, $loc); +     *         throw new BuildException($msg, $causeExc, $loc); +     */ +    function __construct($p1, $p2 = null, $p3 = null) {         +         +        $cause = null; +        $loc = null; +        $msg = ""; +         +        if ($p3 !== null) { +            $cause = $p2; +            $loc = $p3; +            $msg = $p1; +        } elseif ($p2 !== null) { +            if ($p2 instanceof Exception) { +                $cause = $p2; +                $msg = $p1; +            } elseif ($p2 instanceof Location) { +                $loc = $p2; +                if ($p1 instanceof Exception) { +                    $cause = $p1; +                } else { +                    $msg = $p1; +                } +            } +        } elseif ($p1 instanceof Exception) { +            $cause = $p1; +        } else { +            $msg = $p1; +        } +         +        parent::__construct($msg); +         +        if ($cause !== null) { +            $this->cause = $cause; +            $this->message .= " [wrapped: " . $cause->getMessage() ."]"; +        } +         +        if ($loc !== null) { +            $this->setLocation($loc); +        }                 +    } +     +    function getCause() { +        return $this->cause; +    } +     +    function getLocation() { +        return $this->location; +    } + +    function setLocation($loc) {         +        $this->location = $loc; +        $this->message = $loc->toString() . ': ' . $this->message; +    } + +} diff --git a/buildscripts/phing/classes/phing/BuildListener.php b/buildscripts/phing/classes/phing/BuildListener.php new file mode 100644 index 00000000..12a96c7b --- /dev/null +++ b/buildscripts/phing/classes/phing/BuildListener.php @@ -0,0 +1,91 @@ +<?php +/* + *  $Id: BuildListener.php,v 1.6 2003/12/22 18:05:38 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Interface for build listeners. + * + * Classes that implement a listener must extend this class and (faux)implement + * all methods that are decleard as dummies below. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.6 $ + * @see       BuildEvent + * @see       Project::addBuildListener() + * @package   phing + */ +interface BuildListener { + +    /** +     * Fired before any targets are started. +     * +     * @param BuildEvent The BuildEvent +     */ +    function buildStarted(BuildEvent $event); + +    /** +     * Fired after the last target has finished. +     * +     * @param BuildEvent The BuildEvent +     * @see BuildEvent::getException() +     */ +    function buildFinished(BuildEvent $event); + +    /** +     * Fired when a target is started. +     * +     * @param BuildEvent The BuildEvent +     * @see BuildEvent::getTarget() +     */ +    function targetStarted(BuildEvent $event); + +    /** +     * Fired when a target has finished. +     * +     * @param BuildEvent The BuildEvent +     * @see BuildEvent#getException() +     */ +    function targetFinished(BuildEvent $event); + +    /** +     * Fired when a task is started. +     * +     * @param BuildEvent The BuildEvent +     * @see BuildEvent::getTask() +     */ +    function taskStarted(BuildEvent $event); + +    /** +     *  Fired when a task has finished. +     * +     *  @param BuildEvent The BuildEvent +     *  @see BuildEvent::getException() +     */ +    function taskFinished(BuildEvent $event); + +    /** +     *  Fired whenever a message is logged. +     * +     *  @param BuildEvent The BuildEvent +     *  @see BuildEvent::getMessage() +     */ +    function messageLogged(BuildEvent $event); +} diff --git a/buildscripts/phing/classes/phing/IntrospectionHelper.php b/buildscripts/phing/classes/phing/IntrospectionHelper.php new file mode 100644 index 00000000..b4300950 --- /dev/null +++ b/buildscripts/phing/classes/phing/IntrospectionHelper.php @@ -0,0 +1,542 @@ +<?php + +/* + *  $Id: IntrospectionHelper.php,v 1.19 2005/11/08 20:45:59 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/types/Reference.php'; +include_once 'phing/types/Path.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * Helper class that collects the methods that a task or nested element + * holds to set attributes, create nested elements or hold PCDATA + * elements. + * + *<ul> + * <li><strong>SMART-UP INLINE DOCS</strong></li> + * <li><strong>POLISH-UP THIS CLASS</strong></li> + *</ul> + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.19 $ + * @package   phing + */ +class IntrospectionHelper { + + + +    /**  +     * Holds the attribute setter methods. +     *  +     * @var array string[] +     */ +    private $attributeSetters = array(); + +    /**   +     * Holds methods to create nested elements.  +     * +     * @var array string[] +     */ +    private $nestedCreators = array(); + +    /** +     * Holds methods to store configured nested elements.  +     * +     * @var array string[] +     */ +    private $nestedStorers = array(); +     +    /** +     * Map from attribute names to nested types. +     */ +    private $nestedTypes = array(); +         +    /** +     * New idea in phing: any class can register certain +     * keys -- e.g. "task.current_file" -- which can be used in +     * task attributes, if supported.  In the build XML these +     * are referred to like this: +     *         <regexp pattern="\n" replace="%{task.current_file}"/> +     * In the type/task a listener method must be defined: +     *         function setListeningReplace($slot) {} +     * @var array string[] +      */ +    private $slotListeners = array(); +     +    /**  +     * The method to add PCDATA stuff.  +     * +     * @var string Method name of the addText (redundant?) method, if class supports it :) +     */ +    private $methodAddText = null; + +    /** +     * The Class that's been introspected. +     * +     * @var     object +     * @access  private +     */ +    private $bean; +     +    /** +     * The cache of IntrospectionHelper classes instantiated by getHelper(). +     * @var array IntrospectionHelpers[] +     */ +    private static $helpers = array(); +     +    /**  +     * Factory method for helper objects.  +     * +     * @param string $class The class to create a Helper for +     */ +    public static function getHelper($class) { +        if (!isset(self::$helpers[$class])) { +            self::$helpers[$class] = new IntrospectionHelper($class); +        } +        return self::$helpers[$class]; +    } + +    /** +     * This function constructs a new introspection helper for a specific class. +     *  +     * This method loads all methods for the specified class and categorizes them +     * as setters, creators, slot listeners, etc.  This way, the setAttribue() doesn't +     * need to perform any introspection -- either the requested attribute setter/creator +     * exists or it does not & a BuildException is thrown. +     *  +     * @param string $bean The classname for this IH. +     */ +    function __construct($class) { +     +        $this->bean = new ReflectionClass($class); +         +        //$methods = get_class_methods($bean); +        foreach($this->bean->getMethods() as $method) { +         +            if ($method->isPublic()) {                 +             +                // We're going to keep case-insensitive method names +                // for as long as we're allowed :)  It makes it much +                // easier to map XML attributes to PHP class method names. +                $name = strtolower($method->getName()); +                 +                // There are a few "reserved" names that might look like attribute setters +                // but should actually just be skipped.  (Note: this means you can't ever +                // have an attribute named "location" or "tasktype" or a nested element named "task".) +                if ($name === "setlocation" || $name === "settasktype" || $name === "addtask") { +                    continue; +                } +                 +                if ($name === "addtext") { +                     +                    $this->methodAddText = $method; +                     +                } elseif (strpos($name, "setlistening") === 0) { +                     +                    // Phing supports something unique called "RegisterSlots" +                    // These are dynamic values that use a basic slot system so that +                    // classes can register to listen to specific slots, and the value +                    // will always be grabbed from the slot (and never set in the project +                    // component).  This is useful for things like tracking the current +                    // file being processed by a filter (e.g. AppendTask sets an append.current_file +                    // slot, which can be ready by the XSLTParam type.) +                     +                    if (count($method->getParameters()) !== 1) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take exactly one parameter."); +                    } +                                                 +                    $this->slotListeners[$name] = $method; +                     +                } elseif (strpos($name, "set") === 0) { +                     +                    // A standard attribute setter. +                     +                    if (count($method->getParameters()) !== 1) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take exactly one parameter."); +                    } +                     +                    $this->attributeSetters[$name] = $method; +                     +                } elseif (strpos($name, "create") === 0) {                             +                     +                    if (count($method->getParameters()) > 0) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() may not take any parameters."); +                    } +                     +                    // Because PHP doesn't support return types, we are going to do +                    // two things here to guess return type: +                    //     1) parse comments for an explicit value +                    //     2) if that fails, assume that the part of the method after "create" +                    //    is the name of the return type (in many cases it is not) +                     +                    // This isn't super important -- i.e. we're not instantaiting classes +                    // based on this information.  It's more just so that IntrospectionHelper +                    // can keep track of all the nested types -- and provide more helpful +                    // exception messages, etc. +                                 +                    preg_match('/@return[\s]+([\w]+)/', $method->getDocComment(), $matches); +                    if (!empty($matches[1]) && class_exists($matches[1], false)) { +                        $this->nestedTypes[$name] = $matches[1]; +                    } else {                     +                        // assume that method createEquals() creates object of type "Equals" +                        // (that example would be false, of course)                     +                        $this->nestedTypes[$name] = $this->getPropertyName($name, "create"); +                    } +                     +                    $this->nestedCreators[$name] = $method; +                     +                } elseif (strpos($name, "addconfigured") === 0) { +                     +                    // *must* use class hints if using addConfigured ... +                     +                    // 1 param only +                    $params = $method->getParameters(); +                     +                    if (count($params) < 1) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take at least one parameter."); +                    } +                     +                    if (count($params) > 1) { +                        $this->warn($method->getDeclaringClass()->getName()."::".$method->getName()."() takes more than one parameter. (IH only uses the first)"); +                    } +                     +                    $classname = null; +                     +                    if (($hint = $params[0]->getClass()) !== null) {  +                        $classname = $hint->getName();     +                    }                     +                     +                    if ($classname === null) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() method MUST use a class hint to indicate the class type of parameter."); +                    } +                         +                    $this->nestedTypes[$name] = $classname; +                 +                    $this->nestedStorers[$name] = $method; +                     +                } elseif (strpos($name, "add") === 0) { +                     +                    // *must* use class hints if using add ... +                     +                    // 1 param only +                    $params = $method->getParameters(); +                    if (count($params) < 1) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() must take at least one parameter."); +                    } +                     +                    if (count($params) > 1) { +                        $this->warn($method->getDeclaringClass()->getName()."::".$method->getName()."() takes more than one parameter. (IH only uses the first)"); +                    } + +                    $classname = null; +                     +                    if (($hint = $params[0]->getClass()) !== null) {  +                        $classname = $hint->getName();     +                    }                     +                     +                    // we don't use the classname here, but we need to make sure it exists before +                    // we later try to instantiate a non-existant class +                    if ($classname === null) { +                        throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() method MUST use a class hint to indicate the class type of parameter."); +                    } +                 +                    $this->nestedCreators[$name] = $method; +                }  +            } // if $method->isPublic()         +        } // foreach         +    } + + +    /** Sets the named attribute. */ +    function setAttribute(Project $project, $element, $attributeName, &$value) { +         +        // we want to check whether the value we are setting looks like +        // a slot-listener variable:  %{task.current_file} +        // +        // slot-listener variables are not like properties, in that they cannot be mixed with +        // other text values.  The reason for this disparity is that properties are only +        // set when first constructing objects from XML, whereas slot-listeners are always dynamic. +        // +        // This is made possible by PHP5 (objects automatically passed by reference) and PHP's loose +        // typing. +         +        if (StringHelper::isSlotVar($value)) { +             +            $as = "setlistening" . strtolower($attributeName); + +            if (!isset($this->slotListeners[$as])) { +                $msg = $this->getElementName($project, $element) . " doesn't support a slot-listening '$attributeName' attribute."; +                throw new BuildException($msg); +            } +             +            $method = $this->slotListeners[$as]; +             +            $key = StringHelper::slotVar($value); +            $value = Register::getSlot($key); // returns a RegisterSlot object which will hold current value of that register (accessible using getValue()) +             +        } else { +             +            // Traditional value options +             +            $as = "set".strtolower($attributeName); +             +            if (!isset($this->attributeSetters[$as])) { +                $msg = $this->getElementName($project, $element) . " doesn't support the '$attributeName' attribute."; +                throw new BuildException($msg); +            } +             +            $method = $this->attributeSetters[$as];             +             +            if ($as == "setrefid") {             +                $value = new Reference($value); +            } else { +             +                // decode any html entities in string +                $value = html_entity_decode($value);                 +                 +                // value is a string representation of a boolean type, +                // convert it to primitive +                if (StringHelper::isBoolean($value)) { + +                    $value = StringHelper::booleanValue($value); +                } +                 +                // does method expect a PhingFile object? if so, then  +                // pass a project-relative file. +                $params = $method->getParameters(); + +                $classname = null; +                 +                if (($hint = $params[0]->getClass()) !== null) {  +                    $classname = $hint->getName();     +                } +                 +                // there should only be one param; we'll just assume .... +                if ($classname !== null) { +                    switch(strtolower($classname)) { +                        case "phingfile": +                            $value = $project->resolveFile($value); +                            break; +                        case "path": +                            $value = new Path($project, $value); +                            break; +                        case "reference": +                            $value = new Reference($value); +                            break;             +                        // any other object params we want to support should go here ... +                    } +                     +                } // if hint !== null +                 +            } // if not setrefid +             +        } // if is slot-listener +         +        try { +            $project->log("    -calling setter ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); +            $method->invoke($element, $value); +        } catch(Exception $exc) { +            throw new BuildException($exc); +        } +         +    } + +    /** Adds PCDATA areas.*/ +    function addText(Project $project, $element, $text) { +        if ($this->methodAddText === null) { +            $msg = $this->getElementName($project, $element)." doesn't support nested text data."; +            throw new BuildException($msg); +        }         +        try { +            $method = $this->methodAddText; +            $method->invoke($element, $text); +        } catch (Exception $exc) { +            throw new BuildException($exc); +        } +    } + +    /** +     * Creates a named nested element.  +     *  +     * Valid creators can be in the form createFoo() or addFoo(Bar). +     * @return object Returns the nested element. +     * @throws BuildException +     */ +    function createElement(Project $project, $element, $elementName) { +     +        $addMethod = "add".strtolower($elementName); +        $createMethod = "create".strtolower($elementName); +        $nestedElement = null; +         +        if (isset($this->nestedCreators[$createMethod])) { +             +            $method = $this->nestedCreators[$createMethod]; +             try { // try to invoke the creator method on object +                $project->log("    -calling creator ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); +                $nestedElement = $method->invoke($element); +            } catch (Exception $exc) { +                throw new BuildException($exc); +            }             +             +        } elseif (isset($this->nestedCreators[$addMethod])) {             +             +            $method = $this->nestedCreators[$addMethod]; +             +            // project components must use class hints to support the add methods +             +            try { // try to invoke the adder method on object +             +                $project->log("    -calling adder ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); +                // we've already assured that correct num of params +                // exist and that method is using class hints                 +                $params = $method->getParameters(); + +                $classname = null; +             +                if (($hint = $params[0]->getClass()) !== null) {  +                    $classname = $hint->getName();     +                }                 +                 +                // create a new instance of the object and add it via $addMethod                 +                $nestedElement = new $classname(); +                 +                $method->invoke($element, $nestedElement); +                                 +            } catch (Exception $exc) { +                throw new BuildException($exc); +            } +        } else { +            $msg = $this->getElementName($project, $element) . " doesn't support the '$elementName' creator/adder."; +            throw new BuildException($msg); +        }                                 +         +        if ($nestedElement instanceof ProjectComponent) { +            $nestedElement->setProject($project); +        } +         +        return $nestedElement; +    } + +    /** +     * Creates a named nested element. +     * @return void +     * @throws BuildException +     */ +    function storeElement($project, $element, $child, $elementName = null) { +     +        if ($elementName === null) { +            return; +        } +         +        $storer = "addconfigured".strtolower($elementName); +           +        if (isset($this->nestedStorers[$storer])) { +             +            $method = $this->nestedStorers[$storer]; +             +            try {                                 +                $project->log("    -calling storer ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG);                     +                $method->invoke($element, $child);             +            } catch (Exception $exc) { +                throw new BuildException($exc); +            } +        } +         +    } + +    /** Does the introspected class support PCDATA? */ +    function supportsCharacters() { +        return ($this->methodAddText !== null); +    } + +    /** Return all attribues supported by the introspected class. */ +    function getAttributes() { +        $attribs = array(); +        foreach (array_keys($this->attributeSetters) as $setter) { +            $attribs[] =$this->getPropertyName($setter, "set"); +        } +        return $attribs; +    } + +    /** Return all nested elements supported by the introspected class. */ +    function getNestedElements() { +        return $this->nestedTypes; +    } +     +    /** +     * Get the the name for an element. +     * When possible the full classnam (phing.tasks.system.PropertyTask) will +     * be returned.  If not available (loaded in taskdefs or typedefs) then the +     * XML element name will be returned. +     * +     * @param Project $project +     * @param object $element The Task or type element. +     * @return string Fully qualified class name of element when possible. +     */ +    function getElementName(Project $project, $element) { +        +          $taskdefs = $project->getTaskDefinitions(); +        $typedefs = $project->getDataTypeDefinitions(); +         +        // check if class of element is registered with project (tasks & types)         +        // most element types don't have a getTag() method +        $elClass = get_class($element); +         +        if (!in_array('getTag', get_class_methods($elClass))) { +                // loop through taskdefs and typesdefs and see if the class name +                // matches (case-insensitive) any of the classes in there +                foreach(array_merge($taskdefs, $typedefs) as $elName => $class) { +                    if (0 === strcasecmp($elClass, StringHelper::unqualify($class))) { +                        return $class; +                    } +                } +                return "$elClass (unknown)"; +        } else { +            // ->getTag() method does exist, so use it +            $elName = $element->getTag(); +            if (isset($taskdefs[$elName])) { +                return $taskdefs[$elName]; +            } elseif (isset($typedefs[$elName])) { + +                return $typedefs[$elName]; +            } else { +                return "$elName (unknown)"; +            } +        }         +    } + +    /** extract the name of a property from a method name - subtracting  a given prefix. */ +    function getPropertyName($methodName, $prefix) { +        $start = strlen($prefix); +        return strtolower(substr($methodName, $start)); +    } +     +    /** +     * Prints warning message to screen if -debug was used. +     */ +    function warn($msg) { +        if (Phing::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { +            print("[IntrospectionHelper] " . $msg . "\n"); +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/Phing.php b/buildscripts/phing/classes/phing/Phing.php new file mode 100644 index 00000000..bb8d67f6 --- /dev/null +++ b/buildscripts/phing/classes/phing/Phing.php @@ -0,0 +1,1161 @@ +<?php +/* + * $Id: Phing.php,v 1.51 2006/01/06 15:12:33 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Project.php'; +require_once 'phing/ProjectComponent.php'; +require_once 'phing/Target.php'; +require_once 'phing/Task.php'; + +include_once 'phing/BuildException.php'; +include_once 'phing/BuildEvent.php'; + +include_once 'phing/parser/Location.php'; +include_once 'phing/parser/ExpatParser.php'; +include_once 'phing/parser/AbstractHandler.php'; +include_once 'phing/parser/ProjectConfigurator.php'; +include_once 'phing/parser/RootHandler.php'; +include_once 'phing/parser/ProjectHandler.php'; +include_once 'phing/parser/TaskHandler.php'; +include_once 'phing/parser/TargetHandler.php'; +include_once 'phing/parser/DataTypeHandler.php'; +include_once 'phing/parser/NestedElementHandler.php'; + +include_once 'phing/system/util/Properties.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/system/util/Register.php'; + +/** + * Entry point into Phing.  This class handles the full lifecycle of a build -- from  + * parsing & handling commandline arguments to assembling the project to shutting down + * and cleaning up in the end. + * + * If you are invoking Phing from an external application, this is still + * the class to use.  Your applicaiton can invoke the start() method, passing + * any commandline arguments or additional properties. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.51 $ + * @package   phing + */ +class Phing { + +    /** The default build file name */ +    const DEFAULT_BUILD_FILENAME = "build.xml"; + +    /** Our current message output status. Follows PROJECT_MSG_XXX */ +    private static $msgOutputLevel = PROJECT_MSG_INFO; + +    /** PhingFile that we are using for configuration */ +    private $buildFile = null; + +    /** The build targets */ +    private $targets = array(); + +    /** +     * Set of properties that are passed in from commandline or invoking code. +     * @var Properties +     */ +    private static $definedProps; + +    /** Names of classes to add as listeners to project */ +    private $listeners = array(); + +    private $loggerClassname = null; + +    /** The class to handle input (can be only one). */ +    private $inputHandlerClassname; +     +    /** Indicates if this phing should be run */ +    private $readyToRun = false; + +    /** Indicates we should only parse and display the project help information */ +    private $projectHelp = false; +     +    /** Used by utility function getResourcePath() */ +    private static $importPaths; +     +    /** System-wide static properties (moved from System) */ +    private static $properties = array(); +     +    /** Static system timer. */ +    private static $timer; +     +	/** The current Project */ +	private static $currentProject; +	 +	/** Whether to capture PHP errors to buffer. */ +	private static $phpErrorCapture = false; +	 +	/** Array of captured PHP errors */ +	private static $capturedPhpErrors = array(); +	 +    /** +     * Prints the message of the Exception if it's not null. +     */ +    function printMessage(Exception $t) { +        print($t->getMessage() . "\n"); +        if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { +            print($t->getTraceAsString()."\n"); +            if ($t instanceof Exception) {                 +                $c = $t->getCause(); +                if ($c !== null) { +                    print("Wrapped exception trace:\n"); +                    print($c->getTraceAsString() . "\n"); +                } +            } +        } // if output level is DEBUG +    } + +    /**  +     * Entry point allowing for more options from other front ends. +     *  +     * This method encapsulates the complete build lifecycle. +     *  +     * @param array &$args The commandline args passed to phing shell script. +     * @param array $additionalUserProperties   Any additional properties to be passed to Phing (alternative front-end might implement this). +     *                                          These additional properties will be available using the getDefinedProperty() method and will +     *                                          be added to the project's "user" properties. +     * @return void +     * @see execute() +     * @see runBuild() +     */ +    public static function start(&$args, $additionalUserProperties = null) { + +        try { +            $m = new Phing(); +            $m->execute($args); +        } catch (Exception $exc) { +            $m->printMessage($exc); +            self::halt(-1); // Parameter error +        } + +        if ($additionalUserProperties !== null) { +            $keys = $m->additionalUserProperties->keys(); +            while(count($keys)) { +                $key = array_shift($keys); +                $property = $m->additionalUserProperties->getProperty($key); +                $m->setDefinedProperty($key, $property); +            } +        } + +        try { +            $m->runBuild(); +        } catch(Exception $exc) { +            self::halt(1); // Errors occured +        } +         +        // everything fine, shutdown +        self::halt(0); // no errors, everything is cake +    } +     +    /** +     * Making output level a static property so that this property +     * can be accessed by other parts of the system, enabling +     * us to display more information -- e.g. backtraces -- for "debug" level. +     * @return int +     */ +    public static function getMsgOutputLevel() { +        return self::$msgOutputLevel; +    }         +     +    /** +     * Command line entry point. This method kicks off the building +     * of a project object and executes a build using either a given +     * target or the default target. +     * +     * @param array $args Command line args. +     * @return void +     */ +    public static function fire($args) { +        self::start($args, null); +    } +     +    /** +     * Setup/initialize Phing environment from commandline args. +     * @param array $args commandline args passed to phing shell. +     * @return void +     */ +    public function execute($args) { +     +        self::$definedProps = new Properties(); +        $this->searchForThis = null; + +        // cycle through given args +        for ($i = 0, $argcount = count($args); $i < $argcount; ++$i) {  +                            // ++$i intentional here, as first param is script name +            $arg = $args[$i]; + +            if ($arg == "-help" || $arg == "-h") { +                $this->printUsage(); +                return; +            } elseif ($arg == "-version" || $arg == "-v") { +                $this->printVersion(); +                return; +            } elseif ($arg == "-quiet" || $arg == "-q") { +                self::$msgOutputLevel = PROJECT_MSG_WARN; +            } elseif ($arg == "-verbose") { +                $this->printVersion(); +                self::$msgOutputLevel = PROJECT_MSG_VERBOSE; +            } elseif ($arg == "-debug") { +                $this->printVersion(); +                self::$msgOutputLevel = PROJECT_MSG_DEBUG; +            } elseif ($arg == "-logfile") { +                try { // try to set logfile +                    if (!isset($args[$i+1])) { +                        print("You must specify a log file when using the -logfile argument\n"); +                        return; +                    } else { +                        $logFile = new PhingFile($args[++$i]); +                        $this->loggerClassname = 'phing.listener.PearLogger'; +                        $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath()); +                    } +                } catch (IOException $ioe) { +                    print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n"); +                    throw $ioe; +                } +            } elseif ($arg == "-buildfile" || $arg == "-file" || $arg == "-f") { +                if (!isset($args[$i+1])) { +                    print("You must specify a buildfile when using the -buildfile argument\n"); +                    return; +                } else { +                    $this->buildFile = new PhingFile($args[++$i]); +                } +            } elseif ($arg == "-listener") { +                if (!isset($args[$i+1])) { +                    print("You must specify a listener class when using the -listener argument\n"); +                    return; +                } else { +                    $this->listeners[] = $args[++$i]; +                } +                 +            } elseif (StringHelper::startsWith("-D", $arg)) { +                $name = substr($arg, 2); +                $value = null; +                $posEq = strpos($name, "="); +                if ($posEq !== false) { +                    $value = substr($name, $posEq+1); +                    $name  = substr($name, 0, $posEq); +                } elseif ($i < count($args)-1) { +                    $value = $args[++$i]; +                } +                self::$definedProps->setProperty($name, $value); +            } elseif ($arg == "-logger") { +                if (!isset($args[$i+1])) { +                    print("You must specify a classname when using the -logger argument\n"); +                    return; +                } else { +                    $this->loggerClassname = $args[++$i]; +                } +            } elseif ($arg == "-inputhandler") { +                if ($this->inputHandlerClassname !== null) { +                    throw new BuildException("Only one input handler class may be specified."); +                } +                if (!isset($args[$i+1])) { +                    print("You must specify a classname when using the -inputhandler argument\n"); +                    return; +                } else { +                    $this->inputHandlerClassname = $args[++$i]; +                } +            } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") { +                // set the flag to display the targets and quit +                $this->projectHelp = true; +            } elseif ($arg == "-find") { +                // eat up next arg if present, default to build.xml +                if ($i < count($args)-1) { +                    $this->searchForThis = $args[++$i]; +                } else { +                    $this->searchForThis = self::DEFAULT_BUILD_FILENAME; +                } +            } elseif (substr($arg,0,1) == "-") { +                // we don't have any more args +                print("Unknown argument: $arg\n"); +                $this->printUsage(); +                return; +            } else { +                // if it's no other arg, it may be the target +                array_push($this->targets, $arg); +            } +        } + +        // if buildFile was not specified on the command line, +        if ($this->buildFile === null) { +            // but -find then search for it +            if ($this->searchForThis !== null) { +                $this->buildFile = $this->_findBuildFile(self::getProperty("user.dir"), $this->searchForThis); +            } else { +                $this->buildFile = new PhingFile(self::DEFAULT_BUILD_FILENAME); +            } +        } +        // make sure buildfile exists +        if (!$this->buildFile->exists()) { +            throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " does not exist!"); +        } + +        // make sure it's not a directory +        if ($this->buildFile->isDirectory()) {    +            throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " is a dir!"); +        } + +        $this->readyToRun = true; +    } + +    /** +     * Helper to get the parent file for a given file. +     * +     * @param PhingFile $file +     * @return PhingFile Parent file or null if none +     */ +    function _getParentFile(PhingFile $file) { +        $filename = $file->getAbsolutePath(); +        $file     = new PhingFile($filename); +        $filename = $file->getParent(); + +        if ($filename !== null && self::$msgOutputLevel >= PROJECT_MSG_VERBOSE) { +            print("Searching in $filename\n"); +        } + +        return ($filename === null) ? null : new PhingFile($filename); +    } + +    /** +     * Search parent directories for the build file. +     * +     * Takes the given target as a suffix to append to each +     * parent directory in search of a build file.  Once the +     * root of the file-system has been reached an exception +     * is thrown. +     *  +     * @param string $start Start file path. +     * @param string $suffix Suffix filename to look for in parents. +     * @return PhingFile A handle to the build file +     * +     * @throws BuildException    Failed to locate a build file +     */ +    function _findBuildFile($start, $suffix) { +        if (self::$msgOutputLevel >= PROJECT_MSG_INFO) { +            print("Searching for $suffix ...\n"); +        } +        $startf = new PhingFile($start); +        $parent = new PhingFile($startf->getAbsolutePath()); +        $file   = new PhingFile($parent, $suffix); + +        // check if the target file exists in the current directory +        while (!$file->exists()) { +            // change to parent directory +            $parent = $this->_getParentFile($parent); + +            // if parent is null, then we are at the root of the fs, +            // complain that we can't find the build file. +            if ($parent === null) { +                throw new BuildException("Could not locate a build file!"); +            } +            // refresh our file handle +            $file = new PhingFile($parent, $suffix); +        } +        return $file; +    } + +    /** +     * Executes the build. +     * @return void +     */ +    function runBuild() { + +        if (!$this->readyToRun) { +            return; +        } +         +        $project = new Project(); +		 +		self::setCurrentProject($project); +		set_error_handler(array('Phing', 'handlePhpError')); +		 +        $error = null; + +        $this->addBuildListeners($project); +        $this->addInputHandler($project); +         +        // set this right away, so that it can be used in logging. +        $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); + +        try { +            $project->fireBuildStarted(); +            $project->init(); +        } catch (Exception $exc) { +            $project->fireBuildFinished($exc); +            throw $exc;         +        } + +        $project->setUserProperty("phing.version", $this->getPhingVersion()); + +        $e = self::$definedProps->keys(); +        while (count($e)) { +            $arg   = (string) array_shift($e); +            $value = (string) self::$definedProps->getProperty($arg); +            $project->setUserProperty($arg, $value); +        } +        unset($e); + +        $project->setUserProperty("phing.file", $this->buildFile->getAbsolutePath()); + +        // first use the Configurator to create the project object +        // from the given build file. +                 +        try { +            ProjectConfigurator::configureProject($project, $this->buildFile); +        } catch (Exception $exc) { +            $project->fireBuildFinished($exc); +			restore_error_handler(); +			self::unsetCurrentProject(); +            throw $exc; +        }          + +        // make sure that we have a target to execute +        if (count($this->targets) === 0) { +            $this->targets[] = $project->getDefaultTarget(); +        } + +        // execute targets if help param was not given +        if (!$this->projectHelp) { +             +            try {  +                $project->executeTargets($this->targets); +            } catch (Exception $exc) { +                $project->fireBuildFinished($exc); +				restore_error_handler(); +				self::unsetCurrentProject(); +                throw $exc; +            } +        } +        // if help is requested print it +        if ($this->projectHelp) { +            try { +                $this->printDescription($project); +                $this->printTargets($project); +            } catch (Exception $exc) { +                $project->fireBuildFinished($exc); +				restore_error_handler(); +				self::unsetCurrentProject(); +                throw $exc; +            } +        } +                 +        // finally { +        if (!$this->projectHelp) { +            $project->fireBuildFinished(null); +        } +		 +		restore_error_handler(); +		self::unsetCurrentProject(); +    } +     +    /** +     * Bind any default build listeners to this project. +     * Currently this means adding the logger. +     * @param Project $project +     * @return void +     */ +    private function addBuildListeners(Project $project) { +        // Add the default listener +        $project->addBuildListener($this->createLogger()); +    } +     +    /** +     * Creates the InputHandler and adds it to the project. +     * +     * @param Project $project the project instance. +     * +     * @throws BuildException if a specified InputHandler +     *                           class could not be loaded. +     */ +    private function addInputHandler(Project $project) { +        if ($this->inputHandlerClassname === null) { +            $handler = new DefaultInputHandler(); +        } else { +            try { +                $clz = Phing::import($this->inputHandlerClassname); +                $handler = new $clz(); +                if ($project !== null && method_exists($handler, 'setProject')) { +                    $handler->setProject($project); +                }  +            } catch (Exception $e) { +                $msg = "Unable to instantiate specified input handler " +                    . "class " . $this->inputHandlerClassname . " : " +                    . $e->getMessage(); +                throw new BuildException($msg); +            } +        } +        $project->setInputHandler($handler); +    } + +    /** +     * Creates the default build logger for sending build events to the log. +     * @return BuildListener The created Logger +     */ +    private function createLogger() { +        if ($this->loggerClassname !== null) { +            self::import($this->loggerClassname); +            // get class name part             +            $classname = self::import($this->loggerClassname); +            $logger = new $classname; +        } else { +            require_once 'phing/listener/DefaultLogger.php'; +            $logger = new DefaultLogger(); +        } +        $logger->setMessageOutputLevel(self::$msgOutputLevel); +        return $logger; +    } +	 +	/** +	 * Sets the current Project +	 * @param Project $p +	 */ +	public static function setCurrentProject($p) { +		self::$currentProject = $p; +	} +	 +	/** +	 * Unsets the current Project +	 */ +	public static function unsetCurrentProject() { +		self::$currentProject = null; +	} +	 +	/** +	 * Gets the current Project. +	 * @return Project Current Project or NULL if none is set yet/still. +	 */ +	public static function getCurrentProject() { +		return self::$currentProject; +	} +	 +	/** +	 * A static convenience method to send a log to the current (last-setup) Project. +	 * If there is no currently-configured Project, then this will do nothing. +	 * @param string $message +	 * @param int $priority PROJECT_MSG_INFO, etc. +	 */ +	public static function log($message, $priority = PROJECT_MSG_INFO) { +		$p = self::getCurrentProject(); +		if ($p) { +			$p->log($message, $priority); +		} +	} +	 +	/** +	 * Error handler for PHP errors encountered during the build. +	 * This uses the logging for the currently configured project. +	 */ +	public static function handlePhpError($level, $message, $file, $line) { +		 +        // don't want to print supressed errors +        if (error_reporting() > 0) { +		 +			if (self::$phpErrorCapture) { +			 +				self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file); +				 +			} else { +			 +				$message = '[PHP Error] ' . $message; +				$message .= ' [line ' . $line . ' of ' . $file . ']'; +		 +	            switch ($level) { +				 +					case E_STRICT: +					case E_NOTICE: +	                case E_USER_NOTICE: +						self::log($message, PROJECT_MSG_VERBOSE); +	                    break; +					case E_WARNING: +	                case E_USER_WARNING: +						self::log($message, PROJECT_MSG_WARN); +	                    break; +	                case E_ERROR: +					case E_USER_ERROR: +	                default: +						self::log($message, PROJECT_MSG_ERR); +	 +	            } // switch +				 +			} // if phpErrorCapture +			 +        } // if not @ +		 +	} +	 +	/** +	 * Begins capturing PHP errors to a buffer. +	 * While errors are being captured, they are not logged. +	 */ +	public static function startPhpErrorCapture() { +		self::$phpErrorCapture = true; +		self::$capturedPhpErrors = array(); +	} +	 +	/** +	 * Stops capturing PHP errors to a buffer. +	 * The errors will once again be logged after calling this method. +	 */ +	public static function stopPhpErrorCapture() { +		self::$phpErrorCapture = false; +	} +	 +	/** +	 * Clears the captured errors without affecting the starting/stopping of the capture. +	 */ +	public static function clearCapturedPhpErrors() { +		self::$capturedPhpErrors = array(); +	} +	 +	/** +	 * Gets any PHP errors that were captured to buffer. +	 * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level) +	 */ +	public static function getCapturedPhpErrors() { +		return self::$capturedPhpErrors; +	} +	 +    /**  Prints the usage of how to use this class */ +    function printUsage() { +        $lSep = self::getProperty("line.separator"); +        $msg = ""; +        $msg .= "phing [options] [target [target2 [target3] ...]]" . $lSep; +        $msg .= "Options: " . $lSep; +        $msg .= "  -h -help               print this message" . $lSep; +        $msg .= "  -l -list               list available targets in this project" . $lSep; +        $msg .= "  -v -version            print the version information and exit" . $lSep; +        $msg .= "  -q -quiet              be extra quiet" . $lSep; +        $msg .= "  -verbose               be extra verbose" . $lSep; +        $msg .= "  -debug                 print debugging information" . $lSep; +        $msg .= "  -logfile <file>        use given file for log" . $lSep; +        $msg .= "  -logger <classname>    the class which is to perform logging" . $lSep; +        $msg .= "  -f -buildfile <file>   use given buildfile" . $lSep; +        $msg .= "  -D<property>=<value>   use value for given property" . $lSep; +        $msg .= "  -find <file>           search for buildfile towards the root of the" . $lSep; +        $msg .= "                         filesystem and use it" . $lSep; +        //$msg .= "  -recursive <file>      search for buildfile downwards and use it" . $lSep; +        $msg .= $lSep; +        $msg .= "Report bugs to <dev@phing.tigris.org>".$lSep; +        print($msg); +    } + +    function printVersion() { +        print(self::getPhingVersion()."\n"); +    } + +    function getPhingVersion() { +        $versionPath = self::getResourcePath("phing/etc/VERSION.TXT"); +		if ($versionPath === null) { +		    $versionPath = self::getResourcePath("etc/VERSION.TXT"); +		} +        try { // try to read file +            $buffer = null; +            $file = new PhingFile($versionPath); +            $reader = new FileReader($file); +            $reader->readInto($buffer); +            $buffer = trim($buffer); +            //$buffer = "PHING version 1.0, Released 2002-??-??"; +            $phingVersion = $buffer; +        } catch (IOException $iox) { +            print("Can't read version information file\n"); +            throw new BuildException("Build failed"); +        }         +        return $phingVersion; +    } + +    /**  Print the project description, if any */ +    function printDescription(Project $project) { +        if ($project->getDescription() !== null) { +            print($project->getDescription()."\n"); +        } +    } + +    /** Print out a list of all targets in the current buildfile */ +    function printTargets($project) { +        // find the target with the longest name +        $maxLength = 0; +        $targets = $project->getTargets(); +        $targetNames = array_keys($targets); +        $targetName = null; +        $targetDescription = null; +        $currentTarget = null; + +        // split the targets in top-level and sub-targets depending +        // on the presence of a description +         +        $subNames = array(); +        $topNameDescMap = array(); +         +        foreach($targets as $currentTarget) {         +            $targetName = $currentTarget->getName(); +            $targetDescription = $currentTarget->getDescription();             +             +            // subtargets are targets w/o descriptions +            if ($targetDescription === null) { +                $subNames[] = $targetName; +            } else { +                // topNames and topDescriptions are handled later +                // here we store in hash map (for sorting purposes) +                $topNameDescMap[$targetName] = $targetDescription;                +                if (strlen($targetName) > $maxLength) { +                    $maxLength = strlen($targetName); +                } +            } +        } +         +        // Sort the arrays +        sort($subNames); // sort array values, resetting keys (which are numeric)         +        ksort($topNameDescMap); // sort the keys (targetName) keeping key=>val associations +         +        $topNames = array_keys($topNameDescMap); +        $topDescriptions = array_values($topNameDescMap); + +        $defaultTarget = $project->getDefaultTarget(); + +        if ($defaultTarget !== null && $defaultTarget !== "") { +            $defaultName = array(); +            $defaultDesc = array(); +            $defaultName[] = $defaultTarget; + +            $indexOfDefDesc = array_search($defaultTarget, $topNames, true); +            if ($indexOfDefDesc !== false && $indexOfDefDesc >= 0) { +                $defaultDesc = array(); +                $defaultDesc[] = $topDescriptions[$indexOfDefDesc]; +            } + +            $this->_printTargets($defaultName, $defaultDesc, "Default target:", $maxLength); + +        } +        $this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength); +        $this->_printTargets($subNames, null, "Subtargets:", 0); +    }     + +    /** +     * Writes a formatted list of target names with an optional description. +     * +     * @param array $names The names to be printed. +     *              Must not be <code>null</code>. +     * @param array $descriptions The associated target descriptions. +     *                     May be <code>null</code>, in which case +     *                     no descriptions are displayed. +     *                     If non-<code>null</code>, this should have +     *                     as many elements as <code>names</code>. +     * @param string $heading The heading to display. +     *                Should not be <code>null</code>. +     * @param int $maxlen The maximum length of the names of the targets. +     *               If descriptions are given, they are padded to this +     *               position so they line up (so long as the names really +     *               <i>are</i> shorter than this). +     */ +    private function _printTargets($names, $descriptions, $heading, $maxlen) { +        $lSep = self::getProperty("line.separator"); +        $spaces = '  '; +        while (strlen($spaces) < $maxlen) { +            $spaces .= $spaces; +        } +        $msg = ""; +        $msg .= $heading . $lSep; +        $msg .= str_repeat("-",79) . $lSep; + +        $total = count($names); +        for($i=0; $i < $total; $i++) { +            $msg .= " "; +            $msg .= $names[$i]; +            if (!empty($descriptions)) { +                $msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2); +                $msg .= $descriptions[$i]; +            } +            $msg .= $lSep; +        } +        if ($total > 0) { +          print $msg . $lSep; +        }  +   } +    +   /** +    * Import a dot-path notation class path. +    * @param string $dotPath +    * @param mixed $classpath String or object supporting __toString() +    * @return string The unqualified classname (which can be instantiated). +    * @throws BuildException - if cannot find the specified file +    */ +   public static function import($dotPath, $classpath = null) { +         +        // first check to see that the class specified hasn't already been included. +        // (this also handles case where this method is called w/ a classname rather than dotpath) +        $classname = StringHelper::unqualify($dotPath); +        if (class_exists($classname, false)) { +            return $classname; +        } +         +        $dotClassname = basename($dotPath); +        $dotClassnamePos = strlen($dotPath) - strlen($dotClassname); +        $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".php"; +        $path = substr_replace($dotPath, $classFile, $dotClassnamePos); +         +        Phing::__import($path, $classpath); +         +        return $classname; +   } + +   /** +    * Import a PHP file +    * @param string $path Path to the PHP file +    * @param mixed $classpath String or object supporting __toString() +    * @throws BuildException - if cannot find the specified file +    */ +   public static function __import($path, $classpath = null) { +         +        if ($classpath) { +         +            // Apparently casting to (string) no longer invokes __toString() automatically. +            if (is_object($classpath)) { +                $classpath = $classpath->__toString(); +            } +             +            // classpaths are currently additive, but we also don't want to just +            // indiscriminantly prepand/append stuff to the include_path.  This means +            // we need to parse current incldue_path, and prepend any +            // specified classpath locations that are not already in the include_path.               +            // +            // NOTE:  the reason why we do it this way instead of just changing include_path +            // and then changing it back, is that in many cases applications (e.g. Propel) will +            // include/require class files from within method calls.  This means that not all +            // necessary files will be included in this import() call, and hence we can't +            // change the include_path back without breaking those apps.  While this method could +            // be more expensive than switching & switching back (not sure, but maybe), it makes it +            // possible to write far less expensive run-time applications (e.g. using Propel), which is +            // really where speed matters more. +             +            $curr_parts = explode(PATH_SEPARATOR, ini_get('include_path')); +            $add_parts = explode(PATH_SEPARATOR, $classpath); +            $new_parts = array_diff($add_parts, $curr_parts); +            if ($new_parts) { +                if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { +                    print("Phing::import() prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts) . "\n"); +                } +                ini_set('include_path', implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); +            } +        } +         +        $ret = include_once($path);         +         +        if ($ret === false) { +            $e = new BuildException("Error importing $path"); +            if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { +                // We can't log this because listeners belong +                // to projects.  We'll just print it -- of course +                // that isn't very compatible w/ other frontends (but +                // there aren't any right now, so I'm not stressing) +                print("Error importing $path\n"); +                print($e->getTraceAsString()."\n"); +            }         +            throw $e; +        } +         +        return; +   } +    +   /** +    * Looks on include path for specified file. +    * @return string File found (null if no file found). +    */ +   public static function getResourcePath($path) { +         +        if (self::$importPaths === null) { +            $paths = ini_get("include_path");             +            self::$importPaths = explode(PATH_SEPARATOR, ini_get("include_path")); +        } +         +        $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); +        $path = str_replace('/', DIRECTORY_SEPARATOR, $path); + +        foreach (self::$importPaths as $prefix) { +            $foo_path = $prefix . DIRECTORY_SEPARATOR . $path; +            if (file_exists($foo_path)) { +                return $foo_path; +            } +        } +         +        // Check for the property phing.home +        $home_dir = self::getProperty('phing.home'); +         +        if ($home_dir) +        { +			$home_path = $home_dir . DIRECTORY_SEPARATOR . $path; +			 +			if (file_exists($home_path)) +			{ +				return $home_path; +			} +		} +         +        // If we are using this via PEAR then check for the file in the data dir +        // This is a bit of a hack, but works better than previous solution of assuming +        // data_dir is on the include_path. +        $data_dir = '@DATA-DIR@'; +        if ($data_dir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted. +            $data_path = $data_dir . DIRECTORY_SEPARATOR . $path; +            if (file_exists($data_path)) { +                   return $data_path; +               } +        } +         +        return null; +   } +    +   // ------------------------------------------------------------------------------------------- +   // System-wide methods (moved from System class, which had namespace conflicts w/ PEAR System) +   // ------------------------------------------------------------------------------------------- +              +    /** +     * Set System constants which can be retrieved by calling Phing::getProperty($propName). +     * @return void +     */ +    private static function setSystemConstants() { + +        /* +         * PHP_OS returns on +         *   WindowsNT4.0sp6  => WINNT +         *   Windows2000      => WINNT +         *   Windows ME       => WIN32 +         *   Windows 98SE     => WIN32 +         *   FreeBSD 4.5p7    => FreeBSD +         *   Redhat Linux     => Linux +		 *   Mac OS X		  => Darwin +         */ +        self::setProperty('host.os', PHP_OS); +		 +		// this is used by some tasks too +        self::setProperty('os.name', PHP_OS); +		 +        // it's still possible this won't be defined, +        // e.g. if Phing is being included in another app w/o +        // using the phing.php script. +        if (!defined('PHP_CLASSPATH')) { +            define('PHP_CLASSPATH', get_include_path()); +        } +         +        self::setProperty('php.classpath', PHP_CLASSPATH); + +        // try to determine the host filesystem and set system property +        // used by Fileself::getFileSystem to instantiate the correct +        // abstraction layer + +        switch (strtoupper(PHP_OS)) { +            case 'WINNT': +                self::setProperty('host.fstype', 'WINNT'); +                break; +            case 'WIN32': +                self::setProperty('host.fstype', 'WIN32'); +                break; +            default: +                self::setProperty('host.fstype', 'UNIX'); +                break; +        } + +        self::setProperty('php.version', PHP_VERSION); +        self::setProperty('user.home', getenv('HOME')); +        self::setProperty('application.startdir', getcwd()); +        self::setProperty('line.separator', "\n"); + +        // try to detect machine dependent information +        $sysInfo = array(); +        if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN' && function_exists("posix_uname")) { +              $sysInfo = posix_uname(); +        } else { +              $sysInfo['nodename'] = php_uname('n'); +              $sysInfo['machine']= php_uname('m') ; +              //this is a not so ideal substition, but maybe better than nothing +              $sysInfo['domain'] = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : "unknown"; +              $sysInfo['release'] = php_uname('r'); +              $sysInfo['version'] = php_uname('v'); +        }               +      + +        self::setProperty("host.name", isset($sysInfo['nodename']) ? $sysInfo['nodename'] : "unknown"); +        self::setProperty("host.arch", isset($sysInfo['machine']) ? $sysInfo['machine'] : "unknown"); +        self::setProperty("host.domain",isset($sysInfo['domain']) ? $sysInfo['domain'] : "unknown"); +        self::setProperty("host.os.release", isset($sysInfo['release']) ? $sysInfo['release'] : "unknown"); +        self::setProperty("host.os.version", isset($sysInfo['version']) ? $sysInfo['version'] : "unknown"); +        unset($sysInfo); +    } +     +    /** +     * This gets a property that was set via command line or otherwise passed into Phing. +     * "Defined" in this case means "externally defined".  The reason this method exists is to +     * provide a public means of accessing commandline properties for (e.g.) logger or listener  +     * scripts.  E.g. to specify which logfile to use, PearLogger needs to be able to access +     * the pear.log.name property. +     *  +     * @param string $name +     * @return string value of found property (or null, if none found). +     */ +    public static function getDefinedProperty($name) { +        return self::$definedProps->getProperty($name); +    } +     +    /** +     * This sets a property that was set via command line or otherwise passed into Phing. +     *  +     * @param string $name +     * @return string value of found property (or null, if none found). +     */ +    public static function setDefinedProperty($name, $value) { +        return self::$definedProps->setProperty($name, $value); +    } +     +    /** +     * Returns property value for a System property. +     * System properties are "global" properties like line.separator, +     * and user.dir.  Many of these correspond to similar properties in Java +     * or Ant. +     *  +     * @param string $paramName +     * @return string Value of found property (or null, if none found). +     */ +    public static function getProperty($propName) { +     +        // some properties are detemined on each access +        // some are cached, see below + +        // default is the cached value: +        $val = isset(self::$properties[$propName]) ? self::$properties[$propName] : null; +     +        // special exceptions         +        switch($propName) { +            case 'user.dir': +                $val = getcwd(); +            break;             +        } +         +        return $val; +    } + +    /** Retuns reference to all properties*/ +    public static function &getProperties() { +        return self::$properties; +    } + +    public static function setProperty($propName, $propValue) {     +        $propName = (string) $propName; +        $oldValue = self::getProperty($propName); +        self::$properties[$propName] = $propValue; +        return $oldValue; +    } +     +    public static function currentTimeMillis() { +        list($usec, $sec) = explode(" ",microtime()); +        return ((float)$usec + (float)$sec); +    } +     +    /** +     * Sets the include path based on PHP_CLASSPATH constant (set in phing.php). +     * @return void +     */ +    private static function setIncludePaths() { +        $success = false; +         +        if (defined('PHP_CLASSPATH')) { +            $success = ini_set('include_path', PHP_CLASSPATH); +        } else { +            // don't do anything, just assume that include_path has been properly set. +            $success = true; +        } +         +        if ($success === false) { +            print("SYSTEM FAILURE: Could not set PHP include path\n"); +            self::halt(-1); +        } +    } +     +    /** +     * Sets PHP INI values that Phing needs. +     * @return void +     */ +    private static function setIni() { +        error_reporting(E_ALL); +        set_time_limit(0); +        ini_set('magic_quotes_gpc', 'off'); +        ini_set('short_open_tag', 'off'); +        ini_set('default_charset', 'iso-8859-1'); +        ini_set('register_globals', 'off'); +        ini_set('allow_call_time_pass_reference', 'on'); +         +        // should return memory limit in MB   +        $mem_limit = (int) ini_get('memory_limit'); +        if ($mem_limit < 32) { +            ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects +        }         +    } + +    /** +     * Returns reference to Timer object. +     * @return Timer +     */ +    public static function getTimer() { +        if (self::$timer === null) { +            include_once 'phing/system/util/Timer.php'; +            self::$timer= new Timer(); +        } +        return self::$timer; +    } +         +     /** +     * Start up Phing. +     * Sets up the Phing environment -- does NOT initiate the build process. +     * @return void +     */ +    public static function startup() { +        +        register_shutdown_function(array('Phing', 'shutdown')); + +        // some init stuff +        self::getTimer()->start(); + +        self::setSystemConstants(); +        self::setIncludePaths(); +        self::setIni(); +    } +     +    /** +     * Halts the system. +     * @see shutdown() +     */ +    public static function halt($code=0) {         +        self::shutdown($code);         +    } + +    /** +     * Stops timers & exits. +     * @return void +     */ +    public static function shutdown($exitcode = 0) { +        //print("[AUTOMATIC SYSTEM SHUTDOWN]\n"); +        self::getTimer()->stop(); +        exit($exitcode); // final point where everything stops +    } +     +} diff --git a/buildscripts/phing/classes/phing/Project.php b/buildscripts/phing/classes/phing/Project.php new file mode 100644 index 00000000..8123d91e --- /dev/null +++ b/buildscripts/phing/classes/phing/Project.php @@ -0,0 +1,966 @@ +<?php +/* + *  $Id: Project.php,v 1.29 2006/02/02 20:27:10 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +define('PROJECT_MSG_DEBUG', 4); +define('PROJECT_MSG_VERBOSE', 3); +define('PROJECT_MSG_INFO', 2); +define('PROJECT_MSG_WARN', 1); +define('PROJECT_MSG_ERR', 0); + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/TaskAdapter.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/BuildEvent.php'; +include_once 'phing/input/DefaultInputHandler.php'; + +/** + *  The Phing project class. Represents a completely configured Phing project. + *  The class defines the project and all tasks/targets. It also contains + *  methods to start a build as well as some properties and FileSystem + *  abstraction. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.29 $ + * @package   phing + */ +class Project { + +    /** contains the targets */ +    private $targets         = array(); +    /** global filterset (future use) */ +    private $globalFilterSet = array(); +    /**  all globals filters (future use) */ +    private $globalFilters   = array(); +     +    /** Project properties map (usually String to String). */ +    private $properties = array(); +     +    /** +     * Map of "user" properties (as created in the Ant task, for example). +     * Note that these key/value pairs are also always put into the +     * project properties, so only the project properties need to be queried. +     * Mapping is String to String. +     */ +    private $userProperties = array(); +     +    /** +     * Map of inherited "user" properties - that are those "user" +     * properties that have been created by tasks and not been set +     * from the command line or a GUI tool. +     * Mapping is String to String. +     */ +    private $inheritedProperties = array(); +     +    /** task definitions for this project*/ +    private $taskdefs = array(); +     +    /** type definitions for this project */ +    private $typedefs = array(); +     +    /** holds ref names and a reference to the referred object*/ +    private $references = array(); +     +    /** The InputHandler being used by this project. */ +    private $inputHandler; +     +    /* -- properties that come in via xml attributes -- */ +     +    /** basedir (PhingFile object) */ +    private $basedir; +     +    /** the default target name */ +    private $defaultTarget = 'all'; +     +    /** project name (required) */ +    private $name; +     +    /** project description */ +    private $description; + +    /** a FileUtils object */ +    private $fileUtils; +     +    /**  Build listeneers */ +    private $listeners = array(); + +    /** +     *  Constructor, sets any default vars. +     */ +    function __construct() { +        $this->fileUtils = new FileUtils(); +        $this->inputHandler = new DefaultInputHandler(); +    } + +    /** +     * Sets the input handler +     */ +    public function setInputHandler(InputHandler $handler) { +        $this->inputHandler = $handler; +    } + +    /** +     * Retrieves the current input handler. +     */ +    public function getInputHandler() { +        return $this->inputHandler; +    } + +    /** inits the project, called from main app */ +    function init() { +        // set builtin properties +        $this->setSystemProperties(); +         +        // load default tasks +        $taskdefs = Phing::getResourcePath("phing/tasks/defaults.properties"); +         +        try { // try to load taskdefs +            $props = new Properties(); +            $in = new PhingFile((string)$taskdefs); + +            if ($in === null) { +                throw new BuildException("Can't load default task list"); +            } +            $props->load($in); + +            $enum = $props->propertyNames(); +            foreach($enum as $key) { +                $value = $props->getProperty($key); +                $this->addTaskDefinition($key, $value); +            } +        } catch (IOException $ioe) { +            throw new BuildException("Can't load default task list"); +        } + +        // load default tasks +        $typedefs = Phing::getResourcePath("phing/types/defaults.properties"); + +        try { // try to load typedefs +            $props = new Properties(); +            $in    = new PhingFile((string)$typedefs); +            if ($in === null) { +                throw new BuildException("Can't load default datatype list"); +            } +            $props->load($in); + +            $enum = $props->propertyNames(); +            foreach($enum as $key) { +                $value = $props->getProperty($key); +                $this->addDataTypeDefinition($key, $value); +            } +        } catch(IOException $ioe) { +            throw new BuildException("Can't load default datatype list"); +        } +    } + +    /** returns the global filterset (future use) */ +    function getGlobalFilterSet() { +        return $this->globalFilterSet; +    } + +    // --------------------------------------------------------- +    // Property methods +    // --------------------------------------------------------- +     +    /** +     * Sets a property. Any existing property of the same name +     * is overwritten, unless it is a user property. +     * @param string $name The name of property to set. +     *             Must not be <code>null</code>. +     * @param string $value The new value of the property. +     *              Must not be <code>null</code>. +     * @return void +     */ +    public function setProperty($name, $value) { +	 +        // command line properties take precedence +        if (isset($this->userProperties[$name])) { +            $this->log("Override ignored for user property " . $name, PROJECT_MSG_VERBOSE); +            return; +        } + +        if (isset($this->properties[$name])) { +            $this->log("Overriding previous definition of property " . $name, PROJECT_MSG_VERBOSE); +        } + +        $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); +        $this->properties[$name] = $value; +    } + +    /** +     * Sets a property if no value currently exists. If the property +     * exists already, a message is logged and the method returns with +     * no other effect. +     * +     * @param string $name The name of property to set. +     *             Must not be <code>null</code>. +     * @param string $value The new value of the property. +     *              Must not be <code>null</code>. +     * @since 2.0 +     */ +    public function setNewProperty($name, $value) { +        if (isset($this->properties[$name])) { +            $this->log("Override ignored for property " . $name, PROJECT_MSG_DEBUG); +            return; +        } +        $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); +        $this->properties[$name] = $value; +    } + +    /** +     * Sets a user property, which cannot be overwritten by +     * set/unset property calls. Any previous value is overwritten. +     * @param string $name The name of property to set. +     *             Must not be <code>null</code>. +     * @param string $value The new value of the property. +     *              Must not be <code>null</code>. +     * @see #setProperty() +     */ +    public function setUserProperty($name, $value) { +        $this->log("Setting ro project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); +        $this->userProperties[$name] = $value; +        $this->properties[$name] = $value; +    } + +    /** +     * Sets a user property, which cannot be overwritten by set/unset +     * property calls. Any previous value is overwritten. Also marks +     * these properties as properties that have not come from the +     * command line. +     * +     * @param string $name The name of property to set. +     *             Must not be <code>null</code>. +     * @param string $value The new value of the property. +     *              Must not be <code>null</code>. +     * @see #setProperty() +     */ +    public function setInheritedProperty($name, $value) { +        $this->inheritedProperties[$name] = $value; +        $this->setUserProperty($name, $value); +    } + +    /** +     * Sets a property unless it is already defined as a user property +     * (in which case the method returns silently). +     * +     * @param name The name of the property. +     *             Must not be <code>null</code>. +     * @param value The property value. Must not be <code>null</code>. +     */ +    private function setPropertyInternal($name, $value) { +        if (isset($this->userProperties[$name])) { +			$this->log("Override ignored for user property " . $name, PROJECT_MSG_VERBOSE); +            return; +        } +        $this->properties[$name] = $value; +    } + +    /** +     * Returns the value of a property, if it is set. +     * +     * @param string $name The name of the property. +     *             May be <code>null</code>, in which case +     *             the return value is also <code>null</code>. +     * @return string The property value, or <code>null</code> for no match +     *         or if a <code>null</code> name is provided. +     */ +    public function getProperty($name) { +        if (!isset($this->properties[$name])) { +            return null; +        } +        return $this->properties[$name]; +    } + +    /** +     * Replaces ${} style constructions in the given value with the +     * string value of the corresponding data types. +     * +     * @param value The string to be scanned for property references. +     *              May be <code>null</code>. +     * +     * @return the given string with embedded property names replaced +     *         by values, or <code>null</code> if the given string is +     *         <code>null</code>. +     * +     * @exception BuildException if the given value has an unclosed +     *                           property name, e.g. <code>${xxx</code> +     */ +    public function replaceProperties($value) { +        return ProjectConfigurator::replaceProperties($this, $value, $this->properties); +    } + +    /** +     * Returns the value of a user property, if it is set. +     * +     * @param string $name The name of the property. +     *             May be <code>null</code>, in which case +     *             the return value is also <code>null</code>. +     * @return string  The property value, or <code>null</code> for no match +     *         or if a <code>null</code> name is provided. +     */ +     public function getUserProperty($name) { +        if (!isset($this->userProperties[$name])) { +            return null; +        } +        return $this->userProperties[$name]; +    } + +    /** +     * Returns a copy of the properties table. +     * @return array A hashtable containing all properties +     *         (including user properties). +     */ +    public function getProperties() { +        return $this->properties; +    } + +    /** +     * Returns a copy of the user property hashtable +     * @return a hashtable containing just the user properties +     */ +    public function getUserProperties() { +        return $this->userProperties; +    } + +    /** +     * Copies all user properties that have been set on the command +     * line or a GUI tool from this instance to the Project instance +     * given as the argument. +     * +     * <p>To copy all "user" properties, you will also have to call +     * {@link #copyInheritedProperties copyInheritedProperties}.</p> +     * +     * @param Project $other the project to copy the properties to.  Must not be null. +     * @return void +     * @since phing 2.0 +     */ +    public function copyUserProperties(Project $other) {         +        foreach($this->userProperties as $arg => $value) { +            if (isset($this->inheritedProperties[$arg])) { +                continue; +            } +            $other->setUserProperty($arg, $value); +        } +    } + +    /** +     * Copies all user properties that have not been set on the +     * command line or a GUI tool from this instance to the Project +     * instance given as the argument. +     * +     * <p>To copy all "user" properties, you will also have to call +     * {@link #copyUserProperties copyUserProperties}.</p> +     * +     * @param other the project to copy the properties to.  Must not be null. +     * +     * @since phing 2.0 +     */ +    public function copyInheritedProperties(Project $other) { +        foreach($this->userProperties as $arg => $value) { +            if ($other->getUserProperty($arg) !== null) { +                continue; +            } +            $other->setInheritedProperty($arg, $value); +        }         +    } +     +    // --------------------------------------------------------- +    //  END Properties methods +    // --------------------------------------------------------- + + +    function setDefaultTarget($targetName) { +        $this->defaultTarget = (string) trim($targetName); +    } + +    function getDefaultTarget() { +        return (string) $this->defaultTarget; +    } + +    /** +     * Sets the name of the current project +     * +     * @param    string   name of project +     * @return   void +     * @access   public +     * @author   Andreas Aderhold, andi@binarycloud.com +     */ + +    function setName($name) { +        $this->name = (string) trim($name); +        $this->setProperty("phing.project.name", $this->name); +    } + +    /** +     * Returns the name of this project +     * +     * @returns  string  projectname +     * @access   public +     * @author   Andreas Aderhold, andi@binarycloud.com +     */ +    function getName() { +        return (string) $this->name; +    } + +    /** Set the projects description */ +    function setDescription($description) { +        $this->description = (string) trim($description); +    } + +    /** return the description, null otherwise */ +    function getDescription() { +        return $this->description; +    } + +    /** Set basedir object from xml*/ +    function setBasedir($dir) { +        if ($dir instanceof PhingFile) { +            $dir = $dir->getAbsolutePath(); +        } + +        $dir = $this->fileUtils->normalize($dir); + +        $dir = new PhingFile((string) $dir); +        if (!$dir->exists()) { +            throw new BuildException("Basedir ".$dir->getAbsolutePath()." does not exist"); +        } +        if (!$dir->isDirectory()) { +            throw new BuildException("Basedir ".$dir->getAbsolutePath()." is not a directory"); +        } +        $this->basedir = $dir; +        $this->setPropertyInternal("project.basedir", $this->basedir->getAbsolutePath()); +        $this->log("Project base dir set to: " . $this->basedir->getPath(), PROJECT_MSG_VERBOSE); +         +        // [HL] added this so that ./ files resolve correctly.  This may be a mistake ... or may be in wrong place.                 +        chdir($dir->getAbsolutePath()); +    } + +    /** +     * Returns the basedir of this project +     * +     * @returns  PhingFile  Basedir PhingFile object +     * @access   public +     * @throws   BuildException +     * @author   Andreas Aderhold, andi@binarycloud.com +     */ +    function getBasedir() { +        if ($this->basedir === null) {             +            try { // try to set it +                $this->setBasedir("."); +            } catch (BuildException $exc) { +                throw new BuildException("Can not set default basedir. ".$exc->getMessage()); +            } +        } +        return $this->basedir; +    } + +    /** +     * Sets system properties and the environment variables for this project. +     *  +     * @return void +     */ +    function setSystemProperties() { +         +        // first get system properties +        $systemP = array_merge( self::getProperties(), Phing::getProperties() ); +        foreach($systemP as $name => $value) { +            $this->setPropertyInternal($name, $value); +        } +         +        // and now the env vars +        foreach($_SERVER as $name => $value) { +            // skip arrays +            if (is_array($value)) { +                continue; +            } +            $this->setPropertyInternal('env.' . $name, $value); +        } +        return true; +    } + + +    /** +     * Adds a task definition. +     * @param string $name Name of tag. +     * @param string $class The class path to use. +     * @param string $classpath The classpat to use. +     */ +    function addTaskDefinition($name, $class, $classpath = null) { +        $name  = $name; +        $class = $class; +        if ($class === "") { +            $this->log("Task $name has no class defined.", PROJECT_MSG_ERR); +        }  elseif (!isset($this->taskdefs[$name])) { +            Phing::import($class, $classpath); +            $this->taskdefs[$name] = $class; +            $this->log("  +Task definiton: $name ($class)", PROJECT_MSG_DEBUG); +        } else { +            $this->log("Task $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); +        } +    } + +    function &getTaskDefinitions() { +        return $this->taskdefs; +    } + +    /** +     * Adds a data type definition. +     * @param string $name Name of tag. +     * @param string $class The class path to use. +     * @param string $classpath The classpat to use. +     */ +    function addDataTypeDefinition($typeName, $typeClass, $classpath = null) {     +        if (!isset($this->typedefs[$typeName])) {         +            Phing::import($typeClass, $classpath); +            $this->typedefs[$typeName] = $typeClass; +            $this->log("  +User datatype: $typeName ($typeClass)", PROJECT_MSG_DEBUG); +        } else { +            $this->log("Type $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); +        } +    } + +    function getDataTypeDefinitions() { +        return $this->typedefs; +    } + +    /** add a new target to the project */ +    function addTarget($targetName, &$target) { +        if (isset($this->targets[$targetName])) { +            throw new BuildException("Duplicate target: $targetName"); +        } +        $this->addOrReplaceTarget($targetName, $target); +    } + +    function addOrReplaceTarget($targetName, &$target) { +        $this->log("  +Target: $targetName", PROJECT_MSG_DEBUG); +        $target->setProject($this); +        $this->targets[$targetName] = $target; +    } + +    function getTargets() { +        return $this->targets; +    } + +    /** +     * Create a new task instance and return reference to it. This method is +     * sorta factory like. A _local_ instance is created and a reference returned to +     * that instance. Usually PHP destroys local variables when the function call +     * ends. But not if you return a reference to that variable. +     * This is kinda error prone, because if no reference exists to the variable +     * it is destroyed just like leaving the local scope with primitive vars. There's no +     * central place where the instance is stored as in other OOP like languages. +     * +     * [HL] Well, ZE2 is here now, and this is  still working. We'll leave this alone +     * unless there's any good reason not to. +     * +     * @param    string    $taskType    Task name +     * @returns  Task                A task object +     * @throws   BuildException +     *           Exception +     */ +    function createTask($taskType) { +        try { +            $cls = ""; +            $tasklwr = strtolower($taskType); +            foreach ($this->taskdefs as $name => $class) { +                if (strtolower($name) === $tasklwr) { +                    $cls = StringHelper::unqualify($class);                                     +                    break; +                } +            } +             +            if ($cls === "") { +                return null; +            } +             +            if (!class_exists($cls)) { +                throw new BuildException("Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"); +            } +             +            $o = new $cls();         +     +            if ($o instanceof Task) { +                $task = $o; +            } else { +                $this->log ("  (Using TaskAdapter for: $taskType)", PROJECT_MSG_DEBUG); +                // not a real task, try adapter +                $taskA = new TaskAdapter(); +                $taskA->setProxy($o); +                $task = $taskA; +            } +            $task->setProject($this); +            $task->setTaskType($taskType); +            // set default value, can be changed by the user +            $task->setTaskName($taskType); +            $this->log ("  +Task: " . $taskType, PROJECT_MSG_DEBUG); +        } catch (Exception $t) { +            throw new BuildException("Could not create task of type: " . $taskType, $t); +        } +        // everything fine return reference +        return $task; +    } + +    /** +     * Create a task instance and return reference to it +     * See createTask() for explanation how this works +     * +     * @param    string   Type name +     * @returns  object   A datatype object +     * @throws   BuildException +     *           Exception +     */ +    function createDataType($typeName) {         +        try { +            $cls = ""; +            $typelwr = strtolower($typeName); +            foreach ($this->typedefs as $name => $class) { +                if (strtolower($name) === $typelwr) { +                    $cls = StringHelper::unqualify($class);                                     +                    break; +                } +            } +             +            if ($cls === "") { +                return null; +            } +             +            if (!class_exists($cls)) { +                throw new BuildException("Could not instantiate class $cls, even though a class was specified. (Make sure that the specified class file contains a class with the correct name.)"); +            } +             +            $type = new $cls(); +            $this->log("  +Type: $typeName", PROJECT_MSG_DEBUG); +            if (!($type instanceof DataType)) { +                throw new Exception("$class is not an instance of phing.types.DataType"); +            } +            if ($type instanceof ProjectComponent) { +                $type->setProject($this); +            } +        } catch (Exception $t) { +            throw new BuildException("Could not create type: $typeName", $t); +        } +        // everything fine return reference +        return $type; +    } + +    /** +     * Executes a list of targets +     * +     * @param    array  List of target names to execute +     * @returns  void +     * @throws   BuildException +     */ +    function executeTargets($targetNames) { +        foreach($targetNames as $tname) { +            $this->executeTarget($tname); +        } +    } + +    /** +     * Executes a target +     * +     * @param    string  Name of Target to execute +     * @returns  void +     * @throws   BuildException +     */ +    function executeTarget($targetName) { + +        // complain about executing void +        if ($targetName === null) { +            throw new BuildException("No target specified"); +        } + +        // invoke topological sort of the target tree and run all targets +        // until targetName occurs. +        $sortedTargets = $this->_topoSort($targetName, $this->targets);         + +        $curIndex = (int) 0; +        $curTarget = null; +        do { +            try { +                $curTarget = $sortedTargets[$curIndex++]; +                $curTarget->performTasks(); +            } catch (BuildException $exc) { +                $this->log("Execution of target \"".$curTarget->getName()."\" failed for the following reason: ".$exc->getMessage(), PROJECT_MSG_ERR); +                throw $exc; +            } +        } while ($curTarget->getName() !== $targetName); +    } + + +    function resolveFile($fileName, $rootDir = null) { +        if ($rootDir === null) { +            return $this->fileUtils->resolveFile($this->basedir, $fileName); +        } else { +            return $this->fileUtils->resolveFile($rootDir, $fileName); +        } +    }     + +    /** +     * Topologically sort a set of Targets. +     * @param  $root is the (String) name of the root Target. The sort is +     *         created in such a way that the sequence of Targets until the root +     *         target is the minimum possible such sequence. +     * @param  $targets is a array representing a "name to Target" mapping +     * @return An array of Strings with the names of the targets in +     *         sorted order. +     */ +    function _topoSort($root, &$targets) { + +        $root     = (string) $root; +        $ret      = array(); +        $state    = array(); +        $visiting = array(); + +        // We first run a DFS based sort using the root as the starting node. +        // This creates the minimum sequence of Targets to the root node. +        // We then do a sort on any remaining unVISITED targets. +        // This is unnecessary for doing our build, but it catches +        // circular dependencies or missing Targets on the entire +        // dependency tree, not just on the Targets that depend on the +        // build Target. + +        $this->_tsort($root, $targets, $state, $visiting, $ret); + +        $retHuman = ""; +        for ($i=0, $_i=count($ret); $i < $_i; $i++) { +            $retHuman .= $ret[$i]->toString()." "; +        } +        $this->log("Build sequence for target '$root' is: $retHuman", PROJECT_MSG_VERBOSE); + +        $keys = array_keys($targets); +        while($keys) { +            $curTargetName = (string) array_shift($keys); +            if (!isset($state[$curTargetName])) { +                $st = null; +            } else { +                $st = (string) $state[$curTargetName]; +            } + +            if ($st === null) { +                $this->_tsort($curTargetName, $targets, $state, $visiting, $ret); +            } elseif ($st === "VISITING") { +                throw new Exception("Unexpected node in visiting state: $curTargetName"); +            } +        } + +        $retHuman = ""; +        for ($i=0,$_i=count($ret); $i < $_i; $i++) { +            $retHuman .= $ret[$i]->toString()." "; +        } +        $this->log("Complete build sequence is: $retHuman", PROJECT_MSG_VERBOSE); + +        return $ret; +    } + +    // one step in a recursive DFS traversal of the target dependency tree. +    // - The array "state" contains the state (VISITED or VISITING or null) +    //   of all the target names. +    // - The stack "visiting" contains a stack of target names that are +    //   currently on the DFS stack. (NB: the target names in "visiting" are +    //    exactly the target names in "state" that are in the VISITING state.) +    // 1. Set the current target to the VISITING state, and push it onto +    //    the "visiting" stack. +    // 2. Throw a BuildException if any child of the current node is +    //    in the VISITING state (implies there is a cycle.) It uses the +    //    "visiting" Stack to construct the cycle. +    // 3. If any children have not been VISITED, tsort() the child. +    // 4. Add the current target to the Vector "ret" after the children +    //    have been visited. Move the current target to the VISITED state. +    //    "ret" now contains the sorted sequence of Targets upto the current +    //    Target. + +    function _tsort($root, &$targets, &$state, &$visiting, &$ret) { +        $state[$root] = "VISITING"; +        $visiting[]  = $root; + +        if (!isset($targets[$root]) || !($targets[$root] instanceof Target)) { +            $target = null; +        } else { +            $target = $targets[$root]; +        } + +        // make sure we exist +        if ($target === null) { +            $sb = "Target '$root' does not exist in this project."; +            array_pop($visiting); +            if (!empty($visiting)) { +                $parent = (string) $visiting[count($visiting)-1]; +                $sb .= "It is used from target '$parent'."; +            } +            throw new BuildException($sb); +        } + +        $deps = $target->getDependencies(); + +        while($deps) { +            $cur = (string) array_shift($deps); +            if (!isset($state[$cur])) { +                $m = null; +            } else { +                $m = (string) $state[$cur]; +            } +            if ($m === null) { +                // not been visited +                $this->_tsort($cur, $targets, $state, $visiting, $ret); +            } elseif ($m == "VISITING") { +                // currently visiting this node, so have a cycle +                throw $this->_makeCircularException($cur, $visiting); +            } +        } + +        $p = (string) array_pop($visiting); +        if ($root !== $p) { +            throw new Exception("Unexpected internal error: expected to pop $root but got $p"); +        } + +        $state[$root] = "VISITED"; +        $ret[] = $target; +    } + +    function _makeCircularException($end, $stk) { +        $sb = "Circular dependency: $end"; +        do { +            $sb .= " <- ".(string) array_pop($stk); +        } while($c != $end); +        return new BuildException($sb); +    } + +    /** +     * Adds a reference to an object. This method is called when the parser +     * detects a id="foo" attribute. It passes the id as $name and a reference +     * to the object assigned to this id as $value +     */ +    function addReference($name, $object) { +        if (isset($this->references[$name])) { +            $this->log("Overriding previous definition of reference to $name", PROJECT_MSG_WARN); +        } +        $this->log("Adding reference: $name -> ".get_class($object), PROJECT_MSG_DEBUG); +        $this->references[$name] = $object; +    } + +    /** +     * Returns the references array. +     * @return array +     */ +    function getReferences() { +        return $this->references; +    } +	 +	/** +	 * Returns a specific reference. +	 * @param string $key The reference id/key. +	 * @return object or null if not defined +	 */ +	function getReference($key) +	{ +		if (isset($this->references[$key])) { +		    return $this->references[$key]; +		} +		return null; // just to be explicit +	} + +    /** +     * Abstracting and simplifyling Logger calls for project messages +     */ +    function log($msg, $level = PROJECT_MSG_INFO) { +        $this->logObject($this, $msg, $level); +    } + +    function logObject($obj, $msg, $level) { +        $this->fireMessageLogged($obj, $msg, $level); +    } + +    function addBuildListener(BuildListener $listener) { +        $this->listeners[] = $listener; +    } + +    function removeBuildListener(BuildListener $listener) { +        $newarray = array(); +        for ($i=0, $size=count($this->listeners); $i < $size; $i++) { +            if ($this->listeners[$i] !== $listener) { +                $newarray[] = $this->listeners[$i]; +            } +        } +        $this->listeners = $newarray; +    } + +    function getBuildListeners() { +        return $this->listeners; +    } + +    function fireBuildStarted() { +        $event = new BuildEvent($this);         +        foreach($this->listeners as $listener) { +            $listener->buildStarted($event); +        } +    } + +    function fireBuildFinished($exception) {         +        $event = new BuildEvent($this); +        $event->setException($exception); +        foreach($this->listeners as $listener) { +            $listener->buildFinished($event); +        } +    } + +    function fireTargetStarted($target) { +        $event = new BuildEvent($target);         +           foreach($this->listeners as $listener) { +            $listener->targetStarted($event); +        } +    } + +    function fireTargetFinished($target, $exception) { +        $event = new BuildEvent($target);         +        $event->setException($exception); +        foreach($this->listeners as $listener) { +            $listener->targetFinished($event); +        } +    } + +    function fireTaskStarted($task) { +        $event = new BuildEvent($task);         +        foreach($this->listeners as $listener) { +            $listener->taskStarted($event); +        } +    } + +    function fireTaskFinished($task, $exception) { +        $event = new BuildEvent($task);         +        $event->setException($exception); +        foreach($this->listeners as $listener) { +            $listener->taskFinished($event); +        } +    } + +    function fireMessageLoggedEvent($event, $message, $priority) { +        $event->setMessage($message, $priority); +        foreach($this->listeners as $listener) { +            $listener->messageLogged($event); +        } +    } + +    function fireMessageLogged($object, $message, $priority) { +        $this->fireMessageLoggedEvent(new BuildEvent($object), $message, $priority); +    } +} diff --git a/buildscripts/phing/classes/phing/ProjectComponent.php b/buildscripts/phing/classes/phing/ProjectComponent.php new file mode 100644 index 00000000..97ef329f --- /dev/null +++ b/buildscripts/phing/classes/phing/ProjectComponent.php @@ -0,0 +1,72 @@ +<?php +/* + *  $Id: ProjectComponent.php,v 1.5 2003/12/24 13:02:08 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + *  Abstract class providing properties and methods common to all + *  the project components + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org>  + * @version   $Revision: 1.5 $ + * @package   phing + */ +abstract class ProjectComponent { + +    /** +     *  Holds a reference to the project that a project component +     *  (a task, a target, etc.) belongs to +     * +     *  @var    object  A reference to the current project instance +     */ +    protected $project = null; + +    /** +     *  References the project to the current component. +     * +     *  @param    object    The reference to the current project +     *  @access   public +     */ +    function setProject($project) { +        $this->project = $project; +    } + +    /** +     *  Returns a reference to current project +     * +     *  @return   object   Reference to current porject object +     *  @access   public +     */ +    function getProject() { +        return $this->project; +    } + +    /** +     *  Logs a message with the given priority. +     * +     *  @param  string   The message to be logged. +     *  @param  integer  The message's priority at this message should have +     */ +    public function log($msg, $level = PROJECT_MSG_INFO) { +        if ($this->project !== null) { +            $this->project->log($msg, $level); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/RuntimeConfigurable.php b/buildscripts/phing/classes/phing/RuntimeConfigurable.php new file mode 100644 index 00000000..a23437fa --- /dev/null +++ b/buildscripts/phing/classes/phing/RuntimeConfigurable.php @@ -0,0 +1,118 @@ +<?php +/* + *  $Id: RuntimeConfigurable.php,v 1.6 2003/12/24 12:38:39 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + *  Wrapper class that holds the attributes of a Task (or elements + *  nested below that level) and takes care of configuring that element + *  at runtime. + * + *  <strong>SMART-UP INLINE DOCS</strong> + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.6 $ + * @package   phing + */ +class RuntimeConfigurable { + +    private $elementTag = null; +    private $children = array(); +    private $wrappedObject = null; +    private $attributes = array(); +    private $characters = ""; + + +    /** @param proxy The element to wrap. */ +    function __construct($proxy, $elementTag) { +        $this->wrappedObject = $proxy; +        $this->elementTag = $elementTag; +    } + +    function setProxy($proxy) { +        $this->wrappedObject = $proxy; +    } + +    /** Set's the attributes for the wrapped element. */ +    function setAttributes($attributes) { +        $this->attributes = $attributes; +    } + +    /** Returns the AttributeList of the wrapped element. */ +    function getAttributes() { +        return $this->attributes; +    } + +    /** Adds child elements to the wrapped element. */ +    function addChild(RuntimeConfigurable $child) { +        $this->children[] = $child; +    } + +    /** Returns the child with index */ +    function getChild($index) { +        return $this->children[(int)$index]; +    } + +    /** Add characters from #PCDATA areas to the wrapped element. */ +    function addText($data) { +        $this->characters .= (string) $data; +    } + +    function getElementTag() { +        return $this->elementTag; +    } + + +    /** Configure the wrapped element and all children. */ +    function maybeConfigure(Project $project) { +        $id = null; + +        // DataType configured in ProjectConfigurator +        //        if ( is_a($this->wrappedObject, "DataType") ) +        //            return; + +        if ($this->attributes || $this->characters) { +            ProjectConfigurator::configure($this->wrappedObject, $this->attributes, $project); + +            if (isset($this->attributes["id"])) { +                $id = $this->attributes["id"]; +            } + +            $this->attributes = null; + +            if ($this->characters) { +                ProjectConfigurator::addText($project, $this->wrappedObject, (string) $this->characters); +                $this->characters=""; +            } +            if ($id !== null) { +                $project->addReference($id, $this->wrappedObject); +            } +        } + +        if ( is_array($this->children) && !empty($this->children) ) { +            // Configure all child of this object ... +            foreach($this->children as $child) { +                $child->maybeConfigure($project); +                ProjectConfigurator::storeChild($project, $this->wrappedObject, $child->wrappedObject, strtolower($child->getElementTag())); +            } +        } +    } +} + diff --git a/buildscripts/phing/classes/phing/Target.php b/buildscripts/phing/classes/phing/Target.php new file mode 100644 index 00000000..9aeb9440 --- /dev/null +++ b/buildscripts/phing/classes/phing/Target.php @@ -0,0 +1,317 @@ +<?php +/* + * $Id: Target.php,v 1.10 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/TaskContainer.php'; + +/** + *  The Target component. Carries all required target data. Implements the + *  abstract class {@link TaskContainer} + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + *  @access    public + *  @see       TaskContainer + *  @package   phing + */ + +class Target implements TaskContainer { +     +    /** name of target */ +    private $name; +     +    /** dependencies */ +    private $dependencies = array(); +     +    /** holds objects of children of this target */ +    private $children = array(); +     +    /** the if cond. from xml */ +    private $ifCondition = ""; +     +    /** the unless cond. from xml */ +    private $unlessCondition = ""; +     +    /** description of this target */ +    private $description; +     +    /** reference to project */ +    private $project; + +    /** +     *  References the project to the current component. +     * +     *  @param Project The reference to the current project +     */ +    public function setProject(Project $project) { +        $this->project = $project; +    } + +    /** +     *  Returns reference to current project +     * +     *  @return Project Reference to current porject object +     */ +    public function getProject() { +        return $this->project; +    } + +    /** +     *  Sets the target dependencies from xml +     * +     *  @param string $depends Comma separated list of targetnames that depend on +     *                  this target +     *  @throws BuildException +     */ +    public function setDepends($depends) { +        // explode should be faster than strtok +        $deps = explode(',', $depends); +        for ($i=0, $size=count($deps); $i < $size; $i++) { +            $trimmed = trim($deps[$i]); +            if ($trimmed === "") { +                throw new BuildException("Syntax Error: Depend attribute for target ".$this->getName()." is malformed."); +            }  +            $this->addDependency($trimmed); +        } +    } + +    /** +     *  Adds a singular dependent target name to the list +     * +     *  @param   string   The dependency target to add +     *  @access  public +     */ +    public function addDependency($dependency) { +        $this->dependencies[] = (string) $dependency; +    } + +    /** +     *  Returns reference to indexed array of the dependencies this target has. +     * +     *  @return  array  Referece to target dependencoes +     */ +    public function getDependencies() { +        return $this->dependencies; +    } + +    /** +     *  Sets the name of the target +     * +     *  @param  string   Name of this target +     */ +    public function setName($name) { +        $this->name = (string) $name; +    } + +    /** +     *  Returns name of this target. +     * +     *  @return  string     The name of the target +     *  @access   public +     */ +    function getName() { +        return (string) $this->name; +    } + +    /** +     *  Adds a task element to the list of this targets child elements +     * +     *  @param   object  The task object to add +     *  @access  public +     */ +    function addTask(Task $task) { +        $this->children[] = $task; +    } + +    /** +     *  Adds a runtime configurable element to the list of this targets child +     *  elements. +     * +     *  @param   object  The RuntimeConfigurabel object +     *  @access  public +     */ +    function addDataType($rtc) { +        $this->children[] = $rtc; +    } + +    /** +     *  Returns an array of all tasks this target has as childrens. +     * +     *  The task objects are copied here. Don't use this method to modify +     *  task objects. +     * +     *  @return  array  Task[] +     */ +    public function getTasks() { +        $tasks = array(); +        for ($i=0,$size=count($this->children); $i < $size; $i++) { +            $tsk = $this->children[$i]; +            if ($tsk instanceof Task) { +                // note: we're copying objects here! +                $tasks[] = clone $tsk; +            } +        } +        return $tasks; +    } + +    /** +     *  Set the if-condition from the XML tag, if any. The property name given +     *  as parameter must be present so the if condition evaluates to true +     * +     *  @param   string  The property name that has to be present +     *  @access  public +     */ +    public function setIf($property) { +        $this->ifCondition = ($property === null) ? "" : $property; +    } + +    /** +     *  Set the unless-condition from the XML tag, if any. The property name +     *  given as parameter must be present so the unless condition evaluates +     *  to true +     * +     *  @param   string  The property name that has to be present +     *  @access  public +     */ +    public function setUnless($property) { +        $this->unlessCondition = ($property === null) ? "" : $property; +    } + +    /** +     *  Sets a textual description of this target. +     * +     *  @param string The description text +     */ +    public function setDescription($description) { +        if ($description !== null && strcmp($description, "") !== 0) { +            $this->description = (string) $description; +        } else { +            $this->description = null; +        } +    } + +    /** +     *  Returns the description of this target. +     * +     *  @return string The description text of this target +     */ +    public function getDescription() { +        return $this->description; +    } + +    /** +     *  Returns a string representation of this target. In our case it +     *  simply returns the target name field +     * +     *  @return string The string representation of this target +     */ +    function toString() { +        return (string) $this->name; +    } + +    /** +     *  The entry point for this class. Does some checking, then processes and +     *  performs the tasks for this target. +     * +     */ +    public function main() { +        if ($this->testIfCondition() && $this->testUnlessCondition()) { +            foreach($this->children as $o) { +                if ($o instanceof Task) { +                    // child is a task +                    $o->perform(); +                } else { +                    // child is a RuntimeConfigurable +                    $o->maybeConfigure($this->project); +                } +            } +        } elseif (!$this->testIfCondition()) { +            $this->project->log("Skipped target '".$this->name."' because property '".$this->ifCondition."' not set.", PROJECT_MSG_VERBOSE); +        } else { +            $this->project->log("Skipped target '".$this->name."' because property '".$this->unlessCondition."' set.", PROJECT_MSG_VERBOSE); +        } +    } + +    /** +     *  Performs the tasks by calling the main method of this target that +     *  actually executes the tasks. +     * +     *  This method is for ZE2 and used for proper exception handling of +     *  task exceptions. +     */ +    public function performTasks() { +        try {// try to execute this target +            $this->project->fireTargetStarted($this); +            $this->main(); +            $this->project->fireTargetFinished($this, $null=null); +        } catch (Exception $exc) { +            // log here and rethrow +            $this->project->fireTargetFinished($this, $exc); +            throw $exc; +        } +    }     + +    /** +     *  Tests if the property set in ifConfiditon exists. +     * +     *  @return  boolean  <code>true</code> if the property specified +     *                    in <code>$this->ifCondition</code> exists; +     *                    <code>false</code> otherwise +     */ +    private function testIfCondition() { +        if ($this->ifCondition === "") { +            return true; +        } + +        $properties = explode(",", $this->ifCondition); + +        $result = true; +        foreach ($properties as $property) { +            $test = ProjectConfigurator::replaceProperties($this->getProject(), $property, $this->project->getProperties()); +            $result = $result && ($this->project->getProperty($test) !== null); +        } + +        return $result; +    } + +    /** +     *  Tests if the property set in unlessCondition exists. +     * +     *  @return  boolean  <code>true</code> if the property specified +     *                    in <code>$this->unlessCondition</code> exists; +     *                    <code>false</code> otherwise +     */ +    private function testUnlessCondition() { +        if ($this->unlessCondition === "") { +            return true; +        } +         +        $properties = explode(",", $this->unlessCondition); + +        $result = true; +        foreach ($properties as $property) { +            $test = ProjectConfigurator::replaceProperties($this->getProject(), $property, $this->project->getProperties()); +            $result = $result && ($this->project->getProperty($test) === null); +        } +        return $result; +    } + +} diff --git a/buildscripts/phing/classes/phing/Task.php b/buildscripts/phing/classes/phing/Task.php new file mode 100644 index 00000000..893a82e9 --- /dev/null +++ b/buildscripts/phing/classes/phing/Task.php @@ -0,0 +1,266 @@ +<?php +/* + *  $Id: Task.php,v 1.11 2005/10/05 20:23:22 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/RuntimeConfigurable.php'; + +/** + * The base class for all Tasks. + * + * Use {@link Project#createTask} to register a new Task. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.11 $ + * @see       Project#createTask() + * @package   phing + */ +abstract class Task extends ProjectComponent { + +    /** owning Target object */ +    protected $target; +     +    /** description of the task */ +    protected $description; +     +    /** internal taskname (req) */ +    protected $taskType; +     +    /** taskname for logger */ +    protected $taskName; +     +    /** stored buildfile location */ +    protected $location; +     +    /** wrapper of the task */ +    protected $wrapper; + +    /** +     * Sets the owning target this task belongs to. +     * +     * @param   object  Reference to owning target +     * @access  public +     */ +    function setOwningTarget(Target $target) { +        $this->target = $target; +    } + +    /** +     *  Returns the owning target of this task. +     * +     *  @return  object    The target object that owns this task +     *  @access  public +     */ +    function getOwningTarget() { +        return $this->target; +    } + +    /** +     *  Returns the name of task, used only for log messages +     * +     *  @return  string  Name of this task +     *  @access  public +     */ +    function getTaskName() { +        if ($this->taskName === null) { +            // if no task name is set, then it's possible +            // this task was created from within another task.  We don't +            // therefore know the XML tag name for this task, so we'll just +            // use the class name stripped of "task" suffix.  This is only +            // for log messages, so we don't have to worry much about accuracy. +            return preg_replace('/task$/i', '', get_class($this)); +        } +        return $this->taskName; +    } + +    /** +     *  Sets the name of this task for log messages +     * +     *  @return  string  A string representing the name of this task for log +     *  @access  public +     */ +    function setTaskName($name) { +        $this->taskName = (string) $name; +    } + +    /** +     *  Returns the name of the task under which it was invoked, +     *  usually the XML tagname +     * +     *  @return string The type of this task (XML Tag) +     */ +    function getTaskType() { +        return $this->taskType; +    } + +    /** +     *  Sets the type of the task. Usually this is the name of the XML tag +     * +     *  @param string The type of this task (XML Tag) +     */ +    function setTaskType($name) { +        $this->taskType = (string) $name; +    } +	 +	/** +	 * Returns a name  +	 *  +	 */ +	protected function getRegisterSlot($slotName) { +		return Register::getSlot('task.' . $this->getTaskName() . '.' . $slotName); +	} +	 +    /** +     *  Provides a project level log event to the task. +     * +     *  @param string  The message to log +     *  @param integer The priority of the message +     *  @see BuildEvent +     *  @see BuildListener +     */ +    function log($msg, $level = PROJECT_MSG_INFO) { +        $this->project->logObject($this, $msg, $level); +    } + +    /** +     *  Sets a textual description of the task +     * +     *  @param    string    The text describing the task +     */ +    public function setDescription($desc) { +        $this->description = $desc; +    } + +    /** +     *  Returns the textual description of the task +     * +     *  @return  string  The text description of the task +     */ +    public function getDescription() { +        return $this->description; +    } + +    /** +     *  Called by the parser to let the task initialize properly. +     *  Should throw a BuildException if something goes wrong with the build +     * +     *  This is abstract here, but may not be overloaded by subclasses. +     * +     * @throws BuildException +     */ +    public function init() { +    } + +    /** +     *  Called by the project to let the task do it's work. This method may be +     *  called more than once, if the task is invoked more than once. For +     *  example, if target1 and target2 both depend on target3, then running +     *  <em>phing target1 target2</em> will run all tasks in target3 twice. +     * +     *  Should throw a BuildException if someting goes wrong with the build +     * +     *  This is abstract here. Must be overloaded by real tasks. +     * +     *  @access  public +     */ +    abstract function main(); + +    /** +     *  Returns the location within the buildfile this task occurs. Used +     *  by {@link BuildException} to give detailed error messages. +     * +     *  @return Location The location object describing the position of this +     *                   task within the buildfile. +     */ +    function getLocation() { +        return $this->location; +    } + +    /** +     *  Sets the location within the buildfile this task occurs. Called by +     *  the parser to set location information. +     * +     *  @return  object  The location object describing the position of this +     *                   task within the buildfile. +     *  @access  public +     */ +    function setLocation(Location $location) { +        $this->location = $location; +    } + +    /** +     *  Returns the wrapper object for runtime configuration +     * +     *  @return  object  The wrapper object used by this task +     *  @access  public +     */ +    function getRuntimeConfigurableWrapper() { +        if ($this->wrapper === null) { +            $this->wrapper = new RuntimeConfigurable($this, $this->getTaskName()); +        } +        return $this->wrapper; +    } + +    /** +     *  Sets the wrapper object this task should use for runtime +     *  configurable elements. +     * +     *  @param   object  The wrapper object this task should use +     *  @access  public +     */ +    function setRuntimeConfigurableWrapper(RuntimeConfigurable $wrapper) { +        $this->wrapper = $wrapper; +    } + +    /** +     *  Configure this task if it hasn't been done already. +     * +     *  @access  public +     */ +    function maybeConfigure() { +        if ($this->wrapper !== null) { +            $this->wrapper->maybeConfigure($this->project); +        } +    } + +    /** +     *  Perfrom this task +     * +     *  @access  public +     */ +    function perform() { + +        try { // try executing task +            $this->project->fireTaskStarted($this); +            $this->maybeConfigure(); +            $this->main(); +            $this->project->fireTaskFinished($this, $null=null); +        } catch (Exception $exc) { +            if ($exc instanceof BuildException) { +                if ($exc->getLocation() === null) { +                    $exc->setLocation($this->getLocation()); +                } +            } +            $this->project->fireTaskFinished($this, $exc); +            throw $exc; +        } +    } +} diff --git a/buildscripts/phing/classes/phing/TaskAdapter.php b/buildscripts/phing/classes/phing/TaskAdapter.php new file mode 100644 index 00000000..8b84b768 --- /dev/null +++ b/buildscripts/phing/classes/phing/TaskAdapter.php @@ -0,0 +1,84 @@ +<?php +/* + *  $Id: TaskAdapter.php,v 1.7 2005/10/04 13:52:53 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + *  Use introspection to "adapt" an arbitrary ( not extending Task, but with + *  similar patterns). + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.7 $ + *  @package   phing + */ +class TaskAdapter extends Task { +     +    /** target object */ +    private $proxy; +     +    /** +     * Main entry point. +     * @return void +     */ +    function main() { +     +        if (method_exists($this->proxy, "setProject")) { +            try {  // try to set project +                $this->proxy->setProject($this->project); +            } catch (Exception $ex) { +                $this->log("Error setting project in " . get_class($this->proxy) . PROJECT_MSG_ERR); +                throw new BuildException($ex); +            } +        } else { +            throw new Exception("Error setting project in class " . get_class($this->proxy)); +        } +                +        if (method_exists($this->proxy, "main")) { +            try { //try to call main +                $this->proxy->main($this->project); +            } catch (Exception $ex) { +                $this->log("Error in " . get_class($this->proxy), PROJECT_MSG_ERR); +                throw new BuildException($ex->getMessage()); +            } +        } else { +            throw new BuildException("Your task-like class '" . get_class($this->proxy) ."' does not have a main() method"); +        } +    } + +    /** +     * Set the target object. +     * @param object $o +     * @return void +     */ +    function setProxy($o) { +        $this->proxy = $o; +    } + +    /** +     * Gets the target object. +     * @return object +     */ +    function getProxy() { +        return $this->proxy; +    } + +} diff --git a/buildscripts/phing/classes/phing/TaskContainer.php b/buildscripts/phing/classes/phing/TaskContainer.php new file mode 100644 index 00000000..2e9eb67a --- /dev/null +++ b/buildscripts/phing/classes/phing/TaskContainer.php @@ -0,0 +1,42 @@ +<?php +/* + *  $Id: TaskContainer.php,v 1.5 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + *  Abstract interface for objects which can contain tasks (targets) + *  Used to check if a class can contain tasks (via instanceof) + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.5 $ $Date: 2005/10/04 19:13:44 $ + *  @access    public + *  @package   phing + */ +interface TaskContainer { + +    /** +     *  Adds a task to this task container. Must be implemented +     *  by derived class +     * +     *  @param  object  The task to be added to the container +     *  @access public +     */ +    function addTask(Task $task); +} diff --git a/buildscripts/phing/classes/phing/UnknownElement.php b/buildscripts/phing/classes/phing/UnknownElement.php new file mode 100644 index 00000000..745130dc --- /dev/null +++ b/buildscripts/phing/classes/phing/UnknownElement.php @@ -0,0 +1,211 @@ +<?php +/* + *  $Id: UnknownElement.php,v 1.9 2005/11/08 20:45:59 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Wrapper class that holds all information necessary to create a task + * that did not exist when Phing started. + * + * <em> This has something to do with phing encountering an task XML element + * it is not aware of at start time. This is a situation where special steps + * need to be taken so that the element is then known.</em> + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.9 $ + * @package   phing + */ +class UnknownElement extends Task { + +    private $elementName; +    private $realThing; +    private $children = array(); + +    /** +     * Constructs a UnknownElement object +     * +     * @param    string  The XML element name that is unknown +     * @access   public +     */ +    function __construct($elementName) { +        $this->elementName = (string) $elementName; +    } + +    /** +     * Return the XML element name that this <code>UnnownElement</code> +     * handles. +     * +     * @return  string  The XML element name that is unknown +     */ +    public function getTag() { +        return (string) $this->elementName; +    } + +    /** +     * Tries to configure the unknown element +     * +     * @throws  BuildException if the element can not be configured +     */ +    public function maybeConfigure() { +     +        $this->realThing = $this->makeObject($this, $this->wrapper); +        $this->wrapper->setProxy($this->realThing); +        if ($this->realThing instanceof Task) { +            $this->realThing->setRuntimeConfigurableWrapper($this->wrapper); +        } +     +        $this->handleChildren($this->realThing, $this->wrapper); +        $this->wrapper->maybeConfigure($this->getProject()); +                                     +    } + +    /** +     * Called when the real task has been configured for the first time. +     * +     * @throws  BuildException if the task can not be created +     */ +    public function main() { +     +        if ($this->realThing === null) { +            // plain impossible to get here, maybeConfigure should +            // have thrown an exception. +            throw new BuildException("Should not be executing UnknownElement::main() -- task/type: {$this->elementName}"); +        } +         +        if ($this->realThing instanceof Task) { +            $this->realThing->main(); +        } +         +    } + +    /** +     * Add a child element to the unknown element +     * +     * @param   object  The object representing the child element +     */ +    public function addChild(UnknownElement $child) { +        $this->children[] = $child; +    } + +    /** +     *  Handle child elemets of the unknown element, if any. +     * +     *  @param ProjectComponent The parent object the unkown element belongs to +     *  @param object The parent wrapper object +     */ +    function handleChildren(ProjectComponent $parent, $parentWrapper) { + +        if ($parent instanceof TaskAdapter) { +            $parent = $parent->getProxy(); +        } + +        $parentClass = get_class($parent); +        $ih = IntrospectionHelper::getHelper($parentClass); + +        for ($i=0, $childrenCount=count($this->children); $i < $childrenCount; $i++) { + +            $childWrapper = $parentWrapper->getChild($i); +            $child = $this->children[$i]; +            $realChild = null; +            if ($parent instanceof TaskContainer) { +                $realChild = $this->makeTask($child, $childWrapper, false); +                $parent->addTask($realChild); +            } else { +                $realChild = $ih->createElement($this->project, $parent, $child->getTag()); +            } + +            $childWrapper->setProxy($realChild); +            if ($realChild instanceof Task) { +                $realChild->setRuntimeConfigurableWrapper($childWrapper); +            } + +            $child->handleChildren($realChild, $childWrapper); +            if ($realChild instanceof Task) { +                $realChild->maybeConfigure(); +            } +        } +    } + +    /** +     * Creates a named task or data type. If the real object is a task, +     * it is configured up to the init() stage. +     * +     * @param UnknownElement $ue The unknown element to create the real object for. +     *           Must not be <code>null</code>. +     * @param RuntimeConfigurable $w  Ignored in this implementation. +     * @return object The Task or DataType represented by the given unknown element. +     */ +    protected function makeObject(UnknownElement $ue, RuntimeConfigurable $w) { +        $o = $this->makeTask($ue, $w, true); +        if ($o === null) { +            $o = $this->project->createDataType($ue->getTag()); +        } +        if ($o === null) { +            throw new BuildException("Could not create task/type: '".$ue->getTag()."'. Make sure that this class has been declared using taskdef / typedef."); +        } +        return $o; +    } +     +    /** +     *  Create a named task and configure it up to the init() stage. +     * +     * @param UnknownElement $ue The unknwon element to create a task from +     * @param RuntimeConfigurable $w The wrapper object +     * @param boolean $onTopLevel Whether to treat this task as if it is top-level. +     * @return Task The freshly created task +     */ +    protected function makeTask(UnknownElement $ue, RuntimeConfigurable $w, $onTopLevel = false) { + +        $task = $this->project->createTask($ue->getTag()); + +        if ($task === null) { +            if (!$onTopLevel) { +                throw new BuildException("Could not create task of type: '".$this->elementName."'. Make sure that this class has been declared using taskdef."); +            } +            return null;             +        } + +        // used to set the location within the xmlfile so that exceptions can +        // give detailed messages + +        $task->setLocation($this->getLocation()); +        $attrs = $w->getAttributes(); +        if (isset($attrs['id'])) { +            $this->project->addReference($attrs['id'], $task); +        } + +        // UnknownElement always has an associated target +        $task->setOwningTarget($this->target); + +        $task->init(); +        return $task; +    } + +    /** +     *  Get the name of the task to use in logging messages. +     * +     *  @return  string  The task's name +     */ +    function getTaskName() { +        return $this->realThing === null ? parent::getTaskName() : $this->realThing->getTaskName(); +    } +} diff --git a/buildscripts/phing/classes/phing/filters/BaseFilterReader.php b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php new file mode 100644 index 00000000..c9f8c619 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php @@ -0,0 +1,157 @@ +<?php + +/* + *  $Id: BaseFilterReader.php,v 1.8 2004/05/20 02:24:10 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/system/io/FilterReader.php'; +include_once 'phing/system/io/StringReader.php'; + + +/** + * Base class for core filter readers. + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @version   $Revision: 1.8 $ $Date: 2004/05/20 02:24:10 $ + * @access    public + * @see       FilterReader + * @package   phing.filters + */ +class BaseFilterReader extends FilterReader { +     +    /** Have the parameters passed been interpreted? */ +    protected $initialized = false; +     +    /** The Phing project this filter is part of. */ +    protected $project = null; + +    /** +     * Constructor used by Phing's introspection mechanism. +     * The original filter reader is only used for chaining +     * purposes, never for filtering purposes (and indeed +     * it would be useless for filtering purposes, as it has +     * no real data to filter). ChainedReaderHelper uses +     * this placeholder instance to create a chain of real filters. +     *  +     * @param Reader $in +     */ +    function __construct($in = null) { +        if ($in === null) { +            $dummy = ""; +            $in = new StringReader($dummy); +        } +        parent::__construct($in); +    } + +    /** +     * Returns the initialized status. +     *  +     * @return boolean whether or not the filter is initialized +     */ +    function getInitialized() { +        return $this->initialized; +    } + +    /** +     * Sets the initialized status. +     *  +     * @param boolean $initialized Whether or not the filter is initialized. +     */ +    function setInitialized($initialized) { +        $this->initialized = (boolean) $initialized; +    } + +    /** +     * Sets the project to work with. +     *  +     * @param object $project The project this filter is part of.  +     *                Should not be <code>null</code>. +     */ +    function setProject(Project $project) { +        // type check, error must never occur, bad code of it does       +        $this->project = $project; +    } + +    /** +     * Returns the project this filter is part of. +     *  +     * @return object The project this filter is part of +     */ +    function getProject() { +        return $this->project; +    } + +    /** +     * Reads characters. +     * +     * @param  off  Offset at which to start storing characters. +     * @param  len  Maximum number of characters to read. +     * +     * @return Characters read, or -1 if the end of the stream +     *         has been reached +     * +     * @throws IOException If an I/O error occurs +     */ +    function read($len = null) { +        return $this->in->read($len); +    } + +    /** +     * Reads a line of text ending with '\n' (or until the end of the stream). +     * The returned String retains the '\n'. +     *  +     * @return the line read, or <code>null</code> if the end of the +               stream has already been reached +     *  +     * @throws IOException if the underlying reader throws one during  +     *                        reading +     */ +    function readLine() { +        $line = null; + +        while ( ($ch = $this->in->read(1)) !== -1 ) { +            $line .= $ch; +            if ( $ch === "\n" ) +                break; +        } + +        return $line; +    } +     +    /** +     * Returns whether the end of file has been reached with input stream. +     * @return boolean +     */  +    function eof() { +        return $this->in->eof(); +    } +     +    /** +     * Convenience method to support logging in filters. +     * @param string $msg Message to log. +     * @param int $level Priority level. +     */ +    function log($msg, $level = PROJECT_MSG_INFO) { +        if ($this->project !== null) { +            $this->project->log("[filter:".get_class($this)."] ".$msg, $level);     +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php new file mode 100644 index 00000000..3d767b40 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php @@ -0,0 +1,69 @@ +<?php + +/* + *  $Id: BaseParamFilterReader.php,v 1.5 2005/02/27 20:52:08 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/types/Parameterizable.php'; +include_once 'phing/types/Parameter.php'; + +/** + * Base class for core filter readers. + * + * @author <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @copyright © 2003 seasonfive. All rights reserved + * @version   $Revision: 1.5 $ $Date: 2005/02/27 20:52:08 $ + * @access    public + * @see       FilterReader + * @package   phing.filters + */ +class BaseParamFilterReader extends BaseFilterReader implements Parameterizable { +     +    /** The passed in parameter array. */ +    protected $_parameters = array(); +     +    /* +     * Sets the parameters used by this filter, and sets +     * the filter to an uninitialized status. +     *  +     * @param array Array of parameters to be used by this filter. +     *              Should not be <code>null</code>. +    */ +    function setParameters($parameters) { +        // type check, error must never occur, bad code of it does +        if ( !is_array($parameters) ) { +            throw new Exception("Expected parameters array got something else");             +        } + +        $this->_parameters = $parameters; +        $this->setInitialized(false); +    } + +    /* +     * Returns the parameters to be used by this filter. +     *  +     * @return the parameters to be used by this filter +    */ +    function &getParameters() { +        return $this->_parameters; +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ChainableReader.php b/buildscripts/phing/classes/phing/filters/ChainableReader.php new file mode 100644 index 00000000..c7de07c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ChainableReader.php @@ -0,0 +1,42 @@ +<?php + +/* + *  $Id: ChainableReader.php,v 1.2 2003/11/19 05:48:27 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +/** + * Interface indicating that a reader may be chained to another one. + * + * @author Magesh Umasankar + */ +interface ChainableReader { + +    /** +     * Returns a reader with the same configuration as this one, +     * but filtering input from the specified reader. +     *  +     * @param Reader $rdr the reader which the returned reader should be filtering +     *  +     * @return Reader A reader with the same configuration as this one, but +     *         filtering input from the specified reader +     */ +    public function chain(Reader $rdr); +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ExpandProperties.php b/buildscripts/phing/classes/phing/filters/ExpandProperties.php new file mode 100644 index 00000000..dfd98cc8 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ExpandProperties.php @@ -0,0 +1,82 @@ +<?php + +/* + *  $Id: ExpandProperties.php,v 1.6 2004/07/14 17:14:15 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Expands Phing Properties, if any, in the data. + * <p> + * Example:<br> + * <pre><expandproperties/></pre> + * Or: + * <pre><filterreader classname="phing.filters.ExpandProperties'/></pre> + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.6 $ + * @see       BaseFilterReader + * @package   phing.filters + */ +class ExpandProperties extends BaseFilterReader implements ChainableReader { +    +    /** +     * Returns the filtered stream.  +     * The original stream is first read in fully, and the Phing properties are expanded. +     *  +     * @return mixed     the filtered stream, or -1 if the end of the resulting stream has been reached. +     *  +     * @exception IOException if the underlying stream throws an IOException +     * during reading +     */ +    function read($len = null) { +                 +        $buffer = $this->in->read($len); +         +        if($buffer === -1) { +            return -1; +        } +         +        $project = $this->getProject(); +        $buffer = ProjectConfigurator::replaceProperties($project, $buffer, $project->getProperties()); +         +        return $buffer; +    } +         +    /** +     * Creates a new ExpandProperties filter using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new ExpandProperties($reader); +        $newFilter->setProject($this->getProject()); +        return $newFilter; +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/HeadFilter.php b/buildscripts/phing/classes/phing/filters/HeadFilter.php new file mode 100644 index 00000000..84673b4a --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/HeadFilter.php @@ -0,0 +1,161 @@ +<?php + +/* + *  $Id: HeadFilter.php,v 1.6 2004/03/15 14:45:06 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Reads the first <code>n</code> lines of a stream. + * (Default is first 10 lines.) + * <p> + * Example: + * <pre><headfilter lines="3"/></pre> + * Or: + * <pre><filterreader classname="phing.filters.HeadFilter"> + *    <param name="lines" value="3"/> + * </filterreader></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @access    public + * @see       FilterReader + * @package   phing.filters + */ +class HeadFilter extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Parameter name for the number of lines to be returned. +     */  +    const LINES_KEY = "lines"; +     +    /** +     * Number of lines currently read in. +     * @var integer +     */  +    private $_linesRead = 0; +     +    /** +     * Number of lines to be returned in the filtered stream. +     * @var integer +     */  +    private $_lines     = 10; + +    /** +     * Returns first n lines of stream. +     * @return the resulting stream, or -1 +     * if the end of the resulting stream has been reached +     *  +     * @exception IOException if the underlying stream throws an IOException +     * during reading      +     */ +    function read($len = null) { +     +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        // note, if buffer contains fewer lines than +        // $this->_lines this code will not work. +         +        if($this->_linesRead < $this->_lines) { +         +            $buffer = $this->in->read($len); +             +            if($buffer === -1) { +                return -1; +            } +             +            // now grab first X lines from buffer +             +            $lines = explode("\n", $buffer); +             +            $linesCount = count($lines); +             +            // must account for possibility that the num lines requested could  +            // involve more than one buffer read.             +            $len = ($linesCount > $this->_lines ? $this->_lines - $this->_linesRead : $linesCount); +            $filtered_buffer = implode("\n", array_slice($lines, 0, $len) ); +            $this->_linesRead += $len; +             +            return $filtered_buffer; +         +        } +         +        return -1; // EOF, since the file is "finished" as far as subsequent filters are concerned. +    }     + +    /** +     * Sets the number of lines to be returned in the filtered stream. +     *  +     * @param integer $lines the number of lines to be returned in the filtered stream. +     */ +    function setLines($lines) { +        $this->_lines = (int) $lines; +    } + +    /** +     * Returns the number of lines to be returned in the filtered stream. +     *  +     * @return integer The number of lines to be returned in the filtered stream. +     */ +    function getLines() { +        return $this->_lines; +    } + +    /** +     * Creates a new HeadFilter using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *            Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader. +     */ +    function chain(Reader $reader) { +        $newFilter = new HeadFilter($reader); +        $newFilter->setLines($this->getLines()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Scans the parameters list for the "lines" parameter and uses +     * it to set the number of lines to be returned in the filtered stream. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0, $_i=count($params) ; $i < $_i; $i++) { +                if ( self::LINES_KEY == $params[$i]->getName() ) { +                    $this->_lines = (int) $params[$i]->getValue(); +                    break; +                } +            } +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/LineContains.php b/buildscripts/phing/classes/phing/filters/LineContains.php new file mode 100644 index 00000000..8f3136b7 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/LineContains.php @@ -0,0 +1,258 @@ +<?php + +/* + *  $Id: LineContains.php,v 1.11 2005/02/27 20:52:08 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter which includes only those lines that contain all the user-specified + * strings. + * + * Example: + * + * <pre><linecontains> + *   <contains value="foo"> + *   <contains value="bar"> + * </linecontains></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.LineContains"> + *    <param type="contains" value="foo"/> + *    <param type="contains" value="bar"/> + * </filterreader></pre> + * + * This will include only those lines that contain <code>foo</code> and + * <code>bar</code>. + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @author    Hans Lellelid <hans@velum.net> + * @version   $Revision: 1.11 $ + * @see       PhingFilterReader + * @package   phing.filters +*/ +class LineContains extends BaseParamFilterReader implements ChainableReader { + +    /** +     * The parameter name for the string to match on. +     * @var string +     */  +    const CONTAINS_KEY = "contains"; + +    /** +     * Array of Contains objects. +     * @var array +     */  +    private $_contains = array(); + +    /** +     * [Deprecated]  +     * @var string +     */  +    private $_line = null; + +    /** +     * Returns all lines in a buffer that contain specified strings. +     * @return mixed buffer, -1 on EOF +     */ +    function read($len = null) { +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        $buffer = $this->in->read($len); +         +        if ($buffer === -1) { +            return -1; +        } +         +        $lines = explode("\n", $buffer);         +        $matched = array();         +        $containsSize = count($this->_contains); +         +        foreach($lines as $line) {                                 +            for($i = 0 ; $i < $containsSize ; $i++) { +                $containsStr = $this->_contains[$i]->getValue(); +                if ( strstr($line, $containsStr) === false ) { +                    $line = null; +                    break; +                } +            }                 +            if($line !== null) { +                $matched[] = $line; +            }                 +        }         +        $filtered_buffer = implode("\n", $matched);     +        return $filtered_buffer; +    } +     +    /** +     * [Deprecated. For reference only, used to be read() method.]  +     * Returns the next character in the filtered stream, only including +     * lines from the original stream which contain all of the specified words. +     * +     * @return the next character in the resulting stream, or -1 +     * if the end of the resulting stream has been reached +     * +     * @exception IOException if the underlying stream throws an IOException +     * during reading +     */ +    function readChar() { +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } + +        $ch = -1; + +        if ( $this->_line !== null ) { +            $ch = substr($this->_line, 0, 1); +            if ( strlen($this->_line) === 1 ) +                $this->_line = null; +            else +                $this->_line = substr($this->_line, 1); +        } else { +            $this->_line = $this->readLine(); +            if ( $this->_line === null ) { +                $ch = -1; +            } else { +                $containsSize = count($this->_contains); +                for($i = 0 ; $i < $containsSize ; $i++) { +                    $containsStr = $this->_contains[$i]->getValue(); +                    if ( strstr($this->_line, $containsStr) === false ) { +                        $this->_line = null; +                        break; +                    } +                } +                return $this->readChar(); +            } +        } + +        return $ch; +    } + +    /** +     * Adds a <code><contains></code> nested element. +     * +     * @return Contains The <code>contains</code> element added. +     *                  Must not be <code>null</code>. +     */ +    function createContains() { +        $num = array_push($this->_contains, new Contains()); +        return $this->_contains[$num-1]; +    } + +    /** +     * Sets the array of words which must be contained within a line read +     * from the original stream in order for it to match this filter. +     * +     * @param array $contains An array of words which must be contained +     *                 within a line in order for it to match in this filter. +     *                 Must not be <code>null<code>. +     */ +    function setContains($contains) { +        // type check, error must never occur, bad code of it does +        if ( !is_array($contains) ) { +            throw new Exception("Excpected array got something else"); +        } + +        $this->_contains = $contains; +    } + +    /** +     * Returns the vector of words which must be contained within a line read +     * from the original stream in order for it to match this filter. +     * +     * @return array The array of words which must be contained within a line read +     *         from the original stream in order for it to match this filter. The +     *         returned object is "live" - in other words, changes made to the +     *         returned object are mirrored in the filter. +     */ +    function getContains() { +        return $this->_contains; +    } + +    /** +     * Creates a new LineContains using the passed in +     * Reader for instantiation. +     * +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     * +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new LineContains($reader); +        $newFilter->setContains($this->getContains()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Parses the parameters to add user-defined contains strings. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            foreach($params as $param) { +                if ( self::CONTAINS_KEY == $param->getType() ) { +                    $cont = new Contains(); +                    $cont->setValue($param->getValue()); +                    array_push($this->_contains, $cont); +                    break; // because we only support a single contains +                } +            } +        } +    } +} + +/** + * Holds a contains element. + */ +class Contains { + +    /** +     * @var string +     */  +    private $_value; +     +    /** +     * Set 'contains' value. +     * @param string $contains +     */  +    function setValue($contains) { +        $this->_value = (string) $contains; +    } +     +    /** +     * Returns 'contains' value. +     * @return string +     */  +    function getValue() { +        return $this->_value; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php new file mode 100644 index 00000000..dcbb532c --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php @@ -0,0 +1,179 @@ +<?php +/* + *  $Id: LineContainsRegexp.php,v 1.8 2005/02/27 20:52:08 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/types/RegularExpression.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter which includes only those lines that contain the user-specified + * regular expression matching strings. + * + * Example: + * <pre><linecontainsregexp> + *   <regexp pattern="foo*"> + * </linecontainsregexp></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.LineContainsRegExp"> + *    <param type="regexp" value="foo*"/> + * </filterreader></pre> + * + * This will fetch all those lines that contain the pattern <code>foo</code> + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.8 $ + * @see       FilterReader + * @package   phing.filters + */ +class LineContainsRegexp extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Parameter name for regular expression. +     * @var string +     */  +    const REGEXP_KEY = "regexp"; +     +    /** +     * Regular expressions that are applied against lines. +     * @var array +     */  +    private    $_regexps = array(); +         +    /** +     * Returns all lines in a buffer that contain specified strings. +     * @return mixed buffer, -1 on EOF +     */ +    function read($len = null) { +     +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        $buffer = $this->in->read($len); +         +        if ($buffer === -1) { +            return -1; +        } +         +        $lines = explode("\n", $buffer);         +        $matched = array();         +         +        $regexpsSize = count($this->_regexps); +        foreach($lines as $line) {     +             for($i = 0 ; $i<$regexpsSize ; $i++) { +                    $regexp = $this->_regexps[$i]; +                    $re = $regexp->getRegexp($this->getProject()); +                    $matches = $re->matches($line); +                    if ( !$matches ) { +                        $line = null; +                        break; +                    } +            }             +            if($line !== null) { +                $matched[] = $line; +            }                 +        }         +        $filtered_buffer = implode("\n", $matched);     +        return $filtered_buffer; +    } +     +    /** +     * Adds a <code>regexp</code> element. +     *  +     * @return object regExp The <code>regexp</code> element added.  +     */ +    function createRegexp() { +        $num = array_push($this->_regexps, new RegularExpression()); +        return $this->_regexps[$num-1]; +    } + +    /** +     * Sets the vector of regular expressions which must be contained within  +     * a line read from the original stream in order for it to match this  +     * filter. +     *  +     * @param regexps An array of regular expressions which must be contained  +     *                within a line in order for it to match in this filter. Must not be  +     *                <code>null</code>. +     */ +    function setRegexps($regexps) { +        // type check, error must never occur, bad code of it does +        if ( !is_array($regexps) ) { +            throw new Exception("Excpected an 'array', got something else"); +        } +        $this->_regexps = $regexps; +    } + +    /** +     * Returns the array of regular expressions which must be contained within  +     * a line read from the original stream in order for it to match this  +     * filter. +     *  +     * @return array The array of regular expressions which must be contained within  +     *         a line read from the original stream in order for it to match this  +     *         filter. The returned object is "live" - in other words, changes made to  +     *         the returned object are mirrored in the filter. +     */ +    function getRegexps() { +        return $this->_regexps; +    } + +    /** +     * Creates a new LineContainsRegExp using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new LineContainsRegExp($reader); +        $newFilter->setRegexps($this->getRegexps()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Parses parameters to add user defined regular expressions. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0 ; $i<count($params) ; $i++) { +                if ( self::REGEXP_KEY === $params[$i]->getType() ) { +                    $pattern = $params[$i]->getValue(); +                    $regexp = new RegularExpression(); +                    $regexp->setPattern($pattern); +                    array_push($this->_regexps, $regexp); +                } +            } +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/PrefixLines.php b/buildscripts/phing/classes/phing/filters/PrefixLines.php new file mode 100644 index 00000000..a5580f87 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/PrefixLines.php @@ -0,0 +1,142 @@ +<?php + +/* + *  $Id: PrefixLines.php,v 1.6 2004/03/15 14:45:06 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Attaches a prefix to every line. + * + * Example: + * <pre><prefixlines prefix="Foo"/></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.PrefixLines"> + *  <param name="prefix" value="Foo"/> + * </filterreader></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @access    public + * @see       FilterReader + * @package   phing.filters +*/ +class PrefixLines extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Parameter name for the prefix. +     * @var string +     */  +    const PREFIX_KEY = "lines"; +     +    /** +     * The prefix to be used. +     * @var string +     */  +    private    $_prefix = null; +  +    /** +     * Adds a prefix to each line of input stream and returns resulting stream. +     *  +     * @return mixed buffer, -1 on EOF +     */ +    function read($len = null) { +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        $buffer = $this->in->read($len); +         +        if ($buffer === -1) { +            return -1; +        } +         +        $lines = explode("\n", $buffer);         +        $filtered = array();         +         +        foreach($lines as $line) { +            $line = $this->_prefix . $line; +            $filtered[] = $line; +        } +                 +        $filtered_buffer = implode("\n", $filtered);     +        return $filtered_buffer; +    } +     +    /** +     * Sets the prefix to add at the start of each input line. +     *  +     * @param string $prefix The prefix to add at the start of each input line. +     *               May be <code>null</code>, in which case no prefix +     *               is added. +     */ +    function setPrefix($prefix) { +        $this->_prefix = (string) $prefix; +    } + +    /** +     * Returns the prefix which will be added at the start of each input line. +     *  +     * @return string The prefix which will be added at the start of each input line +     */ +    function getPrefix() { +        return $this->_prefix; +    } + +    /** +     * Creates a new PrefixLines filter using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) {   +        $newFilter = new PrefixLines($reader); +        $newFilter->setPrefix($this->getPrefix()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Initializes the prefix if it is available from the parameters. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0, $_i=count($params) ; $i < $_i ; $i++) { +                if ( self::PREFIX_KEY == $params[$i]->getName() ) { +                    $this->_prefix = (string) $params[$i]->getValue(); +                    break; +                } +            } +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php new file mode 100644 index 00000000..3c5592e8 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php @@ -0,0 +1,129 @@ +<?php + +/* + *  $Id: ReplaceRegexp.php,v 1.5 2003/12/24 12:38:39 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; +include_once 'phing/types/RegularExpression.php'; + +/** + * Performs a regexp find/replace on stream. + * <p> + * Example:<br> + * <pre> + * <replaceregexp> + *    <regexp pattern="\r\n" replace="\n"/> + *    <regexp pattern="(\w+)\.xml" replace="\1.php" ignoreCase="true"/> + * </replaceregexp> + * </pre> + * + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.5 $ + * @package   phing.filters + */ +class ReplaceRegexp extends BaseFilterReader implements ChainableReader { +     +    /** +     * @var array RegularExpression[] +     */ +    private $regexps = array();             +     +    /** +     * Creator method handles nested <regexp> tags. +     * @return RegularExpression +     */ +    function createRegexp() { +        $num = array_push($this->regexps, new RegularExpression()); +        return $this->regexps[$num-1]; +    } +     +    /** +     * Sets the current regexps. +     * (Used when, e.g., cloning/chaining the method.) +     * @param array RegularExpression[] +     */ +    function setRegexps($regexps) { +        $this->regexps = $regexps; +    } +     +    /** +     * Gets the current regexps. +     * (Used when, e.g., cloning/chaining the method.) +     * @return array RegularExpression[] +     */     +    function getRegexps() { +        return $this->regexps; +    } +     +    /** +     * Returns the filtered stream.  +     * The original stream is first read in fully, and the regex replace is performed. +     *  +     * @param int $len Required $len for Reader compliance. +     *  +     * @return mixed The filtered stream, or -1 if the end of the resulting stream has been reached. +     *  +     * @exception IOException if the underlying stream throws an IOException +     * during reading +     */ +    function read($len = null) { +                 +        $buffer = $this->in->read($len); +         +        if($buffer === -1) { +            return -1; +        } + +        // perform regex replace here ... +        foreach($this->regexps as $exptype) { +            $regexp = $exptype->getRegexp($this->project); +            try { +                $buffer = $regexp->replace($buffer); +                $this->log("Performing regexp replace: /".$regexp->getPattern()."/".$regexp->getReplace()."/g".($regexp->getIgnoreCase() ? 'i' : ''), PROJECT_MSG_VERBOSE); +            } catch (Exception $e) { +                // perhaps mismatch in params (e.g. no replace or pattern specified) +                $this->log("Error performing regexp replace: " . $e->getMessage(), PROJECT_MSG_WARN); +            } +        } +         +        return $buffer; +    } + +    /** +     * Creates a new ReplaceRegExp filter using the passed in +     * Reader for instantiation. +     *  +     * @param Reader $reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return ReplaceRegExp A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new ReplaceRegExp($reader); +        $newFilter->setProject($this->getProject()); +        $newFilter->setRegexps($this->getRegexps()); +        return $newFilter; +    } + +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/ReplaceTokens.php b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php new file mode 100644 index 00000000..999f734f --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php @@ -0,0 +1,415 @@ +<?php + +/* + *  $Id: ReplaceTokens.php,v 1.14 2005/06/16 15:09:10 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/types/TokenSource.php'; +include_once 'phing/filters/ChainableReader.php'; + +/* + * Replaces tokens in the original input with user-supplied values. + * + * Example: + * + * <pre><replacetokens begintoken="#" endtoken="#">; + *   <token key="DATE" value="${TODAY}"/> + * </replacetokens></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.ReplaceTokens"> + *   <param type="tokenchar" name="begintoken" value="#"/> + *   <param type="tokenchar" name="endtoken" value="#"/> + *   <param type="token" name="DATE" value="${TODAY}"/> + * </filterreader></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.14 $ $Date: 2005/06/16 15:09:10 $ + * @access    public + * @see       BaseParamFilterReader + * @package   phing.filters + */ +class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Default "begin token" character. +     * @var string +     */ +    const DEFAULT_BEGIN_TOKEN = "@"; + +    /** +     * Default "end token" character. +     * @var string +     */ +    const DEFAULT_END_TOKEN = "@"; + +    /** +     * [Deprecated] Data that must be read from, if not null. +     * @var string +     */ +    private    $_queuedData = null; + +    /** +     * Array to hold the replacee-replacer pairs (String to String). +     * @var array +     */ +    private $_tokens = array(); + +    /** +     * Array to hold the token sources that make tokens from +     * different sources available +     * @var array +     */ +    private $_tokensources = array(); + +    /** +     * Array holding all tokens given directly to the Filter and +     * those passed via a TokenSource. +     * @var array +     */ +    private $_alltokens = null; + +    /** +     * Character marking the beginning of a token. +     * @var string +     */ +    private    $_beginToken = "@";  // self::DEFAULT_BEGIN_TOKEN; + +    /** +     * Character marking the end of a token. +     * @var string +     */ +    private    $_endToken = "@"; //self::DEFAULT_END_TOKEN; + +    /** +     * Performs lookup on key and returns appropriate replacement string. +     * @param array $matches Array of 1 el containing key to search for. +     * @return string     Text with which to replace key or value of key if none is found. +     * @access private +     */ +    private function replaceTokenCallback($matches) { +                 +        $key = $matches[1]; +         +        /* Get tokens from tokensource and merge them with the +         * tokens given directly via build file. This should be  +         * done a bit more elegantly +         */ +        if ($this->_alltokens === null) { +            $this->_alltokens = array(); + +            $count = count($this->_tokensources); +            for ($i = 0; $i < $count; $i++) { +                $source = $this->_tokensources[$i]; +                $this->_alltokens = array_merge($this->_alltokens, $source->getTokens()); +            } + + +            $this->_alltokens = array_merge($this->_tokens, $this->_alltokens); +        } + +        $tokens = $this->_alltokens; + +        $replaceWith = null; +        $count = count($tokens); + +        for ($i = 0; $i < $count; $i++) { +            if ($tokens[$i]->getKey() === $key) { +                $replaceWith = $tokens[$i]->getValue(); +            } +        } + +        if ($replaceWith === null) { +            $replaceWith = $this->_beginToken . $key . $this->_endToken;             +            $this->log("No token defined for key \"".$this->_beginToken  . $key . $this->_endToken."\""); +        } else { +            $this->log("Replaced \"".$this->_beginToken  . $key . $this->_endToken ."\" with \"".$replaceWith."\""); +        } + +        return $replaceWith; +    } + +    /** +     * Returns stream with tokens having been replaced with appropriate values. +     * If a replacement value is not found for a token, the token is left in the stream. +     *  +     * @return mixed filtered stream, -1 on EOF. +     */ +    function read($len = null) { +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } + +        // read from next filter up the chain +        $buffer = $this->in->read($len); + +        if($buffer === -1) { +            return -1; +        }     +         +        // filter buffer +        $buffer = preg_replace_callback( +            "/".preg_quote($this->_beginToken)."([\w\.\-:]+?)".preg_quote($this->_endToken)."/", +            array($this, 'replaceTokenCallback'), $buffer); + +        return $buffer; +    } +    +    /** +     * Sets the "begin token" character. +     *  +     * @param string $beginToken the character used to denote the beginning of a token. +     */ +    function setBeginToken($beginToken) { +        $this->_beginToken = (string) $beginToken; +    } + +    /** +     * Returns the "begin token" character. +     *  +     * @return string The character used to denote the beginning of a token. +     */ +    function getBeginToken() { +        return $this->_beginToken; +    } + +    /** +     * Sets the "end token" character. +     *  +     * @param string $endToken the character used to denote the end of a token +     */ +    function setEndToken($endToken) { +        $this->_endToken = (string) $endToken; +    } + +    /** +     * Returns the "end token" character. +     *  +     * @return the character used to denote the beginning of a token +     */ +    function getEndToken() { +        return $this->_endToken; +    } + +    /** +     * Adds a token element to the map of tokens to replace. +     *  +     * @return object The token added to the map of replacements. +     *               Must not be <code>null</code>. +     */ +    function createToken() { +        $num = array_push($this->_tokens, new Token()); +        return $this->_tokens[$num-1]; +    } +     +    /** +     * Adds a token source to the sources of this filter. +     * +     * @return  object  A Reference to the source just added. +     */ +    function createTokensource() { +        $num = array_push($this->_tokensources, new TokenSource()); +        return $this->_tokensources[$num-1]; +    } + +    /** +     * Sets the map of tokens to replace. +     * ; used by ReplaceTokens::chain() +     * +     * @param array A map (String->String) of token keys to replacement +     *              values. Must not be <code>null</code>. +     */ +    function setTokens($tokens) { +        // type check, error must never occur, bad code of it does +        if ( !is_array($tokens) ) { +            throw new Exception("Excpected 'array', got something else"); +        } + +        $this->_tokens = $tokens; +    } + +    /** +     * Returns the map of tokens which will be replaced. +     * ; used by ReplaceTokens::chain() +     * +     * @return array A map (String->String) of token keys to replacement values. +     */ +    function getTokens() { +        return $this->_tokens; +    } + +    /** +     * Sets the tokensources to use; used by ReplaceTokens::chain() +     *  +     * @param   array   An array of token sources. +     */  +    function setTokensources($sources) { +        // type check +        if ( !is_array($sources)) { +            throw new Exception("Exspected 'array', got something else"); +        } +        $this->_tokensources = $sources; +    } + +    /** +     * Returns the token sources used by this filter; used by ReplaceTokens::chain() +     *  +     * @return  array +     */ +    function getTokensources() { +        return $this->_tokensources; +    } + +    /** +     * Creates a new ReplaceTokens using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new ReplaceTokens($reader); +        $newFilter->setProject($this->getProject()); +        $newFilter->setBeginToken($this->getBeginToken()); +        $newFilter->setEndToken($this->getEndToken()); +        $newFilter->setTokens($this->getTokens()); +        $newFilter->setTokensources($this->getTokensources()); +        $newFilter->setInitialized(true); +        return $newFilter; +    } + +    /** +     * Initializes tokens and loads the replacee-replacer hashtable. +     * This method is only called when this filter is used through +     * a <filterreader> tag in build file. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0 ; $i<count($params) ; $i++) { +                if ( $params[$i] !== null ) { +                    $type = $params[$i]->getType(); +                    if ( $type === "tokenchar" ) { +                        $name = $params[$i]->getName(); +                        if ( $name === "begintoken" ) { +                            $this->_beginToken = substr($params[$i]->getValue(), 0, 1); +                        } else if ( $name === "endtoken" ) { +                            $this->_endToken = substr($params[$i]->getValue(), 0, 1); +                        } +                    } else if ( $type === "token" ) { +                        $name  = $params[$i]->getName(); +                        $value = $params[$i]->getValue(); + +                        $tok = new Token(); +                        $tok->setKey($name); +                        $tok->setValue($value); + +                        array_push($this->_tokens, $tok); +                    } else if ( $type === "tokensource" ) { +                        // Store data from nested tags in local array +                        $arr = array(); $subparams = $params[$i]->getParams(); +                        $count = count($subparams); +                        for ($i = 0; $i < $count; $i++)  { +                            $arr[$subparams[$i]->getName()] = $subparams[$i]->getValue(); +                        } + +                        // Create TokenSource +                        $tokensource = new TokenSource(); +                        if (isset($arr["classname"]))  +                            $tokensource->setClassname($arr["classname"]); + +                        // Copy other parameters 1:1 to freshly created TokenSource +                        foreach ($arr as $key => $value) { +                            if (strtolower($key) === "classname") +                                continue; +                            $param = $tokensource->createParam(); +                            $param->setName($key); +                            $param->setValue($value); +                        } + +                        $this->_tokensources[] = $tokensource; +                    } +                } +            } +        } +    } +} + +/** + * Holds a token. + */ +class Token { + +    /** +     * Token key. +     * @var string +     */ +    private $_key; + +    /** +     * Token value. +     * @var string +     */ +    private $_value; + +    /** +     * Sets the token key. +     *  +     * @param string $key The key for this token. Must not be <code>null</code>. +     */ +    function setKey($key) { +        $this->_key = (string) $key; +    } + +    /** +     * Sets the token value. +     *  +     * @param string $value The value for this token. Must not be <code>null</code>. +     */ +    function setValue($value) { +        $this->_value = (string) $value; +    } + +    /** +     * Returns the key for this token. +     *  +     * @return string The key for this token. +     */ +    function getKey() { +        return $this->_key; +    } + +    /** +     * Returns the value for this token. +     *  +     * @return string The value for this token. +     */ +    function getValue() { +        return $this->_value; +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/StripLineBreaks.php b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php new file mode 100644 index 00000000..c5a06129 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php @@ -0,0 +1,148 @@ +<?php + +/* + *  $Id: StripLineBreaks.php,v 1.8 2004/03/15 14:45:06 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Filter to flatten the stream to a single line. + *  + * Example: + * + * <pre><striplinebreaks/></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.StripLineBreaks"/></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.8 $ $Date: 2004/03/15 14:45:06 $ + * @access    public + * @see       BaseParamFilterReader + * @package   phing.filters + */ +class StripLineBreaks extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Default line-breaking characters. +     * @var string +     */ +    const DEFAULT_LINE_BREAKS = "\r\n"; +     +    /** +     * Parameter name for the line-breaking characters parameter. +     * @var string +     */ +    const LINES_BREAKS_KEY = "linebreaks"; +     +    /** +     * The characters that are recognized as line breaks. +     * @var string +     */  +    private    $_lineBreaks = "\r\n"; // self::DEFAULT_LINE_BREAKS; +  +    /** +     * Returns the filtered stream, only including +     * characters not in the set of line-breaking characters. +     *  +     * @return mixed    the resulting stream, or -1 +     *         if the end of the resulting stream has been reached. +     *  +     * @exception IOException if the underlying stream throws an IOException +     *            during reading      +     */ +    function read($len = null) { +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } + +        $buffer = $this->in->read($len); +        if($buffer === -1) { +            return -1; +        } +         +        $buffer = preg_replace("/[".$this->_lineBreaks."]/", '', $buffer);            + +        return $buffer; +    } +     +     /** +     * Sets the line-breaking characters. +     *  +     * @param string $lineBreaks A String containing all the characters to be +     *                   considered as line-breaking. +     */ +    function setLineBreaks($lineBreaks) { +        $this->_lineBreaks = (string) $lineBreaks; +    } + +    /** +     * Gets the line-breaking characters. +     *  +     * @return string A String containing all the characters that are considered as line-breaking. +     */  +    function getLineBreaks() { +        return $this->_lineBreaks; +    } + +    /** +     * Creates a new StripLineBreaks using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new StripLineBreaks($reader); +        $newFilter->setLineBreaks($this->getLineBreaks()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Parses the parameters to set the line-breaking characters. +     */ +    private function _initialize() { +        $userDefinedLineBreaks = null; +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0 ; $i<count($params) ; $i++) { +                if ( self::LINE_BREAKS_KEY === $params[$i]->getName() ) { +                    $userDefinedLineBreaks = $params[$i]->getValue(); +                    break; +                } +            } +        } + +        if ( $userDefinedLineBreaks !== null ) { +            $this->_lineBreaks = $userDefinedLineBreaks; +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/StripLineComments.php b/buildscripts/phing/classes/phing/filters/StripLineComments.php new file mode 100644 index 00000000..5d97979a --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripLineComments.php @@ -0,0 +1,205 @@ +<?php + +/* + *  $Id: StripLineComments.php,v 1.8 2005/02/27 20:52:08 mrook Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/* + * This filter strips line comments. + * + * Example: + * + * <pre><striplinecomments> + *   <comment value="#"/> + *   <comment value="--"/> + *   <comment value="REM "/> + *   <comment value="rem "/> + *   <comment value="//"/> + * </striplinecomments></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.StripLineComments"> + *   <param type="comment" value="#"/> + *   <param type="comment" value="--"/> + *   <param type="comment" value="REM "/> + *   <param type="comment" value="rem "/> + *   <param type="comment" value="//"/> + * </filterreader></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.8 $ $Date: 2005/02/27 20:52:08 $ + * @access    public + * @see       BaseParamFilterReader + * @package   phing.filters + */ +class StripLineComments extends BaseParamFilterReader implements ChainableReader { +     +    /** Parameter name for the comment prefix. */ +    const COMMENTS_KEY = "comment"; +     +    /** Array that holds the comment prefixes. */ +    private $_comments = array(); +     +    /** +     * Returns stream only including +     * lines from the original stream which don't start with any of the  +     * specified comment prefixes. +     *  +     * @return mixed the resulting stream, or -1 +     *         if the end of the resulting stream has been reached. +     *  +     * @throws IOException if the underlying stream throws an IOException +     *            during reading      +     */ +    function read($len = null) { +     +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        $buffer = $this->in->read($len); +         +        if ($buffer === -1) { +            return -1; +        } +         +        $lines = explode("\n", $buffer);         +        $filtered = array();     +             +        $commentsSize = count($this->_comments); +         +        foreach($lines as $line) {             +            for($i = 0; $i < $commentsSize; $i++) { +                $comment = $this->_comments[$i]->getValue(); +                if ( StringHelper::startsWith($comment, ltrim($line)) ) { +                    $line = null; +                    break; +                } +            } +            if ($line !== null) { +                $filtered[] = $line; +            } +        } +                 +        $filtered_buffer = implode("\n", $filtered);     +        return $filtered_buffer; +    }         + +    /* +     * Adds a <code>comment</code> element to the list of prefixes. +     *  +     * @return comment The <code>comment</code> element added to the +     *                 list of comment prefixes to strip. +    */ +    function createComment() { +        $num = array_push($this->_comments, new Comment()); +        return $this->_comments[$num-1]; +    } + +    /* +     * Sets the list of comment prefixes to strip. +     *  +     * @param comments A list of strings, each of which is a prefix +     *                 for a comment line. Must not be <code>null</code>. +    */ +    function setComments($lineBreaks) { +        if (!is_array($lineBreaks)) { +            throw new Exception("Excpected 'array', got something else"); +        } +        $this->_comments = $lineBreaks; +    } + +    /* +     * Returns the list of comment prefixes to strip. +     *  +     * @return array The list of comment prefixes to strip. +    */ +    function getComments() { +        return $this->_comments; +    } + +    /* +     * Creates a new StripLineComments using the passed in +     * Reader for instantiation. +     *  +     * @param reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return a new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new StripLineComments($reader); +        $newFilter->setComments($this->getComments()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /* +     * Parses the parameters to set the comment prefixes. +    */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0 ; $i<count($params) ; $i++) { +                if ( self::COMMENTS_KEY === $params[$i]->getType() ) { +                    $comment = new Comment(); +                    $comment->setValue($params[$i]->getValue()); +                    array_push($this->_comments, $comment); +                } +            } +        } +    } +} + +/* + * The class that holds a comment representation. +*/ +class Comment { +     +    /** The prefix for a line comment. */ +    private    $_value; + +    /* +     * Sets the prefix for this type of line comment. +     * +     * @param string $value The prefix for a line comment of this type. +     *                Must not be <code>null</code>. +     */ +    function setValue($value) { +        $this->_value = (string) $value; +    } + +    /* +     * Returns the prefix for this type of line comment. +     *  +     * @return string The prefix for this type of line comment. +    */ +    function getValue() { +        return $this->_value; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/filters/StripPhpComments.php b/buildscripts/phing/classes/phing/filters/StripPhpComments.php new file mode 100644 index 00000000..9e21eed3 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/StripPhpComments.php @@ -0,0 +1,190 @@ +<?php + +/* + *  $Id: StripPhpComments.php,v 1.6 2004/07/16 01:36:35 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * This is a Php comment and string stripper reader that filters + * those lexical tokens out for purposes of simple Php parsing. + * (if you have more complex Php parsing needs, use a real lexer). + * Since this class heavily relies on the single char read function, + * you are reccomended to make it work on top of a buffered reader. + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @version   $Revision: 1.6 $ $Date: 2004/07/16 01:36:35 $ + * @access    public + * @see       FilterReader + * @package   phing.filters + * @todo -c use new PHP functions to perform this instead of regex. + */ +class StripPhpComments extends BaseFilterReader implements ChainableReader { +    /** +     * The read-ahead character, used for effectively pushing a single +     * character back. -1 indicates that no character is in the buffer. +     */ +    private $_readAheadCh = -1; + +    /** +     * Whether or not the parser is currently in the middle of a string +     * literal. +     * @var boolean +     */ +    private $_inString = false;     + +    /** +     * Returns the  stream without Php comments. +     *  +     * @return the resulting stream, or -1 +     *         if the end of the resulting stream has been reached +     *  +     * @throws IOException if the underlying stream throws an IOException +     *                        during reading      +     */ +    function read($len = null) { +     +        $buffer = $this->in->read($len); +        if($buffer === -1) { +            return -1; +        } +         +        // This regex replace /* */ and // style comments +        $buffer = preg_replace('/\/\*[^*]*\*+([^\/*][^*]*\*+)*\/|\/\/[^\n]*|("(\\\\.|[^"\\\\])*"|\'(\\\\.|[^\'\\\\])*\'|.[^\/"\'\\\\]*)/s', "$2", $buffer); +                 +        // The regex above is not identical to, but is based on the expression below: +        // +        // created by Jeffrey Friedl +        //   and later modified by Fred Curtis. +        //     s{ +        //          /\*         ##  Start of /* ... */ comment +        //          [^*]*\*+    ##  Non-* followed by 1-or-more *'s +        //          ( +        //            [^/*][^*]*\*+ +        //          )*          ##  0-or-more things which don't start with / +        //                      ##    but do end with '*' +        //          /           ##  End of /* ... */ comment +        // +        //        |         ##     OR  various things which aren't comments: +        // +        //          ( +        //            "           ##  Start of " ... " string +        //            ( +        //              \\.           ##  Escaped char +        //            |               ##    OR +        //              [^"\\]        ##  Non "\ +        //            )* +        //           "           ##  End of " ... " string +        // +        //          |         ##     OR +        // +        //            '           ##  Start of ' ... ' string +        //            ( +        //              \\.           ##  Escaped char +        //            |               ##    OR +        //              [^'\\]        ##  Non '\ +        //            )* +        //            '           ##  End of ' ... ' string +        // +        //          |         ##     OR +        // +        //            .           ##  Anything other char +        //            [^/"'\\]*   ##  Chars which doesn't start a comment, string or escape +        //          ) +        //        }{$2}gxs; +                                 +        return $buffer; +    } +         +     +    /* +     * Returns the next character in the filtered stream, not including +     * Php comments. +     *  +     * @return the next character in the resulting stream, or -1 +     *         if the end of the resulting stream has been reached +     *  +     * @throws IOException if the underlying stream throws an IOException +     *                        during reading      +     * @deprecated +     */ +    function readChar() { +        $ch = -1; + +        if ( $this->_readAheadCh !== -1 ) { +            $ch = $this->_readAheadCh; +            $this->_readAheadCh = -1; +        } else { +            $ch = $this->in->readChar(); +            if ( $ch === "\"" ) { +                $this->_inString = !$this->_inString; +            } else { +                if ( !$this->_inString ) { +                    if ( $ch === "/" ) { +                        $ch = $this->in->readChar(); +                        if ( $ch === "/" ) { +                            while ( $ch !== "\n" && $ch !== -1 ) { +                                $ch = $this->in->readChar(); +                            } +                        } else if ( $ch === "*" ) { +                            while ( $ch !== -1 ) { +                                $ch = $this->in->readChar(); +                                while ( $ch === "*" && $ch !== -1 ) { +                                    $ch = $this->in->readChar(); +                                } + +                                if ( $ch === "/" ) { +                                    $ch = $this->readChar(); +                                    echo "$ch\n"; +                                    break; +                                } +                            } +                        } else { +                            $this->_readAheadCh = $ch; +                            $ch = "/"; +                        } +                    } +                } +            } +        } + +        return $ch; +    } + +    /** +     * Creates a new StripJavaComments using the passed in +     * Reader for instantiation. +     *  +     * @param reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return a new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new StripPhpComments($reader); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/TabToSpaces.php b/buildscripts/phing/classes/phing/filters/TabToSpaces.php new file mode 100644 index 00000000..7293d3b5 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TabToSpaces.php @@ -0,0 +1,144 @@ +<?php + +/* + *  $Id: TabToSpaces.php,v 1.9 2004/03/15 14:45:06 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; +require_once 'phing/filters/ChainableReader.php'; + +/** + * Converts tabs to spaces. + * + * Example: + * + * <pre><tabtospaces tablength="8"></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.TabsToSpaces"> + *   <param name="tablength" value="8"> + * </filterreader></pre> + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.9 $ + * @see       BaseParamFilterReader + * @package   phing.filters + */ +class TabToSpaces extends BaseParamFilterReader implements ChainableReader { + +    /** +     * The default tab length.  +     * @var int +     */ +    const DEFAULT_TAB_LENGTH = 8; +     +    /** +     * Parameter name for the length of a tab. +     * @var string +     */ +    const TAB_LENGTH_KEY = "tablength"; +     +    /** +     * Tab length in this filter. +     * @var int +     */   +    private $tabLength = 8; //self::DEFAULT_TAB_LENGTH;     + +    /** +     * Returns stream after converting tabs to the specified number of spaces. +     *  +     * @return the resulting stream, or -1 +     *         if the end of the resulting stream has been reached +     *  +     * @exception IOException if the underlying stream throws an IOException +     *            during reading      +     */ +    function read($len = null) { +     +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } + +          $buffer = $this->in->read($len); +         +        if($buffer === -1) { +            return -1; +        } +         +        $buffer = str_replace("\t", str_repeat(' ', $this->tabLength), $buffer); +         +        return $buffer;         +    } +     +    /** +     * Sets the tab length. +     *  +     * @param int $tabLength The number of spaces to be used when converting a tab. +     */ +    function setTablength($tabLength) { +        $this->tabLength = (int) $tabLength; +    } + +    /** +     * Returns the tab length. +     *  +     * @return int The number of spaces used when converting a tab +     */ +    function getTablength() { +        return $this->tabLength; +    } + +    /** +     * Creates a new TabsToSpaces using the passed in +     * Reader for instantiation. +     *  +     * @param Reader $reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return Reader A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new TabToSpaces($reader); +        $newFilter->setTablength($this->getTablength()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Parses the parameters to set the tab length. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0 ; $i<count($params) ; $i++) { +                if (self::TAB_LENGTH_KEY === $params[$i]->getName()) { +                    $this->tabLength = $params[$i]->getValue(); +                    break; +                } +            } +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/TailFilter.php b/buildscripts/phing/classes/phing/filters/TailFilter.php new file mode 100644 index 00000000..a6af6e4b --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TailFilter.php @@ -0,0 +1,157 @@ +<?php + +/* + *  $Id: TailFilter.php,v 1.7 2004/03/15 14:45:06 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; + +/** + * Reads the last <code>n</code> lines of a stream. (Default is last10 lines.) + * + * Example: + * + * <pre><tailfilter lines="3" /></pre> + * + * Or: + * + * <pre><filterreader classname="phing.filters.TailFilter"> + *   <param name="lines" value="3"> + * </filterreader></pre> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @author    hans lellelid, hans@velum.net + * @copyright © 2003 seasonfive. All rights reserved + * @version   $Revision: 1.7 $ + * @see       BaseParamFilterReader + * @package   phing.filters + */ +class TailFilter extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Parameter name for the number of lines to be returned. +     * @var string +     */ +    const LINES_KEY = "lines"; +     +     +    /** +     * Number of lines to be returned in the filtered stream. +     * @var integer +     */  +    private $_lines = 10; +     +    /** +     * Array to hold lines. +     * @var array +     */  +    private    $_lineBuffer = array(); +                 +    /** +     * Returns the last n lines of a file. +     * @param int $len Num chars to read. +     * @return mixed The filtered buffer or -1 if EOF. +     */ +    function read($len = null) { +     +        while ( ($buffer = $this->in->read($len)) !== -1 ) { +            // Remove the last "\n" from buffer for +            // prevent explode to add an empty cell at +            // the end of array +            $buffer= trim($buffer, "\n"); +             +            $lines = explode("\n", $buffer); + +            if ( count($lines) >= $this->_lines ) { +                // Buffer have more (or same) number of lines than needed. +                // Fill lineBuffer with the last "$this->_lines" lasts ones. +                $off = count($lines)-$this->_lines; +                $this->_lineBuffer = array_slice($lines, $off); +            } else { +                // Some new lines ... +                // Prepare space for insert these new ones +                $this->_lineBuffer = array_slice($this->_lineBuffer, count($lines)-1); +                $this->_lineBuffer = array_merge($this->_lineBuffer, $lines); +            } +        } + +        if ( empty($this->_lineBuffer) ) +            $ret = -1; +        else { +            $ret = implode("\n", $this->_lineBuffer); +            $this->_lineBuffer = array(); +        } + +        return $ret; +    } + +    /** +     * Sets the number of lines to be returned in the filtered stream. +     *  +     * @param integer $lines the number of lines to be returned in the filtered stream. +     */ +    function setLines($lines) { +        $this->_lines = (int) $lines; +    } + +    /** +     * Returns the number of lines to be returned in the filtered stream. +     *  +     * @return integer The number of lines to be returned in the filtered stream. +     */ +    function getLines() { +        return $this->_lines; +    } + +    /** +     * Creates a new TailFilter using the passed in +     * Reader for instantiation. +     *  +     * @param object A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return object A new filter based on this configuration, but filtering +     *         the specified reader. +     */ +    function chain(Reader $reader) { +        $newFilter = new TailFilter($reader); +        $newFilter->setLines($this->getLines()); +        $newFilter->setInitialized(true); +        $newFilter->setProject($this->getProject());         +        return $newFilter; +    } + +    /** +     * Scans the parameters list for the "lines" parameter and uses +     * it to set the number of lines to be returned in the filtered stream. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i=0, $_i=count($params); $i < $_i; $i++) { +                if ( self::LINES_KEY == $params[$i]->getName() ) { +                    $this->_lines = (int) $params[$i]->getValue(); +                    break; +                } +            } +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/TidyFilter.php b/buildscripts/phing/classes/phing/filters/TidyFilter.php new file mode 100644 index 00000000..10d75fc4 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TidyFilter.php @@ -0,0 +1,162 @@ +<?php +/* + *  $Id: TidyFilter.php,v 1.2 2005/12/08 19:15:20 hlellelid Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * This filter uses the bundled-with-PHP Tidy extension to filter input. + *  + * <p> + * Example:<br/> + * <pre> + * <tidyfilter encoding="utf8"> + *   <config name="indent" value="true"/> + *   <config name="output-xhtml" value="true"/> + * </tidyfilter> + * </pre> + *  + * @author Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.2 $ $Date: 2005/12/08 19:15:20 $ + * @package   phing.filters + */ +class TidyFilter extends BaseParamFilterReader implements ChainableReader { +   	 +	/** @var string Encoding of resulting document. */ +	private $encoding = 'utf8'; +    +    /** @var array Parameter[] */ +	private $configParameters = array(); +      +	/** +	 * Set the encoding for resulting (X)HTML document. +	 * @param string $v +	 */ +	public function setEncoding($v) { +		$this->encoding = $v; +	} +	 +	/** +	 * Sets the config params. +	 * @param array Parameter[] +	 * @see chain() +	 */ +	public function setConfigParameters($params) +	{ +		$this->configParameters = $params; +	} +	 +	/** +	 * Adds a <config> element (which is a Parameter). +	 * @return Parameter +	 */ +	public function createConfig() { +		$num = array_push($this->configParameters, new Parameter()); +        return $this->configParameters[$num-1]; +	} +	 +	/** +	 * Converts the Parameter objects being used to store configuration into a simle assoc array. +	 * @return array +	 */ +	private function getDistilledConfig() { +		$config = array(); +		foreach($this->configParameters as $p) { +			$config[$p->getName()] = $p->getValue(); +		} +		return $config; +	} +	 +    /** +     * Reads input and returns Tidy-filtered output. +     *  +     * @return the resulting stream, or -1 if the end of the resulting stream has been reached +     *  +     * @throws IOException if the underlying stream throws an IOException +     *                        during reading      +     */ +    function read($len = null) { +    	 +		if (!class_exists('Tidy')) { +			throw new BuildException("You must enable the 'tidy' extension in your PHP configuration in order to use the Tidy filter."); +		} +		 +		if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +		 +        $buffer = $this->in->read($len); +        if($buffer === -1) { +            return -1; +        } +		 +		$config = $this->getDistilledConfig(); +		 +		$tidy = new Tidy(); +		$tidy->parseString($buffer, $config, $this->encoding); +		$tidy->cleanRepair(); + +		return tidy_get_output($tidy); +		 +    } + + +    /** +     * Creates a new TidyFilter using the passed in Reader for instantiation. +     *  +     * @param reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return a new filter based on this configuration, but filtering +     *         the specified reader +     */ +    public function chain(Reader $reader) { +        $newFilter = new TidyFilter($reader); +		$newFilter->setConfigParameters($this->configParameters); +		$newFilter->setEncoding($this->encoding); +        $newFilter->setProject($this->getProject()); +        return $newFilter; +    } +	 +	/** +     * Initializes any parameters (e.g. config options). +     * This method is only called when this filter is used through a <filterreader> tag in build file. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +		if ($params) { +			foreach($params as $param) { +				if ($param->getType() == "config") { +					$this->configParameters[] = $param; +				} else { +					 +					if ($param->getName() == "encoding") { +					    $this->setEncoding($param->getValue()); +					} +					 +				} +				 +			} +		} +    } + +} diff --git a/buildscripts/phing/classes/phing/filters/TranslateGettext.php b/buildscripts/phing/classes/phing/filters/TranslateGettext.php new file mode 100644 index 00000000..f71823e3 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/TranslateGettext.php @@ -0,0 +1,285 @@ +<?php + +/* + *  $Id: TranslateGettext.php,v 1.11 2005/12/08 15:59:56 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Replaces gettext("message id") and _("message id") with the translated string. + *  + * Gettext is great for creating multi-lingual sites, but in some cases (e.g. for  + * performance reasons) you may wish to replace the gettext calls with the translations + * of the strings; that's what this task is for.  Note that this is similar to + * ReplaceTokens, but both the find and the replace aspect is more complicated -- hence + * this is a separate, stand-alone filter. + *  + * <p> + * Example:<br> + * <pre> + * <translategettext locale="en_US" domain="messages" dir="${webroot}/local"/> + * </pre> + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.11 $ $Date: 2005/12/08 15:59:56 $ + * @access    public + * @see       BaseFilterReader + * @package   phing.filters + */ +class TranslateGettext extends BaseParamFilterReader implements ChainableReader { + +    // constants for specifying keys to expect +    // when this is called using <filterreader ... /> +    const DOMAIN_KEY = "domain"; +    const DIR_KEY = "dir"; +    const LOCALE_KEY = "locale"; +     +    /** The domain to use */ +    private $domain = 'messages'; +     +    /** The dir containing LC_MESSAGES */ +    private $dir; + +    /** The locale to use */ +    private $locale; +     +    /** The system locale before it was changed for this filter. */ +    private $storedLocale; +     +    /** +     * Set the text domain to use. +     * The text domain must correspond to the name of the compiled .mo files. +     * E.g. "messages" ==> $dir/LC_MESSAGES/messages.mo +     *         "mydomain" ==> $dir/LC_MESSAGES/mydomain.mo +     * @param string $domain +     */ +    function setDomain($domain) { +        $this->domain = $domain; +    } +     +    /** +     * Get the current domain. +     * @return string +     */ +    function getDomain() { +        return $this->domain; +    } +     +    /** +     * Sets the root locale directory. +     * @param PhingFile $dir +     */ +    function setDir(PhingFile $dir) { +        $this->dir = $dir; +    } +     +    /** +     * Gets the root locale directory. +     * @return PhingFile +     */ +    function getDir() { +        return $this->dir; +    } +     +    /** +     * Sets the locale to use for translation. +     * Note that for gettext() to work, you have to make sure this locale +     * is specific enough for your system (e.g. some systems may allow an 'en' locale, +     * but others will require 'en_US', etc.). +     * @param string $locale  +     */ +    function setLocale($locale) { +        $this->locale = $locale; +    } +     +    /** +     * Gets the locale to use for translation. +     * @return string +     */ +    function getLocale() { +        return $this->locale; +    } +     +    /** +     * Make sure that required attributes are set. +     * @throws BuldException - if any required attribs aren't set. +     */ +    protected function checkAttributes() { +        if (!$this->domain || !$this->locale || !$this->dir) { +            throw new BuildException("You must specify values for domain, locale, and dir attributes."); +        } +    } +     +    /** +     * Initialize the gettext/locale environment. +     * This method will change some env vars and locale settings; the +     * restoreEnvironment should put them all back :) +     *  +     * @return void +     * @throws BuildException - if locale cannot be set. +     * @see restoreEnvironment() +     */ +    protected function initEnvironment() { +        $this->storedLocale = getenv("LANG"); +         +        $this->log("Setting locale to " . $this->locale, PROJECT_MSG_DEBUG); +        putenv("LANG=".$this->locale); +        $ret = setlocale(LC_ALL, $this->locale); +        if ($ret === false) { +            $msg = "Could not set locale to " . $this->locale +                    . ". You may need to use fully qualified name" +                    . " (e.g. en_US instead of en)."; +            throw new BuildException($msg); +        }         +         +        $this->log("Binding domain '".$this->domain."' to "  . $this->dir, PROJECT_MSG_DEBUG); +        bindtextdomain($this->domain, $this->dir->getAbsolutePath()); +        textdomain($this->domain);         +    } +     +    /** +     * Restores environment settings and locale. +     * This does _not_ restore any gettext-specific settings +     * (e.g. textdomain()). +     *  +     * @return void +     */ +    protected function restoreEnvironment() { +        putenv("LANG=".$this->storedLocale); +        setlocale(LC_ALL, $this->storedLocale); +    } + +    /** +     * Performs gettext translation of msgid and returns translated text. +     *  +     * This function simply wraps gettext() call, but provides ability to log +     * string replacements.  (alternative would be using preg_replace with /e which +     * would probably be faster, but no ability to debug/log.) +     *  +     * @param array $matches Array of matches; we're interested in $matches[2]. +     * @return string Translated text +     */ +    private function xlateStringCallback($matches) { +        $charbefore = $matches[1]; +        $msgid = $matches[2]; +        $translated = gettext($msgid); +        $this->log("Translating \"$msgid\" => \"$translated\"", PROJECT_MSG_DEBUG); +        return $charbefore . '"' . $translated . '"'; +    } +         +    /** +     * Returns the filtered stream.  +     * The original stream is first read in fully, and then translation is performed. +     *  +     * @return mixed     the filtered stream, or -1 if the end of the resulting stream has been reached. +     *  +     * @throws IOException - if the underlying stream throws an IOException during reading +     * @throws BuildException - if the correct params are not supplied +     */ +    function read($len = null) { +                 +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } +         +        // Make sure correct params/attribs have been set +        $this->checkAttributes(); +         +        $buffer = $this->in->read($len);         +        if($buffer === -1) { +            return -1; +        } + +        // Setup the locale/gettext environment +        $this->initEnvironment(); +         + +        // replace any occurrences of _("") or gettext("") with +        // the translated value. +        // +        // ([^\w]|^)_\("((\\"|[^"])*)"\) +        //  --$1---      -----$2----    +        //                 ---$3--  [match escaped quotes or any char that's not a quote] +        //  +        // also match gettext() -- same as above +         +        $buffer = preg_replace_callback('/([^\w]|^)_\("((\\\"|[^"])*)"\)/', array($this, 'xlateStringCallback'), $buffer); +        $buffer = preg_replace_callback('/([^\w]|^)gettext\("((\\\"|[^"])*)"\)/', array($this, 'xlateStringCallback'), $buffer); + +        // Check to see if there are any _('') calls and flag an error + +        // Check to see if there are any unmatched gettext() calls -- and flag an error         +                     +        $matches = array(); +        if (preg_match('/([^\w]|^)(gettext\([^\)]+\))/', $buffer, $matches)) { +            $this->log("Unable to perform translation on: " . $matches[2], PROJECT_MSG_WARN); +        } +                 +        $this->restoreEnvironment(); +         +        return $buffer; +    } + +    /** +     * Creates a new TranslateGettext filter using the passed in +     * Reader for instantiation. +     *  +     * @param Reader $reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     *  +     * @return TranslateGettext A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new TranslateGettext($reader); +        $newFilter->setProject($this->getProject()); +        $newFilter->setDomain($this->getDomain()); +        $newFilter->setLocale($this->getLocale()); +        $newFilter->setDir($this->getDir()); +        return $newFilter; +    } + +    /** +     * Parses the parameters if this filter is being used in "generic" mode. +     */ +    private function _initialize() { +        $params = $this->getParameters(); +        if ( $params !== null ) { +            foreach($params as $param) { +                switch($param->getType()) { +                    case self::DOMAIN_KEY: +                        $this->setDomain($param->getValue()); +                        break; +                    case self::DIR_KEY: +                        $this->setDir($this->project->resolveFile($param->getValue())); +                        break; +                         +                    case self::LOCALE_KEY: +                        $this->setLocale($param->getValue()); +                        break;                 +                } // switch +            } +        } // if params !== null +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/filters/XsltFilter.php b/buildscripts/phing/classes/phing/filters/XsltFilter.php new file mode 100644 index 00000000..0b8c4e6f --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/XsltFilter.php @@ -0,0 +1,317 @@ +<?php + +/* + *  $Id: XsltFilter.php,v 1.16 2005/12/07 20:05:01 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Applies XSL stylesheet to incoming text. + *  + * Uses PHP XSLT support (libxslt). + *  + * @author    Hans Lellelid <hans@velum.net> + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @author    Andreas Aderhold <andi@binarycloud.com> + * @version   $Revision: 1.16 $ + * @see       FilterReader + * @package   phing.filters + */ +class XsltFilter extends BaseParamFilterReader implements ChainableReader { + +    /** +     * Path to XSL stylesheet. +     * @var string +     */ +    private $xslFile   = null; + +    /** +     * Whether XML file has been transformed. +     * @var boolean +     */ +    private $processed = false; +     +    /** +     * XSLT Params. +     * @var array +     */ +    private $xsltParams = array();     +     +    /** +     * Whether to use loadHTML() to parse the input XML file. +     */ +    private $html = false; +     +    /** +     * Create new XSLT Param object, to handle the <param/> nested element. +     * @return XSLTParam +     */ +    function createParam() { +        $num = array_push($this->xsltParams, new XSLTParam()); +        return $this->xsltParams[$num-1]; +    } +     +    /** +     * Sets the XSLT params for this class. +     * This is used to "clone" this class, in the chain() method. +     * @param array $params +     */ +    function setParams($params) { +        $this->xsltParams = $params; +    } +     +    /** +     * Returns the XSLT params set for this class. +     * This is used to "clone" this class, in the chain() method. +     * @return array +     */ +    function getParams() { +        return $this->xsltParams; +    } +         +    /** +     * Set the XSLT stylesheet. +     * @param mixed $file PhingFile object or path. +     */ +    function setStyle(PhingFile $file) { +        $this->xslFile = $file; +    } + +    /** +     * Whether to use HTML parser for the XML. +     * This is supported in libxml2 -- Yay! +     * @return boolean +     */ +    function getHtml() { +        return $this->html; +    } +     +    /** +     * Whether to use HTML parser for XML. +     * @param boolean $b +     */ +    function setHtml($b) {         +        $this->html = (boolean) $b; +    } +     +    /** +     * Get the path to XSLT stylesheet. +     * @return mixed XSLT stylesheet path. +     */ +    function getStyle() { +        return $this->xslFile; +    } +     +    /** +     * Reads stream, applies XSLT and returns resulting stream. +     * @return string transformed buffer. +     * @throws BuildException - if XSLT support missing, if error in xslt processing +     */ +    function read($len = null) { +         +        if (!class_exists('XSLTProcessor')) { +            throw new BuildException("Could not find the XSLTProcessor class. Make sure PHP has been compiled/configured to support XSLT."); +        } +         +        if ($this->processed === true) { +            return -1; // EOF +        } +         +        if ( !$this->getInitialized() ) { +            $this->_initialize(); +            $this->setInitialized(true); +        } + +        // Read XML +        $_xml = null; +        while ( ($data = $this->in->read($len)) !== -1 ) +            $_xml .= $data; + +        if ($_xml === null ) { // EOF? +            return -1; +        } + +        if(empty($_xml)) { +            $this->log("XML file is empty!", PROJECT_MSG_WARN); +            return ''; // return empty string, don't attempt to apply XSLT +        } +        +        // Read XSLT +        $_xsl = null; +        $xslFr = new FileReader($this->xslFile); +        $xslFr->readInto($_xsl); +         +        $this->log("Tranforming XML " . $this->in->getResource() . " using style " . $this->xslFile->getPath(), PROJECT_MSG_VERBOSE); +         +        $out = ''; +        try { +            $out = $this->process($_xml, $_xsl); +            $this->processed = true; +        } catch (IOException $e) {             +            throw new BuildException($e); +        } + +        return $out; +    } + +    // {{{ method _ProcessXsltTransformation($xml, $xslt) throws BuildException +    /** +     * Try to process the XSLT transformation +     * +     * @param   string  XML to process. +     * @param   string  XSLT sheet to use for the processing. +     * +     * @throws BuildException   On XSLT errors +     */ +    protected function process($xml, $xsl) {     +                 +        $processor = new XSLTProcessor(); +         +        $xmlDom = new DOMDocument(); +        $xslDom = new DOMDocument();         +         +        if ($this->html) {             +            $xmlDom->loadHTML($xml); +        } else { +            $xmlDom->loadXML($xml); +        } +         +        $xslDom->loadxml($xsl); +         +        $processor->importStylesheet($xslDom); + +        // ignoring param "type" attrib, because +        // we're only supporting direct XSL params right now +        foreach($this->xsltParams as $param) { +            $this->log("Setting XSLT param: " . $param->getName() . "=>" . $param->getExpression(), PROJECT_MSG_DEBUG); +            $processor->setParameter(null, $param->getName(), $param->getExpression()); +        } +         +        $result = $processor->transformToXML($xmlDom); +         +        if ( !$result ) { +            //$errno = xslt_errno($processor); +            //$err   = xslt_error($processor);     +            throw new BuildException("XSLT Error");             +        } else { +            return $result; +        } +    }     + +    /** +     * Creates a new XsltFilter using the passed in +     * Reader for instantiation. +     * +     * @param Reader A Reader object providing the underlying stream. +     *               Must not be <code>null</code>. +     * +     * @return Reader A new filter based on this configuration, but filtering +     *         the specified reader +     */ +    function chain(Reader $reader) { +        $newFilter = new XsltFilter($reader); +        $newFilter->setProject($this->getProject()); +        $newFilter->setStyle($this->getStyle()); +        $newFilter->setInitialized(true); +        $newFilter->setParams($this->getParams()); +        $newFilter->setHtml($this->getHtml()); +        return $newFilter; +    } + +    /** +     * Parses the parameters to get stylesheet path. +     */ +    private function _initialize() {         +        $params = $this->getParameters(); +        if ( $params !== null ) { +            for($i = 0, $_i=count($params) ; $i < $_i; $i++) { +                if ( $params[$i]->getType() === null ) { +                    if ($params[$i]->getName() === "style") { +                        $this->setStyle($params[$i]->getValue()); +                    } +                } elseif ($params[$i]->getType() == "param") { +                    $xp = new XSLTParam(); +                    $xp->setName($params[$i]->getName()); +                    $xp->setExpression($params[$i]->getValue()); +                    $this->xsltParams[] = $xp; +                } +            } +        } +    } + +} + + +/** + * Class that holds an XSLT parameter. + */ +class XSLTParam { +     +    private $name; +     +    private $expr;     +     +    /** +     * Sets param name. +     * @param string $name +     */ +    public function setName($name) { +        $this->name = $name; +    } +     +    /** +     * Get param name. +     * @return string +     */ +    public function getName() { +        return $this->name; +    } +     +    /** +     * Sets expression value. +     * @param string $expr +     */ +    public function setExpression($expr) { +        $this->expr = $expr; +    } +     +    /** +     * Sets expression to dynamic register slot. +     * @param RegisterSlot $expr +     */ +    public function setListeningExpression(RegisterSlot $expr) { +        $this->expr = $expr;     +    } +     +    /** +     * Returns expression value -- performs lookup if expr is registerslot. +     * @return string +     */ +    public function getExpression() { +        if ($this->expr instanceof RegisterSlot) { +            return $this->expr->getValue(); +        } else { +            return $this->expr; +        } +    }         +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php new file mode 100644 index 00000000..80508a82 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php @@ -0,0 +1,184 @@ +<?php +/* + *  $Id: ChainReaderHelper.php,v 1.8 2005/02/27 20:52:09 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/Project.php'; +include_once 'phing/filters/BaseFilterReader.php'; +include_once 'phing/types/PhingFilterReader.php'; +include_once 'phing/types/FilterChain.php'; +include_once 'phing/types/Parameter.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Process a FilterReader chain. + * + * Here, the interesting method is 'getAssembledReader'. + * The purpose of this one is to create a simple Reader object which + * apply all filters on another primary Reader object.  + * + * For example : In copyFile (phing.util.FileUtils) the primary Reader + * is a FileReader object (more accuratly, a BufferedReader) previously  + * setted for the source file to copy. So, consider this filterchain : + *         + *     <filterchain> + *        <stripphpcomments /> + *        <linecontains> + *            <contains value="foo"> + *        </linecontains> + *      <tabtospaces tablength="8" /> + *    </filterchain> + * + *    getAssembledReader will return a Reader object wich read on each + *    of these filters. Something like this : ('->' = 'which read data from') : + * + *  [TABTOSPACES] -> [LINECONTAINS] -> [STRIPPHPCOMMENTS] -> [FILEREADER] + *                                                         (primary reader) + * + *  So, getAssembledReader will return the TABTOSPACES Reader object. Then + *  each read done with this Reader object will follow this path. + * + *    Hope this explanation is clear :) + * + * TODO: Implement the classPath feature. + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @version   $Revision: 1.8 $ $Date: 2005/02/27 20:52:09 $ + * @access    public + * @package   phing.filters.util +*/ +class ChainReaderHelper { +     +    /** Primary reader to wich the reader chain is to be attached */ +    private $primaryReader = null; +     +    /** The site of the buffer to be used. */ +    private $bufferSize = 8192; +     +    /** Chain of filters */ +    private $filterChains = array(); +     +    /** The Phing project */ +    private $project; + +    /* +     * Sets the primary reader +    */ +    function setPrimaryReader(Reader $reader) { +        $this->primaryReader = $reader; +    } + +    /* +     * Set the project to work with +    */ +    function setProject(Project $project) { +        $this->project = $project; +    } + +    /* +     * Get the project +    */ +    function getProject() { +        return $this->project; +    } + +    /* +     * Sets the buffer size to be used.  Defaults to 8192, +     * if this method is not invoked. +    */ +    function setBufferSize($size) { +        $this->bufferSize = $size; +    } + +    /* +     * Sets the collection of filter reader sets +    */ +    function setFilterChains(&$fchain) { +        $this->filterChains = &$fchain; +    } + +    /* +     * Assemble the reader +    */ +    function getAssembledReader() { +     +        $instream = $this->primaryReader; +        $filterReadersCount = count($this->filterChains); +        $finalFilters = array(); + +        // Collect all filter readers of all filter chains used ... +        for($i = 0 ; $i<$filterReadersCount ; $i++) { +            $filterchain = &$this->filterChains[$i]; +            $filterReaders = $filterchain->getFilterReaders(); +            $readerCount = count($filterReaders); +            for($j = 0 ; $j<$readerCount ; $j++) { +                $finalFilters[] = $filterReaders[$j]; +            } +        } + +        // ... then chain the filter readers. +        $filtersCount = count($finalFilters); +        if ( $filtersCount > 0 ) { +            for($i = 0 ; $i<$filtersCount ; $i++) { +                $filter = $finalFilters[$i]; +                 +                if ( $filter instanceof PhingFilterReader ) { +                 +                    // This filter reader is an external class. +                    $className = $filter->getClassName(); +                    $classpath = $filter->getClasspath(); +                    $project   = $filter->getProject(); +                     +                    if ( $className !== null ) { +                        $cls = Phing::import($className, $classpath); +                        $impl = new $cls();                         +                    } + +                    if ( !($impl instanceof FilterReader) ) { +                        throw new Exception($className." does not extend phing.system.io.FilterReader"); +                    } +                     +                    $impl->setReader($instream); // chain +                    $impl->setProject($this->getProject()); // what about $project above ? + +                    if ( $impl instanceof Parameterizable ) { +                        $impl->setParameters($filter->getParams()); +                    } +                     +                    $instream = $impl; // now that it's been chained +                                                             +                } elseif (($filter instanceof ChainableReader) && ($filter instanceof Reader)) {                    +                    if ( $this->getProject() !== null && ($filter instanceof BaseFilterReader) ) { +                        $filter->setProject($this->getProject()); +                    }                     +                    $instream = $filter->chain($instream); +                } else { +                    throw new Exception("Cannot chain invalid filter: " . get_class($filter)); +                } +            } +        } + +        return $instream; +    }     + +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php new file mode 100644 index 00000000..34bc5943 --- /dev/null +++ b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php @@ -0,0 +1,96 @@ +<?php +/* + *  $Id: IniFileTokenReader.php,v 1.7 2005/05/26 13:10:51 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/types/TokenReader.php'; +include_once 'phing/system/io/IOException.php'; +include_once 'phing/filters/ReplaceTokens.php'; // For class Token + +/** + * Class that allows reading tokens from INI files. + *  + * @author    Manuel Holtgewe + * @version   $Revision: 1.7 $ + * @package   phing.filters.util + */ +class IniFileTokenReader extends TokenReader { + +    /** +     * Holds the path to the INI file that is to be read. +     * @var object  Reference to a PhingFile Object representing +     *              the path to the INI file. +     */ +    private $file = null; + +    /** +     * @var string  Sets the section to load from the INI file. +     *              if omitted, all sections are loaded. +     */ +    private $section = null; + +    /** +     * Reads the next token from the INI file +     * +     * @throws  IOException     On error +     */ +    function readToken() { +        if ($this->file === null) { +            throw new BuildException("No File set for IniFileTokenReader"); +        } + +        static $tokens = null; +        if ($tokens === null) { +            $tokens = array(); +            $arr = parse_ini_file($this->file->getAbsolutePath(), true); +            if ($this->section === null) { +                foreach ($arr as $sec_name => $values) { +                    foreach($arr[$sec_name] as $key => $value) { +                        $tok = new Token; +                        $tok->setKey($key); +                        $tok->setValue($value); +                        $tokens[] = $tok; +                    } +                } +            } else if (isset($arr[$this->section])) { +                foreach ($arr[$this->section] as $key => $value) { +                    $tok = new Token; +                    $tok->setKey($key); +                    $tok->setValue($value); +                    $tokens[] = $tok; +                } +            } +        } + +        if (count($tokens) > 0) { +            return array_pop($tokens); +        } else +            return null; +    } +     +    function setFile(PhingFile $file) { +        $this->file = $file; +    } + +    function setSection($str) { +        $this->section = (string) $str; +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/input/DefaultInputHandler.php b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php new file mode 100644 index 00000000..8ce76cdd --- /dev/null +++ b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php @@ -0,0 +1,82 @@ +<?php + +/* + *  $Id: DefaultInputHandler.php,v 1.6 2004/02/27 18:49:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/input/InputHandler.php'; +include_once 'phing/system/io/ConsoleReader.php'; + +/** + * Prompts using print(); reads input from Console. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version $Revision: 1.6 $ + * @package phing.input + */ +class DefaultInputHandler implements InputHandler { +     +    /** +     * Prompts and requests input.  May loop until a valid input has +     * been entered. +     * @throws BuildException  +     */ +    public function handleInput(InputRequest $request) { +        $prompt = $this->getPrompt($request); +        $in = new ConsoleReader();            +        do { +            print $prompt; +            try { +                $input = $in->readLine(); +                if ($input === "" && ($request->getDefaultValue() !== null) ) { +                    $input = $request->getDefaultValue(); +                } +                $request->setInput($input); +            } catch (Exception $e) { +                throw new BuildException("Failed to read input from Console.", $e); +            } +        } while (!$request->isInputValid()); +    } + +    /** +     * Constructs user prompt from a request. +     * +     * <p>This implementation adds (choice1,choice2,choice3,...) to the +     * prompt for <code>MultipleChoiceInputRequest</code>s.</p> +     * +     * @param $request the request to construct the prompt for. +     *                Must not be <code>null</code>. +     */ +    protected function getPrompt(InputRequest $request) { +        $prompt = $request->getPrompt(); +         +        // use is_a() to avoid needing the class to be loaded +        if (is_a($request, 'YesNoInputRequest')) { // (yes/no) +            $prompt .= '(' . implode('/', $request->getChoices()) .')'; +        } elseif (is_a($request, 'MultipleChoiceInputRequest')) { // (a,b,c,d) +            $prompt .= '(' . implode(',', $request->getChoices()) . ')';             +        } +        if ($request->getDefaultValue() !== null) { +            $prompt .= ' ['.$request->getDefaultValue().']'; +        } +        $pchar = $request->getPromptChar();         +        return $prompt . ($pchar ? $pchar . ' ' : ' '); +    }  +} diff --git a/buildscripts/phing/classes/phing/input/InputHandler.php b/buildscripts/phing/classes/phing/input/InputHandler.php new file mode 100644 index 00000000..68fad7b5 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/InputHandler.php @@ -0,0 +1,45 @@ +<?php + +/* + *  $Id: InputHandler.php,v 1.3 2003/12/24 12:38:39 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Plugin to Phing to handle requests for user input. + * + * @author Stefan Bodewig <stefan.bodewig@epost.de> + * @version $Revision: 1.3 $ + * @package phing.input + */ +interface InputHandler { + +    /** +     * Handle the request encapsulated in the argument. +     * +     * <p>Precondition: the request.getPrompt will return a non-null +     * value.</p> +     * +     * <p>Postcondition: request.getInput will return a non-null +     * value, request.isInputValid will return true.</p> +     * @return void +     * @throws BuildException +     */ +    public function handleInput(InputRequest $request); +     +} diff --git a/buildscripts/phing/classes/phing/input/InputRequest.php b/buildscripts/phing/classes/phing/input/InputRequest.php new file mode 100644 index 00000000..7bfe8def --- /dev/null +++ b/buildscripts/phing/classes/phing/input/InputRequest.php @@ -0,0 +1,107 @@ +<?php + +/* + *  $Id: InputRequest.php,v 1.4 2003/12/24 12:38:39 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Encapsulates an input request. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version $Revision: 1.4 $ + * @package phing.input + */ +class InputRequest { + +    protected $prompt; +    protected $input; +    protected $defaultValue; +    protected $promptChar; +     +    /** +     * @param string $prompt The prompt to show to the user.  Must not be null. +     */ +    public function __construct($prompt) { +        if ($prompt === null) { +            throw new BuildException("prompt must not be null"); +        }         +        $this->prompt = $prompt; +    } + +    /** +     * Retrieves the prompt text. +     */ +    public function getPrompt() { +        return $this->prompt; +    } + +    /** +     * Sets the user provided input. +     */ +    public function setInput($input) { +        $this->input = $input; +    } +     +    /** +     * Is the user input valid? +     */ +    public function isInputValid() { +        return true; +    } + +    /** +     * Retrieves the user input. +     */ +    public function getInput() { +        return $this->input; +    } +     +    /** +     * Set the default value to use. +     * @param mixed $v +     */ +    public function setDefaultValue($v) { +        $this->defaultValue = $v; +    } +     +    /** +     * Return the default value to use. +     * @return mixed +     */ +    public function getDefaultValue() { +        return $this->defaultValue; +    } +     +    /** +     * Set the default value to use. +     * @param string $c +     */ +    public function setPromptChar($c) { +        $this->promptChar = $c; +    } +     +    /** +     * Return the default value to use. +     * @return string +     */ +    public function getPromptChar() { +        return $this->promptChar; +    } +} diff --git a/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php new file mode 100644 index 00000000..d4ea1212 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php @@ -0,0 +1,58 @@ +<?php +/* + *  $Id: MultipleChoiceInputRequest.php,v 1.5 2004/03/15 17:11:15 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/input/InputRequest.php'; + +/** + * Encapsulates an input request. + * + * @author Stefan Bodewig <stefan.bodewig@epost.de> + * @version $Revision: 1.5 $ + * @package phing.input + */ +class MultipleChoiceInputRequest extends InputRequest { + +    protected $choices = array(); + +    /** +     * @param string $prompt The prompt to show to the user.  Must not be null. +     * @param array $choices holds all input values that are allowed. +     *                Must not be null. +     */ +    public function __construct($prompt, $choices) { +        parent::__construct($prompt);         +        $this->choices = $choices; +    } + +    /** +     * @return The possible values. +     */ +    public function getChoices() { +        return $this->choices; +    } + +    /** +     * @return true if the input is one of the allowed values. +     */ +    public function isInputValid() { +        return in_array($this->getInput(), $this->choices); // not strict (?) +    } +} diff --git a/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php b/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php new file mode 100644 index 00000000..e588cead --- /dev/null +++ b/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php @@ -0,0 +1,129 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation.  All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in + *    the documentation and/or other materials provided with the + *    distribution. + * + * 3. The end-user documentation included with the redistribution, if + *    any, must include the following acknowlegement: + *       "This product includes software developed by the + *        Apache Software Foundation (http://www.apache.org/)." + *    Alternately, this acknowlegement may appear in the software itself, + *    if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "Ant" and "Apache Software + *    Foundation" must not be used to endorse or promote products derived + *    from this software without prior written permission. For written + *    permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + *    nor may "Apache" appear in their names without prior written + *    permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation.  For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.input; + +import org.apache.tools.ant.BuildException; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Properties; + +/** + * Reads input from a property file, the file name is read from the + * system property ant.input.properties, the prompt is the key for input. + * + * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> + * @version $Revision: 1.1 $ + * @since Ant 1.5 + */ +public class PropertyFileInputHandler implements InputHandler { +    private Properties props = null; + +    /** +     * Name of the system property we expect to hold the file name. +     */ +    public static final String FILE_NAME_KEY = "ant.input.properties"; + +    /** +     * Empty no-arg constructor. +     */ +    public PropertyFileInputHandler() { +    } + +    /** +     * Picks up the input from a property, using the prompt as the +     * name of the property. +     * +     * @exception BuildException if no property of that name can be found. +     */ +    public void handleInput(InputRequest request) throws BuildException { +        readProps(); +         +        Object o = props.get(request.getPrompt()); +        if (o == null) { +            throw new BuildException("Unable to find input for \'" +                                     + request.getPrompt()+"\'"); +        } +        request.setInput(o.toString()); +        if (!request.isInputValid()) { +            throw new BuildException("Found invalid input " + o +                                     + " for \'" + request.getPrompt() + "\'"); +        } +    } + +    /** +     * Reads the properties file if it hasn't already been read. +     */ +    private synchronized void readProps() throws BuildException { +        if (props == null) { +            String propsFile = System.getProperty(FILE_NAME_KEY); +            if (propsFile == null) { +                throw new BuildException("System property " +                                         + FILE_NAME_KEY +                                         + " for PropertyFileInputHandler not" +                                         + " set"); +            } +             +            props = new Properties(); +             +            try { +                props.load(new FileInputStream(propsFile)); +            } catch (IOException e) { +                throw new BuildException("Couldn't load " + propsFile, e); +            } +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/input/YesNoInputRequest.php b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php new file mode 100644 index 00000000..e34863d5 --- /dev/null +++ b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php @@ -0,0 +1,47 @@ +<?php +/* + *  $Id: YesNoInputRequest.php,v 1.4 2003/12/24 12:38:39 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/input/MultipleChoiceInputRequest.php'; + +/** + * Encapsulates an input request that returns a boolean (yes/no). + * + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.4 $ + * @package phing.input + */ +class YesNoInputRequest extends MultipleChoiceInputRequest {      + +    /** +     * @return true if the input is one of the allowed values. +     */ +    public function isInputValid() { +        return StringHelper::isBoolean($this->input);         +    } +     +    /** +     * Converts input to boolean. +     * @return boolean +     */ +    public function getInput() { +        return StringHelper::booleanValue($this->input); +    } +} diff --git a/buildscripts/phing/classes/phing/lib/Capsule.php b/buildscripts/phing/classes/phing/lib/Capsule.php new file mode 100644 index 00000000..bab05486 --- /dev/null +++ b/buildscripts/phing/classes/phing/lib/Capsule.php @@ -0,0 +1,266 @@ +<?php + +/** + * Capsule is a simple "template" engine that essentially provides an isolated context + * for PHP scripts. + *  + * There is no special templating language, and therefore no limitations to what + * can be accomplished within templates. The main purpose of Capsule is to separate  + * the business logic from display / output logic. + *  + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.9 $ $Date: 2004/08/31 20:12:02 $ + */ +class Capsule { +     +    /** +     * Look for templates here (if relative path provided). +     * @var string +     */ +    protected $templatePath; +     +    /** +     * Where should output files be written? +     * (This is named inconsistently to be compatible w/ Texen.) +     * @var string +     */ +    protected $outputDirectory; +     +    /** +     * The variables that can be used by the templates. +     * @var array Hash of variables. +     */ +    public $vars = array(); +     +    /** +     * Has template been initialized. +     */     +    protected $initialized = false; +     +    /** +     * Stores the pre-parse() include_path. +     * @var string +     */ +    private $old_include_path; +     +    function __construct() { +    } +     +    /** +     * Clears one or several or all variables. +     * @param mixed $which String name of var, or array of names. +     * @return void +     */ +    function clear($which = null) { +        if ($which === null) { +            $this->vars = array(); +        } elseif (is_array($which)) { +            foreach($which as $var) { +                unset($this->vars[$var]); +            } +        } else { +            unset($this->vars[$which]); +        } +    } +     +    /** +     * Set the basepath to use for template lookups. +     * @param string $v +     */ +    function setTemplatePath($v) { +        $this->templatePath = rtrim($v, DIRECTORY_SEPARATOR.'/'); +    } + +    /** +     * Get the basepath to use for template lookups. +     * @return string +     */ +    function getTemplatePath() { +        return $this->templatePath; +    } +     +    /** +     * Set a basepath to use for output file creation. +     * @param string $v +     */ +    function setOutputDirectory($v) { +        $this->outputDirectory = rtrim($v, DIRECTORY_SEPARATOR.'/'); +    } + +    /** +     * Get basepath to use for output file creation. +     * @return string +     */ +    function getOutputDirectory() { +        return $this->outputDirectory; +    } +     +    /** +     * Low overhead (no output buffering) method to simply dump template +     * to buffer. +     *  +     * @param string $__template +     * @return void +     * @throws Exception - if template cannot be found +     */  +    function display($__template) { +         +        // Prepend "private" variable names with $__ in this function +        // to keep namespace conflict potential to a minimum. +             +        // Alias this class to $generator. +        $generator = $this; +                         +        if (isset($this->vars['this'])) { +            throw new Exception("Assigning a variable named \$this to a context conflicts with class namespace."); +        } +         +        // extract variables into local namespace +        extract($this->vars); +         +        // prepend template path to include path,  +        // so that include "path/relative/to/templates"; can be used within templates +        $__old_inc_path = ini_get('include_path'); +        ini_set('include_path', $this->templatePath . PATH_SEPARATOR . $__old_inc_path); +                 +        @ini_set('track_errors', true); +        include $__template; +        @ini_restore('track_errors'); +         +        // restore the include path +        ini_set('include_path', $__old_inc_path); +         +        if (!empty($php_errormsg)) { +            throw new Exception("Unable to parse template " . $__template . ": " . $php_errormsg); +        } +    } +     +    /** +     * Fetches the results of a tempalte parse and either returns +     * the string or writes results to a specified output file. +     * +     * @param string $template The template filename (relative to templatePath or absolute). +     * @param string $outputFile If specified, contents of template will also be written to this file. +     * @param boolean $append Should output be appended to source file? +     * @return string The "parsed" template output. +     * @throws Exception - if template not found. +     */ +    function parse($template, $outputFile = null, $append = false) { +                 +        // main work done right here: +        // hopefully this works recursively ... fingers crossed.     +        ob_start(); +         +        try { +            $this->display($template); +        } catch (Exception $e) { +            ob_end_flush(); // flush the output on error (so we can see up to what point it parsed everything) +            throw $e; +        } +                 +        $output = ob_get_contents(); +        ob_end_clean(); +         +        if ($outputFile !== null) { +            $outputFile = $this->resolvePath($outputFile, $this->outputDirectory); +             +            $flags = null; +            if ($append) $flags = FILE_APPEND; +             +            if (!file_put_contents($outputFile, $output, $flags) && $output != "") { +                throw new Exception("Unable to write output to " . $outputFile); +            } +        } + +        return $output; +    } +     +    /** +     * This returns a "best guess" path for the given file. +     * +     * @param string $file File name or possibly absolute path. +     * @param string $basepath The basepath that should be prepended if $file is not absolute. +     * @return string "Best guess" path for this file. +     */ +    protected function resolvePath($file, $basepath) { +        if ( !($file{0} == DIRECTORY_SEPARATOR || $file{0} == '/')  +            // also account for C:\ style path +                && !($file{1} == ':' && ($file{2} ==  DIRECTORY_SEPARATOR || $file{2} == '/'))) {  +            if ($basepath != null) { +                $file = $basepath . DIRECTORY_SEPARATOR . $file; +            } +        } +        return $file; +    } + +    /** +     * Gets value of specified var or NULL if var has not been put(). +     * @param string $name Variable name to retrieve. +     * @return mixed +     */ +    function get($name) { +        if (!isset($this->vars[$name])) return null; +        return $this->vars[$name]; +    } +     +    /** +     * Merges in passed hash to vars array. +     * +     * Given an array like: +     * +     *            array(     'myvar' => 'Hello', +     *                    'myvar2' => 'Hello') +     * +     * Resulting template will have access to $myvar and $myvar2. +     * +     * @param array $vars +     * @param boolean $recursiveMerge Should matching keys be recursively merged? +     * @return void +     */ +    function putAll($vars, $recursiveMerge = false) { +        if ($recursiveMerge) { +            $this->vars = array_merge_recursive($this->vars, $vars); +        } else { +            $this->vars = array_merge($this->vars, $vars); +        } +    } +     +    /** +     * Adds a variable to the context. +     *  +     * Resulting template will have access to ${$name$} variable. +     *  +     * @param string $name +     * @param mixed $value +     */ +    function put($name, $value) { +        $this->vars[$name] = $value; +    } +         +    /** +     * Put a variable into the context, assigning it by reference. +     * This means that if the template modifies the variable, then it +     * will also be modified in the context. +     * +     * @param $name +     * @param &$value +     */ +    function putRef($name, &$value) { +        $this->vars[$name] = &$value; +    } +     +    /** +     * Makes a copy of the value and puts it into the context. +     * This is primarily to force copying (cloning) of objects, rather +     * than the default behavior which is to assign them by reference. +     * @param string $name +     * @param mixed $value +     */ +    function putCopy($name, $value) { +        if (is_object($value)) { +            $value = clone $value; +        } +        $this->vars[$name] = $value; +    } + +}
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/lib/Zip.php b/buildscripts/phing/classes/phing/lib/Zip.php new file mode 100644 index 00000000..70d31595 --- /dev/null +++ b/buildscripts/phing/classes/phing/lib/Zip.php @@ -0,0 +1,3588 @@ +<?php +/* vim: set ts=4 sw=4: */ +// +----------------------------------------------------------------------+ +// | PHP Version 4                                                        | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2003 The PHP Group                                | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 3.0 of the PHP license,       | +// | that is bundled with this package in the file LICENSE, and is        | +// | available through the world-wide-web at the following url:           | +// | http://www.php.net/license/3_0.txt.                                  | +// | If you did not receive a copy of the PHP license and are unable to   | +// | obtain it through the world-wide-web, please send a note to          | +// | license@php.net so we can mail you a copy immediately.               | +// +----------------------------------------------------------------------+ +// | Author: Vincent Blavet <vincent@blavet.net>                          | +// +----------------------------------------------------------------------+ +// +// $Id: Zip.php,v 1.3 2005/12/27 16:05:57 hlellelid Exp $ + +  // ----- Constants +  define( 'ARCHIVE_ZIP_READ_BLOCK_SIZE', 2048 ); + +  // ----- File list separator +  define( 'ARCHIVE_ZIP_SEPARATOR', ',' ); + +  // ----- Optional static temporary directory +  //       By default temporary files are generated in the script current +  //       path. +  //       If defined : +  //       - MUST BE terminated by a '/'. +  //       - MUST be a valid, already created directory +  //       Samples : +  // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '/temp/' ); +  // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', 'C:/Temp/' ); +  define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '' ); + +  // ----- Error codes +  define( 'ARCHIVE_ZIP_ERR_NO_ERROR', 0 ); +  define( 'ARCHIVE_ZIP_ERR_WRITE_OPEN_FAIL', -1 ); +  define( 'ARCHIVE_ZIP_ERR_READ_OPEN_FAIL', -2 ); +  define( 'ARCHIVE_ZIP_ERR_INVALID_PARAMETER', -3 ); +  define( 'ARCHIVE_ZIP_ERR_MISSING_FILE', -4 ); +  define( 'ARCHIVE_ZIP_ERR_FILENAME_TOO_LONG', -5 ); +  define( 'ARCHIVE_ZIP_ERR_INVALID_ZIP', -6 ); +  define( 'ARCHIVE_ZIP_ERR_BAD_EXTRACTED_FILE', -7 ); +  define( 'ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL', -8 ); +  define( 'ARCHIVE_ZIP_ERR_BAD_EXTENSION', -9 ); +  define( 'ARCHIVE_ZIP_ERR_BAD_FORMAT', -10 ); +  define( 'ARCHIVE_ZIP_ERR_DELETE_FILE_FAIL', -11 ); +  define( 'ARCHIVE_ZIP_ERR_RENAME_FILE_FAIL', -12 ); +  define( 'ARCHIVE_ZIP_ERR_BAD_CHECKSUM', -13 ); +  define( 'ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); +  define( 'ARCHIVE_ZIP_ERR_MISSING_OPTION_VALUE', -15 ); +  define( 'ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE', -16 ); + +  // ----- Warning codes +  define( 'ARCHIVE_ZIP_WARN_NO_WARNING', 0 ); +  define( 'ARCHIVE_ZIP_WARN_FILE_EXIST', 1 ); + +  // ----- Methods parameters +  define( 'ARCHIVE_ZIP_PARAM_PATH', 'path' ); +  define( 'ARCHIVE_ZIP_PARAM_ADD_PATH', 'add_path' ); +  define( 'ARCHIVE_ZIP_PARAM_REMOVE_PATH', 'remove_path' ); +  define( 'ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH', 'remove_all_path' ); +  define( 'ARCHIVE_ZIP_PARAM_SET_CHMOD', 'set_chmod' ); +  define( 'ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING', 'extract_as_string' ); +  define( 'ARCHIVE_ZIP_PARAM_NO_COMPRESSION', 'no_compression' ); +  define( 'ARCHIVE_ZIP_PARAM_BY_NAME', 'by_name' ); +  define( 'ARCHIVE_ZIP_PARAM_BY_INDEX', 'by_index' ); +  define( 'ARCHIVE_ZIP_PARAM_BY_EREG', 'by_ereg' ); +  define( 'ARCHIVE_ZIP_PARAM_BY_PREG', 'by_preg' ); + +  define( 'ARCHIVE_ZIP_PARAM_PRE_EXTRACT', 'callback_pre_extract' ); +  define( 'ARCHIVE_ZIP_PARAM_POST_EXTRACT', 'callback_post_extract' ); +  define( 'ARCHIVE_ZIP_PARAM_PRE_ADD', 'callback_pre_add' ); +  define( 'ARCHIVE_ZIP_PARAM_POST_ADD', 'callback_post_add' ); + + + +/** +* Class for manipulating zip archive files +* +* A class which provided common methods to manipulate ZIP formatted +* archive files. +* It provides creation, extraction, deletion and add features. +* +* @author   Vincent Blavet <vincent@blavet.net> +* @version  $Revision: 1.3 $ +* @package  phing.lib +*/ +class Archive_Zip +{ +    /** +    * The filename of the zip archive. +    * +    * @var string Name of the Zip file +    */ +    var $_zipname=''; + +    /** +    * File descriptor of the opened Zip file. +    * +    * @var int Internal zip file descriptor +    */ +    var $_zip_fd=0; + +    /** +    * @var int last error code +    */ +    var $_error_code=1; + +    /** +    * @var string Last error description +    */ +    var $_error_string=''; + +    // {{{ constructor +    /** +    * Archive_Zip Class constructor. This flavour of the constructor only +    * declare a new Archive_Zip object, identifying it by the name of the +    * zip file. +    * +    * @param    string  $p_zipname  The name of the zip archive to create +    * @access public +    */ +    function __construct($p_zipname) +    { +      if (!extension_loaded('zlib')) { +          throw new Exception("The extension 'zlib' couldn't be found.\n". +              "Please make sure your version of PHP was built ". +              "with 'zlib' support."); +      } + +      // ----- Set the attributes +      $this->_zipname = $p_zipname; +      $this->_zip_fd = 0; +    } +    // }}} + +    // {{{ create() +    /** +    * This method creates a Zip Archive with the filename set with +	* the constructor. +	* The files and directories indicated in $p_filelist +    * are added in the archive. +	* When a directory is in the list, the directory and its content is added +    * in the archive. +    * The methods takes a variable list of parameters in $p_params. +    * The supported parameters for this method are : +    *   'add_path' : Add a path to the archived files. +    *   'remove_path' : Remove the specified 'root' path of the archived files. +    *   'remove_all_path' : Remove all the path of the archived files. +    *   'no_compression' : The archived files will not be compressed. +    * +    * @access public +    * @param  mixed  $p_filelist  The list of the files or folders to add. +    *                             It can be a string with filenames separated +    *                             by a comma, or an array of filenames. +    * @param  mixed  $p_params  An array of variable parameters and values. +    * @return mixed An array of file description on success, +	*               an error code on error +    */ +    function create($p_filelist, $p_params=0) +    { +        $this->_errorReset(); + +        // ----- Set default values +        if ($p_params === 0) { +    	    $p_params = array(); +        } +        if ($this->_check_parameters($p_params, +	                                 array('no_compression' => false, +	                                       'add_path' => "", +	                                       'remove_path' => "", +	                                       'remove_all_path' => false)) != 1) { +		    return 0; +	    } + +        // ----- Look if the $p_filelist is really an array +        $p_result_list = array(); +        if (is_array($p_filelist)) { +            $v_result = $this->_create($p_filelist, $p_result_list, $p_params); +        } + +        // ----- Look if the $p_filelist is a string +        else if (is_string($p_filelist)) { +            // ----- Create a list with the elements from the string +            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); + +            $v_result = $this->_create($v_list, $p_result_list, $p_params); +        } + +        // ----- Invalid variable +        else { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +	                         'Invalid variable type p_filelist'); +            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; +        } + +        if ($v_result != 1) { +            return 0; +        } + +        return $p_result_list; +    } +    // }}} + +    // {{{ add() +    /** +    * This method add files or directory in an existing Zip Archive. +    * If the Zip Archive does not exist it is created. +	* The files and directories to add are indicated in $p_filelist. +	* When a directory is in the list, the directory and its content is added +    * in the archive. +    * The methods takes a variable list of parameters in $p_params. +    * The supported parameters for this method are : +    *   'add_path' : Add a path to the archived files. +    *   'remove_path' : Remove the specified 'root' path of the archived files. +    *   'remove_all_path' : Remove all the path of the archived files. +    *   'no_compression' : The archived files will not be compressed. +    *   'callback_pre_add' : A callback function that will be called before +    *                        each entry archiving. +    *   'callback_post_add' : A callback function that will be called after +    *                         each entry archiving. +    * +    * @access public +    * @param    mixed  $p_filelist  The list of the files or folders to add. +    *                               It can be a string with filenames separated +    *                               by a comma, or an array of filenames. +    * @param    mixed  $p_params  An array of variable parameters and values. +    * @return mixed An array of file description on success, +	*               0 on an unrecoverable failure, an error code is logged. +    */ +    function add($p_filelist, $p_params=0) +    { +        $this->_errorReset(); + +        // ----- Set default values +        if ($p_params === 0) { +        	$p_params = array(); +        } +        if ($this->_check_parameters($p_params, +	                                 array ('no_compression' => false, +	                                        'add_path' => '', +	                                        'remove_path' => '', +	                                        'remove_all_path' => false, +						    	     		'callback_pre_add' => '', +							    		    'callback_post_add' => '')) != 1) { +		    return 0; +	    } + +        // ----- Look if the $p_filelist is really an array +        $p_result_list = array(); +        if (is_array($p_filelist)) { +            // ----- Call the create fct +            $v_result = $this->_add($p_filelist, $p_result_list, $p_params); +        } + +        // ----- Look if the $p_filelist is a string +        else if (is_string($p_filelist)) { +            // ----- Create a list with the elements from the string +            $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); + +            // ----- Call the create fct +            $v_result = $this->_add($v_list, $p_result_list, $p_params); +        } + +        // ----- Invalid variable +        else { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +	                         "add() : Invalid variable type p_filelist"); +            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; +        } + +        if ($v_result != 1) { +            return 0; +        } + +        // ----- Return the result list +        return $p_result_list; +    } +    // }}} + +    // {{{ listContent() +    /** +    * This method gives the names and properties of the files and directories +	* which are present in the zip archive. +    * The properties of each entries in the list are : +    *   filename : Name of the file. +	*              For create() or add() it's the filename given by the user. +	*              For an extract() it's the filename of the extracted file. +    *   stored_filename : Name of the file / directory stored in the archive. +    *   size : Size of the stored file. +    *   compressed_size : Size of the file's data compressed in the archive +    *                     (without the zip headers overhead) +    *   mtime : Last known modification date of the file (UNIX timestamp) +    *   comment : Comment associated with the file +    *   folder : true | false (indicates if the entry is a folder) +    *   index : index of the file in the archive (-1 when not available) +    *   status : status of the action on the entry (depending of the action) : +    *            Values are : +    *              ok : OK ! +    *              filtered : the file/dir was not extracted (filtered by user) +    *              already_a_directory : the file can't be extracted because a +    *                                    directory with the same name already +	*                                    exists +    *              write_protected : the file can't be extracted because a file +    *                                with the same name already exists and is +    *                                write protected +    *              newer_exist : the file was not extracted because a newer +	*                            file already exists +    *              path_creation_fail : the file is not extracted because the +	*                                   folder does not exists and can't be +	*                                   created +    *              write_error : the file was not extracted because there was a +    *                            error while writing the file +    *              read_error : the file was not extracted because there was a +	*                           error while reading the file +    *              invalid_header : the file was not extracted because of an +	*                               archive format error (bad file header) +    * Note that each time a method can continue operating when there +    * is an error on a single file, the error is only logged in the file status. +    * +    * @access public +    * @return mixed An array of file description on success, +	*               0 on an unrecoverable failure, an error code is logged. +    */ +    function listContent() +    { +        $this->_errorReset(); + +        // ----- Check archive +        if (!$this->_checkFormat()) { +            return(0); +        } + +        $v_list = array(); +        if ($this->_list($v_list) != 1) { +            unset($v_list); +            return(0); +        } + +        return $v_list; +    } +    // }}} + +    // {{{ extract() +    /** +    * This method extract the files and folders which are in the zip archive. +    * It can extract all the archive or a part of the archive by using filter +    * feature (extract by name, by index, by ereg, by preg). The extraction +    * can occur in the current path or an other path. +    * All the advanced features are activated by the use of variable +	* parameters. +	* The return value is an array of entry descriptions which gives +	* information on extracted files (See listContent()). +	* The method may return a success value (an array) even if some files +	* are not correctly extracted (see the file status in listContent()). +    * The supported variable parameters for this method are : +    *   'add_path' : Path where the files and directories are to be extracted +    *   'remove_path' : First part ('root' part) of the memorized path +    *                   (if similar) to remove while extracting. +    *   'remove_all_path' : Remove all the memorized path while extracting. +    *   'extract_as_string' : +    *   'set_chmod' : After the extraction of the file the indicated mode +    *                 will be set. +    *   'by_name' : It can be a string with file/dir names separated by ',', +    *               or an array of file/dir names to extract from the archive. +    *   'by_index' : A string with range of indexes separated by ',', +    *                (sample "1,3-5,12"). +    *   'by_ereg' : A regular expression (ereg) that must match the extracted +    *               filename. +    *   'by_preg' : A regular expression (preg) that must match the extracted +    *               filename. +    *   'callback_pre_extract' : A callback function that will be called before +    *                            each entry extraction. +    *   'callback_post_extract' : A callback function that will be called after +    *                            each entry extraction. +    * +    * @access public +    * @param    mixed  $p_params  An array of variable parameters and values. +    * @return mixed An array of file description on success, +	*               0 on an unrecoverable failure, an error code is logged. +    */ +    function extract($p_params=0) +    { + +        $this->_errorReset(); + +        // ----- Check archive +        if (!$this->_checkFormat()) { +            return(0); +        } + +        // ----- Set default values +        if ($p_params === 0) { +        	$p_params = array(); +        } +        if ($this->_check_parameters($p_params, +	                                 array ('extract_as_string' => false, +	                                        'add_path' => '', +	                                        'remove_path' => '', +	                                        'remove_all_path' => false, +					    		     		'callback_pre_extract' => '', +						    			    'callback_post_extract' => '', +							    		    'set_chmod' => 0, +								    	    'by_name' => '', +									        'by_index' => '', +									        'by_ereg' => '', +									        'by_preg' => '') ) != 1) { +	    	return 0; +	    } + +        // ----- Call the extracting fct +        $v_list = array(); +        if ($this->_extractByRule($v_list, $p_params) != 1) { +            unset($v_list); +            return(0); +        } + +        return $v_list; +    } +    // }}} + + +    // {{{ delete() +    /** +    * This methods delete archive entries in the zip archive. +    * Notice that at least one filtering rule (set by the variable parameter +    * list) must be set. +    * Also notice that if you delete a folder entry, only the folder entry +    * is deleted, not all the files bellonging to this folder. +    * The supported variable parameters for this method are : +    *   'by_name' : It can be a string with file/dir names separated by ',', +    *               or an array of file/dir names to delete from the archive. +    *   'by_index' : A string with range of indexes separated by ',', +    *                (sample "1,3-5,12"). +    *   'by_ereg' : A regular expression (ereg) that must match the extracted +    *               filename. +    *   'by_preg' : A regular expression (preg) that must match the extracted +    *               filename. +    * +    * @access public +    * @param    mixed  $p_params  An array of variable parameters and values. +    * @return mixed An array of file description on success, +	*               0 on an unrecoverable failure, an error code is logged. +    */ +    function delete($p_params) +    { +        $this->_errorReset(); + +        // ----- Check archive +        if (!$this->_checkFormat()) { +            return(0); +        } + +        // ----- Set default values +        if ($this->_check_parameters($p_params, +	                                 array ('by_name' => '', +									        'by_index' => '', +									        'by_ereg' => '', +									        'by_preg' => '') ) != 1) { +	    	return 0; +    	} + +        // ----- Check that at least one rule is set +        if (   ($p_params['by_name'] == '') +            && ($p_params['by_index'] == '') +            && ($p_params['by_ereg'] == '') +            && ($p_params['by_preg'] == '')) { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +			                 'At least one filtering rule must' +							 .' be set as parameter'); +            return 0; +        } + +        // ----- Call the delete fct +        $v_list = array(); +        if ($this->_deleteByRule($v_list, $p_params) != 1) { +            unset($v_list); +            return(0); +        } + +        return $v_list; +    } +    // }}} + +    // {{{ properties() +    /** +    * This method gives the global properties of the archive. +    *  The properties are : +    *    nb : Number of files in the archive +    *    comment : Comment associated with the archive file +    *    status : not_exist, ok +    * +    * @access public +    * @param    mixed  $p_params  {Description} +    * @return mixed An array with the global properties or 0 on error. +    */ +    function properties() +    { +        $this->_errorReset(); + +        // ----- Check archive +        if (!$this->_checkFormat()) { +            return(0); +        } + +        // ----- Default properties +        $v_prop = array(); +        $v_prop['comment'] = ''; +        $v_prop['nb'] = 0; +        $v_prop['status'] = 'not_exist'; + +        // ----- Look if file exists +        if (@is_file($this->_zipname)) { +            // ----- Open the zip file +            if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) { +                $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +				                 'Unable to open archive \''.$this->_zipname +								 .'\' in binary read mode'); +                return 0; +            } + +            // ----- Read the central directory informations +            $v_central_dir = array(); +            if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { +                return 0; +            } + +            $this->_closeFd(); + +            // ----- Set the user attributes +            $v_prop['comment'] = $v_central_dir['comment']; +            $v_prop['nb'] = $v_central_dir['entries']; +            $v_prop['status'] = 'ok'; +        } + +        return $v_prop; +    } +    // }}} + + +    // {{{ duplicate() +    /** +    * This method creates an archive by copying the content of an other one. +	* If the archive already exist, it is replaced by the new one without +	* any warning. +    * +    * @access public +    * @param  mixed  $p_archive  It can be a valid Archive_Zip object or +	*                            the filename of a valid zip archive. +    * @return integer 1 on success, 0 on failure. +    */ +    function duplicate($p_archive) +    { +        $this->_errorReset(); + +        // ----- Look if the $p_archive is a Archive_Zip object +        if (   (is_object($p_archive)) +		    && (strtolower(get_class($p_archive)) == 'archive_zip')) { +            $v_result = $this->_duplicate($p_archive->_zipname); +        } + +        // ----- Look if the $p_archive is a string (so a filename) +        else if (is_string($p_archive)) { +            // ----- Check that $p_archive is a valid zip file +            // TBC : Should also check the archive format +            if (!is_file($p_archive)) { +                $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, +				                 "No file with filename '".$p_archive."'"); +                $v_result = ARCHIVE_ZIP_ERR_MISSING_FILE; +            } +            else { +                $v_result = $this->_duplicate($p_archive); +            } +        } + +        // ----- Invalid variable +        else { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +			                 "Invalid variable type p_archive_to_add"); +            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; +        } + +        return $v_result; +    } +    // }}} + +    // {{{ merge() +    /** +    *  This method merge a valid zip archive at the end of the +	*  archive identified by the Archive_Zip object. +    *  If the archive ($this) does not exist, the merge becomes a duplicate. +    *  If the archive to add does not exist, the merge is a success. +    * +    * @access public +    * @param mixed $p_archive_to_add  It can be a valid Archive_Zip object or +	*                                 the filename of a valid zip archive. +    * @return integer 1 on success, 0 on failure. +    */ +    function merge($p_archive_to_add) +    { +        $v_result = 1; +        $this->_errorReset(); + +        // ----- Check archive +        if (!$this->_checkFormat()) { +            return(0); +        } + +        // ----- Look if the $p_archive_to_add is a Archive_Zip object +        if (   (is_object($p_archive_to_add)) +		    && (strtolower(get_class($p_archive_to_add)) == 'archive_zip')) { +            $v_result = $this->_merge($p_archive_to_add); +        } + +        // ----- Look if the $p_archive_to_add is a string (so a filename) +        else if (is_string($p_archive_to_add)) { +            // ----- Create a temporary archive +            $v_object_archive = new Archive_Zip($p_archive_to_add); + +            // ----- Merge the archive +            $v_result = $this->_merge($v_object_archive); +        } + +        // ----- Invalid variable +        else { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +			                 "Invalid variable type p_archive_to_add"); +            $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; +        } + +        return $v_result; +    } +    // }}} + +    // {{{ errorCode() +    /** +    * Method that gives the lastest error code. +    * +    * @access public +    * @return integer The error code value. +    */ +    function errorCode() +    { +        return($this->_error_code); +    } +    // }}} + +    // {{{ errorName() +    /** +    * This method gives the latest error code name. +    * +    * @access public +    * @param  boolean $p_with_code  If true, gives the name and the int value. +    * @return string The error name. +    */ +    function errorName($p_with_code=false) +    { +        $v_const_list = get_defined_constants(); +  	 +      	// ----- Extract error constants from all const. +        for (reset($v_const_list); +		     list($v_key, $v_value) = each($v_const_list);) { +     	    if (substr($v_key, 0, strlen('ARCHIVE_ZIP_ERR_')) +			    =='ARCHIVE_ZIP_ERR_') { +    		    $v_error_list[$v_key] = $v_value; +    	    } +        } +     +        // ----- Search the name form the code value +        $v_key=array_search($this->_error_code, $v_error_list, true); +  	    if ($v_key!=false) { +            $v_value = $v_key; +  	    } +  	    else { +            $v_value = 'NoName'; +  	    } +  	 +        if ($p_with_code) { +            return($v_value.' ('.$this->_error_code.')'); +        } +        else { +          return($v_value); +        } +    } +    // }}} + +    // {{{ errorInfo() +    /** +    * This method returns the description associated with the latest error. +    * +    * @access public +    * @param  boolean $p_full If set to true gives the description with the +    *                         error code, the name and the description. +    *                         If set to false gives only the description +    *                         and the error code. +    * @return string The error description. +    */ +    function errorInfo($p_full=false) +    { +        if ($p_full) { +            return($this->errorName(true)." : ".$this->_error_string); +        } +        else { +            return($this->_error_string." [code ".$this->_error_code."]"); +        } +    } +    // }}} + + +// ----------------------------------------------------------------------------- +// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** +// *****                                                        ***** +// *****       THESES FUNCTIONS MUST NOT BE USED DIRECTLY       ***** +// ----------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _checkFormat() +  // Description : +  //   This method check that the archive exists and is a valid zip archive. +  //   Several level of check exists. (futur) +  // Parameters : +  //   $p_level : Level of check. Default 0. +  //              0 : Check the first bytes (magic codes) (default value)) +  //              1 : 0 + Check the central directory (futur) +  //              2 : 1 + Check each file header (futur) +  // Return Values : +  //   true on success, +  //   false on error, the error code is set. +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_checkFormat() +  * +  * { Description } +  * +  * @param integer $p_level +  */ +  function _checkFormat($p_level=0) +  { +    $v_result = true; + +    // ----- Reset the error handler +    $this->_errorReset(); + +    // ----- Look if the file exits +    if (!is_file($this->_zipname)) { +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, +	                   "Missing archive file '".$this->_zipname."'"); +      return(false); +    } + +    // ----- Check that the file is readeable +    if (!is_readable($this->_zipname)) { +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   "Unable to read archive '".$this->_zipname."'"); +      return(false); +    } + +    // ----- Check the magic code +    // TBC + +    // ----- Check the central header +    // TBC + +    // ----- Check each file header +    // TBC + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _create() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_create() +  * +  * { Description } +  * +  */ +  function _create($p_list, &$p_result_list, &$p_params) +  { +    $v_result=1; +    $v_list_detail = array(); + +	$p_add_dir = $p_params['add_path']; +	$p_remove_dir = $p_params['remove_path']; +	$p_remove_all_dir = $p_params['remove_all_path']; + +    // ----- Open the file in write mode +    if (($v_result = $this->_openFd('wb')) != 1) +    { +      // ----- Return +      return $v_result; +    } + +    // ----- Add the list of files +    $v_result = $this->_addList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); + +    // ----- Close +    $this->_closeFd(); + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _add() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_add() +  * +  * { Description } +  * +  */ +  function _add($p_list, &$p_result_list, &$p_params) +  { +    $v_result=1; +    $v_list_detail = array(); + +	$p_add_dir = $p_params['add_path']; +	$p_remove_dir = $p_params['remove_path']; +	$p_remove_all_dir = $p_params['remove_all_path']; + +    // ----- Look if the archive exists or is empty and need to be created +    if ((!is_file($this->_zipname)) || (filesize($this->_zipname) == 0)) { +      $v_result = $this->_create($p_list, $p_result_list, $p_params); +      return $v_result; +    } + +    // ----- Open the zip file +    if (($v_result=$this->_openFd('rb')) != 1) { +      return $v_result; +    } + +    // ----- Read the central directory informations +    $v_central_dir = array(); +    if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) +    { +      $this->_closeFd(); +      return $v_result; +    } + +    // ----- Go to beginning of File +    @rewind($this->_zip_fd); + +    // ----- Creates a temporay file +    $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; + +    // ----- Open the temporary file in write mode +    if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) +    { +      $this->_closeFd(); + +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   'Unable to open temporary file \'' +					   .$v_zip_temp_name.'\' in binary write mode'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Copy the files from the archive to the temporary file +    // TBC : Here I should better append the file and go back to erase the +	// central dir +    $v_size = $v_central_dir['offset']; +    while ($v_size != 0) +    { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = fread($this->_zip_fd, $v_read_size); +      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Swap the file descriptor +    // Here is a trick : I swap the temporary fd with the zip fd, in order to  +    // use the following methods on the temporary fil and not the real archive +    $v_swap = $this->_zip_fd; +    $this->_zip_fd = $v_zip_temp_fd; +    $v_zip_temp_fd = $v_swap; + +    // ----- Add the files +    $v_header_list = array(); +    if (($v_result = $this->_addFileList($p_list, $v_header_list, +	                                     $p_add_dir, $p_remove_dir, +										 $p_remove_all_dir, $p_params)) != 1) +    { +      fclose($v_zip_temp_fd); +      $this->_closeFd(); +      @unlink($v_zip_temp_name); + +      // ----- Return +      return $v_result; +    } + +    // ----- Store the offset of the central dir +    $v_offset = @ftell($this->_zip_fd); + +    // ----- Copy the block of file headers from the old archive +    $v_size = $v_central_dir['size']; +    while ($v_size != 0) +    { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = @fread($v_zip_temp_fd, $v_read_size); +      @fwrite($this->_zip_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Create the Central Dir files header +    for ($i=0, $v_count=0; $i<sizeof($v_header_list); $i++) +    { +      // ----- Create the file header +      if ($v_header_list[$i]['status'] == 'ok') { +        if (($v_result=$this->_writeCentralFileHeader($v_header_list[$i]))!=1) { +          fclose($v_zip_temp_fd); +          $this->_closeFd(); +          @unlink($v_zip_temp_name); + +          // ----- Return +          return $v_result; +        } +        $v_count++; +      } + +      // ----- Transform the header to a 'usable' info +      $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); +    } + +    // ----- Zip file comment +    $v_comment = ''; + +    // ----- Calculate the size of the central header +    $v_size = @ftell($this->_zip_fd)-$v_offset; + +    // ----- Create the central dir footer +    if (($v_result = $this->_writeCentralHeader($v_count +	                                              +$v_central_dir['entries'], +	                                            $v_size, $v_offset, +												$v_comment)) != 1) { +      // ----- Reset the file list +      unset($v_header_list); + +      // ----- Return +      return $v_result; +    } + +    // ----- Swap back the file descriptor +    $v_swap = $this->_zip_fd; +    $this->_zip_fd = $v_zip_temp_fd; +    $v_zip_temp_fd = $v_swap; + +    // ----- Close +    $this->_closeFd(); + +    // ----- Close the temporary file +    @fclose($v_zip_temp_fd); + +    // ----- Delete the zip file +    // TBC : I should test the result ... +    @unlink($this->_zipname); + +    // ----- Rename the temporary file +    // TBC : I should test the result ... +    //@rename($v_zip_temp_name, $this->_zipname); +    $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _openFd() +  // Description : +  // Parameters : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_openFd() +  * +  * { Description } +  * +  */ +  function _openFd($p_mode) +  { +    $v_result=1; + +    // ----- Look if already open +    if ($this->_zip_fd != 0) +    { +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   'Zip file \''.$this->_zipname.'\' already open'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Open the zip file +    if (($this->_zip_fd = @fopen($this->_zipname, $p_mode)) == 0) +    { +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   'Unable to open archive \''.$this->_zipname +					   .'\' in '.$p_mode.' mode'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _closeFd() +  // Description : +  // Parameters : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_closeFd() +  * +  * { Description } +  * +  */ +  function _closeFd() +  { +    $v_result=1; + +    if ($this->_zip_fd != 0) +      @fclose($this->_zip_fd); +    $this->_zip_fd = 0; + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _addList() +  // Description : +  //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is +  //   different from the real path of the file. This is usefull if you want to have PclTar +  //   running in any directory, and memorize relative path from an other directory. +  // Parameters : +  //   $p_list : An array containing the file or directory names to add in the tar +  //   $p_result_list : list of added files with their properties (specially the status field) +  //   $p_add_dir : Path to add in the filename path archived +  //   $p_remove_dir : Path to remove in the filename path archived +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_addList() +  * +  * { Description } +  * +  */ +  function _addList($p_list, &$p_result_list, +                    $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) +  { +    $v_result=1; + +    // ----- Add the files +    $v_header_list = array(); +    if (($v_result = $this->_addFileList($p_list, $v_header_list, +	                                     $p_add_dir, $p_remove_dir, +										 $p_remove_all_dir, $p_params)) != 1) { +      return $v_result; +    } + +    // ----- Store the offset of the central dir +    $v_offset = @ftell($this->_zip_fd); + +    // ----- Create the Central Dir files header +    for ($i=0,$v_count=0; $i<sizeof($v_header_list); $i++) +    { +      // ----- Create the file header +      if ($v_header_list[$i]['status'] == 'ok') { +        if (($v_result = $this->_writeCentralFileHeader($v_header_list[$i])) != 1) { +          return $v_result; +        } +        $v_count++; +      } + +      // ----- Transform the header to a 'usable' info +      $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); +    } + +    // ----- Zip file comment +    $v_comment = ''; + +    // ----- Calculate the size of the central header +    $v_size = @ftell($this->_zip_fd)-$v_offset; + +    // ----- Create the central dir footer +    if (($v_result = $this->_writeCentralHeader($v_count, $v_size, $v_offset, +	                                            $v_comment)) != 1) +    { +      // ----- Reset the file list +      unset($v_header_list); + +      // ----- Return +      return $v_result; +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _addFileList() +  // Description : +  //   $p_add_dir and $p_remove_dir will give the ability to memorize a path which is +  //   different from the real path of the file. This is usefull if you want to +  //   run the lib in any directory, and memorize relative path from an other directory. +  // Parameters : +  //   $p_list : An array containing the file or directory names to add in the tar +  //   $p_result_list : list of added files with their properties (specially the status field) +  //   $p_add_dir : Path to add in the filename path archived +  //   $p_remove_dir : Path to remove in the filename path archived +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_addFileList() +  * +  * { Description } +  * +  */ +  function _addFileList($p_list, &$p_result_list, +                        $p_add_dir, $p_remove_dir, $p_remove_all_dir, +						&$p_params) +  { +    $v_result=1; +    $v_header = array(); + +    // ----- Recuperate the current number of elt in list +    $v_nb = sizeof($p_result_list); + +    // ----- Loop on the files +    for ($j=0; ($j<count($p_list)) && ($v_result==1); $j++) +    { +      // ----- Recuperate the filename +      $p_filename = $this->_tool_TranslateWinPath($p_list[$j], false); + +      // ----- Skip empty file names +      if ($p_filename == "") +      { +        continue; +      } + +      // ----- Check the filename +      if (!file_exists($p_filename)) +      { +        $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, +		                 "File '$p_filename' does not exists"); +        return Archive_Zip::errorCode(); +      } + +      // ----- Look if it is a file or a dir with no all pathnre move +      if ((is_file($p_filename)) || ((is_dir($p_filename)) && !$p_remove_all_dir)) { +        // ----- Add the file +        if (($v_result = $this->_addFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) +        { +          // ----- Return status +          return $v_result; +        } + +        // ----- Store the file infos +        $p_result_list[$v_nb++] = $v_header; +      } + +      // ----- Look for directory +      if (is_dir($p_filename)) +      { + +        // ----- Look for path +        if ($p_filename != ".") +          $v_path = $p_filename."/"; +        else +          $v_path = ""; + +        // ----- Read the directory for files and sub-directories +        $p_hdir = opendir($p_filename); +        $p_hitem = readdir($p_hdir); // '.' directory +        $p_hitem = readdir($p_hdir); // '..' directory +        while ($p_hitem = readdir($p_hdir)) +        { + +          // ----- Look for a file +          if (is_file($v_path.$p_hitem)) +          { + +            // ----- Add the file +            if (($v_result = $this->_addFile($v_path.$p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) +            { +              // ----- Return status +              return $v_result; +            } + +            // ----- Store the file infos +            $p_result_list[$v_nb++] = $v_header; +          } + +          // ----- Recursive call to _addFileList() +          else +          { + +            // ----- Need an array as parameter +            $p_temp_list[0] = $v_path.$p_hitem; +            $v_result = $this->_addFileList($p_temp_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); + +            // ----- Update the number of elements of the list +            $v_nb = sizeof($p_result_list); +          } +        } + +        // ----- Free memory for the recursive loop +        unset($p_temp_list); +        unset($p_hdir); +        unset($p_hitem); +      } +    } + +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _addFile() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_addFile() +  * +  * { Description } +  * +  */ +  function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) +  { +    $v_result=1; + +    if ($p_filename == "") +    { +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Calculate the stored filename +    $v_stored_filename = $p_filename; + +    // ----- Look for all path to remove +    if ($p_remove_all_dir) { +      $v_stored_filename = basename($p_filename); +    } +    // ----- Look for partial path remove +    else if ($p_remove_dir != "") +    { +      if (substr($p_remove_dir, -1) != '/') +        $p_remove_dir .= "/"; + +      if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) +      { +        if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) +          $p_remove_dir = "./".$p_remove_dir; +        if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) +          $p_remove_dir = substr($p_remove_dir, 2); +      } + +      $v_compare = $this->_tool_PathInclusion($p_remove_dir, $p_filename); +      if ($v_compare > 0) +//      if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) +      { + +        if ($v_compare == 2) { +          $v_stored_filename = ""; +        } +        else { +          $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); +        } +      } +    } +    // ----- Look for path to add +    if ($p_add_dir != "") +    { +      if (substr($p_add_dir, -1) == "/") +        $v_stored_filename = $p_add_dir.$v_stored_filename; +      else +        $v_stored_filename = $p_add_dir."/".$v_stored_filename; +    } + +    // ----- Filename (reduce the path of stored name) +    $v_stored_filename = $this->_tool_PathReduction($v_stored_filename); + + +    /* filename length moved after call-back in release 1.3 +    // ----- Check the path length +    if (strlen($v_stored_filename) > 0xFF) +    { +      // ----- Error log +      $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'"); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } +    */ + +    // ----- Set the file properties +    clearstatcache(); +    $p_header['version'] = 20; +    $p_header['version_extracted'] = 10; +    $p_header['flag'] = 0; +    $p_header['compression'] = 0; +    $p_header['mtime'] = filemtime($p_filename); +    $p_header['crc'] = 0; +    $p_header['compressed_size'] = 0; +    $p_header['size'] = filesize($p_filename); +    $p_header['filename_len'] = strlen($p_filename); +    $p_header['extra_len'] = 0; +    $p_header['comment_len'] = 0; +    $p_header['disk'] = 0; +    $p_header['internal'] = 0; +    $p_header['external'] = (is_file($p_filename)?0xFE49FFE0:0x41FF0010); +    $p_header['offset'] = 0; +    $p_header['filename'] = $p_filename; +    $p_header['stored_filename'] = $v_stored_filename; +    $p_header['extra'] = ''; +    $p_header['comment'] = ''; +    $p_header['status'] = 'ok'; +    $p_header['index'] = -1; + +    // ----- Look for pre-add callback +    if (   (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD])) +	    && ($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] != '')) { + +      // ----- Generate a local information +      $v_local_header = array(); +      $this->_convertHeader2FileInfo($p_header, $v_local_header); + +      // ----- Call the callback +      // Here I do not use call_user_func() because I need to send a reference to the +      // header. +      eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_ADD].'(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);'); +      if ($v_result == 0) { +        // ----- Change the file status +        $p_header['status'] = "skipped"; +        $v_result = 1; +      } + +      // ----- Update the informations +      // Only some fields can be modified +      if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { +        $p_header['stored_filename'] = $this->_tool_PathReduction($v_local_header['stored_filename']); +      } +    } + +    // ----- Look for empty stored filename +    if ($p_header['stored_filename'] == "") { +      $p_header['status'] = "filtered"; +    } + +    // ----- Check the path length +    if (strlen($p_header['stored_filename']) > 0xFF) { +      $p_header['status'] = 'filename_too_long'; +    } + +    // ----- Look if no error, or file not skipped +    if ($p_header['status'] == 'ok') { + +      // ----- Look for a file +      if (is_file($p_filename)) +      { +        // ----- Open the source file +        if (($v_file = @fopen($p_filename, "rb")) == 0) { +          $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); +          return Archive_Zip::errorCode(); +        } +         +        if ($p_params['no_compression']) { +          // ----- Read the file content +          $v_content_compressed = @fread($v_file, $p_header['size']); + +          // ----- Calculate the CRC +          $p_header['crc'] = crc32($v_content_compressed); +        } +        else { +          // ----- Read the file content +          $v_content = @fread($v_file, $p_header['size']); + +          // ----- Calculate the CRC +          $p_header['crc'] = crc32($v_content); + +          // ----- Compress the file +          $v_content_compressed = gzdeflate($v_content); +        } + +        // ----- Set header parameters +        $p_header['compressed_size'] = strlen($v_content_compressed); +        $p_header['compression'] = 8; + +        // ----- Call the header generation +        if (($v_result = $this->_writeFileHeader($p_header)) != 1) { +          @fclose($v_file); +          return $v_result; +        } + +        // ----- Write the compressed content +        $v_binary_data = pack('a'.$p_header['compressed_size'], $v_content_compressed); +        @fwrite($this->_zip_fd, $v_binary_data, $p_header['compressed_size']); + +        // ----- Close the file +        @fclose($v_file); +      } + +      // ----- Look for a directory +      else +      { +        // ----- Set the file properties +        $p_header['filename'] .= '/'; +        $p_header['filename_len']++; +        $p_header['size'] = 0; +        $p_header['external'] = 0x41FF0010;   // Value for a folder : to be checked + +        // ----- Call the header generation +        if (($v_result = $this->_writeFileHeader($p_header)) != 1) +        { +          return $v_result; +        } +      } +    } + +    // ----- Look for pre-add callback +    if (   (isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD])) +	    && ($p_params[ARCHIVE_ZIP_PARAM_POST_ADD] != '')) { + +      // ----- Generate a local information +      $v_local_header = array(); +      $this->_convertHeader2FileInfo($p_header, $v_local_header); + +      // ----- Call the callback +      // Here I do not use call_user_func() because I need to send a reference to the +      // header. +      eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_ADD].'(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);'); +      if ($v_result == 0) { +        // ----- Ignored +        $v_result = 1; +      } + +      // ----- Update the informations +      // Nothing can be modified +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _writeFileHeader() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_writeFileHeader() +  * +  * { Description } +  * +  */ +  function _writeFileHeader(&$p_header) +  { +    $v_result=1; + +    // TBC +    //for(reset($p_header); $key = key($p_header); next($p_header)) { +    //} + +    // ----- Store the offset position of the file +    $p_header['offset'] = ftell($this->_zip_fd); + +    // ----- Transform UNIX mtime to DOS format mdate/mtime +    $v_date = getdate($p_header['mtime']); +    $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; +    $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + +    // ----- Packed data +    $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version'], $p_header['flag'], +                          $p_header['compression'], $v_mtime, $v_mdate, +                          $p_header['crc'], $p_header['compressed_size'], $p_header['size'], +                          strlen($p_header['stored_filename']), $p_header['extra_len']); + +    // ----- Write the first 148 bytes of the header in the archive +    fputs($this->_zip_fd, $v_binary_data, 30); + +    // ----- Write the variable fields +    if (strlen($p_header['stored_filename']) != 0) +    { +      fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); +    } +    if ($p_header['extra_len'] != 0) +    { +      fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _writeCentralFileHeader() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_writeCentralFileHeader() +  * +  * { Description } +  * +  */ +  function _writeCentralFileHeader(&$p_header) +  { +    $v_result=1; + +    // TBC +    //for(reset($p_header); $key = key($p_header); next($p_header)) { +    //} + +    // ----- Transform UNIX mtime to DOS format mdate/mtime +    $v_date = getdate($p_header['mtime']); +    $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; +    $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; + +    // ----- Packed data +    $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], +                          $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], +                          $p_header['compressed_size'], $p_header['size'], +                          strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], +                          $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); + +    // ----- Write the 42 bytes of the header in the zip file +    fputs($this->_zip_fd, $v_binary_data, 46); + +    // ----- Write the variable fields +    if (strlen($p_header['stored_filename']) != 0) +    { +      fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); +    } +    if ($p_header['extra_len'] != 0) +    { +      fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); +    } +    if ($p_header['comment_len'] != 0) +    { +      fputs($this->_zip_fd, $p_header['comment'], $p_header['comment_len']); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _writeCentralHeader() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_writeCentralHeader() +  * +  * { Description } +  * +  */ +  function _writeCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) +  { +    $v_result=1; + +    // ----- Packed data +    $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); + +    // ----- Write the 22 bytes of the header in the zip file +    fputs($this->_zip_fd, $v_binary_data, 22); + +    // ----- Write the variable fields +    if (strlen($p_comment) != 0) +    { +      fputs($this->_zip_fd, $p_comment, strlen($p_comment)); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _list() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_list() +  * +  * { Description } +  * +  */ +  function _list(&$p_list) +  { +    $v_result=1; + +    // ----- Open the zip file +    if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) +    { +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->_zipname.'\' in binary read mode'); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Read the central directory informations +    $v_central_dir = array(); +    if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) +    { +      return $v_result; +    } + +    // ----- Go to beginning of Central Dir +    @rewind($this->_zip_fd); +    if (@fseek($this->_zip_fd, $v_central_dir['offset'])) +    { +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Read each entry +    for ($i=0; $i<$v_central_dir['entries']; $i++) +    { +      // ----- Read the file header +      if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) +      { +        return $v_result; +      } +      $v_header['index'] = $i; + +      // ----- Get the only interesting attributes +      $this->_convertHeader2FileInfo($v_header, $p_list[$i]); +      unset($v_header); +    } + +    // ----- Close the zip file +    $this->_closeFd(); + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _convertHeader2FileInfo() +  // Description : +  //   This function takes the file informations from the central directory +  //   entries and extract the interesting parameters that will be given back. +  //   The resulting file infos are set in the array $p_info +  //     $p_info['filename'] : Filename with full path. Given by user (add), +  //                           extracted in the filesystem (extract). +  //     $p_info['stored_filename'] : Stored filename in the archive. +  //     $p_info['size'] = Size of the file. +  //     $p_info['compressed_size'] = Compressed size of the file. +  //     $p_info['mtime'] = Last modification date of the file. +  //     $p_info['comment'] = Comment associated with the file. +  //     $p_info['folder'] = true/false : indicates if the entry is a folder or not. +  //     $p_info['status'] = status of the action on the file. +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_convertHeader2FileInfo() +  * +  * { Description } +  * +  */ +  function _convertHeader2FileInfo($p_header, &$p_info) +  { +    $v_result=1; + +    // ----- Get the interesting attributes +    $p_info['filename'] = $p_header['filename']; +    $p_info['stored_filename'] = $p_header['stored_filename']; +    $p_info['size'] = $p_header['size']; +    $p_info['compressed_size'] = $p_header['compressed_size']; +    $p_info['mtime'] = $p_header['mtime']; +    $p_info['comment'] = $p_header['comment']; +    $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); +    $p_info['index'] = $p_header['index']; +    $p_info['status'] = $p_header['status']; + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _extractByRule() +  // Description : +  //   Extract a file or directory depending of rules (by index, by name, ...) +  // Parameters : +  //   $p_file_list : An array where will be placed the properties of each +  //                  extracted file +  //   $p_path : Path to add while writing the extracted files +  //   $p_remove_path : Path to remove (from the file memorized path) while writing the +  //                    extracted files. If the path does not match the file path, +  //                    the file is extracted with its memorized path. +  //                    $p_remove_path does not apply to 'list' mode. +  //                    $p_path and $p_remove_path are commulative. +  // Return Values : +  //   1 on success,0 or less on error (see error code list) +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_extractByRule() +  * +  * { Description } +  * +  */ +  function _extractByRule(&$p_file_list, &$p_params) +  { +    $v_result=1; + +	$p_path = $p_params['add_path']; +	$p_remove_path = $p_params['remove_path']; +	$p_remove_all_path = $p_params['remove_all_path']; + +    // ----- Check the path +    if (($p_path == "") +	    || ((substr($p_path, 0, 1) != "/") +	    && (substr($p_path, 0, 3) != "../") && (substr($p_path,1,2)!=":/"))) +      $p_path = "./".$p_path; + +    // ----- Reduce the path last (and duplicated) '/' +    if (($p_path != "./") && ($p_path != "/")) { +      // ----- Look for the path end '/' +      while (substr($p_path, -1) == "/") { +        $p_path = substr($p_path, 0, strlen($p_path)-1); +      } +    } + +    // ----- Look for path to remove format (should end by /) +    if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { +      $p_remove_path .= '/'; +    } +    $p_remove_path_size = strlen($p_remove_path); + +    // ----- Open the zip file +    if (($v_result = $this->_openFd('rb')) != 1) +    { +      return $v_result; +    } + +    // ----- Read the central directory informations +    $v_central_dir = array(); +    if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) +    { +      // ----- Close the zip file +      $this->_closeFd(); + +      return $v_result; +    } + +    // ----- Start at beginning of Central Dir +    $v_pos_entry = $v_central_dir['offset']; + +    // ----- Read each entry +    $j_start = 0; +    for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { +      // ----- Read next Central dir entry +      @rewind($this->_zip_fd); +      if (@fseek($this->_zip_fd, $v_pos_entry)) { +        $this->_closeFd(); + +        $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, +		                 'Invalid archive size'); + +        return Archive_Zip::errorCode(); +      } + +      // ----- Read the file header +      $v_header = array(); +      if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) { +        $this->_closeFd(); + +        return $v_result; +      } + +      // ----- Store the index +      $v_header['index'] = $i; + +      // ----- Store the file position +      $v_pos_entry = ftell($this->_zip_fd); + +      // ----- Look for the specific extract rules +      $v_extract = false; + +      // ----- Look for extract by name rule +      if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) +          && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { + +          // ----- Look if the filename is in the list +          for ($j=0; +		          ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) +			   && (!$v_extract); +			   $j++) { + +              // ----- Look for a directory +              if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1) == "/") { + +                  // ----- Look if the directory is in the filename path +                  if (   (strlen($v_header['stored_filename']) > strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) +                      && (substr($v_header['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { +                      $v_extract = true; +                  } +              } +              // ----- Look for a filename +              elseif ($v_header['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { +                  $v_extract = true; +              } +          } +      } + +      // ----- Look for extract by ereg rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { + +          if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], $v_header['stored_filename'])) { +              $v_extract = true; +          } +      } + +      // ----- Look for extract by preg rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { + +          if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header['stored_filename'])) { +              $v_extract = true; +          } +      } + +      // ----- Look for extract by index rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { + +          // ----- Look if the index is in the list +          for ($j=$j_start; ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) && (!$v_extract); $j++) { + +              if (($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { +                  $v_extract = true; +              } +              if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { +                  $j_start = $j+1; +              } + +              if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { +                  break; +              } +          } +      } + +      // ----- Look for no rule, which means extract all the archive +      else { +          $v_extract = true; +      } + + +      // ----- Look for real extraction +      if ($v_extract) +      { + +        // ----- Go to the file position +        @rewind($this->_zip_fd); +        if (@fseek($this->_zip_fd, $v_header['offset'])) +        { +          // ----- Close the zip file +          $this->_closeFd(); + +          // ----- Error log +          $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); + +          // ----- Return +          return Archive_Zip::errorCode(); +        } + +        // ----- Look for extraction as string +        if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]) { + +          // ----- Extracting the file +          if (($v_result = $this->_extractFileAsString($v_header, $v_string)) != 1) +          { +            // ----- Close the zip file +            $this->_closeFd(); + +            return $v_result; +          } + +          // ----- Get the only interesting attributes +          if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) +          { +            // ----- Close the zip file +            $this->_closeFd(); + +            return $v_result; +          } + +          // ----- Set the file content +          $p_file_list[$v_nb_extracted]['content'] = $v_string; + +          // ----- Next extracted file +          $v_nb_extracted++; +        } +        else { +          // ----- Extracting the file +          if (($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params)) != 1) +          { +            // ----- Close the zip file +            $this->_closeFd(); + +            return $v_result; +          } + +          // ----- Get the only interesting attributes +          if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) +          { +            // ----- Close the zip file +            $this->_closeFd(); + +            return $v_result; +          } +        } +      } +    } + +    // ----- Close the zip file +    $this->_closeFd(); + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _extractFile() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_extractFile() +  * +  * { Description } +  * +  */ +  function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_params) +  { +    $v_result=1; + +    // ----- Read the file header +    if (($v_result = $this->_readFileHeader($v_header)) != 1) +    { +      // ----- Return +      return $v_result; +    } + + +    // ----- Check that the file header is coherent with $p_entry info +    // TBC + +    // ----- Look for all path to remove +    if ($p_remove_all_path == true) { +        // ----- Get the basename of the path +        $p_entry['filename'] = basename($p_entry['filename']); +    } + +    // ----- Look for path to remove +    else if ($p_remove_path != "") +    { +      //if (strcmp($p_remove_path, $p_entry['filename'])==0) +      if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2) +      { + +        // ----- Change the file status +        $p_entry['status'] = "filtered"; + +        // ----- Return +        return $v_result; +      } + +      $p_remove_path_size = strlen($p_remove_path); +      if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) +      { + +        // ----- Remove the path +        $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); + +      } +    } + +    // ----- Add the path +    if ($p_path != '') +    { +      $p_entry['filename'] = $p_path."/".$p_entry['filename']; +    } + +    // ----- Look for pre-extract callback +    if (   (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])) +	    && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) { + +      // ----- Generate a local information +      $v_local_header = array(); +      $this->_convertHeader2FileInfo($p_entry, $v_local_header); + +      // ----- Call the callback +      // Here I do not use call_user_func() because I need to send a reference to the +      // header. +      eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);'); +      if ($v_result == 0) { +        // ----- Change the file status +        $p_entry['status'] = "skipped"; +        $v_result = 1; +      } + +      // ----- Update the informations +      // Only some fields can be modified +      $p_entry['filename'] = $v_local_header['filename']; +    } + +    // ----- Trace + +    // ----- Look if extraction should be done +    if ($p_entry['status'] == 'ok') { + +    // ----- Look for specific actions while the file exist +    if (file_exists($p_entry['filename'])) +    { + +      // ----- Look if file is a directory +      if (is_dir($p_entry['filename'])) +      { + +        // ----- Change the file status +        $p_entry['status'] = "already_a_directory"; + +        // ----- Return +        //return $v_result; +      } +      // ----- Look if file is write protected +      else if (!is_writeable($p_entry['filename'])) +      { + +        // ----- Change the file status +        $p_entry['status'] = "write_protected"; + +        // ----- Return +        //return $v_result; +      } + +      // ----- Look if the extracted file is older +      else if (filemtime($p_entry['filename']) > $p_entry['mtime']) +      { + +        // ----- Change the file status +        $p_entry['status'] = "newer_exist"; + +        // ----- Return +        //return $v_result; +      } +    } + +    // ----- Check the directory availability and create it if necessary +    else { +      if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) +        $v_dir_to_check = $p_entry['filename']; +      else if (!strstr($p_entry['filename'], "/")) +        $v_dir_to_check = ""; +      else +        $v_dir_to_check = dirname($p_entry['filename']); + +      if (($v_result = $this->_dirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { + +        // ----- Change the file status +        $p_entry['status'] = "path_creation_fail"; + +        // ----- Return +        //return $v_result; +        $v_result = 1; +      } +    } +    } + +    // ----- Look if extraction should be done +    if ($p_entry['status'] == 'ok') { + +      // ----- Do the extraction (if not a folder) +      if (!(($p_entry['external']&0x00000010)==0x00000010)) +      { + +        // ----- Look for not compressed file +        if ($p_entry['compressed_size'] == $p_entry['size']) +        { + +          // ----- Opening destination file +          if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) +          { + +            // ----- Change the file status +            $p_entry['status'] = "write_error"; + +            // ----- Return +            return $v_result; +          } + + +          // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks +          $v_size = $p_entry['compressed_size']; +          while ($v_size != 0) +          { +            $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +            $v_buffer = fread($this->_zip_fd, $v_read_size); +            $v_binary_data = pack('a'.$v_read_size, $v_buffer); +            @fwrite($v_dest_file, $v_binary_data, $v_read_size); +            $v_size -= $v_read_size; +          } + +          // ----- Closing the destination file +          fclose($v_dest_file); + +          // ----- Change the file mtime +          touch($p_entry['filename'], $p_entry['mtime']); +        } +        else +        { +          // ----- Trace + +          // ----- Opening destination file +          if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { + +            // ----- Change the file status +            $p_entry['status'] = "write_error"; + +            return $v_result; +          } + + +          // ----- Read the compressed file in a buffer (one shot) +          $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']); + +          // ----- Decompress the file +          $v_file_content = gzinflate($v_buffer); +          unset($v_buffer); + +          // ----- Write the uncompressed data +          @fwrite($v_dest_file, $v_file_content, $p_entry['size']); +          unset($v_file_content); + +          // ----- Closing the destination file +          @fclose($v_dest_file); + +          // ----- Change the file mtime +          touch($p_entry['filename'], $p_entry['mtime']); +        } + +        // ----- Look for chmod option +        if (   (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])) +		    && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) { + +          // ----- Change the mode of the file +          chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]); +        } + +      } +    } + +    // ----- Look for post-extract callback +    if (   (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])) +	    && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) { + +      // ----- Generate a local information +      $v_local_header = array(); +      $this->_convertHeader2FileInfo($p_entry, $v_local_header); + +      // ----- Call the callback +      // Here I do not use call_user_func() because I need to send a reference to the +      // header. +      eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);'); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _extractFileAsString() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_extractFileAsString() +  * +  * { Description } +  * +  */ +  function _extractFileAsString(&$p_entry, &$p_string) +  { +    $v_result=1; + +    // ----- Read the file header +    $v_header = array(); +    if (($v_result = $this->_readFileHeader($v_header)) != 1) +    { +      // ----- Return +      return $v_result; +    } + + +    // ----- Check that the file header is coherent with $p_entry info +    // TBC + +    // ----- Trace + +    // ----- Do the extraction (if not a folder) +    if (!(($p_entry['external']&0x00000010)==0x00000010)) +    { +      // ----- Look for not compressed file +      if ($p_entry['compressed_size'] == $p_entry['size']) +      { +        // ----- Trace + +        // ----- Reading the file +        $p_string = fread($this->_zip_fd, $p_entry['compressed_size']); +      } +      else +      { +        // ----- Trace + +        // ----- Reading the file +        $v_data = fread($this->_zip_fd, $p_entry['compressed_size']); + +        // ----- Decompress the file +        $p_string = gzinflate($v_data); +      } + +      // ----- Trace +    } +    else { +        // TBC : error : can not extract a folder in a string +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _readFileHeader() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_readFileHeader() +  * +  * { Description } +  * +  */ +  function _readFileHeader(&$p_header) +  { +    $v_result=1; + +    // ----- Read the 4 bytes signature +    $v_binary_data = @fread($this->_zip_fd, 4); +    $v_data = unpack('Vid', $v_binary_data); + +    // ----- Check signature +    if ($v_data['id'] != 0x04034b50) +    { + +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Read the first 42 bytes of the header +    $v_binary_data = fread($this->_zip_fd, 26); + +    // ----- Look for invalid block size +    if (strlen($v_binary_data) != 26) +    { +      $p_header['filename'] = ""; +      $p_header['status'] = "invalid_header"; + +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Extract the values +    $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); + +    // ----- Get filename +    $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']); + +    // ----- Get extra_fields +    if ($v_data['extra_len'] != 0) { +      $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']); +    } +    else { +      $p_header['extra'] = ''; +    } + +    // ----- Extract properties +    $p_header['compression'] = $v_data['compression']; +    $p_header['size'] = $v_data['size']; +    $p_header['compressed_size'] = $v_data['compressed_size']; +    $p_header['crc'] = $v_data['crc']; +    $p_header['flag'] = $v_data['flag']; + +    // ----- Recuperate date in UNIX format +    $p_header['mdate'] = $v_data['mdate']; +    $p_header['mtime'] = $v_data['mtime']; +    if ($p_header['mdate'] && $p_header['mtime']) +    { +      // ----- Extract time +      $v_hour = ($p_header['mtime'] & 0xF800) >> 11; +      $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; +      $v_seconde = ($p_header['mtime'] & 0x001F)*2; + +      // ----- Extract date +      $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; +      $v_month = ($p_header['mdate'] & 0x01E0) >> 5; +      $v_day = $p_header['mdate'] & 0x001F; + +      // ----- Get UNIX date format +      $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + +    } +    else +    { +      $p_header['mtime'] = time(); +    } + +    // ----- Other informations + +    // TBC +    //for(reset($v_data); $key = key($v_data); next($v_data)) { +    //} + +    // ----- Set the stored filename +    $p_header['stored_filename'] = $p_header['filename']; + +    // ----- Set the status field +    $p_header['status'] = "ok"; + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _readCentralFileHeader() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_readCentralFileHeader() +  * +  * { Description } +  * +  */ +  function _readCentralFileHeader(&$p_header) +  { +    $v_result=1; + +    // ----- Read the 4 bytes signature +    $v_binary_data = @fread($this->_zip_fd, 4); +    $v_data = unpack('Vid', $v_binary_data); + +    // ----- Check signature +    if ($v_data['id'] != 0x02014b50) +    { + +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Read the first 42 bytes of the header +    $v_binary_data = fread($this->_zip_fd, 42); + +    // ----- Look for invalid block size +    if (strlen($v_binary_data) != 42) +    { +      $p_header['filename'] = ""; +      $p_header['status'] = "invalid_header"; + +      // ----- Error log +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); + +      // ----- Return +      return Archive_Zip::errorCode(); +    } + +    // ----- Extract the values +    $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); + +    // ----- Get filename +    if ($p_header['filename_len'] != 0) +      $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']); +    else +      $p_header['filename'] = ''; + +    // ----- Get extra +    if ($p_header['extra_len'] != 0) +      $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']); +    else +      $p_header['extra'] = ''; + +    // ----- Get comment +    if ($p_header['comment_len'] != 0) +      $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']); +    else +      $p_header['comment'] = ''; + +    // ----- Extract properties + +    // ----- Recuperate date in UNIX format +    if ($p_header['mdate'] && $p_header['mtime']) +    { +      // ----- Extract time +      $v_hour = ($p_header['mtime'] & 0xF800) >> 11; +      $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; +      $v_seconde = ($p_header['mtime'] & 0x001F)*2; + +      // ----- Extract date +      $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; +      $v_month = ($p_header['mdate'] & 0x01E0) >> 5; +      $v_day = $p_header['mdate'] & 0x001F; + +      // ----- Get UNIX date format +      $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); + +    } +    else +    { +      $p_header['mtime'] = time(); +    } + +    // ----- Set the stored filename +    $p_header['stored_filename'] = $p_header['filename']; + +    // ----- Set default status to ok +    $p_header['status'] = 'ok'; + +    // ----- Look if it is a directory +    if (substr($p_header['filename'], -1) == '/') +    { +      $p_header['external'] = 0x41FF0010; +    } + + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _readEndCentralDir() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_readEndCentralDir() +  * +  * { Description } +  * +  */ +  function _readEndCentralDir(&$p_central_dir) +  { +    $v_result=1; + +    // ----- Go to the end of the zip file +    $v_size = filesize($this->_zipname); +    @fseek($this->_zip_fd, $v_size); +    if (@ftell($this->_zip_fd) != $v_size) { +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +	                   'Unable to go to the end of the archive \'' +					   .$this->_zipname.'\''); +      return Archive_Zip::errorCode(); +    } + +    // ----- First try : look if this is an archive with no commentaries +	// (most of the time) +    // in this case the end of central dir is at 22 bytes of the file end +    $v_found = 0; +    if ($v_size > 26) { +      @fseek($this->_zip_fd, $v_size-22); +      if (($v_pos = @ftell($this->_zip_fd)) != ($v_size-22)) { +        $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +		                 'Unable to seek back to the middle of the archive \'' +						 .$this->_zipname.'\''); +        return Archive_Zip::errorCode(); +      } + +      // ----- Read for bytes +      $v_binary_data = @fread($this->_zip_fd, 4); +      $v_data = unpack('Vid', $v_binary_data); + +      // ----- Check signature +      if ($v_data['id'] == 0x06054b50) { +        $v_found = 1; +      } + +      $v_pos = ftell($this->_zip_fd); +    } + +    // ----- Go back to the maximum possible size of the Central Dir End Record +    if (!$v_found) { +      $v_maximum_size = 65557; // 0xFFFF + 22; +      if ($v_maximum_size > $v_size) +        $v_maximum_size = $v_size; +      @fseek($this->_zip_fd, $v_size-$v_maximum_size); +      if (@ftell($this->_zip_fd) != ($v_size-$v_maximum_size)) { +        $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +		                 'Unable to seek back to the middle of the archive \'' +						 .$this->_zipname.'\''); +        return Archive_Zip::errorCode(); +      } + +      // ----- Read byte per byte in order to find the signature +      $v_pos = ftell($this->_zip_fd); +      $v_bytes = 0x00000000; +      while ($v_pos < $v_size) { +        // ----- Read a byte +        $v_byte = @fread($this->_zip_fd, 1); + +        // -----  Add the byte +        $v_bytes = ($v_bytes << 8) | Ord($v_byte); + +        // ----- Compare the bytes +        if ($v_bytes == 0x504b0506) { +          $v_pos++; +          break; +        } + +        $v_pos++; +      } + +      // ----- Look if not found end of central dir +      if ($v_pos == $v_size) { +        $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +		                 "Unable to find End of Central Dir Record signature"); +        return Archive_Zip::errorCode(); +      } +    } + +    // ----- Read the first 18 bytes of the header +    $v_binary_data = fread($this->_zip_fd, 18); + +    // ----- Look for invalid block size +    if (strlen($v_binary_data) != 18) { +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +	                   "Invalid End of Central Dir Record size : " +					   .strlen($v_binary_data)); +      return Archive_Zip::errorCode(); +    } + +    // ----- Extract the values +    $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); + +    // ----- Check the global size +    if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { +      $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, +	                   "Fail to find the right signature"); +      return Archive_Zip::errorCode(); +    } + +    // ----- Get comment +    if ($v_data['comment_size'] != 0) +      $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']); +    else +      $p_central_dir['comment'] = ''; + +    $p_central_dir['entries'] = $v_data['entries']; +    $p_central_dir['disk_entries'] = $v_data['disk_entries']; +    $p_central_dir['offset'] = $v_data['offset']; +    $p_central_dir['size'] = $v_data['size']; +    $p_central_dir['disk'] = $v_data['disk']; +    $p_central_dir['disk_start'] = $v_data['disk_start']; + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _deleteByRule() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_deleteByRule() +  * +  * { Description } +  * +  */ +  function _deleteByRule(&$p_result_list, &$p_params) +  { +    $v_result=1; +    $v_list_detail = array(); + +    // ----- Open the zip file +    if (($v_result=$this->_openFd('rb')) != 1) +    { +      // ----- Return +      return $v_result; +    } + +    // ----- Read the central directory informations +    $v_central_dir = array(); +    if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) +    { +      $this->_closeFd(); +      return $v_result; +    } + +    // ----- Go to beginning of File +    @rewind($this->_zip_fd); + +    // ----- Scan all the files +    // ----- Start at beginning of Central Dir +    $v_pos_entry = $v_central_dir['offset']; +    @rewind($this->_zip_fd); +    if (@fseek($this->_zip_fd, $v_pos_entry)) { +      // ----- Clean +      $this->_closeFd(); + +      $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, +	                   'Invalid archive size'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Read each entry +    $v_header_list = array(); +    $j_start = 0; +    for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { + +      // ----- Read the file header +      $v_header_list[$v_nb_extracted] = array(); +      $v_result +	    = $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]); +      if ($v_result != 1) { +        // ----- Clean +        $this->_closeFd(); + +        return $v_result; +      } + +      // ----- Store the index +      $v_header_list[$v_nb_extracted]['index'] = $i; + +      // ----- Look for the specific extract rules +      $v_found = false; + +      // ----- Look for extract by name rule +      if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) +          && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { + +          // ----- Look if the filename is in the list +          for ($j=0; +		       ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) +			     && (!$v_found); +			   $j++) { + +              // ----- Look for a directory +              if (substr($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j], -1) == "/") { + +                  // ----- Look if the directory is in the filename path +                  if (   (strlen($v_header_list[$v_nb_extracted]['stored_filename']) > strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) +                      && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { +                      $v_found = true; +                  } +                  elseif (   (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ +                          && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { +                      $v_found = true; +                  } +              } +              // ----- Look for a filename +              elseif ($v_header_list[$v_nb_extracted]['stored_filename'] +			          == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { +                  $v_found = true; +              } +          } +      } + +      // ----- Look for extract by ereg rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { + +          if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], +		           $v_header_list[$v_nb_extracted]['stored_filename'])) { +              $v_found = true; +          } +      } + +      // ----- Look for extract by preg rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { + +          if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], +		                 $v_header_list[$v_nb_extracted]['stored_filename'])) { +              $v_found = true; +          } +      } + +      // ----- Look for extract by index rule +      else if (   (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) +               && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { + +          // ----- Look if the index is in the list +          for ($j=$j_start; +		       ($j<sizeof($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) +			     && (!$v_found); +			   $j++) { + +              if (   ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) +			      && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { +                  $v_found = true; +              } +              if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { +                  $j_start = $j+1; +              } + +              if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { +                  break; +              } +          } +      } + +      // ----- Look for deletion +      if ($v_found) { +        unset($v_header_list[$v_nb_extracted]); +      } +      else { +        $v_nb_extracted++; +      } +    } + +    // ----- Look if something need to be deleted +    if ($v_nb_extracted > 0) { + +        // ----- Creates a temporay file +        $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-') +		                   .'.tmp'; + +        // ----- Creates a temporary zip archive +        $v_temp_zip = new Archive_Zip($v_zip_temp_name); + +        // ----- Open the temporary zip file in write mode +        if (($v_result = $v_temp_zip->_openFd('wb')) != 1) { +            $this->_closeFd(); + +            // ----- Return +            return $v_result; +        } + +        // ----- Look which file need to be kept +        for ($i=0; $i<sizeof($v_header_list); $i++) { + +            // ----- Calculate the position of the header +            @rewind($this->_zip_fd); +            if (@fseek($this->_zip_fd,  $v_header_list[$i]['offset'])) { +                // ----- Clean +                $this->_closeFd(); +                $v_temp_zip->_closeFd(); +                @unlink($v_zip_temp_name); + +                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, +				                 'Invalid archive size'); +                return Archive_Zip::errorCode(); +            } + +            // ----- Read the file header +            if (($v_result = $this->_readFileHeader($v_header_list[$i])) != 1) { +                // ----- Clean +                $this->_closeFd(); +                $v_temp_zip->_closeFd(); +                @unlink($v_zip_temp_name); + +                return $v_result; +            } + +            // ----- Write the file header +            $v_result = $v_temp_zip->_writeFileHeader($v_header_list[$i]); +            if ($v_result != 1) { +                // ----- Clean +                $this->_closeFd(); +                $v_temp_zip->_closeFd(); +                @unlink($v_zip_temp_name); + +                return $v_result; +            } + +            // ----- Read/write the data block +            $v_result = $this->_tool_CopyBlock($this->_zip_fd, +			                                   $v_temp_zip->_zip_fd, +								       $v_header_list[$i]['compressed_size']); +            if ($v_result != 1) { +                // ----- Clean +                $this->_closeFd(); +                $v_temp_zip->_closeFd(); +                @unlink($v_zip_temp_name); + +                return $v_result; +            } +        } + +        // ----- Store the offset of the central dir +        $v_offset = @ftell($v_temp_zip->_zip_fd); + +        // ----- Re-Create the Central Dir files header +        for ($i=0; $i<sizeof($v_header_list); $i++) { +            // ----- Create the file header +            $v_result=$v_temp_zip->_writeCentralFileHeader($v_header_list[$i]); +            if ($v_result != 1) { +            	// ----- Clean +                $v_temp_zip->_closeFd(); +                $this->_closeFd(); +                @unlink($v_zip_temp_name); + +                return $v_result; +            } + +            // ----- Transform the header to a 'usable' info +            $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i], +			                                     $p_result_list[$i]); +        } + + +        // ----- Zip file comment +        $v_comment = ''; + +        // ----- Calculate the size of the central header +        $v_size = @ftell($v_temp_zip->_zip_fd)-$v_offset; + +        // ----- Create the central dir footer +        $v_result = $v_temp_zip->_writeCentralHeader(sizeof($v_header_list), +		                                             $v_size, $v_offset, +													 $v_comment); +        if ($v_result != 1) { +            // ----- Clean +            unset($v_header_list); +            $v_temp_zip->_closeFd(); +            $this->_closeFd(); +            @unlink($v_zip_temp_name); + +            return $v_result; +        } + +        // ----- Close +        $v_temp_zip->_closeFd(); +        $this->_closeFd(); + +        // ----- Delete the zip file +        // TBC : I should test the result ... +        @unlink($this->_zipname); + +        // ----- Rename the temporary file +        // TBC : I should test the result ... +        //@rename($v_zip_temp_name, $this->_zipname); +        $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + +        // ----- Destroy the temporary archive +        unset($v_temp_zip); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _dirCheck() +  // Description : +  //   Check if a directory exists, if not it creates it and all the parents directory +  //   which may be useful. +  // Parameters : +  //   $p_dir : Directory path to check. +  // Return Values : +  //    1 : OK +  //   -1 : Unable to create directory +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_dirCheck() +  * +  * { Description } +  * +  * @param [type] $p_is_dir +  */ +  function _dirCheck($p_dir, $p_is_dir=false) +  { +    $v_result = 1; + +    // ----- Remove the final '/' +    if (($p_is_dir) && (substr($p_dir, -1)=='/')) { +      $p_dir = substr($p_dir, 0, strlen($p_dir)-1); +    } + +    // ----- Check the directory availability +    if ((is_dir($p_dir)) || ($p_dir == "")) { +      return 1; +    } + +    // ----- Extract parent directory +    $p_parent_dir = dirname($p_dir); + +    // ----- Just a check +    if ($p_parent_dir != $p_dir) { +      // ----- Look for parent directory +      if ($p_parent_dir != "") { +        if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) { +          return $v_result; +        } +      } +    } + +    // ----- Create the directory +    if (!@mkdir($p_dir, 0777)) { +      $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, +	                   "Unable to create directory '$p_dir'"); +      return Archive_Zip::errorCode(); +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _merge() +  // Description : +  //   If $p_archive_to_add does not exist, the function exit with a success result. +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_merge() +  * +  * { Description } +  * +  */ +  function _merge(&$p_archive_to_add) +  { +    $v_result=1; + +    // ----- Look if the archive_to_add exists +    if (!is_file($p_archive_to_add->_zipname)) { +      // ----- Nothing to merge, so merge is a success +      return 1; +    } + +    // ----- Look if the archive exists +    if (!is_file($this->_zipname)) { +      // ----- Do a duplicate +      $v_result = $this->_duplicate($p_archive_to_add->_zipname); + +      return $v_result; +    } + +    // ----- Open the zip file +    if (($v_result=$this->_openFd('rb')) != 1) { +      return $v_result; +    } + +    // ----- Read the central directory informations +    $v_central_dir = array(); +    if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { +      $this->_closeFd(); +      return $v_result; +    } + +    // ----- Go to beginning of File +    @rewind($this->_zip_fd); + +    // ----- Open the archive_to_add file +    if (($v_result=$p_archive_to_add->_openFd('rb')) != 1) { +      $this->_closeFd(); +      return $v_result; +    } + +    // ----- Read the central directory informations +    $v_central_dir_to_add = array(); +    $v_result = $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add); +    if ($v_result != 1) { +      $this->_closeFd(); +      $p_archive_to_add->_closeFd(); +      return $v_result; +    } + +    // ----- Go to beginning of File +    @rewind($p_archive_to_add->_zip_fd); + +    // ----- Creates a temporay file +    $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; + +    // ----- Open the temporary file in write mode +    if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { +      $this->_closeFd(); +      $p_archive_to_add->_closeFd(); +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   'Unable to open temporary file \'' +					   .$v_zip_temp_name.'\' in binary write mode'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Copy the files from the archive to the temporary file +    // TBC : Here I should better append the file and go back to erase the +	// central dir +    $v_size = $v_central_dir['offset']; +    while ($v_size != 0) { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = fread($this->_zip_fd, $v_read_size); +      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Copy the files from the archive_to_add into the temporary file +    $v_size = $v_central_dir_to_add['offset']; +    while ($v_size != 0) { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = fread($p_archive_to_add->_zip_fd, $v_read_size); +      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Store the offset of the central dir +    $v_offset = @ftell($v_zip_temp_fd); + +    // ----- Copy the block of file headers from the old archive +    $v_size = $v_central_dir['size']; +    while ($v_size != 0) { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = @fread($this->_zip_fd, $v_read_size); +      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Copy the block of file headers from the archive_to_add +    $v_size = $v_central_dir_to_add['size']; +    while ($v_size != 0) { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = @fread($p_archive_to_add->_zip_fd, $v_read_size); +      @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Zip file comment +    // TBC : I should merge the two comments +    $v_comment = ''; + +    // ----- Calculate the size of the (new) central header +    $v_size = @ftell($v_zip_temp_fd)-$v_offset; + +    // ----- Swap the file descriptor +    // Here is a trick : I swap the temporary fd with the zip fd, in order to use +    // the following methods on the temporary fil and not the real archive fd +    $v_swap = $this->_zip_fd; +    $this->_zip_fd = $v_zip_temp_fd; +    $v_zip_temp_fd = $v_swap; + +    // ----- Create the central dir footer +    if (($v_result = $this->_writeCentralHeader($v_central_dir['entries'] +	                                          +$v_central_dir_to_add['entries'], +												$v_size, $v_offset, +												$v_comment)) != 1) { +      $this->_closeFd(); +      $p_archive_to_add->_closeFd(); +      @fclose($v_zip_temp_fd); +      $this->_zip_fd = null; + +      // ----- Reset the file list +      unset($v_header_list); + +      // ----- Return +      return $v_result; +    } + +    // ----- Swap back the file descriptor +    $v_swap = $this->_zip_fd; +    $this->_zip_fd = $v_zip_temp_fd; +    $v_zip_temp_fd = $v_swap; + +    // ----- Close +    $this->_closeFd(); +    $p_archive_to_add->_closeFd(); + +    // ----- Close the temporary file +    @fclose($v_zip_temp_fd); + +    // ----- Delete the zip file +    // TBC : I should test the result ... +    @unlink($this->_zipname); + +    // ----- Rename the temporary file +    // TBC : I should test the result ... +    //@rename($v_zip_temp_name, $this->_zipname); +    $this->_tool_Rename($v_zip_temp_name, $this->_zipname); + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _duplicate() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_duplicate() +  * +  * { Description } +  * +  */ +  function _duplicate($p_archive_filename) +  { +    $v_result=1; + +    // ----- Look if the $p_archive_filename exists +    if (!is_file($p_archive_filename)) { + +      // ----- Nothing to duplicate, so duplicate is a success. +      $v_result = 1; + +      // ----- Return +      return $v_result; +    } + +    // ----- Open the zip file +    if (($v_result=$this->_openFd('wb')) != 1) { +      // ----- Return +      return $v_result; +    } + +    // ----- Open the temporary file in write mode +    if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { +      $this->_closeFd(); +      $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, +	                   'Unable to open archive file \'' +					   .$p_archive_filename.'\' in binary write mode'); +      return Archive_Zip::errorCode(); +    } + +    // ----- Copy the files from the archive to the temporary file +    // TBC : Here I should better append the file and go back to erase the +	// central dir +    $v_size = filesize($p_archive_filename); +    while ($v_size != 0) { +      $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +	                  ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +      $v_buffer = fread($v_zip_temp_fd, $v_read_size); +      @fwrite($this->_zip_fd, $v_buffer, $v_read_size); +      $v_size -= $v_read_size; +    } + +    // ----- Close +    $this->_closeFd(); + +    // ----- Close the temporary file +    @fclose($v_zip_temp_fd); + +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  /** +  * Archive_Zip::_check_parameters() +  * +  * { Description } +  * +  * @param integer $p_error_code +  * @param string $p_error_string +  */ +  function _check_parameters(&$p_params, $p_default) +  { +     +    // ----- Check that param is an array +    if (!is_array($p_params)) { +        $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +		                 'Unsupported parameter, waiting for an array'); +        return Archive_Zip::errorCode(); +    } +     +    // ----- Check that all the params are valid +    for (reset($p_params); list($v_key, $v_value) = each($p_params); ) { +    	if (!isset($p_default[$v_key])) { +            $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, +			                 'Unsupported parameter with key \''.$v_key.'\''); + +            return Archive_Zip::errorCode(); +    	} +    } + +	// ----- Set the default values +    for (reset($p_default); list($v_key, $v_value) = each($p_default); ) { +    	if (!isset($p_params[$v_key])) { +    		$p_params[$v_key] = $p_default[$v_key]; +    	} +    } +     +    // ----- Check specific parameters +    $v_callback_list = array ('callback_pre_add','callback_post_add', +	                          'callback_pre_extract','callback_post_extract'); +    for ($i=0; $i<sizeof($v_callback_list); $i++) { +    	$v_key=$v_callback_list[$i]; +        if (   (isset($p_params[$v_key])) && ($p_params[$v_key] != '')) { +            if (!function_exists($p_params[$v_key])) { +                $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, +				                 "Callback '".$p_params[$v_key] +								 ."()' is not an existing function for " +								 ."parameter '".$v_key."'"); +                return Archive_Zip::errorCode(); +            } +	    } +    } + +    return(1); +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _errorLog() +  // Description : +  // Parameters : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_errorLog() +  * +  * { Description } +  * +  * @param integer $p_error_code +  * @param string $p_error_string +  */ +  function _errorLog($p_error_code=0, $p_error_string='') +  { +      $this->_error_code = $p_error_code; +      $this->_error_string = $p_error_string; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : _errorReset() +  // Description : +  // Parameters : +  // --------------------------------------------------------------------------- +  /** +  * Archive_Zip::_errorReset() +  * +  * { Description } +  * +  */ +  function _errorReset() +  { +      $this->_error_code = 1; +      $this->_error_string = ''; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : $this->_tool_PathReduction() +  // Description : +  // Parameters : +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * _tool_PathReduction() +  * +  * { Description } +  * +  */ +  function _tool_PathReduction($p_dir) +  { +    $v_result = ""; + +    // ----- Look for not empty path +    if ($p_dir != "") +    { +      // ----- Explode path by directory names +      $v_list = explode("/", $p_dir); + +      // ----- Study directories from last to first +      for ($i=sizeof($v_list)-1; $i>=0; $i--) +      { +        // ----- Look for current path +        if ($v_list[$i] == ".") +        { +          // ----- Ignore this directory +          // Should be the first $i=0, but no check is done +        } +        else if ($v_list[$i] == "..") +        { +          // ----- Ignore it and ignore the $i-1 +          $i--; +        } +        else if (($v_list[$i] == "") && ($i!=(sizeof($v_list)-1)) && ($i!=0)) +        { +          // ----- Ignore only the double '//' in path, +          // but not the first and last '/' +        } +        else +        { +          $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); +        } +      } +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : $this->_tool_PathInclusion() +  // Description : +  //   This function indicates if the path $p_path is under the $p_dir tree. Or, +  //   said in an other way, if the file or sub-dir $p_path is inside the dir +  //   $p_dir. +  //   The function indicates also if the path is exactly the same as the dir. +  //   This function supports path with duplicated '/' like '//', but does not +  //   support '.' or '..' statements. +  // Parameters : +  // Return Values : +  //   0 if $p_path is not inside directory $p_dir +  //   1 if $p_path is inside directory $p_dir +  //   2 if $p_path is exactly the same as $p_dir +  // --------------------------------------------------------------------------- +  /** +  * _tool_PathInclusion() +  * +  * { Description } +  * +  */ +  function _tool_PathInclusion($p_dir, $p_path) +  { +    $v_result = 1; + +    // ----- Explode dir and path by directory separator +    $v_list_dir = explode("/", $p_dir); +    $v_list_dir_size = sizeof($v_list_dir); +    $v_list_path = explode("/", $p_path); +    $v_list_path_size = sizeof($v_list_path); + +    // ----- Study directories paths +    $i = 0; +    $j = 0; +    while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { + +      // ----- Look for empty dir (path reduction) +      if ($v_list_dir[$i] == '') { +        $i++; +        continue; +      } +      if ($v_list_path[$j] == '') { +        $j++; +        continue; +      } + +      // ----- Compare the items +      if (   ($v_list_dir[$i] != $v_list_path[$j]) +	      && ($v_list_dir[$i] != '') +		  && ( $v_list_path[$j] != ''))  { +        $v_result = 0; +      } + +      // ----- Next items +      $i++; +      $j++; +    } + +    // ----- Look if everything seems to be the same +    if ($v_result) { +      // ----- Skip all the empty items +      while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; +      while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; + +      if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { +        // ----- There are exactly the same +        $v_result = 2; +      } +      else if ($i < $v_list_dir_size) { +        // ----- The path is shorter than the dir +        $v_result = 0; +      } +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : $this->_tool_CopyBlock() +  // Description : +  // Parameters : +  //   $p_mode : read/write compression mode +  //             0 : src & dest normal +  //             1 : src gzip, dest normal +  //             2 : src normal, dest gzip +  //             3 : src & dest gzip +  // Return Values : +  // --------------------------------------------------------------------------- +  /** +  * _tool_CopyBlock() +  * +  * { Description } +  * +  * @param integer $p_mode +  */ +  function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode=0) +  { +    $v_result = 1; + +    if ($p_mode==0) +    { +      while ($p_size != 0) +      { +        $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +		                ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +        $v_buffer = @fread($p_src, $v_read_size); +        @fwrite($p_dest, $v_buffer, $v_read_size); +        $p_size -= $v_read_size; +      } +    } +    else if ($p_mode==1) +    { +      while ($p_size != 0) +      { +        $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +		                ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +        $v_buffer = @gzread($p_src, $v_read_size); +        @fwrite($p_dest, $v_buffer, $v_read_size); +        $p_size -= $v_read_size; +      } +    } +    else if ($p_mode==2) +    { +      while ($p_size != 0) +      { +        $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +		                ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +        $v_buffer = @fread($p_src, $v_read_size); +        @gzwrite($p_dest, $v_buffer, $v_read_size); +        $p_size -= $v_read_size; +      } +    } +    else if ($p_mode==3) +    { +      while ($p_size != 0) +      { +        $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE +		                ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); +        $v_buffer = @gzread($p_src, $v_read_size); +        @gzwrite($p_dest, $v_buffer, $v_read_size); +        $p_size -= $v_read_size; +      } +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : $this->_tool_Rename() +  // Description : +  //   This function tries to do a simple rename() function. If it fails, it +  //   tries to copy the $p_src file in a new $p_dest file and then unlink the +  //   first one. +  // Parameters : +  //   $p_src : Old filename +  //   $p_dest : New filename +  // Return Values : +  //   1 on success, 0 on failure. +  // --------------------------------------------------------------------------- +  /** +  * _tool_Rename() +  * +  * { Description } +  * +  */ +  function _tool_Rename($p_src, $p_dest) +  { +    $v_result = 1; + +    // ----- Try to rename the files +    if (!@rename($p_src, $p_dest)) { + +      // ----- Try to copy & unlink the src +      if (!@copy($p_src, $p_dest)) { +        $v_result = 0; +      } +      else if (!@unlink($p_src)) { +        $v_result = 0; +      } +    } + +    // ----- Return +    return $v_result; +  } +  // --------------------------------------------------------------------------- + +  // --------------------------------------------------------------------------- +  // Function : $this->_tool_TranslateWinPath() +  // Description : +  //   Translate windows path by replacing '\' by '/' and optionally removing +  //   drive letter. +  // Parameters : +  //   $p_path : path to translate. +  //   $p_remove_disk_letter : true | false +  // Return Values : +  //   The path translated. +  // --------------------------------------------------------------------------- +  /** +  * _tool_TranslateWinPath() +  * +  * { Description } +  * +  * @param [type] $p_remove_disk_letter +  */ +  function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true) +  { +    if (stristr(php_uname(), 'windows')) { +      // ----- Look for potential disk letter +      if (   ($p_remove_disk_letter) +	      && (($v_position = strpos($p_path, ':')) != false)) { +          $p_path = substr($p_path, $v_position+1); +      } +      // ----- Change potential windows directory separator +      if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { +          $p_path = strtr($p_path, '\\', '/'); +      } +    } +    return $p_path; +  } +  // --------------------------------------------------------------------------- + +  } +  // End of class + +?> diff --git a/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php new file mode 100644 index 00000000..00b0a7a9 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php @@ -0,0 +1,231 @@ +<?php +/* + * $Id: AnsiColorLogger.php,v 1.13 2005/05/26 13:10:51 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/listener/DefaultLogger.php'; +include_once 'phing/system/util/Properties.php'; + +/** + * Uses ANSI Color Code Sequences to colorize messages + * sent to the console. + * + * If used with the -logfile option, the output file + * will contain all the necessary escape codes to + * display the text in colorized mode when displayed + * in the console using applications like cat, more, + * etc. + * + * This is designed to work on terminals that support ANSI + * color codes.  It works on XTerm, ETerm, Mindterm, etc. + * It also works on Win9x (with ANSI.SYS loaded.) + * + * NOTE: + * It doesn't work on WinNT's COMMAND.COM even with + * ANSI.SYS loaded. + * + * The default colors used for differentiating + * the message levels can be changed by editing the + * /org/apache/tools/ant/listener/defaults.properties + * file. + * This file contains 5 key/value pairs: + * AnsiColorLogger.ERROR_COLOR=2;31 + * AnsiColorLogger.WARNING_COLOR=2;35 + * AnsiColorLogger.INFO_COLOR=2;36 + * AnsiColorLogger.VERBOSE_COLOR=2;32 + * AnsiColorLogger.DEBUG_COLOR=2;34 + * + * Another option is to pass a system variable named + * ant.logger.defaults, with value set to the path of + * the file that contains user defined Ansi Color + * Codes, to the <B>java</B> command using -D option. + * + * To change these colors use the following chart: + * + *      <B>ANSI COLOR LOGGER CONFIGURATION</B> + * + * Format for AnsiColorLogger.*= + *  Attribute;Foreground;Background + *  + *  Attribute is one of the following: + *  0 -> Reset All Attributes (return to normal mode) + *  1 -> Bright (Usually turns on BOLD) + *  2 -> Dim + *  3 -> Underline + *  5 -> link + *  7 -> Reverse + *  8 -> Hidden + * + *  Foreground is one of the following: + *  30 -> Black + *  31 -> Red + *  32 -> Green + *  33 -> Yellow + *  34 -> Blue + *  35 -> Magenta + *  36 -> Cyan + *  37 -> White + * + *  Background is one of the following: + *  40 -> Black + *  41 -> Red + *  42 -> Green + *  43 -> Yellow + *  44 -> Blue + *  45 -> Magenta + *  46 -> Cyan + *  47 -> White + *  + * @author     Hans Lellelid <hans@xmpl.org> (Phing) + * @author     Magesh Umasankar (Ant) + * @package    phing.listener + * @version    $Revision: 1.13 $ + */ +final class AnsiColorLogger extends DefaultLogger { + +    const ATTR_NORMAL = 0; +    const ATTR_BRIGHT = 1; +    const ATTR_DIM = 2; +    const ATTR_UNDERLINE = 3; +    const ATTR_BLINK = 5; +    const ATTR_REVERSE = 7; +    const ATTR_HIDDEN = 8; + +    const FG_BLACK = 30; +    const FG_RED = 31; +    const FG_GREEN = 32; +    const FG_YELLOW = 33; +    const FG_BLUE = 34; +    const FG_MAGENTA = 35; +    const FG_CYAN = 36; +    const FG_WHITE = 37; + +    const BG_BLACK = 40; +    const BG_RED = 41; +    const BG_GREEN = 42; +    const BG_YELLOW = 44; +    const BG_BLUE = 44; +    const BG_MAGENTA = 45; +    const BG_CYAN = 46; +    const BG_WHITE = 47; + +    const PREFIX = "\x1b["; +    const SUFFIX = "m"; +    const SEPARATOR = ';'; +    const END_COLOR = "\x1b[m"; // self::PREFIX . self::SUFFIX; + +    private $errColor; +    private $warnColor; +    private $infoColor; +    private $verboseColor; +    private $debugColor; + +    private $colorsSet = false; +     +    /** +     * Construct new AnsiColorLogger +     * Perform initializations that cannot be done in var declarations. +     */ +    public function __construct() { +        parent::__construct(); +        $this->errColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_RED . self::SUFFIX; +        $this->warnColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_MAGENTA . self::SUFFIX; +        $this->infoColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_CYAN . self::SUFFIX; +        $this->verboseColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_GREEN . self::SUFFIX; +        $this->debugColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_BLUE . self::SUFFIX; +    } +     +    /** +     * Set the colors to use from a property file specified by the +     * special ant property ant.logger.defaults +     */ +    private final function setColors() { +     +        $userColorFile = Phing::getProperty("phing.logger.defaults"); +        $systemColorFile = new PhingFile(Phing::getResourcePath("phing/listener/defaults.properties")); + +        $in = null; + +        try { +            $prop = new Properties(); + +            if ($userColorFile !== null) { +                $prop->load($userColorFile); +            } else { +                $prop->load($systemColorFile); +            }                         +             +            $err = $prop->getProperty("AnsiColorLogger.ERROR_COLOR"); +            $warn = $prop->getProperty("AnsiColorLogger.WARNING_COLOR"); +            $info = $prop->getProperty("AnsiColorLogger.INFO_COLOR"); +            $verbose = $prop->getProperty("AnsiColorLogger.VERBOSE_COLOR"); +            $debug = $prop->getProperty("AnsiColorLogger.DEBUG_COLOR"); +            if ($err !== null) { +                $errColor = self::PREFIX . $err . self::SUFFIX; +            } +            if ($warn !== null) { +                $warnColor = self::PREFIX . $warn . self::SUFFIX; +            } +            if ($info !== null) { +                $infoColor = self::PREFIX . $info . self::SUFFIX; +            } +            if ($verbose !== null) { +                $verboseColor = self::PREFIX . $verbose . self::SUFFIX; +            } +            if ($debug !== null) { +                $debugColor = self::PREFIX . $debug . self::SUFFIX; +            } +        } catch (IOException $ioe) { +            //Ignore exception - we will use the defaults. +        } +    } + +    /** +     * @see DefaultLogger#printMessage +     */ +    protected final function printMessage($message, $priority) { +     +        if ($message !== null) { +         +            if (!$this->colorsSet) { +                $this->setColors(); +                $this->colorsSet = true; +            } +             +            switch ($priority) { +                case PROJECT_MSG_ERR: +                    $message = $this->errColor . $message . self::END_COLOR; +                    break; +                case PROJECT_MSG_WARN: +                    $message = $this->warnColor . $message . self::END_COLOR;                     +                    break; +                case PROJECT_MSG_INFO: +                    $message = $this->infoColor . $message . self::END_COLOR; +                    break; +                case PROJECT_MSG_VERBOSE: +                    $message = $this->verboseColor . $message . self::END_COLOR; +                    break; +                case PROJECT_MSG_DEBUG: +                    $message = $this->debugColor . $message . self::END_COLOR; +                    break; +            } +            print($message."\n"); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/listener/BuildLogger.php b/buildscripts/phing/classes/phing/listener/BuildLogger.php new file mode 100644 index 00000000..d1c5fcb6 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/BuildLogger.php @@ -0,0 +1,42 @@ +<?php +	/** +	 * $Id: BuildLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +	 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +	 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +	 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +	 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +	 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +	 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +	 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +	 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +	 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 * +	 * This software consists of voluntary contributions made by many individuals +	 * and is licensed under the LGPL. For more information please see +	 * <http://phing.info>. +	 */ +	 +	require_once 'phing/BuildListener.php'; +	/** +	 * Interface used by Phing Ant to log the build output. +	 * +	 * @author Michiel Rook <michiel@trendserver.nl> +	 * @version $Id: BuildLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ +	 * @package phing.listener +	 */ +	interface BuildLogger extends BuildListener +	{ +		/** +		 * Sets the highest level of message this logger should respond to. +		 * +		 * Only messages with a message level lower than or equal to the +		 * given level should be written to the log. +		 * +		 * @param int the logging level for the logger. +		 */ +		function setMessageOutputLevel($level); +	}; +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/listener/DefaultLogger.php b/buildscripts/phing/classes/phing/listener/DefaultLogger.php new file mode 100644 index 00000000..c7387592 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/DefaultLogger.php @@ -0,0 +1,233 @@ +<?php +/* + *  $Id: DefaultLogger.php,v 1.11 2005/08/25 19:33:43 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/BuildListener.php'; +include_once 'phing/BuildEvent.php'; + +/** + *  Writes a build event to the console. + * + *  Currently, it only writes which targets are being executed, and + *  any messages that get logged. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.11 $ $Date: 2005/08/25 19:33:43 $ + *  @see       BuildEvent + *  @package   phing.listener + */ +class DefaultLogger implements BuildListener { + +    /** +     *  Size of the left column in output. The default char width is 12. +     *  @var int +     */ +    const LEFT_COLUMN_SIZE = 12; + +    /** +     *  The message output level that should be used. The default is +     *  <code>PROJECT_MSG_VERBOSE</code>. +     *  @var int +     */ +    protected $msgOutputLevel = PROJECT_MSG_ERR; + +    /** +     *  Time that the build started +     *  @var int +     */ +    protected $startTime; + +    /** +     *  Char that should be used to seperate lines. Default is the system +     *  property <em>line.seperator</em>. +     *  @var string +     */ +    protected $lSep; + +    /** +     *  Construct a new default logger. +     */ +    public function __construct() { +        $this->lSep = Phing::getProperty("line.separator"); +    } + +    /** +     *  Set the msgOutputLevel this logger is to respond to. +     * +     *  Only messages with a message level lower than or equal to the given +     *  level are output to the log. +     * +     *  <p> Constants for the message levels are in Project.php. The order of +     *  the levels, from least to most verbose, is: +     * +     *  <ul> +     *    <li>PROJECT_MSG_ERR</li> +     *    <li>PROJECT_MSG_WARN</li> +     *    <li>PROJECT_MSG_INFO</li> +     *    <li>PROJECT_MSG_VERBOSE</li> +     *    <li>PROJECT_MSG_DEBUG</li> +     *  </ul> +     * +     *  The default message level for DefaultLogger is PROJECT_MSG_ERR. +     * +     *  @param  integer  the logging level for the logger. +     *  @access public +     */ +    function setMessageOutputLevel($level) { +        $this->msgOutputLevel = (int) $level; +    } + +    /** +    *  Sets the start-time when the build started. Used for calculating +    *  the build-time. +    * +    *  @param  object  The BuildEvent +    *  @access public +    */ + +    function buildStarted(BuildEvent $event) { +        $this->startTime = Phing::currentTimeMillis(); +        if ($this->msgOutputLevel >= PROJECT_MSG_INFO) { +            $this->printMessage("Buildfile: ".$event->getProject()->getProperty("phing.file"), PROJECT_MSG_INFO); +        } +    } + +    /** +     *  Prints whether the build succeeded or failed, and any errors that +     *  occured during the build. Also outputs the total build-time. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function buildFinished(BuildEvent $event) { +        $error = $event->getException(); +        if ($error === null) { +            print($this->lSep . "BUILD FINISHED" . $this->lSep); +        } else { +            print($this->lSep . "BUILD FAILED" . $this->lSep); +            if (PROJECT_MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) { +                print($error->__toString().$this->lSep); +            } else { +                print($error->getMessage()); +            } +        } +        print($this->lSep . "Total time: " .$this->_formatTime(Phing::currentTimeMillis() - $this->startTime) . $this->lSep); +    } + +    /** +     *  Prints the current target name +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getTarget() +     */ +    function targetStarted(BuildEvent $event) { +        if (PROJECT_MSG_INFO <= $this->msgOutputLevel) { +            print($this->lSep . $event->getProject()->getName() . ' > ' . $event->getTarget()->getName() . ':' . $this->lSep); +        } +    } + +    /** +     *  Fired when a target has finished. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function targetFinished(BuildEvent $event) {} + +    /** +     *  Fired when a task is started. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getTask() +     */ +    function taskStarted(BuildEvent $event) {} + +    /** +     *  Fired when a task has finished. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function taskFinished(BuildEvent $event) {} + +    /** +     *  Print a message to the stdout. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getMessage() +     */ +    function messageLogged(BuildEvent $event) { +        if ($event->getPriority() <= $this->msgOutputLevel) { +            $msg = ""; +            if ($event->getTask() !== null) { +                $name = $event->getTask(); +                $name = $name->getTaskName(); +                $msg = str_pad("[$name] ", self::LEFT_COLUMN_SIZE, " ", STR_PAD_LEFT); +                #for ($i=0; $i < ($this->LEFT_COLUMN_SIZE - strlen($msg)); ++$i) { +                #    print(" "); +                #} +                #print($msg); +            } +            $msg .= $event->getMessage(); +            $this->printMessage($msg, $event->getPriority()); +        } +    } + +    /** +     *  Formats a time micro integer to human readable format. +     * +     *  @param  integer The time stamp +     *  @access private +     */ +    function _formatTime($micros) { +        $seconds = $micros; +        $minutes = $seconds / 60; +        if ($minutes > 1) { +            return sprintf("%1.0f minute%s %0.2f second%s", +                                    $minutes, ($minutes === 1 ? " " : "s "), +                                    $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s")); +        } else { +            return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s")); +        } +    } +     +    /** +     * Prints a message to console. +     *  +     * @param string $message  The message to print.  +     *                 Should not be <code>null</code>. +     * @param int $priority The priority of the message.  +     *                 (Ignored in this implementation.) +     * @return void +     */ +    protected function printMessage($message, $priority) { +        print($message . $this->lSep); +    }     +} diff --git a/buildscripts/phing/classes/phing/listener/NoBannerLogger.php b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php new file mode 100644 index 00000000..e222e10c --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php @@ -0,0 +1,61 @@ +<?php +/* + * $Id: NoBannerLogger.php,v 1.4 2003/12/24 13:02:08 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/listener/DefaultLogger.php'; + +/** + *  Extends DefaultLogger to strip out empty targets.  This logger is most + *  commonly used and also enforced by the default phing invokation scripts + *  in bin/. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.4 $ $Date: 2003/12/24 13:02:08 $ + *  @package   phing.listener + */ +class NoBannerLogger extends DefaultLogger { + +    private $targetName = null; + +    function targetStarted(BuildEvent $event) { +        $target = $event->getTarget(); +        $this->targetName = $target->getName(); +    } + +    function targetFinished(BuildEvent $event) { +        $this->targetName = null; +    } + +    function messageLogged(BuildEvent $event) { +        if ($event->getPriority() > $this->msgOutputLevel || +                null === $event->getMessage() || +                         trim($event->getMessage() === "")) { +            return; +        } + +        if ($this->targetName !== null) { +            print($this->lSep . "Target: ".$this->targetName . $this->lSep); +            $this->targetName = null; +        } + +        parent::messageLogged($event); +    } +} diff --git a/buildscripts/phing/classes/phing/listener/PearLogger.php b/buildscripts/phing/classes/phing/listener/PearLogger.php new file mode 100644 index 00000000..2bea6655 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/PearLogger.php @@ -0,0 +1,246 @@ +<?php +/* + *  $Id: PearLogger.php,v 1.3 2004/03/15 14:45:06 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/BuildListener.php'; +include_once 'phing/BuildEvent.php'; +require_once 'Log.php'; + +/** + * Writes log messages to PEAR Log. + *  + * By default it will log to file in current directory w/ name 'phing.log'.  You can customize + * this behavior by setting properties: + * - pear.log.type + * - pear.log.name + * - pear.log.ident (note that this class changes ident to project name) + * - pear.log.conf (note that array values are currently unsupported in Phing property files) + *  + * <code> + *  phing -f build.xml -logger phing.listener.PearLogger -Dpear.log.type=file -Dpear.log.name=/path/to/log.log + * </code> + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.3 $ $Date: 2004/03/15 14:45:06 $ + * @see       BuildEvent + * @package   phing.listener + */ +class PearLogger implements BuildListener { + +    /** +     *  Size of the left column in output. The default char width is 12. +     *  @var int +     */ +    const LEFT_COLUMN_SIZE = 12; + +    /** +     *  The message output level that should be used. The default is +     *  <code>PROJECT_MSG_VERBOSE</code>. +     *  @var int +     */ +    protected $msgOutputLevel = PROJECT_MSG_ERR; + +    /** +     *  Time that the build started +     *  @var int +     */ +    protected $startTime; +     +    /** +     * Maps Phing PROJECT_MSG_* constants to PEAR_LOG_* constants. +     * @var array +     */ +    protected static $levelMap = array( PROJECT_MSG_DEBUG => PEAR_LOG_DEBUG, +                                        PROJECT_MSG_INFO => PEAR_LOG_INFO, +                                        PROJECT_MSG_VERBOSE => PEAR_LOG_NOTICE, +                                        PROJECT_MSG_WARN => PEAR_LOG_WARNING, +                                        PROJECT_MSG_ERR => PEAR_LOG_ERR +                                       ); +    /** +     * Whether logging has been configured. +     * @var boolean +     */ +    protected $logConfigured = false; +               +    /** +     * Configure the logger. +     */ +    protected function configureLogging() { +     +        $type = Phing::getDefinedProperty('pear.log.type'); +        $name = Phing::getDefinedProperty('pear.log.name'); +        $ident = Phing::getDefinedProperty('pear.log.ident'); +        $conf = Phing::getDefinedProperty('pear.log.conf'); +         +        if ($type === null) $type = 'file'; +        if ($name === null) $name = 'phing.log'; +        if ($ident === null) $ident = 'phing'; +        if ($conf === null) $conf = array(); +         +        $this->logger = Log::singleton($type, $name, $ident, $conf, self::$levelMap[$this->msgOutputLevel]); +    }         +     +    /** +     * Get the configured PEAR logger to use. +     * This method just ensures that logging has been configured and returns the configured logger. +     * @return Log +     */ +    protected function logger() { +        if (!$this->logConfigured) { +            $this->configureLogging(); +        } +        return $this->logger; +    } +     +    /** +     *  Set the msgOutputLevel this logger is to respond to. +     * +     *  Only messages with a message level lower than or equal to the given +     *  level are output to the log. +     * +     *  <p> Constants for the message levels are in Project.php. The order of +     *  the levels, from least to most verbose, is: +     * +     *  <ul> +     *    <li>PROJECT_MSG_ERR</li> +     *    <li>PROJECT_MSG_WARN</li> +     *    <li>PROJECT_MSG_INFO</li> +     *    <li>PROJECT_MSG_VERBOSE</li> +     *    <li>PROJECT_MSG_DEBUG</li> +     *  </ul> +     * +     *  The default message level for DefaultLogger is PROJECT_MSG_ERR. +     * +     *  @param  integer  the logging level for the logger. +     *  @access public +     */ +    function setMessageOutputLevel($level) { +        $this->msgOutputLevel = (int) $level; +    } + +    /** +    *  Sets the start-time when the build started. Used for calculating +    *  the build-time. +    * +    *  @param  object  The BuildEvent +    *  @access public +    */ + +    function buildStarted(BuildEvent $event) { +        $this->startTime = Phing::currentTimeMillis(); +        $this->logger()->setIdent($event->getProject()->getName()); +        $this->logger()->info("Starting build with buildfile: ". $event->getProject()->getProperty("phing.file")); +    } + +    /** +     *  Prints whether the build succeeded or failed, and any errors that +     *  occured during the build. Also outputs the total build-time. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function buildFinished(BuildEvent $event) { +        $error = $event->getException(); +        if ($error === null) { +            $msg = "Finished successful build."; +        } else { +            $msg = "Build failed. [reason: " . $error->getMessage() ."]"; +        } +        $this->logger()->log($msg . " Total time: " . $this->_formatTime(Phing::currentTimeMillis() - $this->startTime)); +    } + +    /** +     *  Prints the current target name +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getTarget() +     */ +    function targetStarted(BuildEvent $event) {} + +    /** +     *  Fired when a target has finished. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function targetFinished(BuildEvent $event) {} + +    /** +     *  Fired when a task is started. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getTask() +     */ +    function taskStarted(BuildEvent $event) {} + +    /** +     *  Fired when a task has finished. We don't need specific action on this +     *  event. So the methods are empty. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getException() +     */ +    function taskFinished(BuildEvent $event) {} + +    /** +     *  Print a message to the stdout. +     * +     *  @param  object  The BuildEvent +     *  @access public +     *  @see    BuildEvent::getMessage() +     */ +    function messageLogged(BuildEvent $event) { +        if ($event->getPriority() <= $this->msgOutputLevel) {             +            $msg = ""; +            if ($event->getTask() !== null) { +                $name = $event->getTask(); +                $name = $name->getTaskName(); +                $msg = str_pad("[$name] ", self::LEFT_COLUMN_SIZE, " ", STR_PAD_LEFT); +            } +            $msg .= $event->getMessage(); +            $this->logger()->log($msg, self::$levelMap[$event->getPriority()]); +        } +    } + +    /** +     *  Formats a time micro integer to human readable format. +     * +     *  @param  integer The time stamp +     *  @access private +     */ +    function _formatTime($micros) { +        $seconds = $micros; +        $minutes = $seconds / 60; +        if ($minutes > 1) { +            return sprintf("%1.0f minute%s %0.2f second%s", +                                    $minutes, ($minutes === 1 ? " " : "s "), +                                    $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s")); +        } else { +            return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s")); +        } +    }          +} diff --git a/buildscripts/phing/classes/phing/listener/XmlLogger.php b/buildscripts/phing/classes/phing/listener/XmlLogger.php new file mode 100644 index 00000000..07ff031e --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/XmlLogger.php @@ -0,0 +1,265 @@ +<?php +	/** +	 * $Id: XmlLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +	 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +	 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +	 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +	 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +	 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +	 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +	 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +	 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +	 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 * +	 * This software consists of voluntary contributions made by many individuals +	 * and is licensed under the LGPL. For more information please see +	 * <http://phing.info>. +	 */ +	 +	require_once 'phing/listener/BuildLogger.php'; +	require_once 'phing/listener/DefaultLogger.php'; +	require_once 'phing/system/util/Timer.php'; +	/** +	 * Generates a file in the current directory with +	 * an XML description of what happened during a build. +	 * The default filename is "log.xml", but this can be overridden +	 * with the property <code>XmlLogger.file</code>. +	 * +	 * @author Michiel Rook <michiel@trendserver.nl> +	 * @version $Id: XmlLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ +	 * @package phing.listener +	 */	 +	class XmlLogger implements BuildLogger +	{ +		/** XML element name for a build. */ +		const BUILD_TAG = "build"; +		/** XML element name for a target. */ +		const TARGET_TAG = "target"; +		/** XML element name for a task. */ +		const TASK_TAG = "task"; +		/** XML element name for a message. */ +		const MESSAGE_TAG = "message"; +		/** XML attribute name for a name. */ +		const NAME_ATTR = "name"; +		/** XML attribute name for a time. */ +		const TIME_ATTR = "time"; +		/** XML attribute name for a message priority. */ +		const PRIORITY_ATTR = "priority"; +		/** XML attribute name for a file location. */ +		const LOCATION_ATTR = "location"; +		/** XML attribute name for an error description. */ +		const ERROR_ATTR = "error"; +		/** XML element name for a stack trace. */ +		const STACKTRACE_TAG = "stacktrace"; +		 +		private $doc = NULL; +		 +		private $buildStartTime = 0; +		private $targetStartTime = 0; +		private $taskStartTime = 0; +		 +		private $buildElement = NULL; +		 +		private $msgOutputLevel = PROJECT_MSG_DEBUG; +		 +		/** +		 *  Constructs a new BuildListener that logs build events to an XML file. +		 */ +		function __construct() +		{ +			$this->doc = new DOMDocument(); +			$this->doc->formatOutput = true; +			 +			$this->buildTimer = new Timer(); +			$this->targetTimer = new Timer(); +			$this->taskTimer = new Timer(); +		} +		 +		/** +		 * Fired when the build starts, this builds the top-level element for the +		 * document and remembers the time of the start of the build. +		 * +		 * @param BuildEvent Ignored. +		 */ +		function buildStarted(BuildEvent $event) +		{ +			$this->buildTimerStart = Phing::currentTimeMillis(); +			$this->buildElement = $this->doc->createElement(XmlLogger::BUILD_TAG); +		} +		 +		/** +		 * Fired when the build finishes, this adds the time taken and any +		 * error stacktrace to the build element and writes the document to disk. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */ +		function buildFinished(BuildEvent $event) +		{ +			$this->buildTimer->stop(); +			 +			$elapsedTime = Phing::currentTimeMillis() - $this->buildTimerStart; +			 +			$this->buildElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); +			 +			if ($event->getException() != null) +			{ +				$this->buildElement->setAttribute(XmlLogger::ERROR_ATTR, $event->getException()->toString()); +				 +				$errText = $this->doc->createCDATASection($event->getException()->getTraceAsString()); +				$stacktrace = $this->doc->createElement(XmlLogger::STACKTRACE_TAG); +				$stacktrace->appendChild($errText); +				$this->buildElement->appendChild($stacktrace); +			} +			 +			$outFilename = $event->getProject()->getProperty("XmlLogger.file"); +			 +			if ($outFilename == "") +			{ +				$outFilename = "log.xml"; +			} +			$writer = new FileWriter($outFilename); +			 +			$writer->write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); +			$writer->write($this->doc->saveXML($this->buildElement)); +			$writer->close(); +		} +		/** +		 * Fired when a target starts building, remembers the current time and the name of the target. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */ +		function targetStarted(BuildEvent $event) +		{ +			$target = $event->getTarget(); +			 +			$this->targetTimerStart = Phing::currentTimeMillis(); +			 +			$this->targetElement = $this->doc->createElement(XmlLogger::TARGET_TAG); +			$this->targetElement->setAttribute(XmlLogger::NAME_ATTR, $target->getName()); +		} +		 +		/** +		 * Fired when a target finishes building, this adds the time taken +		 * to the appropriate target element in the log. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */ +		function targetFinished(BuildEvent $event) +		{ +			$target = $event->getTarget(); +			 +			$elapsedTime = Phing::currentTimeMillis() - $this->targetTimerStart; +			 +			$this->targetElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); +			 +			$this->buildElement->appendChild($this->targetElement); +		} +		 +		/** +		 * Fired when a task starts building, remembers the current time and the name of the task. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */ +		function taskStarted(BuildEvent $event) +		{ +			$task = $event->getTask(); +			 +			$this->taskTimerStart = Phing::currentTimeMillis(); +			 +			$this->taskElement = $this->doc->createElement(XmlLogger::TASK_TAG); +			$this->taskElement->setAttribute(XmlLogger::NAME_ATTR, $task->getTaskName()); +			$this->taskElement->setAttribute(XmlLogger::LOCATION_ATTR, $task->getLocation()->toString()); +		} +		/** +		 * Fired when a task finishes building, this adds the time taken +		 * to the appropriate task element in the log. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */		 +		function taskFinished(BuildEvent $event) +		{ +			$task = $event->getTask(); +			 +			$elapsedTime = Phing::currentTimeMillis() - $this->taskTimerStart; +			$this->taskElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); +			 +			$this->targetElement->appendChild($this->taskElement); +		} +		 +		/** +		 * Fired when a message is logged, this adds a message element to the +		 * most appropriate parent element (task, target or build) and records +		 * the priority and text of the message. +		 * +		 * @param BuildEvent An event with any relevant extra information. +		 *              Will not be <code>null</code>. +		 */ +		function messageLogged(BuildEvent $event) +		{ +			$priority = $event->getPriority(); +			 +			if ($priority > $this->msgOutputLevel) +			{ +				return; +			} +			 +			$messageElement = $this->doc->createElement(XmlLogger::MESSAGE_TAG); +			 +			switch ($priority) +			{ +				case PROJECT_MSG_ERR:  +					$name = "error";  +					break; +					 +				case PROJECT_MSG_WARN: +					$name = "warn"; +					break; +				 +				case PROJECT_MSG_INFO: +					$name = "info"; +					break; +					 +				default: +					$name = "debug"; +					break; +			} +			 +			$messageElement->setAttribute(XmlLogger::PRIORITY_ATTR, $name); +			 +			$messageText = $this->doc->createCDATASection($event->getMessage()); +			 +			$messageElement->appendChild($messageText); +			 +			if ($event->getTask() != null) +			{ +				$this->taskElement->appendChild($messageElement); +			} +			else +			if ($event->getTarget() != null) +			{ +				$this->targetElement->appendChild($messageElement); +			} +			else +			if ($this->buildElement != null) +			{			 +				$this->buildElement->appendChild($messageElement); +			} +		} +		 +		/** +		 * Set the logging level when using this as a Logger +		 */ +		function setMessageOutputLevel($level) +		{ +			$this->msgOutputLevel = $level; +		} +	}; +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/listener/defaults.properties b/buildscripts/phing/classes/phing/listener/defaults.properties new file mode 100644 index 00000000..f60a3fd5 --- /dev/null +++ b/buildscripts/phing/classes/phing/listener/defaults.properties @@ -0,0 +1,43 @@ +#################################################### +# +#           ANSI COLOR LOGGER CONFIGURATION +# +# Format for AnsiColorLogger.*= +#  Attribute;Foreground;Background +# +#  Attribute is one of the following: +#  0 -> Reset All Attributes (return to normal mode) +#  1 -> Bright (Usually turns on BOLD) +#  2 -> Dim +#  3 -> Underline +#  5 -> link +#  7 -> Reverse +#  8 -> Hidden +#   +#  Foreground is one of the following: +#  30 -> Black +#  31 -> Red +#  32 -> Green +#  33 -> Yellow +#  34 -> Blue +#  35 -> Magenta +#  36 -> Cyan +#  37 -> White +# +#  Background is one of the following: +#  40 -> Black +#  41 -> Red +#  42 -> Green +#  43 -> Yellow +#  44 -> Blue +#  45 -> Magenta +#  46 -> Cyan +#  47 -> White +# +#################################################### + +AnsiColorLogger.ERROR_COLOR=2;31 +AnsiColorLogger.WARNING_COLOR=2;35 +AnsiColorLogger.INFO_COLOR=2;36 +AnsiColorLogger.VERBOSE_COLOR=2;32 +AnsiColorLogger.DEBUG_COLOR=2;34 diff --git a/buildscripts/phing/classes/phing/mappers/FileNameMapper.php b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php new file mode 100644 index 00000000..c8f1f8a9 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php @@ -0,0 +1,59 @@ +<?php +/*  + *  $Id: FileNameMapper.php,v 1.7 2004/01/22 03:29:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * Interface for filename mapper classes. + * + * @author Andreas Aderhold, andi@binarycloud.com + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.7 $ + * @package phing.mappers + */ +interface FileNameMapper { + +    /** +     * The mapper implementation. +     * +     * @param mixed $sourceFileName The data the mapper works on. +     * @return  array The data after the mapper has been applied; must be in array format (for some reason). +     */ +    public function main($sourceFileName); + +    /** +     * Accessor. Sets the to property. The actual implementation +     * depends on the child class. +     * +     * @param string $to To what this mapper should convert the from string +     * @return void +     */ +    public function setTo($to); + +    /** +     * Accessor. Sets the from property. What this mapper should +     * recognize. The actual implementation is dependent upon the +     * child class +     * +     * @param string $from On what this mapper should work +     * @return void +     */ +    public function setFrom($from); + +} diff --git a/buildscripts/phing/classes/phing/mappers/FlattenMapper.php b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php new file mode 100644 index 00000000..fea5c1e4 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php @@ -0,0 +1,55 @@ +<?php +/*  + *  $Id: FlattenMapper.php,v 1.9 2005/05/26 13:10:51 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/mappers/FileNameMapper.php'; + +/** + * Removes any directory information from the passed path. + * + * @author   Andreas Aderhold <andi@binarycloud.com> + * @version  $Revision: 1.9 $ + * @package  phing.mappers + */ +class FlattenMapper implements FileNameMapper { + +    /** +     * The mapper implementation. Returns string with source filename +     * but without leading directory information +     * +     * @param string $sourceFileName The data the mapper works on +     * @return array The data after the mapper has been applied +     */ +    function main($sourceFileName) { +        $f = new PhingFile($sourceFileName); +        return array($f->getName()); +    } + +    /** +     * Ignored here. +     */ +    function setTo($to) {} + +    /** +     * Ignored here. +     */ +    function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/GlobMapper.php b/buildscripts/phing/classes/phing/mappers/GlobMapper.php new file mode 100644 index 00000000..3c178620 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/GlobMapper.php @@ -0,0 +1,113 @@ +<?php +/*  + *  $Id: GlobMapper.php,v 1.10 2004/01/22 03:29:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/mappers/FileNameMapper.php'; + +/** + * description here + * + * @author   Andreas Aderhold, andi@binarycloud.com + * @version  $Revision: 1.10 $ + * @package   phing.mappers + */ +class GlobMapper implements FileNameMapper { + +    /** +     * Part of "from" pattern before the *. +     */ +    private $fromPrefix = null; + +    /** +     * Part of "from" pattern after the *. +     */ +    private $fromPostfix = null; + +    /** +     * Length of the prefix ("from" pattern). +     */ +    private $prefixLength; + +    /** +     * Length of the postfix ("from" pattern). +     */ +    private $postfixLength; + +    /** +     * Part of "to" pattern before the *. +     */ +    private $toPrefix = null; + +    /** +     * Part of "to" pattern after the *. +     */ +    private $toPostfix = null; + + +    function main($_sourceFileName) { +        if (($this->fromPrefix === null) +            || !StringHelper::startsWith($this->fromPrefix, $_sourceFileName) +            || !StringHelper::endsWith($this->fromPostfix, $_sourceFileName)) { +            return null; +        } +        $varpart = $this->_extractVariablePart($_sourceFileName); +        $substitution = $this->toPrefix.$varpart.$this->toPostfix; +        return array($substitution); +    } + + + +   function setFrom($from) { +        $index = strrpos($from, '*'); + +        if ($index === false) { +            $this->fromPrefix = $from; +            $this->fromPostfix = ""; +        } else { +            $this->fromPrefix  = substr($from, 0, $index); +            $this->fromPostfix = substr($from, $index+1); +        } +        $this->prefixLength  = strlen($this->fromPrefix); +        $this->postfixLength = strlen($this->fromPostfix); +    } + +    /** +     * Sets the "to" pattern. Required. +     */ +    function setTo($to) { +        $index = strrpos($to, '*'); +        if ($index === false) { +            $this->toPrefix = $to; +            $this->toPostfix = ""; +        } else { +            $this->toPrefix  = substr($to, 0, $index); +            $this->toPostfix = substr($to, $index+1); +        } +    } + +    private function _extractVariablePart($_name) { +        // ergh, i really hate php's string functions .... all but natural +        $start = ($this->prefixLength === 0) ? 0 : $this->prefixLength; +        $end   = ($this->postfixLength === 0) ? strlen($_name) : strlen($_name) - $this->postfixLength; +        $len   = $end-$start; +        return substr($_name, $start, $len); +    } + +} diff --git a/buildscripts/phing/classes/phing/mappers/IdentityMapper.php b/buildscripts/phing/classes/phing/mappers/IdentityMapper.php new file mode 100644 index 00000000..daf80c25 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/IdentityMapper.php @@ -0,0 +1,54 @@ +<?php +/*  + *  $Id: IdentityMapper.php,v 1.7 2004/01/22 03:29:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/mappers/FileNameMapper.php'; + +/** + * This mapper does nothing ;) + *  + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.7 $ + * @package   phing.mappers + */ +class IdentityMapper implements FileNameMapper { + +    /** +     * The mapper implementation. Basically does nothing in this case. +     * +     * @param  string $sourceFileName The data the mapper works on. +     * @return array The data after the mapper has been applied +     */ +    function main($sourceFileName) { +        return array($sourceFileName); +    } + +    /** +     * Ignored here. +     */ +    function setTo($to) {} + +    /** +     * Ignored here. +     */ +    function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/MergeMapper.php b/buildscripts/phing/classes/phing/mappers/MergeMapper.php new file mode 100644 index 00000000..f10f41c0 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/MergeMapper.php @@ -0,0 +1,69 @@ +<?php +/*  + *  $Id: MergeMapper.php,v 1.8 2004/01/22 03:29:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/mappers/FileNameMapper.php'; + +/** + * For merging files into a single file.  In practice just returns whatever value + * was set for "to". + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @version   $Revision: 1.8 $ + * @package   phing.mappers + */ +class MergeMapper implements FileNameMapper { +     +    /** the merge */ +    private $mergedFile; + +    /** +     * The mapper implementation. Basically does nothing in this case. +     * +     * @param    mixed     The data the mapper works on +     * @returns  mixed     The data after the mapper has been applied +     * @access   public +     * @author   Andreas Aderhold, andi@binarycloud.com +     */ +    function main($sourceFileName) { +        if ($this->mergedFile === null) {             +            throw new BuildException("MergeMapper error, to attribute not set");             +        }          +        return array($this->mergedFile); +    } + +    /** +     * Accessor. Sets the to property +     * +     * @param    string     To what this mapper should convert the from string +     * @returns  boolean    True +     * @access   public +     * @author   Andreas Aderhold, andi@binarycloud.com +     */ +    function setTo($to) { +        $this->mergedFile = $to; +    }     + +    /** +     * Ignored. +     */ +    function setFrom($from) {} + +} diff --git a/buildscripts/phing/classes/phing/mappers/RegexpMapper.php b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php new file mode 100644 index 00000000..a3d51976 --- /dev/null +++ b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php @@ -0,0 +1,97 @@ +<?php +/*  + *  $Id: RegexpMapper.php,v 1.9 2004/03/15 17:11:15 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/mappers/FileNameMapper.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/util/regexp/Regexp.php'; + +/** + * Uses regular expressions to perform filename transformations. + * + * @author Andreas Aderhold <andi@binarycloud.com> + * @author Hans Lellelid <hans@velum.net> + * @version $Revision: 1.9 $ + * @package phing.mappers + */ +class RegexpMapper implements FileNameMapper { + +    /** +     * @var string +     */ +    private $to; +     +    /** +     * The Regexp engine. +     * @var Regexp +     */ +    private $reg; + +    function __construct() {                 +        // instantiage regexp matcher here +        $this->reg = new Regexp(); +    } + +    /** +     * Sets the "from" pattern. Required. +     */ +    function setFrom($from) { +        $this->reg->SetPattern($from); +    } + +    /** +     * Sets the "to" pattern. Required. +     */ +    function setTo($to) { +     +        // [HL] I'm changing the way this works for now to just use string +        //$this->to = StringHelper::toCharArray($to); +         +        $this->to = $to; +    } + +    function main($sourceFileName) { +        if ($this->reg === null  || $this->to === null || !$this->reg->matches((string) $sourceFileName)) { +            return null; +        } +        return array($this->replaceReferences($sourceFileName)); +    } + +    /** +     * Replace all backreferences in the to pattern with the matched groups. +     * groups of the source. +     * @param string $source The source filename. +     */ +    private function replaceReferences($source) { +         +        // FIXME +        // Can't we just use engine->replace() to handle this?  the Preg engine +        // will automatically convert \1 references to $1 +         +        // the expression has already been processed (when ->matches() was run in Main()) +        // so no need to pass $source again to the engine. +        $groups = (array) $this->reg->getGroups();             +         +        // replace \1 with value of $groups[1] and return the modified "to" string +        return preg_replace('/\\\([\d]+)/e', "\$groups[$1]", $this->to);             +    } +     +} + diff --git a/buildscripts/phing/classes/phing/parser/AbstractHandler.php b/buildscripts/phing/classes/phing/parser/AbstractHandler.php new file mode 100644 index 00000000..6f8d7705 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/AbstractHandler.php @@ -0,0 +1,98 @@ +<?php + +/* + * $Id: AbstractHandler.php,v 1.6 2004/02/27 18:16:10 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/parser/ExpatParseException.php'; + +/** + * This is an abstract class all SAX handler classes must extend + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.6 $ + * @package   phing.parser + */ +abstract class AbstractHandler { + +    public $parentHandler = null; +    public $parser = null; + +    /** +     * Constructs a SAX handler parser. +     * +     * The constructor must be called by all derived classes. +     * +     * @param   object  the parser object +     * @param   object  the parent handler of this handler +     */ +    protected function __construct($parser, $parentHandler) { +        $this->parentHandler = $parentHandler; +        $this->parser = $parser; +        $this->parser->setHandler($this); +    } +         +    /** +     * Gets invoked when a XML open tag occurs +     * +     * Must be overloaded by the child class. Throws an ExpatParseException +     * if there is no handler registered for an element. +     * +     * @param  string  the name of the XML element +     * @param  array   the attributes of the XML element +     */ +    public function startElement($name, $attribs) { +        throw new ExpatParseException("Unexpected element $name"); +    } + +    /** +     * Gets invoked when element closes method. +     * +     */ +    protected function finished() {} + +    /** +     * Gets invoked when a XML element ends. +     * +     * Can be overloaded by the child class. But should not. It hands +     * over control to the parentHandler of this. +     * +     * @param  string  the name of the XML element +     */ +    public function endElement($name) { +        $this->finished();         +        $this->parser->setHandler($this->parentHandler); +    } + +    /** +     * Invoked by occurance of #PCDATA. +     * +     * @param     string  the name of the XML element +     * @exception ExpatParserException if there is no CDATA but method +     *            was called +     * @access    public +     */ +    public function characters($data) { +        $s = trim($data); +        if (strlen($s) > 0) { +            throw new ExpatParseException("Unexpected text '$s'", $this->parser->getLocation()); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php new file mode 100644 index 00000000..60cf0c11 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php @@ -0,0 +1,140 @@ +<?php +/* + *  $Id: AbstractSAXParser.php,v 1.13 2004/03/20 03:33:06 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * The abstract SAX parser class. + * + * This class represents a SAX parser. It is a abstract calss that must be + * implemented by the real parser that must extend this class + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.13 $ + * @package   phing.parser + */ +abstract class AbstractSAXParser { +     +    /** The AbstractHandler object. */ +    protected $handler; + +    /** +     * Constructs a SAX parser +     */ +    function __construct() {} + +    /** +     * Sets options for PHP interal parser. Must be implemented by the parser +     * class if it should be used. +     */ +    abstract function parserSetOption($opt, $val); + +    /** +     * Sets the current element handler object for this parser. Usually this +     * is an object using extending "AbstractHandler". +     * +     * @param AbstractHandler $obj The handler object. +     */ +    function setHandler( $obj) { +        $this->handler = $obj; +    } + +    /** +     * Method that gets invoked when the parser runs over a XML start element. +     * +     * This method is called by PHP's internal parser funcitons and registered +     * in the actual parser implementation. +     * It gives control to the current active handler object by calling the +     * <code>startElement()</code> method. +     *  +     * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS +     * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. +     * +     * @param  object  the php's internal parser handle +     * @param  string  the open tag name +     * @param  array   the tag's attributes if any +     */ +    function startElement($parser, $name, $attribs) { +        try { +            $this->handler->startElement($name, $attribs);         +        } catch (Exception $e) { +            print "[Exception in XML parsing]\n"; +            print $e; +            Phing::halt(-1); +        } +    } + +    /** +     * Method that gets invoked when the parser runs over a XML close element. +     * +     * This method is called by PHP's internal parser funcitons and registered +     * in the actual parser implementation. +     * +     * It gives control to the current active handler object by calling the +     * <code>endElement()</code> method. +     * +     * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS +     * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. +     *  +     * @param   object  the php's internal parser handle +     * @param   string  the closing tag name +     */ +    function endElement($parser, $name) { +        try { +            $this->handler->endElement($name); +        } catch (Exception $e) { +            print "[Exception in XML parsing]\n"; +            print $e; +            Phing::halt(-1); +        } +    } + +    /** +     * Method that gets invoked when the parser runs over CDATA. +     * +     * This method is called by PHP's internal parser functions and registered +     * in the actual parser implementation. +     * +     * It gives control to the current active handler object by calling the +     * <code>characters()</code> method. That processes the given CDATA. +     * +     * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS +     * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. +     *  +     * @param resource $parser php's internal parser handle. +     * @param string $data the CDATA +     */ +    function characters($parser, $data) { +        try {      +            $this->handler->characters($data);         +        } catch (Exception $e) { +            print "[Exception in XML parsing]\n"; +            print $e; +            Phing::halt(-1); +        } +    } + +    /** +     * Entrypoint for parser. This method needs to be implemented by the +     * child classt that utilizes the concrete parser +     */ +    abstract function parse(); +} diff --git a/buildscripts/phing/classes/phing/parser/DataTypeHandler.php b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php new file mode 100644 index 00000000..37d757c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php @@ -0,0 +1,144 @@ +<?php +/* + *  $Id: DataTypeHandler.php,v 1.8 2005/11/02 13:55:33 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/RuntimeConfigurable.php'; + +/** + * Configures a Project (complete with Targets and Tasks) based on + * a XML build file. + * <p> + * Design/ZE2 migration note: + * If PHP would support nested classes. All the phing/parser/*Filter + * classes would be nested within this class + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.8 $ $Date: 2005/11/02 13:55:33 $ + * @access    public + * @package   phing.parser + */ + +class DataTypeHandler extends AbstractHandler { + +    private $target; +    private $element; +    private $wrapper; + +    /** +     * Constructs a new DataTypeHandler and sets up everything. +     * +     * @param AbstractSAXParser $parser The XML parser (default: ExpatParser) +     * @param AbstractHandler $parentHandler The parent handler that invoked this handler. +     * @param ProjectConfigurator $configurator The ProjectConfigurator object +     * @param Target $target The target object this datatype is contained in (null for top-level datatypes). +     */ +    function __construct(AbstractSAXParser $parser, AbstractHandler $parentHandler, ProjectConfigurator $configurator, $target = null) { // FIXME b2 typehinting +        parent::__construct($parser, $parentHandler); +        $this->target = $target; +        $this->configurator = $configurator; +    } + +    /** +     * Executes initialization actions required to setup the data structures +     * related to the tag. +     * <p> +     * This includes: +     * <ul> +     * <li>creation of the datatype object</li> +     * <li>calling the setters for attributes</li> +     * <li>adding the type to the target object if any</li> +     * <li>adding a reference to the task (if id attribute is given)</li> +         * </ul> +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @throws ExpatParseException if attributes are incomplete or invalid +     * @access public +     */ +    function init($propType, $attrs) { +        // shorthands +        $project = $this->configurator->project; +        $configurator = $this->configurator; + +        try {//try +            $this->element = $project->createDataType($propType); + +            if ($this->element === null) { +                throw new BuildException("Unknown data type $propType"); +            } + +            if ($this->target !== null) { +                $this->wrapper = new RuntimeConfigurable($this->element, $propType); +                $this->wrapper->setAttributes($attrs); +                $this->target->addDataType($this->wrapper); +            } else { +                $configurator->configure($this->element, $attrs, $project); +                $configurator->configureId($this->element, $attrs); +            } + +        } catch (BuildException $exc) { +            throw new ExpatParseException($exc, $this->parser->getLocation()); +        } +    } + +    /** +     * Handles character data. +     * +     * @param  string  the CDATA that comes in +     * @access public +     */ +    function characters($data) { +        $project = $this->configurator->project; +        try {//try +            $this->configurator->addText($project, $this->element, $data); +        } catch (BuildException $exc) { +            throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); +        } +    } + +    /** +     * Checks for nested tags within the current one. Creates and calls +     * handlers respectively. +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @access public +     */ +    function startElement($name, $attrs) { +        $nef = new NestedElementHandler($this->parser, $this, $this->configurator, $this->element, $this->wrapper, $this->target); +        $nef->init($name, $attrs); +    } +     +   /** +    * Overrides endElement for data types. Tells the type +    * handler that processing the element had been finished so +    * handlers know they can perform actions that need to be +    * based on the data contained within the element. +    * +    * @param  string  the name of the XML element +    * @return void +    */ +   function endElement($name) { +       $this->element->parsingComplete(); +       parent::endElement($name); +   } +          +} diff --git a/buildscripts/phing/classes/phing/parser/ExpatParseException.php b/buildscripts/phing/classes/phing/parser/ExpatParseException.php new file mode 100644 index 00000000..d5086c30 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ExpatParseException.php @@ -0,0 +1,31 @@ +<?php +/* + *  $Id: ExpatParseException.php,v 1.5 2003/11/19 05:48:28 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +require_once 'phing/BuildException.php'; + +/** + * This class throws errors for Expat, the XML processor. + * + * @author   Andreas Aderhold, andi@binarycloud.com + * @version  $Revision: 1.5 $ $Date: 2003/11/19 05:48:28 $ + * @package  phing.parser + */ +class ExpatParseException extends BuildException {} diff --git a/buildscripts/phing/classes/phing/parser/ExpatParser.php b/buildscripts/phing/classes/phing/parser/ExpatParser.php new file mode 100644 index 00000000..82046f8d --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ExpatParser.php @@ -0,0 +1,140 @@ +<?php +/* + *  $Id: ExpatParser.php,v 1.8 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/parser/AbstractSAXParser.php'; +include_once 'phing/parser/ExpatParseException.php'; +include_once 'phing/system/io/IOException.php'; +include_once 'phing/system/io/FileReader.php'; + +/** + * This class is a wrapper for the PHP's internal expat parser. + * + * It takes an XML file represented by a abstract path name, and starts + * parsing the file and calling the different "trap" methods inherited from + * the AbstractParser class. + * + * Those methods then invoke the represenatative methods in the registered + * handler classes. + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.8 $ $Date: 2005/05/26 13:10:52 $ + * @access    public + * @package   phing.parser + */ + +class ExpatParser extends AbstractSAXParser { +     +    /** @var resource */ +    private $parser; +     +    /** @var Reader */ +    private $reader; +     +    private $file; +     +    private $buffer = 4096; +     +    private $error_string = ""; +     +    private $line = 0; +     +    /** @var Location Current cursor pos in XML file. */ +    private $location; + +    /** +     * Constructs a new ExpatParser object. +     * +     * The constructor accepts a PhingFile object that represents the filename +     * for the file to be parsed. It sets up php's internal expat parser +     * and options. +     * +     * @param Reader $reader  The Reader Object that is to be read from. +     * @param string $filename Filename to read. +     * @throws Exception if the given argument is not a PhingFile object +     */ +    function __construct(Reader $reader, $filename=null) { + +        $this->reader = $reader; +        if ($filename !== null) { +            $this->file = new PhingFile($filename); +        } +        $this->parser = xml_parser_create(); +        $this->buffer = 4096; +        $this->location = new Location(); +        xml_set_object($this->parser, $this); +        xml_set_element_handler($this->parser, array($this,"startElement"),array($this,"endElement")); +        xml_set_character_data_handler($this->parser, array($this, "characters")); +    } + +    /** +     * Override PHP's parser default settings, created in the constructor. +     * +     * @param  string  the option to set +     * @throws mixed   the value to set +     * @return boolean true if the option could be set, otherwise false +     * @access public +     */ +    function parserSetOption($opt, $val) { +        return xml_parser_set_option($this->parser, $opt, $val); +    } + +    /** +     * Returns the location object of the current parsed element. It describes +     * the location of the element within the XML file (line, char) +     * +     * @return object  the location of the current parser +     * @access public +     */ +    function getLocation() { +        if ($this->file !== null) { +            $path = $this->file->getAbsolutePath(); +        } else { +            $path = $this->reader->getResource(); +        } +        $this->location = new Location($path, xml_get_current_line_number($this->parser), xml_get_current_column_number($this->parser)); +        return $this->location; +    } + +    /** +     * Starts the parsing process. +     * +     * @param  string  the option to set +     * @return int     1 if the parsing succeeded +     * @throws ExpatParseException if something gone wrong during parsing +     * @throws IOException if XML file can not be accessed +     * @access public +     */ +    function parse() { +     +        while ( ($data = $this->reader->read()) !== -1 ) {             +            if (!xml_parse($this->parser, $data, $this->reader->eof())) { +                $error = xml_error_string(xml_get_error_code($this->parser)); +                $e = new ExpatParseException($error, $this->getLocation()); +                xml_parser_free($this->parser);                 +                throw $e;   +            } +        } +        xml_parser_free($this->parser); +         +        return 1; +    } +} diff --git a/buildscripts/phing/classes/phing/parser/Location.php b/buildscripts/phing/classes/phing/parser/Location.php new file mode 100644 index 00000000..fd79866c --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/Location.php @@ -0,0 +1,72 @@ +<?php +/* + *  $Id: Location.php,v 1.6 2003/12/24 13:02:09 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Stores the file name and line number of a XML file + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.6 $ $Date: 2003/12/24 13:02:09 $ + * @access    public + * @package   phing.parser + */ + +class Location { + +    private $fileName; +    private $lineNumber; +    private $columnNumber; + +    /** +     * Constructs the location consisting of a file name and line number +     * +     * @param  string  the filename +     * @param  integer the line number +     * @param  integer the column number +     * @access public +     */ +    function Location($fileName = null, $lineNumber = null, $columnNumber = null) { +        $this->fileName = $fileName; +        $this->lineNumber = $lineNumber; +        $this->columnNumber = $columnNumber; +    } + +    /** +     * Returns the file name, line number and a trailing space. +     * +     * An error message can be appended easily. For unknown locations, +     * returns empty string. +     * +     * @return string the string representation of this Location object +     * @access public +     */ +    function toString() { +        $buf = ""; +        if ($this->fileName !== null) { +            $buf.=$this->fileName; +            if ($this->lineNumber !== null) { +                $buf.= ":".$this->lineNumber; +            } +            $buf.=":".$this->columnNumber; +        } +        return (string) $buf; +    } +} diff --git a/buildscripts/phing/classes/phing/parser/NestedElementHandler.php b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php new file mode 100644 index 00000000..8ecd0ed3 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php @@ -0,0 +1,186 @@ +<?php +/* + *  $Id: NestedElementHandler.php,v 1.10 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/IntrospectionHelper.php'; +include_once 'phing/TaskContainer.php'; + +/** + * The nested element handler class. + * + * This class handles the occurance of runtime registered tags like + * datatypes (fileset, patternset, etc) and it's possible nested tags. It + * introspects the implementation of the class and sets up the data structures. + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + * @access    public + * @package   phing.parser + */ + +class NestedElementHandler extends AbstractHandler { + +    /** +     * Reference to the parent object that represents the parent tag +     * of this nested element +     * @var object +     */ +    private $parent; + +    /** +     * Reference to the child object that represents the child tag +     * of this nested element +     * @var object +     */ +    private $child; + +    /** +     *  Reference to the parent wrapper object +     *  @var object +     */ +    private $parentWrapper; + +    /** +     *  Reference to the child wrapper object +     *  @var object +     */ +    private $childWrapper; + +    /** +     *  Reference to the related target object +     *  @var object the target instance +     */ +    private $target; + +    /** +     *  Constructs a new NestedElement handler and sets up everything. +     * +     *  @param  object  the ExpatParser object +     *  @param  object  the parent handler that invoked this handler +     *  @param  object  the ProjectConfigurator object +     *  @param  object  the parent object this element is contained in +     *  @param  object  the parent wrapper object +     *  @param  object  the target object this task is contained in +     *  @access public +     */ +    function __construct($parser, $parentHandler, $configurator, $parent, $parentWrapper, $target) { +        parent::__construct($parser, $parentHandler); +        $this->configurator = $configurator; +        if ($parent instanceof TaskAdapter) { +            $this->parent = $parent->getProxy(); +        } else { +            $this->parent = $parent; +        } +        $this->parentWrapper = $parentWrapper; +        $this->target = $target;         +    } + +    /** +     * Executes initialization actions required to setup the data structures +     * related to the tag. +     * <p> +     * This includes: +     * <ul> +     * <li>creation of the nested element</li> +     * <li>calling the setters for attributes</li> +     * <li>adding the element to the container object</li> +     * <li>adding a reference to the element (if id attribute is given)</li> +         * </ul> +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @throws ExpatParseException if the setup process fails +     * @access public +     */ +    function init($propType, $attrs) { +        $configurator = $this->configurator; +        $project = $this->configurator->project; + +        // introspect the parent class that is custom +        $parentClass = get_class($this->parent); +        $ih = IntrospectionHelper::getHelper($parentClass); +        try { +            if ($this->parent instanceof UnknownElement) { +                $this->child = new UnknownElement(strtolower($propType)); +                $this->parent->addChild($this->child); +            } else {                 +                $this->child = $ih->createElement($project, $this->parent, strtolower($propType)); +            } +             +            $configurator->configureId($this->child, $attrs); +             +            if ($this->parentWrapper !== null) { +                $this->childWrapper = new RuntimeConfigurable($this->child, $propType); +                $this->childWrapper->setAttributes($attrs); +                $this->parentWrapper->addChild($this->childWrapper); +            } else { +                $configurator->configure($this->child, $attrs, $project); +                $ih->storeElement($project, $this->parent, $this->child, strtolower($propType)); +            } +        } catch (BuildException $exc) { +            throw new ExpatParseException("Error initializing nested element <$propType>", $exc, $this->parser->getLocation()); +        } +    } + +    /** +     * Handles character data. +     * +     * @param  string  the CDATA that comes in +     * @throws ExpatParseException if the CDATA could not be set-up properly +     * @access public +     */ +    function characters($data) { + +        $configurator = $this->configurator;         +        $project = $this->configurator->project; + +        if ($this->parentWrapper === null) { +            try {                 +                $configurator->addText($project, $this->child, $data); +            } catch (BuildException $exc) { +                throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); +            } +        } else {                     +            $this->childWrapper->addText($data); +        } +    } + +    /** +     * Checks for nested tags within the current one. Creates and calls +     * handlers respectively. +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @access public +     */ +    function startElement($name, $attrs) { +        //print(get_class($this) . " name = $name, attrs = " . implode(",",$attrs) . "\n"); +		if ($this->child instanceof TaskContainer) { +                // taskcontainer nested element can contain other tasks - no other +                // nested elements possible +			$tc = new TaskHandler($this->parser, $this, $this->configurator, $this->child, $this->childWrapper, $this->target); +			$tc->init($name, $attrs); +		} else { +			$neh = new NestedElementHandler($this->parser, $this, $this->configurator, $this->child, $this->childWrapper, $this->target); +        	$neh->init($name, $attrs); +		} +    } +} diff --git a/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php new file mode 100644 index 00000000..6b69e955 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php @@ -0,0 +1,246 @@ +<?php +/* + * $Id: ProjectConfigurator.php,v 1.17 2006/01/06 14:57:18 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/BuildException.php'; +include_once 'phing/system/lang/FileNotFoundException.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * The datatype handler class. + * + * This class handles the occurance of registered datatype tags like + * FileSet + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.17 $ $Date: 2006/01/06 14:57:18 $ + * @access    public + * @package   phing.parser + */ +class ProjectConfigurator { + +    public $project; +    public $locator; +     +    public $buildFile; +    public $buildFileParent; +         +    /** +     * Static call to ProjectConfigurator. Use this to configure a +     * project. Do not use the new operator. +     * +     * @param  object  the Project instance this configurator should use +     * @param  object  the buildfile object the parser should use +     * @access public +     */ +    public static function configureProject(Project $project, PhingFile $buildFile) { +        $pc = new ProjectConfigurator($project, $buildFile); +        $pc->parse(); +    } + +    /** +     * Constructs a new ProjectConfigurator object +     * This constructor is private. Use a static call to +     * <code>configureProject</code> to configure a project. +     * +     * @param  object  the Project instance this configurator should use +     * @param  object  the buildfile object the parser should use +     * @access private +     */ +    function __construct(Project $project, PhingFile $buildFile) { +        $this->project = $project; +        $this->buildFile = new PhingFile($buildFile->getAbsolutePath()); +        $this->buildFileParent = new PhingFile($this->buildFile->getParent()); +    } + +    /** +     * Creates the ExpatParser, sets root handler and kick off parsing +     * process. +     * +     * @throws BuildException if there is any kind of execption during +     *         the parsing process +     * @access private +     */ +    protected function parse() { +        try { +            $reader = new BufferedReader(new FileReader($this->buildFile)); +            $reader->open(); +            $parser = new ExpatParser($reader); +            $parser->parserSetOption(XML_OPTION_CASE_FOLDING,0); +            $parser->setHandler(new RootHandler($parser, $this)); +            $this->project->log("parsing buildfile ".$this->buildFile->getName(), PROJECT_MSG_VERBOSE); +            $parser->parse(); +            $reader->close(); +        } catch (Exception $exc) { +            throw new BuildException("Error reading project file", $exc); +        } +    } + +    /** +     * Configures an element and resolves eventually given properties. +     * +     * @param  object  the element to configure +     * @param  array   the element's attributes +     * @param  object  the project this element belongs to +     * @throws Exception if arguments are not valid +     * @throws BuildException if attributes can not be configured +     * @access public +     */ +    function configure($target, $attrs, Project $project) {                + +        if ($target instanceof TaskAdapter) { +            $target = $target->getProxy(); +        } +         +		// if the target is an UnknownElement, this means that the tag had not been registered +		// when the enclosing element (task, target, etc.) was configured.  It is possible, however,  +		// that the tag was registered (e.g. using <taskdef>) after the original configuration. +		// ... so, try to load it again: +		if ($target instanceof UnknownElement) { +			$tryTarget = $project->createTask($target->getTaskType()); +			if ($tryTarget) { +				$target = $tryTarget; +			} +		} + +        $bean = get_class($target); +        $ih = IntrospectionHelper::getHelper($bean); + +        foreach ($attrs as $key => $value) { +            if ($key == 'id') { +                continue; +                // throw new BuildException("Id must be set Extermnally"); +            }             +            $value = self::replaceProperties($project, $value, $project->getProperties()); +            try { // try to set the attribute +                $ih->setAttribute($project, $target, strtolower($key), $value); +            } catch (BuildException $be) { +                // id attribute must be set externally +                if ($key !== "id") { +                    throw $be; +                } +            } +        } +    } + +    /** +     * Configures the #CDATA of an element. +     * +     * @param  object  the project this element belongs to +     * @param  object  the element to configure +     * @param  string  the element's #CDATA +     * @access public +     */ +    function addText($project, $target, $text = null) { +        if ($text === null || strlen(trim($text)) === 0) { +            return; +        }     +        $ih = IntrospectionHelper::getHelper(get_class($target)); +        $text = self::replaceProperties($project, $text, $project->getProperties()); +        $ih->addText($project, $target, $text); +    } + +    /** +     * Stores a configured child element into its parent object +     * +     * @param  object  the project this element belongs to +     * @param  object  the parent element +     * @param  object  the child element +     * @param  string  the XML tagname +     * @access public +     */ +    function storeChild($project, $parent, $child, $tag) { +        $ih = IntrospectionHelper::getHelper(get_class($parent)); +        $ih->storeElement($project, $parent, $child, $tag); +    } + +    // The following two properties are a sort of hack +    // to enable a static function to serve as the callback +    // for preg_replace_callback().  Clearly we cannot use object +    // variables, since the replaceProperties() is called statically. +    // This is IMO better than using global variables in the callback. +     +    private static $propReplaceProject; +    private static $propReplaceProperties; +          +    /** +     * Replace ${} style constructions in the given value with the +     * string value of the corresponding data types. This method is +     * static. +     * +     * @param  object  the project that should be used for property look-ups +     * @param  string  the string to be scanned for property references +     * @param  array   proeprty keys +     * @return string  the replaced string or <code>null</code> if the string +     *                 itself was null +     */ +    public static function replaceProperties(Project $project, $value, $keys) { +         +        if ($value === null) { +            return null; +        } +         +        // These are a "hack" to support static callback for preg_replace_callback() +         +        // make sure these get initialized every time         +        self::$propReplaceProperties = $keys; +        self::$propReplaceProject = $project; +         +        // Because we're not doing anything special (like multiple passes), +        // regex is the simplest / fastest.  PropertyTask, though, uses +        // the old parsePropertyString() method, since it has more stringent +        // requirements. +         +        $sb = preg_replace_callback('/\$\{([^}]+)\}/', array('ProjectConfigurator', 'replacePropertyCallback'), $value); +        return $sb;         +    } +     +    /** +     * Private [static] function for use by preg_replace_callback to replace a single param. +     * This method makes use of a static variable to hold the  +     */ +    private static function replacePropertyCallback($matches) +    { +        $propertyName = $matches[1]; +        if (!isset(self::$propReplaceProperties[$propertyName])) { +                    self::$propReplaceProject->log('Property ${'.$propertyName.'} has not been set.', PROJECT_MSG_VERBOSE); +                    return $matches[0]; +        } else { +			self::$propReplaceProject->log('Property ${'.$propertyName.'} => ' . self::$propReplaceProperties[$propertyName], PROJECT_MSG_DEBUG); +		} +        return self::$propReplaceProperties[$propertyName]; +    }            + +    /** +     * Scan Attributes for the id attribute and maybe add a reference to +     * project. +     * +     * @param object the element's object +     * @param array  the element's attributes +     */ +    function configureId(&$target, $attr) { +        if (isset($attr['id']) && $attr['id'] !== null) { +            $this->project->addReference($attr['id'], $target); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/parser/ProjectHandler.php b/buildscripts/phing/classes/phing/parser/ProjectHandler.php new file mode 100644 index 00000000..54486ec9 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/ProjectHandler.php @@ -0,0 +1,146 @@ +<?php +/* + * $Id: ProjectHandler.php,v 1.14 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/parser/AbstractHandler.php'; +require_once 'phing/system/io/PhingFile.php'; + +/** + * Handler class for the <project> XML element This class handles all elements + * under the <project> element. + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright (c) 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.14 $ $Date: 2005/10/04 19:13:44 $ + * @access    public + * @package   phing.parser + */ +class ProjectHandler extends AbstractHandler { + +    /** +     * The phing project configurator object. +     * @var ProjectConfigurator +     */ +    private $configurator; + +    /** +     * Constructs a new ProjectHandler +     * +     * @param  object  the ExpatParser object +     * @param  object  the parent handler that invoked this handler +     * @param  object  the ProjectConfigurator object +     * @access public +     */ +    function __construct($parser, $parentHandler, $configurator) { +        $this->configurator = $configurator; +        parent::__construct($parser, $parentHandler); +    } + +    /** +     * Executes initialization actions required to setup the project. Usually +     * this method handles the attributes of a tag. +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @param  object  the ProjectConfigurator object +     * @throws ExpatParseException if attributes are incomplete or invalid +     * @access public +     */ +    function init($tag, $attrs) { +        $def = null; +        $name = null; +        $id    = null; +        $baseDir = null; + +        // some shorthands +        $project = $this->configurator->project; +        $buildFileParent = $this->configurator->buildFileParent; + +        foreach ($attrs as $key => $value) { +            if ($key === "default") { +                $def = $value; +            } elseif ($key === "name") { +                $name = $value; +            } elseif ($key === "id") { +                $id = $value; +            } elseif ($key === "basedir") { +                $baseDir = $value; +            } else { +                throw new ExpatParseException("Unexpected attribute '$key'"); +            } +        } +        if ($def === null) { +            throw new ExpatParseException("The default attribute of project is required"); +        } +        $project->setDefaultTarget($def); + +        if ($name !== null) { +            $project->setName($name); +            $project->addReference($name, $project); +        } + +        if ($id !== null) { +            $project->addReference($id, $project); +        } + +        if ($project->getProperty("project.basedir") !== null) { +            $project->setBasedir($project->getProperty("project.basedir")); +        } else { +            if ($baseDir === null) { +                $project->setBasedir($buildFileParent->getAbsolutePath()); +            } else { +                // check whether the user has specified an absolute path +                $f = new PhingFile($baseDir); +                if ($f->isAbsolute()) { +                    $project->setBasedir($baseDir); +                } else { +                    $project->setBaseDir($project->resolveFile($baseDir, $buildFileParent)); +                } +            } +        } +    } + +    /** +     * Handles start elements within the <project> tag by creating and +     * calling the required handlers for the detected element. +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @throws ExpatParseException if a unxepected element occurs +     * @access public +     */ +    function startElement($name, $attrs) { +     +		$project = $this->configurator->project; +        $types = $project->getDataTypeDefinitions(); +		 +		if ($name == "target") { +			$tf = new TargetHandler($this->parser, $this, $this->configurator); +			$tf->init($name, $attrs); +		} elseif (isset($types[$name])) { +           $tyf = new DataTypeHandler($this->parser, $this, $this->configurator); +           $tyf->init($name, $attrs); +        } else { +			$tf = new TaskHandler($this->parser, $this, $this->configurator); +			$tf->init($name, $attrs); +        } +    } +} + diff --git a/buildscripts/phing/classes/phing/parser/RootHandler.php b/buildscripts/phing/classes/phing/parser/RootHandler.php new file mode 100644 index 00000000..28afb5d5 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/RootHandler.php @@ -0,0 +1,82 @@ +<?php +/* + *  $Id: RootHandler.php,v 1.7 2003/12/24 13:02:09 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/parser/AbstractHandler.php'; +include_once 'phing/parser/ExpatParseException.php'; +include_once 'phing/parser/ProjectHandler.php'; + +/** + * Root filter class for a phing buildfile. + * + * The root filter is called by the parser first. This is where the phing + * specific parsing starts. RootHandler decides what to do next. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.7 $ + * @package   phing.parser + */ +class RootHandler extends AbstractHandler { + +    /** +     * The phing project configurator object +     */ +    private $configurator; + +    /** +     * Constructs a new RootHandler +     * +     * The root filter is required so the parser knows what to do. It's +     * called by the ExpatParser that is instatiated in ProjectConfigurator. +     * +     * It recieves the expat parse object ref and a reference to the +     * configurator +     * +     * @param AbstractSAXParser $parser The ExpatParser object. +     * @param ProjectConfigurator $configurator The ProjectConfigurator object. +     */ +    function __construct(AbstractSAXParser $parser, ProjectConfigurator $configurator) { +        $this->configurator = $configurator; +        parent::__construct($parser, $this); +    } + +    /** +     * Kick off a custom action for a start element tag. +     * +     * The root element of our buildfile is the <project> element. The +     * root filter handles this element if it occurs, creates ProjectHandler  +     * to handle any nested tags & attributes of the <project> tag, +     * and calls init. +     * +     * @param string $tag The xml tagname +     * @param array  $attrs The attributes of the tag +     * @throws ExpatParseException if the first element within our build file +     *         is not the >project< element +     */ +    function startElement($tag, $attrs) { +        if ($tag === "project") { +            $ph = new ProjectHandler($this->parser, $this, $this->configurator); +            $ph->init($tag, $attrs); +        } else { +            throw new ExpatParseException("Unexpected tag <$tag> in top-level of build file.", $this->parser->getLocation()); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/parser/TargetHandler.php b/buildscripts/phing/classes/phing/parser/TargetHandler.php new file mode 100644 index 00000000..7ca94b44 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/TargetHandler.php @@ -0,0 +1,149 @@ +<?php +/* + * $Id: TargetHandler.php,v 1.10 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/parser/AbstractHandler.php'; + +/** + * The target handler class. + * + * This class handles the occurance of a <target> tag and it's possible + * nested tags (datatypes and tasks). + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @copyright  2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.10 $ + * @package   phing.parser + */ +class TargetHandler extends AbstractHandler { + +    /** +     * Reference to the target object that represents the currently parsed +     * target. +     * @var object the target instance +     */ +    private $target; + +    /** +     * The phing project configurator object +     * @var ProjectConfigurator +     */ +    private $configurator; + +    /** +     * Constructs a new TargetHandler +     * +     * @param  object  the ExpatParser object +     * @param  object  the parent handler that invoked this handler +     * @param  object  the ProjectConfigurator object +     */ +    function __construct(AbstractSAXParser $parser, AbstractHandler $parentHandler, ProjectConfigurator $configurator) { +        parent::__construct($parser, $parentHandler); +        $this->configurator = $configurator;       +    } + +    /** +     * Executes initialization actions required to setup the data structures +     * related to the tag. +     * <p> +     * This includes: +     * <ul> +     * <li>creation of the target object</li> +     * <li>calling the setters for attributes</li> +     * <li>adding the target to the project</li> +     * <li>adding a reference to the target (if id attribute is given)</li> +     * </ul> +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     * @throws ExpatParseException if attributes are incomplete or invalid +     */ +    function init($tag, $attrs) { +        $name = null; +        $depends = ""; +        $ifCond = null; +        $unlessCond = null; +        $id = null; +        $description = null; + +        foreach($attrs as $key => $value) { +            if ($key==="name") { +                $name = (string) $value; +            } else if ($key==="depends") { +                $depends = (string) $value; +            } else if ($key==="if") { +                $ifCond = (string) $value; +            } else if ($key==="unless") { +                $unlessCond = (string) $value; +            } else if ($key==="id") { +                $id = (string) $value; +            } else if ($key==="description") { +                $description = (string)$value; +            } else { +                throw new ExpatParseException("Unexpected attribute '$key'", $this->parser->getLocation()); +            } +        } + +        if ($name === null) { +            throw new ExpatParseException("target element appears without a name attribute",  $this->parser->getLocation()); +        } + +        // shorthand +        $project = $this->configurator->project; + +        $this->target = new Target(); +        $this->target->setName($name); +        $this->target->setIf($ifCond); +        $this->target->setUnless($unlessCond); +        $this->target->setDescription($description); + +        $project->addTarget($name, $this->target); + +        if ($id !== null && $id !== "") { +            $project->addReference($id, $this->target); +        } +        // take care of dependencies +        if (strlen($depends) > 0) { +            $this->target->setDepends($depends); +        } + +    } + +    /** +     * Checks for nested tags within the current one. Creates and calls +     * handlers respectively. +     * +     * @param  string  the tag that comes in +     * @param  array   attributes the tag carries +     */ +    function startElement($name, $attrs) { +        // shorthands +        $project = $this->configurator->project; +        $types = $project->getDataTypeDefinitions(); + +        if (isset($types[$name])) { +            $th = new DataTypeHandler($this->parser, $this, $this->configurator, $this->target); +            $th->init($name, $attrs); +        } else { +            $tmp = new TaskHandler($this->parser, $this, $this->configurator, $this->target, null, $this->target); +            $tmp->init($name, $attrs); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/parser/TaskHandler.php b/buildscripts/phing/classes/phing/parser/TaskHandler.php new file mode 100644 index 00000000..976aebf2 --- /dev/null +++ b/buildscripts/phing/classes/phing/parser/TaskHandler.php @@ -0,0 +1,229 @@ +<?php +/* + *  $Id: TaskHandler.php,v 1.10 2005/10/04 19:13:44 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/UnknownElement.php'; + +/** + * The task handler class. + * + * This class handles the occurance of a <task> tag and it's possible + * nested tags (datatypes and tasks) that may be unknown off bat and are + * initialized on the fly. + * + * @author      Andreas Aderhold <andi@binarycloud.com> + * @copyright © 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.10 $ + * @package   phing.parser + */ +class TaskHandler extends AbstractHandler { + +    /** +     * Reference to the target object that contains the currently parsed +     * task +     * @var object the target instance +     */ +    private $target; + +    /** +     * Reference to the target object that represents the currently parsed +     * target. This must not necessarily be a target, hence extra variable. +     * @var object the target instance +     */ +    private $container; + +    /** +     * Reference to the task object that represents the currently parsed +     * target. +     * @var Task +     */ +    private $task; +	 +	/** + 	 * Wrapper for the parent element, if any. The wrapper for this +	 * element will be added to this wrapper as a child. +	 * @var RuntimeConfigurable +	 */ +	private $parentWrapper; +	 +	/** +	 * Wrapper for this element which takes care of actually configuring +	 * the element, if this element is contained within a target. +	 * Otherwise the configuration is performed with the configure method. +	 * @see ProjectHelper::configure(Object,AttributeList,Project) +	 */ +    private $wrapper; + +    /** +     * The phing project configurator object +     * @var ProjectConfigurator +     */ +    private $configurator; + +    /** +     * Constructs a new TaskHandler and sets up everything. +     * +     * @param AbstractSAXParser The ExpatParser object +     * @param object $parentHandler The parent handler that invoked this handler +     * @param ProjectConfigurator $configurator +     * @param TaskContainer $container The container object this task is contained in (null for top-level tasks). +	 * @param RuntimeConfigurable $parentWrapper  Wrapper for the parent element, if any. +     * @param Target $target The target object this task is contained in (null for top-level tasks). +     */ +    function __construct(AbstractSAXParser $parser, $parentHandler, ProjectConfigurator $configurator, $container = null, $parentWrapper = null, $target = null) { +         +        parent::__construct($parser, $parentHandler); +     +        if (($container !== null) && !($container instanceof TaskContainer)) { +            throw new Exception("Argument expected to be a TaskContainer, got something else"); +        } +		if (($parentWrapper !== null) && !($parentWrapper instanceof RuntimeConfigurable)) { +            throw new Exception("Argument expected to be a RuntimeConfigurable, got something else."); +        } +        if (($target !== null) && !($target instanceof Target)) { +            throw new Exception("Argument expected to be a Target, got something else"); +        } + +		$this->configurator = $configurator; +        $this->container = $container; +		$this->parentWrapper = $parentWrapper; +        $this->target = $target; +    } + +    /** +     * Executes initialization actions required to setup the data structures +     * related to the tag. +     * <p> +     * This includes: +     * <ul> +     * <li>creation of the task object</li> +     * <li>calling the setters for attributes</li> +     * <li>adding the task to the container object</li> +     * <li>adding a reference to the task (if id attribute is given)</li> +     * <li>executing the task if the container is the <project> +     * element</li> +     * </ul> +     * +     * @param string $tag The tag that comes in +     * @param array $attrs Attributes the tag carries +     * @throws ExpatParseException if attributes are incomplete or invalid +     */ +    function init($tag, $attrs) { +        // shorthands +        try { +            $configurator = $this->configurator; +            $project = $this->configurator->project; +             +            $this->task = $project->createTask($tag); +        } catch (BuildException $be) { +            // swallow here, will be thrown again in +            // UnknownElement->maybeConfigure if the problem persists. +            print("Swallowing exception: ".$be->getMessage() . "\n"); +        } + +        // the task is not known of bat, try to load it on thy fly +        if ($this->task === null) { +            $this->task = new UnknownElement($tag); +            $this->task->setProject($project); +            $this->task->setTaskType($tag); +            $this->task->setTaskName($tag); +        } + +        // add file position information to the task (from parser) +        // should be used in task exceptions to provide details +        $this->task->setLocation($this->parser->getLocation()); +        $configurator->configureId($task, $attrs); +		 +		if ($this->container) { +			$this->container->addTask($this->task); +		} +		 +        // Top level tasks don't have associated targets +		// FIXME: if we do like Ant 1.6 and create an implicitTarget in the projectconfigurator object +		// then we don't need to check for null here ... but there's a lot of stuff that will break if we +		// do that at this point. +        if ($this->target !== null) { +            $this->task->setOwningTarget($this->target); +            $this->task->init(); +            $this->wrapper = $this->task->getRuntimeConfigurableWrapper(); +            $this->wrapper->setAttributes($attrs); +			if ($this->parentWrapper !== null) { // this may not make sense only within this if-block, but it +												// seems to address current use cases adequately +		    	$this->parentWrapper->addChild($this->wrapper); +			} +        } else { +            $this->task->init(); +            $configurator->configure($this->task, $attrs, $project); +        } +    } + +    /** +     * Executes the task at once if it's directly beneath the <project> tag. +     */ +    protected function finished() { +        if ($this->task !== null && $this->target === null) { +            try { +                $this->task->main(); +            } catch (Exception $e) { +                $this->task->log($e->getMessage(), PROJECT_MSG_ERR); +                throw $e; +            } +        } +    } + +    /** +     * Handles character data. +     * +     * @param string $data The CDATA that comes in +     */ +    function characters($data) { +        if ($this->wrapper === null) { +            $configurator = $this->configurator; +            $project = $this->configurator->project; +            try { // try +                $configurator->addText($project, $this->task, $data); +            } catch (BuildException $exc) { +                throw new ExpatParseException($exc->getMessage(), $this->parser->getLocation()); +            } +        } else { +            $this->wrapper->addText($data); +        } +    } + +    /** +     * Checks for nested tags within the current one. Creates and calls +     * handlers respectively. +     * +     * @param string $name The tag that comes in +     * @param array $attrs Attributes the tag carries +     */ +    function startElement($name, $attrs) { +        $project = $this->configurator->project; +        if ($this->task instanceof TaskContainer) { +            //print("TaskHandler::startElement() (TaskContainer) name = $name, attrs = " . implode(",",$attrs) . "\n"); +            $th = new TaskHandler($this->parser, $this, $this->configurator, $this->task, $this->wrapper, $this->target); +            $th->init($name, $attrs); +        } else { +            //print("TaskHandler::startElement() name = $name, attrs = " . implode(",",$attrs) . "\n"); +            $tmp = new NestedElementHandler($this->parser, $this, $this->configurator, $this->task, $this->wrapper, $this->target); +            $tmp->init($name, $attrs); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/system/io/BufferedReader.php b/buildscripts/phing/classes/phing/system/io/BufferedReader.php new file mode 100644 index 00000000..4946985c --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/BufferedReader.php @@ -0,0 +1,170 @@ +<?php +/* + *  $Id: BufferedReader.php,v 1.6 2005/12/27 19:12:13 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/system/io/Reader.php'; + +/* + * Convenience class for reading files. + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @version   $Revision: 1.6 $ $Date: 2005/12/27 19:12:13 $ + * @access    public + * @see       FilterReader + * @package   phing.system.io +*/ +class BufferedReader extends Reader { + +    private $bufferSize = 0; +    private $buffer     = null; +    private $bufferPos  = 0; +     +    /** +     * The Reader we are buffering for. +     */ +    private $in; +     +    /** +     *  +     * @param object $reader The reader (e.g. FileReader). +     * @param integer $buffsize The size of the buffer we should use for reading files. +     *                             A large buffer ensures that most files (all scripts?) are parsed in 1 buffer. +     */      +    function __construct(Reader $reader, $buffsize = 65536) { +        $this->in = $reader; +        $this->bufferSize = $buffsize; +    } + +    /** +     * Reads and returns $_bufferSize chunk of data. +     * @return mixed buffer or -1 if EOF. +     */ +    function read($len = null) { +        // ignore $len param, not sure how to hanlde it, since  +        // this should only read bufferSize amount of data. +        if ($len !== null) { +            $this->currentPosition = ftell($this->fd); +        } +         +        if ( ($data = $this->in->read($this->bufferSize)) !== -1 ) { +		 +			// not all files end with a newline character, so we also need to check EOF +			if (!$this->in->eof()) { +			 +	            $notValidPart = strrchr($data, "\n"); +	            $notValidPartSize = strlen($notValidPart); +	         +	            if ( $notValidPartSize > 1 ) { +	                // Block doesn't finish on a EOL +	                // Find the last EOL and forgot all following stuff +	                $dataSize = strlen($data); +	                $validSize = $dataSize - $notValidPartSize + 1; +	             +	                $data = substr($data, 0, $validSize); +	 +	                // Rewind to the begining of the forgotten stuff. +	                $this->in->skip(-$notValidPartSize+1); +	            } +				 +			} // if !EOF +        } +        return $data; +    } +     +    function skip($n) { +        return $this->in->skip($n); +    } +     +    function reset() { +        return $this->in->reset(); +    } +     +    function close() { +        return $this->in->close(); +    } +     +    function open() { +        return $this->in->open(); +    } +     +    /** +     * Read a line from input stream. +     */ +    function readLine() { +        $line = null; +        while ( ($ch = $this->readChar()) !== -1 ) { +            if ( $ch === "\n" ) { +                break; +            } +            $line .= $ch; +        } + +        // Warning : Not considering an empty line as an EOF +        if ( $line === null && $ch !== -1 ) +            return ""; + +        return $line; +    } +     +    /** +     * Reads a single char from the reader. +     * @return string single char or -1 if EOF. +     */ +    function readChar() {         + +        if ( $this->buffer === null ) { +            // Buffer is empty, fill it ... +            $read = $this->in->read($this->bufferSize); +            if ($read === -1) { +                $ch = -1; +            } else { +                $this->buffer = $read; +                return $this->readChar(); // recurse +            } +        } else {             +            // Get next buffered char ... +            // handle case where buffer is read-in, but is empty.  The next readChar() will return -1 EOF, +            // so we just return empty string (char) at this point.  (Probably could also return -1 ...?) +            $ch = ($this->buffer !== "") ? $this->buffer{$this->bufferPos} : ''; +            $this->bufferPos++; +            if ( $this->bufferPos >= strlen($this->buffer) ) { +                $this->buffer = null; +                $this->bufferPos = 0; +            } +        } + +        return $ch; +    } +     +    /** +     * Returns whether eof has been reached in stream. +     * This is important, because filters may want to know if the end of the file (and not just buffer) +     * has been reached. +     * @return boolean +     */  +    function eof() { +        return $this->in->eof(); +    } + +    function getResource() { +        return $this->in->getResource(); +    }     +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/BufferedWriter.php b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php new file mode 100644 index 00000000..c982db28 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php @@ -0,0 +1,72 @@ +<?php +/* + *  $Id: BufferedWriter.php,v 1.10 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +include_once 'phing/system/io/Writer.php'; + +/** + * Convenience class for writing files. + * + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.10 $ + * @package   phing.system.io  + */ +class BufferedWriter extends Writer { +     +    /** +     * The size of the buffer in kb. +     */ +    private $bufferSize    = 0; +     +    /** +     * The Writer we are buffering output to. +     */ +    private $out; + +    function __construct(Writer $writer, $buffsize = 8192) { +        $this->out = $writer; +        $this->bufferSize = $buffsize; +    } + +    function write($buf, $off = null, $len = null) { +        return $this->out->write($buf, $off, $len); +    } +     +    function newLine() { +        $this->write(Phing::getProperty('line.separator')); +    } +     +    function getResource() { +        return $this->out->getResource(); +    } + +    function reset() { +        return $this->out->reset(); +    } +     +    function close() { +        return $this->out->close(); +    } +     +    function open() { +        return $this->out->open(); +    } +     +} diff --git a/buildscripts/phing/classes/phing/system/io/ConsoleReader.php b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php new file mode 100644 index 00000000..33b37619 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php @@ -0,0 +1,84 @@ +<?php +/* + *  $Id: ConsoleReader.php,v 1.4 2004/08/12 16:26:12 matthewh Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading console input. + *  + * @author Hans Lellelid <hans@xmpl.org> + * @author Matthew Hershberger <matthewh@lightsp.com> + * @version $Revision: 1.4 $ + * @package phing.system.io + */ +class ConsoleReader extends Reader { +     +    function readLine() { +         +        $out = fgets(STDIN); // note: default maxlen is 1kb +        $out = rtrim($out); + +        return $out; +    } +     +    /** +     *  +     * @param int $len Num chars to read. +     * @return string chars read or -1 if eof. +     */ +    function read($len = null) { +         +        $out = fread(STDIN, $len); +         +         +        return $out; +        // FIXME +        // read by chars doesn't work (yet?) with PHP stdin.  Maybe +        // this is just a language feature, maybe there's a way to get +        // ability to read chars w/o <enter> ? +         +    }    +         +    function close() { +		// STDIN is always open +    } + +    function open() { +		// STDIN is always open +    } + +    /** +     * Whether eof has been reached with stream. +     * @return boolean +     */ +    function eof() { +        return feof(STDIN); +    }         +     +    /** +     * Returns path to file we are reading. +     * @return string +     */ +    function getResource() { +        return "console"; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FileReader.php b/buildscripts/phing/classes/phing/system/io/FileReader.php new file mode 100644 index 00000000..cbea2c7e --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileReader.php @@ -0,0 +1,179 @@ +<?php +/* + *  $Id: FileReader.php,v 1.9 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading files. The constructor of this + *  @package   phing.system.io + */ + +class FileReader extends Reader { + +    protected $file; +    protected $fd; + +    protected $currentPosition = 0; +    protected $mark = 0; + +    function __construct($file, $exclusive = false) { +     +        if ($file instanceof PhingFile) { +            $this->file = $file; +        } elseif (is_string($file)) { +            $this->file = new PhingFile($file); +        } else { +            throw new Exception("Illegal argument type to " . __METHOD__); +        } +    } + +    function skip($n) { +        $this->open(); + +        $start = $this->currentPosition; + +        $ret = @fseek($this->fd, $n, SEEK_CUR); +        if ( $ret === -1 ) +            return -1; + +        $this->currentPosition = ftell($this->fd); + +        if ( $start > $this->currentPosition ) +            $skipped = $start - $this->currentPosition; +        else +            $skipped = $this->currentPosition - $start; + +        return $skipped; +    } +     +    /** +     * Read data from file. +     * @param int $len Num chars to read. +     * @return string chars read or -1 if eof. +     */ +    function read($len = null) { +        $this->open(); +        if (feof($this->fd)) { +            return -1; +        } + +        // Compute length to read +        // possible that filesize($this->file) will be larger than  +        // available bytes to read, but that's fine -- better to err on high end +        $length = ($len === null) ? filesize($this->file->getAbsolutePath()) : $len; + +        // Read data +        $out = fread($this->fd, $length + 1); // adding 1 seems to ensure that next call to read() will return EOF (-1) +        $this->currentPosition = ftell($this->fd); + +        return $out; +    }     +     +    function mark($n = null) { +        $this->mark = $this->currentPosition; +    } +     +    function reset() { +        // goes back to last mark, by default this would be 0 (i.e. rewind file). +        fseek($this->fd, SEEK_SET, $this->mark); +        $this->mark = 0; +    } + +    function close() { +        if ($this->fd === null) { +            return true; +        } + +        if (false === @fclose($this->fd)) { +            // FAILED. +            $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; +            throw new IOException($msg); +        } else { +            $this->fd = null; +            return true; +        } +    } + +    function open() { +        global $php_errormsg; +         +        if ($this->fd === null) { +            $this->fd = @fopen($this->file->getAbsolutePath(), "rb"); +        } + +        if ($this->fd === false) { +            // fopen FAILED. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "Cannot fopen ".$this->file->getAbsolutePath().". $php_errormsg"; +            throw new IOException($msg); +        } + +        if (false) { +            // Locks don't seem to work on windows??? HELP!!!!!!!!! +            // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. +            $msg = "Cannot acquire flock on $file. $php_errormsg"; +            throw new IOException($msg); +        } + +        return true; +    } + +    /** +     * Whether eof has been reached with stream. +     * @return boolean +     */ +    function eof() { +        return feof($this->fd); +    } +      +    /** +     * Reads a entire file and stores the data in the variable +     * passed by reference. +     * +     * @param    string $file    String. Path and/or name of file to read. +     * @param    object &$rBuffer    Reference. Variable of where to put contents. +     * +     * @return    TRUE on success. Err object on failure. +     * @author  Charlie Killian, charlie@tizac.com +     */ +    function readInto(&$rBuffer) { + +        $this->open(); + +        $fileSize = $this->file->length(); +        if ($fileSize === false) { +            $msg = "Cannot get filesize of " . $this->file->__toString() . " $php_errormsg"; +            throw new IOException($msg); +        } +        $rBuffer = fread($this->fd, $fileSize); +        $this->close(); +    } +     +    /** +     * Returns path to file we are reading. +     * @return string +     */ +    function getResource() { +        return $this->file->toString(); +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FileSystem.php b/buildscripts/phing/classes/phing/system/io/FileSystem.php new file mode 100644 index 00000000..2802ddfb --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileSystem.php @@ -0,0 +1,657 @@ +<?php + +/*  + *  $Id: FileSystem.php,v 1.11 2005/12/01 20:56:59 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * This is an abstract class for platform specific filesystem implementations + * you have to implement each method in the platform specific filesystem implementation + * classes Your local filesytem implementation must extend this class. + * You should also use this class as a template to write your local implementation + * Some native PHP filesystem specific methods are abstracted here as well. Anyway + * you _must_ always use this methods via a PhingFile object (that by nature uses the + * *FileSystem drivers to access the real filesystem via this class using natives. + * + * FIXME: + *  - Error handling reduced to min fallthrough runtime excetions + *    more precise errorhandling is done by the PhingFile class + *     + * @author Charlie Killian <charlie@tizac.com> + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.11 $ + * @package phing.system.io + */ +abstract class FileSystem {     + +    /* properties for simple boolean attributes */ +    const BA_EXISTS    = 0x01; +    const BA_REGULAR   = 0x02; +    const BA_DIRECTORY = 0x04; +    const BA_HIDDEN    = 0x08; +     +    /** Instance for getFileSystem() method. */ +    private static $fs; +     +    /** +     * Static method to return the FileSystem singelton representing +     * this platform's local filesystem driver. +     */ +    function getFileSystem() { +        if (self::$fs === null) { +            switch(Phing::getProperty('host.fstype')) { +                case 'UNIX': +                    include_once 'phing/system/io/UnixFileSystem.php'; +                    self::$fs = new UnixFileSystem(); +                break; +                case 'WIN32': +                    include_once 'phing/system/io/Win32FileSystem.php'; +                    self::$fs = new Win32FileSystem(); +                break; +                case 'WINNT': +                    include_once 'phing/system/io/WinNTFileSystem.php'; +                    self::$fs = new WinNTFileSystem(); +                break; +                default: +                    throw new Exception("Host uses unsupported filesystem, unable to proceed"); +            } +        } +        return self::$fs; +    } + +    /* -- Normalization and construction -- */ + +    /** +     * Return the local filesystem's name-separator character. +     */ +    abstract function getSeparator(); + +    /** +     * Return the local filesystem's path-separator character. +     */ +    abstract function getPathSeparator(); + +    /** +     * Convert the given pathname string to normal form.  If the string is +     * already in normal form then it is simply returned. +     */ +    abstract function normalize($strPath); + +    /** +     * Compute the length of this pathname string's prefix.  The pathname +     * string must be in normal form. +     */ +    abstract function prefixLength($pathname); + +    /** +     * Resolve the child pathname string against the parent. +     * Both strings must be in normal form, and the result +     * will be a string in normal form. +     */ +    abstract function resolve($parent, $child); +     +    /** +     * Resolve the given abstract pathname into absolute form.  Invoked by the +     * getAbsolutePath and getCanonicalPath methods in the PhingFile class. +     */ +    abstract function resolveFile(PhingFile $f); + +    /** +     * Return the parent pathname string to be used when the parent-directory +     * argument in one of the two-argument PhingFile constructors is the empty +     * pathname. +     */ +    abstract function getDefaultParent(); + +    /** +     * Post-process the given URI path string if necessary.  This is used on +     * win32, e.g., to transform "/c:/foo" into "c:/foo".  The path string +     * still has slash separators; code in the PhingFile class will translate them +     * after this method returns. +     */ +    abstract function fromURIPath($path); + +    /* -- Path operations -- */ + +    /** +     * Tell whether or not the given abstract pathname is absolute. +     */ +    abstract function isAbsolute(PhingFile $f); + +    /**  +     * canonicalize filename by checking on disk  +     * @return mixed Canonical path or false if the file doesn't exist. +     */ +    function canonicalize($strPath) { +        return @realpath($strPath);         +    } + +    /* -- Attribute accessors -- */ + +    /** +     * Return the simple boolean attributes for the file or directory denoted +     * by the given abstract pathname, or zero if it does not exist or some +     * other I/O error occurs. +     */ +    function getBooleanAttributes($f) { +        throw new Exception("SYSTEM ERROR method getBooleanAttributes() not implemented by fs driver"); +    } + +    /** +     * Check whether the file or directory denoted by the given abstract +     * pathname may be accessed by this process.  If the second argument is +     * false, then a check for read access is made; if the second +     * argument is true, then a check for write (not read-write) +     * access is made.  Return false if access is denied or an I/O error +     * occurs. +     */ +    function checkAccess(PhingFile $f, $write = false) { +        // we clear stat cache, its expensive to look up from scratch, +        // but we need to be sure +        @clearstatcache(); + + +        // Shouldn't this be $f->GetAbsolutePath() ? +        // And why doesn't GetAbsolutePath() work? + +        $strPath = (string) $f->getPath(); + +        // FIXME +        // if file object does denote a file that yet not existst +        // path rights are checked +        if (!@file_exists($strPath) && !is_dir($strPath)) { +            $strPath = $f->getParent(); +            if ($strPath === null || !is_dir($strPath)) { +                $strPath = Phing::getProperty("user.dir"); +            } +            //$strPath = dirname($strPath); +        } + +        if (!$write) { +            return (boolean) @is_readable($strPath); +        } else { +            return (boolean) @is_writable($strPath); +        } +    } + +    /** +     * Return the time at which the file or directory denoted by the given +     * abstract pathname was last modified, or zero if it does not exist or +     * some other I/O error occurs. +     */ +    function getLastModifiedTime(PhingFile $f) { +         +        if (!$f->exists()) { +            return 0; +        } + +        @clearstatcache(); +        $strPath = (string) $f->getPath(); +        $mtime = @filemtime($strPath); +        if (false === $mtime) { +            // FAILED. Log and return err. +            $msg = "FileSystem::Filemtime() FAILED. Cannot can not get modified time of $strPath. $php_errormsg"; +            throw new Exception($msg); +        } else { +            return (int) $mtime; +        } +    } + +    /** +     * Return the length in bytes of the file denoted by the given abstract +     * pathname, or zero if it does not exist, is a directory, or some other +     * I/O error occurs. +     */ +    function getLength(PhingFile $f) { +        $strPath = (string) $f->getAbsolutePath(); +        $fs = filesize((string) $strPath); +        if ($fs !== false) { +            return $fs; +        } else { +            $msg = "FileSystem::Read() FAILED. Cannot get filesize of $strPath. $php_errormsg"; +            throw new Exception($msg); +        } +    } + +    /* -- File operations -- */ + +    /** +     * Create a new empty file with the given pathname.  Return +     * true if the file was created and false if a +     * file or directory with the given pathname already exists.  Throw an +     * IOException if an I/O error occurs. +     * +     * @param       string      Path of the file to be created. +     *      +     * @throws      IOException +     */ +    function createNewFile($strPathname) { +        if (@file_exists($strPathname)) +            return false; +             +        // Create new file +        $fp = @fopen($strPathname, "w"); +        if ($fp === false) { +            throw new IOException("The file \"$strPathname\" could not be created");             +        } +        @fclose($fp);         +        return true; +    } + +    /** +     * Delete the file or directory denoted by the given abstract pathname, +     * returning true if and only if the operation succeeds. +     */ +    function delete(PhingFile $f) { +        if ($f->isDirectory()) { +            return $this->rmdir($f->getPath()); +        } else { +            return $this->unlink($f->getPath()); +        } +    } + +    /** +     * Arrange for the file or directory denoted by the given abstract +     * pathname to be deleted when Phing::shutdown is called, returning +    * true if and only if the operation succeeds. +     */ +    function deleteOnExit($f) { +        throw new Exception("deleteOnExit() not implemented by local fs driver"); +    } + +    /** +     * List the elements of the directory denoted by the given abstract +     * pathname.  Return an array of strings naming the elements of the +     * directory if successful; otherwise, return <code>null</code>. +     */ +    function listDir(PhingFile $f) { +        $strPath = (string) $f->getAbsolutePath(); +        $d = @dir($strPath); +        if (!$d) { +            return null; +        } +        $list = array(); +        while($entry = $d->read()) { +            if ($entry != "." && $entry != "..") { +                array_push($list, $entry); +            } +        } +        $d->close(); +        unset($d); +        return $list; +    } + +    /** +     * Create a new directory denoted by the given abstract pathname, +     * returning true if and only if the operation succeeds. +     */ +    function createDirectory(&$f) { +        return @mkdir($f->getAbsolutePath(),0755); +    } + +    /** +     * Rename the file or directory denoted by the first abstract pathname to +     * the second abstract pathname, returning true if and only if +     * the operation succeeds. +     * +     * @param PhingFile $f1 abstract source file +     * @param PhingFile $f2 abstract destination file +     * @return void     +     * @throws Exception if rename cannot be performed +     */ +    function rename(PhingFile $f1, PhingFile $f2) {         +        // get the canonical paths of the file to rename +        $src = $f1->getAbsolutePath(); +        $dest = $f2->getAbsolutePath(); +        if (false === @rename($src, $dest)) { +            $msg = "Rename FAILED. Cannot rename $src to $dest. $php_errormsg"; +            throw new Exception($msg); +        } +    } + +    /** +     * Set the last-modified time of the file or directory denoted by the +     * given abstract pathname returning true if and only if the +     * operation succeeds. +     * @return void +     * @throws Exception +     */ +    function setLastModifiedTime(PhingFile $f, $time) {         +        $path = $f->getPath(); +        $success = @touch($path, $time); +        if (!$success) { +            throw new Exception("Could not create directory due to: $php_errormsg"); +        } +    } + +    /** +     * Mark the file or directory denoted by the given abstract pathname as +     * read-only, returning <code>true</code> if and only if the operation +     * succeeds. +     */ +    function setReadOnly($f) { +        throw new Exception("setReadonle() not implemented by local fs driver"); +    } + +    /* -- Filesystem interface -- */ + +    /** +     * List the available filesystem roots, return array of PhingFile objects +     */ +    function listRoots() { +        throw new Exception("SYSTEM ERROR [listRoots() not implemented by local fs driver]"); +    } + +    /* -- Basic infrastructure -- */ + +    /** +     * Compare two abstract pathnames lexicographically. +     */ +    function compare($f1, $f2) { +        throw new Exception("SYSTEM ERROR [compare() not implemented by local fs driver]"); +    } + +    /** +     * Copy a file. +     * +     * @param PhingFile $src Source path and name file to copy. +     * @param PhingFile $dest Destination path and name of new file. +     * +     * @return void      +     * @throws Exception if file cannot be copied. +     */ +    function copy(PhingFile $src, PhingFile $dest) { +        global $php_errormsg; +        $srcPath  = $src->getAbsolutePath(); +        $destPath = $dest->getAbsolutePath(); + +        if (false === @copy($srcPath, $destPath)) { // Copy FAILED. Log and return err. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::copy() FAILED. Cannot copy $srcPath to $destPath. $php_errormsg"; +            throw new Exception($msg); +        } +         +        try { +            $dest->setMode($src->getMode()); +        } catch(Exception $exc) { +            // [MA] does chmod returns an error on systems that do not support it ? +            // eat it up for now. +        } +    } + +    /** +     * Change the permissions on a file or directory. +     * +     * @param    pathname    String. Path and name of file or directory. +     * @param    mode        Int. The mode (permissions) of the file or +     *                        directory. If using octal add leading 0. eg. 0777. +     *                        Mode is affected by the umask system setting. +     * +     * @return void      +     * @throws Exception if operation failed. +     */ +    function chmod($pathname, $mode) {     +        $str_mode = decoct($mode); // Show octal in messages.     +        if (false === @chmod($pathname, $mode)) {// FAILED. +            $msg = "FileSystem::chmod() FAILED. Cannot chmod $pathname. Mode $str_mode. $php_errormsg"; +            throw new Exception($msg); +        } +    } + +    /** +     * Locks a file and throws an Exception if this is not possible. +     * @return void +     * @throws Exception +     */ +    function lock(PhingFile $f) { +        $filename = $f->getPath(); +        $fp = @fopen($filename, "w"); +        $result = @flock($fp, LOCK_EX); +        @fclose($fp); +        if (!$result) { +            throw new Exception("Could not lock file '$filename'"); +        } +    } + +    /** +     * Unlocks a file and throws an IO Error if this is not possible. +     * +     * @throws Exception +     * @return void +     */ +    function unlock(PhingFile $f) { +        $filename = $f->getPath(); +        $fp = @fopen($filename, "w"); +        $result = @flock($fp, LOCK_UN); +        fclose($fp); +        if (!$result) { +            throw new Exception("Could not unlock file '$filename'"); +        } +    } + +    /** +     * Delete a file. +     * +     * @param    file    String. Path and/or name of file to delete. +     * +     * @return void +     * @throws Exception - if an error is encountered. +     */ +    function unlink($file) { +        global $php_errormsg; +        if (false === @unlink($file)) { +            $msg = "FileSystem::unlink() FAILED. Cannot unlink '$file'. $php_errormsg"; +            throw new Exception($msg); +        } +    } + +    /** +     * Symbolically link a file to another name. +     *  +     * Currently symlink is not implemented on Windows. Don't use if the application is to be portable. +     * +     * @param string $target Path and/or name of file to link. +     * @param string $link Path and/or name of link to be created. +     * @return void +     */ +    function symlink($target, $link) { +     +        // If Windows OS then symlink() will report it is not supported in +        // the build. Use this error instead of checking for Windows as the OS. + +        if (false === @symlink($target, $link)) { +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::Symlink() FAILED. Cannot symlink '$target' to '$link'. $php_errormsg"; +            throw new Exception($msg); +        } + +    } + +    /** +     * Set the modification and access time on a file to the present time. +     * +     * @param string $file Path and/or name of file to touch. +     * @param int $time  +     * @return void +     */ +    function touch($file, $time = null) { +        global $php_errormsg; +         +        if (null === $time) { +            $error = @touch($file); +        } else { +            $error = @touch($file, $time); +        } + +        if (false === $error) { // FAILED. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::touch() FAILED. Cannot touch '$file'. $php_errormsg";             +            throw new Exception($msg);             +        } +    } + +    /** +     * Delete an empty directory OR a directory and all of its contents. +     * +     * @param    dir    String. Path and/or name of directory to delete. +     * @param    children    Boolean.    False: don't delete directory contents. +     *                                    True: delete directory contents. +     * +     * @return void +     */ +    function rmdir($dir, $children = false) { +        global $php_errormsg; +         +        // If children=FALSE only delete dir if empty. +        if (false === $children) { +         +            if (false === @rmdir($dir)) { // FAILED. +                // Add error from php to end of log message. $php_errormsg. +                $msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg"; +                throw new Exception($msg); +            } +             +        } else { // delete contents and dir. + +            $handle = @opendir($dir); + +            if (false === $handle) { // Error. + +                $msg = "FileSystem::rmdir() FAILED. Cannot opendir() $dir. $php_errormsg";                 +                throw new Exception($msg); + +            } else { // Read from handle. + +                // Don't error on readdir(). +                while (false !== ($entry = @readdir($handle))) { + +                    if ($entry != '.' && $entry != '..') { + +                        // Only add / if it isn't already the last char. +                        // This ONLY serves the purpose of making the Logger +                        // output look nice:) + +                        if (strpos(strrev($dir), DIRECTORY_SEPARATOR) === 0) {// there is a / +                            $next_entry = $dir . $entry; +                        } else { // no / +                            $next_entry = $dir . DIRECTORY_SEPARATOR . $entry; +                        } + +                        // NOTE: As of php 4.1.1 is_dir doesn't return FALSE it +                        // returns 0. So use == not ===. + +                        // Don't error on is_dir() +                        if (false == @is_dir($next_entry)) { // Is file. +                             +                            try { +                                self::unlink($next_entry); // Delete. +                            } catch (Exception $e) {                             +                                $msg = "FileSystem::Rmdir() FAILED. Cannot FileSystem::Unlink() $next_entry. ". $e->getMessage(); +                                throw new Exception($msg); +                            } + +                        } else { // Is directory. +                             +                            try { +                                self::rmdir($next_entry, true); // Delete +                            } catch (Exception $e) { +                                $msg = "FileSystem::rmdir() FAILED. Cannot FileSystem::rmdir() $next_entry. ". $e->getMessage(); +                                throw new Exception($msg); +                            } + +                        } // end is_dir else +                    } // end .. if +                } // end while +            } // end handle if + +            // Don't error on closedir() +            @closedir($handle); +             +            if (false === @rmdir($dir)) { // FAILED. +                // Add error from php to end of log message. $php_errormsg. +                $msg = "FileSystem::rmdir() FAILED. Cannot rmdir $dir. $php_errormsg"; +                throw new Exception($msg); +            } +             +        } +                 +    } + +    /** +     * Set the umask for file and directory creation. +     * +     * @param    mode    Int. Permissions ususally in ocatal. Use leading 0 for +     *                    octal. Number between 0 and 0777. +     * +     * @return void +     * @throws Exception if there is an error performing operation.      +     */ +    function umask($mode) { +        global $php_errormsg; +         +        // CONSIDERME: +        // Throw a warning if mode is 0. PHP converts illegal octal numbers to +        // 0 so 0 might not be what the user intended. +                         +        $str_mode = decoct($mode); // Show octal in messages. + +        if (false === @umask($mode)) { // FAILED. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::Umask() FAILED. Value $mode. $php_errormsg"; +            throw new Exception($msg); +        } +    } + +    /** +     * Compare the modified time of two files. +     * +     * @param    file1    String. Path and name of file1. +     * @param    file2    String. Path and name of file2. +     * +     * @return    Int.     1 if file1 is newer. +     *                 -1 if file2 is newer. +     *                  0 if files have the same time. +     *                  Err object on failure. +     *      +     * @throws Exception - if cannot get modified time of either file. +     */ +    function compareMTimes($file1, $file2) { + +        $mtime1 = filemtime($file1); +        $mtime2 = filemtime($file2); + +        if ($mtime1 === false) { // FAILED. Log and return err.         +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file1."; +            throw new Exception($msg);             +        } elseif ($mtime2 === false) { // FAILED. Log and return err. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "FileSystem::compareMTimes() FAILED. Cannot can not get modified time of $file2."; +            throw new Exception($msg); +        } else { // Worked. Log and return compare.                 +            // Compare mtimes. +            if ($mtime1 == $mtime2) { +                return 0; +            } else { +                return ($mtime1 < $mtime2) ? -1 : 1; +            } // end compare +        } +    } +         +} diff --git a/buildscripts/phing/classes/phing/system/io/FileWriter.php b/buildscripts/phing/classes/phing/system/io/FileWriter.php new file mode 100644 index 00000000..d6265777 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FileWriter.php @@ -0,0 +1,139 @@ +<?php +/* + *  $Id: FileWriter.php,v 1.7 2005/05/26 13:10:52 mrook Exp $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/Writer.php'; + +/** + * Convenience class for reading files. The constructor of this + * + * @package   phing.system.io + */ +class FileWriter extends Writer { + +    protected $file; +    protected $fd; +     +    /** Whether to append contents to file. */ +    protected $append; +     +    /** Whether we should attempt to lock the file (currently disabled). */ +    protected $exclusive; +     +    /** +     * Construct a new FileWriter. +     * @param mixed $file PhingFile or string pathname. +     * @param boolean $append Append to existing file? +     * @param boolean $exclusive Lock file? (currently disabled due to windows incompatibility) +     */ +    function __construct($file, $append = false, $exclusive = false) { +        if ($file instanceof PhingFile) { +            $this->file = $file; +        } elseif (is_string($file)) { +            $this->file = new PhingFile($file); +        } else { +            throw new Exception("Invalid argument type for \$file."); +        } +        $this->append = $append; +        $this->exclusive = $exclusive; +    } + +    function close() { +        if ($this->fd === null) { +            return true; +        } + +        if (false === @fclose($this->fd)) { +            // FAILED. +            $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; +            throw new IOException($msg); +        } else { +            $this->fd = null; +            return true; +        } +    } + +    function open() { +        if ($this->fd === null) { +            if ($this->append) { $flags = "ab"; } else { $flags = "wb"; } +            $this->fd = @fopen($this->file->getPath(), $flags); +        } + +        if ($this->fd === false) { +            // fopen FAILED. +            // Add error from php to end of log message. $php_errormsg. +            $msg = "Cannot fopen ".$this->file->getPath()." $php_errormsg"; +            throw new IOException($msg); +        } + +        if (false) { +            // Locks don't seem to work on windows??? HELP!!!!!!!!! +            // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. +            $msg = "Cannot acquire flock on $file. $php_errormsg"; +            throw new IOException($msg); +        } + +        return true; +    } +     +    function reset() { +        // FIXME -- what exactly should this do, if anything? +        // reset to beginning of file (i.e. re-open)? +    } +     +    function writeBuffer($buffer) { + +        if (!$this->file->canWrite()) { +            throw new IOException("No permission to write to file: " . $this->file->__toString()); +        } + +        $this->open(); +        $result = @fwrite($this->fd, $buffer); +        $this->close(); + +        if ($result === false) { +            throw new IOException("Error writing file: ". $this->file->toString()); +        } else { +            return true; +        } +    } + +    function write($buf, $off = null, $len = null) { +        if ( $off === null && $len === null ) +            $to_write = $buf; +        else +            $to_write = substr($buf, $off, $len); + +        $this->open(); +        $result = @fwrite($this->fd, $to_write); + +        if ( $result === false ) { +            throw new IOException("Error writing file."); +        } else { +            return true; +        } +    } +     +    function getResource() { +        return $this->file->toString(); +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/FilterReader.php b/buildscripts/phing/classes/phing/system/io/FilterReader.php new file mode 100644 index 00000000..8c683408 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/FilterReader.php @@ -0,0 +1,72 @@ +<?php +/* + *  $Id: FilterReader.php,v 1.6 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/system/io/Reader.php'; + +/** + * Convenience class for reading files. The constructor of this + *  @package   phing.system.io + * + * TODO: All filters should be ProjectComponents, too! + */ +class FilterReader extends Reader { +     +    protected $in; +     +    function __construct(Reader $in = null) { +        $this->in = $in; +        //parent::__construct(new FileReader($file, $exclusive)); +    } +     +    public function setReader(Reader $in) { +        $this->in = $in; +    } +     +    public function skip($n) { +        return $this->in->skip($n); +    } +     +    /** +     * Read data from source. +     * FIXME: Clean up this function signature, as it a) params aren't being used +     * and b) it doesn't make much sense. +     */ +    public function read($len = null) { +        return $this->in->read($len); +    } + +    public function reset() { +        return $this->in->reset(); +    } +     +    public function close() { +        return $this->in->close(); +    } +     +    public function open() { +        return $this->in->open(); +    } + +    function getResource() { +        return $this->in->getResource(); +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/IOException.php b/buildscripts/phing/classes/phing/system/io/IOException.php new file mode 100644 index 00000000..e2c73b27 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/IOException.php @@ -0,0 +1,28 @@ +<?php +/* + *  $Id: IOException.php,v 1.4 2005/02/27 20:52:09 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * Extends Exception to take advantage of methods therein. + * + * @package   phing.system.io + */ +class IOException extends Exception {} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/io/PhingFile.php b/buildscripts/phing/classes/phing/system/io/PhingFile.php new file mode 100644 index 00000000..cd881963 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/PhingFile.php @@ -0,0 +1,866 @@ +<?php +/* + *  $Id: PhingFile.php,v 1.1 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/io/FileSystem.php'; +include_once 'phing/system/lang/NullPointerException.php'; + +/** + * An abstract representation of file and directory pathnames. + * + * @version   $Revision: 1.1 $ + * @package   phing.system.io + */ +class PhingFile { + +    /** separator string, static, obtained from FileSystem */ +    public static $separator; + +    /** path separator string, static, obtained from FileSystem (; or :)*/ +    public static $pathSeparator; +     +    /** +     * This abstract pathname's normalized pathname string.  A normalized +     * pathname string uses the default name-separator character and does not +     * contain any duplicate or redundant separators. +     */ +    private $path = null; + +    /** The length of this abstract pathname's prefix, or zero if it has no prefix. */ +    private $prefixLength = 0; + +    /** constructor */ +    function __construct($arg1 = null, $arg2 = null) { +         +        if (self::$separator === null || self::$pathSeparator === null) { +            $fs = FileSystem::getFileSystem(); +            self::$separator = $fs->getSeparator(); +            self::$pathSeparator = $fs->getPathSeparator(); +        } + +        /* simulate signature identified constructors */ +        if ($arg1 instanceof PhingFile && is_string($arg2)) { +            $this->_constructFileParentStringChild($arg1, $arg2); +        } elseif (is_string($arg1) && ($arg2 === null)) { +            $this->_constructPathname($arg1); +        } elseif(is_string($arg1) && is_string($arg2)) { +            $this->_constructStringParentStringChild($arg1, $arg2); +        } else { +            if ($arg1 === null) { +                throw new NullPointerException("Argument1 to function must not be null"); +            } +            $this->path = (string) $arg1; +            $this->prefixLength = (int) $arg2; +        } +    } + +    /** Returns the length of this abstract pathname's prefix. */ +    function getPrefixLength() { +        return (int) $this->prefixLength; +    } +     +    /* -- constructors not called by signature match, so we need some helpers --*/ + +    function _constructPathname($pathname) { +        // obtain ref to the filesystem layer +        $fs = FileSystem::getFileSystem(); + +        if ($pathname === null) { +            throw new NullPointerException("Argument to function must not be null"); +        } + +        $this->path = (string) $fs->normalize($pathname); +        $this->prefixLength = (int) $fs->prefixLength($this->path); +    } + +    function _constructStringParentStringChild($parent, $child = null) { +        // obtain ref to the filesystem layer +        $fs = FileSystem::getFileSystem(); + +        if ($child === null) { +            throw new NullPointerException("Argument to function must not be null"); +        } +        if ($parent !== null) { +            if ($parent === "") { +                $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); +            } else { +                $this->path = $fs->resolve($fs->normalize($parent), $fs->normalize($child)); +            } +        } else { +            $this->path = (string) $fs->normalize($child); +        } +        $this->prefixLength = (int) $fs->prefixLength($this->path); +    } + +    function _constructFileParentStringChild($parent, $child = null) { +        // obtain ref to the filesystem layer +        $fs = FileSystem::getFileSystem(); + +        if ($child === null) { +            throw new NullPointerException("Argument to function must not be null"); +        } + +        if ($parent !== null) { +            if ($parent->path === "") { +                $this->path = $fs->resolve($fs->getDefaultParent(), $fs->normalize($child)); +            } else { +                $this->path = $fs->resolve($parent->path, $fs->normalize($child)); +            } +        } else { +            $this->path = $fs->normalize($child); +        } +        $this->prefixLength = $fs->prefixLength($this->path); +    } + +    /* -- Path-component accessors -- */ + +    /** +     * Returns the name of the file or directory denoted by this abstract +     * pathname.  This is just the last name in the pathname's name +     * sequence.  If the pathname's name sequence is empty, then the empty +     * string is returned. +     * +     * @return  The name of the file or directory denoted by this abstract +     *          pathname, or the empty string if this pathname's name sequence +     *          is empty +     */ +    function getName() { +        // that's a lastIndexOf +        $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); +        if ($index < $this->prefixLength) { +            return substr($this->path, $this->prefixLength); +        } +        return substr($this->path, $index + 1); +    } + +    /** +     * Returns the pathname string of this abstract pathname's parent, or +     * null if this pathname does not name a parent directory. +     * +     * The parent of an abstract pathname consists of the pathname's prefix, +     * if any, and each name in the pathname's name sequence except for the last. +     * If the name sequence is empty then the pathname does not name a parent +     * directory. +     * +     * @return  The pathname string of the parent directory named by this +     *          abstract pathname, or null if this pathname does not name a parent +     */ +    function getParent() { +        // that's a lastIndexOf +        $index = ((($res = strrpos($this->path, self::$separator)) === false) ? -1 : $res); +        if ($index < $this->prefixLength) { +            if (($this->prefixLength > 0) && (strlen($this->path > $this->prefixLength))) { +                return substr($this->path, 0, $this->prefixLength); +            } +            return null; +        } +        return substr($this->path, 0, $index); +    } + +    /** +     * Returns the abstract pathname of this abstract pathname's parent, +     * or null if this pathname does not name a parent directory. +     * +     * The parent of an abstract pathname consists of the pathname's prefix, +     * if any, and each name in the pathname's name sequence except for the +     * last.  If the name sequence is empty then the pathname does not name +     * a parent directory. +     * +     * @return  The abstract pathname of the parent directory named by this +     *          abstract pathname, or null if this pathname +     *          does not name a parent +     */ +    function getParentFile() { +        $p = $this->getParent(); +        if ($p === null) { +            return null; +        } +        return new PhingFile((string) $p, (int) $this->prefixLength); +    } + +    /** +     * Converts this abstract pathname into a pathname string.  The resulting +     * string uses the default name-separator character to separate the names +     * in the name sequence. +     * +     * @return  The string form of this abstract pathname +     */ +    function getPath() { +        return (string) $this->path; +    } + +    /** +     * Tests whether this abstract pathname is absolute.  The definition of +     * absolute pathname is system dependent.  On UNIX systems, a pathname is +     * absolute if its prefix is "/".  On Win32 systems, a pathname is absolute +     * if its prefix is a drive specifier followed by "\\", or if its prefix +     * is "\\". +     * +     * @return  true if this abstract pathname is absolute, false otherwise +     */ +    function isAbsolute() { +        return ($this->prefixLength !== 0); +    } + + +    /** +     * Returns the absolute pathname string of this abstract pathname. +     * +     * If this abstract pathname is already absolute, then the pathname +     * string is simply returned as if by the getPath method. +     * If this abstract pathname is the empty abstract pathname then +     * the pathname string of the current user directory, which is named by the +     * system property user.dir, is returned.  Otherwise this +     * pathname is resolved in a system-dependent way.  On UNIX systems, a +     * relative pathname is made absolute by resolving it against the current +     * user directory.  On Win32 systems, a relative pathname is made absolute +     * by resolving it against the current directory of the drive named by the +     * pathname, if any; if not, it is resolved against the current user +     * directory. +     * +     * @return  The absolute pathname string denoting the same file or +     *          directory as this abstract pathname +     * @see     #isAbsolute() +     */ +    function getAbsolutePath() { +        $fs = FileSystem::getFileSystem();         +        return $fs->resolveFile($this); +    } + +    /** +     * Returns the absolute form of this abstract pathname.  Equivalent to +     * getAbsolutePath. +     * +     * @return  The absolute abstract pathname denoting the same file or +     *          directory as this abstract pathname +     */ +    function getAbsoluteFile() { +        return new PhingFile((string) $this->getAbsolutePath()); +    } + + +    /** +     * Returns the canonical pathname string of this abstract pathname. +     * +     * A canonical pathname is both absolute and unique. The precise +     * definition of canonical form is system-dependent. This method first +     * converts this pathname to absolute form if necessary, as if by invoking the +     * getAbsolutePath() method, and then maps it to its unique form in a +     * system-dependent way.  This typically involves removing redundant names +     * such as "." and .. from the pathname, resolving symbolic links +     * (on UNIX platforms), and converting drive letters to a standard case +     * (on Win32 platforms). +     * +     * Every pathname that denotes an existing file or directory has a +     * unique canonical form.  Every pathname that denotes a nonexistent file +     * or directory also has a unique canonical form.  The canonical form of +     * the pathname of a nonexistent file or directory may be different from +     * the canonical form of the same pathname after the file or directory is +     * created.  Similarly, the canonical form of the pathname of an existing +     * file or directory may be different from the canonical form of the same +     * pathname after the file or directory is deleted. +     * +     * @return  The canonical pathname string denoting the same file or +     *          directory as this abstract pathname +     */ +    function getCanonicalPath() { +        $fs = FileSystem::getFileSystem(); +        return $fs->canonicalize($this->path); +    } + + +    /** +     * Returns the canonical form of this abstract pathname.  Equivalent to +     * getCanonicalPath(. +     * +     * @return  PhingFile The canonical pathname string denoting the same file or +     *          directory as this abstract pathname +     */ +    function getCanonicalFile() { +        return new PhingFile($this->getCanonicalPath()); +    } + +    /** +     * Converts this abstract pathname into a file: URL.  The +     * exact form of the URL is system-dependent.  If it can be determined that +     * the file denoted by this abstract pathname is a directory, then the +     * resulting URL will end with a slash. +     * +     * Usage note: This method does not automatically escape +     * characters that are illegal in URLs.  It is recommended that new code +     * convert an abstract pathname into a URL by first converting it into a +     * URI, via the toURI() method, and then converting the URI +     * into a URL via the URI::toURL() +     * +     * @return  A URL object representing the equivalent file URL +     * +     * +     */ +    function toURL() { +        /* +        // URL class not implemented yet +        return new URL("file", "", $this->_slashify($this->getAbsolutePath(), $this->isDirectory())); +        */ +    } + +    /** +     * Constructs a file: URI that represents this abstract pathname. +     * Not implemented yet +     */ +    function toURI() { +        /* +        $f = $this->getAbsoluteFile(); +           $sp = (string) $this->slashify($f->getPath(), $f->isDirectory()); +           if (StringHelper::startsWith('//', $sp)) +        $sp = '//' + sp; +           return new URI('file', null, $sp, null); +        */ +    } + +    function _slashify($path, $isDirectory) { +        $p = (string) $path; + +        if (self::$separator !== '/') { +            $p = str_replace(self::$separator, '/', $p); +        } + +        if (!StringHelper::startsWith('/', $p)) { +            $p = '/'.$p; +        } + +        if (!StringHelper::endsWith('/', $p) && $isDirectory) { +            $p = $p.'/'; +        } + +        return $p; +    } + +    /* -- Attribute accessors -- */ + +    /** +     * Tests whether the application can read the file denoted by this +     * abstract pathname. +     * +     * @return  true if and only if the file specified by this +     *          abstract pathname exists and can be read by the +     *          application; false otherwise +     */ +    function canRead() { +        $fs = FileSystem::getFileSystem(); + +        if ($fs->checkAccess($this)) { +            return (boolean) @is_readable($this->getAbsolutePath()); +        } +        return false; +    } + +    /** +     * Tests whether the application can modify to the file denoted by this +     * abstract pathname. +     * +     * @return  true if and only if the file system actually +     *          contains a file denoted by this abstract pathname and +     *          the application is allowed to write to the file; +     *          false otherwise. +     * +     */ +    function canWrite() { +        $fs = FileSystem::getFileSystem(); +        return $fs->checkAccess($this, true); +    } + +    /** +     * Tests whether the file denoted by this abstract pathname exists. +     * +     * @return  true if and only if the file denoted by this +     *          abstract pathname exists; false otherwise +     * +     */ +    function exists() {                 +        if ($this->isFile()) { +            return @file_exists($this->path); +        } else { +            return @is_dir($this->path); +        } +    } + +    /** +     * Tests whether the file denoted by this abstract pathname is a +     * directory. +     * +     * @return true if and only if the file denoted by this +     *         abstract pathname exists and is a directory; +     *         false otherwise +     * +     */ +    function isDirectory() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No read access to ".$this->path); +        } +        return @is_dir($this->path); +    } + +    /** +     * Tests whether the file denoted by this abstract pathname is a normal +     * file.  A file is normal if it is not a directory and, in +     * addition, satisfies other system-dependent criteria.  Any non-directory +     * file created by a Java application is guaranteed to be a normal file. +     * +     * @return  true if and only if the file denoted by this +     *          abstract pathname exists and is a normal file; +     *          false otherwise +     */ +    function isFile() { +        //$fs = FileSystem::getFileSystem(); +        return @is_file($this->path); +    } + +    /** +     * Tests whether the file named by this abstract pathname is a hidden +     * file.  The exact definition of hidden is system-dependent.  On +     * UNIX systems, a file is considered to be hidden if its name begins with +     * a period character ('.').  On Win32 systems, a file is considered to be +     * hidden if it has been marked as such in the filesystem. Currently there +     * seems to be no way to dermine isHidden on Win file systems via PHP +     * +     * @return  true if and only if the file denoted by this +     *          abstract pathname is hidden according to the conventions of the +     *          underlying platform +     */ +    function isHidden() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No read access to ".$this->path); +        } +        return (($fs->getBooleanAttributes($this) & $fs->BA_HIDDEN) !== 0); +    } + +    /** +     * Returns the time that the file denoted by this abstract pathname was +     * last modified. +     * +     * @return  A integer value representing the time the file was +     *          last modified, measured in milliseconds since the epoch +     *          (00:00:00 GMT, January 1, 1970), or 0 if the +     *          file does not exist or if an I/O error occurs +     */ +    function lastModified() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No read access to " . $this->path); +        } +        return $fs->getLastModifiedTime($this); +    } + +    /** +     * Returns the length of the file denoted by this abstract pathname. +     * The return value is unspecified if this pathname denotes a directory. +     * +     * @return  The length, in bytes, of the file denoted by this abstract +     *          pathname, or 0 if the file does not exist +     */ +    function length() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No read access to ".$this->path."\n"); +        } +        return $fs->getLength($this); +    } + +    /** +     * Convenience method for returning the contents of this file as a string. +     * This method uses file_get_contents() to read file in an optimized way. +     * @return string +     * @throws Exception - if file cannot be read +     */ +    function contents() { +        if (!$this->canRead() || !$this->isFile()) { +            throw new IOException("Cannot read file contents!"); +        } +        return file_get_contents($this->getAbsolutePath()); +    } +     +    /* -- File operations -- */ + +    /** +     * Atomically creates a new, empty file named by this abstract pathname if +     * and only if a file with this name does not yet exist.  The check for the +     * existence of the file and the creation of the file if it does not exist +     * are a single operation that is atomic with respect to all other +     * filesystem activities that might affect the file. +     * +     * @return  true if the named file does not exist and was +     *          successfully created; <code>false</code> if the named file +     *          already exists +     * @throws IOException if file can't be created +     */ +    function createNewFile($parents=true, $mode=0777) { +        $file = FileSystem::getFileSystem()->createNewFile($this->path); +        return $file; +    } + +    /** +     * Deletes the file or directory denoted by this abstract pathname.  If +     * this pathname denotes a directory, then the directory must be empty in +     * order to be deleted. +     * +     * @return  true if and only if the file or directory is +     *          successfully deleted; false otherwise +     */ +    function delete() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this, true) !== true) { +            throw new IOException("No read access to " . $this->path."\n"); +        } +        return $fs->delete($this); +    } + +    /** +     * Requests that the file or directory denoted by this abstract pathname +     * be deleted when php terminates.  Deletion will be attempted only for +     * normal termination of php and if and if only Phing::shutdown() is +     * called. +     * +     * Once deletion has been requested, it is not possible to cancel the +     * request.  This method should therefore be used with care. +     * +     */ +    function deleteOnExit() { +        $fs = FileSystem::getFileSystem(); +        $fs->deleteOnExit($this); +    } + +    /** +     * Returns an array of strings naming the files and directories in the +     * directory denoted by this abstract pathname. +     * +     * If this abstract pathname does not denote a directory, then this +     * method returns null  Otherwise an array of strings is +     * returned, one for each file or directory in the directory.  Names +     * denoting the directory itself and the directory's parent directory are +     * not included in the result.  Each string is a file name rather than a +     * complete path. +     * +     * There is no guarantee that the name strings in the resulting array +     * will appear in any specific order; they are not, in particular, +     * guaranteed to appear in alphabetical order. +     * +     * @return  An array of strings naming the files and directories in the +     *          directory denoted by this abstract pathname.  The array will be +     *          empty if the directory is empty.  Returns null if +     *          this abstract pathname does not denote a directory, or if an +     *          I/O error occurs. +     * +     */ +    function listDir($filter = null) { +        $fs = FileSystem::getFileSystem(); +        return $fs->lister($this, $filter); +    } + +    function listFiles($filter = null) { +        $ss = $this->listDir($filter); +        if ($ss === null) { +            return null; +        } +        $n = count($ss); +        $fs = array(); +        for ($i = 0; $i < $n; $i++) { +            $fs[$i] = new PhingFile((string)$this->path, (string)$ss[$i]); +        } +        return $fs; +    } + +    /** +     * Creates the directory named by this abstract pathname, including any +     * necessary but nonexistent parent directories.  Note that if this +     * operation fails it may have succeeded in creating some of the necessary +     * parent directories. +     * +     * @return  true if and only if the directory was created, +     *          along with all necessary parent directories; false +     *          otherwise +     * @throws  IOException +     */ +    function mkdirs() { +        if ($this->exists()) { +            return false; +        } +		try { +			if ($this->mkdir()) { +	            return true; +	        } +		} catch (IOException $ioe) { +			// IOException from mkdir() means that directory propbably didn't exist. +		}         +        $parentFile = $this->getParentFile(); +        return (($parentFile !== null) && ($parentFile->mkdirs() && $this->mkdir())); +    } + +    /** +     * Creates the directory named by this abstract pathname. +     * +     * @return  true if and only if the directory was created; false otherwise +     * @throws  IOException +     */ +    function mkdir() { +        $fs = FileSystem::getFileSystem(); + +        if ($fs->checkAccess(new PhingFile($this->path), true) !== true) { +            throw new IOException("No write access to " . $this->getPath()); +        } +        return $fs->createDirectory($this); +    } + +    /** +     * Renames the file denoted by this abstract pathname. +     * +     * @param   destFile  The new abstract pathname for the named file +     * @return  true if and only if the renaming succeeded; false otherwise +     */ +    function renameTo(PhingFile $destFile) { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No write access to ".$this->getPath()); +        } +        return $fs->rename($this, $destFile); +    } + +    /** +     * Simple-copies file denoted by this abstract pathname into another +     * PhingFile +     * +     * @param PhingFile $destFile  The new abstract pathname for the named file +     * @return true if and only if the renaming succeeded; false otherwise +     */ +    function copyTo(PhingFile $destFile) { +        $fs = FileSystem::getFileSystem(); + +        if ($fs->checkAccess($this) !== true) { +            throw new IOException("No read access to ".$this->getPath()."\n"); +        } + +        if ($fs->checkAccess($destFile, true) !== true) { +            throw new IOException("File::copyTo() No write access to ".$destFile->getPath()); +        } +        return $fs->copy($this, $destFile); +    } + +    /** +     * Sets the last-modified time of the file or directory named by this +     * abstract pathname. +     * +     * All platforms support file-modification times to the nearest second, +     * but some provide more precision.  The argument will be truncated to fit +     * the supported precision.  If the operation succeeds and no intervening +     * operations on the file take place, then the next invocation of the +     * lastModified method will return the (possibly truncated) time argument +     * that was passed to this method. +     * +     * @param  time  The new last-modified time, measured in milliseconds since +     *               the epoch (00:00:00 GMT, January 1, 1970) +     * @return true if and only if the operation succeeded; false otherwise +     */ +    function setLastModified($time) { +        $time = (int) $time; +        if ($time < 0) { +            throw new Exception("IllegalArgumentException, Negative $time\n"); +        } + +        // FIXME check if accessible +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this, true) !== true) { +            throw new IOException("File::setLastModified(). No write access to file\n"); +        } +        return $fs->setLastModifiedTime($this, $time); +    } + +    /** +     * Marks the file or directory named by this abstract pathname so that +     * only read operations are allowed.  After invoking this method the file +     * or directory is guaranteed not to change until it is either deleted or +     * marked to allow write access.  Whether or not a read-only file or +     * directory may be deleted depends upon the underlying system. +     * +     * @return true if and only if the operation succeeded; false otherwise +     */ +    function setReadOnly() { +        $fs = FileSystem::getFileSystem(); +        if ($fs->checkAccess($this, true) !== true) { +            // Error, no write access +            throw new IOException("No write access to " . $this->getPath()); +        } +        return $fs->setReadOnly($this); +    } + +    /** +     * Sets the mode of the file +     * @param int $mode Ocatal mode. +     */ +    function setMode($mode) { +        $fs = FileSystem::getFileSystem(); +        return $fs->chmod($this->getPath(), $mode); +    } + +    /** +     * Retrieve the mode of this file. +     * @return int +     */ +    function getMode() { +        return @fileperms($this->getPath()); +    } + +    /* -- Filesystem interface -- */ + +    /** +     * List the available filesystem roots. +     * +     * A particular platform may support zero or more hierarchically-organized +     * file systems.  Each file system has a root  directory from which all +     * other files in that file system can be reached. +     * Windows platforms, for example, have a root directory for each active +     * drive; UNIX platforms have a single root directory, namely "/". +     * The set of available filesystem roots is affected by various system-level +     * operations such the insertion or ejection of removable media and the +     * disconnecting or unmounting of physical or virtual disk drives. +     * +     * This method returns an array of PhingFile objects that +     * denote the root directories of the available filesystem roots.  It is +     * guaranteed that the canonical pathname of any file physically present on +     * the local machine will begin with one of the roots returned by this +     * method. +     * +     * The canonical pathname of a file that resides on some other machine +     * and is accessed via a remote-filesystem protocol such as SMB or NFS may +     * or may not begin with one of the roots returned by this method.  If the +     * pathname of a remote file is syntactically indistinguishable from the +     * pathname of a local file then it will begin with one of the roots +     * returned by this method.  Thus, for example, PhingFile objects +     * denoting the root directories of the mapped network drives of a Windows +     * platform will be returned by this method, while PhingFile +     * objects containing UNC pathnames will not be returned by this method. +     * +     * @return  An array of PhingFile objects denoting the available +     *          filesystem roots, or null if the set of roots +     *          could not be determined.  The array will be empty if there are +     *          no filesystem roots. +     */ +    function listRoots() { +        $fs = FileSystem::getFileSystem(); +        return (array) $fs->listRoots(); +    } + +    /* -- Tempfile management -- */ + +    /** +     * Returns the path to the temp directory. +     */ +    function getTempDir() { +        return Phing::getProperty('php.tmpdir'); +    } + +    /** +     * Static method that creates a unique filename whose name begins with +     * $prefix and ends with $suffix in the directory $directory. $directory +     * is a reference to a PhingFile Object. +     * Then, the file is locked for exclusive reading/writing. +     * +     * @author      manuel holtgrewe, grin@gmx.net +     * @throws      IOException +     * @access      public +     */ +    function createTempFile($prefix, $suffix, PhingFile $directory) { +         +        // quick but efficient hack to create a unique filename ;-) +        $result = null; +        do { +            $result = new PhingFile($directory, $prefix . substr(md5(time()), 0, 8) . $suffix); +        } while (file_exists($result->getPath())); + +        $fs = FileSystem::getFileSystem(); +        $fs->createNewFile($result->getPath()); +        $fs->lock($result); + +        return $result; +    } + +    /** +     * If necessary, $File the lock on $File is removed and then the file is +     * deleted +     * +     * @access      public +     */ +    function removeTempFile() { +        $fs = FileSystem::getFileSystem(); +        // catch IO Exception +        $fs->unlock($this); +        $this->delete(); +    } + + +    /* -- Basic infrastructure -- */ + +    /** +     * Compares two abstract pathnames lexicographically.  The ordering +     * defined by this method depends upon the underlying system.  On UNIX +     * systems, alphabetic case is significant in comparing pathnames; on Win32 +     * systems it is not. +     * +     * @param PhingFile $file Th file whose pathname sould be compared to the pathname of this file. +     * +     * @return int Zero if the argument is equal to this abstract pathname, a +     *        value less than zero if this abstract pathname is +     *        lexicographically less than the argument, or a value greater +     *        than zero if this abstract pathname is lexicographically +     *        greater than the argument +     */ +    function compareTo(PhingFile $file) { +        $fs = FileSystem::getFileSystem(); +        return $fs->compare($this, $file); +    } + +    /** +     * Tests this abstract pathname for equality with the given object. +     * Returns <code>true</code> if and only if the argument is not +     * <code>null</code> and is an abstract pathname that denotes the same file +     * or directory as this abstract pathname.  Whether or not two abstract +     * pathnames are equal depends upon the underlying system.  On UNIX +     * systems, alphabetic case is significant in comparing pathnames; on Win32 +     * systems it is not. +     * @return boolean +     */ +    function equals($obj) { +        if (($obj !== null) && ($obj instanceof PhingFile)) { +            return ($this->compareTo($obj) === 0); +        } +        return false; +    } + +    /** Backwards compatibility -- use PHP5's native __tostring method. */ +    function toString() { +        return $this->getPath(); +    } +     +    /** PHP5's native method. */ +    function __toString() { +        return $this->getPath(); +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/Reader.php b/buildscripts/phing/classes/phing/system/io/Reader.php new file mode 100644 index 00000000..1e377378 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Reader.php @@ -0,0 +1,88 @@ +<?php +/* + *  $Id: Reader.php,v 1.5 2003/12/24 12:38:40 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +/** + * Abstract class for reading character streams. + * @author Hans Lellelid <hans@xmpl.org> + * @author Yannick Lecaillez <yl@seasonfive.com> + * @version $Revision: 1.5 $ + * @package phing.system.io + */ +abstract class Reader { + +    /** +     * Read data from source. +     * If length is specified, then only that number of chars is read, +     * otherwise stream is read until EOF. +     * @param int $len +     */ +    abstract public function read($len = null); +             +    /** +     * Close stream. +     */ +    abstract public function close(); +     +    /** +     * Open stream for reading. +     */ +    abstract public function open(); +     +    /** +     * Returns the filename, url, etc. that is being read from. +     * This is critical for, e.g., ExpatParser's ability to know +     * the filename that is throwing an ExpatParserException, etc. +     * @return string +     */ +    abstract function getResource(); + +    /** +     * Move stream position relative to current pos. +     * @param int $n +     */ +    public function skip($n) {} +     +    /** +     * Reset the current position in stream to beginning or last mark (if supported). +     */     +    public function reset() {} +         +    /** +     * If supported, places a "marker" (like a bookmark) at current stream position. +     * A subsequent call to reset() will move stream position back +     * to last marker (if supported). +     */     +    public function mark() {} + +    /** +     * Whether marking is supported. +     * @return boolean +     */ +    public function markSupported() {} +     +    /** +     * Is stream ready for reading. +     * @return boolean +     */ +    public function ready() {} + +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/StringReader.php b/buildscripts/phing/classes/phing/system/io/StringReader.php new file mode 100644 index 00000000..689a2115 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/StringReader.php @@ -0,0 +1,73 @@ +<?php +/* + *  $Id: StringReader.php,v 1.8 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * Dummy class for reading character streams.  + * @package phing.system.io + */ +class StringReader extends Reader { +     +    private    $_string; +    private $mark = 0; +    private $currPos = 0; +     +    function __construct($string) { +        $this->_string = $string; +    } + +    function skip($n) {} + +    function read($len = null) { +        if ($len === null) { +            return $this->_string; +        } else {             +            if ($this->currPos >= strlen($this->_string)) { +                return -1; +            }             +            $out = substr($this->_string, $this->currPos, $len); +            $this->currPos += $len; +            return $out; +        } +    } + +    function mark() { +        $this->mark = $this->currPos; +    } + +    function reset() { +        $this->currPos = $this->mark; +    } + +    function close() {} + +    function open() {} + +    function ready() {} + +    function markSupported() { +        return true; +    } +     +    function getResource() { +        return '(string) "'.$this->_string . '"'; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/TokenReader.php b/buildscripts/phing/classes/phing/system/io/TokenReader.php new file mode 100644 index 00000000..a57d994c --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/TokenReader.php @@ -0,0 +1,51 @@ +<?php +/* + *  $Id: TokenReader.php,v 1.3 2003/11/19 05:48:29 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/system/io/Reader.php'; +include_once 'phing/filters/ReplaceTokens.php'; // for class Token + +/** + * Abstract class for reading Tokens from a resource + * + * @author    Manuel Holtgewe + * @version   $Revision: 1.3 $ + * @access    public + * @package   phing.system.io + */ +class TokenReader extends Reader { + +    /** +     * Constructor +     */ +    function __construct() { +    } + +    /** +     * Reads a token from the resource and returns it as a +     * Token object. +     * +     * @access  public +     */ +    function readToken() { +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php new file mode 100644 index 00000000..fb4e49b4 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php @@ -0,0 +1,266 @@ +<?php +/* + *  $Id: UnixFileSystem.php,v 1.10 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/io/FileSystem.php'; + +/** + * UnixFileSystem class. This class encapsulates the basic file system functions + * for platforms using the unix (posix)-stylish filesystem. It wraps php native + * functions suppressing normal PHP error reporting and instead uses Exception + * to report and error. + * + * This class is part of a oop based filesystem abstraction and targeted to run + * on all supported php platforms. + * + * Note: For debugging turn track_errors on in the php.ini. The error messages + * and log messages from this class will then be clearer because $php_errormsg + * is passed as part of the message. + * + * FIXME: + *  - Comments + *  - Error handling reduced to min, error are handled by PhingFile mainly + * + * @author    Andreas Aderhold, andi@binarycloud.com + * @version   $Revision: 1.10 $ + * @package   phing.system.io + */ +class UnixFileSystem extends FileSystem { + +    /** +     * returns OS dependant path separator char +     */ +    function getSeparator() { +        return '/'; +    } + +    /** +     * returns OS dependant directory separator char +     */ +    function getPathSeparator() { +        return ':'; +    } + +    /** +     * A normal Unix pathname contains no duplicate slashes and does not end +     * with a slash.  It may be the empty string. +     * +     * Check that the given pathname is normal.  If not, invoke the real +     * normalizer on the part of the pathname that requires normalization. +     * This way we iterate through the whole pathname string only once. +     */ +    function normalize($strPathname) { +         +        if (empty($strPathname)) { +            return; +        } +         +        // Resolve home directories. We assume /home is where all home +        // directories reside, b/c there is no other way to do this with +        // PHP AFAIK. +        if ($strPathname{0} === "~") { +            if ($strPathname{1} === "/") { // like ~/foo => /home/user/foo +                $strPathname = "/home/" . get_current_user() . substr($strPathname, 1); +            } else { // like ~foo => /home/foo +                $pos = strpos($strPathname, "/"); +                $name = substr($strPathname, 1, $pos - 2); +                $strPathname = "/home/" . $name . substr($strPathname, $pos); +            } +        } + +        $n = strlen($strPathname); +        $prevChar = 0; +        for ($i=0; $i < $n; $i++) { +            $c = $strPathname{$i}; +            if (($prevChar === '/') && ($c === '/')) { +                return self::normalizer($strPathname, $n, $i - 1); +            } +            $prevChar = $c; +        } +        if ($prevChar === '/') { +            return self::normalizer($strPathname, $n, $n - 1); +        } +        return $strPathname; +    } + +    /** +     * Normalize the given pathname, whose length is $len, starting at the given +     * $offset; everything before this offset is already normal. +     */ +    protected function normalizer($pathname, $len, $offset) { +        if ($len === 0) { +            return $pathname; +        } +        $n = (int) $len; +        while (($n > 0) && ($pathname{$n-1} === '/')) { +            $n--; +        } +        if ($n === 0) { +            return '/'; +        } +        $sb = ""; + +        if ($offset > 0) { +            $sb .= substr($pathname, 0, $offset); +        } +        $prevChar = 0; +        for ($i = $offset; $i < $n; $i++) { +            $c = $pathname{$i}; +            if (($prevChar === '/') && ($c === '/')) { +                continue; +            } +            $sb .= $c; +            $prevChar = $c; +        } +        return $sb; +    } + +    /** +     * Compute the length of the pathname string's prefix.  The pathname +     * string must be in normal form. +     */ +    function prefixLength($pathname) { +        if (strlen($pathname === 0)) { +            return 0; +        } +        return (($pathname{0} === '/') ? 1 : 0); +    } + +    /** +     * Resolve the child pathname string against the parent. +     * Both strings must be in normal form, and the result +     * will be in normal form. +     */ +    function resolve($parent, $child) { + +        if ($child === "") { +            return $parent; +        } + +        if ($child{0} === '/') { +            if ($parent === '/') { +                return $child; +            } +            return $parent.$child; +        } + +        if ($parent === '/') { +            return $parent.$child; +        } + +        return $parent.'/'.$child; +    } + +    function getDefaultParent() { +        return '/'; +    } + +    function isAbsolute(PhingFile $f) { +        return ($f->getPrefixLength() !== 0); +    } + +    /** +     * the file resolver +     */ +    function resolveFile(PhingFile $f) { +        // resolve if parent is a file oject only +        if ($this->isAbsolute($f)) { +            return $f->getPath(); +        } else { +            return $this->resolve(Phing::getProperty("user.dir"), $f->getPath()); +        }        +    } + +    /* -- most of the following is mapped to the php natives wrapped by FileSystem */     + +    /* -- Attribute accessors -- */ +    function getBooleanAttributes(&$f) { +        //$rv = getBooleanAttributes0($f); +        $name = $f->getName(); +        $hidden = (strlen($name) > 0) && ($name{0} == '.'); +        return ($hidden ? $this->BA_HIDDEN : 0); +    } + +    /** +     * set file readonly on unix +     */ +    function setReadOnly($f) { +        if ($f instanceof File) { +            $strPath = (string) $f->getPath(); +            $perms = (int) (@fileperms($strPath) & 0444); +            return FileSystem::Chmod($strPath, $perms); +        } else { +            throw new Exception("IllegalArgutmentType: Argument is not File"); +        } +    } + +    /** +     * compares file paths lexicographically +     */ +    function compare($f1, $f2) { +        if ( ($f1 instanceof PhingFile) && ($f2 instanceof PhingFile) ) { +            $f1Path = $f1->getPath(); +            $f2Path = $f2->getPath(); +            return (boolean) strcmp((string) $f1Path, (string) $f2Path); +        } else { +            throw new Exception("IllegalArgutmentType: Argument is not PhingFile"); +        } +    } + +    /* -- fs interface --*/ + +    function listRoots() { +        if (!$this->checkAccess('/', false)) { +            die ("Can not access root"); +        } +        return array(new PhingFile("/")); +    } + +    /** +     * returns the contents of a directory in an array +     */ +    function lister($f) { +        $dir = @opendir($f->getAbsolutePath()); +        if (!$dir) { +            throw new Exception("Can't open directory " . $f->__toString()); +        } +        $vv = array(); +        while (($file = @readdir($dir)) !== false) { +            if ($file == "." || $file == "..") { +                continue; +            } +            $vv[] = (string) $file; +        } +        @closedir($dir); +        return $vv; +    } + +    function fromURIPath($p) { +        if (StringHelper::endsWith("/", $p) && (strlen($p) > 1)) { + +            // "/foo/" --> "/foo", but "/" --> "/"             +            $p = substr($p, 0, strlen($p) - 1); + +        } + +        return $p; +    } +     +} diff --git a/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php new file mode 100644 index 00000000..c32c21ff --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php @@ -0,0 +1,477 @@ +<?php +/* + *  $Id: Win32FileSystem.php,v 1.10 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/system/io/FileSystem.php'; + +/** + *  @package   phing.system.io + */ +class Win32FileSystem extends FileSystem { + +    protected $slash; +    protected $altSlash; +    protected $semicolon; + +    private static $driveDirCache = array(); + +    function __construct() { +        $this->slash = self::getSeparator(); +        $this->semicolon = self::getPathSeparator(); +        $this->altSlash = ($this->slash === '\\') ? '/' : '\\'; +    } + +    function isSlash($c) { +        return ($c == '\\') || ($c == '/'); +    } + +    function isLetter($c) { +        return ((ord($c) >= ord('a')) && (ord($c) <= ord('z'))) +               || ((ord($c) >= ord('A')) && (ord($c) <= ord('Z'))); +    } + +    function slashify($p) { +        if ((strlen($p) > 0) && ($p{0} != $this->slash)) { +            return $this->slash.$p; +        } +        else { +            return $p; +        } +    } + +    /* -- Normalization and construction -- */ + +    function getSeparator() { +        // the ascii value of is the \ +        return chr(92); +    } + +    function getPathSeparator() { +        return ';'; +    } + +    /** +     * A normal Win32 pathname contains no duplicate slashes, except possibly +     * for a UNC prefix, and does not end with a slash.  It may be the empty +     * string.  Normalized Win32 pathnames have the convenient property that +     * the length of the prefix almost uniquely identifies the type of the path +     * and whether it is absolute or relative: +     * +     *    0  relative to both drive and directory +     *    1  drive-relative (begins with '\\') +     *    2  absolute UNC (if first char is '\\'), else directory-relative (has form "z:foo") +     *    3  absolute local pathname (begins with "z:\\") +     */ +    function normalizePrefix($strPath, $len, $sb) { +        $src = 0; +        while (($src < $len) && $this->isSlash($strPath{$src})) { +            $src++; +        } +        $c = ""; +        if (($len - $src >= 2) +                && $this->isLetter($c = $strPath{$src}) +                && $strPath{$src + 1} === ':') { +            /* Remove leading slashes if followed by drive specifier. +             * This hack is necessary to support file URLs containing drive +             * specifiers (e.g., "file://c:/path").  As a side effect, +             * "/c:/path" can be used as an alternative to "c:/path". */ +            $sb .= $c; +            $sb .= ':'; +            $src += 2; +        } +        else { +            $src = 0; +            if (($len >= 2) +                    && $this->isSlash($strPath{0}) +                    && $this->isSlash($strPath{1})) { +                /* UNC pathname: Retain first slash; leave src pointed at +                 * second slash so that further slashes will be collapsed +                 * into the second slash.  The result will be a pathname +                 * beginning with "\\\\" followed (most likely) by a host +                 * name. */ +                $src = 1; +                $sb.=$this->slash; +            } +        } +        return $src; +    } + +    /** Normalize the given pathname, whose length is len, starting at the given +       offset; everything before this offset is already normal. */ +    protected function normalizer($strPath, $len, $offset) { +        if ($len == 0) { +            return $strPath; +        } +        if ($offset < 3) { +            $offset = 0;    //Avoid fencepost cases with UNC pathnames +        } +        $src = 0; +        $slash = $this->slash; +        $sb = ""; + +        if ($offset == 0) { +            // Complete normalization, including prefix +            $src = $this->normalizePrefix($strPath, $len, $sb); +        } else { +            // Partial normalization +            $src = $offset; +            $sb .= substr($strPath, 0, $offset); +        } + +        // Remove redundant slashes from the remainder of the path, forcing all +        // slashes into the preferred slash +        while ($src < $len) { +            $c = $strPath{$src++}; +            if ($this->isSlash($c)) { +                while (($src < $len) && $this->isSlash($strPath{$src})) { +                    $src++; +                } +                if ($src === $len) { +                    /* Check for trailing separator */ +                    $sn = (int) strlen($sb); +                    if (($sn == 2) && ($sb{1} === ':')) { +                        // "z:\\" +                        $sb .= $slash; +                        break; +                    } +                    if ($sn === 0) { +                        // "\\" +                        $sb .= $slash; +                        break; +                    } +                    if (($sn === 1) && ($this->isSlash($sb{0}))) { +                        /* "\\\\" is not collapsed to "\\" because "\\\\" marks +                        the beginning of a UNC pathname.  Even though it is +                        not, by itself, a valid UNC pathname, we leave it as +                        is in order to be consistent with the win32 APIs, +                        which treat this case as an invalid UNC pathname +                        rather than as an alias for the root directory of +                        the current drive. */ +                        $sb .= $slash; +                        break; +                    } +                    // Path does not denote a root directory, so do not append +                    // trailing slash +                    break; +                } else { +                    $sb .= $slash; +                } +            } else { +                $sb.=$c; +            } +        } +        $rv = (string) $sb; +        return $rv; +    } + +    /** +     * Check that the given pathname is normal.  If not, invoke the real +     * normalizer on the part of the pathname that requires normalization. +     * This way we iterate through the whole pathname string only once. +     * @param string $strPath +     * @return string +     */ +    function normalize($strPath) { +        $n = strlen($strPath); +        $slash    = $this->slash; +        $altSlash = $this->altSlash; +        $prev = 0; +        for ($i = 0; $i < $n; $i++) { +            $c = $strPath{$i}; +            if ($c === $altSlash) { +                return $this->normalizer($strPath, $n, ($prev === $slash) ? $i - 1 : $i); +            } +            if (($c === $slash) && ($prev === $slash) && ($i > 1)) { +                return $this->normalizer($strPath, $n, $i - 1); +            } +            if (($c === ':') && ($i > 1)) { +                return $this->normalizer($strPath, $n, 0); +            } +            $prev = $c; +        } +        if ($prev === $slash) { +            return $this->normalizer($strPath, $n, $n - 1); +        } +        return $strPath; +    } + +    function prefixLength($strPath) { +        $path  = (string) $strPath; +        $slash = (string) $this->slash; +        $n = (int) strlen($path); +        if ($n === 0) { +            return 0; +        } +        $c0 = $path{0}; +        $c1 = ($n > 1) ? $path{1} : +              0; +        if ($c0 === $slash) { +            if ($c1 === $slash) { +                return 2;            // absolute UNC pathname "\\\\foo" +            } +            return 1;                // drive-relative "\\foo" +        } + +        if ($this->isLetter($c0) && ($c1 === ':')) { +            if (($n > 2) && ($path{2}) === $slash) { +                return 3;            // Absolute local pathname "z:\\foo" */ +            } +            return 2;                // Directory-relative "z:foo" +        } +        return 0;                    // Completely relative +    } + +    function resolve($parent, $child) { +        $parent = (string) $parent; +        $child  = (string) $child; +        $slash  = (string) $this->slash; + +        $pn = (int) strlen($parent); +        if ($pn === 0) { +            return $child; +        } +        $cn = (int) strlen($child); +        if ($cn === 0) { +            return $parent; +        } + +        $c = $child; +        if (($cn > 1) && ($c{0} === $slash)) { +            if ($c{1} === $slash) { +                // drop prefix when child is a UNC pathname +                $c = substr($c, 2); +            } +            else { +                //Drop prefix when child is drive-relative */ +                $c = substr($c, 1); +            } +        } + +        $p = $parent; +        if ($p{$pn - 1} === $slash) { +            $p = substr($p, 0, $pn - 1); +        } +        return $p.$this->slashify($c); +    } + +    function getDefaultParent() { +        return (string) ("".$this->slash); +    } + +    function fromURIPath($strPath) { +        $p = (string) $strPath; +        if ((strlen($p) > 2) && ($p{2} === ':')) { + +            // "/c:/foo" --> "c:/foo" +            $p = substr($p,1); + +            // "c:/foo/" --> "c:/foo", but "c:/" --> "c:/" +            if ((strlen($p) > 3) && StringHelper::endsWith('/', $p)) { +                $p = substr($p, 0, strlen($p) - 1); +            } +        } elseif ((strlen($p) > 1) && StringHelper::endsWith('/', $p)) { +            // "/foo/" --> "/foo" +            $p = substr($p, 0, strlen($p) - 1); +        } +        return (string) $p; +    } + + +    /* -- Path operations -- */ + +    function isAbsolute(PhingFile $f) { +        $pl = (int) $f->getPrefixLength(); +        $p  = (string) $f->getPath(); +        return ((($pl === 2) && ($p{0} === $this->slash)) || ($pl === 3) || ($pl === 1 && $p{0} === $this->slash)); +    } + +    /** private */ +    function _driveIndex($d) { +        $d = (string) $d{0}; +        if ((ord($d) >= ord('a')) && (ord($d) <= ord('z'))) { +            return ord($d) - ord('a'); +        } +        if ((ord($d) >= ord('A')) && (ord($d) <= ord('Z'))) { +            return ord($d) - ord('A'); +        } +        return -1; +    } + +    /** private */ +    function _getDriveDirectory($drive) { +        $drive = (string) $drive{0}; +        $i = (int) $this->_driveIndex($drive); +        if ($i < 0) { +            return null; +        } + +        $s = (isset(self::$driveDirCache[$i]) ? self::$driveDirCache[$i] : null); + +        if ($s !== null) { +            return $s; +        } + +        $s = $this->_getDriveDirectory($i + 1); +        self::$driveDirCache[$i] = $s; +        return $s; +    } + +    function _getUserPath() { +        //For both compatibility and security, we must look this up every time +        return (string) $this->normalize(Phing::getProperty("user.dir")); +    } + +    function _getDrive($path) { +        $path = (string) $path; +        $pl   = $this->prefixLength($path); +        return ($pl === 3) ? substr($path, 0, 2) : null; +    } + +    function resolveFile(PhingFile $f) { +        $path = $f->getPath(); +        $pl   = (int) $f->getPrefixLength(); + +        if (($pl === 2) && ($path{0} === $this->slash)) { +            return path;            // UNC +        } + +        if ($pl === 3) { +            return $path;            // Absolute local +        } + +        if ($pl === 0) { +            return (string) ($this->_getUserPath().$this->slashify($path)); //Completely relative +        } + +        if ($pl === 1) {            // Drive-relative +            $up = (string) $this->_getUserPath(); +            $ud = (string) $this->_getDrive($up); +            if ($ud !== null) { +                return (string) $ud.$path; +            } +            return (string) $up.$path;            //User dir is a UNC path +        } + +        if ($pl === 2) {                // Directory-relative +            $up = (string) $this->_getUserPath(); +            $ud = (string) $this->_getDrive($up); +            if (($ud !== null) && StringHelper::startsWith($ud, $path)) { +                return (string) ($up . $this->slashify(substr($path,2))); +            } +            $drive = (string) $path{0}; +            $dir   = (string) $this->_getDriveDirectory($drive); + +            $np = (string) ""; +            if ($dir !== null) { +                /* When resolving a directory-relative path that refers to a +                drive other than the current drive, insist that the caller +                have read permission on the result */ +                $p = (string) $drive . (':'.$dir.$this->slashify(substr($path,2))); + +                if (!$this->checkAccess($p, false)) { +                    // FIXME +                    // throw security error +                    die("Can't resolve path $p"); +                } +                return $p; +            } +            return (string) $drive.':'.$this->slashify(substr($path,2)); //fake it +        } +         +        throw new Exception("Unresolvable path: " . $path); +    } + +    /* -- most of the following is mapped to the functions mapped th php natives in FileSystem */ + +    /* -- Attribute accessors -- */ + +    function setReadOnly($f) { +        // dunno how to do this on win +        throw new Exception("WIN32FileSystem doesn't support read-only yet."); +    } + +    /* -- Filesystem interface -- */ + +    protected function _access($path) { +        if (!$this->checkAccess($path, false)) { +            throw new Exception("Can't resolve path $p"); +        } +        return true; +    } + +    function _nativeListRoots() { +        // FIXME +    } + +    function listRoots() { +        $ds = _nativeListRoots(); +        $n = 0; +        for ($i = 0; $i < 26; $i++) { +            if ((($ds >> $i) & 1) !== 0) { +                if (!$this->access((string)( chr(ord('A') + $i) . ':' . $this->slash))) { +                    $ds &= ~(1 << $i); +                } else { +                    $n++; +                } +            } +        } +        $fs = array(); +        $j = (int) 0; +        $slash = (string) $this->slash; +        for ($i = 0; $i < 26; $i++) { +            if ((($ds >> $i) & 1) !== 0) { +                $fs[$j++] = new PhingFile(chr(ord('A') + $i) . ':' . $this->slash); +            } +        } +        return $fs; +    } + +    /* -- Basic infrastructure -- */ + +    /** compares file paths lexicographically */ +    function compare(PhingFile $f1, PhingFile $f2) { +        $f1Path = $f1->getPath(); +        $f2Path = $f2->getPath(); +        return (boolean) strcasecmp((string) $f1Path, (string) $f2Path);         +    } + + +    /** +     * returns the contents of a directory in an array +     */ +    function lister($f) { +        $dir = @opendir($f->getAbsolutePath()); +        if (!$dir) { +            throw new Exception("Can't open directory " . $f->__toString()); +        } +        $vv = array(); +        while (($file = @readdir($dir)) !== false) { +            if ($file == "." || $file == "..") { +                continue; +            } +            $vv[] = (string) $file; +        } +        @closedir($dir); +        return $vv; +    } + +} + +?> diff --git a/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php new file mode 100644 index 00000000..86f76d80 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php @@ -0,0 +1,35 @@ +<?php +/* + *  $Id: WinNTFileSystem.php,v 1.3 2003/11/19 05:48:29 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/system/io/Win32FileSystem.php'; + +/** + * FileSystem for Windows NT/2000. + *  @package   phing.system.io + */ + +class WinNTFileSystem extends Win32FileSystem { + +    /* -- class only for convenience and future use everything is inherinted --*/ + + +} +?> diff --git a/buildscripts/phing/classes/phing/system/io/Writer.php b/buildscripts/phing/classes/phing/system/io/Writer.php new file mode 100644 index 00000000..5e1a69b9 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/io/Writer.php @@ -0,0 +1,48 @@ +<?php +/* + *  $Id: Writer.php,v 1.6 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * Abstract class for writing character streams.  + * @package   phing.system.io + */ +abstract class Writer { + +    abstract public function write($buf, $off = null, $len = null); + +    abstract public function reset(); +     +    abstract public function close(); +     +    abstract public function open(); + +    public function mark() {} +     +    public function ready() {} + +    public function markSupported() {} +     +    /** +     * Returns the filename, url, etc. that is being written to. +     * @return string +     */     +    abstract function getResource(); +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/Character.php b/buildscripts/phing/classes/phing/system/lang/Character.php new file mode 100644 index 00000000..bb7a5589 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/Character.php @@ -0,0 +1,49 @@ +<?php +/* + *  $Id: Character.php,v 1.3 2003/11/19 05:48:29 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * @package phing.system.lang + */ +class Character { + +    // this class might be extended with plenty of ordinal char constants +    // and the like to support the multibyte aware datatype (char) in php +    // in form of an object. +    // anyway just a thought + +    function isLetter($char) { + +        if (strlen($char) !== 1) +            $char = 0; + +        $char = (int) ord($char); + +        if ($char >= ord('A') && $char <= ord('Z')) +            return true; + +        if ($char >= ord('a') && $char <= ord('z')) +            return true; + +        return false; +    } + +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/EventObject.php b/buildscripts/phing/classes/phing/system/lang/EventObject.php new file mode 100644 index 00000000..4a2211bc --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/EventObject.php @@ -0,0 +1,52 @@ +<?php +/* + *  $Id: EventObject.php,v 1.5 2005/02/27 20:52:10 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + *  @package phing.system.lang + */ +class EventObject { + +    /** The object on which the Event initially occurred. */ +    protected $source; + +    /** Constructs a prototypical Event. */ +    function __construct($source) { +        if ($source === null) { +            throw new Exception("Null source"); +        } +        $this->source = $source; +    } + +    /** The object on which the Event initially occurred. */ +    function getSource() { +        return $this->source; +    } + +    /** Returns a String representation of this EventObject.*/ +    function toString() { +        if (method_exists($this->source, "toString")) { +            return get_class($this)."[source=".$this->source->toString()."]"; +        } else { +            return get_class($this)."[source=".get_class($this->source)."]"; +        } +    } +} +?> diff --git a/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php new file mode 100644 index 00000000..ff48c785 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php @@ -0,0 +1,27 @@ +<?php +/* + *  $Id: FileNotFoundException.php,v 1.4 2005/02/27 20:52:10 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + *  @package   phing.system.lang + */ +class FileNotFoundException extends Exception {} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/NullPointerException.php b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php new file mode 100644 index 00000000..38fa5c10 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php @@ -0,0 +1,27 @@ +<?php +/* + *  $Id: NullPointerException.php,v 1.4 2005/02/27 20:52:10 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * @package phing.system.lang + */ +class NullPointerException extends Exception {} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/SecurityException.php b/buildscripts/phing/classes/phing/system/lang/SecurityException.php new file mode 100644 index 00000000..21e8b1c3 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/lang/SecurityException.php @@ -0,0 +1,27 @@ +<?php +/* + *  $Id: SecurityException.php,v 1.4 2005/02/27 20:52:10 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * @package phing.system.lang + */ +class SecurityException extends Exception {} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/util/Message.php b/buildscripts/phing/classes/phing/system/util/Message.php new file mode 100644 index 00000000..bf7bb56b --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Message.php @@ -0,0 +1,9 @@ +<?php +// +// FIXME. Logger will be renamed to Message, new level is introduces MSG_NOTICE +// Message can handle some more later on +//   - formatted output +//   - sending to dialog or phpgtk whatever +//   - etc +// +?> diff --git a/buildscripts/phing/classes/phing/system/util/Properties.php b/buildscripts/phing/classes/phing/system/util/Properties.php new file mode 100644 index 00000000..deff2cdf --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Properties.php @@ -0,0 +1,270 @@ +<?php + +/* + *  $Id: Properties.php,v 1.13 2005/05/26 13:10:52 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/FileWriter.php'; + +/** + * Convenience class for reading and writing property files. + *  + * FIXME + *        - Add support for arrays (separated by ',') + * + * @package    phing.system.util + * @version $Revision: 1.13 $ + */ +class Properties { + +    private $properties = array(); + +    /** +     * Load properties from a file. +     * +     * @param PhingFile $file +     * @return void +     * @throws IOException - if unable to read file. +     */ +    function load(PhingFile $file) { +        if ($file->canRead()) { +            $this->parse($file->getPath(), false);                     +        } else { +            throw new IOException("Can not read file ".$file->getPath()); +        } +         +    } +     +    /** +     * Replaces parse_ini_file() or better_parse_ini_file(). +     * Saves a step since we don't have to parse and then check return value +     * before throwing an error or setting class properties. +     *  +     * @param string $filePath +     * @param boolean $processSections Whether to honor [SectionName] sections in INI file. +     * @return array Properties loaded from file (no prop replacements done yet). +     */ +    protected function parse($filePath) { + +        // load() already made sure that file is readable                 +        // but we'll double check that when reading the file into  +        // an array +         +        if (($lines = @file($filePath)) === false) { +            throw new IOException("Unable to parse contents of $filePath"); +        } +         +        $this->properties = array(); +        $sec_name = ""; +         +        foreach($lines as $line) { +             +            $line = trim($line); +     +            if($line == "") +                continue; +                     +            if ($line{0} == '#' or $line{0} == ';') { +                // it's a comment, so continue to next line +                continue; +            } else { +                $pos = strpos($line, '='); +                $property = trim(substr($line, 0, $pos)); +                $value = trim(substr($line, $pos + 1));                 +                $this->properties[$property] = $this->inVal($value); +            } +             +        } // for each line         +    } +     +    /** +     * Process values when being read in from properties file. +     * does things like convert "true" => true +     * @param string $val Trimmed value. +     * @return mixed The new property value (may be boolean, etc.) +     */ +    protected function inVal($val) { +        if ($val === "true") {  +            $val = true; +        } elseif ($val === "false") {  +            $val = false;  +        } +        return $val; +    } +     +    /** +     * Process values when being written out to properties file. +     * does things like convert true => "true" +     * @param mixed $val The property value (may be boolean, etc.) +     * @return string +     */ +    protected function outVal($val) { +        if ($val === true) { +            $val = "true"; +        } elseif ($val === false) { +            $val = "false"; +        } +        return $val; +    } +     +    /** +     * Create string representation that can be written to file and would be loadable using load() method. +     *  +     * Essentially this function creates a string representation of properties that is ready to +     * write back out to a properties file.  This is used by store() method. +     * +     * @return string +     */ +    public function toString() { +        $buf = "";         +        foreach($this->properties as $key => $item) { +            $buf .= $key . "=" . $this->outVal($item) . Phing::getProperty('line.separator'); +        } +        return $buf;     +    } +     +    /** +     * Stores current properties to specified file. +     *  +     * @param PhingFile $file File to create/overwrite with properties. +     * @param string $header Header text that will be placed (within comments) at the top of properties file. +     * @return void +     * @throws IOException - on error writing properties file. +     */ +    function store(PhingFile $file, $header = null) { +        // stores the properties in this object in the file denoted +        // if file is not given and the properties were loaded from a +        // file prior, this method stores them in the file used by load()         +        try { +            $fw = new FileWriter($file); +            $fw->open(); +            if ($header !== null) { +                $fw->write( "# " . $header . Phing::getProperty("line.separator") ); +            } +            $fw->write($this->toString()); +            $fw->close(); +        } catch (IOException $e) { +            throw new IOException("Error writing property file: " . $e->getMessage()); +        }                 +    } +     +    /** +     * Returns copy of internal properties hash. +     * Mostly for performance reasons, property hashes are often +     * preferable to passing around objects. +     * +     * @return array +     */ +    function getProperties() { +        return $this->properties; +    } +     +    /** +     * Get value for specified property. +     * This is the same as get() method. +     * +     * @param string $prop The property name (key). +     * @return mixed +     * @see get() +     */ +    function getProperty($prop) { +        if (!isset($this->properties[$prop])) { +            return null; +        } +        return $this->properties[$prop]; +    } + +    /** +     * Get value for specified property. +     * This function exists to provide a hashtable-like interface for +     * properties. +     * +     * @param string $prop The property name (key). +     * @return mixed +     * @see getProperty() +     */     +    function get($prop) { +         if (!isset($this->properties[$prop])) { +            return null; +        } +        return $this->properties[$prop]; +    } +     +    /** +     * Set the value for a property. +     * +     * @param string $key +     * @param mixed $value +     * @return mixed Old property value or NULL if none was set. +     */ +    function setProperty($key, $value) { +        $oldValue = @$this->properties[$key];        +        $this->properties[$key] = $value; +        return $oldValue; +    } +     +    /** +     * Set the value for a property. +     * This function exists to provide hashtable-lie +     * interface for properties. +     * +     * @param string $key +     * @param mixed $value +     */ +    function put($key, $value) { +        return $this->setProperty($key, $value); +    } +     +    /** +     * Same as keys() function, returns an array of property names. +     * @return array +     */ +    function propertyNames() { +        return $this->keys(); +    } +     +    /** +     * Whether loaded properties array contains specified property name. +     * @return boolean +     */ +    function containsKey($key) { +        return isset($this->properties[$key]); +    } + +    /** +     * Returns properties keys. +     * Use this for foreach() {} iterations, as this is +     * faster than looping through property values. +     * @return array +     */ +    function keys() { +        return array_keys($this->properties); +    } +     +    /** +     * Whether properties list is empty. +     * @return boolean +     */ +    function isEmpty() { +        return empty($this->properties); +    } + +} +?> diff --git a/buildscripts/phing/classes/phing/system/util/Register.php b/buildscripts/phing/classes/phing/system/util/Register.php new file mode 100644 index 00000000..5ef2b2fd --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Register.php @@ -0,0 +1,115 @@ +<?php + +/** + * Static class to handle a slot-listening system. + * + * Unlike the slots/signals Qt model, this class manages something that is + * more like a simple hashtable, where each slot has only one value.  For that + * reason "Registers" makes more sense, the reference being to CPU registers. + * + * This could be used for anything, but it's been built for a pretty specific phing + * need, and that is to allow access to dynamic values that are set by logic + * that is not represented in a build file.  For exampe, we need a system for getting + * the current resource (file) that is being processed by a filterchain in a fileset. + *  + * Each slot corresponds to only one read-only, dynamic-value RegisterSlot object. In + * a build.xml register slots are expressed using a syntax similar to variables: + *  + * <replaceregexp> + *    <regexp pattern="\n" replace="%{task.current_file}"/> + * </replaceregexp> + *  + * The task/type must provide a supporting setter for the attribute: + *  + * <code> + *     function setListeningReplace(RegisterSlot $slot) { + *        $this->replace = $slot; + *  } + * + *  // in main() + *  if ($this->replace instanceof RegisterSlot) { + *        $this->regexp->setReplace($this->replace->getValue()); + *  } else { + *        $this->regexp->setReplace($this->replace); + *  } + * </code> + * + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.3 $ + * @package phing.system.util + */ +class Register { +     +    /** Slots that have been registered */ +    private static $slots = array(); +     +    /** +     * Returns RegisterSlot for specified key. +     *  +     * If not slot exists a new one is created for key. +     *  +     * @param string $key +     * @return RegisterSlot +     */ +    public static function getSlot($key) { +        if (!isset(self::$slots[$key])) { +            self::$slots[$key] = new RegisterSlot($key); +        } +        return self::$slots[$key]; +    }     +} + + +/** + * Represents a slot in the register. + */ +class RegisterSlot { +     +    /** The name of this slot. */ +    private $key; +     +    /** The value for this slot. */ +    private $value; +     +    /** +     * Constructs a new RegisterSlot, setting the key to passed param. +     * @param string $key +     */ +    public function __construct($key) { +        $this->key = (string) $key; +    } +     +    /** +     * Sets the key / name for this slot. +     * @param string $k +     */ +    public function setKey($k) { +        $this->key = (string) $k; +    } + +    /** +     * Gets the key / name for this slot. +     * @return string +     */ +    public function getKey() { +        return $this->key; +    } +     +    /** +     * Sets the value for this slot. +     * @param mixed +     */ +    public function setValue($v) { +        $this->value = $v; +    } +     +    /** +     * Returns the value at this slot. +     * @return mixed +     */ +    public function getValue() { +        return $this->value; +    } +     +} +?> diff --git a/buildscripts/phing/classes/phing/system/util/Timer.php b/buildscripts/phing/classes/phing/system/util/Timer.php new file mode 100644 index 00000000..a2a665b0 --- /dev/null +++ b/buildscripts/phing/classes/phing/system/util/Timer.php @@ -0,0 +1,96 @@ +<?php +/* + *  $Id: Timer.php,v 1.5 2003/12/24 13:02:09 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +/** + * This class can be used to obtain the execution time of all of the scripts + * that are executed in the process of building a page. + * + * Example: + * To be done before any scripts execute: + * + * $Timer = new Timer; + * $Timer->Start_Timer(); + * + * To be done after all scripts have executed: + * + * $timer->Stop_Timer(); + * $timer->Get_Elapsed_Time(int number_of_places); + * + * @author    Charles Killian + * @author    Hans Lellelid <hans@xmpl.org> + * @package    phing.system.util + * @version    $Revision: 1.5 $ $Date: 2003/12/24 13:02:09 $ + */ +class Timer { + +    /** start time */ +    protected $stime; +     +    /** end time */ +    protected $etime;   + +    /** +     * This function sets the class variable $stime to the current time in +     * microseconds. +     * @return void +     */ +    public function start() { +        $this->stime = $this->getMicrotime(); +    } + +    /** +     * This function sets the class variable $etime to the current time in +     * microseconds. +     * @return void +     */ +    function stop() { +        $this->etime = $this->getMicrotime(); +    } +     +    /** +     * This function returns the elapsed time in seconds. +     * +     * Call start_time() at the beginning of script execution and end_time() at +     * the end of script execution.  Then, call elapsed_time() to obtain the +     * difference between start_time() and end_time(). +     * +     * @param    $places  decimal place precision of elapsed time (default is 5) +     * @return string Properly formatted time. +     */ +    function getElapsedTime($places=5) { +        $etime = $this->etime - $this->stime; +        $format = "%0.".$places."f"; +        return (sprintf ($format, $etime)); +    } + +    /** +     * This function returns the current time in microseconds. +     * +     * @author    Everett Michaud, Zend.com +     * @return    current time in microseconds +     * @access    private +     */ +    function getMicrotime() { +        list($usec, $sec) = explode(" ", microtime()); +        return ((float)$usec + (float)$sec); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/defaults.properties b/buildscripts/phing/classes/phing/tasks/defaults.properties new file mode 100644 index 00000000..d0e62eff --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/defaults.properties @@ -0,0 +1,69 @@ +; ------------------------------------- +; These taskdefs are loaded at startup. +; ------------------------------------- + +; Internal system tasks +;  +adhoc=phing.tasks.system.AdhocTask +adhoc-task=phing.tasks.system.AdhocTaskdefTask +adhoc-type=phing.tasks.system.AdhocTypedefTask +append=phing.tasks.system.AppendTask +available=phing.tasks.system.AvailableTask +chmod=phing.tasks.system.ChmodTask +condition=phing.tasks.system.ConditionTask +copy=phing.tasks.system.CopyTask +cvs=phing.tasks.system.CvsTask +cvspass=phing.tasks.system.CvsPassTask +delete=phing.tasks.system.DeleteTask +echo=phing.tasks.system.EchoTask +exec=phing.tasks.system.ExecTask +fail=phing.tasks.system.ExitTask +foreach=phing.tasks.system.ForeachTask +includepath=phing.tasks.system.IncludePathTask +input=phing.tasks.system.InputTask +mkdir=phing.tasks.system.MkdirTask +move=phing.tasks.system.MoveTask +phing=phing.tasks.system.PhingTask +phingcall=phing.tasks.system.PhingCallTask +php=phing.tasks.system.PhpEvalTask +property=phing.tasks.system.PropertyTask +propertyprompt=phing.tasks.system.PropertyPromptTask +reflexive=phing.tasks.system.ReflexiveTask +resolvepath=phing.tasks.system.ResolvePathTask +taskdef=phing.tasks.system.TaskdefTask +touch=phing.tasks.system.TouchTask +tstamp=phing.tasks.system.TstampTask +typedef=phing.tasks.system.TypedefTask +uptodate=phing.tasks.system.UpToDateTask +xslt=phing.tasks.system.XsltTask +if=phing.tasks.system.IfTask +warn=phing.tasks.system.WarnTask + +; "Core" contributed tasks +; -- i.e. no taskdef needed. + +sql=phing.tasks.ext.CreoleSQLExecTask +package-as-path=phing.tasks.ext.PackageAsPathTask +smarty=phing.tasks.ext.SmartyTask +capsule=phing.tasks.ext.CapsuleTask +tar=phing.tasks.ext.TarTask +pearpkg=phing.tasks.ext.PearPackageTask +mail=phing.tasks.ext.MailTask +zip=phing.tasks.ext.ZipTask +phplint=phing.tasks.ext.PhpLintTask + +; "ext" tasks +phpdoc=phing.tasks.ext.phpdoc.PHPDocumentorTask +svnlastrevision=phing.tasks.ext.svn.SvnLastRevisionTask +svnexport=phing.tasks.ext.svn.SvnExportTask +phpunit2=phing.tasks.ext.phpunit2.PHPUnit2Task +phpunit2report=phing.tasks.ext.phpunit2.PHPUnit2ReportTask +coverage-setup=phing.tasks.ext.coverage.CoverageSetupTask +coverage-merger=phing.tasks.ext.coverage.CoverageMergerTask +coverage-report=phing.tasks.ext.coverage.CoverageReportTask +ioncubeencoder=phing.tasks.ext.ioncube.IoncubeEncoderTask +ioncubelicense=phing.tasks.ext.ioncube.IoncubeLicenseTask +simpletest=phing.tasks.ext.simpletest.SimpleTestTask +phplint=phing.tasks.ext.PhpLintTask +xmllint=phing.tasks.ext.XmlLintTask +analyze=phing.tasks.ext.ZendCodeAnalyzerTask
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php new file mode 100644 index 00000000..aa43a0e4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php @@ -0,0 +1,478 @@ +<?php + +/* + *  $Id: CapsuleTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +include_once 'phing/Task.php'; +include_once 'phing/BuildException.php'; +include_once 'phing/lib/Capsule.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * A phing task for generating output by using Capsule. + * + * This is based on the interface to TexenTask from Apache's Velocity engine.  + * + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.17 $ + * @package   phing.tasks.ext + */ +class CapsuleTask extends Task { + +    /** +     * Capsule "template" engine. +     * @var Capsule +     */ +    protected $context; +        +    /** +     * Any vars assigned via the build file. +     * @var array AssignedVar[] +     */ +    protected $assignedVars = array(); +     +    /** +     * This is the control template that governs the output. +     * It may or may not invoke the services of worker +     * templates. +     * @var string +     */ +    protected $controlTemplate; +     +    /** +     * This is where Velocity will look for templates +     * using the file template loader. +     * @var string +     */ +    protected $templatePath; +     +    /** +     * This is where texen will place all the output +     * that is a product of the generation process. +     * @var string +     */ +    protected $outputDirectory; +     +    /** +     * This is the file where the generated text +     * will be placed. +     * @var string +     */ +    protected $outputFile; + +    /** +     * <p> +     * These are properties that are fed into the +     * initial context from a properties file. This +     * is simply a convenient way to set some values +     * that you wish to make available in the context. +     * </p> +     * <p> +     * These values are not critical, like the template path +     * or output path, but allow a convenient way to +     * set a value that may be specific to a particular +     * generation task. +     * </p> +     * <p> +     * For example, if you are generating scripts to allow +     * user to automatically create a database, then +     * you might want the <code>$databaseName</code>  +     * to be placed +     * in the initial context so that it is available +     * in a script that might look something like the +     * following: +     * <code><pre> +     * #!bin/sh +     *  +     * echo y | mysqladmin create $databaseName +     * </pre></code> +     * The value of <code>$databaseName</code> isn't critical to +     * output, and you obviously don't want to change +     * the ant task to simply take a database name. +     * So initial context values can be set with +     * properties file. +     * +     * @var array +     */ +    protected $contextProperties; +         +    // ----------------------------------------------------------------------- +    // The following getters & setters are used by phing to set properties +    // specified in the XML for the capsule task. +    // ----------------------------------------------------------------------- +     +    /** +     * [REQUIRED] Set the control template for the +     * generating process. +     * @param string $controlTemplate +     * @return void +     */ +    public function setControlTemplate ($controlTemplate) { +        $this->controlTemplate = $controlTemplate; +    } + +    /** +     * Get the control template for the +     * generating process. +     * @return string +     */ +    public function getControlTemplate() { +        return $this->controlTemplate; +    } + +    /** +     * [REQUIRED] Set the path where Velocity will look +     * for templates using the file template +     * loader. +     * @return void +     * @throws Exception  +     */ +    public function setTemplatePath($templatePath) { +        $resolvedPath = "";         +        $tok = strtok($templatePath, ","); +        while ( $tok ) {             +            // resolve relative path from basedir and leave +            // absolute path untouched. +            $fullPath = $this->project->resolveFile($tok); +            $cpath = $fullPath->getCanonicalPath(); +            if ($cpath === false) { +                $this->log("Template directory does not exist: " . $fullPath->getAbsolutePath()); +            } else { +                $resolvedPath .= $cpath; +            } +            $tok = strtok(","); +            if ( $tok ) { +                $resolvedPath .= ","; +            } +        } +        $this->templatePath = $resolvedPath; +     } + +    /** +     * Get the path where Velocity will look +     * for templates using the file template +     * loader. +     * @return string +     */ +    public function getTemplatePath() { +        return $this->templatePath; +    }         + +    /** +     * [REQUIRED] Set the output directory. It will be +     * created if it doesn't exist. +     * @param PhingFile $outputDirectory +     * @return void +     * @throws Exception +     */ +    public function setOutputDirectory(PhingFile $outputDirectory) { +        try { +            if (!$outputDirectory->exists()) { +                $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),PROJECT_MSG_VERBOSE); +                if (!$outputDirectory->mkdirs()) { +                    throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath()); +                } +            } +            $this->outputDirectory = $outputDirectory->getCanonicalPath(); +        } catch (IOException $ioe) { +            throw new BuildException($ioe); +        } +    } +       +    /** +     * Get the output directory. +     * @return string +     */ +    public function getOutputDirectory() { +        return $this->outputDirectory; +    }         + +    /** +     * [REQUIRED] Set the output file for the +     * generation process. +     * @param string $outputFile (TODO: change this to File) +     * @return void +     */ +    public function setOutputFile($outputFile) { +        $this->outputFile = $outputFile; +    } + +    /** +     * Get the output file for the +     * generation process. +     * @return string +     */ +    public function getOutputFile() { +        return $this->outputFile; +    }         +     +    /** +     * Set the context properties that will be +     * fed into the initial context be the +     * generating process starts. +     * @param string $file +     * @return void +     */ +    public function setContextProperties($file) { +        $sources = explode(",", $file); +        $this->contextProperties = new Properties(); +         +        // Always try to get the context properties resource +        // from a file first. Templates may be taken from a JAR +        // file but the context properties resource may be a  +        // resource in the filesystem. If this fails than attempt +        // to get the context properties resource from the +        // classpath. +        for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) { +            $source = new Properties(); +             +            try { +             +                // resolve relative path from basedir and leave +                // absolute path untouched. +                $fullPath = $this->project->resolveFile($sources[$i]); +                $this->log("Using contextProperties file: " . $fullPath->toString()); +                $source->load($fullPath); +                 +            } catch (Exception $e) { +               +              throw new BuildException("Context properties file " . $sources[$i] . +                            " could not be found in the file system!"); +                      +            } +         +            $keys = $source->keys(); +             +            foreach ($keys as $key) { +                $name = $key; +                $value = $this->project->replaceProperties($source->getProperty($name)); +                $this->contextProperties->setProperty($name, $value); +            } +        } +    } + +    /** +     * Get the context properties that will be +     * fed into the initial context be the +     * generating process starts. +     * @return Properties +     */ +    public function getContextProperties() { +        return $this->contextProperties; +    }      + +    /**  +     * Creates an "AssignedVar" class. +     */ +    public function createAssign() { +        $a = new AssignedVar(); +        $this->assignedVars[] = $a; +        return $a; +    } +     +    // --------------------------------------------------------------- +    // End of XML setters & getters +    // --------------------------------------------------------------- +    +    /** +     * Creates a Smarty object. +     * +     * @return Smarty initialized (cleared) Smarty context. +     * @throws Exception the execute method will catch  +     *         and rethrow as a <code>BuildException</code> +     */ +    public function initControlContext() { +        $this->context->clear(); +        foreach($this->assignedVars as $var) { +            $this->context->put($var->getName(), $var->getValue()); +        } +        return $this->context; +    } +     +    /** +     * Execute the input script with Velocity +     * +     * @throws BuildException   +     * BuildExceptions are thrown when required attributes are missing. +     * Exceptions thrown by Velocity are rethrown as BuildExceptions. +     */ +    public function main() { +     +        // Make sure the template path is set. +        if (empty($this->templatePath)) { +            throw new BuildException("The template path needs to be defined!"); +        }             +     +        // Make sure the control template is set. +        if ($this->controlTemplate === null) { +            throw new BuildException("The control template needs to be defined!"); +        }             + +        // Make sure the output directory is set. +        if ($this->outputDirectory === null) { +            throw new BuildException("The output directory needs to be defined!"); +        }             +         +        // Make sure there is an output file. +        if ($this->outputFile === null) { +            throw new BuildException("The output file needs to be defined!"); +        }             +         +        // Setup Smarty runtime. +         +        // Smarty uses one object to store properties and to store +        // the context for the template (unlike Velocity).  We setup this object, calling it +        // $this->context, and then initControlContext simply zeros out +        // any assigned variables. +        $this->context = new Capsule(); +                 +        if ($this->templatePath !== null) { +            $this->log("Using templatePath: " . $this->templatePath); +            $this->context->setTemplatePath($this->templatePath); +        }                                                         +                 +        // Make sure the output directory exists, if it doesn't +        // then create it. +        $outputDir = new PhingFile($this->outputDirectory); +        if (!$outputDir->exists()) { +            $this->log("Output directory does not exist, creating: " . $outputDir->getAbsolutePath()); +            $outputDir->mkdirs(); +        } +         +        $this->context->setOutputDirectory($outputDir->getAbsolutePath()); +         +        $path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile; +        $this->log("Generating to file " . $path); +         +        //$writer = new FileWriter($path); +                 +        // The generator and the output path should +        // be placed in the init context here and +        // not in the generator class itself. +        $c = $this->initControlContext(); +         +        // Set any variables that need to always +        // be loaded +        $this->populateInitialContext($c); +         +        // Feed all the options into the initial +        // control context so they are available +        // in the control/worker templates. +        if ($this->contextProperties !== null) { +             +            foreach($this->contextProperties->keys() as $property) { +                     +            $value = $this->contextProperties->getProperty($property); +             +            // Special exception (from Texen) +            // for properties ending in file.contents: +            // in that case we dump the contents of the file +            // as the "value" for the Property. +            if (preg_match('/file\.contents$/', $property)) { +                // pull in contents of file specified  +                                         +                $property = substr($property, 0, strpos($property, "file.contents") - 1); +                 +                // reset value, and then  +                // read in teh contents of the file into that var +                $value = ""; +                $f = new PhingFile($project->resolveFile($value)->getCanonicalPath());                         +                if ($f->exists()) { +                    $fr = new FileReader($f); +                    $fr->readInto($value); +                } +                                                                 +            } // if ends with file.contents +             +            if (StringHelper::isBoolean($value)) { +                $value = StringHelper::booleanValue($value); +            } +                                                             +            $c->put($property, $value);  +                  +            } // foreach property +                 +        } // if contextProperties !== null +         +        try { +            $this->log("Parsing control template: " . $this->controlTemplate); +            $c->parse($this->controlTemplate, $path); +        } catch (Exception $ioe) { +            throw new BuildException("Cannot write parsed template: ". $ioe->getMessage()); +        }         +         +        $this->cleanup();     +    } + +    /** +     * Place useful objects into the initial context. +     * +     * +     * @param Capsule $context The context to populate, as retrieved from +     * {@link #initControlContext()}. +     * @return void +     * @throws Exception Error while populating context.  The {@link +     * #main()} method will catch and rethrow as a +     * <code>BuildException</code>. +     */ +    protected function populateInitialContext(Capsule $context) { +        $this->context->put("now", strftime("%c", time())); +        $this->context->put("task", $this); +    } + +    /** +     * A hook method called at the end of {@link #execute()} which can +     * be overridden to perform any necessary cleanup activities (such +     * as the release of database connections, etc.).  By default, +     * does nothing. +     * @return void +     * @throws Exception Problem cleaning up. +     */ +    protected function cleanup() { +    } +} + + +/** + * An "inner" class for holding assigned var values. + * May be need to expand beyond name/value in the future. + */ +class AssignedVar { +     +    private $name; +    private $value; +     +    function setName($v) { +        $this->name = $v; +    } +     +    function setValue($v) { +        $this->value = $v; +    } +     +    function getName() { +        return $this->name; +    } +     +    function getValue() { +        return $this->value; +    } + +}
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php new file mode 100644 index 00000000..d35e44f4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php @@ -0,0 +1,556 @@ +<?php +/* + *  $Id: CreoleSQLExecTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/ext/CreoleTask.php'; +include_once 'phing/system/io/StringReader.php'; + +/** + * Executes a series of SQL statements on a database using Creole. + * + * <p>Statements can + * either be read in from a text file using the <i>src</i> attribute or from  + * between the enclosing SQL tags.</p> + *  + * <p>Multiple statements can be provided, separated by semicolons (or the  + * defined <i>delimiter</i>). Individual lines within the statements can be  + * commented using either --, // or REM at the start of the line.</p> + *  + * <p>The <i>autocommit</i> attribute specifies whether auto-commit should be  + * turned on or off whilst executing the statements. If auto-commit is turned  + * on each statement will be executed and committed. If it is turned off the  + * statements will all be executed as one transaction.</p> + *  + * <p>The <i>onerror</i> attribute specifies how to proceed when an error occurs  + * during the execution of one of the statements.  + * The possible values are: <b>continue</b> execution, only show the error; + * <b>stop</b> execution and commit transaction; + * and <b>abort</b> execution and transaction and fail task.</p> + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Jeff Martin <jeff@custommonkey.org> (Ant) + * @author    Michael McCallum <gholam@xtra.co.nz> (Ant) + * @author    Tim Stephenson <tim.stephenson@sybase.com> (Ant) + * @package   phing.tasks.ext + * @version   $Revision: 1.21 $ + */ +class CreoleSQLExecTask extends CreoleTask { + +    private $goodSql = 0; +    private $totalSql = 0; + +    const DELIM_ROW = "row"; +    const DELIM_NORMAL = "normal"; + +    /** +     * Database connection +     */ +    private $conn = null; + +    /** +     * files to load +     */ +    private $filesets = array(); + +    /** +     * SQL statement +     */ +    private $statement = null; + +    /** +     * SQL input file +     */ +    private $srcFile = null; + +    /** +     * SQL input command +     */ +    private $sqlCommand = ""; + +    /** +     * SQL transactions to perform +     */ +    private $transactions = array(); + +    /** +     * SQL Statement delimiter +     */ +    private $delimiter = ";"; +     +    /** +     * The delimiter type indicating whether the delimiter will +     * only be recognized on a line by itself +     */ +    private $delimiterType = "normal"; // can't use constant just defined +     +    /** +     * Print SQL results. +     */ +    private $print = false; + +    /** +     * Print header columns. +     */ +    private $showheaders = true; + +    /** +     * Results Output file. +     */ +    private $output = null; + +     +    /** +     * Action to perform if an error is found +     **/ +    private $onError = "abort"; +     +    /** +     * Encoding to use when reading SQL statements from a file +     */ +    private $encoding = null; + +    /** +     * Append to an existing file or overwrite it? +     */ +    private $append = false; +         +    /** +     * Set the name of the SQL file to be run. +     * Required unless statements are enclosed in the build file +     */ +    public function setSrc(PhingFile $srcFile) {        +        $this->srcFile = $srcFile; +    } +     +    /** +     * Set an inline SQL command to execute.  +     * NB: Properties are not expanded in this text. +     */ +    public function addText($sql) { +        $this->sqlCommand .= $sql; +    } +     +    /** +     * Adds a set of files (nested fileset attribute). +     */ +    public function addFileset(FileSet $set) { +        $this->filesets[] = $set; +    } + +    /** +     * Add a SQL transaction to execute +     */ +    public function createTransaction() { +        $t = new SQLExecTransaction($this); +        $this->transactions[] = $t; +        return $t; +    } +     +    /** +     * Set the file encoding to use on the SQL files read in +     * +     * @param encoding the encoding to use on the files +     */ +    public function setEncoding($encoding) { +        $this->encoding = $encoding; +    } +     +    /** +     * Set the statement delimiter. +     * +     * <p>For example, set this to "go" and delimitertype to "ROW" for +     * Sybase ASE or MS SQL Server.</p> +     * +     * @param delimiter +     */ +    public function setDelimiter($delimiter) +    { +        $this->delimiter = $delimiter; +    } + +    /** +     * Set the Delimiter type for this sql task. The delimiter type takes two +     * values - normal and row. Normal means that any occurence of the delimiter +     * terminate the SQL command whereas with row, only a line containing just +     * the delimiter is recognized as the end of the command. +     * +     * @param string $delimiterType +     */ +    public function setDelimiterType($delimiterType) +    { +        $this->delimiterType = $delimiterType; +    } +     +    /** +     * Set the print flag. +     * +     * @param boolean $print +     */ +    public function setPrint($print) +    { +        $this->print = (boolean) $print; +    } +         +    /** +     * Print headers for result sets from the  +     * statements; optional, default true. +     * @param boolean $showheaders +     */ +    public function setShowheaders($showheaders) { +        $this->showheaders = (boolean) $showheaders; +    } + +    /** +     * Set the output file;  +     * optional, defaults to the console. +     * @param PhingFile $output +     */ +    public function setOutput(PhingFile $output) { +        $this->output = $output; +    } + +    /** +     * whether output should be appended to or overwrite +     * an existing file.  Defaults to false. +     * @param $append +     */ +    public function setAppend($append) { +        $this->append = (boolean) $append; +    } + +     +    /** +     * Action to perform when statement fails: continue, stop, or abort +     * optional; default "abort" +     */ +    public function setOnerror($action) { +        $this->onError = $action; +    } + +    /** +     * Load the sql file and then execute it +     * @throws BuildException +     */ +    public function main()  { +             +        $savedTransaction = array(); +        for($i=0,$size=count($this->transactions); $i < $size; $i++) { +            $savedTransaction[] = clone $this->transactions[$i]; +        } +         +        $savedSqlCommand = $this->sqlCommand; + +        $this->sqlCommand = trim($this->sqlCommand); + +        try { +            if ($this->srcFile === null && $this->sqlCommand === ""  +                && empty($this->filesets)) {  +                if (count($this->transactions) === 0) { +                    throw new BuildException("Source file or fileset, " +                                             . "transactions or sql statement " +                                             . "must be set!", $this->location); +                } +            } +         +            if ($this->srcFile !== null && !$this->srcFile->exists()) { +                throw new BuildException("Source file does not exist!", $this->location); +            } + +            // deal with the filesets +            for ($i = 0,$size=count($this->filesets); $i < $size; $i++) { +                $fs = $this->filesets[$i]; +                $ds = $fs->getDirectoryScanner($this->project); +                $srcDir = $fs->getDir($this->project); +                 +                $srcFiles = $ds->getIncludedFiles(); +                 +                // Make a transaction for each file +                for ($j=0, $size=count($srcFiles); $j < $size; $j++) { +                    $t = $this->createTransaction(); +                    $t->setSrc(new PhingFile($srcDir, $srcFiles[$j])); +                } +            } +             +            // Make a transaction group for the outer command +            $t = $this->createTransaction(); +            if ($this->srcFile) $t->setSrc($this->srcFile); +            $t->addText($this->sqlCommand); +            $this->conn = $this->getConnection(); + +            try { +                 +                $this->statement = $this->conn->createStatement(); +                 +                $out = null; +                 +                try { +                     +                    if ($this->output !== null) { +                        $this->log("Opening output file " . $this->output, PROJECT_MSG_VERBOSE); +                        $out = new BufferedWriter(new FileWriter($this->output->getAbsolutePath(), $this->append)); +                    } +                     +                    // Process all transactions +                    for ($i=0,$size=count($this->transactions); $i < $size; $i++) { +                        $this->transactions[$i]->runTransaction($out); +                        if (!$this->isAutocommit()) { +                            $this->log("Commiting transaction", PROJECT_MSG_VERBOSE); +                            $this->conn->commit(); +                        } +                    } +                    if ($out) $out->close(); +                } catch (Exception $e) { +                    if ($out) $out->close(); +                    throw $e; +                }  +            } catch (IOException $e) { +                if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { +                    try { +                        $this->conn->rollback(); +                    } catch (SQLException $ex) {} +                } +                throw new BuildException($e->getMessage(), $this->location); +            } catch (SQLException $e){ +                if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { +                    try { +                        $this->conn->rollback(); +                    } catch (SQLException $ex) {} +                } +                throw new BuildException($e->getMessage(), $this->location); +            } +             +            $this->log($this->goodSql . " of " . $this->totalSql . +                " SQL statements executed successfully"); +        } catch (Exception $e) { +            $this->transactions = $savedTransaction; +            $this->sqlCommand = $savedSqlCommand; +            throw $e; +        } +        // finally { +        $this->transactions = $savedTransaction; +        $this->sqlCommand = $savedSqlCommand; +         +    } + + +    /** +     * read in lines and execute them +     * @throws SQLException, IOException  +     */ +    public function runStatements(Reader $reader, $out = null) { +        $sql = ""; +        $line = ""; +        $in = new BufferedReader($reader); +        try { +            while (($line = $in->readLine()) !== null) { +                $line = trim($line); +                $line = ProjectConfigurator::replaceProperties($this->project, $line, +                        $this->project->getProperties()); +                 +                if (StringHelper::startsWith("//", $line) ||  +                    StringHelper::startsWith("--", $line) || +                    StringHelper::startsWith("#", $line)) { +                    continue; +                } +                 +                if (strlen($line) > 4 +                        && strtoupper(substr($line,0, 4)) == "REM ") { +                    continue; +                } + +                $sql .= " " . $line; +                $sql = trim($sql); + +                // SQL defines "--" as a comment to EOL +                // and in Oracle it may contain a hint +                // so we cannot just remove it, instead we must end it +                if (strpos($line, "--") !== false) { +                    $sql .= "\n"; +                } + +                if ($this->delimiterType == self::DELIM_NORMAL +                        && StringHelper::endsWith($this->delimiter, $sql) +                        || $this->delimiterType == self::DELIM_ROW +                        && $line == $this->delimiter) { +                    $this->log("SQL: " . $sql, PROJECT_MSG_VERBOSE); +                    $this->execSQL(StringHelper::substring($sql, 0, strlen($sql) - strlen($this->delimiter)) - 1, $out); +                    $sql = ""; +                } +            } + +            // Catch any statements not followed by ; +            if ($sql !== "") { +                $this->execSQL($sql, $out); +            } +        } catch (SQLException $e) { +            throw new BuildException("Error running statements", $e); +        } +    } +  +         +    /** +     * Exec the sql statement. +     * @throws SQLException  +     */ +    protected function execSQL($sql, $out = null) { +        // Check and ignore empty statements +        if (trim($sql) == "") { +            return; +        } + +        try { +            $this->totalSql++; +            if (!$this->statement->execute($sql)) { +                $this->log($this->statement->getUpdateCount() . " rows affected", PROJECT_MSG_VERBOSE); +            } else { +                if ($this->print) { +                    $this->printResults($out); +                } +            } +             +            $this->goodSql++; +             +        } catch (SQLException $e) {             +            $this->log("Failed to execute: " . $sql, PROJECT_MSG_ERR); +            if ($this->onError != "continue") {             +                throw new BuildException("Failed to execute SQL", $e); +            } +            $this->log($e->getMessage(), PROJECT_MSG_ERR); +        } +    } +     +    /** +     * print any results in the statement. +     * @throw SQLException +     */ +    protected function printResults($out = null) { +        $lSep = Phing::getProperty('line.separator'); +        $rs = null;         +        do { +            $rs = $this->statement->getResultSet(); +             +            if ($rs !== null) { +             +                $this->log("Processing new result set.", PROJECT_MSG_VERBOSE);             +     +                $line = ""; + +                $colsprinted = false; +                 +                while ($rs->next()) { +                    $fields = $rs->getRow(); +                     +                    if (!$colsprinted && $this->showheaders) { +                        $first = true; +                        foreach($fields as $fieldName => $ignore) { +                            if ($first) $first = false; else $line .= ","; +                            $line .= $fieldName; +                        } +                        if ($out !== null) { +                            $out->write($line); +                            $out->newLine(); +                        } else { +                            print($line.$lSep); +                        } +                        $line = ""; +                        $colsprinted = true; +                    } // if show headers +                     +                    $first = true; +                    foreach($fields as $columnValue) { +                         +                        if ($columnValue != null) { +                            $columnValue = trim($columnValue); +                        } + +                        if ($first) { +                            $first = false; +                        } else { +                            $line .= ","; +                        } +                        $line .= $columnValue; +                    } +                     +                    if ($out !== null) { +                        $out->write($line); +                        $out->newLine(); +                    } else {                     +                        print($line . $lSep); +                    } +                    $line = ""; +                     +                } // while rs->next() +            } +        } while ($this->statement->getMoreResults()); +        print($lSep); +        if ($out !== null) $out->newLine(); +    } +} + + +/** + * "Inner" class that contains the definition of a new transaction element. + * Transactions allow several files or blocks of statements + * to be executed using the same JDBC connection and commit + * operation in between. + */ +class SQLExecTransaction { + +    private $tSrcFile = null; +    private $tSqlCommand = ""; +    private $parent; +     +    function __construct($parent) +    { +        // Parent is required so that we can log things ... +        $this->parent = $parent; +    } +     +    public function setSrc(PhingFile $src) +    { +        $this->tSrcFile = $src; +    } + +    public function addText($sql) +    { +        $this->tSqlCommand .= $sql; +    } + +    /** +     * @throws IOException, SQLException +     */ +    public function runTransaction($out = null) +    { +        if (!empty($this->tSqlCommand)) { +            $this->parent->log("Executing commands", PROJECT_MSG_INFO); +            $this->parent->runStatements(new StringReader($this->tSqlCommand), $out); +        } + +        if ($this->tSrcFile !== null) { +            $this->parent->log("Executing file: " . $this->tSrcFile->getAbsolutePath(), +                PROJECT_MSG_INFO); +            $reader = new FileReader($this->tSrcFile); +            $this->parent->runStatements($reader, $out); +            $reader->close(); +        } +    } +} + + diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php new file mode 100644 index 00000000..a1b439e5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php @@ -0,0 +1,242 @@ +<?php + +/* + *  $Id: CreoleTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/Reference.php'; + +/** + * Handles Creole configuration needed by SQL type tasks. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Nick Chalko <nick@chalko.com> (Ant) + * @author    Jeff Martin <jeff@custommonkey.org> (Ant) + * @author    Michael McCallum <gholam@xtra.co.nz> (Ant) + * @author    Tim Stephenson <tim.stephenson@sybase.com> (Ant) + * @version   $Revision: 1.13 $ + * @package   phing.tasks.system + */ +abstract class CreoleTask extends Task { + +    /** +     * Used for caching loaders / driver. This is to avoid +     * getting an OutOfMemoryError when calling this task +     * multiple times in a row. +     *  +     * NOT IMPLEMENTED YET +     */ +    private static $loaderMap = array(); + +    private $caching = true; + +    /** +     * Autocommit flag. Default value is false +     */ +    private $autocommit = false; +     +    /** +     * [optional] Classpath to Creole driver to use. +     * @param string +     */ +    private $driver; +     +    /** +     * DB url. +     */ +    private $url; + +    /** +     * User name. +     */ +    private $userId; + +    /** +     * Password +     */ +    private $password; + +    /** +     * RDBMS Product needed for this SQL. +     **/ +    private $rdbms; +    +      /** +     * Initialize CreoleTask. +     * This method includes any necessary Creole libraries and triggers +     * appropriate error if they cannot be found.  This is not done in header +     * because we may want this class to be loaded w/o triggering an error. +     */ +    function init() { +        include_once 'creole/Creole.php'; +        if (!class_exists('Creole')) { +            throw new Exception("Creole task depends on Creole classes being on include_path. (i.e. include of 'creole/Creole.php' failed.)"); +        } +    } + +    /** +     * Caching loaders / driver. This is to avoid +     * getting an OutOfMemoryError when calling this task +     * multiple times in a row; default: true +     * @param $enable +     */ +    public function setCaching($enable) { +        $this->caching = $enable; +    } + +    /** +     * Sets the database connection URL; required. +     * @param url The url to set +     */ +    public function setUrl($url) { +        $this->url = $url; +    } + +    /** +     * Set the Creole driver to be used. +     * +     * @param string $driver driver class name +     */ +    public function setDriver($driver) +    { +        $this->driver = $driver; +    } +         +    /** +     * Sets the password; required. +     * @param password The password to set +     */ +    public function setPassword($password) { +        $this->password = $password; +    } + +    /** +     * Auto commit flag for database connection; +     * optional, default false. +     * @param autocommit The autocommit to set +     */ +    public function setAutocommit($autocommit) { +        $this->autocommit = $autocommit; +    } + +    /** +     * Sets the version string, execute task only if  +     * rdbms version match; optional. +     * @param version The version to set +     */ +    public function setVersion($version) { +        $this->version = $version; +    } +        +    protected function getLoaderMap() { +        return self::$loaderMap; +    } + + +    /** +     * Creates a new Connection as using the driver, url, userid and password specified. +     * The calling method is responsible for closing the connection. +     * @return Connection the newly created connection. +     * @throws BuildException if the UserId/Password/Url is not set or there is no suitable driver or the driver fails to load. +     */ +    protected function getConnection() { +             +        if ($this->url === null) { +            throw new BuildException("Url attribute must be set!", $this->location); +        } +                 +        try { + +            $this->log("Connecting to " . $this->getUrl(), PROJECT_MSG_VERBOSE); +            $info = new Properties(); +             +            $dsn = Creole::parseDSN($this->url); +             +            if (!isset($dsn["username"]) && $this->userId === null) { +                throw new BuildException("Username must be in URL or userid attribute must be set.", $this->location);                 +            }                         +             +            if ($this->userId) { +                $dsn["username"] = $this->getUserId(); +            } +             +            if ($this->password) { +                $dsn["password"] = $this->getPassword(); +            } +             +            if ($this->driver) { +                Creole::registerDriver($dsn['phptype'], $this->driver); +            } +             +            $conn = Creole::getConnection($dsn); +            $conn->setAutoCommit($this->autocommit); +            return $conn; +             +        } catch (SQLException $e) { +            throw new BuildException($e->getMessage(), $this->location); +        } + +    } + +    public function isCaching($value) { +        $this->caching = $value; +    } + +    /** +     * Gets the autocommit. +     * @return Returns a boolean +     */ +    public function isAutocommit() { +        return $this->autocommit; +    } + +    /** +     * Gets the url. +     * @return Returns a String +     */ +    public function getUrl() { +        return $this->url; +    } + +    /** +     * Gets the userId. +     * @return Returns a String +     */ +    public function getUserId() { +        return $this->userId; +    } + +    /** +     * Set the user name for the connection; required. +     * @param userId The userId to set +     */ +    public function setUserid($userId) { +        $this->userId = $userId; +    } + +    /** +     * Gets the password. +     * @return Returns a String +     */ +    public function getPassword() { +        return $this->password; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/MailTask.php b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php new file mode 100644 index 00000000..16d29fb8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php @@ -0,0 +1,77 @@ +<?php +/* + *  $Id: MailTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +include_once 'phing/Task.php'; + +/** + *  Send a message by mail()  + * + *  <mail to="user@example.org" subject="build complete">The build process is a success...</mail>  + *  + *  @author   Francois Harvey at SecuriWeb (http://www.securiweb.net) + *  @version  $Revision: 1.1 $ + *  @package  phing.tasks.ext + */ +class MailTask extends Task { + +    protected $recipient; +       +    protected $subject; +     +    protected $msg; + +    function main() { +        $this->log('Sending mail to ' . $this->recipient );     +        mail($this->recipient, $this->subject, $this->msg); +    } + +    /** setter for message */ +    function setMsg($msg) { +        $this->setMessage($msg); +    } + +    /** alias setter */ +    function setMessage($msg) { +        $this->msg = (string) $msg; +    } +     +    /** setter for subject **/ +    function setSubject($subject) { +        $this->subject = (string) $subject;     +    } + +    /** setter for recipient **/ +    function setRecipient($recipient) { +        $this->recipient = (string) $recipient; +    } + +    /** alias for recipient **/ +    function setTo($recipient) { +        $this->recipient = (string) $recipient; +    } +         +    /** Supporting the <mail>Message</mail> syntax. */ +    function addText($msg) +    { +        $this->msg = (string) $msg; +    } +} + diff --git a/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php new file mode 100644 index 00000000..b8664aac --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php @@ -0,0 +1,65 @@ +<?php + +/* + *  $Id: PackageAsPathTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/Task.php'; + +/** + * Convert dot-notation packages to relative paths. + * + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.5 $ + * @package   phing.tasks.ext + */ +class PackageAsPathTask extends Task { + +    /** The package to convert. */ +    protected $pckg; + +    /** The value to store the conversion in. */ +    protected $name; +     +    /** +     * Executes the package to patch converstion and stores it +     * in the user property <code>value</code>. +     */ +    public function main() +    { +        $this->project->setUserProperty($this->name, strtr($this->pckg, '.', '/'));         +    } + +    /** +     * @param string $pckg the package to convert +     */ +    public function setPackage($pckg) +    { +        $this->pckg = $pckg; +    } + +    /** +     * @param string $name the Ant variable to store the path in +     */ +    public function setName($name) +    { +        $this->name = $name; +    } +     +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php b/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php new file mode 100644 index 00000000..4f8ee3ab --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php @@ -0,0 +1,421 @@ +<?php +/* + *  $Id: PearPackageTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/types/FileSet.php'; + +/** + * A task to create PEAR package.xml file. + *  + * This class uses the PEAR_PackageFileMaintainer class to perform the work. + *  + * This class is designed to be very flexible -- i.e. account for changes to the package.xml w/o + * requiring changes to this class.  We've accomplished this by having generic <option> and <mapping> + * nested elements.  All options are set using PEAR_PackageFileMaintainer::setOptions(). + *  + * The <option> tag is used to set a simple option value. + * <code> + * <option name="option_name" value="option_value"/>  + * or <option name="option_name">option_value</option> + * </code> + *  + * The <mapping> tag represents a complex data type.  You can use nested <element> (and nested <element> with + * <element> tags) to represent the full complexity of the structure.  Bear in mind that what you are creating + * will be mapped to an associative array that will be passed in via PEAR_PackageFileMaintainer::setOptions(). + * <code> + * <mapping name="option_name"> + *  <element key="key_name" value="key_val"/> + *  <element key="key_name" value="key_val"/> + * </mapping> + * </code> + *  + * Here's an over-simple example of how this could be used: + * <code> + * <pearpkg name="phing" dir="${build.src.dir}" destFile="${build.base.dir}/package.xml"> + *  <fileset> + *   <include name="**"/> + *  </fileset> + *  <option name="notes">Sample release notes here.</option> + *  <option name="description">Package description</option> + *  <option name="summary">Short description</option> + *  <option name="version" value="2.0.0b1"/> + *  <option name="state" value="beta"/> + *  <mapping name="maintainers"> + *   <element> + *    <element key="handle" value="hlellelid"/> + *    <element key="name" value="Hans"/> + *    <element key="email" value="hans@xmpl.org"/> + *    <element key="role" value="lead"/> + *   </element> + *  </mapping> + * </pearpkg> + * </code> + * + * Look at the build.xml in the Phing base directory (assuming you have the full distro / CVS version of Phing) to + * see a more complete example of how to call this script. + *  + * @author   Hans Lellelid <hans@xmpl.org> + * @package  phing.tasks.ext + * @version  $Revision: 1.9 $ + */ +class PearPackageTask extends MatchingTask { +     +    /** */         +    private $package; + +    /** Base directory for reading files. */ +    private $dir; +     +    /** Package file */ +    private $packageFile; +     +    /** @var array FileSet[] */ +    private $filesets = array(); +     +    /** @var PEAR_PackageFileManager */ +    private $pkg; +     +    private $preparedOptions = array(); +     +    /** @var array PearPkgOption[] */ +    private $options = array(); +     +    /** Nested <mapping> (complex options) types. */ +    private $mappings = array(); +     +    public function init() { +        include_once 'PEAR/PackageFileManager.php'; +        if (!class_exists('PEAR_PackageFileManager')) { +            throw new BuildException("You must have installed PEAR_PackageFileManager in order to create a PEAR package.xml file."); +        } +    } +     +    /** +     * Sets PEAR package.xml options, based on class properties. +     * @return void +     */ +    private function setOptions() { +     +        // 1) first prepare/populate options         +        $this->populateOptions(); + +        // 2) make any final adjustments (this could move into populateOptions() also) +         +        // default PEAR basedir would be the name of the package (e.g."phing") +        if (!isset($this->preparedOptions['baseinstalldir'])) { +            $this->preparedOptions['baseinstalldir'] = $this->package; +        } +         +        // unless filelistgenerator has been overridden, we use Phing FileSet generator +        if (!isset($this->preparedOptions['filelistgenerator'])) { +            if (empty($this->filesets)) { +                throw new BuildException("You must use a <fileset> tag to specify the files to include in the package.xml"); +            } +            $this->preparedOptions['filelistgenerator'] = 'Fileset'; +            $this->preparedOptions['usergeneratordir'] = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'pearpackage'; +            // Some PHING-specific options needed by our Fileset reader +            $this->preparedOptions['phing_project'] = $this->project; +            $this->preparedOptions['phing_filesets'] = $this->filesets; +        } elseif ($this->preparedOptions['filelistgeneragor'] != 'Fileset' && !empty($this->filesets)) { +            throw new BuildException("You cannot use <fileset> element if you have specified the \"filelistgenerator\" option."); +        }                 +         +        // 3) Set the options +                 +        // No need for excessive validation here, since the  PEAR class will do its own  +        // validation & return errors +        $e = $this->pkg->setOptions($this->preparedOptions); +             +        if (PEAR::isError($e)) { +            throw new BuildException("Unable to set options.", new Exception($e->getMessage())); +        } +    } +     +    /** +     * Fixes the boolean in optional dependencies +     */ +    private function fixDeps($deps) +    { +        foreach (array_keys($deps) as $dep) +        { +            if (isset($deps[$dep]['optional']) && $deps[$dep]['optional']) +            { +                $deps[$dep]['optional'] = "yes"; +            } +        } +         +        return $deps; +    } +     +    /** +     * Adds the options that are set via attributes and the nested tags to the options array. +     */ +    private function populateOptions() { +         +        // These values could be overridden if explicitly defined using nested tags     +        $this->preparedOptions['package'] = $this->package; +        $this->preparedOptions['packagedirectory'] = $this->dir->getAbsolutePath(); +         +        if ($this->packageFile !== null) { +            // create one w/ full path +            $f = new PhingFile($this->packageFile->getAbsolutePath()); +            $this->preparedOptions['packagefile'] = $f->getName(); +            // must end in trailing slash +            $this->preparedOptions['outputdirectory'] = $f->getParent() . DIRECTORY_SEPARATOR; +            $this->log("Creating package file: " . $f->__toString(), PROJECT_MSG_INFO); +        } else { +            $this->log("Creating [default] package.xml file in base directory.", PROJECT_MSG_INFO); +        } +         +        // converts option objects and mapping objects into  +        // key => value options that can be passed to PEAR_PackageFileManager +         +        foreach($this->options as $opt) { +            $this->preparedOptions[ $opt->getName() ] = $opt->getValue(); //no arrays yet. preg_split('/\s*,\s*/', $opt->getValue()); +        } +         +        foreach($this->mappings as $map) { +            $value = $map->getValue(); // getValue returns complex value +             +            if ($map->getName() == 'deps') +            { +                $value = $this->fixDeps($value); +            } +             +            $this->preparedOptions[ $map->getName() ] = $value; +        } +    } +     +    /** +     * Main entry point. +     * @return void +     */ +    public function main() {         +         +        if ($this->dir === null) { +            throw new BuildException("You must specify the \"dir\" attribute for PEAR package task."); +        } +         +        if ($this->package === null) { +            throw new BuildException("You must specify the \"name\" attribute for PEAR package task."); +        } +         +        $this->pkg = new PEAR_PackageFileManager();                 +         +        $this->setOptions(); +         +        $e = $this->pkg->writePackageFile(); +        if (PEAR::isError($e)) { +            throw new BuildException("Unable to write package file.", new Exception($e->getMessage())); +        } +         +    } +     +    /** +     * Used by the PEAR_PackageFileManager_PhingFileSet lister. +     * @return array FileSet[] +     */ +    public function getFileSets() { +        return $this->filesets; +    } +     +    // ------------------------------- +    // Set properties from XML +    // ------------------------------- + +    /** +     * Nested creator, creates a FileSet for this task +     * +     * @return FileSet The created fileset object +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } +     +    /** +     * Set "package" property from XML. +     * @see setName() +     * @param string $v +     * @return void +     */ +    public function setPackage($v) { +        $this->package = $v; +    } +     +    /** +     * Sets "dir" property from XML. +     * @param PhingFile $f +     * @return void +     */ +    public function setDir(PhingFile $f) { +        $this->dir = $f; +    } + +    /** +     * Sets "name" property from XML. +     * @param string $v +     * @return void +     */ +    public function setName($v) { +        $this->package = $v; +    } +     +    /** +     * Sets the file to use for generated package.xml +     */ +    public function setDestFile(PhingFile $f) { +        $this->packageFile = $f; +    } +     +    /** +     * Handles nested generic <option> elements. +     */ +    function createOption() { +        $o = new PearPkgOption(); +        $this->options[] = $o; +        return $o; +    } +     +    /** +     * Handles nested generic <option> elements. +     */ +    function createMapping() { +        $o = new PearPkgMapping(); +        $this->mappings[] = $o; +        return $o; +    } +} + + + +/** + * Generic option class is used for non-complex options. + */ +class PearPkgOption { +     +    private    $name; +    private $value; +     +    public function setName($v) { $this->name = $v; } +    public function getName() { return $this->name; } +     +    public function setValue($v) { $this->value = $v; } +    public function getValue() { return $this->value; } +    public function addText($txt) { $this->value = trim($txt); } +         +} + +/** + * Handles complex options <mapping> elements which are hashes (assoc arrays). + */ +class PearPkgMapping { + +    private    $name; +    private $elements = array();     +     +    public function setName($v) { +        $this->name = $v; +    } +     +    public function getName() {  +        return $this->name; +    } + +    public function createElement() {  +        $e = new PearPkgMappingElement(); +        $this->elements[] = $e; +        return $e; +    } +         +    public function    getElements() { +        return $this->elements; +    } +     +    /** +     * Returns the PHP hash or array of hashes (etc.) that this mapping represents. +     * @return array +     */ +    public function getValue() { +        $value = array(); +        foreach($this->getElements() as $el) { +            if ($el->getKey() !== null) { +                $value[ $el->getKey() ] = $el->getValue(); +            } else { +                $value[] = $el->getValue(); +            } +        } +        return $value; +    } +} + +/** + * Sub-element of <mapping>. + */ +class PearPkgMappingElement { + +    private    $key; +    private $value; +    private $elements = array(); +     +    public function setKey($v) { +        $this->key = $v; +    } +     +    public function getKey() { +        return $this->key; +    } +     +    public function setValue($v) { +        $this->value = $v; +    } +     +    /** +     * Returns either the simple value or +     * the calculated value (array) of nested elements. +     * @return mixed +     */ +    public function getValue() {     +        if (!empty($this->elements)) { +            $value = array(); +            foreach($this->elements as $el) { +                if ($el->getKey() !== null) { +                    $value[ $el->getKey() ] = $el->getValue(); +                } else { +                    $value[] = $el->getValue(); +                } +            }             +            return $value; +        } else  { +            return $this->value;         +        } +    } +     +    /** +     * Handles nested <element> tags. +     */ +    public function createElement() { +        $e = new PearPkgMappingElement(); +        $this->elements[] = $e; +        return $e; +    } +     +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php b/buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php new file mode 100644 index 00000000..2fd89fc3 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php @@ -0,0 +1,82 @@ +<?php +require_once 'phing/Task.php'; + +/** + * A PHP lint task. Checking syntax of one or more PHP source file. + * + * @author   Knut Urdalen <knut.urdalen@telio.no> + * @package  phing.tasks.ext + */ +class PhpLintTask extends Task { + +  protected $file;  // the source file (from xml attribute) +  protected $filesets = array(); // all fileset objects assigned to this task + +  /** +   * File to be performed syntax check on +   * @param PhingFile $file +   */ +  public function setFile(PhingFile $file) { +    $this->file = $file; +  } +   +  /** +   * Nested creator, creates a FileSet for this task +   * +   * @return FileSet The created fileset object +   */ +  function createFileSet() { +    $num = array_push($this->filesets, new FileSet()); +    return $this->filesets[$num-1]; +  } + +  /** +   * Execute lint check against PhingFile or a FileSet +   */ +  public function main() { +    if(!isset($this->file) and count($this->filesets) == 0) { +      throw new BuildException("Missing either a nested fileset or attribute 'file' set"); +    } + +    if($this->file instanceof PhingFile) { +      $this->lint($this->file->getPath()); +    } else { // process filesets +      $project = $this->getProject(); +      foreach($this->filesets as $fs) { +	$ds = $fs->getDirectoryScanner($project); +	$files = $ds->getIncludedFiles(); +	$dir = $fs->getDir($this->project)->getPath(); +	foreach($files as $file) { +	  $this->lint($dir.DIRECTORY_SEPARATOR.$file); +	} +      } +    } +  } + +  /** +   * Performs the actual syntax check +   * +   * @param string $file +   * @return void +   */ +  protected function lint($file) { +    $command = 'php -l '; +    if(file_exists($file)) { +      if(is_readable($file)) { +	$message = array(); +	exec($command.$file, $message); +	if(!preg_match('/^No syntax errors detected/', $message[0])) { +	  $this->log($message[1], PROJECT_MSG_ERR); +	} else { +	  $this->log($file.': No syntax errors detected', PROJECT_MSG_INFO); +	} +      } else { +	throw new BuildException('Permission denied: '.$file); +      } +    } else { +      throw new BuildException('File not found: '.$file); +    } +  } +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php b/buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php new file mode 100644 index 00000000..97eada3d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php @@ -0,0 +1,610 @@ +<?php + +/* + *  $Id: SmartyTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ +  +require_once 'phing/Task.php'; +include_once 'phing/BuildException.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * A phing task for generating output by using Smarty. + * + * This is based on the TexenTask from Apache's Velocity engine.  This class + * was originally proted in order to provide a template compiling system for + * Torque. + * + * TODO: + *        - Add Path / useClasspath support? + * + * @author    Hans Lellelid <hans@xmpl.org> (SmartyTask) + * @author    Jason van Zyl <jvanzyl@apache.org> (TexenTask) + * @author    Robert Burrell Donkin <robertdonkin@mac.com> + * @version   $Id: SmartyTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package   phing.tasks.ext + */ +class SmartyTask extends Task { + +    /** +     * Smarty template engine. +     * @var Smarty +     */ +    protected $context; +     +    /** +     * Variables that are assigned to the context on parse/compile. +     * @var array +     */ +    protected $properties = array(); +     +    /** +     * This is the control template that governs the output. +     * It may or may not invoke the services of worker +     * templates. +     * @var string +     */ +    protected $controlTemplate; +     +    /** +     * This is where Velocity will look for templates +     * using the file template loader. +     * @var string +     */ +    protected $templatePath; +     +    /** +     * This is where texen will place all the output +     * that is a product of the generation process. +     * @var string +     */ +    protected $outputDirectory; +     +    /** +     * This is the file where the generated text +     * will be placed. +     * @var string +     */ +    protected $outputFile; + +    /** +     * <p> +     * These are properties that are fed into the +     * initial context from a properties file. This +     * is simply a convenient way to set some values +     * that you wish to make available in the context. +     * </p> +     * <p> +     * These values are not critical, like the template path +     * or output path, but allow a convenient way to +     * set a value that may be specific to a particular +     * generation task. +     * </p> +     * <p> +     * For example, if you are generating scripts to allow +     * user to automatically create a database, then +     * you might want the <code>$databaseName</code>  +     * to be placed +     * in the initial context so that it is available +     * in a script that might look something like the +     * following: +     * <code><pre> +     * #!bin/sh +     *  +     * echo y | mysqladmin create $databaseName +     * </pre></code> +     * The value of <code>$databaseName</code> isn't critical to +     * output, and you obviously don't want to change +     * the ant task to simply take a database name. +     * So initial context values can be set with +     * properties file. +     * +     * @var array +     */ +    protected $contextProperties; +         +    /** +     * Smarty compiles templates before parsing / replacing tokens in them. +     * By default it will try ./templates_c, but you may wish to override this. +     * @var string +     */ +    protected $compilePath; +     +    /** +     * Whether to force Smarty to recompile templates. +     * Smarty does check file modification time, but you can set this +     * to be *sure* that the template will be compiled (of course it will +     * be slower if you do). +     * @var boolean +     */ +    protected $forceCompile = false; +     +    /** +     * Smarty can use config files. +     * This tells Smarty where to look for the config files. +     * @var string +     */ +    protected $configPath; +     +    /** +     * Customize the left delimiter for Smarty tags. +     * @var string +     */ +    protected $leftDelimiter; + +    /** +     * Customize the right delimiter for Smarty tags. +     * @var string +     */ +    protected $rightDelimiter; + +    // ----------------------------------------------------------------------- +    // The following getters & setters are used by phing to set properties +    // specified in the XML for the smarty task. +    // ----------------------------------------------------------------------- +     +    public function init() { +        include_once 'Smarty.class.php'; +        if (!class_exists('Smarty')) { +            throw new BuildException("To use SmartyTask, you must have the path to Smarty.class.php on your include_path or your \$PHP_CLASSPATH environment variable."); +        } +    } +     +    /** +     * [REQUIRED] Set the control template for the +     * generating process. +     * @param string $controlTemplate +     * @return void +     */ +    public function setControlTemplate ($controlTemplate) { +        $this->controlTemplate = $controlTemplate; +    } + +    /** +     * Get the control template for the +     * generating process. +     * @return string +     */ +    public function getControlTemplate() { +        return $this->controlTemplate; +    } + +    /** +     * [REQUIRED] Set the path where Velocity will look +     * for templates using the file template +     * loader. +     * @return void +     * @throws Exception  +     */ +    public function setTemplatePath($templatePath) { +        $resolvedPath = "";         +        $tok = strtok($templatePath, ","); +        while ( $tok ) {             +            // resolve relative path from basedir and leave +            // absolute path untouched. +            $fullPath = $this->project->resolveFile($tok); +            $cpath = $fullPath->getCanonicalPath(); +            if ($cpath === false) { +                $this->log("Template directory does not exist: " . $fullPath->getAbsolutePath()); +            } else { +                $resolvedPath .= $cpath; +            } +            $tok = strtok(","); +            if ( $tok ) { +                $resolvedPath .= ","; +            } +        } +        $this->templatePath = $resolvedPath; +     } + +    /** +     * Get the path where Velocity will look +     * for templates using the file template +     * loader. +     * @return string +     */ +    public function getTemplatePath() { +        return $this->templatePath; +    }         + +    /** +     * [REQUIRED] Set the output directory. It will be +     * created if it doesn't exist. +     * @param PhingFile $outputDirectory +     * @return void +     * @throws Exception +     */ +    public function setOutputDirectory(PhingFile $outputDirectory) { +        try {             +            if (!$outputDirectory->exists()) { +                $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),PROJECT_MSG_VERBOSE); +                if (!$outputDirectory->mkdirs()) { +                    throw new IOException("Unable to create Ouptut directory: " . $outputDirectory->getAbsolutePath()); +                } +            } +            $this->outputDirectory = $outputDirectory->getCanonicalPath(); +        } catch (IOException $ioe) { +            throw new BuildException($ioe->getMessage()); +        } +    } +       +    /** +     * Get the output directory. +     * @return string +     */ +    public function getOutputDirectory() { +        return $this->outputDirectory; +    }         + +    /** +     * [REQUIRED] Set the output file for the +     * generation process. +     * @return void +     */ +    public function setOutputFile($outputFile) { +        $this->outputFile = $outputFile; +    } + +    /** +     * Get the output file for the +     * generation process. +     * @return string +     */ +    public function getOutputFile() { +        return $this->outputFile; +    }         + +    /** +     * Set the path Smarty uses as a "cache" for compiled templates. +     * @param string $compilePath +     */ +    public function setCompilePath($compilePath) { +        $this->compilePath = $compilePath; +    } +     +    /** +     * Get the path Smarty uses for compiling templates. +     * @return string +     */ +    public function getCompilePath() { +        return $this->compilePath; +    } +     +    /** +     * Set whether Smarty should always recompile tempaltes. +     * @param boolean $force +     * @return void +     */ +    public function setForceCompile($force) { +        $this->forceCompile = (boolean) $force; +    } +     +    /** +     * Get whether Smarty should always recompile template. +     * @return boolean +     */ +    public function getForceCompile() { +        return $this->forceCompile; +    } +     +    /** +     * Set where Smarty looks for config files. +     * @param string $configPath +     * @return void +     */ +    public function setConfigPath($configPath) { +        $this->configPath = $configPath; +    } +     +    /** +     * Get the path that Smarty uses for looking for config files. +     * @return string +     */ +    public function getConfigPath() { +        return $this->configPath; +    } +     +    /** +     * Set Smarty template left delimiter. +     * @param string $delim +     * @return void +     */ +    public function setLeftDelimiter($delim) { +        $this->leftDelimiter = $delim; +    } +     +    /** +     * Get Smarty template right delimiter +     * @return string +     */ +    public function getLeftDelimiter() { +        return $this->leftDelimiter; +    } +     +    /** +     * Set Smarty template right delimiter. +     * @param string $delim +     * @return void +     */ +    public function setRightDelimiter($delim) { +        $this->rightDelimiter = $delim; +    } +     +    /** +     * Get Smarty template right delimiter +     * @return string +     */ +    public function getRightDelimiter() { +        return $this->rightDelimiter; +    } +     +     +    /** +     * Set the context properties that will be +     * fed into the initial context be the +     * generating process starts. +     * @param string $file +     * @return void +     */ +    public function setContextProperties($file) { +     +        $sources = explode(",", $file); +        $this->contextProperties = new Properties(); +         +        // Always try to get the context properties resource +        // from a file first. Templates may be taken from a JAR +        // file but the context properties resource may be a  +        // resource in the filesystem. If this fails than attempt +        // to get the context properties resource from the +        // classpath. +        for ($i=0, $sourcesLength=count($sources); $i < $sourcesLength; $i++) { +            $source = new Properties(); +             +            try { +             +                // resolve relative path from basedir and leave +                // absolute path untouched. +                $fullPath = $this->project->resolveFile($sources[$i]); +                $this->log("Using contextProperties file: " . $fullPath->__toString()); +                $source->load($fullPath); +                 +            } catch (Exception $e) { +               +              throw new BuildException("Context properties file " . $sources[$i] . +                            " could not be found in the file system!"); +                      +            } +         +            $keys = $source->keys(); +             +            foreach ($keys as $key) { +                $name = $key; +                $value = $this->project->replaceProperties($source->getProperty($name)); +                $this->contextProperties->setProperty($name, $value); +            } +        } +    } + +    /** +     * Get the context properties that will be +     * fed into the initial context be the +     * generating process starts. +     * @return Properties +     */ +    public function getContextProperties() { +        return $this->contextProperties; +    }      + +    // --------------------------------------------------------------- +    // End of XML setters & getters +    // --------------------------------------------------------------- + +    +    /** +     * Creates a Smarty object. +     * +     * @return Smarty initialized (cleared) Smarty context. +     * @throws Exception the execute method will catch  +     *         and rethrow as a <code>BuildException</code> +     */ +    public function initControlContext() {         +        $this->context->clear_all_assign();         +        return $this->context; +    } +     +    /** +     * Execute the input script with Velocity +     * +     * @throws BuildException   +     * BuildExceptions are thrown when required attributes are missing. +     * Exceptions thrown by Velocity are rethrown as BuildExceptions. +     */ +    public function main() { +     +        // Make sure the template path is set. +        if (empty($this->templatePath)) { +            throw new BuildException("The template path needs to be defined!"); +        }             +     +        // Make sure the control template is set. +        if ($this->controlTemplate === null) { +            throw new BuildException("The control template needs to be defined!"); +        }             + +        // Make sure the output directory is set. +        if ($this->outputDirectory === null) { +            throw new BuildException("The output directory needs to be defined!"); +        }             +         +        // Make sure there is an output file. +        if ($this->outputFile === null) { +            throw new BuildException("The output file needs to be defined!"); +        }             +         +        // Setup Smarty runtime. +         +        // Smarty uses one object to store properties and to store +        // the context for the template (unlike Velocity).  We setup this object, calling it +        // $this->context, and then initControlContext simply zeros out +        // any assigned variables. +        $this->context = new Smarty(); +         +        if ($this->compilePath !== null) { +            $this->log("Using compilePath: " . $this->compilePath); +            $this->context->compile_dir = $this->compilePath; +        } +         +        if ($this->configPath !== null) { +            $this->log("Using configPath: " . $this->configPath); +            $this->context->config_dir = $this->configPath; +        }         +         +        if ($this->forceCompile !== null) { +            $this->context->force_compile = $this->forceCompile; +        } +         +        if ($this->leftDelimiter !== null) { +            $this->context->left_delimiter = $this->leftDelimiter; +        } +         +        if ($this->rightDelimiter !== null) { +            $this->context->right_delimiter = $this->rightDelimiter; +        } +         +        if ($this->templatePath !== null) { +            $this->log("Using templatePath: " . $this->templatePath); +            $this->context->template_dir = $this->templatePath; +        }                                                         +         +        $smartyCompilePath = new PhingFile($this->context->compile_dir); +        if (!$smartyCompilePath->exists()) { +            $this->log("Compile directory does not exist, creating: " . $smartyCompilePath->getPath(), PROJECT_MSG_VERBOSE); +            if (!$smartyCompilePath->mkdirs()) { +                throw new BuildException("Smarty needs a place to compile templates; specify a 'compilePath' or create ".$this->context->compile_dir); +            } +        } +         +        // Make sure the output directory exists, if it doesn't +        // then create it. +        $file = new PhingFile($this->outputDirectory); +        if (!$file->exists()) { +            $this->log("Output directory does not exist, creating: " . $file->getAbsolutePath()); +            $file->mkdirs(); +        } +         +        $path = $this->outputDirectory . DIRECTORY_SEPARATOR . $this->outputFile; +        $this->log("Generating to file " . $path); +         +        $writer = new FileWriter($path); +                 +        // The generator and the output path should +        // be placed in the init context here and +        // not in the generator class itself. +        $c = $this->initControlContext(); +         +        // Set any variables that need to always +        // be loaded +        $this->populateInitialContext($c); +         +        // Feed all the options into the initial +        // control context so they are available +        // in the control/worker templates. +        if ($this->contextProperties !== null) { +             +            foreach($this->contextProperties->keys() as $property) { +                     +                $value = $this->contextProperties->getProperty($property); +                 +                // Special exception (from Texen) +                // for properties ending in file.contents: +                // in that case we dump the contents of the file +                // as the "value" for the Property. +                if (StringHelper::endsWith("file.contents", $property)) { +                    // pull in contents of file specified  +                                             +                    $property = substr($property, 0, strpos($property, "file.contents") - 1); +                     +                    // reset value, and then  +                    // read in teh contents of the file into that var +                    $value = ""; +                    $f = new PhingFile($project->resolveFile($value)->getCanonicalPath());                         +                    if ($f->exists()) { +                        try { +                            $fr = new FileReader($f); +                            $fr->readInto($value); +                        } catch (Exception $e) { +                            throw $e; +                        } +                    }     +                                                                     +                 } // if ends with file.contents +                 +                    if (StringHelper::isBoolean($value)) { +                        $value = StringHelper::booleanValue($value); +                    } +                                                         +                 $c->assign($property, $value);  +                  +            } // foreach property +                 +        } // if contextProperties !== null +         +        try { +            //$c->display($this->controlTemplate);             +            $writer->write($c->fetch($this->controlTemplate)); +            $writer->close(); +        } catch (IOException $ioe) { +            $writer->close(); +            throw new BuildException("Cannot write parsed template."); +        }         +         +        $this->cleanup();     +    } + +    /** +     * <p>Place useful objects into the initial context.</p> +     * +     * <p>TexenTask places <code>Date().toString()</code> into the +     * context as <code>$now</code>.  Subclasses who want to vary the +     * objects in the context should override this method.</p> +     * +     * <p><code>$generator</code> is not put into the context in this +     * method.</p> +     * +     * @param context The context to populate, as retrieved from +     * {@link #initControlContext()}. +     * @return void +     * @throws Exception Error while populating context.  The {@link +     * #execute()} method will catch and rethrow as a +     * <code>BuildException</code>. +     */ +    protected function populateInitialContext(Smarty $context)  {        +    } +     +    /** +     * A hook method called at the end of {@link #execute()} which can +     * be overridden to perform any necessary cleanup activities (such +     * as the release of database connections, etc.).  By default, +     * does nothing. +     * @return void +     * @throws Exception Problem cleaning up. +     */ +    protected function cleanup() { +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/TarTask.php b/buildscripts/phing/classes/phing/tasks/ext/TarTask.php new file mode 100644 index 00000000..8d6bb47f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/TarTask.php @@ -0,0 +1,380 @@ +<?php +/* + *  $Id: TarTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/MergeMapper.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * Creates a tar archive using PEAR Archive_Tar. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Stefano Mazzocchi <stefano@apache.org> (Ant) + * @author    Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @author    Magesh Umasankar + * @version   $Revision: 1.10 $ + * @package   phing.tasks.ext + */ +class TarTask extends MatchingTask { +     +    const TAR_NAMELEN = 100; +     +    const WARN = "warn"; +    const FAIL = "fail";    +    const OMIT = "omit";     +     +    private $tarFile; +    private $baseDir; + +    private $longFileMode = "warn"; + +    private $filesets = array(); +    private $fileSetFiles = array(); + +    /** +     * Indicates whether the user has been warned about long files already. +     */ +    private $longWarningGiven = false; +     +    /** +     * Compression mode.  Available options "gzip", "bzip2", "none" (null). +     */ +    private $compression = null; +     +    /** +     * Ensures that PEAR lib exists. +     */ +    public function init() { +        include_once 'Archive/Tar.php'; +        if (!class_exists('Archive_Tar')) { +            throw new BuildException("You must have installed the PEAR Archive_Tar class in order to use TarTask."); +        } +    } +     +    /** +     * Add a new fileset +     * @return FileSet +     */ +    public function createTarFileSet() { +        $this->fileset = new TarFileSet(); +        $this->filesets[] = $this->fileset; +        return $this->fileset; +    } +     +    /** +     * Add a new fileset.  Alias to createTarFileSet() for backwards compatibility. +     * @return FileSet +     * @see createTarFileSet() +     */ +    public function createFileSet() { +        $this->fileset = new TarFileSet(); +        $this->filesets[] = $this->fileset; +        return $this->fileset; +    } + +    /** +     * Set is the name/location of where to create the tar file. +     * @param PhingFile $destFile The output of the tar +     */ +    public function setDestFile(PhingFile $destFile) { +        $this->tarFile = $destFile; +    } + +    /** +     * This is the base directory to look in for things to tar. +     * @param PhingFile $baseDir +     */ +    public function setBasedir(PhingFile $baseDir) { +        $this->baseDir = $baseDir; +    } + +    /** +     * Set how to handle long files, those with a path>100 chars. +     * Optional, default=warn. +     * <p> +     * Allowable values are +     * <ul> +     * <li>  truncate - paths are truncated to the maximum length +     * <li>  fail - paths greater than the maximim cause a build exception +     * <li>  warn - paths greater than the maximum cause a warning and GNU is used +     * <li>  gnu - GNU extensions are used for any paths greater than the maximum. +     * <li>  omit - paths greater than the maximum are omitted from the archive +     * </ul> +     */ +    public function setLongfile($mode) { +        $this->longFileMode = $mode; +    } + +    /** +     * Set compression method. +     * Allowable values are +     * <ul> +     * <li>  none - no compression +     * <li>  gzip - Gzip compression +     * <li>  bzip2 - Bzip2 compression +     * </ul> +     */ +    public function setCompression($mode) {         +        switch($mode) { +            case "gzip": +                $this->compression = "gz"; +                break; +            case "bzip2": +                $this->compression = "bz2"; +                break; +            case "none": +                $this->compression = null; +                break; +            default: +                $this->log("Ignoring unknown compression mode: ".$mode, PROJECT_MSG_WARN); +                $this->compression = null; +        } +    } +     +    /** +     * do the work +     * @throws BuildException +     */ +    public function main() { +     +        if ($this->tarFile === null) { +            throw new BuildException("tarfile attribute must be set!", $this->getLocation()); +        } + +        if ($this->tarFile->exists() && $this->tarFile->isDirectory()) { +            throw new BuildException("tarfile is a directory!", $this->getLocation()); +        } + +        if ($this->tarFile->exists() && !$this->tarFile->canWrite()) { +            throw new BuildException("Can not write to the specified tarfile!", $this->getLocation()); +        } + +        // shouldn't need to clone, since the entries in filesets +        // themselves won't be modified -- only elements will be added +        $savedFileSets = $this->filesets; +         +        try { +            if ($this->baseDir !== null) { +                if (!$this->baseDir->exists()) { +                    throw new BuildException("basedir does not exist!", $this->getLocation()); +                } + +                // add the main fileset to the list of filesets to process. +                $mainFileSet = new TarFileSet($this->fileset); +                $mainFileSet->setDir($this->baseDir); +                $this->filesets[] = $mainFileSet; +            } + +            if (empty($this->filesets)) { +                throw new BuildException("You must supply either a basedir " +                                         . "attribute or some nested filesets.", +                                         $this->getLocation()); +            }                         +             +            // check if tar is out of date with respect to each +            // fileset +            $upToDate = true; +            foreach($this->filesets as $fs) { +                $files = $fs->getFiles($this->project); +                if (!$this->archiveIsUpToDate($files, $fs->getDir($this->project))) { +                    $upToDate = false; +                } +                for ($i=0, $fcount=count($files); $i < $fcount; $i++) { +                    if ($this->tarFile->equals(new PhingFile($fs->getDir($this->project), $files[$i]))) { +                        throw new BuildException("A tar file cannot include itself", $this->getLocation()); +                    } +                } +            } +             +            if ($upToDate) { +                $this->log("Nothing to do: " . $this->tarFile->__toString() . " is up to date.", PROJECT_MSG_INFO); +                return; +            } + +            $this->log("Building tar: " . $this->tarFile->__toString(), PROJECT_MSG_INFO); +             +            $tar = new Archive_Tar($this->tarFile->getAbsolutePath(), $this->compression); +             +            // print errors +            $tar->setErrorHandling(PEAR_ERROR_PRINT); +             +            foreach($this->filesets as $fs) {                                 +                    $files = $fs->getFiles($this->project); +                    if (count($files) > 1 && strlen($fs->getFullpath()) > 0) { +                        throw new BuildException("fullpath attribute may only " +                                                 . "be specified for " +                                                 . "filesets that specify a " +                                                 . "single file."); +                    } +                    // FIXME  +                    // Current model is only adding directories implicitly.  This +                    // won't add any empty directories.  Perhaps modify TarFileSet::getFiles() +                    // to also include empty directories.  Not high priority, since non-inclusion +                    // of empty dirs is probably not unexpected behavior for TarTask. +                    $fsBasedir = $fs->getDir($this->project); +                    $filesToTar = array(); +                    for ($i=0, $fcount=count($files); $i < $fcount; $i++) { +                        $f = new PhingFile($fsBasedir, $files[$i]); +                        $filesToTar[] = $f->getAbsolutePath();                         +                    }                     +                    $tar->addModify($filesToTar, '', $fsBasedir->getAbsolutePath());             +            } +                          +                 +        } catch (IOException $ioe) { +                $msg = "Problem creating TAR: " . $ioe->getMessage(); +                $this->filesets = $savedFileSets; +                throw new BuildException($msg, $ioe, $this->getLocation()); +        } +         +        $this->filesets = $savedFileSets; +    } +            +    /** +     * @param array $files array of filenames +     * @param PhingFile $dir +     * @return boolean +     */ +    protected function archiveIsUpToDate($files, $dir) { +        $sfs = new SourceFileScanner($this); +        $mm = new MergeMapper(); +        $mm->setTo($this->tarFile->getAbsolutePath()); +        return count($sfs->restrict($files, $dir, null, $mm)) == 0; +    } +    +} + + +/** + * This is a FileSet with the option to specify permissions. + *  + * Permissions are currently not implemented by PEAR Archive_Tar, + * but hopefully they will be in the future. + *  + */ +class TarFileSet extends FileSet { + +    private $files = null; + +    private $mode = 0100644; + +    private $userName = ""; +    private $groupName = ""; +    private $prefix = ""; +    private $fullpath = ""; +    private $preserveLeadingSlashes = false; + +    /** +     *  Get a list of files and directories specified in the fileset. +     *  @return array a list of file and directory names, relative to +     *    the baseDir for the project. +     */ +    public function getFiles(Project $p) { +        if ($this->files === null) { +            $ds = $this->getDirectoryScanner($p); +            $this->files = $ds->getIncludedFiles(); +        } +        return $this->files; +    } + +    /** +     * A 3 digit octal string, specify the user, group and  +     * other modes in the standard Unix fashion;  +     * optional, default=0644 +     * @param string $octalString +     */ +    public function setMode($octalString) { +        $octal = (int) $octalString; +        $this->mode = 0100000 | $octal; +    } + +    public function getMode() { +        return $this->mode; +    } + +    /** +     * The username for the tar entry  +     * This is not the same as the UID, which is +     * not currently set by the task. +     */ +    public function setUserName($userName) { +        $this->userName = $userName; +    } + +    public function getUserName() { +        return $this->userName; +    } + +    /** +     * The groupname for the tar entry; optional, default="" +     * This is not the same as the GID, which is +     * not currently set by the task. +     */ +    public function setGroup($groupName) { +        $this->groupName = $groupName; +    } + +    public function getGroup() { +        return $this->groupName; +    } + +    /** +     * If the prefix attribute is set, all files in the fileset +     * are prefixed with that path in the archive. +     * optional. +     */ +    public function setPrefix($prefix) { +        $this->prefix = $prefix; +    } + +    public function getPrefix() { +        return $this->prefix; +    } + +    /** +     * If the fullpath attribute is set, the file in the fileset +     * is written with that path in the archive. The prefix attribute, +     * if specified, is ignored. It is an error to have more than one file specified in +     * such a fileset. +     */ +    public function setFullpath($fullpath) { +        $this->fullpath = $fullpath; +    } + +    public function getFullpath() { +        return $this->fullpath; +    } + +    /** +     * Flag to indicates whether leading `/'s should +     * be preserved in the file names. +     * Optional, default is <code>false</code>. +     * @return void +     */ +    public function setPreserveLeadingSlashes($b) { +        $this->preserveLeadingSlashes = (boolean) $b; +    } + +    public function getPreserveLeadingSlashes() { +        return $this->preserveLeadingSlashes; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php b/buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php new file mode 100644 index 00000000..866e954d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php @@ -0,0 +1,116 @@ +<?php +require_once 'phing/Task.php'; + +/** + * A XML lint task. Checking syntax of one or more XML files against an XML Schema using the DOM extension. + * + * @author   Knut Urdalen <knut.urdalen@telio.no> + * @package  phing.tasks.ext + */ +class XmlLintTask extends Task { + +  protected $file;  // the source file (from xml attribute) +  protected $schema; // the schema file (from xml attribute) +  protected $filesets = array(); // all fileset objects assigned to this task + +  /** +   * File to be performed syntax check on +   * +   * @param PhingFile $file +   */ +  public function setFile(PhingFile $file) { +    $this->file = $file; +  } + +  /** +   * XML Schema Description file to validate against +   * +   * @param PhingFile $schema +   */ +  public function setSchema(PhingFile $schema) { +    $this->schema = $schema; +  } +   +  /** +   * Nested creator, creates a FileSet for this task +   * +   * @return FileSet The created fileset object +   */ +  function createFileSet() { +    $num = array_push($this->filesets, new FileSet()); +    return $this->filesets[$num-1]; +  } + +  /** +   * Execute lint check against PhingFile or a FileSet +   */ +  public function main() { +    if(!isset($this->schema)) { +      throw new BuildException("Missing attribute 'schema'"); +    } +    $schema = $this->schema->getPath(); +    if(!file_exists($schema)) { +      throw new BuildException("File not found: ".$schema); +    } +    if(!isset($this->file) and count($this->filesets) == 0) { +      throw new BuildException("Missing either a nested fileset or attribute 'file' set"); +    } + +    set_error_handler(array($this, 'errorHandler')); +    if($this->file instanceof PhingFile) { +      $this->lint($this->file->getPath()); +    } else { // process filesets +      $project = $this->getProject(); +      foreach($this->filesets as $fs) { +	$ds = $fs->getDirectoryScanner($project); +	$files = $ds->getIncludedFiles(); +	$dir = $fs->getDir($this->project)->getPath(); +	foreach($files as $file) { +	  $this->lint($dir.DIRECTORY_SEPARATOR.$file); +	} +      } +    } +    restore_error_handler(); +  } + +  /** +   * Performs validation +   * +   * @param string $file +   * @return void +   */ +  protected function lint($file) { +    if(file_exists($file)) { +      if(is_readable($file)) { +	$dom = new DOMDocument(); +	$dom->load($file); +	if($dom->schemaValidate($this->schema->getPath())) { +	  $this->log($file.' validated', PROJECT_MSG_INFO); +	} else { +	  $this->log($file.' fails to validate (See messages above)', PROJECT_MSG_ERR); +	} +      } else { +	throw new BuildException('Permission denied: '.$file); +      } +    } else { +      throw new BuildException('File not found: '.$file); +    } +  } + +  /** +   * Local error handler to catch validation errors and log them through Phing +   * +   * @param int    $level +   * @param string $message +   * @param string $file +   * @param int    $line +   */ +  public function errorHandler($level, $message, $file, $line, $context) { +    $matches = array(); +    preg_match('/^.*\(\): (.*)$/', $message, $matches); +    $this->log($matches[1], PROJECT_MSG_ERR); +  } + +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php b/buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php new file mode 100644 index 00000000..490ee797 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php @@ -0,0 +1,163 @@ +<?php +require_once 'phing/Task.php'; + +/** + * ZendCodeAnalyzerTask analyze PHP source code using the ZendCodeAnalyzer included in Zend Studio 5.1 + *  + * Available warnings: + * <b>zend-error</b> - %s(line %d): %s + * <b>oneline-comment</b> - One-line comment ends with ?> tag. + * <b>bool-assign</b> - Assignment seen where boolean expression is expected. Did you mean '==' instead of '='? + * <b>bool-print</b> - Print statement used when boolean expression is expected. + * <b>bool-array</b> - Array used when boolean expression is expected. + * <b>bool-object</b> - Object used when boolean expression is expected. + * <b>call-time-ref</b> - Call-time reference is deprecated. Define function as accepting parameter by reference instead. + * <b>if-if-else</b> - In if-if-else construction else relates to the closest if. Use braces to make the code clearer. + * <b>define-params</b> - define() requires two or three parameters. + * <b>define-const</b> - First parameter for define() should be string. Maybe you forgot quotes? + * <b>break-var</b> - Break/continue with variable is dangerous - break level can be out of scope. + * <b>break-depth</b> - Break/continue with depth more than current nesting level. + * <b>var-once</b> - Variable '%s' encountered only once. May be a typo? + * <b>var-arg-unused</b> - Function argument '%s' is never used. + * <b>var-global-unused</b> - Global variable '%s' is defined but never used. + * <b>var-use-before-def</b> - Variable '%s' is used before it was assigned. + * <b>var-use-before-def-global</b> - Global variable '%s' is used without being assigned. You are probably relying on register_globals feature of PHP. Note that this feature is off by default. + * <b>var-no-global</b> - PHP global variable '%s' is used as local. Maybe you wanted to define '%s' as global? + * <b>var-value-unused</b> - Value assigned to variable '%s' is never used + * <b>var-ref-notmodified</b> - Function parameter '%s' is passed by reference but never modified. Consider passing by value. + * <b>return-empty-val</b> - Function '%s' has both empty return and return with value. + * <b>return-empty-used</b> - Function '%s' has empty return but return value is used. + * <b>return-noref</b> - Function '%s' returns reference but the value is not assigned by reference. Maybe you meant '=&' instead of '='? + * <b>return-end-used</b> - Control reaches the end of function '%s'(file %s, line %d) but return value is used. + * <b>sprintf-miss-args</b> - Missing arguments for sprintf: format reqires %d arguments but %d are supplied. + * <b>sprintf-extra-args</b> - Extra arguments for sprintf: format reqires %d arguments but %d are supplied. + * <b>unreach-code</b> - Unreachable code in function '%s'. + * <b>include-var</b> - include/require with user-accessible variable can be dangerous. Consider using constant instead. + * <b>non-object</b> - Variable '%s' used as object, but has different type. + * <b>bad-escape</b> - Bad escape sequence: \%c, did you mean \\%c? + * <b>empty-cond</b> - Condition without a body + * <b>expr-unused</b> - Expression result is never used + * + * @author   Knut Urdalen <knut.urdalen@telio.no> + * @package  phing.tasks.ext + */ +class ZendCodeAnalyzerTask extends Task { +   +  protected $analyzerPath = ""; // Path to ZendCodeAnalyzer binary +  protected $file = "";  // the source file (from xml attribute) +  protected $filesets = array(); // all fileset objects assigned to this task +  protected $warnings = array(); +  protected $counter = 0; +  protected $disable = array(); +  protected $enable = array(); +   +  /** +   * File to be analyzed +   *  +   * @param PhingFile $file +   */ +  public function setFile(PhingFile $file) { +    $this->file = $file; +  } +   +  /** +   * Path to ZendCodeAnalyzer binary +   * +   * @param string $analyzerPath +   */ +  public function setAnalyzerPath($analyzerPath) { +    $this->analyzerPath = $analyzerPath; +  } +   +  /** +   * Disable warning levels. Seperate warning levels with ',' +   * +   * @param string $disable +   */ +  public function setDisable($disable) { +    $this->disable = explode(",", $disable); +  } +   +  /** +   * Enable warning levels. Seperate warning levels with ',' +   * +   * @param string $enable +   */ +  public function setEnable($enable) { +    $this->enable = explode(",", $enable); +  } +   +  /** +   * Nested creator, creates a FileSet for this task +   * +   * @return FileSet The created fileset object +   */ +  function createFileSet() { +    $num = array_push($this->filesets, new FileSet()); +    return $this->filesets[$num-1]; +  } + +  /** +   * Analyze against PhingFile or a FileSet +   */ +  public function main() { +    if(!isset($this->analyzerPath)) { +      throw new BuildException("Missing attribute 'analyzerPath'"); +    } +    if(!isset($this->file) and count($this->filesets) == 0) { +      throw new BuildException("Missing either a nested fileset or attribute 'file' set"); +    } +     +    if($this->file instanceof PhingFile) { +      $this->analyze($this->file->getPath()); +    } else { // process filesets +      $project = $this->getProject(); +      foreach($this->filesets as $fs) { +      	$ds = $fs->getDirectoryScanner($project); +      	$files = $ds->getIncludedFiles(); +      	$dir = $fs->getDir($this->project)->getPath(); +      	foreach($files as $file) { +	  $this->analyze($dir.DIRECTORY_SEPARATOR.$file); +      	} +      } +    } +    $this->log("Number of findings: ".$this->counter, PROJECT_MSG_INFO); +  } + +  /** +   * Analyze file +   * +   * @param string $file +   * @return void +   */ +  protected function analyze($file) { +    if(file_exists($file)) { +      if(is_readable($file)) { +      	 +      	// Construct shell command +      	$cmd = $this->analyzerPath." "; +      	foreach($this->enable as $enable) { // Enable warning levels +      		$cmd .= " --enable $enable "; +      	} +      	foreach($this->disable as $disable) { // Disable warning levels +      		$cmd .= " --disable $disable "; +      	} +      	$cmd .= "$file 2>&1"; +      	 +      	// Execute command +      	$result = shell_exec($cmd); +      	$result = explode("\n", $result); +      	for($i=2, $size=count($result); $i<($size-1); $i++) { +	  $this->counter++; +	  $this->log($result[$i], PROJECT_MSG_WARN); +      	} +      } else { +      	throw new BuildException('Permission denied: '.$file); +      } +    } else { +      throw new BuildException('File not found: '.$file); +    } +  } +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php new file mode 100644 index 00000000..33ef16ae --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php @@ -0,0 +1,176 @@ +<?php +/* + *  $Id: ZipTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/MergeMapper.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/lib/Zip.php'; + +/** + * Creates a zip archive using PEAR Archive_Zip (which is presently unreleased + * and included with Phing). + * + * @author    Michiel Rook <michiel@trendserver.nl> + * @version   $Revision: 1.2 $ + * @package   phing.tasks.ext + * @since     2.1.0 + */ +class ZipTask extends MatchingTask { +     +    private $zipFile; +    private $baseDir; + +    private $filesets = array(); +    private $fileSetFiles = array(); + +    /** +     * Add a new fileset. +     * @return FileSet +     */ +    public function createFileSet() { +        $this->fileset = new FileSet(); +        $this->filesets[] = $this->fileset; +        return $this->fileset; +    } + +    /** +     * Set is the name/location of where to create the zip file. +     * @param PhingFile $destFile The output of the zip +     */ +    public function setDestFile(PhingFile $destFile) { +        $this->zipFile = $destFile; +    } + +    /** +     * This is the base directory to look in for things to zip. +     * @param PhingFile $baseDir +     */ +    public function setBasedir(PhingFile $baseDir) { +        $this->baseDir = $baseDir; +    } + +    /** +     * do the work +     * @throws BuildException +     */ +    public function main() { +     +        if ($this->zipFile === null) { +            throw new BuildException("zipfile attribute must be set!", $this->getLocation()); +        } + +        if ($this->zipFile->exists() && $this->zipFile->isDirectory()) { +            throw new BuildException("zipfile is a directory!", $this->getLocation()); +        } + +        if ($this->zipFile->exists() && !$this->zipFile->canWrite()) { +            throw new BuildException("Can not write to the specified zipfile!", $this->getLocation()); +        } + +        // shouldn't need to clone, since the entries in filesets +        // themselves won't be modified -- only elements will be added +        $savedFileSets = $this->filesets; +         +        try { +            if ($this->baseDir !== null) { +                if (!$this->baseDir->exists()) { +                    throw new BuildException("basedir does not exist!", $this->getLocation()); +                } + +                // add the main fileset to the list of filesets to process. +                $mainFileSet = new FileSet($this->fileset); +                $mainFileSet->setDir($this->baseDir); +                $this->filesets[] = $mainFileSet; +            } + +            if (empty($this->filesets)) { +                throw new BuildException("You must supply either a basedir " +                                         . "attribute or some nested filesets.", +                                         $this->getLocation()); +            }                         +             +            // check if zip is out of date with respect to each +            // fileset +            $upToDate = true; +            foreach($this->filesets as $fs) { +            	$ds = $fs->getDirectoryScanner($this->project); +            	$files = $ds->getIncludedFiles(); +                if (!$this->archiveIsUpToDate($files, $fs->getDir($this->project))) { +                    $upToDate = false; +                } +                for ($i=0, $fcount=count($files); $i < $fcount; $i++) { +                    if ($this->zipFile->equals(new PhingFile($fs->getDir($this->project), $files[$i]))) { +                        throw new BuildException("A zip file cannot include itself", $this->getLocation()); +                    } +                } +            } +             +            if ($upToDate) { +                $this->log("Nothing to do: " . $this->zipFile->__toString() . " is up to date.", PROJECT_MSG_INFO); +                return; +            } + +            $this->log("Building zip: " . $this->zipFile->__toString(), PROJECT_MSG_INFO); +             +            $zip = new Archive_Zip($this->zipFile->getAbsolutePath()); +             +            foreach($this->filesets as $fs) {                                 +            	$ds = $fs->getDirectoryScanner($this->project); +            	$files = $ds->getIncludedFiles(); + +                // FIXME  +                // Current model is only adding directories implicitly.  This +                // won't add any empty directories.  Perhaps modify FileSet::getFiles() +                // to also include empty directories.  Not high priority, since non-inclusion +                // of empty dirs is probably not unexpected behavior for ZipTask. +                $fsBasedir = $fs->getDir($this->project); +                $filesToZip = array(); +                for ($i=0, $fcount=count($files); $i < $fcount; $i++) { +                    $f = new PhingFile($fsBasedir, $files[$i]); +                    $filesToZip[] = $f->getAbsolutePath();                         +                }                     +                $zip->add($filesToZip, array('remove_path' => $fsBasedir->getPath())); +            } +                          +                 +        } catch (IOException $ioe) { +                $msg = "Problem creating ZIP: " . $ioe->getMessage(); +                $this->filesets = $savedFileSets; +                throw new BuildException($msg, $ioe, $this->getLocation()); +        } +         +        $this->filesets = $savedFileSets; +    } +            +    /** +     * @param array $files array of filenames +     * @param PhingFile $dir +     * @return boolean +     */ +    protected function archiveIsUpToDate($files, $dir) { +        $sfs = new SourceFileScanner($this); +        $mm = new MergeMapper(); +        $mm->setTo($this->zipFile->getAbsolutePath()); +        return count($sfs->restrict($files, $dir, null, $mm)) == 0; +    } +    +} diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php new file mode 100644 index 00000000..99bcc7c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php @@ -0,0 +1,127 @@ +<?php +/** + * $Id: CoverageMerger.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/system/util/Properties.php'; + +/** + * Saves coverage output of the test to a specified database + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: CoverageMerger.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageMerger +{ +	private static function mergeCodeCoverage($left, $right) +	{ +		$coverageMerged = array(); + +		reset($left); +		reset($right); + +		while (current($left) && current($right)) +		{ +			$linenr_left = key($left); +			$linenr_right = key($right); + +			if ($linenr_left < $linenr_right) +			{ +				$coverageMerged[$linenr_left] = current($left); + +				next($left); +			} +			else +			if ($linenr_right < $linenr_left) +			{ +				$coverageMerged[$linenr_right] = current($right); +				next($right); +			} +			else +			{ +				if (current($left) < 0) +				{ +					$coverageMerged[$linenr_right] = current($right); +				} +				else +				if (current($right) < 0) +				{ +					$coverageMerged[$linenr_right] = current($left); +				} +				else +				{ +					$coverageMerged[$linenr_right] = current($left) + current($right); +				} +				 +				next($left); +				next($right); +			} +		} + +		while (current($left)) +		{ +			$coverageMerged[key($left)] = current($left); +			next($left); +		} + +		while (current($right)) +		{ +			$coverageMerged[key($right)] = current($right); +			next($right); +		} + +		return $coverageMerged; +	} + +	static function merge($project, $codeCoverageInformation) +	{ +		$database = new PhingFile($project->getProperty('coverage.database')); + +		$props = new Properties(); +		$props->load($database); +		 +		$coverageTotal = $codeCoverageInformation; +		 +		foreach ($coverageTotal as $coverage) +		{ +			foreach ($coverage as $filename => $coverageFile) +			{ +				$filename = strtolower($filename); +				 +				if ($props->getProperty($filename) != null) +				{ +					$file = unserialize($props->getProperty($filename)); +					$left = $file['coverage']; +					$right = $coverageFile; +					 +					$coverageMerged = CoverageMerger::mergeCodeCoverage($left, $right); +					 +					$file['coverage'] = $coverageMerged; +					 +					$props->setProperty($filename, serialize($file)); +				} +			} +		} + +		$props->store($database); +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php new file mode 100644 index 00000000..4a78df6f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php @@ -0,0 +1,92 @@ +<?php +/** + * $Id: CoverageMergerTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +/** + * Merges code coverage snippets into a code coverage database + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: CoverageMergerTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageMergerTask extends Task +{ +	/** the list of filesets containing the .php filename rules */ +	private $filesets = array(); + +	/** +	 * Add a new fileset containing the .php files to process +	 * +	 * @param FileSet the new fileset containing .php files +	 */ +	function addFileSet(FileSet $fileset) +	{ +		$this->filesets[] = $fileset; +	} + +	/** +	 * Iterate over all filesets and return all the filenames. +	 * +	 * @return array an array of filenames +	 */ +	private function getFilenames() +	{ +		$files = array(); + +		foreach ($this->filesets as $fileset) +		{ +			$ds = $fileset->getDirectoryScanner($this->project); +			$ds->scan(); + +			$includedFiles = $ds->getIncludedFiles(); +			 +			foreach ($includedFiles as $file) +			{ +				$fs = new PhingFile(basename($ds->getBaseDir()), $file); +					 +				$files[] = $fs->getAbsolutePath(); +			} +		} + +		return $files; +	} +	 +	function main() +	{ +		$files = $this->getFilenames(); +		 +		$this->log("Merging " . count($files) . " coverage files"); + +		foreach ($files as $file) +		{ +			$coverageInformation = unserialize(file_get_contents($file)); +			 +			CoverageMerger::merge($this->project, array($coverageInformation)); +		} +	} +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php new file mode 100644 index 00000000..72fa57a7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php @@ -0,0 +1,406 @@ +<?php +/** + * $Id: CoverageReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/phpunit2/PHPUnit2Util.php'; +require_once 'phing/tasks/ext/coverage/CoverageReportTransformer.php'; + +/** + * Transforms information in a code coverage database to XML + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: CoverageReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageReportTask extends Task +{ +	private $outfile = "coverage.xml"; + +	private $transformers = array(); + +	/** the classpath to use (optional) */ +	private $classpath = NULL; +	 +	/** the path to the GeSHi library (optional) */ +	private $geshipath = ""; +	 +	/** the path to the GeSHi language files (optional) */ +	private $geshilanguagespath = ""; +	 +	function setClasspath(Path $classpath) +	{ +		if ($this->classpath === null) +		{ +			$this->classpath = $classpath; +		} +		else +		{ +			$this->classpath->append($classpath); +		} +	} + +	function createClasspath() +	{ +		$this->classpath = new Path(); +		return $this->classpath; +	} +	 +	function setGeshiPath($path) +	{ +		$this->geshipath = $path; +	} + +	function setGeshiLanguagesPath($path) +	{ +		$this->geshilanguagespath = $path; +	} + +	function __construct() +	{ +		$this->doc = new DOMDocument(); +		$this->doc->encoding = 'UTF-8'; +		$this->doc->formatOutput = true; +		$this->doc->appendChild($this->doc->createElement('snapshot')); +	} + +	function setOutfile($outfile) +	{ +		$this->outfile = $outfile; +	} + +	/** +	 * Generate a report based on the XML created by this task +	 */ +	function createReport() +	{ +		$transformer = new CoverageReportTransformer($this); +		$this->transformers[] = $transformer; +		return $transformer; +	} + +	protected function getPackageElement($packageName) +	{ +		$packages = $this->doc->documentElement->getElementsByTagName('package'); + +		foreach ($packages as $package) +		{ +			if ($package->getAttribute('name') == $packageName) +			{ +				return $package; +			} +		} + +		return NULL; +	} + +	protected function addClassToPackage($classname, $element) +	{ +		$packageName = PHPUnit2Util::getPackageName($classname); + +		$package = $this->getPackageElement($packageName); + +		if ($package === NULL) +		{ +			$package = $this->doc->createElement('package'); +			$package->setAttribute('name', $packageName); +			$this->doc->documentElement->appendChild($package); +		} + +		$package->appendChild($element); +	} + +	protected function stripDiv($source) +	{ +		$openpos = strpos($source, "<div"); +		$closepos = strpos($source, ">", $openpos); + +		$line = substr($source, $closepos + 1); + +		$tagclosepos = strpos($line, "</div>"); + +		$line = substr($line, 0, $tagclosepos); + +		return $line; +	} + +	protected function highlightSourceFile($filename) +	{ +		if ($this->geshipath) +		{ +			require_once $this->geshipath . '/geshi.php'; +			 +			$source = file_get_contents($filename); + +			$geshi = new GeSHi($source, 'php', $this->geshilanguagespath); + +			$geshi->enable_line_numbers(GESHI_NORMAL_LINE_NUMBERS); + +			$geshi->enable_strict_mode(true); + +			$geshi->enable_classes(true); + +			$geshi->set_url_for_keyword_group(3, '');  + +			$html = $geshi->parse_code(); + +			$lines = split("<li>|</li>", $html); + +			// skip first and last line +			array_pop($lines); +			array_shift($lines); + +			$lines = array_filter($lines); + +			$lines = array_map(array($this, 'stripDiv'), $lines); + +			return $lines; +		} +		else +		{ +			$lines = file($filename); +			 +			for ($i = 0; $i < count($lines); $i++) +			{ +				$line = $lines[$i]; +				 +				$line = rtrim($line); + +				$lines[$i] = utf8_encode($line); +			} +			 +			return $lines; +		} +	} + +	protected function transformSourceFile($filename, $coverageInformation, $classStartLine = 1) +	{ +		$sourceElement = $this->doc->createElement('sourcefile'); +		$sourceElement->setAttribute('name', basename($filename)); + +		$filelines = $this->highlightSourceFile($filename); + +		$linenr = 1; + +		foreach ($filelines as $line) +		{ +			$lineElement = $this->doc->createElement('sourceline'); +			$lineElement->setAttribute('coveredcount', (isset($coverageInformation[$linenr]) ? $coverageInformation[$linenr] : '0')); + +			if ($linenr == $classStartLine) +			{ +				$lineElement->setAttribute('startclass', 1); +			} + +			$textnode = $this->doc->createTextNode($line); +			$lineElement->appendChild($textnode); + +			$sourceElement->appendChild($lineElement); + +			$linenr++; +		} + +		return $sourceElement; +	} +	 +	protected function filterCovered($var) +	{ +		return ($var >= 0); +	} + +	protected function transformCoverageInformation($filename, $coverageInformation) +	{ +		$classes = PHPUnit2Util::getDefinedClasses($filename, $this->classpath); +		 +		if (is_array($classes)) +		{ +			foreach ($classes as $classname) +			{ +				$reflection = new ReflectionClass($classname); +				 +				$methods = $reflection->getMethods(); +				 +				$classElement = $this->doc->createElement('class'); +				$classElement->setAttribute('name', $reflection->getName()); +				 +				$this->addClassToPackage($reflection->getName(), $classElement); + +				$classStartLine = $reflection->getStartLine(); +				 +				$methodscovered = 0; +				$methodcount = 0; +				 +				end($coverageInformation); +				unset($coverageInformation[key($coverageInformation)]); +				 +				// Strange PHP5 reflection bug, classes without parent class or implemented interfaces seem to start one line off +				if ($reflection->getParentClass() == NULL && count($reflection->getInterfaces()) == 0) +				{ +					unset($coverageInformation[$classStartLine + 1]); +				} +				else +				{ +					unset($coverageInformation[$classStartLine]); +				} +				 +				reset($coverageInformation);				 +				 +				foreach ($methods as $method) +				{ +					// PHP5 reflection considers methods of a parent class to be part of a subclass, we don't +					if ($method->getDeclaringClass()->getName() != $reflection->getName()) +					{ +						continue; +					} + +					// small fix for XDEBUG_CC_UNUSED +					if (isset($coverageInformation[$method->getStartLine()])) +					{ +						unset($coverageInformation[$method->getStartLine()]); +					} + +					if (isset($coverageInformation[$method->getEndLine()])) +					{ +						unset($coverageInformation[$method->getEndLine()]); +					} + +					if ($method->isAbstract()) +					{ +						continue; +					} + +					$linenr = key($coverageInformation); + +					while ($linenr < $method->getStartLine()) +					{ +						next($coverageInformation); +						$linenr = key($coverageInformation); +					} + +					if (current($coverageInformation) > 0 && $method->getStartLine() <= $linenr && $linenr <= $method->getEndLine()) +					{ +						$methodscovered++; +					} + +					$methodcount++; +				} + +				$statementcount = count($coverageInformation); +				$statementscovered = count(array_filter($coverageInformation, array($this, 'filterCovered'))); + +				$classElement->appendChild($this->transformSourceFile($filename, $coverageInformation, $classStartLine)); + +				$classElement->setAttribute('methodcount', $methodcount); +				$classElement->setAttribute('methodscovered', $methodscovered); +				$classElement->setAttribute('statementcount', $statementcount); +				$classElement->setAttribute('statementscovered', $statementscovered); +				$classElement->setAttribute('totalcount', $methodcount + $statementcount); +				$classElement->setAttribute('totalcovered', $methodscovered + $statementscovered); +			} +		} +	} + +	protected function calculateStatistics() +	{ +		$packages = $this->doc->documentElement->getElementsByTagName('package'); + +		$totalmethodcount = 0; +		$totalmethodscovered = 0; + +		$totalstatementcount = 0; +		$totalstatementscovered = 0; + +		foreach ($packages as $package) +		{ +			$methodcount = 0; +			$methodscovered = 0; + +			$statementcount = 0; +			$statementscovered = 0; + +			$classes = $package->getElementsByTagName('class'); + +			foreach ($classes as $class) +			{ +				$methodcount += $class->getAttribute('methodcount'); +				$methodscovered += $class->getAttribute('methodscovered'); + +				$statementcount += $class->getAttribute('statementcount'); +				$statementscovered += $class->getAttribute('statementscovered'); +			} + +			$package->setAttribute('methodcount', $methodcount); +			$package->setAttribute('methodscovered', $methodscovered); + +			$package->setAttribute('statementcount', $statementcount); +			$package->setAttribute('statementscovered', $statementscovered); + +			$package->setAttribute('totalcount', $methodcount + $statementcount); +			$package->setAttribute('totalcovered', $methodscovered + $statementscovered); + +			$totalmethodcount += $methodcount; +			$totalmethodscovered += $methodscovered; + +			$totalstatementcount += $statementcount; +			$totalstatementscovered += $statementscovered; +		} + +		$this->doc->documentElement->setAttribute('methodcount', $totalmethodcount); +		$this->doc->documentElement->setAttribute('methodscovered', $totalmethodscovered); + +		$this->doc->documentElement->setAttribute('statementcount', $totalstatementcount); +		$this->doc->documentElement->setAttribute('statementscovered', $totalstatementscovered); + +		$this->doc->documentElement->setAttribute('totalcount', $totalmethodcount + $totalstatementcount); +		$this->doc->documentElement->setAttribute('totalcovered', $totalmethodscovered + $totalstatementscovered); +	} + +	function main() +	{ +		$this->log("Transforming coverage report"); +		 +		$database = new PhingFile($this->project->getProperty('coverage.database')); +		 +		$props = new Properties(); +		$props->load($database); + +		foreach ($props->keys() as $filename) +		{ +			$file = unserialize($props->getProperty($filename)); + +			$this->transformCoverageInformation($file['fullname'], $file['coverage']); +		} +		 +		$this->calculateStatistics(); + +		$this->doc->save($this->outfile); + +		foreach ($this->transformers as $transformer) +		{ +			$transformer->setXmlDocument($this->doc); +			$transformer->transform(); +		} +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php new file mode 100644 index 00000000..b7fee32f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php @@ -0,0 +1,121 @@ +<?php +/** + * $Id: CoverageReportTransformer.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/FileWriter.php'; +require_once 'phing/util/ExtendedFileStream.php'; + +/** + * Transform a Phing/Xdebug code coverage xml report. + * The default transformation generates an html report in framed style. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: CoverageReportTransformer.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageReportTransformer +{ +	private $task = NULL; +	private $styleDir = ""; +	private $toDir = ""; +	private $document = NULL; + +	function __construct(Task $task) +	{ +		$this->task = $task; +	} + +	function setStyleDir($styleDir) +	{ +		$this->styleDir = $styleDir; +	} + +	function setToDir($toDir) +	{ +		$this->toDir = $toDir; +	} + +	function setXmlDocument($document) +	{ +		$this->document = $document; +	} + +	function transform() +	{ +        $dir = new PhingFile($this->toDir); + +        if (!$dir->exists()) +        { +            throw new BuildException("Directory '" . $this->toDir . "' does not exist"); +        } + +		$xslfile = $this->getStyleSheet(); + +		$xsl = new DOMDocument(); +		$xsl->load($xslfile->getAbsolutePath()); + +		$proc = new XSLTProcessor(); +		$proc->importStyleSheet($xsl); + +		ExtendedFileStream::registerStream(); + +		// no output for the framed report +		// it's all done by extension... +		$proc->setParameter('', 'output.dir', $dir->getAbsolutePath()); +		$proc->transformToXML($this->document); +	} + +	private function getStyleSheet() +	{ +		$xslname = "coverage-frames.xsl"; + +		if ($this->styleDir) +		{ +			$file = new PhingFile($this->styleDir, $xslname); +		} +		else +		{ +			$path = Phing::getResourcePath("phing/etc/$xslname"); +			 +			if ($path === NULL) +			{ +				$path = Phing::getResourcePath("etc/$xslname"); + +				if ($path === NULL) +				{ +					throw new BuildException("Could not find $xslname in resource path"); +				} +			} +			 +			$file = new PhingFile($path); +		} + +		if (!$file->exists()) +		{ +			throw new BuildException("Could not find file " . $file->getPath()); +		} + +		return $file; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php new file mode 100644 index 00000000..058b891b --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php @@ -0,0 +1,163 @@ +<?php +/** + * $Id: CoverageSetupTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/system/util/Properties.php'; +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +/** + * Initializes a code coverage database + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: CoverageSetupTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.coverage + * @since 2.1.0 + */ +class CoverageSetupTask extends Task +{ +	/** the list of filesets containing the .php filename rules */ +	private $filesets = array(); + +	/** the filename of the coverage database */ +	private $database = "coverage.db"; + +	/** the classpath to use (optional) */ +	private $classpath = NULL; + +	/** +	 * Add a new fileset containing the .php files to process +	 * +	 * @param FileSet the new fileset containing .php files +	 */ +	function addFileSet(FileSet $fileset) +	{ +		$this->filesets[] = $fileset; +	} + +	/** +	 * Sets the filename of the coverage database to use +	 * +	 * @param string the filename of the database +	 */ +	function setDatabase($database) +	{ +		$this->database = $database; +	} + +	function setClasspath(Path $classpath) +	{ +		if ($this->classpath === null) +		{ +			$this->classpath = $classpath; +		} +		else +		{ +			$this->classpath->append($classpath); +		} +	} + +	function createClasspath() +	{ +		$this->classpath = new Path(); +		return $this->classpath; +	} +	 +	/** +	 * Iterate over all filesets and return the filename of all files +	 * that end with .php. This is to avoid loading an xml file +	 * for example. +	 * +	 * @return array an array of (basedir, filenames) pairs +	 */ +	private function getFilenames() +	{ +		$files = array(); + +		foreach ($this->filesets as $fileset) +		{ +			$ds = $fileset->getDirectoryScanner($this->project); +			$ds->scan(); + +			$includedFiles = $ds->getIncludedFiles(); + +			foreach ($includedFiles as $file) +			{ +				if (strstr($file, ".php")) +				{ +					$fs = new PhingFile(realpath($ds->getBaseDir()), $file); +					 +					$files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath()); +				} +			} +		} + +		return $files; +	} +	 +	function init() +	{ +		include_once 'PHPUnit2/Framework/TestCase.php'; +		if (!class_exists('PHPUnit2_Framework_TestCase')) { +			throw new Exception("PHPUnit2Task depends on PEAR PHPUnit2 package being installed."); +		} +	} + +	function main() +	{ +		$files = $this->getFilenames(); + +		$this->log("Setting up coverage database for " . count($files) . " files"); + +		$props = new Properties(); + +		foreach ($files as $file) +		{ +			$fullname = $file['fullname']; +			$filename = $file['key']; +			 +			$props->setProperty($filename, serialize(array('fullname' => $fullname, 'coverage' => array()))); +		} + +		$dbfile = new PhingFile($this->database); + +		$props->store($dbfile); + +		$this->project->setProperty('coverage.database', $dbfile->getAbsolutePath()); +	 +		foreach ($files as $file) +		{ +			$fullname = $file['fullname']; +			 +			xdebug_start_code_coverage(XDEBUG_CC_UNUSED); +			 +			Phing::__import($fullname, $this->classpath); +			 +			$coverage = xdebug_get_code_coverage(); +			 +			xdebug_stop_code_coverage(); +			 +			CoverageMerger::merge($this->project, array($coverage)); +		} +	} +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php new file mode 100644 index 00000000..99434aaa --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php @@ -0,0 +1,44 @@ +<?php
 +/**
 + * $Id: IoncubeComment.php 59 2006-04-28 14:49:47Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +/**
 + * Wrapper for comments for ionCube tasks
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: IoncubeComment.php 59 2006-04-28 14:49:47Z mrook $
 + * @package phing.tasks.ext.ioncube
 + * @since 2.2.0
 + */
 +class IoncubeComment
 +{
 +	private $value = "";
 +	
 +	public function getValue()
 +	{
 +		return $this->value;
 +	}
 +	
 +	public function addText($txt)
 +	{
 +		$this->value = trim($txt);
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php new file mode 100644 index 00000000..9eecd5a0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php @@ -0,0 +1,336 @@ +<?php +/** + * $Id: IoncubeEncoderTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/ioncube/IoncubeComment.php'; + +/** + * Invokes the ionCube Encoder (PHP4 or PHP5) + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: IoncubeEncoderTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.ioncube + * @since 2.2.0 + */ +class IoncubeEncoderTask extends Task +{ +	private $phpVersion = "5"; +	private $ioncubePath = "/usr/local/ioncube"; +	private $encoderName = "ioncube_encoder"; +	 +	private $fromDir = ""; +	private $toDir = ""; +	 +	private $encrypt = ""; +	 +	private $targetOption = ""; +	private $binary = false; +	private $optimize = ""; +	private $withoutRuntimeLoaderSupport = false; +	 +	private $licensePath = ""; +	private $passPhrase = ""; +	 +	private $comments = array(); + +	/** +	 * Sets the path to the ionCube encoder +	 */ +	function setIoncubePath($ioncubePath) +	{ +		$this->ioncubePath = $ioncubePath; +	} + +	/** +	 * Returns the path to the ionCube encoder +	 */ +	function getIoncubePath() +	{ +		return $this->ioncubePath; +	} + +	/** +	 * Sets the version of PHP to use (defaults to 5) +	 */ +	function setPhpVersion($phpVersion) +	{ +		$this->phpVersion = $phpVersion; +	} + +	/** +	 * Returns the version of PHP to use (defaults to 5) +	 */ +	function getPhpVersion() +	{ +		return $this->phpVersion; +	} +	 +	/** +	 * Sets the source directory +	 */ +	function setFromDir($fromDir) +	{ +		$this->fromDir = $fromDir; +	} + +	/** +	 * Returns the source directory +	 */ +	function getFromDir($fromDir) +	{ +		return $this->fromDir; +	} +	 +	/** +	 * Sets the target directory +	 */ +	function setToDir($toDir) +	{ +		$this->toDir = $toDir; +	} + +	/** +	 * Returns the target directory +	 */ +	function getToDir($toDir) +	{ +		return $this->toDir; +	} + +	/** +	 * Sets regexps of additional files to encrypt (separated by space) +	 */ +	function setEncrypt($encrypt) +	{ +		$this->encrypt = $encrypt; +	} +	 +	/** +	 * Returns regexps of additional files to encrypt (separated by space) +	 */ +	function getEncrypt() +	{ +		return $this->encrypt; +	} +	 +	/** +	 * Sets the binary option +	 */ +	function setBinary($binary) +	{ +		$this->binary = $binary; +	} +	 +	/** +	 * Returns the binary option +	 */ +	function getBinary() +	{ +		return $this->binary; +	} + +	/** +	 * Sets the optimize option +	 */ +	function setOptimize($optimize) +	{ +		$this->optimize = $optimize; +	} +	 +	/** +	 * Returns the optimize option +	 */ +	function getOptimize() +	{ +		return $this->optimize; +	} + +	/** +	 * Sets the without-runtime-loader-support option +	 */ +	function setWithoutRuntimeLoaderSupport($withoutRuntimeLoaderSupport) +	{ +		$this->withoutRuntimeLoaderSupport = $withoutRuntimeLoaderSupport; +	} +	 +	/** +	 * Returns the without-runtime-loader-support option +	 */ +	function getWithoutRuntimeLoaderSupport() +	{ +		return $this->withoutRuntimeLoaderSupport; +	} +	 +	/** +	 * Sets the option to use when encoding target directory already exists (defaults to none) +	 */ +	function setTargetOption($targetOption) +	{ +		$this->targetOption = $targetOption; +	} + +	/** +	 * Returns he option to use when encoding target directory already exists (defaults to none) +	 */ +	function getTargetOption() +	{ +		return $this->targetOption; +	} +	 +	/** +	 * Sets the path to the license file to use +	 */ +	function setLicensePath($licensePath) +	{ +		$this->licensePath = $licensePath; +	} + +	/** +	 * Returns the path to the license file to use +	 */ +	function getLicensePath() +	{ +		return $this->licensePath; +	} + +	/** +	 * Sets the passphrase to use when encoding files +	 */ +	function setPassPhrase($passPhrase) +	{ +		$this->passPhrase = $passPhrase; +	} + +	/** +	 * Returns the passphrase to use when encoding files +	 */ +	function getPassPhrase() +	{ +		return $this->passPhrase; +	} + +	/** +	 * Adds a comment to be used in encoded files +	 */ +	function addComment(IoncubeComment $comment) +	{ +		$this->comments[] = $comment; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$arguments = $this->constructArguments(); +		 +		$encoder = new PhingFile($this->ioncubePath, $this->encoderName . ($this->phpVersion == 5 ? '5' : '')); +		 +		$this->log("Running ionCube Encoder..."); +		 +		exec($encoder->__toString() . " " . $arguments . " 2>&1", $output, $return); +		 +        if ($return != 0) +        { +			throw new BuildException("Could not execute ionCube Encoder: " . implode(' ', $output)); +        }        +	} + +	/** +	 * Constructs an argument string for the ionCube encoder +	 */ +	private function constructArguments() +	{ +		$arguments = ""; +		 +		if ($this->binary) +		{ +			$arguments.= "--binary "; +		} +		 +		if (!empty($this->optimize)) +		{ +			$arguments.= "--optimize " . $this->optimize . " "; +		} +		 +		if ($this->withoutRuntimeLoaderSupport) +		{ +			$arguments.= "--without-runtime-loader-support "; +		} +		 +		if (!empty($this->targetOption)) +		{ +			switch ($this->targetOption) +			{ +				case "replace": +				case "merge": +				case "update": +				case "rename": +				{ +					$arguments.= "--" . $this->targetOption . "-target "; +				} break; +				 +				default: +				{ +					throw new BuildException("Unknown target option '" . $this->targetOption . "'"); +				} break; +			} +		} +		 +		if (!empty($this->encrypt)) +		{ +			foreach (explode(" ", $this->encrypt) as $encrypt) +			{ +				$arguments.= "--encrypt '$encrypt' "; +			} +		} +		 +		if (!empty($this->licensePath)) +		{ +			$arguments.= "--with-license '" . $this->licensePath . "' "; +		} + +		if (!empty($this->passPhrase)) +		{ +			$arguments.= "--passphrase '" . $this->passPhrase . "' "; +		} +		 +		foreach ($this->comments as $comment) +		{ +			$arguments.= "--add-comment '" . $comment->getValue() . "' "; +		} +		 +		if ($this->fromDir != "") +		{ +			$arguments .= $this->fromDir . " "; +		} + +		if ($this->toDir != "") +		{ +			$arguments .= "-o " . $this->toDir . " "; +		} + +		return $arguments; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php new file mode 100644 index 00000000..70abd544 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php @@ -0,0 +1,144 @@ +<?php +/** + * $Id: IoncubeLicenseTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/ioncube/IoncubeComment.php'; + +/** + * Invokes the ionCube "make_license" program + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: IoncubeLicenseTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.ioncube + * @since 2.2.0 + */ +class IoncubeLicenseTask extends Task +{ +	private $ioncubePath = "/usr/local/ioncube"; +	 +	private $licensePath = ""; +	private $passPhrase = ""; +	 +	private $comments = array(); + +	/** +	 * Sets the path to the ionCube encoder +	 */ +	function setIoncubePath($ioncubePath) +	{ +		$this->ioncubePath = $ioncubePath; +	} + +	/** +	 * Returns the path to the ionCube encoder +	 */ +	function getIoncubePath() +	{ +		return $this->ioncubePath; +	} + +	/** +	 * Sets the path to the license file to use +	 */ +	function setLicensePath($licensePath) +	{ +		$this->licensePath = $licensePath; +	} + +	/** +	 * Returns the path to the license file to use +	 */ +	function getLicensePath() +	{ +		return $this->licensePath; +	} + +	/** +	 * Sets the passphrase to use when encoding files +	 */ +	function setPassPhrase($passPhrase) +	{ +		$this->passPhrase = $passPhrase; +	} + +	/** +	 * Returns the passphrase to use when encoding files +	 */ +	function getPassPhrase() +	{ +		return $this->passPhrase; +	} + +	/** +	 * Adds a comment to be used in encoded files +	 */ +	function addComment(IoncubeComment $comment) +	{ +		$this->comments[] = $comment; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$arguments = $this->constructArguments(); +		 +		$makelicense = new PhingFile($this->ioncubePath, 'make_license'); +		 +		$this->log("Running ionCube make_license..."); +		 +		exec($makelicense->__toString() . " " . $arguments . " 2>&1", $output, $return); +		 +        if ($return != 0) +        { +			throw new BuildException("Could not execute ionCube make_license: " . implode(' ', $output)); +        }        +	} + +	/** +	 * Constructs an argument string for the ionCube make_license +	 */ +	private function constructArguments() +	{ +		$arguments = ""; +		 +		if (!empty($this->passPhrase)) +		{ +			$arguments.= "--passphrase '" . $this->passPhrase . "' "; +		} +		 +		foreach ($this->comments as $comment) +		{ +			$arguments.= "--header-line '" . $comment->getValue() . "' "; +		} +		 +		if (!empty($this->licensePath)) +		{ +			$arguments.= "--o '" . $this->licensePath . "' "; +		} + +		return $arguments; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php b/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php new file mode 100644 index 00000000..12bd4e55 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php @@ -0,0 +1,231 @@ +<?php +/* + *  $Id: Fileset.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/io/PhingFile.php'; + +/** + * Builds list of files for PEAR_PackageFileManager using a Phing FileSet. + * + * Some code here is taken from PEAR_PackageFileManager_File -- getting results from flat + * array into the assoc array expected from getFileList(). + *  + * @author   Greg Beaver  + * @author   Hans Lellelid <hans@xmpl.org> + * @package  phing.tasks.ext.pearpackage + * @version  $Revision: 1.7 $ + */ +class PEAR_PackageFileManager_Fileset { + +    /** +     * @access private +     * @var PEAR_PackageFileManager +     */ +    private $parent; +     +    /** +     * Curent Phing Project. +     * @var Project +     */ +    private $project; +     +    /** +     * FileSets to use. +     * @var array FileSet[] +     */ +    private $filesets = array(); + +    /** +     * Set up the FileSet filelist generator +     * +     * 'project' and 'filesets' are the only options that this class uses. +     *  +     * @param PEAR_PackageFileManager +     * @param array +     */ +    function __construct($parent, $options) +    { +        $this->parent = $parent; +        $this->project = $options['phing_project']; +        $this->filesets = $options['phing_filesets']; +    } +     +    /** +     * Generate the <filelist></filelist> section +     * of the package file. +     * +     * This function performs the backend generation of the array +     * containing all files in this package +     * @return array structure of all files to include +     */ +    function getFileList() {     + +        $allfiles = array();         +         +        foreach($this->filesets as $fs) { +            $ds = $fs->getDirectoryScanner($this->project); +             +            $files = $ds->getIncludedFiles(); +             +            // We need to store these files keyed by the basedir from DirectoryScanner +            // so that we can resolve the fullpath of the file later. +            if (isset($allfiles[$ds->getBasedir()])) +            { +                $allfiles[$ds->getBasedir()] = array_merge($allfiles[$ds->getBasedir()], $files); +            } +            else +            { +                $allfiles[$ds->getBasedir()] = $files; +            } +        } +         +        $struc = array(); +         +        foreach($allfiles as $basedir => $files) { +         +            foreach($files as $file) { +                             +                // paths are relative to $basedir above +                $path = strtr(dirname($file), DIRECTORY_SEPARATOR, '/'); +     +                if (!$path || $path == '.') { +                    $path = '/'; // for array index +                } +                 +				$parts = explode('.', basename($file)); +                $ext = array_pop($parts); +                if (strlen($ext) == strlen($file)) { +                    $ext = ''; +                } +                 +                $f = new PhingFile($basedir, $file); +                 +                $struc[$path][] = array('file' => basename($file), +                                        'ext' => $ext, +                                        'path' => (($path == '/') ? basename($file) : $path . '/' . basename($file)), +                                        'fullpath' => $f->getAbsolutePath());         +            }                                         +        } +                 +        uksort($struc,'strnatcasecmp'); +        foreach($struc as $key => $ind) { +            usort($ind, array($this, 'sortfiles')); +            $struc[$key] = $ind; +        } + +        $tempstruc = $struc; +        $struc = array('/' => $tempstruc['/']); +        $bv = 0; +        foreach($tempstruc as $key => $ind) { +            $save = $key; +            if ($key != '/') { +                $struc['/'] = $this->setupDirs($struc['/'], explode('/', $key), $tempstruc[$key]); +            } +        } +        uksort($struc['/'], array($this, 'mystrucsort')); + +        return $struc; +    } + +    /** +     * Recursively move contents of $struc into associative array +     * +     * The contents of $struc have many indexes like 'dir/subdir/subdir2'. +     * This function converts them to +     * array('dir' => array('subdir' => array('subdir2'))) +     * @param array struc is array('dir' => array of files in dir, +     *              'dir/subdir' => array of files in dir/subdir,...) +     * @param array array form of 'dir/subdir/subdir2' array('dir','subdir','subdir2') +     * @return array same as struc but with array('dir' => +     *              array(file1,file2,'subdir' => array(file1,...))) +     */ +    private function setupDirs($struc, $dir, $contents) { +     +        if (!count($dir)) { +            foreach($contents as $dir => $files) { +                if (is_string($dir)) { +                    if (strpos($dir, '/')) { +                        $test = true; +                        $a = $contents[$dir]; +                        unset($contents[$dir]); +                        $b = explode('/', $dir); +                        $c = array_shift($b); +                        if (isset($contents[$c])) { +                            $contents[$c] = $this->setDir($contents[$c], $this->setupDirs(array(), $b, $a)); +                        } else { +                            $contents[$c] = $this->setupDirs(array(), $b, $a); +                        } +                    } +                } +            } +            return $contents; +        } +        $me = array_shift($dir); +        if (!isset($struc[$me])) { +            $struc[$me] = array(); +        } +        $struc[$me] = $this->setupDirs($struc[$me], $dir, $contents); +        return $struc; +    } +     +    /** +     * Recursively add all the subdirectories of $contents to $dir without erasing anything in +     * $dir +     * @param array +     * @param array +     * @return array processed $dir +     */ +    function setDir($dir, $contents) +    { +        while(list($one,$two) = each($contents)) { +            if (isset($dir[$one])) { +                $dir[$one] = $this->setDir($dir[$one], $contents[$one]); +            } else { +                $dir[$one] = $two; +            } +        } +        return $dir; +    } +     +    /** +     * Sorting functions for the file list +     * @param string +     * @param string +     * @access private +     */ +    function sortfiles($a, $b) +    { +        return strnatcasecmp($a['file'],$b['file']); +    } +     +    function mystrucsort($a, $b) +    { +        if (is_numeric($a) && is_string($b)) return 1; +        if (is_numeric($b) && is_string($a)) return -1; +        if (is_numeric($a) && is_numeric($b)) +        { +            if ($a > $b) return 1; +            if ($a < $b) return -1; +            if ($a == $b) return 0; +        } +        return strnatcasecmp($a,$b); +    } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php new file mode 100644 index 00000000..2fefc4e5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php @@ -0,0 +1,157 @@ +<?php + +	/** +	 * $Id: PHPDocumentorTask.php 59 2006-04-28 14:49:47Z mrook $ +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +	 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +	 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +	 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +	 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +	 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +	 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +	 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +	 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +	 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 * +	 * This software consists of voluntary contributions made by many individuals +	 * and is licensed under the LGPL. For more information please see +	 * <http://phing.info>. +	 */ +	  +	require_once 'phing/Task.php'; + +	/** +	 * Task to run phpDocumentor. +	 * +	 * @author Michiel Rook <michiel@trendserver.nl> +	 * @version $Id: PHPDocumentorTask.php 59 2006-04-28 14:49:47Z mrook $ +	 * @package phing.tasks.ext.phpdoc +	 */	 +	class PHPDocumentorTask extends Task +	{ +		/** +		 * The name of the executable for phpDocumentor +		 */ +		const PHPDOC = 'phpdoc'; +		 +		private $title = "Default Title"; +				 +		private $destdir = "."; +				 +		private $sourcepath = NULL; +				 +		private $output = ""; +				 +		private $linksource = false; +		 +		private $parseprivate = false; + +		/** +		 * Set the title for the generated documentation +		 */ +		function setTitle($title) +		{ +			$this->title = $title; +		} +		 +		/** +		 * Set the destination directory for the generated documentation +		 */ +		function setDestdir($destdir) +		{ +			$this->destdir = $destdir; +		} +		 +		/** +		 * Set the source path +		 */ +		function setSourcepath(Path $sourcepath) +		{ +			if ($this->sourcepath === NULL) +			{ +				$this->sourcepath = $sourcepath; +			} +			else +			{ +				$this->sourcepath->append($sourcepath); +			} +		} +		 +		/** +		 * Set the output type +		 */		 +		function setOutput($output) +		{ +			$this->output = $output; +		} +		 +		/** +		 * Should sources be linked in the generated documentation +		 */ +		function setLinksource($linksource) +		{ +			$this->linksource = $linksource; +		} +		 +		/** +		 * Should private members/classes be documented +		 */ +		function setParseprivate($parseprivate) +		{ +			$this->parseprivate = $parseprivate; +		} +		 +		/** +		 * Main entrypoint of the task +		 */ +		function main() +		{ +			$arguments = $this->constructArguments(); +			 +			exec(self::PHPDOC . " " . $arguments, $output, $retval); +		} +		 +		/** +		 * Constructs an argument string for phpDocumentor +		 */ +		private function constructArguments() +		{ +			$arguments = "-q "; +			 +			if ($this->title) +			{ +				$arguments.= "-ti \"" . $this->title . "\" "; +			} +			 +			if ($this->destdir) +			{ +				$arguments.= "-t " . $this->destdir . " "; +			} +			 +			if ($this->sourcepath !== NULL) +			{ +				$arguments.= "-d " . $this->sourcepath->__toString() . " "; +			} +			 +			if ($this->output) +			{ +				$arguments.= "-o " . $this->output . " "; +			} +			 +			if ($this->linksource) +			{ +				$arguments.= "-s "; +			} +			 +			if ($this->parseprivate) +			{ +				$arguments.= "-pp "; +			} +						 +			return $arguments; +		} +	}; + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php new file mode 100644 index 00000000..63f8911a --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php @@ -0,0 +1,171 @@ +<?php +/** + * $Id: BatchTest.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/FileSet.php'; + +/** + * Scans a list of (.php) files given by the fileset attribute, extracts + * all subclasses of PHPUnit2_Framework_TestCase. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: BatchTest.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class BatchTest +{ +	/** the list of filesets containing the testcase filename rules */ +	private $filesets = array(); + +	/** the reference to the project */ +	private $project = NULL; + +	/** the classpath to use with Phing::__import() calls */ +	private $classpath = NULL; +	 +	/** names of classes to exclude */ +	private $excludeClasses = array(); +	 +	/** +	 * Create a new batchtest instance +	 * +	 * @param Project the project it depends on. +	 */ +	function __construct(Project $project) +	{ +		$this->project = $project; +	} +	 +	/** +	 * Sets the classes to exclude +	 */ +	function setExclude($exclude) +	{ +		$this->excludeClasses = explode(" ", $exclude); +	} + +	/** +	 * Sets the classpath +	 */ +	function setClasspath(Path $classpath) +	{ +		if ($this->classpath === null) +		{ +			$this->classpath = $classpath; +		} +		else +		{ +			$this->classpath->append($classpath); +		} +	} + +	/** +	 * Creates a new Path object +	 */ +	function createClasspath() +	{ +		$this->classpath = new Path(); +		return $this->classpath; +	} + +	/** +	 * Returns the classpath +	 */ +	function getClasspath() +	{ +		return $this->classpath; +	} + +	/** +	 * Add a new fileset containing the XML results to aggregate +	 * +	 * @param FileSet the new fileset containing XML results. +	 */ +	function addFileSet(FileSet $fileset) +	{ +		$this->filesets[] = $fileset; +	} + +	/** +	 * Iterate over all filesets and return the filename of all files +	 * that end with .php. +	 * +	 * @return array an array of filenames +	 */ +	private function getFilenames() +	{ +		$filenames = array(); + +		foreach ($this->filesets as $fileset) +		{ +			$ds = $fileset->getDirectoryScanner($this->project); +			$ds->scan(); + +			$files = $ds->getIncludedFiles(); + +			foreach ($files as $file) +			{ +				if (strstr($file, ".php")) +				{ +					$filenames[] = $ds->getBaseDir() . "/" . $file; +				} +			} +		} + +		return $filenames; +	} +	 +	/** +	 * Filters an array of classes, removes all classes that are not subclasses of PHPUnit2_Framework_TestCase, +	 * or classes that are declared abstract +	 */ +	private function filterTests($input) +	{ +		$reflect = new ReflectionClass($input); +		 +		return is_subclass_of($input, 'PHPUnit2_Framework_TestCase') && (!$reflect->isAbstract()); +	} + +	/** +	 * Returns an array of PHPUnit2_Framework_TestCase classes that are declared +	 * by the files included by the filesets +	 * +	 * @return array an array of PHPUnit2_Framework_TestCase classes. +	 */ +	function elements() +	{ +		$filenames = $this->getFilenames(); +		 +		$declaredClasses = array();		 + +		foreach ($filenames as $filename) +		{ +			$definedClasses = PHPUnit2Util::getDefinedClasses($filename); +			 +			$declaredClasses = array_merge($declaredClasses, $definedClasses); +		} +		 +		$elements = array_filter($declaredClasses, array($this, "filterTests")); + +		return $elements; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php new file mode 100644 index 00000000..9d2a4656 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php @@ -0,0 +1,120 @@ +<?php +/** + * $Id: FormatterElement.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php'; +require_once 'phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php'; +require_once 'phing/system/io/PhingFile.php'; + +/** + * A wrapper for the implementations of PHPUnit2ResultFormatter. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: FormatterElement.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class FormatterElement +{ +	protected $formatter = NULL; +	 +	protected $type = ""; +	 +	protected $useFile = true; +	 +	protected $toDir = "."; +	 +	protected $outfile = ""; + +	function setType($type) +	{ +		$this->type = $type; + +		if ($this->type == "xml") +		{ +			$destFile = new PhingFile($this->toDir, 'testsuites.xml'); +			$this->formatter = new XMLPHPUnit2ResultFormatter(); +		} +		else +		if ($this->type == "plain") +		{ +			$this->formatter = new PlainPHPUnit2ResultFormatter(); +		} +		else +		{ +			throw new BuildException("Formatter '" . $this->type . "' not implemented"); +		} +	} + +	function setClassName($className) +	{ +		$classNameNoDot = Phing::import($className); + +		$this->formatter = new $classNameNoDot(); +	} + +	function setUseFile($useFile) +	{ +		$this->useFile = $useFile; +	} +	 +	function getUseFile() +	{ +		return $this->useFile; +	} +	 +	function setToDir($toDir) +	{ +		$this->toDir = $toDir; +	} +	 +	function getToDir() +	{ +		return $this->toDir; +	} + +	function setOutfile($outfile) +	{ +		$this->outfile = $outfile; +	} +	 +	function getOutfile() +	{ +		if ($this->outfile) +		{ +			return $this->outfile; +		} +		else +		{ +			return $this->formatter->getPreferredOutfile() . $this->getExtension(); +		} +	} +	 +	function getExtension() +	{ +		return $this->formatter->getExtension(); +	} + +	function getFormatter() +	{ +		return $this->formatter; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php new file mode 100644 index 00000000..1e08e79c --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php @@ -0,0 +1,162 @@ +<?php +/** + * $Id: PHPUnit2ReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/FileWriter.php'; +require_once 'phing/util/ExtendedFileStream.php'; + +/** + * Transform a PHPUnit2 xml report using XSLT. + * This transformation generates an html report in either framed or non-framed + * style. The non-framed style is convenient to have a concise report via mail,  + * the framed report is much more convenient if you want to browse into  + * different packages or testcases since it is a Javadoc like report. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PHPUnit2ReportTask.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2ReportTask extends Task +{ +	private $format = "noframes"; +	private $styleDir = ""; +	private $toDir = ""; + +	/** the directory where the results XML can be found */ +	private $inFile = "testsuites.xml"; + +	/** +	 * Set the filename of the XML results file to use. +	 */ +	function setInFile($inFile) +	{ +		$this->inFile = $inFile; +	} + +	/** +	 * Set the format of the generated report. Must be noframes or frames. +	 */ +	function setFormat($format) +	{ +		$this->format = $format; +	} + +	/** +	 * Set the directory where the stylesheets are located. +	 */ +	function setStyleDir($styleDir) +	{ +		$this->styleDir = $styleDir; +	} + +	/** +	 * Set the directory where the files resulting from the  +	 * transformation should be written to. +	 */ +	function setToDir($toDir) +	{ +		$this->toDir = $toDir; +	} + +	private function getStyleSheet() +	{ +		$xslname = "phpunit2-" . $this->format . ".xsl"; + +		if ($this->styleDir) +		{ +			$file = new PhingFile($this->styleDir, $xslname); +		} +		else +		{ +			$path = Phing::getResourcePath("phing/etc/$xslname"); +			 +			if ($path === NULL) +			{ +				$path = Phing::getResourcePath("etc/$xslname"); + +				if ($path === NULL) +				{ +					throw new BuildException("Could not find $xslname in resource path"); +				} +			} +			 +			$file = new PhingFile($path); +		} + +		if (!$file->exists()) +		{ +			throw new BuildException("Could not find file " . $file->getPath()); +		} + +		return $file; +	} + +	function transform($document) +	{ +		$dir = new PhingFile($this->toDir); +		 +		if (!$dir->exists()) +		{ +			throw new BuildException("Directory '" . $this->toDir . "' does not exist"); +		} +		 +		$xslfile = $this->getStyleSheet(); + +		$xsl = new DOMDocument(); +		$xsl->load($xslfile->getAbsolutePath()); + +		$proc = new XSLTProcessor(); +		$proc->importStyleSheet($xsl); + +		if ($this->format == "noframes") +		{ +			$writer = new FileWriter(new PhingFile($this->toDir, "phpunit2-noframes.html")); +			$writer->write($proc->transformToXML($document)); +			$writer->close(); +		} +		else +		{ +			ExtendedFileStream::registerStream(); + +			// no output for the framed report +			// it's all done by extension... +			$dir = new PhingFile($this->toDir); +			$proc->setParameter('', 'output.dir', $dir->getAbsolutePath()); +			$proc->transformToXML($document); +		} +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$testSuitesDoc = new DOMDocument(); +		$testSuitesDoc->load($this->inFile); +		 +		$this->transform($testSuitesDoc); +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php new file mode 100644 index 00000000..5722c63e --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php @@ -0,0 +1,154 @@ +<?php +/** + * $Id: PHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; + +require_once 'phing/system/io/Writer.php'; + +/** + * This abstract class describes classes that format the results of a PHPUnit2 testrun. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +abstract class PHPUnit2ResultFormatter implements PHPUnit2_Framework_TestListener +{ +	protected $out = NULL; +	 +	protected $project = NULL; +	 +	private $timer = NULL; + +	private $runCount = 0; +	 +	private $failureCount = 0; +	 +	private $errorCount = 0;	 +	 +	/** +	 * Sets the writer the formatter is supposed to write its results to. +   	 */ +	function setOutput(Writer $out) +	{ +		$this->out = $out;	 +	} + +	/** +	 * Returns the extension used for this formatter +	 * +	 * @return string the extension +	 */ +	function getExtension() +	{ +		return ""; +	} + +	/** +	 * Sets the project +	 * +	 * @param Project the project +	 */ +	function setProject(Project $project) +	{ +		$this->project = $project; +	} +	 +	function getPreferredOutfile() +	{ +		return ""; +	} +	 +	function startTestRun() +	{ +	} +	 +	function endTestRun() +	{ +	} +	 +	function startTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		$this->runCount = 0; +		$this->failureCount = 0; +		$this->errorCount = 0; +		 +		$this->timer = new Timer(); +		$this->timer->start(); +	} +	 +	function endTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		$this->timer->stop(); +	} + +	function startTest(PHPUnit2_Framework_Test $test) +	{ +		$this->runCount++; +	} + +	function endTest(PHPUnit2_Framework_Test $test) +	{ +	} + +	function addError(PHPUnit2_Framework_Test $test, Exception $e) +	{ +		$this->errorCount++; +	} + +	function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) +	{ +		$this->failureCount++; +	} + +	function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) +	{ +	} + +	function getRunCount() +	{ +		return $this->runCount; +	} +	 +	function getFailureCount() +	{ +		return $this->failureCount; +	} +	 +	function getErrorCount() +	{ +		return $this->errorCount; +	} +	 +	function getElapsedTime() +	{ +		if ($this->timer) +		{ +			return $this->timer->getElapsedTime(); +		} +		else +		{ +			return 0; +		} +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php new file mode 100644 index 00000000..ffd36405 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php @@ -0,0 +1,239 @@ +<?php +/** + * $Id: PHPUnit2Task.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/util/LogWriter.php'; + +/** + * Runs PHPUnit2 tests. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PHPUnit2Task.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @see BatchTest + * @since 2.1.0 + */ +class PHPUnit2Task extends Task +{ +	private $batchtests = array(); +	private $formatters = array(); +	private $haltonerror = false; +	private $haltonfailure = false; +	private $failureproperty; +	private $errorproperty; +	private $printsummary = false; +	private $testfailed = false; +	private $codecoverage = false; + +	/** +	 * Initialize Task. + 	 * This method includes any necessary PHPUnit2 libraries and triggers +	 * appropriate error if they cannot be found.  This is not done in header +	 * because we may want this class to be loaded w/o triggering an error. +	 */ +	function init() { +		include_once 'PHPUnit2/Util/Filter.php'; +		if (!class_exists('PHPUnit2_Util_Filter')) { +			throw new BuildException("PHPUnit2Task depends on PEAR PHPUnit2 package being installed.", $this->getLocation()); +		} +		 +		if (version_compare(PHP_VERSION, '5.0.3') < 0) { +		    throw new BuildException("PHPUnit2Task requires PHP version >= 5.0.3.", $this->getLocation()); +		} + +		// other dependencies that should only be loaded when class is actually used. +		require_once 'phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php'; +		require_once 'phing/tasks/ext/phpunit2/BatchTest.php'; +		require_once 'phing/tasks/ext/phpunit2/FormatterElement.php'; +		require_once 'phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php'; + +		// add some defaults to the PHPUnit2 Filter +		PHPUnit2_Util_Filter::addFileToFilter('PHPUnit2Task.php'); +		PHPUnit2_Util_Filter::addFileToFilter('PHPUnit2TestRunner.php'); +		PHPUnit2_Util_Filter::addFileToFilter('phing/Task.php'); +		PHPUnit2_Util_Filter::addFileToFilter('phing/Target.php'); +		PHPUnit2_Util_Filter::addFileToFilter('phing/Project.php'); +		PHPUnit2_Util_Filter::addFileToFilter('phing/Phing.php'); +		PHPUnit2_Util_Filter::addFileToFilter('phing.php'); + +	} +	 +	function setFailureproperty($value) +	{ +		$this->failureproperty = $value; +	} +	 +	function setErrorproperty($value) +	{ +		$this->errorproperty = $value; +	} +	 +	function setHaltonerror($value) +	{ +		$this->haltonerror = $value; +	} + +	function setHaltonfailure($value) +	{ +		$this->haltonfailure = $value; +	} + +	function setPrintsummary($printsummary) +	{ +		$this->printsummary = $printsummary; +	} +	 +	function setCodecoverage($codecoverage) +	{ +		$this->codecoverage = $codecoverage; +	} + +	/** +	 * Add a new formatter to all tests of this task. +	 * +	 * @param FormatterElement formatter element +	 */ +	function addFormatter(FormatterElement $fe) +	{ +		$this->formatters[] = $fe; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$tests = array(); +		 +		if ($this->printsummary) +		{ +			$fe = new FormatterElement(); +			$fe->setClassName('SummaryPHPUnit2ResultFormatter'); +			$fe->setUseFile(false); +			$this->formatters[] = $fe; +		} +		 +		foreach ($this->batchtests as $batchtest) +		{ +			$tests = array_merge($tests, $batchtest->elements()); +		}			 +		 +		foreach ($this->formatters as $fe) +		{ +			$formatter = $fe->getFormatter();			 +			$formatter->setProject($this->getProject()); + +			if ($fe->getUseFile()) +			{ +				$destFile = new PhingFile($fe->getToDir(), $fe->getOutfile()); +				 +				$writer = new FileWriter($destFile->getAbsolutePath()); + +				$formatter->setOutput($writer); +			} +			else +			{ +				$formatter->setOutput($this->getDefaultOutput()); +			} + +			$formatter->startTestRun(); +		} +		 +		foreach ($tests as $test) +		{ +			$this->execute(new PHPUnit2_Framework_TestSuite(new ReflectionClass($test))); +		} + +		foreach ($this->formatters as $fe) +		{ +			$formatter = $fe->getFormatter(); +			$formatter->endTestRun(); +		} +		 +		if ($this->testfailed) +		{ +			throw new BuildException("One or more tests failed"); +		} +	} + +	/** +	 * @throws BuildException +	 */ +	private function execute($suite) +	{ +		$runner = new PHPUnit2TestRunner($suite, $this->project); +		 +		$runner->setCodecoverage($this->codecoverage); + +		foreach ($this->formatters as $fe) +		{ +			$formatter = $fe->getFormatter(); + +			$runner->addFormatter($formatter); +		} + +		$runner->run(); + +		$retcode = $runner->getRetCode(); +		 +		if ($retcode == PHPUnit2TestRunner::ERRORS) { +		    if ($this->errorproperty) { +				$this->project->setNewProperty($this->errorproperty, true); +			} +			if ($this->haltonerror) { +			    $this->testfailed = true; +			} +		} elseif ($retcode == PHPUnit2TestRunner::FAILURES) { +			if ($this->failureproperty) { +				$this->project->setNewProperty($this->failureproperty, true); +			} +			 +			if ($this->haltonfailure) { +				$this->testfailed = true; +			} +		} +		 +	} + +	private function getDefaultOutput() +	{ +		return new LogWriter($this); +	} + +	/** +	 * Adds a set of tests based on pattern matching. +	 * +	 * @return BatchTest a new instance of a batch test. +	 */ +	function createBatchTest() +	{ +		$batchtest = new BatchTest($this->getProject()); + +		$this->batchtests[] = $batchtest; + +		return $batchtest; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php new file mode 100644 index 00000000..bbd19f34 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php @@ -0,0 +1,107 @@ +<?php +/** + * $Id: PHPUnit2TestRunner.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'PHPUnit2/Framework/TestListener.php'; +require_once 'PHPUnit2/Framework/TestResult.php'; +require_once 'PHPUnit2/Framework/TestSuite.php'; + +require_once 'phing/tasks/ext/coverage/CoverageMerger.php'; + +require_once 'phing/system/util/Timer.php'; + +/** + * Simple Testrunner for PHPUnit2 that runs all tests of a testsuite. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PHPUnit2TestRunner.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2TestRunner +{ +	const SUCCESS = 0; +	const FAILURES = 1; +	const ERRORS = 2; + +	private $test = NULL; +	private $suite = NULL; +	private $retCode = 0; +	private $formatters = array(); +	 +	private $codecoverage = false; +	 +	private $project = NULL; + +	function __construct(PHPUnit2_Framework_TestSuite $suite, Project $project) +	{ +		$this->suite = $suite; +		$this->project = $project; +		$this->retCode = self::SUCCESS; +	} +	 +	function setCodecoverage($codecoverage) +	{ +		$this->codecoverage = $codecoverage; +	} + +	function addFormatter(PHPUnit2_Framework_TestListener $formatter) +	{ +		$this->formatters[] = $formatter; +	} + +	function run() +	{ +		$res = new PHPUnit2_Framework_TestResult(); + +		if ($this->codecoverage) +		{ +			$res->collectCodeCoverageInformation(TRUE); +		} + +		foreach ($this->formatters as $formatter) +		{ +			$res->addListener($formatter); +		} + +		$this->suite->run($res); +		 +		if ($this->codecoverage) +		{ +			CoverageMerger::merge($this->project, $res->getCodeCoverageInformation()); +		} +		 +		if ($res->errorCount() != 0) +		{ +			$this->retCode = self::ERRORS; +		} + +		else if ($res->failureCount() != 0 || $res->notImplementedCount() != 0) +		{ +			$this->retCode = self::FAILURES; +		} +	} + +	function getRetCode() +	{ +		return $this->retCode; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php new file mode 100644 index 00000000..f4d1f62a --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php @@ -0,0 +1,114 @@ +<?php +/** + * $Id: PHPUnit2Util.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Various utility functions + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PHPUnit2Util.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PHPUnit2Util +{ +	protected static $definedClasses = array(); +	 +	/** +	 * Returns the package of a class as defined in the docblock of the class using @package +	 * +	 * @param string the name of the class +	 * @return string the name of the package +	 */ +	static function getPackageName($classname) +	{ +		$reflect = new ReflectionClass($classname); + +		if (preg_match('/@package[\s]+([\.\w]+)/', $reflect->getDocComment(), $matches)) +		{ +			return $matches[1]; +		} +		else +		{ +			return "default"; +		} +	} +	 +	/** +	 * Derives the classname from a filename. +	 * Assumes that there is only one class defined in that particular file, and that +	 * the naming follows the dot-path (Java) notation scheme. +	 * +	 * @param string the filename +	 * @return string the name fo the class +	 */ +	static function getClassFromFileName($filename) +	{ +		$filename = basename($filename); +		 +		$rpos = strrpos($filename, '.'); +		 +		if ($rpos != -1) +		{ +			$filename = substr($filename, 0, $rpos); +		} +		 +		return $filename; +	} + +	/** +	 * @param string the filename +	 * @param Path optional classpath +	 * @return array list of classes defined in the file +	 */ +	static function getDefinedClasses($filename, $classpath = NULL) +	{ +		$filename = realpath($filename); +		 +		if (!file_exists($filename)) +		{ +			throw new Exception("File '" . $filename . "' does not exist"); +		} +		 +		if (isset(self::$definedClasses[$filename])) +		{ +			return self::$definedClasses[$filename]; +		} +		 +		Phing::__import($filename, $classpath); + +		$declaredClasses = get_declared_classes(); +		 +		foreach ($declaredClasses as $classname) +		{ +			$reflect = new ReflectionClass($classname); +			 +			self::$definedClasses[$reflect->getFilename()][] = $classname; +			 +			if (is_array(self::$definedClasses[$reflect->getFilename()])) +			{			 +				self::$definedClasses[$reflect->getFilename()] = array_unique(self::$definedClasses[$reflect->getFilename()]); +			} +		} +				 +		return self::$definedClasses[$filename]; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..b0a9ae58 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php @@ -0,0 +1,117 @@ +<?php +/** + * $Id: PlainPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Util/Filter.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints plain text output of the test to a specified Writer. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: PlainPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class PlainPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ +	private $inner = ""; +	 +	function getExtension() +	{ +		return ".txt"; +	} +	 +	function getPreferredOutfile() +	{ +		return "testresults"; +	} + +	function startTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		parent::startTestSuite($suite); +		 +		$this->inner = ""; +	} +	 +	function endTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		parent::endTestSuite($suite); +		 +		$sb = "Testsuite: " . $suite->getName() . "\n"; +		$sb.= "Tests run: " . $this->getRunCount(); +		$sb.= ", Failures: " . $this->getFailureCount(); +		$sb.= ", Errors: " . $this->getErrorCount(); +		$sb.= ", Time elapsed: " . $this->getElapsedTime(); +		$sb.= " sec\n"; + +		if ($this->out != NULL) +		{ +			$this->out->write($sb); +			$this->out->write($this->inner); +		} +	} + +	function addError(PHPUnit2_Framework_Test $test, Exception $e) +	{ +		parent::addError($test, $e); +		 +		$this->formatError("ERROR", $test, $e); +	} + +	function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) +	{ +		parent::addFailure($test, $t); +		 +		$this->formatError("FAILED", $test, $t); +	} + +	function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) +	{ +		parent::addIncompleteTest($test, $e); +		 +		$this->formatError("INCOMPLETE", $test, $e); +	} + +	private function formatError($type, PHPUnit2_Framework_Test $test, Exception $e) +	{ +		if ($test != null) +		{ +			$this->endTest($test); +		} + +		$this->inner.= $test->getName() . " " . $type . "\n"; +		$this->inner.= $e->getMessage() . "\n"; +		$this->inner.= PHPUnit2_Util_Filter::getFilteredStackTrace($e) . "\n"; +	} +	 +	function endTestRun() +	{ +		parent::endTestRun(); +		 +		if ($this->out != NULL) +		{ +			$this->out->close(); +		} +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..df17d2d4 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php @@ -0,0 +1,58 @@ +<?php +/** + * $Id: SummaryPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'PHPUnit2/Framework/Test.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints short summary output of the test to Phing's logging system. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: SummaryPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */	 +class SummaryPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ +	function endTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		parent::endTestSuite($suite); +		 +		$sb = "Tests run: " . $this->getRunCount(); +		$sb.= ", Failures: " . $this->getFailureCount(); +		$sb.= ", Errors: " . $this->getErrorCount(); +		$sb.= ", Time elapsed: " . $this->getElapsedTime(); +		$sb.= " sec\n"; +		 +		if ($this->out != NULL) +		{ +			$this->out->write($sb); +			$this->out->close(); +		} +	} +	 +	function getExtension() +	{ +		return NULL; +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php new file mode 100644 index 00000000..ac2fec8f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php @@ -0,0 +1,117 @@ +<?php +/** + * $Id: XMLPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'PHPUnit2/Framework/Test.php'; +require_once 'PHPUnit2/Runner/Version.php'; + +require_once 'PHPUnit2/Util/Log/XML.php'; + +require_once 'phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php'; + +/** + * Prints XML output of the test to a specified Writer + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: XMLPHPUnit2ResultFormatter.php 59 2006-04-28 14:49:47Z mrook $ + * @package phing.tasks.ext.phpunit2 + * @since 2.1.0 + */ +class XMLPHPUnit2ResultFormatter extends PHPUnit2ResultFormatter +{ +	private $logger = NULL; +	 +	function __construct() +	{ +		$this->logger = new PHPUnit2_Util_Log_XML(); +		$this->logger->setWriteDocument(false); +	} +	 +	function getExtension() +	{ +		return ".xml"; +	} +	 +	function getPreferredOutfile() +	{ +		return "testsuites"; +	} +	 +	function startTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		parent::startTestSuite($suite); +		 +		$this->logger->startTestSuite($suite); +	} +	 +	function endTestSuite(PHPUnit2_Framework_TestSuite $suite) +	{ +		parent::endTestSuite($suite); +		 +		$this->logger->endTestSuite($suite); +	} +	 +	function startTest(PHPUnit2_Framework_Test $test) +	{ +		parent::startTest($test); +		 +		$this->logger->startTest($test); +	} + +	function endTest(PHPUnit2_Framework_Test $test) +	{ +		parent::endTest($test); +		 +		$this->logger->endTest($test); +	} +	 +	function addError(PHPUnit2_Framework_Test $test, Exception $e) +	{ +		parent::addError($test, $e); +		 +		$this->logger->addError($test, $e); +	} + +	function addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $t) +	{ +		parent::addFailure($test, $t); +		 +		$this->logger->addFailure($test, $t); +	} + +	function addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e) +	{ +		parent::addIncompleteTest($test, $e); +		 +		$this->logger->addIncompleteTest($test, $e); +	} +	 +	function endTestRun() +	{ +		parent::endTestRun(); +		 +		if ($this->out) +		{ +			$this->out->write($this->logger->getXML()); +			$this->out->close(); +		} +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php new file mode 100644 index 00000000..11e360e0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php @@ -0,0 +1,52 @@ +<?php
 +/**
 + * $Id: SimpleTestCountResultFormatter.php 58 2006-04-28 14:41:04Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php';
 +
 +/**
 + * Dummy result formatter used to count SimpleTest results
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: SimpleTestCountResultFormatter.php 58 2006-04-28 14:41:04Z mrook $
 + * @package phing.tasks.ext.simpletest
 + * @since 2.2.0
 + */
 +class SimpleTestCountResultFormatter extends SimpleTestResultFormatter
 +{
 +	const SUCCESS = 0;
 +	const FAILURES = 1;
 +	const ERRORS = 2;
 +	
 +	function getRetCode()
 +	{
 +		if ($this->getExceptionCount() != 0)
 +		{
 +			return self::ERRORS;
 +		}
 +		else if ($this->getFailCount() != 0)
 +		{
 +			return self::FAILURES;
 +		}
 +		
 +		return self::SUCCESS;
 +	}	
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php new file mode 100644 index 00000000..fab27315 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php @@ -0,0 +1,62 @@ +<?php
 +/**
 + * $Id: SimpleTestFormatterElement.php 58 2006-04-28 14:41:04Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php';
 +require_once 'phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php';
 +require_once 'phing/tasks/ext/phpunit2/FormatterElement.php';
 +
 +/**
 + * Child class of "FormatterElement", overrides setType to provide other
 + * formatter classes for SimpleTest
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: SimpleTestFormatterElement.php 58 2006-04-28 14:41:04Z mrook $
 + * @package phing.tasks.ext.simpletest
 + * @since 2.2.0
 + */
 +class SimpleTestFormatterElement extends FormatterElement
 +{
 +	function setType($type)
 +	{
 +		$this->type = $type;
 +
 +		if ($this->type == "xml")
 +		{
 +			$destFile = new PhingFile($this->toDir, 'testsuites.xml');
 +			//$this->formatter = new SimpleTestXmlResultFormatter();
 +		}
 +		else
 +		if ($this->type == "plain")
 +		{
 +			$this->formatter = new SimpleTestPlainResultFormatter();
 +		}
 +		else
 +		if ($this->type == "summary")
 +		{
 +			$this->formatter = new SimpleTestSummaryResultFormatter();
 +		}
 +		else
 +		{
 +			throw new BuildException("Formatter '" . $this->type . "' not implemented");
 +		}
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php new file mode 100644 index 00000000..f84ca815 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php @@ -0,0 +1,95 @@ +<?php
 +/**
 + * $Id: SimpleTestPlainResultFormatter.php 59 2006-04-28 14:49:47Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php';
 +
 +/**
 + * Prints plain text output of the test to a specified Writer.
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: SimpleTestPlainResultFormatter.php 59 2006-04-28 14:49:47Z mrook $
 + * @package phing.tasks.ext.simpletest
 + * @since 2.2.0
 + */
 +class SimpleTestPlainResultFormatter extends SimpleTestResultFormatter
 +{
 +	private $inner = "";
 +	
 +	function getExtension()
 +	{
 +		return ".txt";
 +	}
 +	
 +	function getPreferredOutfile()
 +	{
 +		return "testresults";
 +	}
 +
 +	function paintCaseStart($test_name)
 +	{
 +		parent::paintCaseStart($test_name);
 +		
 +		$this->inner = "";
 +	}
 +	
 +	function paintCaseEnd($test_name)
 +	{
 +		parent::paintCaseEnd($test_name);
 +		
 +		/* Only count suites where more than one test was run */
 +		if ($this->getRunCount())
 +		{
 +			$sb.= "Testsuite: $test_name\n";
 +			$sb.= "Tests run: " . $this->getRunCount();
 +			$sb.= ", Failures: " . $this->getFailureCount();
 +			$sb.= ", Errors: " . $this->getErrorCount();
 +			$sb.= ", Time elapsed: " . $this->getElapsedTime();
 +			$sb.= " sec\n";
 +
 +			if ($this->out != NULL)
 +			{
 +				$this->out->write($sb);
 +				$this->out->write($this->inner);
 +			}
 +		}
 +	}
 +
 +	function paintError($message)
 +	{
 +		parent::paintError($message);
 +		
 +		$this->formatError("ERROR", $message);
 +	}
 +
 +	function paintFail($message)
 +	{
 +		parent::paintFail($message);
 +		
 +		$this->formatError("FAILED", $message);
 +	}
 +
 +	private function formatError($type, $message)
 +	{
 +		$this->inner.= $this->getTestName() . " " . $type . "\n";
 +		$this->inner.= $message . "\n";	
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php new file mode 100644 index 00000000..7f94892f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php @@ -0,0 +1,162 @@ +<?php
 +/**
 + * $Id: SimpleTestResultFormatter.php 58 2006-04-28 14:41:04Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'simpletest/scorer.php';
 +
 +require_once 'phing/system/io/Writer.php';
 +
 +/**
 + * This abstract class describes classes that format the results of a SimpleTest testrun.
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: SimpleTestResultFormatter.php 58 2006-04-28 14:41:04Z mrook $
 + * @package phing.tasks.ext.phpunit2
 + * @since 2.2.0
 + */
 +abstract class SimpleTestResultFormatter extends SimpleReporter
 +{
 +	protected $out = NULL;
 +	
 +	protected $project = NULL;
 +	
 +	private $timer = NULL;
 +
 +	private $runCount = 0;
 +	
 +	private $failureCount = 0;
 +	
 +	private $errorCount = 0;	
 +
 +	private $currentTest = "";
 +	
 +	/**
 +	 * Sets the writer the formatter is supposed to write its results to.
 +   	 */
 +	function setOutput(Writer $out)
 +	{
 +		$this->out = $out;	
 +	}
 +
 +	/**
 +	 * Returns the extension used for this formatter
 +	 *
 +	 * @return string the extension
 +	 */
 +	function getExtension()
 +	{
 +		return "";
 +	}
 +
 +	/**
 +	 * Sets the project
 +	 *
 +	 * @param Project the project
 +	 */
 +	function setProject(Project $project)
 +	{
 +		$this->project = $project;
 +	}
 +	
 +	function getPreferredOutfile()
 +	{
 +		return "";
 +	}
 +	
 +	function paintMethodStart($test_name)
 +	{
 +		parent::paintMethodStart($test_name);
 +		
 +		$this->currentTest = $test_name;
 +	}
 +	
 +	function paintMethodEnd($test_name)
 +	{
 +		parent::paintMethodEnd($test_name);
 +		
 +		$this->runCount++;
 +	}
 +	
 +	function paintCaseStart($test_name)
 +	{
 +		parent::paintCaseStart($test_name);
 +		
 +		$this->runCount = 0;
 +		$this->failureCount = 0;
 +		$this->errorCount = 0;
 +		
 +		$this->timer = new Timer();
 +		$this->timer->start();
 +	}
 +		
 +	function paintCaseEnd($test_name)
 +	{
 +		parent::paintCaseEnd($test_name);
 +		
 +		$this->timer->stop();
 +	}
 +
 +	function paintError($message)
 +	{
 +		parent::paintError($message);
 +		
 +		$this->errorCount++;
 +	}
 +
 +	function paintFail($message)
 +	{
 +		parent::paintFail($message);
 +		
 +		$this->failureCount++;
 +	}
 +
 +	function getRunCount()
 +	{
 +		return $this->runCount;
 +	}
 +	
 +	function getFailureCount()
 +	{
 +		return $this->failureCount;
 +	}
 +	
 +	function getErrorCount()
 +	{
 +		return $this->errorCount;
 +	}
 +	
 +	function getTestName()
 +	{
 +		return $this->currentTest;
 +	}
 +	
 +	function getElapsedTime()
 +	{
 +		if ($this->timer)
 +		{
 +			return $this->timer->getElapsedTime();
 +		}
 +		else
 +		{
 +			return 0;
 +		}
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php new file mode 100644 index 00000000..79494bc9 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php @@ -0,0 +1,54 @@ +<?php
 +/**
 + * $Id: SimpleTestSummaryResultFormatter.php 59 2006-04-28 14:49:47Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'phing/tasks/ext/simpletest/SimpleTestResultFormatter.php';
 +
 +/**
 + * Prints short summary output of the test to Phing's logging system.
 + *
 + * @author Michiel Rook <michiel@trendserver.nl>
 + * @version $Id: SimpleTestSummaryResultFormatter.php 59 2006-04-28 14:49:47Z mrook $
 + * @package phing.tasks.ext.simpletest
 + * @since 2.2.0
 + */
 +class SimpleTestSummaryResultFormatter extends SimpleTestResultFormatter
 +{
 +	function paintCaseEnd($test_name)
 +	{
 +		parent::paintCaseEnd($test_name);
 +		
 +		/* Only count suites where more than one test was run */
 +		if ($this->getRunCount())
 +		{
 +			$sb.= "Tests run: " . $this->getRunCount();
 +			$sb.= ", Failures: " . $this->getFailureCount();
 +			$sb.= ", Errors: " . $this->getErrorCount();
 +			$sb.= ", Time elapsed: " . $this->getElapsedTime();
 +			$sb.= " sec\n";
 +
 +			if ($this->out != NULL)
 +			{
 +				$this->out->write($sb);
 +			}
 +		}
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php new file mode 100644 index 00000000..6aede68f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php @@ -0,0 +1,238 @@ +<?php +/** + * $Id: SimpleTestTask.php 58 2006-04-28 14:41:04Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/system/io/PhingFile.php'; +require_once 'phing/system/io/Writer.php'; +require_once 'phing/util/LogWriter.php'; + +/** + * Runs SimpleTest tests. + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: SimpleTestTask.php 58 2006-04-28 14:41:04Z mrook $ + * @package phing.tasks.ext.simpletest + * @since 2.2.0 + */ +class SimpleTestTask extends Task +{ +	private $formatters = array(); +	private $haltonerror = false; +	private $haltonfailure = false; +	private $failureproperty; +	private $errorproperty; +	private $printsummary = false; +	private $testfailed = false; + +	/** +	 * Initialize Task. + 	 * This method includes any necessary SimpleTest libraries and triggers +	 * appropriate error if they cannot be found.  This is not done in header +	 * because we may want this class to be loaded w/o triggering an error. +	 */ +	function init() { +		@include_once 'simpletest/scorer.php'; +		 +		if (!class_exists('SimpleReporter')) { +			throw new BuildException("SimpleTestTask depends on SimpleTest package being installed.", $this->getLocation()); +		} +		 +		require_once 'simpletest/reporter.php'; +		require_once 'simpletest/xml.php'; +		require_once 'simpletest/test_case.php'; +		require_once 'phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php'; +		require_once 'phing/tasks/ext/simpletest/SimpleTestFormatterElement.php'; +	} +	 +	function setFailureproperty($value) +	{ +		$this->failureproperty = $value; +	} +	 +	function setErrorproperty($value) +	{ +		$this->errorproperty = $value; +	} +	 +	function setHaltonerror($value) +	{ +		$this->haltonerror = $value; +	} + +	function setHaltonfailure($value) +	{ +		$this->haltonfailure = $value; +	} + +	function setPrintsummary($printsummary) +	{ +		$this->printsummary = $printsummary; +	} +	 +	/** +	 * Add a new formatter to all tests of this task. +	 * +	 * @param SimpleTestFormatterElement formatter element +	 */ +	function addFormatter(SimpleTestFormatterElement $fe) +	{ +		$this->formatters[] = $fe; +	} + +	/** +	 * Add a new fileset containing the XML results to aggregate +	 * +	 * @param FileSet the new fileset containing XML results. +	 */ +	function addFileSet(FileSet $fileset) +	{ +		$this->filesets[] = $fileset; +	} + +	/** +	 * Iterate over all filesets and return the filename of all files +	 * that end with .php. +	 * +	 * @return array an array of filenames +	 */ +	private function getFilenames() +	{ +		$filenames = array(); + +		foreach ($this->filesets as $fileset) +		{ +			$ds = $fileset->getDirectoryScanner($this->project); +			$ds->scan(); + +			$files = $ds->getIncludedFiles(); + +			foreach ($files as $file) +			{ +				if (strstr($file, ".php")) +				{ +					$filenames[] = $ds->getBaseDir() . "/" . $file; +				} +			} +		} + +		return $filenames; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$group = new GroupTest(); +		 +		$filenames = $this->getFilenames(); +		 +		foreach ($filenames as $testfile) +		{ +			$group->addTestFile($testfile); +		} +		 +		if ($this->printsummary) +		{ +			$fe = new SimpleTestFormatterElement(); +			$fe->setType('summary'); +			$fe->setUseFile(false); +			$this->formatters[] = $fe; +		} +		 +		foreach ($this->formatters as $fe) +		{ +			$formatter = $fe->getFormatter(); +			$formatter->setProject($this->getProject()); + +			if ($fe->getUseFile()) +			{ +				$destFile = new PhingFile($fe->getToDir(), $fe->getOutfile()); +				 +				$writer = new FileWriter($destFile->getAbsolutePath()); + +				$formatter->setOutput($writer); +			} +			else +			{ +				$formatter->setOutput($this->getDefaultOutput()); +			} +		} +		 +		$this->execute($group); +		 +		if ($this->testfailed) +		{ +			throw new BuildException("One or more tests failed"); +		} +	} +	 +	private function execute($suite) +	{ +		$counter = new SimpleTestCountResultFormatter(); +		$reporter = new MultipleReporter(); +		$reporter->attachReporter($counter); +		 +		foreach ($this->formatters as $fe) +		{ +			$formatter = $fe->getFormatter(); + +			$reporter->attachReporter($formatter); +		}		 +		 +		$suite->run($reporter); +		 +		$retcode = $counter->getRetCode(); +		 +		if ($retcode == SimpleTestCountResultFormatter::ERRORS) +		{ +		    if ($this->errorproperty) +		    { +				$this->project->setNewProperty($this->errorproperty, true); +			} +			 +			if ($this->haltonerror) +			{ +			    $this->testfailed = true; +			} +		} +		elseif ($retcode == SimpleTestCountResultFormatter::FAILURES) +		{ +			if ($this->failureproperty) +			{ +				$this->project->setNewProperty($this->failureproperty, true); +			} +			 +			if ($this->haltonfailure) +			{ +				$this->testfailed = true; +			} +		} +	} + +	private function getDefaultOutput() +	{ +		return new LogWriter($this); +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php new file mode 100644 index 00000000..71e3ba2e --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php @@ -0,0 +1,180 @@ +<?php
 +/*
 + *  $Id: SvnBaseTask.php 38 2006-03-09 14:05:11Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 + 
 +include_once 'phing/Task.php';
 +
 +/**
 + *  Send a message by mail() 
 + *
 + *  <mail to="user@example.org" subject="build complete">The build process is a success...</mail> 
 + * 
 + *  @author   Francois Harvey at SecuriWeb (http://www.securiweb.net)
 + *  @version  $Id: SvnBaseTask.php 38 2006-03-09 14:05:11Z mrook $
 + *  @package  phing.tasks.ext
 + */
 +abstract class SvnBaseTask extends Task
 +{
 +	private $workingCopy = "";
 +	
 +	private $repositoryUrl = "";
 +	
 +	private $svnPath = "/usr/bin/svn";
 +	
 +	private $svn = NULL;
 +	
 +	private $mode = "";
 +	
 +	private $svnArgs = array();
 +
 +	/**
 +	 * Initialize Task.
 + 	 * This method includes any necessary SVN libraries and triggers
 +	 * appropriate error if they cannot be found.  This is not done in header
 +	 * because we may want this class to be loaded w/o triggering an error.
 +	 */
 +	function init() {
 +		include_once 'VersionControl/SVN.php';
 +		if (!class_exists('VersionControl_SVN')) {
 +			throw new Exception("SvnLastRevisionTask depends on PEAR VersionControl_SVN package being installed.");
 +		}
 +	}
 +
 +	/**
 +	 * Sets the path to the workingcopy
 +	 */
 +	function setWorkingCopy($workingCopy)
 +	{
 +		$this->workingCopy = $workingCopy;
 +	}
 +
 +	/**
 +	 * Returns the path to the workingcopy
 +	 */
 +	function getWorkingCopy()
 +	{
 +		return $this->workingCopy;
 +	}
 +
 +	/**
 +	 * Sets the path/URI to the repository
 +	 */
 +	function setRepositoryUrl($repositoryUrl)
 +	{
 +		$this->repositoryUrl = $repositoryUrl;
 +	}
 +
 +	/**
 +	 * Returns the path/URI to the repository
 +	 */
 +	function getRepositoryUrl()
 +	{
 +		return $this->repositoryUrl;
 +	}
 +
 +	/**
 +	 * Sets the path to the SVN executable
 +	 */
 +	function setSvnPath($svnPath)
 +	{
 +		$this->svnPath = $svnPath;
 +	}
 +
 +	/**
 +	 * Returns the path to the SVN executable
 +	 */
 +	function getSvnPath()
 +	{
 +		return $this->svnPath;
 +	}
 +	
 +	/**
 +	 * Creates a VersionControl_SVN class based on $mode
 +	 *
 +	 * @param string The SVN mode to use (info, export, checkout, ...)
 +	 * @throws BuildException
 +	 */
 +	protected function setup($mode)
 +	{
 +		$this->mode = $mode;
 +		
 +		// Set up runtime options. Will be passed to all
 +		// subclasses.
 +		$options = array('fetchmode' => VERSIONCONTROL_SVN_FETCHMODE_ASSOC, 'svn_path' => $this->getSvnPath());
 +		
 +		// Pass array of subcommands we need to factory
 +		$this->svn = VersionControl_SVN::factory($mode, $options);
 +
 +		if (!empty($this->repositoryUrl))
 +		{
 +			$this->svnArgs = array($this->repositoryUrl);
 +		}
 +		else
 +		if (!empty($this->workingCopy))
 +		{
 +			if (is_dir($this->workingCopy))
 +			{
 +				if (in_array(".svn", scandir($this->workingCopy)))
 +				{
 +					$this->svnArgs = array($this->workingCopy);
 +				}
 +				else
 +				{
 +					throw new BuildException("'".$this->workingCopy."' doesn't seem to be a working copy");
 +				}
 +			}
 +			else
 +			{
 +				throw new BuildException("'".$this->workingCopy."' is not a directory");
 +			}
 +		}
 +	}
 +	
 +	/**
 +	 * Executes the constructed VersionControl_SVN instance
 +	 *
 +	 * @param array Additional arguments to pass to SVN.
 +	 * @param array Switches to pass to SVN.
 +	 * @return string Output generated by SVN.
 +	 */
 +	protected function run($args = array(), $switches = array())
 +	{
 +		$svnstack = PEAR_ErrorStack::singleton('VersionControl_SVN');
 +		
 +		$tempArgs = $this->svnArgs;
 +		
 +		$tempArgs = array_merge($tempArgs, $args);
 +		
 +		if ($output = $this->svn->run($tempArgs, $switches))
 +		{
 +			return $output;
 +		}
 +		else
 +		{
 +			if (count($errs = $svnstack->getErrors()))
 +			{
 +				$err = current($errs);
 +
 +				throw new BuildException("Failed to run the 'svn " . $this->mode . "' command: " . $err['message']);
 +			}
 +		}
 +	}
 +}
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php new file mode 100644 index 00000000..7cb6c897 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php @@ -0,0 +1,68 @@ +<?php +/** + * $Id: SvnExportTask.php 37 2006-03-09 14:04:22Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/svn/SvnBaseTask.php'; + +/** + * Exports/checks out a repository to a local directory + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: SvnExportTask.php 37 2006-03-09 14:04:22Z mrook $ + * @package phing.tasks.ext.svn + * @see VersionControl_SVN + * @since 2.1.0 + */ +class SvnExportTask extends SvnBaseTask +{ +	private $toDir = ""; + +	/** +	 * Sets the path to export/checkout to +	 */ +	function setToDir($toDir) +	{ +		$this->toDir = $toDir; +	} + +	/** +	 * Returns the path to export/checkout to +	 */ +	function getToDir() +	{ +		return $this->toDir; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$this->setup('export'); +		 +		$this->log("Exporting SVN repository to '" . $this->toDir . "'"); +		 +		$this->run(array($this->toDir)); +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php new file mode 100644 index 00000000..e45ac50c --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php @@ -0,0 +1,75 @@ +<?php +/** + * $Id: SvnLastRevisionTask.php 37 2006-03-09 14:04:22Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/tasks/ext/svn/SvnBaseTask.php'; + +/** + * Stores the number of the last revision of a workingcopy in a property + * + * @author Michiel Rook <michiel@trendserver.nl> + * @version $Id: SvnLastRevisionTask.php 37 2006-03-09 14:04:22Z mrook $ + * @package phing.tasks.ext.svn + * @see VersionControl_SVN + * @since 2.1.0 + */ +class SvnLastRevisionTask extends SvnBaseTask +{ +	private $propertyName = "svn.lastrevision"; + +	/** +	 * Sets the name of the property to use +	 */ +	function setPropertyName($propertyName) +	{ +		$this->propertyName = $propertyName; +	} + +	/** +	 * Returns the name of the property to use +	 */ +	function getPropertyName() +	{ +		return $this->propertyName; +	} + +	/** +	 * The main entry point +	 * +	 * @throws BuildException +	 */ +	function main() +	{ +		$this->setup('info'); +		 +		$output = $this->run(); +		 +		if (preg_match('/Rev:[\s]+([\d]+)/', $output, $matches)) +		{ +			$this->project->setProperty($this->getPropertyName(), $matches[1]); +		} +		else +		{ +			throw new BuildException("Failed to parse the output of 'svn info'."); +		} +	} +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php new file mode 100644 index 00000000..e4c291a1 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php @@ -0,0 +1,88 @@ +<?php +/* + *  $Id: AdhocTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; + +/** + * Abstract class for creating adhoc Phing components in buildfile. + * + * By itself this class can be used to declare a single class within your buildfile. + * You can then reference this class in any task that takes custom classes (selectors, + * mappers, filters, etc.) + *  + * Subclasses exist for conveniently declaring and registering tasks and types. + *  + * @author   Hans Lellelid <hans@xmpl.org> + * @version  $Revision: 1.6 $ + * @package  phing.tasks.system + */ +class AdhocTask extends Task { +             +    /** +     * The PHP script +     * @var string +     */ +    protected $script; +     +    protected $newClasses = array(); +     +    /** +     * Main entry point +     */ +    public function main() {     +        $this->execute();         +        if ($this->newClasses) { +            foreach($this->newClasses as $classname) { +                $this->log("Added adhoc class " . $classname, PROJECT_MSG_VERBOSE); +            } +        } else { +            $this->log("Adhoc task executed but did not result in any new classes.", PROJECT_MSG_VERBOSE); +        } +    } +     +    /** +     * Get array of names of newly defined classes. +     * @return array +     */ +    protected function getNewClasses() { +        return $this->newClasses; +    } +     +    /** +     * Load the adhoc class, and perform any core validation. +     * @return string The classname of the ProjectComponent class. +     * @throws BuildException - if more than one class is defined. +     */ +    protected function execute() { +        $classes = get_declared_classes();         +        eval($this->script);         +        $this->newClasses = array_diff(get_declared_classes(), $classes);         +    } +             +    /** +     * Set the script. +     * @param string $script +     */ +    public function addText($script) { +        $this->script = $script; +    } +            +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php new file mode 100644 index 00000000..ea336f84 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php @@ -0,0 +1,90 @@ +<?php + +/* + * $Id: AdhocTaskdefTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/tasks/system/AdhocTask.php'; + +/** + * A class for creating adhoc tasks in build file. + *  + * <target name="test-adhoc"> + *        <adhoc-task name="foo"><![CDATA[ + * + *            class FooTest extends Task { + *                private $bar; + *                 + *                function setBar($bar) { + *                    $this->bar = $bar; + *                } + *                 + *                function main() { + *                    $this->log("In FooTest: " . $this->bar); + *                } + *            } + * + *        ]]></adhoc-task> + *  + *      <foo bar="B.L.I.N.G"/> + * </target> + *   + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.5 $ + * @package   phing.tasks.system + */ +class AdhocTaskdefTask extends AdhocTask { + +    /** +     * The tag that refers to this task. +     */ +    private $name; +     +    /** +     * Set the tag that will represent this adhoc task/type. +     * @param string $name +     */        +    public function setName($name) { +        $this->name = $name; +    } +     +    /** Main entry point */ +    public function main() {         +        if ($this->name === null) { +            throw new BuildException("The name attribute is required for adhoc task definition.",$this->location); +        } +         +        $this->execute(); +         +        $classes = $this->getNewClasses(); +        if (count($classes) !== 1) { +            throw new BuildException("You must define one (and only one) class for AdhocTaskdefTask."); +        } +        $classname = array_shift($classes); +         +        // instantiate it to make sure it is an instance of Task +        $t = new $classname(); +        if (!($t instanceof Task)) { +            throw new BuildException("The adhoc class you defined must be an instance of phing.Task", $this->location); +        } +         +        $this->log("Task " . $this->name . " will be handled by class " . $classname, PROJECT_MSG_VERBOSE); +        $this->project->addTaskDefinition($this->name, $classname);         +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php new file mode 100644 index 00000000..b836ad93 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php @@ -0,0 +1,71 @@ +<?php + +/* + * $Id: AdhocTypedefTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/tasks/system/AdhocTask.php'; + +/** + * A class for creating adhoc datatypes in build file. + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.4 $ + * @package   phing.tasks.system + */ +class AdhocTypedefTask extends AdhocTask { + +    /** +     * The tag that refers to this task. +     */ +    private $name; + +    /** +     * Set the tag that will represent this adhoc task/type. +     * @param string $name +     */        +    public function setName($name) { +        $this->name = $name; +    } +         +    /** Main entry point */ +    public function main() { +     +        if ($this->name === null) { +            throw new BuildException("The name attribute is required for adhoc task definition.",$this->location); +        } +         +        $this->execute(); +         +        $classes = $this->getNewClasses(); +        if (count($classes) !== 1) { +            throw new BuildException("You must define one (and only one) class for AdhocTypedefTask."); +        } +        $classname = array_shift($classes); +         +        // instantiate it to make sure it is an instance of ProjectComponent +        $t = new $classname(); +        if (!($t instanceof ProjectComponent)) { +            throw new BuildException("The adhoc class you defined must be an instance of phing.ProjectComponent", $this->location); +        } +         +        $this->log("Datatype " . $this->name . " will be handled by class " . $classname, PROJECT_MSG_VERBOSE); +        $this->project->addDataTypeDefinition($this->name, $classname);         +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AppendTask.php b/buildscripts/phing/classes/phing/tasks/system/AppendTask.php new file mode 100644 index 00000000..feb797cf --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AppendTask.php @@ -0,0 +1,240 @@ +<?php +/* + *  $Id: AppendTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/FileList.php'; +include_once 'phing/types/FileSet.php'; + +/** + *  Appends text, contents of a file or set of files defined by a filelist to a destination file. + * + * <code> + * <append text="And another thing\n" destfile="badthings.log"/> + * </code> + * OR + * <code> + * <append file="header.html" destfile="fullpage.html"/> + * <append file="body.html" destfile="fullpage.html"/> + * <append file="footer.html" destfile="fullpage.html"/> + * </code> + * OR + * <code> + * <append destfile="${process.outputfile}"> + *    <filterchain> + *        <xsltfilter style="${process.stylesheet}"> + *            <param name="mode" expression="${process.xslt.mode}"/> + *            <param name="file_name" expression="%{task.append.current_file.basename}"/> <!-- Example of using a RegisterSlot variable --> + *        </xsltfilter> + *    </filterchain> + *     <filelist dir="book/" listfile="book/PhingGuide.book"/>             + * </append> + * </code> + * @package phing.tasks.system + * @version $Revision: 1.14 $ + */ +class AppendTask extends Task { +     +    /** Append stuff to this file. */ +    private $to; +     +    /** Explicit file to append. */ +    private $file; +     +    /** Any filesets of files that should be appended. */ +    private $filesets = array(); +     +    /** Any filelists of files that should be appended. */ +    private $filelists = array(); +     +    /** Any filters to be applied before append happens. */ +    private $filterChains = array(); +     +    /** Text to append. (cannot be used in conjunction w/ files or filesets) */ +    private $text; +     +    /** Sets specific file to append. */ +    function setFile(PhingFile $f) {         +        $this->file = $f; +    } +     +    /** +     * Set target file to append to. +     * @deprecated Will be removed with final release. +     */ +    function setTo(PhingFile $f) {         +        $this->log("The 'to' attribute is deprecated in favor of 'destFile'; please update your code.", PROJECT_MSG_WARN); +        $this->to = $f; +    } +     +    /** +     * The more conventional naming for method to set destination file. +     * @param PhingFile $f +     */ +    function setDestFile(PhingFile $f) {         +        $this->to = $f; +    } +     +    /** +     * Supports embedded <filelist> element. +     * @return FileList +     */ +    function createFileList() { +        $num = array_push($this->filelists, new FileList()); +        return $this->filelists[$num-1]; +    } + +    /** +     * Nested creator, adds a set of files (nested <fileset> attribute). +     * This is for when you don't care what order files get appended. +     * @return FileSet +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } +     +    /** +     * Creates a filterchain +     * +     * @return FilterChain The created filterchain object +     */ +    function createFilterChain() { +        $num = array_push($this->filterChains, new FilterChain($this->project)); +        return $this->filterChains[$num-1]; +    }     +     +    /** +     * Sets text to append.  (cannot be used in conjunction w/ files or filesets). +     * @param string $txt +     */ +    function setText($txt) { +        $this->text = (string) $txt; +    } + +    /** +     * Sets text to append. Supports CDATA. +     * @param string $txt +     */ +    function addText($txt) { +        $this->text = (string) $txt; +    } + +     +    /** Append the file(s). */ +    function main() { +     +        if ($this->to === null) { +            throw new BuildException("You must specify the 'destFile' attribute"); +        } +         +        if ($this->file === null && empty($this->filelists) && empty($this->filesets) && $this->text === null) { +            throw new BuildException("You must specify a file, use a filelist, or specify a text value."); +        } +         +        if ($this->text !== null && ($this->file !== null || !empty($this->filelists))) { +            throw new BuildException("Cannot use text attribute in conjunction with file or filelists."); +        } +         +        // create a filwriter to append to "to" file. +        $writer = new FileWriter($this->to, $append=true); +         +        if ($this->text !== null) {             +             +            // simply append the text +            $this->log("Appending string to " . $this->to->getPath()); +             +            // for debugging primarily, maybe comment +            // out for better performance(?) +            $lines = explode("\n", $this->text); +            foreach($lines as $line) { +                $this->log($line, PROJECT_MSG_VERBOSE); +            } +             +            $writer->write($this->text); +                         +        } else {         +             +            // append explicitly-specified file +            if ($this->file !== null) {  +                try { +                    $this->appendFile($writer, $this->file); +                } catch (Exception $ioe) { +                    $this->log("Unable to append contents of file " . $this->file->getAbsolutePath() . ": " . $ioe->getMessage(), PROJECT_MSG_WARN); +                }                 +            } +             +            // append the files in the filelists +            foreach($this->filelists as $fl) { +                try { +                    $files = $fl->getFiles($this->project); +                    $this->appendFiles($writer, $files, $fl->getDir($this->project)); +                } catch (BuildException $be) { +                    $this->log($be->getMessage(), PROJECT_MSG_WARN); +                } +            } +             +            // append any files in filesets +            foreach($this->filesets as $fs) { +                try { +                    $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles(); +                    $this->appendFiles($writer, $files, $fs->getDir($this->project)); +                } catch (BuildException $be) { +                    $this->log($be->getMessage(), PROJECT_MSG_WARN); +                } +            }                         +             +        } // if ($text ) {} else {} +         +        $writer->close(); +    } +     +    /** +     * Append an array of files in a directory. +     * @param FileWriter $writer The FileWriter that is appending to target file. +     * @param array $files array of files to delete; can be of zero length +     * @param PhingFile $dir directory to work from +     */ +    private function appendFiles(FileWriter $writer, $files, PhingFile $dir) { +        if (!empty($files)) { +            $this->log("Attempting to append " . count($files) . " files" .($dir !== null ? ", using basedir " . $dir->getPath(): "")); +            $basenameSlot = Register::getSlot("task.append.current_file"); +            $pathSlot = Register::getSlot("task.append.current_file.path"); +            foreach($files as $filename) { +                try { +                    $f = new PhingFile($dir, $filename); +                    $basenameSlot->setValue($filename); +                    $pathSlot->setValue($f->getPath()); +                    $this->appendFile($writer, $f); +                } catch (Exception $ioe) { +                    $this->log("Unable to append contents of file " . $f->getAbsolutePath() . ": " . $ioe->getMessage(), PROJECT_MSG_WARN); +                } +            } +        } // if !empty         +    } +     +    private function appendFile(FileWriter $writer, PhingFile $f) { +        $in = FileUtils::getChainedReader(new FileReader($f), $this->filterChains, $this->project); +        while(-1 !== ($buffer = $in->read())) { // -1 indicates EOF +            $writer->write($buffer); +        } +        $this->log("Appending contents of " . $f->getPath() . " to " . $this->to->getPath());     +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php b/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php new file mode 100644 index 00000000..76de3e40 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php @@ -0,0 +1,132 @@ +<?php +/* + *  $Id: AvailableTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  <available> task. + * + *  Note: implements condition interface (see condition/Condition.php) + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.11 $ + *  @package   phing.tasks.system + */ +class AvailableTask extends Task { + +    /** Property to check for. */ +    private $property; +     +    /** Value property should be set to. */ +    private $value = "true"; +     +    /** Resource to check for */ +    private $resource; +     +    private $type = null; +    private $filepath = null; + +    function setProperty($property) { +        $this->property = (string) $property; +    } + +    function setValue($value) { +        $this->value = (string) $value; +    } + +    function setFile(PhingFile $file) { +        $this->file = $file; +    } + +    function setResource($resource) { +        $this->resource = (string) $resource; +    } + +    function setType($type) { +        $this->type = (string) strtolower($type); +    } + +    function main() { +        if ($this->property === null) { +            throw new BuildException("property attribute is required", $this->location); +        } +        if ($this->evaluate()) { +            $this->project->setProperty($this->property, $this->value); +        } +    } + +    function evaluate() { +        if ($this->file === null && $this->resource === null) { +            throw new BuildException("At least one of (file|resource) is required", $this->location);             +        } + +        if ($this->type !== null && ($this->type !== "file" && $this->type !== "dir")) { +            throw new BuildException("Type must be one of either dir or file", $this->location); +        } +         +        if (($this->file !== null) && !$this->_checkFile()) { +            $this->log("Unable to find " . $this->file->__toString() . " to set property " . $this->property, PROJECT_MSG_VERBOSE); +            return false; +        } + +        if (($this->resource !== null) && !$this->_checkResource($this->resource)) { +            $this->log("Unable to load resource " . $this->resource . " to set property " . $this->property, PROJECT_MSG_VERBOSE); +            return false; +        } + +        return true; +    } + +    // this is prepared for the path type +    function _checkFile() { +        if ($this->filepath === null) { +            return $this->_checkFile1($this->file); +        } else { +            $paths = $this->filepath->listDir(); +            for($i=0,$pcnt=count($paths); $i < $pcnt; $i++) { +                $this->log("Searching " . $paths[$i], PROJECT_MSG_VERBOSE); +                $tmp = new PhingFile($paths[$i], $this->file->getName()); +                if($tmp->isFile()) { +                    return true; +                } +            } +        } +        return false; +    } + +    function _checkFile1($file) { +        if ($this->type !== null) { +            if ($this->type === "dir") { +                return $file->isDirectory(); +            } else if ($this->type === "file") { +                return $file->isFile(); +            } +        } +        return $file->exists(); +    } + +    function _checkResource($resource) { +        return $this->_checkFile1(new PhingFile(Phing::getResourcePath($resource))); +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php new file mode 100644 index 00000000..80470dea --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php @@ -0,0 +1,177 @@ +<?php +/* + *  $Id: ChmodTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/types/FileSet.php'; + +/** + * Task that changes the permissions on a file/directory. + * + * @author    Manuel Holtgrewe <grin@gmx.net> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.12 $ + * @package   phing.tasks.system + */ +class ChmodTask extends Task { + +    private $file; + +    private $mode; + +    private $filesets = array(); + +    private $filesystem; +	 +	private $quiet = false;	 +	private $failonerror = true; +	 +	/** +	 * This flag means 'note errors to the output, but keep going' +	 * @see setQuiet() +	 */ +    function setFailonerror($bool) { +        $this->failonerror = $bool; +    }	 + +    /** +     * Set quiet mode, which suppresses warnings if chmod() fails. +	 * @see setFailonerror() +     */ +    function setQuiet($bool) { +        $this->quiet = $bool; +        if ($this->quiet) { +            $this->failonerror = false; +        } +    } +	 +    /** +     * Sets a single source file to touch.  If the file does not exist +     * an empty file will be created. +     */ +    function setFile(PhingFile $file) {         +        $this->file = $file; +    }  + +    function setMode($str) { +        $this->mode = $str; +    } + +    /** +     * Nested creator, adds a set of files (nested fileset attribute). +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +    /** +     * Execute the touch operation. +     * @return void +     */ +    function main() { +        // Check Parameters +        $this->checkParams();        +        $this->chmod(); +    } +     +    /** +     * Ensure that correct parameters were passed in. +     * @return void +     */ +    private function checkParams() { +     +        if ($this->file === null && empty($this->filesets)) { +            throw new BuildException("Specify at least one source - a file or a fileset."); +        } + +        if ($this->mode === null) { +            throw new BuildException("You have to specify an octal mode for chmod."); +        } + +        // check for mode to be in the correct format +        if (!preg_match('/^([0-7]){3,4}$/', $this->mode)) { +            throw new BuildException("You have specified an invalid mode."); +        } +      +    } + +    /** +     * Does the actual work. +     * @return void +     */ +    private function chmod() { +    	 +		if (strlen($this->mode) === 4) { +			$mode = octdec($this->mode); +		} else { +			// we need to prepend the 0 before converting +			$mode = octdec("0". $this->mode); +		} +         +        // one file +        if ($this->file !== null) { +            $this->chmodFile($this->file, $mode); +        } + +        // filesets +        foreach($this->filesets as $fs) { +                     +            $ds = $fs->getDirectoryScanner($this->project); +            $fromDir = $fs->getDir($this->project); + +            $srcFiles = $ds->getIncludedFiles(); +            $srcDirs = $ds->getIncludedDirectories(); + +            for ($j = 0, $filecount = count($srcFiles); $j < $filecount; $j++) { +                $this->chmodFile(new PhingFile($fromDir, $srcFiles[$j]), $mode); +            } + +            for ($j = 0, $dircount = count($srcDirs); $j <  $dircount; $j++) { +                $this->chmodFile(new PhingFile($fromDir, $srcDirs[$j]), $mode); +            } +        } + +    } + +	/** +	 * Actually change the mode for the file. +	 * @param PhingFile $file +	 * @param int $mode +	 */ +    private function chmodFile(PhingFile $file, $mode) { +        if ( !$file->exists() ) { +            throw new BuildException("The file " . $file->__toString() . " does not exist"); +        }    +		      +		try { +			$file->setMode($mode); +			$this->log("Changed file mode on '" . $file->__toString() ."' to " . vsprintf("%o", $mode)); +		} catch (Exception $e) { +			if($this->failonerror) { +				throw $e; +			} else { +				$this->log($e->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +			} +		} +    } +	 +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php b/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php new file mode 100644 index 00000000..fe6ee60b --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php @@ -0,0 +1,74 @@ +<?php +/* + *  $Id: ConditionTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  <condition> task as a generalization of <available> + * + *  <p>This task supports boolean logic as well as pluggable conditions + *  to decide, whether a property should be set.</p> + * + *  <p>This task does not extend Task to take advantage of + *  ConditionBase.</p> + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.7 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @access    public + *  @package   phing.tasks.system + */ +class ConditionTask extends ConditionBase { + +    private $property; +    private $value = "true"; + +    /** +     * The name of the property to set. Required. +     */ +    function setProperty($p) { +        $this->property = $p; +    } + +    /** +     * The value for the property to set. Defaults to "true". +     */ +    function setValue($v) { +        $this->value = $v; +    } + +    /** +     * See whether our nested condition holds and set the property. +     */ +    function main() { + +        if ($this->countConditions() > 1) { +            throw new BuildException("You must not nest more than one condition into <condition>"); +        } +        if ($this->countConditions() < 1) { +            throw new BuildException("You must nest a condition into <condition>"); +        } +        $cs = $this->getIterator();         +        if ($cs->current()->evaluate()) { +            $this->project->setProperty($this->property, $this->value); +        } +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CopyTask.php b/buildscripts/phing/classes/phing/tasks/system/CopyTask.php new file mode 100644 index 00000000..c5e4c2a5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CopyTask.php @@ -0,0 +1,401 @@ +<?php +/* + *  $Id: CopyTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/IdentityMapper.php'; +include_once 'phing/mappers/FlattenMapper.php'; + +/** + * A phing copy task.  Copies a file or directory to a new file + * or directory.  Files are only copied if the source file is newer + * than the destination file, or when the destination file does not + * exist. It is possible to explictly overwrite existing files. + * + * @author   Andreas Aderhold, andi@binarycloud.com + * @version  $Revision: 1.16 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @package  phing.tasks.system + */ +class CopyTask extends Task { + +    protected $file          = null;   // the source file (from xml attribute) +    protected $destFile      = null;   // the destiantion file (from xml attribute) +    protected $destDir       = null;   // the destination dir (from xml attribute) +    protected $overwrite     = false;  // overwrite destination (from xml attribute) +    protected $preserveLMT   = true;   // sync timestamps (from xml attribute) +    protected $includeEmpty  = true;   // include empty dirs? (from XML) +    protected $flatten       = false;  // apply the FlattenMapper right way (from XML) +    protected $mapperElement = null; + +    protected $fileCopyMap   = array(); // asoc array containing mapped file names +    protected $dirCopyMap    = array(); // asoc array containing mapped file names +    protected $fileUtils     = null;    // a instance of fileutils +    protected $filesets      = array(); // all fileset objects assigned to this task +    protected $filterChains  = array(); // all filterchains objects assigned to this task + +    protected $verbosity     = PROJECT_MSG_VERBOSE; + +    /** +     * Sets up this object internal stuff. i.e. the Fileutils instance +     * +     * @return object   The CopyTask instnace +     * @access public +     */ +    function __construct() { +        $this->fileUtils = new FileUtils(); +    } + +    /** +     * Set the overwrite flag. IntrospectionHelper takes care of +     * booleans in set* methods so we can assume that the right +     * value (boolean primitive) is coming in here. +     * +     * @param  boolean  Overwrite the destination file(s) if it/they already exist +     * @return void +     * @access public +     */ +    function setOverwrite($bool) { +        $this->overwrite = (boolean) $bool; +    } + +    /** +     * Used to force listing of all names of copied files. +     * @param boolean $verbosity +     */ +    function setVerbose($verbosity) { +        if ($verbosity) { +            $this->verbosity = PROJECT_MSG_INFO; +        } else { +            $this->verbosity = PROJECT_MSG_VERBOSE; +        } +    } + +    /** +     * Set the preserve timestmap flag. IntrospectionHelper takes care of +     * booleans in set* methods so we can assume that the right +     * value (boolean primitive) is coming in here. +     * +     * @param  boolean  Preserve the timestamp on the destination file +     * @return void +     * @access public +     */ +    function setTstamp($bool) { +        $this->preserveLMT = (boolean) $bool; +    } + + +    /** +     * Set the include empty dirs flag. IntrospectionHelper takes care of +     * booleans in set* methods so we can assume that the right +     * value (boolean primitive) is coming in here. +     * +     * @param  boolean  Flag if empty dirs should be cpoied too +     * @return void +     * @access public +     */ +    function setIncludeEmptyDirs($bool) { +        $this->includeEmpty = (boolean) $bool; +    } + + +    /** +     * Set the file. We have to manually take care of the +     * type that is coming due to limited type support in php +     * in and convert it manually if neccessary. +     * +     * @param  string/object  The source file. Either a string or an PhingFile object +     * @return void +     * @access public +     */ +    function setFile(PhingFile $file) { +        $this->file = $file; +    } + + +    /** +     * Set the toFile. We have to manually take care of the +     * type that is coming due to limited type support in php +     * in and convert it manually if neccessary. +     * +     * @param  string/object  The dest file. Either a string or an PhingFile object +     * @return void +     * @access public +     */ +    function setTofile(PhingFile $file) { +        $this->destFile = $file; +    } + + +    /** +     * Set the toDir. We have to manually take care of the +     * type that is coming due to limited type support in php +     * in and convert it manually if neccessary. +     * +     * @param  string/object  The directory, either a string or an PhingFile object +     * @return void +     * @access public +     */ +    function setTodir(PhingFile $dir) { +        $this->destDir = $dir; +    } + +    /** +     * Nested creator, creates a FileSet for this task +     * +     * @access  public +     * @return  object  The created fileset object +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +    /** +     * Creates a filterchain +     * +     * @access public +     * @return  object  The created filterchain object +     */ +    function createFilterChain() { +        $num = array_push($this->filterChains, new FilterChain($this->project)); +        return $this->filterChains[$num-1]; +    } + +    /** +     * Nested creator, creates one Mapper for this task +     * +     * @access  public +     * @return  object  The created Mapper type object +     * @throws  BuildException +     */ +    function createMapper() { +        if ($this->mapperElement !== null) { +            throw new BuildException("Cannot define more than one mapper", $this->location); +        } +        $this->mapperElement = new Mapper($this->project); +        return $this->mapperElement; +    } + +    /** +     * The main entry point where everything gets in motion. +     * +     * @access  public +     * @return  true on success +     * @throws  BuildException +     */ +    function main() { + +        $this->validateAttributes(); + +        if ($this->file !== null) { +            if ($this->file->exists()) { +                if ($this->destFile === null) { +                    $this->destFile = new PhingFile($this->destDir, (string) $this->file->getName()); +                } +                if ($this->overwrite === true || ($this->file->lastModified() > $this->destFile->lastModified())) { +                    $this->fileCopyMap[$this->file->getAbsolutePath()] = $this->destFile->getAbsolutePath(); +                } else { +                    $this->log($this->file->getName()." omitted, is up to date"); +                } +            } else { +                // terminate build +                throw new BuildException("Could not find file " . $this->file->__toString() . " to copy."); +            } +        } + +        $project = $this->getProject(); + +        // process filesets +        foreach($this->filesets as $fs) { +            $ds = $fs->getDirectoryScanner($project); +            $fromDir  = $fs->getDir($project); +            $srcFiles = $ds->getIncludedFiles(); +            $srcDirs  = $ds->getIncludedDirectories(); +            $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs); +        } + +        // go and copy the stuff +        $this->doWork(); + +        if ($this->destFile !== null) { +            $this->destDir = null; +        } +    } + +    /** +     * Validates attributes coming in from XML +     * +     * @access  private +     * @return  void +     * @throws  BuildException +     */ +    private function validateAttributes() { + +        if ($this->file === null && count($this->filesets) === 0) { +            throw new BuildException("CopyTask. Specify at least one source - a file or a fileset."); +        } + +        if ($this->destFile !== null && $this->destDir !== null) { +            throw new BuildException("Only one of destfile and destdir may be set."); +        } + +        if ($this->destFile === null && $this->destDir === null) { +            throw new BuildException("One of destfile or destdir must be set."); +        } + +        if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) { +            throw new BuildException("Use a fileset to copy directories."); +        } + +        if ($this->destFile !== null && count($this->filesets) > 0) { +            throw new BuildException("Cannot concatenate multple files into a single file."); +        } + +        if ($this->destFile !== null) { +            $this->destDir = new PhingFile($this->destFile->getParent()); +        } +    } + +    /** +     * Compares source files to destination files to see if they +     * should be copied. +     * +     * @access  private +     * @return  void +     */ +    private function _scan(&$fromDir, &$toDir, &$files, &$dirs) { +        /* mappers should be generic, so we get the mappers here and +        pass them on to builMap. This method is not redundan like it seems */ +        $mapper = null; +        if ($this->mapperElement !== null) { +            $mapper = $this->mapperElement->getImplementation(); +        } else if ($this->flatten) { +            $mapper = new FlattenMapper(); +        } else { +            $mapper = new IdentityMapper(); +        } +        $this->buildMap($fromDir, $toDir, $files, $mapper, $this->fileCopyMap); +		$this->buildMap($fromDir, $toDir, $dirs, $mapper, $this->dirCopyMap); +    } + +    /** +     * Builds a map of filenames (from->to) that should be copied +     * +     * @access  private +     * @return  void +     */ +    private function buildMap(&$fromDir, &$toDir, &$names, &$mapper, &$map) { +        $toCopy = null; +        if ($this->overwrite) { +            $v = array(); +            foreach($names as $name) { +                $result = $mapper->main($name); +                if ($result !== null) { +                    $v[] = $name; +                } +            } +            $toCopy = $v; +        } else { +            $ds = new SourceFileScanner($this); +            $toCopy = $ds->restrict($names, $fromDir, $toDir, $mapper); +        } + +        for ($i=0,$_i=count($toCopy); $i < $_i; $i++) { +            $src  = new PhingFile($fromDir, $toCopy[$i]); +            $mapped = $mapper->main($toCopy[$i]); +            $dest = new PhingFile($toDir, $mapped[0]); +            $map[$src->getAbsolutePath()] = $dest->getAbsolutePath(); +        } +    } + + +    /** +     * Actually copies the files +     * +     * @access  private +     * @return  void +     * @throws  BuildException +     */ +    private function doWork() { + +		// These "slots" allow filters to retrieve information about the currently-being-process files +		$fromSlot = $this->getRegisterSlot("currentFromFile"); +		$fromBasenameSlot = $this->getRegisterSlot("currentFromFile.basename"); + +		$toSlot = $this->getRegisterSlot("currentToFile"); +		$toBasenameSlot = $this->getRegisterSlot("currentToFile.basename"); + +        $mapSize = count($this->fileCopyMap); +        $total = $mapSize; +        if ($mapSize > 0) { +            $this->log("Copying ".$mapSize." file".(($mapSize) === 1 ? '' : 's')." to ". $this->destDir->getAbsolutePath()); +            // walks the map and actually copies the files +            $count=0; +            foreach($this->fileCopyMap as $from => $to) { +                if ($from === $to) { +                    $this->log("Skipping self-copy of " . $from, $this->verbosity); +                    $total--; +                    continue; +                } +                $this->log("From ".$from." to ".$to, $this->verbosity); +                try { // try to copy file + +					$fromFile = new PhingFile($from); +					$toFile = new PhingFile($to); + +                    $fromSlot->setValue($fromFile->getPath()); +					$fromBasenameSlot->setValue($fromFile->getName()); + +					$toSlot->setValue($toFile->getPath()); +					$toBasenameSlot->setValue($toFile->getName()); + +                    $this->fileUtils->copyFile($fromFile, $toFile, $this->overwrite, $this->preserveLMT, $this->filterChains, $this->getProject()); + +                    $count++; +                } catch (IOException $ioe) { +                    $this->log("Failed to copy " . $from . " to " . $to . ": " . $ioe->getMessage(), PROJECT_MSG_ERR); +                } +            } +        } + +        // handle empty dirs if appropriate +        if ($this->includeEmpty) { +            $e = array_values($this->dirCopyMap); +            $count = 0; +            foreach ($e as $dir) { +                $d = new PhingFile((string) $dir); +                if (!$d->exists()) { +                    if (!$d->mkdirs()) { +                        $this->log("Unable to create directory " . $d->__toString(), PROJECT_MSG_ERR); +                    } else { +                        $count++; +                    } +                } +            } +            if ($count > 0) { +                $this->log("Copied ".$count." empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath()); +            } +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php new file mode 100644 index 00000000..0003c50f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php @@ -0,0 +1,173 @@ +<?php +/* + *  $Id: CvsPassTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/BufferedWriter.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * Adds an new entry to a CVS password file. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Jeff Martin <jeff@custommonkey.org> (Ant) + * @version $Revision: 1.7 $ + * @package phing.tasks.system + */ +class CVSPassTask extends Task { + +    /** CVS Root */ +    private $cvsRoot;  +    /** Password file to add password to */ +    private $passFile; +    /** Password to add to file */ +    private $password; + +    /** Array contain char conversion data */ +    private static $shifts = array( +          0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,  15, +         16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31, +        114, 120,  53,  79,  96, 109,  72, 108,  70,  64,  76,  67, 116,  74,  68,  87, +        111,  52,  75, 119,  49,  34,  82,  81,  95,  65, 112,  86, 118, 110, 122, 105, +         41,  57,  83,  43,  46, 102,  40,  89,  38, 103,  45,  50,  42, 123,  91,  35, +        125,  55,  54,  66, 124, 126,  59,  47,  92,  71, 115,  78,  88, 107, 106,  56, +         36, 121, 117, 104, 101, 100,  69,  73,  99,  63,  94,  93,  39,  37,  61,  48, +         58, 113,  32,  90,  44,  98,  60,  51,  33,  97,  62,  77,  84,  80,  85, 223, +        225, 216, 187, 166, 229, 189, 222, 188, 141, 249, 148, 200, 184, 136, 248, 190, +        199, 170, 181, 204, 138, 232, 218, 183, 255, 234, 220, 247, 213, 203, 226, 193, +        174, 172, 228, 252, 217, 201, 131, 230, 197, 211, 145, 238, 161, 179, 160, 212, +        207, 221, 254, 173, 202, 146, 224, 151, 140, 196, 205, 130, 135, 133, 143, 246, +        192, 159, 244, 239, 185, 168, 215, 144, 139, 165, 180, 157, 147, 186, 214, 176, +        227, 231, 219, 169, 175, 156, 206, 198, 129, 164, 150, 210, 154, 177, 134, 127, +        182, 128, 158, 208, 162, 132, 167, 209, 149, 241, 153, 251, 237, 236, 171, 195, +        243, 233, 253, 240, 194, 250, 191, 155, 142, 137, 245, 235, 163, 242, 178, 152  +    ); + +    /** +     * Create a CVS task using the default cvspass file location. +     */ +    public function __construct() { +        $this->passFile = new PhingFile( +            Phing::getProperty("cygwin.user.home", +                Phing::getProperty("user.home")) +            . DIRECTORY_SEPARATOR . ".cvspass"); +    } + +    /** +     * Does the work. +     * +     * @throws BuildException if someting goes wrong with the build +     */ +    public final function main() { +        if ($this->cvsRoot === null) { +            throw new BuildException("cvsroot is required"); +        } +        if ($this->password === null) { +            throw new BuildException("password is required"); +        } + +        $this->log("cvsRoot: " . $this->cvsRoot, PROJECT_MSG_DEBUG); +        $this->log("password: " . $this->password, PROJECT_MSG_DEBUG); +        $this->log("passFile: " . $this->passFile->__toString(), PROJECT_MSG_DEBUG); + +        $reader = null; +        $writer = null; +         +        try { +            $buf = ""; + +            if ($this->passFile->exists()) { +                $reader = new BufferedReader(new FileReader($this->passFile)); +                 +                $line = null; +                while (($line = $reader->readLine()) !== null) { +                    if (!StringHelper::startsWith($this->cvsRoot, $line)) { +                        $buf .= $line . Phing::getProperty("line.separator"); +                    } +                } +            } + +            $pwdfile = $buf . $this->cvsRoot . " A" . $this->mangle($this->password); + +            $this->log("Writing -> " . $pwdfile , PROJECT_MSG_DEBUG); + +            $writer = new BufferedWriter(new FileWriter($this->passFile)); +            $writer->write($pwdfile); +            $writer->newLine(); +             +            $writer->close(); +            if ($reader) { +                $reader->close(); +            } +                         +        } catch (IOException $e) { +            if ($reader) { +                try { +                    $reader->close(); +                } catch (Exception $e) {}                 +            } +             +            if ($writer) { +                try { +                    $writer->close(); +                } catch (Exception $e) {}                 +            } +             +            throw new BuildException($e); +        } +    } +     +    /** +     * "Encode" the password. +     */ +    private final function mangle($password){ +        $buf = ""; +        for ($i = 0, $plen = strlen($password); $i < $plen; $i++) { +            $buf .= chr(self::$shifts[ord($password{$i})]); +        } +        return $buf; +    } + +    /** +     * The CVS repository to add an entry for. +     * @param string $cvsRoot +     */ +    public function setCvsroot($cvsRoot) { +        $this->cvsRoot = $cvsRoot; +    } + +    /** +     * Password file to add the entry to. +     * @param PhingFile $passFile +     */ +    public function setPassfile(PhingFile $passFile) { +        $this->passFile = $passFile; +    } + +    /** +     * Password to be added to the password file. +     * @param string $password +     */ +    public function setPassword($password) { +        $this->password = $password; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/CvsTask.php b/buildscripts/phing/classes/phing/tasks/system/CvsTask.php new file mode 100644 index 00000000..de2950ec --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/CvsTask.php @@ -0,0 +1,540 @@ +<?php +/* + *  $Id: CvsTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/ExecTask.php'; +include_once 'phing/types/Commandline.php'; + +/** + * Task for performing CVS operations. + *  + *  NOTE: This implementation has been moved here from Cvs.java with + *  the addition of some accessors for extensibility.  Another task + *  can extend this with some customized output processing. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author costin@dnt.ro (Ant) + * @author stefano@apache.org (Ant) + * @author Wolfgang Werner <wwerner@picturesafe.de> (Ant) + * @author Kevin Ross <kevin.ross@bredex.com> (Ant) + * @version $Revision: 1.14 $ + * @package phing.tasks.system + */ +class CvsTask extends Task { + +    /**  +     * Default compression level to use, if compression is enabled via +     * setCompression( true ).  +     */ +    const DEFAULT_COMPRESSION_LEVEL = 3; + +    private $cmd; + +    /**  +     * List of Commandline children  +     * @var array Commandline[] +     */ +    private $commandlines = array(); + +    /** +     * the CVSROOT variable. +     */ +    private $cvsRoot; + +    /** +     * the CVS_RSH variable. +     */ +    private $cvsRsh; + +    /** +     * the package/module to check out. +     */ +    private $cvsModule; + +    /** +     * the default command. +     */ +    private static $default_command = "checkout"; +     +    /** +     * the CVS command to execute. +     */ +    private $command = null; + +    /** +     * suppress information messages. +     */ +    private $quiet = false; + +    /** +     * compression level to use. +     */ +    private $compression = 0; + +    /** +     * report only, don't change any files. +     */ +    private $noexec = false; + +    /** +     * CVS port +     */ +    private $port = 0; + +    /** +     * CVS password file +     * @var File +     */ +    private $passFile = null; + +    /** +     * the directory where the checked out files should be placed. +     * @var File +     */ +    private $dest; +    +    private $error; +     +    private $output; +    +    /** +     * If true it will stop the build if cvs exits with error. +     * Default is false. (Iulian) +     * @var boolean +     */ +    private $failOnError = false; +   +    public function init() { +        $this->cmd = new Commandline(); +    } +     +    /** +     * Sets up the environment for toExecute and then runs it. +     * @param Commandline $toExecute +     * @throws BuildException +     */ +    protected function runCommand(Commandline $toExecute) { +     +        // We are putting variables into the script's environment +        // and not removing them (!)  This should be fine, but is  +        // worth remembering and testing. +             +        if ($this->port > 0) { +            putenv("CVS_CLIENT_PORT=".$this->port); +        } +         +         // Need a better cross platform integration with <cvspass>, so +         // use the same filename. + +        if ($this->passFile === null) { +            $defaultPassFile = new PhingFile(Phing::getProperty("cygwin.user.home", Phing::getProperty("user.home"))  +                . DIRECTORY_SEPARATOR . ".cvspass"); +            if($defaultPassFile->exists()) { +                $this->setPassfile($defaultPassFile); +            } +        } + +        if ($this->passFile !== null) { +            if ($this->passFile->isFile() && $this->passFile->canRead()) {             +                putenv("CVS_PASSFILE=" . $this->passFile->__toString()); +                $this->log("Using cvs passfile: " . $this->passFile->__toString(), PROJECT_MSG_INFO); +            } elseif (!$this->passFile->canRead()) { +                $this->log("cvs passfile: " . $this->passFile->__toString()  +                    . " ignored as it is not readable", PROJECT_MSG_WARN); +            } else { +                $this->log("cvs passfile: " . $this->passFile->__toString()  +                    . " ignored as it is not a file", +                    PROJECT_MSG_WARN); +            } +        } + +        if ($this->cvsRsh !== null) { +            putenv("CVS_RSH=".$this->cvsRsh); +        } + +        // Use the ExecTask to handle execution of the command         +        $exe = new ExecTask($this->project); +        $exe->setProject($this->project); +         +        //exe.setAntRun(project); +        if ($this->dest === null) { +            $this->dest = $this->project->getBaseDir(); +        } + +        if (!$this->dest->exists()) { +            $this->dest->mkdirs(); +        } +         +        if ($this->output !== null) { +            $exe->setOutput($this->output); +        } + +        if ($this->error !== null) { +            $exe->setError($this->error); +        } +         +        $exe->setDir($this->dest); +         +        if (is_object($toExecute)) { +            $toExecuteStr = $toExecute->__toString(); // unfortunately no more automagic for initial 5.0.0 release :( +        } +         +        $exe->setCommand($toExecuteStr); +         +        try { +            $actualCommandLine = $toExecuteStr; // we converted to string above +            $this->log($actualCommandLine, PROJECT_MSG_INFO); +            $retCode = $exe->execute(); +            $this->log("retCode=" . $retCode, PROJECT_MSG_DEBUG); +            /*Throw an exception if cvs exited with error. (Iulian)*/ +            if ($this->failOnError && $retCode !== 0) { +                throw new BuildException("cvs exited with error code " +                                         . $retCode  +                                         . Phing::getProperty("line.separator") +                                         . "Command line was [" +                                         . $toExecute->describeCommand() . "]", $this->getLocation()); +            } +        } catch (IOException $e) { +            if ($this->failOnError) { +                throw new BuildException($e, $this->getLocation()); +            } else { +                $this->log("Caught exception: " . $e, PROJECT_MSG_WARN); +            } +        } catch (BuildException $e) { +            if ($this->failOnError) { +                throw $e; +            } else { +                $t = $e->getCause(); +                if ($t === null) { +                    $t = $e; +                } +                $this->log("Caught exception: " . $t, PROJECT_MSG_WARN); +            } +        } catch (Exception $e) { +            if ($this->failOnError) { +                throw new BuildException($e, $this->getLocation()); +            } else { +                $this->log("Caught exception: " . $e, PROJECT_MSG_WARN); +            } +        } +    } + +    /** +     *  +     * @return void +     * @throws BuildException +     */ +    public function main() { + +        $savedCommand = $this->getCommand(); + +        if ($this->getCommand() === null && empty($this->commandlines)) { +            // re-implement legacy behaviour: +            $this->setCommand(self::$default_command); +        } + +        $c = $this->getCommand(); +        $cloned = null; +        if ($c !== null) { +            $cloned = $this->cmd->__copy(); +            $cloned->createArgument(true)->setLine($c); +            $this->addConfiguredCommandline($cloned, true); +        } + +        try { +            for ($i = 0, $vecsize=count($this->commandlines); $i < $vecsize; $i++) { +                $this->runCommand($this->commandlines[$i]); +            } +             +            // finally    { +            if ($cloned !== null) { +                $this->removeCommandline($cloned); +            } +            $this->setCommand($savedCommand); +             +        } catch (Exception $e) { +            // finally { +            if ($cloned !== null) { +                $this->removeCommandline($cloned); +            } +            $this->setCommand($savedCommand); +            throw $e; +        } +    } + +    /** +     * The CVSROOT variable. +     * +     * @param string $root +     */ +    public function setCvsRoot($root) { + +        // Check if not real cvsroot => set it to null +        if ($root !== null) { +            if (trim($root) == "") { +                $root = null; +            } +        } + +        $this->cvsRoot = $root; +    } + +    public function getCvsRoot() { +        return $this->cvsRoot; +    } + +    /** +     * The CVS_RSH variable. +     * +     * @param rsh +     */ +    public function setCvsRsh($rsh) { +        // Check if not real cvsrsh => set it to null +        if ($rsh !== null) { +            if (trim($rsh) == "") { +                $rsh = null; +            } +        } + +        $this->cvsRsh = $rsh; +    } + +    public function getCvsRsh() { +        return $this->cvsRsh; +    } + +    /** +     * Port used by CVS to communicate with the server. +     * +     * @param int $port +     */ +    public function setPort($port){ +        $this->port = $port; +    } + +    /** +     * @return int +     */ +    public function getPort() { +        return $this->port; +    } + +    /** +     * Password file to read passwords from. +     * +     * @param passFile +     */ +    public function setPassfile(PhingFile $passFile) { +        $this->passFile = $passFile; +    } +     +    /** +     * @return File +     */ +    public function getPassFile() { +        return $this->passFile; +    } + +    /** +     * The directory where the checked out files should be placed. +     * +     * @param PhingFile $dest +     */ +    public function setDest(PhingFile $dest) { +        $this->dest = $dest; +    } + +    public function getDest() { +        return $this->dest; +    } + +    /** +     * The package/module to operate upon. +     * +     * @param string $p +     */ +    public function setModule($m) { +        $this->cvsModule = $m; +    } + +    public function getModule(){ +        return $this->cvsModule; +    } + +    /** +     * The tag of the package/module to operate upon. +     * @param string $p +     */ +    public function setTag($p) { +        // Check if not real tag => set it to null +        if ($p !== null && trim($p) !== "") { +            $this->appendCommandArgument("-r"); +            $this->appendCommandArgument($p); +        } +    } + +    /** +     * This needs to be public to allow configuration +     *      of commands externally. +     */ +    public function appendCommandArgument($arg) { +        $this->cmd->createArgument()->setValue($arg); +    } + +    /** +     * Use the most recent revision no later than the given date. +     * @param p +     */ +    public function setDate($p) { +        if ($p !== null && trim($p) !== "") { +            $this->appendCommandArgument("-D"); +            $this->appendCommandArgument($p); +        } +    } + +    /** +     * The CVS command to execute. +     * @param string $c +     */ +    public function setCommand($c) { +        $this->command = $c; +    } +     +    public function getCommand() { +        return $this->command; +    } + +    /** +     * If true, suppress informational messages. +     * @param boolean $q +     */ +    public function setQuiet($q) { +        $this->quiet = $q; +    } + +    /** +     * If true, report only and don't change any files. +     * +     * @param boolean $ne +     */ +    public function setNoexec($ne) { +        $this->noexec = (boolean) $ne; +    } + +    /** +     * Stop the build process if the command exits with +     * a return code other than 0. +     * Defaults to false. +     * @param boolean $failOnError +     */ +    public function setFailOnError($failOnError) { +        $this->failOnError = (boolean) $failOnError; +    } + +    /** +     * Configure a commandline element for things like cvsRoot, quiet, etc. +     * @return string +     */ +    protected function configureCommandline($c) { +        if ($c === null) { +            return; +        } +        $c->setExecutable("cvs"); +         +        if ($this->cvsModule !== null) { +            $c->createArgument()->setLine($this->cvsModule); +        } +        if ($this->compression > 0 && $this->compression < 10) { +            $c->createArgument(true)->setValue("-z" . $this->compression); +        } +        if ($this->quiet) { +            $c->createArgument(true)->setValue("-q"); +        } +        if ($this->noexec) { +            $c->createArgument(true)->setValue("-n"); +        } +        if ($this->cvsRoot !== null) { +            $c->createArgument(true)->setLine("-d" . $this->cvsRoot); +        } +    } + +    protected function removeCommandline(Commandline $c) { +        $idx = array_search($c, $this->commandlines, true); +        if ($idx === false) { +            return false; +        } +        $this->commandlines = array_splice($this->commandlines, $idx, 1); +        return true; +    } + +    /** +    * Configures and adds the given Commandline. +    * @param insertAtStart If true, c is +    */ +    public function addConfiguredCommandline(Commandline $c, $insertAtStart = false) { +        if ($c === null) { +            return;  +        } +        $this->configureCommandline($c); +        if ($insertAtStart) { +            array_unshift($this->commandlines, $c); +        } else { +            array_push($this->commandlines, $c); +        } +    } + +    /** +    * If set to a value 1-9 it adds -zN to the cvs command line, else +    * it disables compression. +    * @param int $level +    */ +    public function setCompressionLevel($level) { +        $this->compression = $level; +    } + +    /** +     * If true, this is the same as compressionlevel="3". +     * +     * @param boolean $usecomp If true, turns on compression using default +     * level, AbstractCvsTask.DEFAULT_COMPRESSION_LEVEL. +     */ +    public function setCompression($usecomp) { +        $this->setCompressionLevel($usecomp ?  +                            self::DEFAULT_COMPRESSION_LEVEL : 0); +    } + +    /** +     * File to which output should be written. +     * @param PhingFile $output +     */ +    function setOutput(PhingFile $f) { +        $this->output = $f; +    } +     +    /** +     * File to which error output should be written. +     * @param PhingFile $output +     */ +    function setError(PhingFile $f) { +        $this->error = $f; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php b/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php new file mode 100644 index 00000000..00e1e7a7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php @@ -0,0 +1,277 @@ +<?php +/* + *  $Id: DeleteTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Deletes a file or directory, or set of files defined by a fileset. + *  + * @version   $Revision: 1.13 $ + * @package   phing.tasks.system + */ +class DeleteTask extends Task { + +    protected $file; +    protected $dir; +    protected $filesets = array(); +    protected $includeEmpty = false; + +    protected $quiet = false; +    protected $failonerror = true; +    protected $verbosity = PROJECT_MSG_VERBOSE; +	 +	/** Any filelists of files that should be deleted. */ +    private $filelists = array(); +	 +    /**  +     * Set the name of a single file to be removed. +     * @param PhingFile $file +     */ +    function setFile(PhingFile $file) {        +        $this->file = $file; +    } + +    /**  +     * Set the directory from which files are to be deleted. +     * @param PhingFile $dir +     */ +    function setDir(PhingFile $dir) { +        $this->dir = $dir; +    } + +    /** +     * Used to force listing of all names of deleted files. +     * @param boolean $verbosity +     */ +    function setVerbose($verbosity) { +        if ($verbosity) { +            $this->verbosity = PROJECT_MSG_INFO; +        } else { +            $this->verbosity = PROJECT_MSG_VERBOSE; +        } +    } + +    /** +     * If the file does not exist, do not display a diagnostic +     * message or modify the exit status to reflect an error. +     * This means that if a file or directory cannot be deleted, +     * then no error is reported. This setting emulates the +     * -f option to the Unix rm command. Default is false +    * meaning things are verbose +     */ +    function setQuiet($bool) { +        $this->quiet = $bool; +        if ($this->quiet) { +            $this->failonerror = false; +        } +    } + +    /** this flag means 'note errors to the output, but keep going' */ +    function setFailOnError($bool) { +        $this->failonerror = $bool; +    } + + +    /** Used to delete empty directories.*/ +    function setIncludeEmptyDirs($includeEmpty) { +        $this->includeEmpty = (boolean) $includeEmpty; +    } + +    /** Nested creator, adds a set of files (nested fileset attribute). */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } +	 +	/** Nested creator, adds a set of files (nested fileset attribute). */ +    function createFileList() { +        $num = array_push($this->filelists, new FileList()); +        return $this->filelists[$num-1]; +    } + +    /** Delete the file(s). */ +    function main() { +        if ($this->file === null && $this->dir === null && count($this->filesets) === 0 && count($this->filelists) === 0) { +            throw new BuildException("At least one of the file or dir attributes, or a fileset element, or a filelist element must be set."); +        } + +        if ($this->quiet && $this->failonerror) { +            throw new BuildException("quiet and failonerror cannot both be set to true", $this->location); +        } + +        // delete a single file +        if ($this->file !== null) { +            if ($this->file->exists()) { +                if ($this->file->isDirectory()) { +                    $this->log("Directory " . $this->file->__toString() . " cannot be removed using the file attribute. Use dir instead."); +                } else { +                    $this->log("Deleting: " . $this->file->__toString()); +                    try { +                        $this->file->delete(); +                    } catch(Exception $e) { +                        $message = "Unable to delete file " . $this->file->__toString() .": " .$e->getMessage(); +                        if($this->failonerror) { +                            throw new BuildException($message); +                        } else { +                            $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +                        }                         +                    } +                } +            } else { +                $this->log("Could not find file " . $this->file->getAbsolutePath() . " to delete.",PROJECT_MSG_VERBOSE); +            } +        } + +        // delete the directory +        if ($this->dir !== null && $this->dir->exists() && $this->dir->isDirectory()) { +            if ($this->verbosity === PROJECT_MSG_VERBOSE) { +                $this->log("Deleting directory " . $this->dir->__toString()); +            } +            $this->removeDir($this->dir); +        } +		 +		// delete the files in the filelists +		foreach($this->filelists as $fl) { +			try { +				$files = $fl->getFiles($this->project); +				$this->removeFiles($fl->getDir($this->project), $files, $empty=array()); +			} catch (BuildException $be) { +				// directory doesn't exist or is not readable +					if ($this->failonerror) { +					throw $be; +				} else { +					$this->log($be->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +				} +			} +		} +			 +        // delete the files in the filesets +        foreach($this->filesets as $fs) { +            try { +                $ds = $fs->getDirectoryScanner($this->project); +                $files = $ds->getIncludedFiles(); +                $dirs = $ds->getIncludedDirectories(); +                $this->removeFiles($fs->getDir($this->project), $files, $dirs); +            } catch (BuildException $be) { +                    // directory doesn't exist or is not readable +                    if ($this->failonerror) { +                        throw $be; +                    } else { +                        $this->log($be->getMessage(), $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +                    } +                } +        } +    } +     +    /** +     * Recursively removes a directory. +     * @param PhingFile $d The directory to remove. +     */ +    private function removeDir($d) { +        $list = $d->listDir(); +        if ($list === null) { +            $list = array(); +        } +         +        foreach($list as $s) { +            $f = new PhingFile($d, $s); +            if ($f->isDirectory()) { +                $this->removeDir($f); +            } else { +                $this->log("Deleting " . $f->__toString(), $this->verbosity); +                try { +                    $f->delete(); +                } catch (Exception $e) { +                    $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage(); +                    if($this->failonerror) { +                        throw new BuildException($message); +                    } else { +                        $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +                    } +                }                +            } +        } +        $this->log("Deleting directory " . $d->getAbsolutePath(), $this->verbosity); +        try { +            $d->delete(); +        } catch (Exception $e) { +            $message = "Unable to delete directory " . $d->__toString() . ": " . $e->getMessage(); +            if($this->failonerror) { +              throw new BuildException($message); +            } else { +              $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +            } +        }                +    } + +    /** +     * remove an array of files in a directory, and a list of subdirectories +     * which will only be deleted if 'includeEmpty' is true +     * @param PhingFile $d directory to work from +     * @param array &$files array of files to delete; can be of zero length +     * @param array &$dirs array of directories to delete; can of zero length +     */ +    private function removeFiles(PhingFile $d, &$files, &$dirs) { +        if (count($files) > 0) { +            $this->log("Deleting " . count($files) . " files from " . $d->__toString()); +            for ($j=0,$_j=count($files); $j < $_j; $j++) { +                $f = new PhingFile($d, $files[$j]); +                $this->log("Deleting " . $f->getAbsolutePath(), $this->verbosity); +                try { +                    $f->delete(); +                } catch (Exception $e) { +                    $message = "Unable to delete file " . $f->__toString() . ": " . $e->getMessage(); +                    if($this->failonerror) { +                        throw new BuildException($message); +                    } else { +                        $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +                    } +                }                + +            } +        } + +        if (count($dirs) > 0 && $this->includeEmpty) { +            $dirCount = 0; +            for ($j=count($dirs)-1; $j>=0; --$j) { +                $dir = new PhingFile($d, $dirs[$j]); +                $dirFiles = $dir->listDir(); +                if ($dirFiles === null || count($dirFiles) === 0) { +                    $this->log("Deleting " . $dir->__toString(), $this->verbosity); +                    try { +                        $dir->delete(); +                        $dirCount++; +                    } catch (Exception $e) { +                        $message="Unable to delete directory " + $dir; +                        if($this->failonerror) { +                            throw new BuildException($message); +                        } else { +                            $this->log($message, $this->quiet ? PROJECT_MSG_VERBOSE : PROJECT_MSG_WARN); +                        } +                    } +                } +            } +            if ($dirCount > 0) { +                $this->log("Deleted $dirCount director" . ($dirCount==1 ? "y" : "ies") . " from " . $d->__toString()); +            } +        } +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/EchoTask.php b/buildscripts/phing/classes/phing/tasks/system/EchoTask.php new file mode 100644 index 00000000..229f5130 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/EchoTask.php @@ -0,0 +1,107 @@ +<?php +/* + *  $Id: EchoTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +include_once 'phing/Task.php'; + +/** + *  Echos a message to the logging system or to a file + * + *  @author   Michiel Rook <michiel@trendserver.nl> + *  @author   Andreas Aderhold, andi@binarycloud.com + *  @version  $Revision: 1.5 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @package  phing.tasks.system + */ + +class EchoTask extends Task { +	 +    protected $msg = ""; +     +    protected $file = ""; +     +    protected $append = false; +     +    protected $level = "info"; + +    function main() {		 +		switch ($this->level) +		{ +			case "error": $loglevel = PROJECT_MSG_ERR; break; +			case "warning": $loglevel = PROJECT_MSG_WARN; break; +			case "info": $loglevel = PROJECT_MSG_INFO; break; +			case "verbose": $loglevel = PROJECT_MSG_VERBOSE; break; +			case "debug": $loglevel = PROJECT_MSG_DEBUG; break; +		} +		 +		if (empty($this->file)) +		{ +        	$this->log($this->msg, $loglevel); +		} +		else +		{ +			if ($this->append) +			{ +				$handle = fopen($this->file, "a"); +			} +			else +			{ +				$handle = fopen($this->file, "w"); +			} +			 +			fwrite($handle, $this->msg); +			 +			fclose($handle); +		} +    } +     +    /** setter for file */ +    function setFile($file) +    { +		$this->file = (string) $file; +	} + +    /** setter for level */ +    function setLevel($level) +    { +		$this->level = (string) $level; +	} + +    /** setter for append */ +    function setAppend($append) +    { +		$this->append = $append; +	} + +    /** setter for message */ +    function setMsg($msg) { +        $this->setMessage($msg); +    } + +    /** alias setter */ +    function setMessage($msg) { +        $this->msg = (string) $msg; +    } +     +    /** Supporting the <echo>Message</echo> syntax. */ +    function addText($msg) +    { +        $this->msg = (string) $msg; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ExecTask.php b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php new file mode 100644 index 00000000..104f7697 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php @@ -0,0 +1,248 @@ +<?php + +/* + *  $Id: ExecTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Executes a command on the shell. + * + * @author   Andreas Aderhold <andi@binarycloud.com> + * @author   Hans Lellelid <hans@xmpl.org> + * @version  $Revision: 1.17 $ + * @package  phing.tasks.system + */ +class ExecTask extends Task { + +    /** +     * Command to execute. +     * @var string +     */ +    protected $command; +     +    /** +     * Working directory. +     * @var File +     */ +    protected $dir; +     +    /** +     * Operating system. +     * @var string +     */ +    protected $os; +     +    /** +     * Whether to escape shell command using escapeshellcmd(). +     * @var boolean +     */ +    protected $escape = false; +     +    /** +     * Where to direct output. +     * @var File +     */ +    protected $output; +     +    /** +     * Whether to passthru the output +     * @var boolean +     */ +    protected $passthru = false; +     +    /** +     * Where to direct error output. +     * @var File +     */ +    protected $error; +     +	/** +	 * If spawn is set then [unix] programs will redirect stdout and add '&'. +	 * @var boolean +	 */ +	protected $spawn = false; +	 +    /** +     * Whether to check the return code. +     * @var boolean +     */ +    protected $checkreturn = false; +     +    /** +     * Main method: wraps execute() command. +     * @return void +     */ +    public function main() { +        $this->execute(); +    } +     +    /** +     * Executes a program and returns the return code. +     * Output from command is logged at INFO level. +     * @return int Return code from execution. +     */ +    public function execute() { +     +         // test if os match +        $myos = Phing::getProperty("os.name"); +        $this->log("Myos = " . $myos, PROJECT_MSG_VERBOSE); +        if (($this->os !== null) && (strpos($os, $myos) === false)) { +            // this command will be executed only on the specified OS +            $this->log("Not found in " . $os, PROJECT_MSG_VERBOSE); +            return 0; +        } +         +         if ($this->dir !== null) { +            if ($this->dir->isDirectory()) { +                $currdir = getcwd(); +                @chdir($this->dir->getPath()); +            } else { +                throw new BuildException("Can't chdir to:" . $this->dir->__toString()); +            } +        } + + +        if ($this->escape == true) { +            // FIXME - figure out whether this is correct behavior +            $this->command = escapeshellcmd($this->command); +        } +         +        if ($this->error !== null) { +            $this->command .= ' 2> ' . $this->error->getPath(); +            $this->log("Writing error output to: " . $this->error->getPath()); +        } +         +        if ($this->output !== null) { +            $this->command .= ' 1> ' . $this->output->getPath(); +            $this->log("Writing standard output to: " . $this->output->getPath()); +        } elseif ($this->spawn) { +			$this->command .= ' 1>/dev/null'; +			$this->log("Sending ouptut to /dev/null"); +		} +         +        // If neither output nor error are being written to file +        // then we'll redirect error to stdout so that we can dump +        // it to screen below. + +        if ($this->output === null && $this->error === null) { +            $this->command .= ' 2>&1'; +        } +        		 +		// we ignore the spawn boolean for windows +		if ($this->spawn) { +		    $this->command .= ' &'; +		} + +		$this->log("Executing command: " . $this->command); +				 +        $output = array(); +        $return = null; +        exec($this->command, $output, $return); + +        if ($this->dir !== null) { +            @chdir($currdir); +        } + +        foreach($output as $line) { +            $this->log($line,  ($this->passthru ? PROJECT_MSG_INFO : PROJECT_MSG_VERBOSE)); +        } +         +        if($return != 0 && $this->checkreturn) +        { +          throw new BuildException("Task exited with code $return"); +        } +         +        return $return; +    } + +    /** +     * The command to use. +     * @param mixed $command String or string-compatible (e.g. w/ __toString()). +     */ +    function setCommand($command) { +        $this->command = "" . $command; +    } +     +    /** +     * Whether to use escapeshellcmd() to escape command. +     * @param boolean $escape +     */ +    function setEscape($escape) { +        $this->escape = (bool) $escape; +    } +     +    /** +     * Specify the workign directory for executing this command. +     * @param PhingFile $dir +     */ +    function setDir(PhingFile $dir) { +        $this->dir = $dir; +    } +     +    /** +     * Specify OS (or muliple OS) that must match in order to execute this command. +     * @param string $os +     */ +    function setOs($os) { +        $this->os = (string) $os; +    } +     +    /** +     * File to which output should be written. +     * @param PhingFile $output +     */ +    function setOutput(PhingFile $f) { +        $this->output = $f; +    } +     +    /** +     * File to which error output should be written. +     * @param PhingFile $output +     */ +    function setError(PhingFile $f) { +        $this->error = $f; +    } +     +    /** +     * Whether to use passthru the output. +     * @param boolean $passthru +     */ +    function setPassthru($passthru) { +        $this->passthru = (bool) $passthru; +    } +     +	/** +	 * Whether to suppress all output and run in the background. +	 * @param boolean $spawn +	 */ +	function setSpawn($spawn) { +		$this->spawn  = (bool) $spawn; +	} + +    /** +     * Whether to check the return code. +     * @param boolean $checkreturn +     */ +    function setCheckreturn($checkreturn) { +      $this->checkreturn = (bool) $checkreturn; +    } +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/ExitTask.php b/buildscripts/phing/classes/phing/tasks/system/ExitTask.php new file mode 100644 index 00000000..7e08d369 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ExitTask.php @@ -0,0 +1,118 @@ +<?php +/* + *  $Id: ExitTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; + +/** + * Exits the active build, giving an additional message + * if available. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Nico Seessle <nico@seessle.de> (Ant) + * @version   $Revision: 1.7 $ + * @package   phing.tasks.system + */ +class ExitTask extends Task {  + +    private $message; +    private $ifCondition; +    private $unlessCondition; + +    /** +     * A message giving further information on why the build exited. +     * +     * @param string $value message to output +     */ +    public function setMsg($value) { +        $this->setMessage($value); +    } + +    /** +     * A message giving further information on why the build exited. +     * +     * @param value message to output +     */ +    public function setMessage($value) { +        $this->message = $value; +    } + +    /** +     * Only fail if a property of the given name exists in the current project. +     * @param c property name +     */ +    public function setIf($c) { +        $this->ifCondition = $c; +    } + +    /** +     * Only fail if a property of the given name does not +     * exist in the current project. +     * @param c property name +     */ +    public function setUnless($c) { +        $this->unlessCondition = $c; +    } + +    /** +     * @throws BuildException +     */ +    public function main()  { +        if ($this->testIfCondition() && $this->testUnlessCondition()) { +            if ($this->message !== null) {  +                throw new BuildException($this->message); +            } else { +                throw new BuildException("No message"); +            } +        } +    } + +    /** +     * Set a multiline message. +     */ +    public function addText($msg) { +        if ($this->message === null) { +            $this->message = ""; +        } +        $this->message .= $this->project->replaceProperties($msg); +    } + +    /** +     * @return boolean +     */ +    private function testIfCondition() { +        if ($this->ifCondition === null || $this->ifCondition === "") { +            return true; +        } +         +        return $this->project->getProperty($this->ifCondition) !== null; +    } +     +    /** +     * @return boolean +     */ +    private function testUnlessCondition() { +        if ($this->unlessCondition === null || $this->unlessCondition ===  "") { +            return true; +        } +        return $this->project->getProperty($this->unlessCondition) === null; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php b/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php new file mode 100644 index 00000000..a2a42665 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php @@ -0,0 +1,138 @@ +<?php +/* + *  $Id: ForeachTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/PhingTask.php'; + +/** + * <foreach> task + * + * Task definition for the foreach task.  This task takes a list with + * delimited values, and executes a target with set param. + * + * Usage: + * <foreach list="values" target="targ" param="name" delimiter="|" /> + * + * Attributes: + * list      --> The list of values to process, with the delimiter character, + *               indicated by the "delimiter" attribute, separating each value. + * target    --> The target to call for each token, passing the token as the + *               parameter with the name indicated by the "param" attribute. + * param     --> The name of the parameter to pass the tokens in as to the + *               target. + * delimiter --> The delimiter string that separates the values in the "list" + *               parameter.  The default is ",". + * + * @author    Jason Hines <jason@greenhell.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.9 $ + * @package   phing.tasks.system + */ +class ForeachTask extends Task { +     +    /** Delimter-separated list of values to process. */ +    private $list; +     +    /** Name of parameter to pass to callee */ +    private $param; +     +    /** Delimter that separates items in $list */ +    private $delimiter = ','; +     +    /** +     * PhingCallTask that will be invoked w/ calleeTarget. +     * @var PhingCallTask +     */ +    private $callee; +     +    /** +     * Target to execute. +     * @var string +     */ +    private $calleeTarget; + +    function init() { +        $this->callee = $this->project->createTask("phingcall"); +        $this->callee->setOwningTarget($this->getOwningTarget()); +        $this->callee->setTaskName($this->getTaskName()); +        $this->callee->setLocation($this->getLocation()); +        $this->callee->init(); +    } + +    /** +     * This method does the work. +     * @return void +     */    +    function main() { +        if ($this->list === null) { +            throw new BuildException("Missing list to iterate through"); +        } +        if (trim($this->list) === '') { +            return; +        } +        if ($this->param === null) { +            throw new BuildException("You must supply a property name to set on each iteration in param"); +        } +        if ($this->calleeTarget === null) { +            throw new BuildException("You must supply a target to perform"); +        } + +        $callee = $this->callee; +        $callee->setTarget($this->calleeTarget); +        $callee->setInheritAll(true); +        $callee->setInheritRefs(true); +         +        $arr = explode($this->delimiter, $this->list); +         +        foreach ($arr as $value) { +            $this->log("Setting param '$this->param' to value '$value'", PROJECT_MSG_VERBOSE); +            $prop = $callee->createProperty(); +            $prop->setOverride(true); +            $prop->setName($this->param); +            $prop->setValue($value); +            $callee->main(); +        } +    } + +    function setList($list) { +        $this->list = (string) $list; +    } + +    function setTarget($target) { +        $this->calleeTarget = (string) $target; +    } + +    function setParam($param) { +        $this->param = (string) $param; +    } + +    function setDelimiter($delimiter) { +        $this->delimiter = (string) $delimiter; +    } + +    /** +     * @return Property +     */ +    function createProperty() { +        return $this->callee->createProperty(); +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/IfTask.php b/buildscripts/phing/classes/phing/tasks/system/IfTask.php new file mode 100644 index 00000000..ab773355 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/IfTask.php @@ -0,0 +1,224 @@ +<?php + +/* + *  $Id: IfTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/tasks/system/condition/ConditionBase.php'; +require_once 'phing/tasks/system/SequentialTask.php'; + +/** + * Perform some tasks based on whether a given condition holds true or + * not. + * + * <p>This task is heavily based on the Condition framework that can + * be found in Ant 1.4 and later, therefore it cannot be used in + * conjunction with versions of Ant prior to 1.4.</p> + * + * <p>This task doesn't have any attributes, the condition to test is + * specified by a nested element - see the documentation of your + * <code><condition></code> task (see + * <a href="http://jakarta.apache.org/ant/manual/CoreTasks/condition.html">the + * online documentation</a> for example) for a complete list of nested + * elements.</p> + * + * <p>Just like the <code><condition></code> task, only a single + * condition can be specified - you combine them using + * <code><and></code> or <code><or></code> conditions.</p> + * + * <p>In addition to the condition, you can specify three different + * child elements, <code><elseif></code>, <code><then></code> and + * <code><else></code>.  All three subelements are optional. + * + * Both <code><then></code> and <code><else></code> must not be + * used more than once inside the if task.  Both are + * containers for Ant tasks, just like Ant's + * <code><parallel></code> and <code><sequential></code> + * tasks - in fact they are implemented using the same class as Ant's + * <code><sequential></code> task.</p> + * + *  The <code><elseif></code> behaves exactly like an <code><if></code> + * except that it cannot contain the <code><else></code> element + * inside of it.  You may specify as may of these as you like, and the + * order they are specified is the order they are evaluated in.  If the + * condition on the <code><if></code> is false, then the first + * <code><elseif></code> who's conditional evaluates to true + * will be executed.  The <code><else></code> will be executed + * only if the <code><if></code> and all <code><elseif></code> + * conditions are false. + * + * <p>Use the following task to define the <code><if></code> + * task before you use it the first time:</p> + * + * <pre><code> + *   <taskdef name="if" classname="net.sf.antcontrib.logic.IfTask" /> + * </code></pre> + * + * <h3>Crude Example</h3> + * + * <code> + * <if> + *  <equals arg1="${foo}" arg2="bar" /> + *  <then> + *    <echo message="The value of property foo is bar" /> + *  </then> + *  <else> + *    <echo message="The value of property foo is not bar" /> + *  </else> + * </if> + * </code> + * + * <code> + * <if> + *  <equals arg1="${foo}" arg2="bar" /> + *  <then> + *   <echo message="The value of property foo is 'bar'" /> + *  </then> + * + *  <elseif> + *   <equals arg1="${foo}" arg2="foo" /> + *   <then> + *    <echo message="The value of property foo is 'foo'" /> + *   </then> + *  </elseif> + * + *  <else> + *   <echo message="The value of property foo is not 'foo' or 'bar'" /> + *  </else> + * </if> + * </code> + * + * @author <a href="mailto:stefan.bodewig@freenet.de">Stefan Bodewig</a> + */ +class IfTask extends ConditionBase { + + +    private $thenTasks = null; +    private $elseIfTasks = array(); +    private $elseTasks = null; + +    /*** +     * A nested Else if task +     */ +    public function addElseIf(ElseIfTask $ei) +    { +        $this->elseIfTasks[] = $ei; +    } + +    /** +     * A nested <then> element - a container of tasks that will +     * be run if the condition holds true. +     * +     * <p>Not required.</p> +     */ +    public function addThen(SequentialTask $t) { +        if ($this->thenTasks != null) { +            throw new BuildException("You must not nest more than one <then> into <if>"); +        } +        $this->thenTasks = $t; +    } + +    /** +     * A nested <else> element - a container of tasks that will +     * be run if the condition doesn't hold true. +     * +     * <p>Not required.</p> +     */ +    public function addElse(SequentialTask $e) { +        if ($this->elseTasks != null) { +            throw new BuildException("You must not nest more than one <else> into <if>"); +        } +        $this->elseTasks = $e; +    } + +    public function main() { +	 +        if ($this->countConditions() > 1) { +            throw new BuildException("You must not nest more than one condition into <if>"); +        } +        if ($this->countConditions() < 1) { +            throw new BuildException("You must nest a condition into <if>"); +        } +		$conditions = $this->getConditions(); +		$c = $conditions[0]; +		 +        if ($c->evaluate()) { +            if ($this->thenTasks != null) { +                $this->thenTasks->main(); +            } +        } else { +            $done = false; +            $sz = count($this->elseIfTasks); +			for($i=0; $i < $sz && !$done; $i++) { +				$ei = $this->elseIfTasks[$i]; +                if ($ei->evaluate()) { +                    $done = true; +                    $ei->main(); +                } +            } + +            if (!$done && $this->elseTasks != null) { +                $this->elseTasks->main(); +            } +        } +    } +} + +/** + * "Inner" class for IfTask. + * This class has same basic structure as the IfTask, although of course it doesn't support <else> tags. + */ +class ElseIfTask extends ConditionBase { + +        private $thenTasks = null; + +        public function addThen(SequentialTask $t) { +            if ($this->thenTasks != null) { +                throw new BuildException("You must not nest more than one <then> into <elseif>"); +            } +            $this->thenTasks = $t; +        } +	 +		/** +		 * @return boolean +		 */ +        public function evaluate() { +		 +            if ($this->countConditions() > 1) { +                throw new BuildException("You must not nest more than one condition into <elseif>"); +            } +            if ($this->countConditions() < 1) { +                throw new BuildException("You must nest a condition into <elseif>"); +            } +			 +			$conditions = $this->getConditions(); +			$c = $conditions[0]; + +            return $c->evaluate(); +        } +		 +		/** +		 *  +		 */ +        public function main() { +            if ($this->thenTasks != null) { +                $this->thenTasks->main(); +            } +        } +    }
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php new file mode 100644 index 00000000..ce9beee5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php @@ -0,0 +1,115 @@ +<?php + +/* + * $Id: IncludePathTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; +include_once 'phing/types/Path.php'; + +/** + * Adds a normalized path to the PHP include_path. + *  + * This provides a way to alter the include_path without editing any global php.ini settings + * or PHP_CLASSPATH environment variable. + *  + * <code> + *   <includepath classpath="new/path/here"/> + * </code> + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.1 $ + * @package   phing.tasks.system + */ +class IncludePathTask extends Task { +    +    /** +     * Classname of task to register. +     * This can be a dot-path -- relative to a location on PHP include_path. +     * E.g. path.to.MyClass ->  path/to/MyClass.php +     * @var string +     */ +    private $classname; +     +    /** +     * Path to add to PHP include_path to aid in finding specified class. +     * @var Path +     */ +    private $classpath; +     +    /** +     * Refid to already defined classpath +     */ +    private $classpathId; +     +    /** +     * Set the classpath to be used when searching for component being defined +     *  +     * @param Path $classpath An Path object containing the classpath. +     */ +    public function setClasspath(Path $classpath) { +        if ($this->classpath === null) { +            $this->classpath = $classpath; +        } else { +            $this->classpath->append($classpath); +        } +    } + +    /** +     * Create the classpath to be used when searching for component being defined +     */  +    public function createClasspath() { +        if ($this->classpath === null) { +            $this->classpath = new Path($this->project); +        } +        return $this->classpath->createPath(); +    } + +    /** +     * Reference to a classpath to use when loading the files. +     */ +    public function setClasspathRef(Reference $r) { +        $this->classpathId = $r->getRefId(); +        $this->createClasspath()->setRefid($r); +    } + +     +    /** Main entry point */ +    public function main() { +     +        // Apparently casting to (string) no longer invokes __toString() automatically. +        if (is_object($this->classpath)) { +            $this->classpath = $this->classpath->__toString(); +        } +         +        if (empty($this->classpath)) { +            throw new BuildException("Provided classpath was empty."); +        } +         +        $curr_parts = explode(PATH_SEPARATOR, get_include_path()); +        $add_parts = explode(PATH_SEPARATOR, $this->classpath); +        $new_parts = array_diff($add_parts, $curr_parts); +         +        if ($new_parts) { +            $this->log("Prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts), PROJECT_MSG_VERBOSE); +            set_include_path(implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); +        } +         +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/InputTask.php b/buildscripts/phing/classes/phing/tasks/system/InputTask.php new file mode 100644 index 00000000..a5e1fdb9 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/InputTask.php @@ -0,0 +1,146 @@ +<?php +/* + *  $Id: InputTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/input/InputRequest.php'; +include_once 'phing/input/YesNoInputRequest.php'; +include_once 'phing/input/MultipleChoiceInputRequest.php'; +  +/** + * Reads input from the InputHandler. + *  + * @see       Project::getInputHandler() + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Ulrich Schmidt <usch@usch.net> (Ant) + * @author    Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version   $Revision: 1.6 $ + * @package   phing.tasks.system + */ +class InputTask extends Task { +     +    private $validargs; +    private $message = ""; // required +    private $propertyName; // required +    private $defaultValue; +    private $promptChar; +     +    /** +     * Defines valid input parameters as comma separated strings. If set, input +     * task will reject any input not defined as accepted and requires the user +     * to reenter it. Validargs are case sensitive. If you want 'a' and 'A' to +     * be accepted you need to define both values as accepted arguments. +     * +     * @param validargs A comma separated String defining valid input args. +     */ +    public function setValidargs ($validargs) { +        $this->validargs = $validargs; +    } + +    /** +     * Defines the name of a property to be set from input. +     * +     * @param string $name Name for the property to be set from input +     */ +    public function setPropertyName($name) { +        $this->propertyName = $name; +    } + +    /** +     * Sets the Message which gets displayed to the user during the build run. +     * @param message The message to be displayed. +     */ +    public function setMessage ($message) { +        $this->message = $message; +    } + +    /** +     * Set a multiline message. +     */ +    public function addText($msg) { +        $this->message .= $this->project->replaceProperties($msg); +    } +     +    /** +     * Add a default value. +     * @param string $v +     */ +    public function setDefaultValue($v) { +        $this->defaultValue = $v; +    } +     +    /** +     * Set the character/string to use for the prompt. +     * @param string $c +     */ +    public function setPromptChar($c) { +        $this->promptChar = $c; +    } +     +    /** +     * Actual method executed by phing. +     * @throws BuildException +     */ +    public function main() { +     +        if ($this->propertyName === null) { +            throw new BuildException("You must specify a value for propertyName attribute."); +        } +         +        if ($this->validargs !== null) { +            $accept = preg_split('/[\s,]+/', $this->validargs); +             +            // is it a boolean (yes/no) inputrequest? +            $yesno = false; +            if (count($accept) == 2) { +                $yesno = true; +                foreach($accept as $ans) { +                    if(!StringHelper::isBoolean($ans)) { +                        $yesno = false; +                        break; +                    } +                } +            } +            if ($yesno) $request = new YesNoInputRequest($this->message, $accept); +            else $request = new MultipleChoiceInputRequest($this->message, $accept); +        } else { +            $request = new InputRequest($this->message); +        } +         +        // default default is curr prop value         +        $request->setDefaultValue($this->project->getProperty($this->propertyName)); +         +        $request->setPromptChar($this->promptChar); +         +        // unless overridden... +        if ($this->defaultValue !== null) { +            $request->setDefaultValue($this->defaultValue); +        } +         +        $this->project->getInputHandler()->handleInput($request); + +        $value = $request->getInput(); +         +        if ($value !== null) { +            $this->project->setUserProperty($this->propertyName, $value); +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php new file mode 100644 index 00000000..c5497fbd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php @@ -0,0 +1,361 @@ +<?php +/* + *  $Id: MatchingTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/types/selectors/SelectorContainer.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/types/PatternSet.php'; +include_once 'phing/util/DirectoryScanner.php'; + +/** + * This is an abstract task that should be used by all those tasks that  + * require to include or exclude files based on pattern matching. + * + * This is very closely based on the ANT class of the same name. + *  + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Arnout J. Kuiper <ajkuiper@wxs.nl> (Ant) + * @author    Stefano Mazzocchi  <stefano@apache.org> (Ant) + * @author    Sam Ruby <rubys@us.ibm.com> (Ant) + * @author    Jon S. Stevens <jon@clearink.com> (Ant + * @author    Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.4 $ + * @package   phing.tasks.system + */ +abstract class MatchingTask extends Task implements SelectorContainer { + +    /** @var boolean */ +    protected $useDefaultExcludes = true; +     +    /** @var FileSet */ +    protected $fileset; +     +    /** +     * Create instance; set fileset to new FileSet. +     */ +    public function __construct() { +        $this->fileset = new FileSet(); +    } +     +    /** +     * @see ProjectComponent::setProject() +     */ +    public function setProject(Project $project) { +        parent::setProject($project); +        $this->fileset->setProject($project); +    } + +    /** +     * add a name entry on the include list +     * @return PatternSetNameEntry +     */ +    public function createInclude() { +        return $this->fileset->createInclude(); +    } + +    /** +     * add a name entry on the include files list +     * @return PatternSetNameEntry +     */ +    public function createIncludesFile() { +        return $this->fileset->createIncludesFile(); +    } + +    /** +     * add a name entry on the exclude list +     * @return PatternSetNameEntry +     */ +    public function createExclude() { +        return $this->fileset->createExclude(); +    } + +    /** +     * add a name entry on the include files list +     * @return PatternSetNameEntry +     */ +    public function createExcludesFile() { +        return $this->fileset->createExcludesFile(); +    } + +    /** +     * add a set of patterns +     * @return PatternSet +     */ +    public function createPatternSet() { +        return $this->fileset->createPatternSet(); +    } + +    /** +     * Sets the set of include patterns. Patterns may be separated by a comma +     * or a space. +     * +     * @param string $includes the string containing the include patterns +     * @return void +     */ +    public function setIncludes($includes) { +        $this->fileset->setIncludes($includes); +    }     + +    /** +     * Sets the set of exclude patterns. Patterns may be separated by a comma +     * or a space. +     * +     * @param string $excludes the string containing the exclude patterns +     */ +    public function setExcludes($excludes) { +        $this->fileset->setExcludes($excludes); +    } + +     +    /** +     * Sets whether default exclusions should be used or not. +     * +     * @param boolean $useDefaultExcludes "true"|"on"|"yes" when default exclusions +     *                           should be used, "false"|"off"|"no" when they +     *                           shouldn't be used. +     */ +    public function setDefaultexcludes($useDefaultExcludes) { +        $this->useDefaultExcludes = (boolean) $useDefaultExcludes; +    } + +    /** +     * Returns the directory scanner needed to access the files to process. +     * @return DirectoryScanner +     */ +    protected function getDirectoryScanner(PhingFile $baseDir) { +        $this->fileset->setDir($baseDir); +        $this->fileset->setDefaultexcludes($this->useDefaultExcludes); +        return $this->fileset->getDirectoryScanner($this->project); +    } + +    /** +     * Sets the name of the file containing the includes patterns. +     * +     * @param PhingFile $includesfile A string containing the filename to fetch +     * the include patterns from. +     * @return void +     */ +    public function setIncludesfile(PhingFile $includesfile) { +        $this->fileset->setIncludesfile(includesfile); +    } + +    /** +     * Sets the name of the file containing the includes patterns. +     * +     * @param PhingFile $excludesfile A string containing the filename to fetch +     * the include patterns from. +     * @return void +     */ +    public function setExcludesfile(PhingFile $excludesfile) { +        $this->fileset->setExcludesfile($excludesfile); +    } + +    /** +     * Sets case sensitivity of the file system +     * +     * @param boolean $isCaseSensitive "true"|"on"|"yes" if file system is case +     *                           sensitive, "false"|"off"|"no" when not. +     * @return void +     */ +    public function setCaseSensitive($isCaseSensitive) { +        $this->fileset->setCaseSensitive($isCaseSensitive); +    } + +    /** +     * Sets whether or not symbolic links should be followed. +     * +     * @param boolean $followSymlinks whether or not symbolic links should be followed +     * @return void +     */ +    public function setFollowSymlinks($followSymlinks) { +        $this->fileset->setFollowSymlinks($followSymlinks); +    } + +    /** +     * Indicates whether there are any selectors here. +     * +     * @return boolean Whether any selectors are in this container +     */ +    public function hasSelectors() { +        return $this->fileset->hasSelectors(); +    } + +    /** +     * Gives the count of the number of selectors in this container +     * +     * @return int The number of selectors in this container +     */ +    public function selectorCount() { +        return $this->fileset->selectorCount(); +    } + +    /** +     * Returns the set of selectors as an array. +     * +     * @return array FileSelector[] An array of selectors in this container +     */ +    public function getSelectors(Project $p) { +        return $this->fileset->getSelectors($p); +    } + +    /** +     * Returns an enumerator for accessing the set of selectors. +     * +     * @return an enumerator that goes through each of the selectors +     */ +    public function selectorElements() { +        return $this->fileset->selectorElements(); +    } + +    /** +     * Add a new selector into this container. +     * +     * @param FileSelector $selector the new selector to add +     * @return void +     */ +    public function appendSelector(FileSelector $selector) { +        $this->fileset->appendSelector($selector); +    } + +    /* Methods below all add specific selectors */ + +    /** +     * add a "Select" selector entry on the selector list +     * @return SelectSelector +     */ +    public function createSelector() { +        return $this->fileset->createSelector(); +    } + +    /** +     * add an "And" selector entry on the selector list +     * @return AndSelector +     */ +    public function createAnd() { +        return $this->fileset->createAnd(); +    } + +    /** +     * add an "Or" selector entry on the selector list +     * @return void +     */ +    public function createOr() { +        return $this->fileset->createOr(); +    } + +    /** +     * add a "Not" selector entry on the selector list +     * @return NotSelector +     */ +    public function createNot() { +        return $this->fileset->createNot(); +    } + +    /** +     * add a "None" selector entry on the selector list +     * @return NoneSelector +     */ +    public function createNone() { +        return $this->fileset->createNone(); +    } + +    /** +     * add a majority selector entry on the selector list +     * @return MajoritySelector +     */ +    public function createMajority() { +        return $this->fileset->createMajority(); +    } + +    /** +     * add a selector date entry on the selector list +     * @return DateSelector +     */ +    public function createDate() { +        return $this->fileset->addDate(); +    } + +    /** +     * add a selector size entry on the selector list +     * @return SizeSelector +     */ +    public function createSize() { +        return $this->fileset->createSize(); +    } + +    /** +     * add a selector filename entry on the selector list +     * @return FilenameSelector +     */ +    public function createFilename() { +        return $this->fileset->createFilename(); +    } + +    /** +     * add an extended selector entry on the selector list +     * @return ExtendSelector +     */ +    public function createCustom() { +        return $this->fileset->createCustom(); +    } + +    /** +     * add a contains selector entry on the selector list +     * @return ContainsSelector +     */ +    public function createContains() { +        return $this->fileset->createContains(); +    } + +    /** +     * add a present selector entry on the selector list +     * @return PresentSelector +     */ +    public function createPresent() { +        return $this->fileset->createPresent(); +    } + +    /** +     * add a depth selector entry on the selector list +     * @return DepthSelector +     */ +    public function createDepth() { +        return $this->fileset->createDepth(); +    } + +    /** +     * add a depends selector entry on the selector list +     * @return DependSelector +     */ +    public function createDepend() { +        return $this->fileset->createDepend(); +    } + +    /** +     * Accessor for the implict fileset. +     * +     * @return FileSet +     */ +    protected final function getImplicitFileSet() { +        return $this->fileset; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php b/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php new file mode 100644 index 00000000..9d5c1f31 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php @@ -0,0 +1,64 @@ +<?php +/* + *  $Id: MkdirTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * Task to create a directory. + * + * @author   Andreas Aderhold, andi@binarycloud.com + * @version  $Revision: 1.8 $ + * @package  phing.tasks.system + */ +class MkdirTask extends Task { + +    /** directory to create*/ +    private $dir; + +    /** +     * create the directory and all parents +     * +     * @throws BuildException if dir is somehow invalid, or creation failed. +     */ +    function main() { +        if ($this->dir === null) { +            throw new BuildException("dir attribute is required", $this->location); +        } +        if ($this->dir->isFile()) { +            throw new BuildException("Unable to create directory as a file already exists with that name: " . $this->dir->getAbsolutePath()); +        } +        if (!$this->dir->exists()) { +            $result = $this->dir->mkdirs(); +            if (!$result) { +                $msg = "Directory " . $this->dir->getAbsolutePath() . " creation was not successful for an unknown reason"; +                throw new BuildException($msg, $this->location); +            } +            $this->log("Created dir: " . $this->dir->getAbsolutePath()); +        } +    } + +    /** the directory to create; required. */ +    function setDir(PhingFile $dir) { +        $this->dir = $dir; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/MoveTask.php b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php new file mode 100644 index 00000000..a3e94536 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php @@ -0,0 +1,197 @@ +<?php +/* + *  $Id: MoveTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/CopyTask.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/IOException.php'; + +/** + * Moves a file or directory to a new file or directory. + *  + * By default, the destination file is overwritten if it + * already exists.  When overwrite is turned off, then files + * are only moved if the source file is newer than the + * destination file, or when the destination file does not + * exist. + * + * Source files and directories are only deleted when the file or + * directory has been copied to the destination successfully. + * + * @version $Revision: 1.8 $ + * @package phing.tasks.system + */ +class MoveTask extends CopyTask { + +    function __construct() { +        parent::__construct(); +        $this->forceOverwrite = true; +    } +     +    protected function doWork() { +     +        $copyMapSize = count($this->fileCopyMap); +        if ($copyMapSize > 0) { +            // files to move +            $this->log("Moving $copyMapSize files to " . $this->destDir->getAbsolutePath()); + +            foreach($this->fileCopyMap as $from => $to) { +                if ($from == $to) { +                    $this->log("Skipping self-move of $from", $this->verbosity); +                    continue; +                } + +                $moved = false; +                $f = new PhingFile($from); +                $d = new PhingFile($to); +                 +                $moved = false; +                try { // try to rename                     +                    $this->log("Attempting to rename $from to $to", $this->verbosity); +                    $this->renameFile($f, $d, $this->forceOverwrite); +                    $moved = true; +                } catch (IOException $ioe) { +                    $moved = false; +                    $this->log("Failed to rename $from to $to: " . $ioe->getMessage(), $this->verbosity); +                } + +                if (!$moved) {                     +                    try { // try to move +                        $this->log("Moving $from to $to", $this->verbosity); + +                        $this->fileUtils->copyFile($f, $d, $this->forceOverwrite, $this->preserveLMT, $this->filterChains, $this->getProject());                         + +                        $f = new PhingFile($fromFile); +                        $f->delete(); +                    } catch (IOException $ioe) { +                        $msg = "Failed to move $from to $to: " . $ioe->getMessage(); +                        throw new BuildException($msg, $this->location); +                    } +                } // if !moved +            } // foreach fileCopyMap +        } // if copyMapSize + +        // handle empty dirs if appropriate +        if ($this->includeEmpty) { +            $e = array_keys($this->dirCopyMap); +            $count = 0; +            foreach ($e as $dir) { +                $d = new PhingFile((string) $dir); +                if (!$d->exists()) { +                    if (!$d->mkdirs()) { +                        $this->log("Unable to create directory " . $d->getAbsolutePath(), PROJECT_MSG_ERR); +                    } else { +                        $count++; +                    } +                } +            } +            if ($count > 0) { +                $this->log("moved $count empty director" . ($count == 1 ? "y" : "ies") . " to " . $this->destDir->getAbsolutePath()); +            } +        } + +        if (count($this->filesets) > 0) { +            // process filesets +            foreach($this->filesets as $fs) { +                $dir = $fs->getDir($this->project); +                if ($this->okToDelete($dir)) { +                    $this->deleteDir($dir); +                } +            } +        } +    } + +    /** Its only ok to delete a dir tree if there are no files in it. */ +    private function okToDelete($d) { +        $list = $d->listDir(); +        if ($list === null) { +            return false;     // maybe io error? +        } +         +        foreach($list as $s) { +            $f = new PhingFile($d, $s); +            if ($f->isDirectory()) { +                if (!$this->okToDelete($f)) { +                    return false; +                } +            } else { +                // found a file +                return false; +            } +        } +        return true; +    } + +    /** Go and delete the directory tree. */ +    private function deleteDir($d) { +     +        $list = $d->listDir(); +        if ($list === null) { +            return;      // on an io error list() can return null +        } +         +        foreach($list as $fname) { +            $f = new PhingFile($d, $fname); +            if ($f->isDirectory()) { +                $this->deleteDir($f); +            } else { +                throw new BuildException("UNEXPECTED ERROR - The file " . $f->getAbsolutePath() . " should not exist!"); +            } +        } + +        $this->log("Deleting directory " . $d->getPath(), $this->verbosity); +        try { +            $d->delete(); +        } catch (Exception $e) { +            throw new BuildException("Unable to delete directory " . $d->__toString() . ": " . $e->getMessage()); +        } +    } + +    /** +     * Attempts to rename a file from a source to a destination. +     * If overwrite is set to true, this method overwrites existing file +     * even if the destination file is newer. +     * Otherwise, the source f +     * ile is renamed only if the destination file # +     * is older than it. +     */ +    private function renameFile(PhingFile $sourceFile, PhingFile $destFile, $overwrite) { +        $renamed = true; + +        // ensure that parent dir of dest file exists! +        $parent = $destFile->getParentFile(); +        if ($parent !== null) { +            if (!$parent->exists()) { +                $parent->mkdirs(); +            } +        } +        if ($destFile->exists()) { +            try { +                $destFile->delete(); +            } catch (Exception $e) { +                throw new BuildException("Unable to remove existing file " . $destFile->__toString() . ": " . $e->getMessage()); +            } +        } +        $renamed = $sourceFile->renameTo($destFile); + +        return $renamed; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php new file mode 100644 index 00000000..34d4336d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php @@ -0,0 +1,139 @@ +<?php +/* + *  $Id: PhingCallTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Call another target in the same project. + * + *   <pre> + *    <target name="foo"> + *      <phingcall target="bar"> + *        <property name="property1" value="aaaaa" /> + *        <property name="foo" value="baz" /> + *       </phingcall> + *    </target> + * + *    <target name="bar" depends="init"> + *      <echo message="prop is ${property1} ${foo}" /> + *    </target> + *  </pre> + * + * <p>This only works as expected if neither property1 nor foo are + *  defined in the project itself. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @copyright 2001,2002 THYRELL. All rights reserved + * @version   $Revision: 1.9 $ + * @access    public + * @package   phing.tasks.system + */ +class PhingCallTask extends Task { + +    private $callee; +    private $subTarget; +    // must match the default value of PhingTask#inheritAll +    private $inheritAll = true; +    // must match the default value of PhingTask#inheritRefs +    private $inheritRefs = false; + +    /** +     *  If true, pass all properties to the new Phing project. +     *  Defaults to true. Future use. +     *  @param boolean new value +     */ +    function setInheritAll($inherit) { +        $this->inheritAll = (boolean) $inherit; +    } + +    /** +     *  If true, pass all references to the new Phing project. +     *  Defaults to false. Future use. +    * +     *  @param boolean new value +     */ +    function setInheritRefs($inheritRefs) { +        $this->inheritRefs = (boolean) $inheritRefs; +    } + +    /** +     *  init this task by creating new instance of the phing task and +     *  configuring it's by calling its own init method. +     */ +    function init() { +        $this->callee = $this->project->createTask("phing"); +        $this->callee->setOwningTarget($this->getOwningTarget()); +        $this->callee->setTaskName($this->getTaskName()); +        $this->callee->setLocation($this->getLocation()); +        $this->callee->init(); +    } + +    /** +     *  hand off the work to the phing task of ours, after setting it up +     *  @throws BuildException on validation failure or if the target didn't +     *  execute +     */ +    function main() {         +             +        $this->log("Running PhingCallTask for target '" . $this->subTarget . "'", PROJECT_MSG_DEBUG); +        if ($this->callee === null) { +            $this->init(); +        } + +        if ($this->subTarget === null) { +            throw new BuildException("Attribute target is required.", $this->location); +        } +         +        $this->callee->setPhingfile($this->project->getProperty("phing.file")); +        $this->callee->setTarget($this->subTarget); +        $this->callee->setInheritAll($this->inheritAll); +        $this->callee->setInheritRefs($this->inheritRefs); +        $this->callee->main(); +    } + +    /** +     * Alias for createProperty +     * @see createProperty() +     */ +    function createParam() { +        if ($this->callee === null) { +            $this->init(); +        } +        return $this->callee->createProperty(); +    } +     +    /** +     * Property to pass to the invoked target. +     */ +    function createProperty() { +        if ($this->callee === null) { +            $this->init(); +        } +        return $this->callee->createProperty(); +    } + +    /** +     * Target to execute, required. +     */ +    function setTarget($target) { +        $this->subTarget = (string) $target; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php new file mode 100644 index 00000000..e9883dd7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php @@ -0,0 +1,596 @@ +<?php + +/* + *  $Id: PhingTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/Task.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/types/Reference.php'; +include_once 'phing/tasks/system/PropertyTask.php'; + +/** + * Task that invokes phing on another build file. + *  + * Use this task, for example, if you have nested buildfiles in your project. Unlike + * AntTask, PhingTask can even support filesets: + *  + * <pre> + *   <phing> + *    <fileset dir="${srcdir}"> + *      <include name="** /build.xml" /> <!-- space added after ** is there because of PHP comment syntax --> + *      <exclude name="build.xml" /> + *    </fileset> + *   </phing> + * </pre> + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.20 $ + * @package   phing.tasks.system + */ +class PhingTask extends Task { + +    /** the basedir where is executed the build file */ +    private $dir; +     +    /** build.xml (can be absolute) in this case dir will be ignored */ +    private $phingFile; +     +    /** the target to call if any */ +    protected $newTarget; +     +    /** should we inherit properties from the parent ? */ +    private $inheritAll = true; +     +    /** should we inherit references from the parent ? */ +    private $inheritRefs = false; + +    /** the properties to pass to the new project */ +    private $properties = array(); + +    /** the references to pass to the new project */ +    private $references = array(); + +    /** The filesets that contain the files PhingTask is to be run on. */ +    private $filesets = array(); + +    /** the temporary project created to run the build file */ +    private $newProject; + +    /** Fail the build process when the called build fails? */ +    private $haltOnFailure = false; + +    /** +     *  If true, abort the build process if there is a problem with or in the target build file. +     *  Defaults to false. +     * +     *  @param boolean new value +     */ +    public function setHaltOnFailure($hof) { +        $this->haltOnFailure = (boolean) $hof; +    } + +    /** +     * Creates a Project instance for the project to call. +     * @return void +     */ +    public function init() { +        $this->newProject = new Project(); +        $tdf = $this->project->getTaskDefinitions(); +        $this->newProject->addTaskDefinition("property", $tdf["property"]); +    } + +    /** +     * Called in execute or createProperty if newProject is null. +     * +     * <p>This can happen if the same instance of this task is run +     * twice as newProject is set to null at the end of execute (to +     * save memory and help the GC).</p> +     * +     * <p>Sets all properties that have been defined as nested +     * property elements.</p> +     */ +    private function reinit() { +        $this->init(); +        $count = count($this->properties); +        for ($i = 0; $i < $count; $i++) { +            $p = $this->properties[$i]; +            $newP = $this->newProject->createTask("property"); +            $newP->setName($p->getName()); +            if ($p->getValue() !== null) { +                $newP->setValue($p->getValue()); +            } +            if ($p->getFile() !== null) { +                $newP->setFile($p->getFile()); +            }             +            if ($p->getPrefix() !== null) { +                $newP->setPrefix($p->getPrefix()); +            } +            if ($p->getRefid() !== null) { +                $newP->setRefid($p->getRefid()); +            } +            if ($p->getEnvironment() !== null) { +                $newP->setEnvironment($p->getEnvironment()); +            } +            if ($p->getUserProperty() !== null) { +                $newP->setUserProperty($p->getUserProperty()); +            } +            if ($p->getOverride() !== null) { +                $newP->setOverride($p->getOverride()); +            } +            $this->properties[$i] = $newP; +        } +    } + +    /** +     * Main entry point for the task. +     * +     * @return void +     */ +    public function main() { +     +        // Call Phing on the file set with the attribute "phingfile" +        if ($this->phingFile !== null or $this->dir !== null) { +            $this->processFile(); +        } + +        // if no filesets are given stop here; else process filesets +        if (empty($this->filesets)) {  +            return; +        } +         +        // preserve old settings +        $savedDir = $this->dir; +        $savedPhingFile = $this->phingFile; +        $savedTarget = $this->newTarget; +        $buildFailed = false; + +        // set no specific target for files in filesets +        // [HL] I'm commenting this out; I don't know why this should not be supported! +        // $this->newTarget = null; +         +        foreach($this->filesets as $fs) { + +            $ds = $fs->getDirectoryScanner($this->project); + +            $fromDir  = $fs->getDir($this->project); +            $srcFiles = $ds->getIncludedFiles(); + +            foreach($srcFiles as $fname) {             +                $f = new PhingFile($ds->getbasedir(), $fname); +                $f = $f->getAbsoluteFile(); +                $this->phingFile = $f->getAbsolutePath(); +                $this->dir = $f->getParentFile(); +                $this->processFile();    // run Phing! +            } +        }         +         +        // side effect free programming ;-) +        $this->dir = $savedDir;         +        $this->phingFile = $savedPhingFile; +        $this->newTarget = $savedTarget; +         +        // [HL] change back to correct dir +        if ($this->dir !== null) { +            chdir($this->dir->getAbsolutePath()); +        } +         +    } +     +    /** +     * Execute phing file. +     *  +     * @return void +     */ +    private function processFile()  { +             +        $savedDir = $this->dir; +        $savedPhingFile = $this->phingFile; +        $savedTarget = $this->newTarget; +         +        try { +            if ($this->newProject === null) { +                $this->reinit(); +            } + +            if (($this->dir === null) && ($this->inheritAll)) { +                $this->dir = $this->getProject()->getBaseDir(); +            } +            $this->initializeProject(); +            if ($this->dir !== null) { +                $this->newProject->setBaseDir($this->dir); +                if ($savedDir !== null) { // has been set explicitly +                    $this->newProject->setInheritedProperty("project.basedir", $this->dir->getAbsolutePath()); +                }                                 +            } else { +                $this->dir = $this->getProject()->getBaseDir(); +            } + +            $this->overrideProperties(); +            if ($this->phingFile === null) { +                $this->phingFile = "build.xml"; +            } +             +            $fu = new FileUtils(); +            $file = $fu->resolveFile($this->dir, $this->phingFile); +            $this->phingFile = $file->getAbsolutePath(); +             +            $this->log("Calling Buildfile '" . $this->phingFile . "' with target '" . $this->newTarget . "'"); +                         +            $this->newProject->setUserProperty("phing.file", $this->phingFile); +                        +            ProjectConfigurator::configureProject($this->newProject, new PhingFile($this->phingFile)); + +            if ($this->newTarget === null) { +                $this->newTarget = $this->newProject->getDefaultTarget(); +            } + +            // Are we trying to call the target in which we are defined? +            if ($this->newProject->getBaseDir() == $this->project->getBaseDir() && +                $this->newProject->getProperty("phing.file") == $this->project->getProperty("phing.file") && +                $this->getOwningTarget() !== null && +                $this->newTarget == $this->getOwningTarget()->getName()) { + +                throw new BuildException("phing task calling its own parent target"); +            } + +            $this->addReferences(); +            $this->newProject->executeTarget($this->newTarget); +             +        } catch (Exception $e) { +            $buildFailed = true; +            $this->log($e->getMessage(), PROJECT_MSG_ERR); +             +            // important!!! continue on to perform cleanup +            // tasks.     +           } +         +        //  } finally { +        // restore values (prevent side-effects) +        // !this must match code in catch () {}  block! +        $this->newProject = null; +        $pkeys = array_keys($this->properties); +        foreach($pkeys as $k) { +            $this->properties[$k]->setProject(null); +        }         +        $this->dir = $savedDir;         +        $this->phingFile = $savedPhingFile; +        $this->newTarget = $savedTarget; +         +        // [HL] change back to correct dir +        if ($this->dir !== null) { +            chdir($this->dir->getAbsolutePath()); +        } + +        if ($this->haltOnFailure == true && $buildFailed == true) +            throw new BuildException("Execution of the target buildfile failed. Aborting."); +    } + +    /** +     * Configure the Project, i.e. make intance, attach build listeners +     * (copy from father project), add Task and Datatype definitions, +     * copy properties and references from old project if these options +     * are set via the attributes of the XML tag. +     * +     * Developer note: +     * This function replaces the old methods "init", "_reinit" and  +     * "_initializeProject". +     * +     * @access      protected +     */ +    private function initializeProject() { +         +        $this->newProject->setInputHandler($this->project->getInputHandler()); +         +        foreach($this->project->getBuildListeners() as $listener) { +            $this->newProject->addBuildListener($listener); +        } +         +        /* Copy things from old project. Datatypes and Tasks are always +         * copied, properties and references only if specified so/not +         * specified otherwise in the XML definition. +         */ +        // Add Datatype definitions +        foreach ($this->project->getDataTypeDefinitions() as $typeName => $typeClass) { +            $this->newProject->addDataTypeDefinition($typeName, $typeClass); +        } +         +        // Add Task definitions +        foreach ($this->project->getTaskDefinitions() as $taskName => $taskClass) { +            if ($taskClass == "propertytask") { +                // we have already added this taskdef in init() +                continue; +            } +            $this->newProject->addTaskDefinition($taskName, $taskClass); +        } + +        // set user-defined properties +        $this->project->copyUserProperties($this->newProject); + +        if (!$this->inheritAll) { +           // set System built-in properties separately, +           // b/c we won't inherit them. +           $this->newProject->setSystemProperties(); + +        } else { +            // set all properties from calling project +            $properties = $this->project->getProperties(); +            foreach ($properties as $name => $value) {                 +                if ($name == "basedir" || $name == "phing.file" || $name == "phing.version") { +                    // basedir and phing.file get special treatment in main() +                    continue; +                } +                   // don't re-set user properties, avoid the warning message +                if ($this->newProject->getProperty($name) === null){ +                    // no user property +                    $this->newProject->setNewProperty($name, $value); +                } +            } +             +        } +     +    } + +    /** +     * Override the properties in the new project with the one +     * explicitly defined as nested elements here. +     * @return void +     * @throws BuildException  +     */ +    private function overrideProperties() {      +        foreach(array_keys($this->properties) as $i) { +            $p = $this->properties[$i]; +            $p->setProject($this->newProject); +            $p->main(); +        } +        $this->project->copyInheritedProperties($this->newProject); +    } + +    /** +     * Add the references explicitly defined as nested elements to the +     * new project.  Also copy over all references that don't override +     * existing references in the new project if inheritrefs has been +     * requested. +     *  +     * @return void +     * @throws BuildException  +     */ +    private function addReferences() { +     +        // parent project references +        $projReferences = $this->project->getReferences(); +         +        $newReferences = $this->newProject->getReferences(); +         +        $subprojRefKeys = array(); +         +        if (count($this->references) > 0) { +            for ($i=0, $count=count($this->references); $i < $count; $i++) { +                $ref = $this->references[$i];             +                $refid = $ref->getRefId(); +                 +                if ($refid === null) { +                    throw new BuildException("the refid attribute is required" +                                             . " for reference elements"); +                } +                if (!isset($projReferences[$refid])) { +                    $this->log("Parent project doesn't contain any reference '" +                        . $refid . "'", +                        PROJECT_MSG_WARN); +                    continue; +                } +                 +                $subprojRefKeys[] = $refid; +                //thisReferences.remove(refid); +                $toRefid = $ref->getToRefid(); +                if ($toRefid === null) { +                    $toRefid = $refid; +                } +                $this->copyReference($refid, $toRefid); +            } +        } + +        // Now add all references that are not defined in the +        // subproject, if inheritRefs is true +        if ($this->inheritRefs) { +         +            // get the keys that are were not used by the subproject +            $unusedRefKeys = array_diff(array_keys($projReferences), $subprojRefKeys); +             +            foreach($unusedRefKeys as $key) { +                if (isset($newReferences[$key])) { +                    continue; +                } +                $this->copyReference($key, $key); +            } +        } +    } + +    /** +     * Try to clone and reconfigure the object referenced by oldkey in +     * the parent project and add it to the new project with the key +     * newkey. +     * +     * <p>If we cannot clone it, copy the referenced object itself and +     * keep our fingers crossed.</p> +     * +     * @param string $oldKey +     * @param string $newKey +     * @return void +     */ +    private function copyReference($oldKey, $newKey) { +        $orig = $this->project->getReference($oldKey); +        if ($orig === null) { +            $this->log("No object referenced by " . $oldKey . ". Can't copy to "  +                .$newKey,  +                PROJECT_SG_WARN); +            return; +        } + +        $copy = clone $orig; + +        if ($copy instanceof ProjectComponent) { +            $copy->setProject($this->newProject); +        } elseif (in_array('setProject', get_class_methods(get_class($copy)))) { +            $copy->setProject($this->newProject); +		} elseif ($copy instanceof Project) { +			// don't copy the old "Project" itself +        } else { +            $msg = "Error setting new project instance for " +                . "reference with id " . $oldKey; +            throw new BuildException($msg); +        } +         +        $this->newProject->addReference($newKey, $copy); +    } + +    /** +     * If true, pass all properties to the new phing project. +     * Defaults to true. +     * +     * @access      public +     */ +    function setInheritAll($value) { +        $this->inheritAll = (boolean) $value; +    } + +    /** +     * If true, pass all references to the new phing project. +     * Defaults to false. +     * +     * @access      public +     */ +    function setInheritRefs($value) { +        $this->inheritRefs = (boolean)$value; +    } + +    /** +     * The directory to use as a base directory for the new phing project. +     * Defaults to the current project's basedir, unless inheritall +     * has been set to false, in which case it doesn't have a default +     * value. This will override the basedir setting of the called project. +     * +     * @access      public +     */ +    function setDir($d) { +        if ( is_string($d) ) +            $this->dir = new PhingFile($d); +        else +            $this->dir = $d; +    } + +    /** +     * The build file to use. +     * Defaults to "build.xml". This file is expected to be a filename relative +     * to the dir attribute given. +     * +     * @access      public +     */ +    function setPhingfile($s) { +        // it is a string and not a file to handle relative/absolute +        // otherwise a relative file will be resolved based on the current +        // basedir. +        $this->phingFile = $s; +    } + +   /** +    * Alias function for setPhingfile +    * +    * @access       public +    */ +    function setBuildfile($s) { +        $this->setPhingFile($s); +    } + +    /** +     * The target of the new Phing project to execute. +     * Defaults to the new project's default target. +     * +     * @access      public +     */ +    function setTarget($s) { +        $this->newTarget = $s; +    } + +    /** +     * Support for filesets; This method returns a reference to an instance +     * of a FileSet object. +     * +     * @return FileSet +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +    /** +     * Property to pass to the new project. +     * The property is passed as a 'user property' +     * +     * @access      public +     */ +    function createProperty() { +        $p = new PropertyTask(); +        $p->setFallback($this->newProject); +        $p->setUserProperty(true); +        $this->properties[] = $p; +        return $p; +    } + +    /** +     * Reference element identifying a data type to carry +     * over to the new project. +     * +     * @access      public +     */ +    function createReference() { +        $num = array_push($this->references, new PhingReference()); +        return $this->references[$num-1]; +    } + +} + +/** + * Helper class that implements the nested <reference> + * element of <phing> and <phingcall>. + */ +class PhingReference extends Reference { + +    private $targetid = null; + +    /** +     * Set the id that this reference to be stored under in the +     * new project. +     * +     * @param targetid the id under which this reference will be passed to +     *        the new project */ +    public function setToRefid($targetid) { +        $this->targetid = $targetid; +    } + +    /** +     * Get the id under which this reference will be stored in the new +     * project +     * +     * @return the id of the reference in the new project. +     */ +    public function getToRefid() { +        return $this->targetid; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php b/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php new file mode 100644 index 00000000..f1b72815 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php @@ -0,0 +1,169 @@ +<?php +/* + *  $Id: PhpEvalTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; + +/** + * Executes PHP function or evaluates expression and sets return value to a property. + * + *    WARNING: + *        This task can, of course, be abused with devastating effects.  E.g. do not + *        modify internal Phing classes unless you know what you are doing. + * + * @author   Hans Lellelid <hans@xmpl.org> + * @version  $Revision: 1.7 $ + * @package  phing.tasks.system + * + * @todo Add support for evaluating expressions + */ +class PhpEvalTask extends Task { +         +    protected $expression; // Expression to evaluate +    protected $function; // Function to execute +    protected $class; // Class containing function to execute +    protected $returnProperty; // name of property to set to return value  +    protected $params = array(); // parameters for function calls +     +    /** Main entry point. */ +    function main() { +         +        if ($this->function === null && $this->expression === null) { +            throw new BuildException("You must specify a function to execute or PHP expression to evalute.", $this->location); +        } +         +        if ($this->function !== null && $this->expression !== null) { +            throw new BuildException("You can specify function or expression, but not both.", $this->location); +        } +         +        if ($this->expression !== null && !empty($this->params)) { +            throw new BuildException("You cannot use nested <param> tags when evaluationg a PHP expression.", $this->location); +        } +         +        $retval = null; +        if ($this->function !== null) { +            $retval = $this->callFunction();                                     +        } elseif ($this->expression !== null) { +            $retval = $this->evalExpression(); +        } +         +        if ($this->returnProperty !== null) { +            $this->project->setProperty($this->returnProperty, $retval); +        } +    } +     +    /** +     * Calls function and returns results. +     * @return mixed +     */ +    protected function callFunction() { +                         +        if ($this->class !== null) { +            // import the classname & unqualify it, if necessary +            $this->class = Phing::import($this->class); +                         +            $user_func = array($this->class, $this->function); +            $h_func = $this->class . '::' . $this->function; // human-readable (for log) +        } else { +            $user_func = $this->function; +            $h_func = $user_func; // human-readable (for log) +        } +         +        // put parameters into simple array +        $params = array(); +        foreach($this->params as $p) { +            $params[] = $p->getValue(); +        } +         +        $this->log("Calling PHP function: " . $h_func . "()"); +        foreach($params as $p) { +            $this->log("  param: " . $p, PROJECT_MSG_VERBOSE); +        }  +         +        $return = call_user_func_array($user_func, $params); +        return $return; +    } +     +    /** +     * Evaluates expression and returns resulting value. +     * @return mixed +     */ +    protected function evalExpression() { +        $this->log("Evaluating PHP expression: " . $this->expression); +        if (!StringHelper::endsWith(';', trim($this->expression))) { +            $this->expression .= ';'; +        } +        $retval = null; +        eval('$retval = ' . $this->expression); +        return $retval; +    } +     +    /** Set function to execute */ +    public function setFunction($f) { +       $this->function = $f; +    } + +    /** Set [static] class which contains function to execute */ +    public function setClass($c) { +       $this->class = $c; +    } +     +    /** Sets property name to set with return value of function or expression.*/ +    public function setReturnProperty($r) { +       $this->returnProperty = $r; +    } +     +    /** Set PHP expression to evaluate. */ +    public function addText($expression) { +        $this->expression = $expression; +    } + +    /** Set PHP expression to evaluate. */ +    public function setExpression($expression) { +        $this->expression = $expression; +    } +     +    /** Add a nested <param> tag. */ +    public function createParam() { +        $p = new FunctionParam(); +        $this->params[] = $p; +        return $p; +    }         +} + +/** + * Supports the <param> nested tag for PhpTask. + */ +class FunctionParam { + +    private $val; +     +    public function setValue($v) { +        $this->val = $v; +    } +     +    public function addText($v) { +        $this->val = $v; +    } +     +    public function getValue() { +        return $this->val; +    } +}
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php new file mode 100644 index 00000000..e7e12f33 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php @@ -0,0 +1,201 @@ +<?php +/* + *  $Id: PropertyPromptTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/system/io/ConsoleReader.php'; + +/** + * Deprecated task that uses console to prompt user for property values. + *  + * This class is very slightly simpler than the InputTask, but lacks the ability + * to use a non-console input handler.  You should, therefore, use InputTask.  This + * class can serve as a reference, but will be removed in the future. + *  + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Anthony J. Young-Garner <ajyoung@alum.mit.edu> (Ant) + * @version   $Revision: 1.4 $ + * @package   phing.tasks.system + * @deprecated - in favor of the more capable InputTask + */  +class PropertyPromptTask extends Task { + +    private $propertyName;        // required +    private $defaultValue; +    private $proposedValue;        // required +    private $promptText;        // required +    private $promptCharacter; +    private $useExistingValue; + +    /** +     * Sets the prompt text that will be presented to the user. +     * @param string $prompt +     * @return void +     */ +    public function addText($prompt) { +        $this->setPromptText($prompt); +    } + +    /** +     * Run the PropertyPrompt task. +     * @throws BuildException +     */ +    public function main() { +        $this->proposedValue = $this->project->getProperty($this->propertyName); +        $currentValue = $this->defaultValue; +        if ($currentValue == "" && $this->proposedValue !== null) { $currentValue = $this->proposedValue; } +        if (! (($this->useExistingValue === true) && ($this->proposedValue !== null))) { +                         +            $this->log("Prompting user for " . $this->propertyName . ". " . $this->getDefaultMessage(), PROJECT_MSG_VERBOSE); +             +            print "\n" . $this->promptText . " [" . $currentValue . "] " . $this->promptCharacter . " "; + +            /** future version should probably have hooks for validation of user input.*/ +            $reader = new ConsoleReader(); +             +            try { +                $this->proposedValue  = $reader->readLine(); +            } catch (IOException $e) { +                $this->log("Prompt failed. Using default. (Failure reason: " . $e->getMessage().")"); +                $this->proposedValue = $this->defaultValue; +            } +             +            if (empty($this->proposedValue)) { +                $this->log("No value specified, using default.", PROJECT_MSG_VERBOSE); +                $this->proposedValue = $this->defaultValue; +            } +             +            if (!empty($this->proposedValue)) {                     +                $this->project->setProperty($this->propertyName, $this->proposedValue); +            } +              +        }     +    } +     +    /** +     * Returns a string to be inserted in the log message +     * indicating whether a default response was specified +     * in the build file. +     */ +    private function getDefaultMessage() { +        if ($this->defaultValue == "") { +            return "No default response specified."; +        } else return "Default response is " . $this->defaultValue . "."; +    } +     +    /** +     * Returns defaultValue specified  +     * in this task for the Property +     * being set. +     * @return string +     */ +    public function getDefaultValue() { +        return $this->defaultValue; +    } +     +    /** +     * Returns the terminating character used to  +     * punctuate the prompt text. +     * @return string +     */ +    public function getPromptCharacter() { +        return $this->promptCharacter; +    } +     +    /** +     * Returns text of the prompt. +     * @return java.lang.String +     */ +    public function getPromptText() { +        return $this->promptText; +    } +     +    /** +     * Returns name of the Ant Project Property +     * being set by this task. +     * @return string +     */ +    public function getPropertyName() { +        return $this->propertyName; +    } +    /** +     * Initializes this task. +     */ +    public function init() { +        parent::init(); +        $this->defaultValue    = ""; +        $this->promptCharacter = "?"; +        $this->useExistingValue = false; +    } +         +    /** +     * Insert the method's description here. +     * Creation date: (12/10/2001 8:16:16 AM) +     * @return boolean +     */ +    public function isUseExistingValue() { +        return $this->useExistingValue; +    } +     +    /** +     * Sets defaultValue for the Property +     * being set by this task. +     * @param string $newDefaultvalue +     */ +    public function setDefaultvalue($newDefaultvalue) { +        $this->defaultValue = $newDefaultvalue; +    } +     +    /** +     * Sets the terminating character used to  +     * punctuate the prompt text (default is "?"). +     * @param newPromptcharacter java.lang.String +     */ +    public function setPromptCharacter($newPromptcharacter) { +        $this->promptCharacter = $newPromptcharacter; +    } +     +    /** +     * Sets text of the prompt. +     * @param newPrompttext java.lang.String +     */ +    public function setPromptText($newPrompttext) { +        $this->promptText = $newPrompttext; +    } +     +    /** +     * Specifies the Phing Project Property +     * being set by this task. +     * @param newPropertyname java.lang.String +     */ +    public function setPropertyName($newPropertyname) { +        $this->propertyName = $newPropertyname; +    } +     +    /** +     *  +     *  +     * @param boolean newUseExistingValue +     */ +    public function setUseExistingValue($newUseExistingValue) { +        $this->useExistingValue = $newUseExistingValue; +    } +     +} diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php new file mode 100644 index 00000000..d6168e44 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php @@ -0,0 +1,438 @@ +<?php + +/* + *  $Id: PropertyTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/Task.php'; +include_once 'phing/system/util/Properties.php'; + +/** + * Task for setting properties in buildfiles. + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision$ + * @package   phing.tasks.system + */ +class PropertyTask extends Task { + +    /** name of the property */ +    protected $name;  +     +    /** value of the property */ +    protected $value; +     +    protected $reference; +    protected $env;     // Environment +    protected $file; +    protected $ref; +    protected $prefix; +    protected $fallback; +     +    /** Whether to force overwrite of existing property. */ +    protected $override = false; +     +    /** Whether property should be treated as "user" property. */ +    protected $userProperty = false; + +    /** +     * Sets a the name of current property component +     */ +    function setName($name) { +        $this->name = (string) $name; +    } +     +    /** Get property component name. */ +    function getName() { +        return $this->name; +    } + +    /** +     * Sets a the value of current property component. +     * @param    mixed      Value of name, all scalars allowed +     */ +    function setValue($value) { +        $this->value = (string) $value; +    } +	 +	/** +	 * Sets value of property to CDATA tag contents. +	 * @param string $values +	 * @since 2.2.0 +	 */ +	public function addText($value) { +		$this->setValue($value); +	} +     +    /** Get the value of current property component. */ +    function getValue() { +        return $this->value; +    } +     +    /** Set a file to use as the source for properties. */ +    function setFile($file) { +        if (is_string($file)) { +            $file = new PhingFile($file); +        } +        $this->file = $file; +    } +     +    /** Get the PhingFile that is being used as property source. */ +    function getFile() { +        return $this->file; +    } + +    function setRefid(Reference $ref) { +        $this->reference = $ref; +    } +     +    function getRefid() { +        return $this->reference; +    } + +    /** +     * Prefix to apply to properties loaded using <code>file</code>. +     * A "." is appended to the prefix if not specified. +     * @param string $prefix prefix string +     * @return void +     * @since 2.0 +     */ +    public function setPrefix($prefix) { +        $this->prefix = $prefix; +        if (!StringHelper::endsWith(".", $prefix)) { +            $this->prefix .= "."; +        } +    } + +    /** +     * @return string +     * @since 2.0 +     */ +    public function getPrefix() { +        return $this->prefix; +    } + +    /** +    * the prefix to use when retrieving environment variables. +    * Thus if you specify environment="myenv" +    * you will be able to access OS-specific +    * environment variables via property names "myenv.PATH" or +    * "myenv.TERM". +    * <p> +    * Note that if you supply a property name with a final +    * "." it will not be doubled. ie environment="myenv." will still +    * allow access of environment variables through "myenv.PATH" and +    * "myenv.TERM". This functionality is currently only implemented +    * on select platforms. Feel free to send patches to increase the number of platforms +    * this functionality is supported on ;).<br> +    * Note also that properties are case sensitive, even if the +    * environment variables on your operating system are not, e.g. it +    * will be ${env.Path} not ${env.PATH} on Windows 2000. +    * @param env prefix +    */ +    function setEnvironment($env) { +        $this->env = (string) $env; +    } + +    function getEnvironment() { +        return $this->env; +    } +     +    /** +     * Set whether this is a user property (ro). +     * This is deprecated in Ant 1.5, but the userProperty attribute +     * of the class is still being set via constructor, so Phing will +     * allow this method to function. +     * @param boolean $v +     */ +    function setUserProperty($v) { +        $this->userProperty = (boolean) $v; +    } +     +    function getUserProperty() { +        return $this->userProperty; +    } +     +    function setOverride($v) { +        $this->override = (boolean) $v; +    } +     +    function getOverride() { +        return $this->override; +    } +     +    function toString() { +        return (string) $this->value; +    } + +	/** +	 * @param Project $p +	 */ +    function setFallback($p) { +        $this->fallback = $p; +    } +     +    function getFallback() { +        return $this->fallback; +    } +    /** +     * set the property in the project to the value. +     * if the task was give a file or env attribute +     * here is where it is loaded +     */ +    function main() { +        if ($this->name !== null) { +            if ($this->value === null && $this->ref === null) { +                throw new BuildException("You must specify value or refid with the name attribute", $this->getLocation()); +            } +        } else { +            if ($this->file === null && $this->env === null ) { +                throw new BuildException("You must specify file or environment when not using the name attribute", $this->getLocation()); +            } +        } + +        if ($this->file === null && $this->prefix !== null) { +            throw new BuildException("Prefix is only valid when loading from a file.", $this->getLocation()); +        } +         +        if (($this->name !== null) && ($this->value !== null)) { +            $this->addProperty($this->name, $this->value); +        } + +        if ($this->file !== null) { +            $this->loadFile($this->file); +        } + +        if ( $this->env !== null ) { +            $this->loadEnvironment($this->env); +        } + +        if (($this->name !== null) && ($this->ref !== null)) { +            // get the refereced property +            try { +            $this->addProperty($this->name, $this->reference->getReferencedObject($this->project)->toString()); +            } catch (BuildException $be) { +                if ($this->fallback !== null) { +                     $this->addProperty($this->name, $this->reference->getReferencedObject($this->fallback)->toString()); +                } else { +                    throw $be; +                } +            } +        } +    } +     +    /** +     * load the environment values +     * @param string $prefix prefix to place before them +     */ +    protected function loadEnvironment($prefix) { + +        $props = new Properties(); +        if ( substr($prefix, strlen($prefix)-1) == '.' ) { +            $prefix .= "."; +        } +        $this->log("Loading Environment $prefix", PROJECT_MSG_VERBOSE); +        foreach($_ENV as $key => $value) { +            $props->setProperty($prefix . '.' . $key, $value); +        } +        $this->addProperties($props); +    } + +    /** +     * iterate through a set of properties, +     * resolve them then assign them +     */ +    protected function addProperties($props) { +        $this->resolveAllProperties($props); +        foreach($props->keys() as $name) {         +            $value = $props->getProperty($name); +            $v = $this->project->replaceProperties($value);             +            if ($this->prefix !== null) { +                $name = $this->prefix . $name; +            } +            $this->addProperty($name, $v); +        } +    } + +    /** +     * add a name value pair to the project property set +     * @param string $name name of property +     * @param string $value value to set +     */ +    protected function addProperty($name, $value) { +        if ($this->userProperty) { +            if ($this->project->getUserProperty($name) === null || $this->override) { +                $this->project->setInheritedProperty($name, $value); +            } else { +                $this->log("Override ignored for " . $name, PROJECT_MSG_VERBOSE); +            } +        } else { +            if ($this->override) { +                $this->project->setProperty($name, $value); +            } else { +                $this->project->setNewProperty($name, $value); +            } +        } +    } + +    /** +     * load properties from a file. +     * @param PhingFile $file +     */ +    protected function loadFile(PhingFile $file) { +        $props = new Properties(); +        $this->log("Loading ". $file->getAbsolutePath(), PROJECT_MSG_INFO); +        try { // try to load file +            if ($file->exists()) { +                $props->load($file); +                $this->addProperties($props); +            } else { +                $this->log("Unable to find property file: ". $file->getAbsolutePath() ."... skipped", PROJECT_MSG_WARN); +            } +        } catch (IOException $ioe) { +            throw new BuildException("Could not load properties from file.", $ioe); +        } +    } +     +    /** +     * Given a Properties object, this method goes through and resolves +     * any references to properties within the object. +     *  +     * @param Properties $props The collection of Properties that need to be resolved. +     * @return void +     */ +    protected function resolveAllProperties(Properties $props) { +         +        $keys = $props->keys(); + +        while(count($keys)) { + +            // There may be a nice regex/callback way to handle this +            // replacement, but at the moment it is pretty complex, and +            // would probably be a lot uglier to work into a preg_replace_callback() +            // system.  The biggest problem is the fact that a resolution may require +            // multiple passes. +             +            $name     = array_shift($keys); +            $value    = $props->getProperty($name); +            $resolved = false; +             +            while(!$resolved) { +             +                $fragments = array(); +                $propertyRefs = array(); + +                // [HL] this was ::parsePropertyString($this->value ...) ... this seems wrong +                self::parsePropertyString($value, $fragments, $propertyRefs); + +                $resolved = true; +                if (count($propertyRefs) !== 0) { + +                    $sb = ""; + +                    $i = $fragments; +                    $j = $propertyRefs; +                    while(count($i)) { +                        $fragment = array_shift($i); +                        if ($fragment === null) { +                            $propertyName = array_shift($j); + +                            if ($propertyName === $name) { +                                // Should we maybe just log this as an error & move on? +                                // $this->log("Property ".$name." was circularly defined.", PROJECT_MSG_ERR); +                                throw new BuildException("Property ".$name." was circularly defined."); +                            } + +                            $fragment = $this->getProject()->getProperty($propertyName); +                            if ($fragment === null) { +                                if ($props->containsKey($propertyName)) { +                                    $fragment = $props->getProperty($propertyName); +                                    $resolved = false; // parse again (could have been replaced w/ another var) +                                } else { +                                    $fragment = "\${".$propertyName."}"; +                                } +                            } +                        } +                        $sb .= $fragment; +                    } +                     +                    $this->log("Resolved Property \"$value\" to \"$sb\"", PROJECT_MSG_DEBUG); +                    $value = $sb;                     +                    $props->setProperty($name, $value); +                                  +                } // if (count($propertyRefs)) +                 +            } // while (!$resolved) +             +        } // while (count($keys) +    } + + +     /** +     * This method will parse a string containing ${value} style +     * property values into two lists. The first list is a collection +     * of text fragments, while the other is a set of string property names +     * null entries in the first list indicate a property reference from the +     * second list. +     * +     * This is slower than regex, but useful for this class, which has to handle +     * multiple parsing passes for properties. +     * +     * @param string $value The string to be scanned for property references +     * @param array &$fragments The found fragments +     * @param  array &$propertyRefs The found refs +     */ +    protected function parsePropertyString($value, &$fragments, &$propertyRefs) { +     +        $prev = 0; +        $pos  = 0; + +        while (($pos = strpos($value, '$', $prev)) !== false) { +             +            if ($pos > $prev) { +                array_push($fragments, StringHelper::substring($value, $prev, $pos-1)); +            } +            if ($pos === (strlen($value) - 1)) { +                array_push($fragments, '$'); +                $prev = $pos + 1; +            } elseif ($value{$pos+1} !== '{' ) { + +                // the string positions were changed to value-1 to correct +                // a fatal error coming from function substring() +                array_push($fragments, StringHelper::substring($value, $pos, $pos + 1)); +                $prev = $pos + 2; +            } else { +                $endName = strpos($value, '}', $pos); +                if ($endName === false) { +                    throw new BuildException("Syntax error in property: $value"); +                } +                $propertyName = StringHelper::substring($value, $pos + 2, $endName-1); +                array_push($fragments, null); +                array_push($propertyRefs, $propertyName); +                $prev = $endName + 1; +            } +        } + +        if ($prev < strlen($value)) { +            array_push($fragments, StringHelper::substring($value, $prev)); +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php b/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php new file mode 100644 index 00000000..dc7cfeb7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php @@ -0,0 +1,155 @@ +<?php +/* + *  $Id: ReflexiveTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * This task is for using filter chains to make changes to files and overwrite the original files. + *  + * This task was created to serve the need for "cleanup" tasks -- e.g. a ReplaceRegexp task or strip task + * being used to modify files and then overwrite the modified files.  In many (most?) cases you probably + * should just use a copy task  to preserve the original source files, but this task supports situations + * where there is no src vs. build directory, and modifying source files is actually desired. + *  + * <code> + *    <reflexive> + *        <fileset dir="."> + *            <include pattern="*.html"> + *        </fileset> + *        <filterchain> + *            <replaceregexp> + *                <regexp pattern="\n\r" replace="\n"/> + *            </replaceregexp> + *        </filterchain>  + *    </reflexive> + * </code> + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.11 $ + * @package   phing.tasks.system + */ +class ReflexiveTask extends Task { +     +    /** Single file to process. */ +    private $file; +     +    /** Any filesets that should be processed. */ +    private $filesets = array(); +     +    /** Any filters to be applied before append happens. */ +    private $filterChains = array(); +         +    /** Alias for setFrom() */ +    function setFile(PhingFile $f) { +        $this->file = $f; +    } +     +    /** Nested creator, adds a set of files (nested fileset attribute). */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +    /** +     * Creates a filterchain +     * +     * @return  object  The created filterchain object +     */ +    function createFilterChain() { +        $num = array_push($this->filterChains, new FilterChain($this->project)); +        return $this->filterChains[$num-1]; +    }                     +     +    /** Append the file(s). */ +    function main() { +             +        if ($this->file === null && empty($this->filesets)) { +            throw new BuildException("You must specify a file or fileset(s) for the <reflexive> task."); +        } +         +        // compile a list of all files to modify, both file attrib and fileset elements +        // can be used. +         +        $files = array(); +         +        if ($this->file !== null) { +            $files[] = $this->file; +        } +         +        if (!empty($this->filesets)) { +            $filenames = array(); +            foreach($this->filesets as $fs) { +                try { +                    $ds = $fs->getDirectoryScanner($this->project); +                    $filenames = $ds->getIncludedFiles(); // get included filenames +                    $dir = $fs->getDir($this->project); +                    foreach ($filenames as $fname) { +                        $files[] = new PhingFile($dir, $fname); +                    } +                } catch (BuildException $be) { +                    $this->log($be->getMessage(), PROJECT_MSG_WARN); +                } +            }                         +        } +         +        $this->log("Applying reflexive processing to " . count($files) . " files."); + +		// These "slots" allow filters to retrieve information about the currently-being-process files		 +		$slot = $this->getRegisterSlot("currentFile"); +		$basenameSlot = $this->getRegisterSlot("currentFile.basename");	 + +         +        foreach($files as $file) { +			// set the register slots +			 +			$slot->setValue($file->getPath()); +			$basenameSlot->setValue($file->getName()); +			 +            // 1) read contents of file, pulling through any filters +            $in = null; +            try {                 +                $contents = ""; +                $in = FileUtils::getChainedReader(new FileReader($file), $this->filterChains, $this->project); +                while(-1 !== ($buffer = $in->read())) { +                    $contents .= $buffer; +                } +                $in->close(); +            } catch (Exception $e) { +                if ($in) $in->close(); +                $this->log("Erorr reading file: " . $e->getMessage(), PROJECT_MSG_WARN); +            } +             +            try { +                // now create a FileWriter w/ the same file, and write to the file +                $out = new FileWriter($file); +                $out->write($contents); +                $out->close(); +                $this->log("Applying reflexive processing to " . $file->getPath(), PROJECT_MSG_VERBOSE); +            } catch (Exception $e) { +                if ($out) $out->close(); +                $this->log("Error writing file back: " . $e->getMessage(), PROJECT_MSG_WARN); +            } +             +        } +                                 +    }    + +}
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php new file mode 100644 index 00000000..b468afb5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php @@ -0,0 +1,122 @@ +<?php +/* + *  $Id: ResolvePathTask.php 59 2006-04-28 14:49:47Z mrook $   + *  + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Task for resolving relative paths and setting absolute path in property value. + *  + * This task was created to address a need for resolving absolute paths of files / directories. + * In many cases a relative directory (e.g. "./build") is specified, but it needs to be treated + * as an absolute path since other build files (e.g. in subdirs) should all be using the same + * path -- and not treating it as a relative path to their own directory. + *  + * <code> + * <property name="relative_path" value="./dirname"/> + * <resolvepath propertyName="absolute_path" file="${relative_path}"/> + * <echo>Resolved [absolute] path: ${absolute_path}</echo> + * </code> + *  + * TODO: + *      - Possibly integrate this with PackageAsPath, for handling/resolving dot-path paths. + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.6 $ + * @package   phing.tasks.system + */ +class ResolvePathTask extends Task { + +    /** Name of property to set. */ +    private $propertyName; +     +    /** The [possibly] relative file/path that needs to be resolved. */ +    private $file; +     +    /** Base directory used for resolution. */ +    private $dir; +     +    /** +     * Set the name of the property to set. +     * @param string $v Property name +     * @return void +     */ +    public function setPropertyName($v) { +        $this->propertyName = $v; +    } +     +    /** +     * Sets a base dir to use for resolution. +     * @param PhingFile $d +     */ +    function setDir(PhingFile $d) { +        $this->dir = $d; +    } +     +    /** +     * Sets a path (file or directory) that we want to resolve. +     * This is the same as setFile() -- just more generic name so that it's +     * clear that you can also use it to set directory. +     * @param string $f +     * @see setFile() +     */ +    function setPath($f) { +        $this->file = $f; +    } +     +    /** +     * Sets a file that we want to resolve. +     * @param string $f +     */ +    function setFile($f) { +        $this->file = $f; +    } + +    /** +     * Perform the resolution & set property. +     */ +    public function main() {         +         +        if (!$this->propertyName) { +            throw new BuildException("You must specify the propertyName attribute", $this->getLocation()); +        } +         +        // Currently only files are supported +        if ($this->file === null) { +            throw new BuildException("You must specify a path to resolve", $this->getLocation()); +        } +         +		$fs = FileSystem::getFileSystem(); +		 +        // if dir attribute was specified then we should +        // use that as basedir to which file was relative. +		// -- unless the file specified is an absolute path +        if ($this->dir !== null && !$fs->isAbsolute(new PhingFile($this->file))) { +            $resolved = new PhingFile($this->dir->getPath(), $this->file); +        } else { +            // otherwise just resolve it relative to project basedir +            $resolved = $this->project->resolveFile($this->file); +        } +         +        $this->log("Resolved " . $this->file . " to " . $resolved->getAbsolutePath(), PROJECT_MSG_INFO); +        $this->project->setProperty($this->propertyName, $resolved->getAbsolutePath()); +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php b/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php new file mode 100644 index 00000000..50327e3f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php @@ -0,0 +1,57 @@ +<?php + +/* + *  $Id: SequentialTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +require_once 'phing/TaskContainer.php'; + +/** + * Sequential is a container task that contains other Phing Task objects. + * + * The sequential task has no attributes and does not support any nested + * elements apart from Ant tasks. Any valid Ant task may be embedded within the + * sequential task. + * + * @since 2.1.2 + */ +class SequentialTask extends Task implements TaskContainer { + +    /** Optional Vector holding the nested tasks */ +    private $nestedTasks = array(); + +    /** +     * Add a nested task to Sequential. +     * @param Task $nestedTask  Nested task to execute Sequential +     */ +    public function addTask(Task $nestedTask) { +        $this->nestedTasks[] = $nestedTask; +    } + +    /** +     * Execute all nestedTasks. +     * @throws BuildException if one of the nested tasks fails. +     */ +    public function main() { +		foreach($this->nestedTasks as $task) { +			$task->perform(); +		} +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php b/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php new file mode 100644 index 00000000..4a90e106 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php @@ -0,0 +1,127 @@ +<?php + +/* + * $Id: TaskdefTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; + +/** + * Register a task for use within a buildfile. + *  + * This is for registering your own tasks -- or any non-core Task -- for use within a buildfile. + * If you find that you are using a particular class frequently, you may want to edit the  + * phing/tasks/defaults.properties file so that it is included by default. You may also + * want to submit it (if LGPL or compatible license) to be included in Phing distribution. + *  + * <pre> + *   <taskdef name="mytag" classname="path.to.MyHandlingClass"/> + *   . + *   . + *   <mytag param1="val1" param2="val2"/> + * </pre> + *  + * TODO: + *    -- possibly refactor since this is almost the same as TypeDefTask + *      (right now these are just too simple to really justify creating an abstract class) + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.11 $ + * @package   phing.tasks.system + */ +class TaskdefTask extends Task { + +    /** Tag name for task that will be used in XML */ +    private $name; +     +    /** +     * Classname of task to register. +     * This can be a dot-path -- relative to a location on PHP include_path. +     * E.g. path.to.MyClass ->  path/to/MyClass.php +     * @var string +     */ +    private $classname; +     +    /** +     * Path to add to PHP include_path to aid in finding specified class. +     * @var Path +     */ +    private $classpath; +     +    /** +     * Refid to already defined classpath +     */ +    private $classpathId; +     +    /** +     * Set the classpath to be used when searching for component being defined +     *  +     * @param Path $classpath An Path object containing the classpath. +     */ +    public function setClasspath(Path $classpath) { +        if ($this->classpath === null) { +            $this->classpath = $classpath; +        } else { +            $this->classpath->append($classpath); +        } +    } + +    /** +     * Create the classpath to be used when searching for component being defined +     */  +    public function createClasspath() { +        if ($this->classpath === null) { +            $this->classpath = new Path($this->project); +        } +        return $this->classpath->createPath(); +    } + +    /** +     * Reference to a classpath to use when loading the files. +     */ +    public function setClasspathRef(Reference $r) { +        $this->classpathId = $r->getRefId(); +        $this->createClasspath()->setRefid($r); +    } + +    /** +     * Sets the name that will be used in XML buildfile. +     * @param string $name +     */ +    public function setName($name)    { +        $this->name = $name; +    } +     +    /** +     * Sets the class name / dotpath to use. +     * @param string $class +     */ +    public function setClassname($class) { +        $this->classname = $class; +    } +     +    /** Main entry point */ +    public function main() { +        if ($this->name === null || $this->classname === null) { +            throw new BuildException("You must specify name and class attributes for <taskdef>."); +        } +        $this->log("Task " . $this->name . " will be handled by class " . $this->classname, PROJECT_MSG_VERBOSE); +        $this->project->addTaskDefinition($this->name, $this->classname, $this->classpath); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/TouchTask.php b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php new file mode 100644 index 00000000..6c6c4080 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php @@ -0,0 +1,170 @@ +<?php +/* + *  $Id: TouchTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/util/DirectoryScanner.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/util/FileUtils.php'; +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/system/io/IOException.php'; + +/** + * Touch a file and/or fileset(s); corresponds to the Unix touch command. + * + * If the file to touch doesn't exist, an empty one is created. + * + * @version $Revision: 1.12 $ + * @package phing.tasks.system + */ +class TouchTask extends Task { + +    private $file; +    private $millis    = -1; +    private $dateTime; +    private $filesets = array(); +    private $fileUtils; + +    function __construct() { +        $this->fileUtils = new FileUtils(); +    } + +    /** +     * Sets a single source file to touch.  If the file does not exist +     * an empty file will be created. +     */ +    function setFile(PhingFile $file) {         +        $this->file = $file; +    } + +    /** +     * the new modification time of the file +     * in milliseconds since midnight Jan 1 1970. +     * Optional, default=now +     */ +    function setMillis($millis) { +        $this->millis = (int) $millis; +    } + +    /** +     * the new modification time of the file +     * in the format MM/DD/YYYY HH:MM AM or PM; +     * Optional, default=now +     */ +    function setDatetime($dateTime) { +        $this->dateTime = (string) $dateTime; +    } + +    /** +     * Nested creator, adds a set of files (nested fileset attribute). +     * @return FileSet +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +    /** +     * Execute the touch operation. +     */ +    function main() { +        $savedMillis = $this->millis; + +        if ($this->file === null && count($this->filesets) === 0) { +            throw new BuildException("Specify at least one source - a file or a fileset."); +        } + +        if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) { +            throw new BuildException("Use a fileset to touch directories."); +        } + +        try { // try to touch file +            if ($this->dateTime !== null) { +                $this->setMillis(strtotime($this->dateTime)); +                if ($this->millis < 0) { +                    throw new BuildException("Date of {$this->dateTime} results in negative milliseconds value relative to epoch (January 1, 1970, 00:00:00 GMT)."); +                } +            } +            $this->_touch(); +        } catch (Exception $ex) { +            throw new BuildException("Error touch()ing file", $ex, $this->location); +        } +         +        $this->millis = $savedMillis; +         +    } + +    /** +     * Does the actual work. +     */ +    function _touch() { +        if ($this->file !== null) { +            if (!$this->file->exists()) { +                $this->log("Creating " . $this->file->__toString(), PROJECT_MSG_INFO); +                try { // try to create file +                    $this->file->createNewFile(); +                } catch(IOException  $ioe) { +                    throw new BuildException("Error creating new file " . $this->file->__toString(), $ioe, $this->location); +                } +            } +        } + +        $resetMillis = false; +        if ($this->millis < 0) { +            $resetMillis = true; +            $this->millis = Phing::currentTimeMillis(); +        } + +        if ($this->file !== null) { +            $this->touchFile($this->file); +        } + +        // deal with the filesets +        foreach($this->filesets as $fs) { +         +            $ds = $fs->getDirectoryScanner($this->getProject()); +            $fromDir = $fs->getDir($this->getProject()); + +            $srcFiles = $ds->getIncludedFiles(); +            $srcDirs = $ds->getIncludedDirectories(); + +            for ($j=0,$_j=count($srcFiles); $j < $_j; $j++) { +                $this->touchFile(new PhingFile($fromDir, (string) $srcFiles[$j])); +            } +             +            for ($j=0,$_j=count($srcDirs); $j < $_j ; $j++) { +                $this->touchFile(new PhingFile($fromDir, (string) $srcDirs[$j])); +            } +        } + +        if ($resetMillis) { +            $this->millis = -1; +        } +    } + +    private function touchFile($file) { +        if ( !$file->canWrite() ) { +            throw new BuildException("Can not change modification date of read-only file " . $file->__toString()); +        } +        $file->setLastModified($this->millis); +    } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/TstampTask.php b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php new file mode 100644 index 00000000..9341c3dd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php @@ -0,0 +1,168 @@ +<?php +/* + *  $Id: TstampTask.php 58 2006-04-28 14:41:04Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/Task.php'; + +/** + * Sets properties to the current time, or offsets from the current time. + * The default properties are TSTAMP, DSTAMP and TODAY; + * + * Based on Ant's Tstamp task. + *  + * @author   Michiel Rook <michiel@trendserver.nl> + * @version  $Revision: 1.6 $ + * @package  phing.tasks.system + * @since    2.2.0 + */ +class TstampTask extends Task +{ +	private $customFormats = array(); +	 +	private $prefix = ""; +	 +	/** +	 * Set a prefix for the properties. If the prefix does not end with a "." +	 * one is automatically added. +	 * @param prefix the prefix to use. +	 */ +	public function setPrefix($prefix) +	{ +		$this->prefix = $prefix; +		 +		if (!empty($this->prefix)) +		{ +			$this->prefix.= "."; +		} +	} +	 +    /** +     * Adds a custom format +     * +	 * @param TstampCustomFormat custom format +     */ +	public function addFormat(TstampCustomFormat $cf) +	{ +		$this->customFormats[] = $cf; +	} + +    /** +     * Create the timestamps. Custom ones are done before +     * the standard ones. +     * +     * @throws BuildException +     */ +    public function main() +    { +		foreach ($this->customFormats as $cf) +		{ +			$cf->execute($this); +		} +		 +		$dstamp = strftime('%Y%m%d'); +		$this->prefixProperty('DSTAMP', $dstamp); +		 +		$tstamp = strftime('%H%M'); +		$this->prefixProperty('TSTAMP', $tstamp); +		 +		$today = strftime('%B %d %Y'); +		$this->prefixProperty('TODAY', $today); +	} +	 +    /** +     * helper that encapsulates prefix logic and property setting +     * policy (i.e. we use setNewProperty instead of setProperty). +     */ +    public function prefixProperty($name, $value) +    { +        $this->getProject()->setNewProperty($this->prefix . $name, $value); +    } +} + +class TstampCustomFormat +{ +	private $propertyName = ""; +	private $pattern = ""; +	private $locale = ""; +	 +	/** +	 * The property to receive the date/time string in the given pattern +	 * +	 * @param propertyName the name of the property. +	 */ +	public function setProperty($propertyName) +	{ +		$this->propertyName = $propertyName; +	} + +	/** +	 * The date/time pattern to be used. The values are as +	 * defined by the PHP strftime() function. +	 * +	 * @param pattern +	 */ +	public function setPattern($pattern) +	{ +		$this->pattern = $pattern; +	} +	 +	/** +	 * The locale used to create date/time string. +	 * +	 * @param locale +	 */ +	public function setLocale($locale) +	{ +		$this->locale = $locale; +	} +	 +	/** +	 * validate parameter and execute the format. +	 * +	 * @param TstampTask reference to task +	 */ +	public function execute(TstampTask $tstamp) +	{ +		if (empty($this->propertyName)) +		{ +			throw new BuildException("property attribute must be provided"); +		} + +		if (empty($this->pattern)) +		{ +			throw new BuildException("pattern attribute must be provided"); +		} +		 +		if (!empty($this->locale)) +		{ +			setlocale(LC_ALL, $this->locale); +		} +		 +		$value = strftime($this->pattern); +		$tstamp->prefixProperty($this->propertyName, $value); +		 +		if (!empty($this->locale)) +		{ +			// reset locale +			setlocale(LC_ALL, NULL); +		} +	} +} +?> diff --git a/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php b/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php new file mode 100644 index 00000000..de058c90 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php @@ -0,0 +1,125 @@ +<?php +/* + *  $Id: TypedefTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; + +/** + * Register a datatype for use within a buildfile. + *  + * This is for registering your own datatypes for use within a buildfile. + *  + * If you find that you are using a particular class frequently, you may want to edit the  + * phing/types/defaults.properties file so that it is included by default.  You may also + * want to submit it (if LGPL or compatible license) to be included in Phing distribution. + *  + * <pre> + *   <typedef name="mytype" classname="path.to.MyHandlingClass"/> + *   . + *   <sometask ...> + *     <mytype param1="val1" param2="val2"/> + *   </sometask> + * </pre> + *  + * TODO: + *    -- possibly refactor since this is almost the same as TaskDefTask + *      (right now these are just too simple to really justify creating an abstract class) + *  + * @author    Hans Lellelid <hans@xmpl.org> + * @version   $Revision: 1.7 $ + * @package   phing.tasks.system + */ +class TypedefTask extends Task { +     +    /** Tag name for datatype that will be used in XML */ +    private $name; +     +    /** +     * Classname of task to register. +     * This can be a dot-path -- relative to a location on PHP include_path. +     * E.g. path.to.MyClass ->  path/to/MyClass.php +     * @var string +     */ +    private $classname; +     +    /** +     * Path to add to PHP include_path to aid in finding specified class. +     * @var Path +     */ +    private $classpath; +     +    /** Refid to already defined classpath */ +    private $classpathId; +     +    /** +     * Set the classpath to be used when searching for component being defined +     *  +     * @param Path $classpath An Path object containing the classpath. +     */ +    public function setClasspath(Path $classpath) { +        if ($this->classpath === null) { +            $this->classpath = $classpath; +        } else { +            $this->classpath->append($classpath); +        } +    } + +    /** +     * Create the classpath to be used when searching for component being defined +     */  +    public function createClasspath() { +        if ($this->classpath === null) { +            $this->classpath = new Path($this->project); +        } +        return $this->classpath->createPath(); +    } + +    /** +     * Reference to a classpath to use when loading the files. +     */ +    public function setClasspathRef(Reference $r) { +        $this->classpathId = $r->getRefId(); +        $this->createClasspath()->setRefid($r); +    } +     +    /** Main entry point */ +    public function main() { +        if ($this->name === null || $this->classname === null) { +            throw new BuildException("You must specify name and class attributes for <typedef>."); +        }         +        $this->project->addDataTypeDefinition($this->name, $this->classname, $this->classpath); +    } +     +    /** +     * Sets the name that will be used in XML buildfile. +     * @param string $name +     */ +    public function setName($name)    { +        $this->name = $name; +    } +     +    /** +     * Sets the class name / dotpath to use. +     * @param string $class +     */ +    public function setClassname($class) { +        $this->classname = $class; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php b/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php new file mode 100644 index 00000000..720fae12 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php @@ -0,0 +1,217 @@ +<?php +/* + * $Id: UpToDateTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/condition/Condition.php'; +include_once 'phing/util/DirectoryScanner.php'; +include_once 'phing/util/SourceFileScanner.php'; +include_once 'phing/mappers/MergeMapper.php'; + +/** + * Sets the given property if the specified target has a timestamp + * greater than all of the source files. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    William Ferguson <williamf@mincom.com> (Ant) + * @author    Hiroaki Nakamura <hnakamur@mc.neweb.ne.jp> (Ant) + * @author    Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version   $Revision: 1.6 $ + * @package   phing.tasks.system + */ +class UpToDateTask extends Task implements Condition { + +    private $_property; +    private $_value; +    private $_sourceFile; +    private $_targetFile; +    private $sourceFileSets = array(); + +    protected $mapperElement = null; + +    /** +     * The property to set if the target file is more up-to-date than +     * (each of) the source file(s). +     * +     * @param property the name of the property to set if Target is up-to-date. +     */ +    public function setProperty($property) { +        $this->_property = $property; +    } + +    /** +     * The value to set the named property to if the target file is more +     * up-to-date than (each of) the source file(s). Defaults to 'true'. +     * +     * @param value the value to set the property to if Target is up-to-date +     */ +    public function setValue($value) { +        $this->_value = $value; +    } + +    /** +     * Returns the value, or "true" if a specific value wasn't provided. +     */ +    private function getValue() { +        return ($this->_value !== null) ? $this->_value : "true"; +    }  + +    /** +     * The file which must be more up-to-date than (each of) the source file(s) +     * if the property is to be set. +     * +     * @param file the file we are checking against. +     */ +    public function setTargetFile($file) { +        if (is_string($file)) { +            $file = new PhingFile($file); +        } +        $this->_targetFile = $file; +    } + +    /** +     * The file that must be older than the target file +     * if the property is to be set. +     * +     * @param file the file we are checking against the target file. +     */ +    public function setSrcfile($file) { +        if (is_string($file)) { +            $file = new PhingFile($file); +        } +        $this->_sourceFile = $file; +    } + +    /** +     * Nested <srcfiles> element. +     */ +    public function createSrcfiles() { +        $fs = new FileSet(); +        $this->sourceFileSets[] = $fs; +        return $fs; +    } + +    /** +     * Defines the FileNameMapper to use (nested mapper element). +     */ +    public function createMapper() { +        if ($this->mapperElement !== null) { +            throw new BuildException("Cannot define more than one mapper", +                                     $this->location); +        } +        $this->mapperElement = new Mapper($this->getProject()); +        return $this->mapperElement; +    } + +    /** +     * Evaluate (all) target and source file(s) to +     * see if the target(s) is/are up-to-date. +     * @return boolean +     */ +    public function evaluate() { +        if (count($this->sourceFileSets) === 0 && $this->_sourceFile === null) { +            throw new BuildException("At least one srcfile or a nested " +                                     . "<srcfiles> element must be set."); +        } + +        if (count($this->sourceFileSets) > 0 && $this->_sourceFile !== null) { +            throw new BuildException("Cannot specify both the srcfile " +                                     . "attribute and a nested <srcfiles> " +                                     . "element."); +        } + +        if ($this->_targetFile === null && $this->mapperElement === null) { +            throw new BuildException("The targetfile attribute or a nested " +                                     . "mapper element must be set."); +        } + +        // if the target file is not there, then it can't be up-to-date +        if ($this->_targetFile !== null && !$this->_targetFile->exists()) { +            return false; +        }  + +        // if the source file isn't there, throw an exception +        if ($this->_sourceFile !== null && !$this->_sourceFile->exists()) { +            throw new BuildException($this->_sourceFile->getAbsolutePath()  +                                     . " not found."); +        } + +        $upToDate = true; +        for($i=0,$size=count($this->sourceFileSets); $i < $size && $upToDate; $i++) { +            $fs = $this->sourceFileSets[$i]; +            $ds = $fs->getDirectoryScanner($this->project); +            $upToDate = $upToDate && $this->scanDir($fs->getDir($this->project), +                                           $ds->getIncludedFiles()); +        } + +        if ($this->_sourceFile !== null) { +            if ($this->mapperElement === null) { +                $upToDate = $upToDate && +                    ($this->_targetFile->lastModified() >= $this->_sourceFile->lastModified()); +            } else { +                $sfs = new SourceFileScanner($this); +                $upToDate = $upToDate && +                    count($sfs->restrict($this->_sourceFile->getAbsolutePath(), +                                  null, null,  +                                  $this->mapperElement->getImplementation())) === 0;                    +            } +        } +        return $upToDate; +    } + + +    /** +     * Sets property to true if target file(s) have a more recent timestamp +     * than (each of) the corresponding source file(s). +     * @throws BuildException  +     */ +    public function main() { +        if ($this->_property === null) { +            throw new BuildException("property attribute is required.",  +                                     $this->location); +        } +        $upToDate = $this->evaluate(); +        if ($upToDate) { +            $this->project->setNewProperty($this->_property, $this->getValue()); +            if ($this->mapperElement === null) { +                $this->log("File \"" . $this->_targetFile->getAbsolutePath()  +                    . "\" is up-to-date.", PROJECT_MSG_VERBOSE); +            } else { +                $this->log("All target files are up-to-date.", +                    PROJECT_MSG_VERBOSE); +            } +        } +    } + +    protected function scanDir(PhingFile $srcDir, $files) { +        $sfs = new SourceFileScanner($this); +        $mapper = null; +        $dir = $srcDir; +        if ($this->mapperElement === null) { +            $mm = new MergeMapper(); +            $mm->setTo($this->_targetFile->getAbsolutePath()); +            $mapper = $mm; +            $dir = null; +        } else { +            $mapper = $this->mapperElement->getImplementation(); +        } +        return (count($sfs->restrict($files, $srcDir, $dir, $mapper)) === 0); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/WarnTask.php b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php new file mode 100644 index 00000000..50318e71 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php @@ -0,0 +1,35 @@ +<?php +/* + *  $Id: WarnTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/tasks/system/EchoTask.php'; + +/** + * Simple task to echo a warning message (PROJECT_MSG_WARN) to all output devices. + * + * @author   Hans Lellelid <hans@xmpl.org> + * @version  $Revision: 1.1 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + * @package  phing.tasks.system + */ +class WarnTask extends EchoTask { +    function main() { +        $this->log($this->msg, PROJECT_MSG_WARN); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/XsltTask.php b/buildscripts/phing/classes/phing/tasks/system/XsltTask.php new file mode 100644 index 00000000..0374aa59 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/XsltTask.php @@ -0,0 +1,81 @@ +<?php +/* + *  $Id: XsltTask.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/CopyTask.php'; +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/system/io/FileWriter.php'; +include_once 'phing/filters/XsltFilter.php'; + +/** + * Implements an XSLT processing filter while copying files. + * + * This is a shortcut for calling the <copy> task with the XSLTFilter used + * in the <filterchains> section. + *  + * @author    Andreas Aderhold, andi@binarycloud.com + * @version   $Revision: 1.8 $ + * @package   phing.tasks.system + */ +class XsltTask extends CopyTask { +     +    /** XSLTFilter object that we use to handle transformation. */ +    private $xsltFilter; +     +    /** Parameters to pass to XSLT procesor. */ +    private $parameters = array(); +     +    /** +     * Setup the filterchains w/ XSLTFilter that we will use while copying the files. +     */ +    function init() { +        $xf = new XsltFilter(); +        $chain = $this->createFilterChain($this->getProject()); +        $chain->addXsltFilter($xf); +        $this->xsltFilter = $xf;         +    } +     +    /** +     * Set any XSLT Param and invoke CopyTask::main() +     * @see CopyTask::main() +     */ +    function main() {         +        $this->log("Doing XSLT transformation using stylesheet " . $this->xsltFilter->getStyle(), PROJECT_MSG_VERBOSE); +        $this->xsltFilter->setParams($this->parameters); +        parent::main(); +    } +     +    /** +     * Set the stylesheet to use. +     * @param PhingFile $style +     */ +    function setStyle(PhingFile $style) { +        $this->xsltFilter->setStyle($style); +    } +     +    /** +     * Support nested <param> tags useing XSLTParam class. +     * @return XSLTParam +     */ +    function createParam() { +        $num = array_push($this->parameters, new XSLTParam()); +        return $this->parameters[$num-1]; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php new file mode 100644 index 00000000..c16ce499 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php @@ -0,0 +1,46 @@ +<?php +/* + * $Id: AndCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  <and> condition container. + * + *  Iterates over all conditions and returns false as soon as one + *  evaluates to false. + *  + *  @author    Hans Lellelid <hans@xmpl.org> + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.7 $ + *  @package   phing.tasks.system.condition + */ +class AndCondition extends ConditionBase implements Condition { + +    public function evaluate() { +        foreach($this as $c) { // ConditionBase implements IteratorAggregator +              if (!$c->evaluate()) { +                return false; +            } +        } +        return true;        +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php b/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php new file mode 100644 index 00000000..73e0c232 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php @@ -0,0 +1,39 @@ +<?php + +/* + *  $Id: Condition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Condition interface specification: + * + * Each condition must implement a method applying to this prototye: + * + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +interface Condition { +    /** +     * @return boolean +     * @throws BuildException +     */ +    public function evaluate(); +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php b/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php new file mode 100644 index 00000000..1c09fe49 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php @@ -0,0 +1,195 @@ +<?php +/* + *  $Id: ConditionBase.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/Project.php'; +include_once 'phing/tasks/system/AvailableTask.php'; +include_once 'phing/tasks/system/condition/Condition.php'; + +/** + *  Abstract baseclass for the <condition> task as well as several + *  conditions - ensures that the types of conditions inside the task + *  and the "container" conditions are in sync. + *  + *    @author    Hans Lellelid <hans@xmpl.org> + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.16 $ + *  @package   phing.tasks.system.condition + */ +abstract class ConditionBase extends ProjectComponent implements IteratorAggregate { +         +    public $conditions = array(); // needs to be public for "inner" class access + +    function countConditions() { +        return count($this->conditions); +    } +     +    /** +     * Required for IteratorAggregate +     */ +    function getIterator() { +        return new ConditionEnumeration($this); +    } +     +    function getConditions() { +        return $this->conditions; +    } + +    /** +     * @return void +     */ +    function addAvailable(AvailableTask $a) { +        $this->conditions[] = $a; +    } + +    /** +     * @return NotCondition +     */ +    function createNot() { +        include_once 'phing/tasks/system/condition/NotCondition.php'; +        $num = array_push($this->conditions, new NotCondition()); +        return $this->conditions[$num-1];         +    } + +    /** +     * @return AndCondition +     */ +    function createAnd() { +        include_once 'phing/tasks/system/condition/AndCondition.php'; +        $num = array_push($this->conditions, new AndCondition()); +        return $this->conditions[$num-1]; +    } +     +    /** +     * @return OrCondition +     */ +    function createOr() { +        include_once 'phing/tasks/system/condition/OrCondition.php'; +        $num = array_push($this->conditions, new OrCondition()); +        return $this->conditions[$num-1];         +    } + +    /** +     * @return EqualsCondition +     */ +    function createEquals() { +        include_once 'phing/tasks/system/condition/EqualsCondition.php';   +        $num = array_push($this->conditions, new EqualsCondition()); +        return $this->conditions[$num-1]; +    } + +    /** +     * @return OsCondition +     */ +    function createOs() { +        include_once 'phing/tasks/system/condition/OsCondition.php'; +        $num = array_push($this->conditions, new OsCondition()); +        return $this->conditions[$num-1]; +    } +    +    /** +     * @return IsFalseCondition +     */ +    function createIsFalse() { +        include_once 'phing/tasks/system/condition/IsFalseCondition.php'; +        $num = array_push($this->conditions, new IsFalseCondition()); +        return $this->conditions[$num-1]; +    } +    +    /** +     * @return IsTrueCondition +     */ +    function createIsTrue() { +        include_once 'phing/tasks/system/condition/IsTrueCondition.php'; +        $num = array_push($this->conditions, new IsTrueCondition()); +        return $this->conditions[$num-1]; +    } +    +    /** +     * @return ContainsCondition +     */ +    function createContains() { +        include_once 'phing/tasks/system/condition/ContainsCondition.php'; +        $num = array_push($this->conditions, new ContainsCondition()); +        return $this->conditions[$num-1]; +    } +    +    /** +     * @return IsSetCondition +     */ +    function createIsSet() { +        include_once 'phing/tasks/system/condition/IsSetCondition.php'; +        $num = array_push($this->conditions, new IsSetCondition()); +        return $this->conditions[$num-1]; +    } + +    /** +     * @return ReferenceExistsCondition +     */ +    function createReferenceExists() { +        include_once 'phing/tasks/system/condition/ReferenceExistsCondition.php'; +        $num = array_push($this->conditions, new ReferenceExistsCondition()); +        return $this->conditions[$num-1]; +    } + +} + +/** + * "Inner" class for handling enumerations. + * Uses build-in PHP5 iterator support. + */ +class ConditionEnumeration implements Iterator { +     +    /** Current element number */ +    private $num = 0; +     +    /** "Outer" ConditionBase class. */ +    private $outer; + +    function __construct(ConditionBase $outer) { +        $this->outer = $outer; +    } +     +    public function valid() { +        return $this->outer->countConditions() > $this->num; +    } + +    function current() { +        $o = $this->outer->conditions[$this->num]; +        if ($o instanceof ProjectComponent) { +            $o->setProject($this->outer->getProject()); +        } +        return $o; +    } +     +    function next() { +        $this->num++; +    } +     +    function key() { +        return $this->num; +    } +     +    function rewind() { +        $this->num = 0; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php new file mode 100644 index 00000000..95849cd8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php @@ -0,0 +1,76 @@ +<?php + +/* + *  $Id: ContainsCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Is one string part of another string? + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version $Revision: 1.3 $ + * @package phing.tasks.system.condition + */ +class ContainsCondition implements Condition { + +    private $string; +    private $subString; +    private $caseSensitive = true; + +    /** +     * The string to search in. +     * @param string $a1 +     */ +    public function setString($a1) { +        $this->string = $a1; +    } + +    /** +     * The string to search for. +     * @param string $a2 +     */ +    public function setSubstring($a2) { +        $this->subString = $a2; +    } + +    /** +     * Whether to search ignoring case or not. +     */ +    public function setCaseSensitive($b) { +        $this->caseSensitive = (boolean) $b; +    } + +    /**  +     * Check whether string contains substring. +     * @throws BuildException +     */ +    public function evaluate()  { +        if ($this->string === null || $this->subString === null) { +            throw new BuildException("both string and substring are required " +                                     . "in contains"); +        } + +        return $this->caseSensitive  +            ? strpos($this->string, $this->subString) !== false +            : substr(strtolower($this->string), strtolower($this->subString)) !== false; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php new file mode 100644 index 00000000..32d51380 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php @@ -0,0 +1,78 @@ +<?php +/* + *  $Id: EqualsCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + *  A simple string comparator.  Compares two strings for eqiality in a + *  binary safe manner. Implements the condition interface specification. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.7 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @access    public + *  @package   phing.tasks.system.condition + */ +class EqualsCondition implements Condition { + +    private $arg1; +    private $arg2; +    private $trim = false; +    private $caseSensitive = true; +     +    public function setArg1($a1) { +        $this->arg1 = $a1; +    } + +    public function setArg2($a2) { +        $this->arg2 = $a2; +    } + +    /** +     * Should we want to trim the arguments before comparing them? +     * @param boolean $b +     */ +    public function setTrim($b) { +        $this->trim = (boolean) $b; +    } + +    /** +     * Should the comparison be case sensitive? +     * @param boolean $b +     */ +    public function setCaseSensitive($b) { +        $this->caseSensitive = (boolean) $b; +    }  +     +    public function evaluate() { +        if ($this->arg1 === null || $this->arg2 === null) { +            throw new BuildException("Both arg1 and arg2 are required in equals."); +        } +         +        if ($this->trim) { +            $this->arg1 = trim($this->arg1); +            $this->arg2 = trim($this->arg2); +        } +         +        //print("[comparison] Comparing '".$this->arg1."' and '".$this->arg2."'\n"); +        return $this->caseSensitive ? $this->arg1 === $this->arg2 : strtolower($this->arg1) === strtolower($this->arg2); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php new file mode 100644 index 00000000..ebbd1a3d --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php @@ -0,0 +1,60 @@ +<?php +/* + *  $Id: IsFalseCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given string evals to false. + *  + * @author Hans Lellelid (Phing) + * @author Steve Loughran (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +class IsFalseCondition extends ProjectComponent implements Condition { +     +    /**   +     * what we eval +     */  +    private $value; + +    /** +     * Set the value to be tested. +     * @param boolean $value +     */  +    public function setValue($value) { +        $this->value = $value; +    } + +    /** +     * return the inverted value; +     * @throws BuildException if someone forgot to spec a value +     */  +    public function evaluate() { +        if ($this->value === null) { +            throw new BuildException("Nothing to test for falsehood"); +        } +        return !$this->value; +    } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php new file mode 100644 index 00000000..4f81c50f --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php @@ -0,0 +1,53 @@ +<?php +/* + *  $Id: IsSetCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given property has been set. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @version $Revision: 1.4 $ + * @package phing.tasks.system.condition + */ +class IsSetCondition extends ProjectComponent implements Condition { +     +    private $property; + +    public function setProperty($p) { +        $this->property = $p; +    } + +    /** +     * Check whether property is set. +     * @throws BuildException +     */ +    public function evaluate()  { +        if ($this->property === null) { +            throw new BuildException("No property specified for isset " +                                     . "condition"); +        }         +        return $this->project->getProperty($this->property) !== null; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php new file mode 100644 index 00000000..4affefc5 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php @@ -0,0 +1,59 @@ +<?php +/* + *  $Id: IsTrueCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/ProjectComponent.php'; +require_once 'phing/tasks/system/condition/Condition.php'; + +/** + * Condition that tests whether a given string evals to true. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Steve Loughran (Ant) + * @package phing.tasks.system.condition + */ +class IsTrueCondition extends ProjectComponent implements Condition { + +    /**   +     * what we eval +     */  +    private $value; + +    /** +     * Set the value to be tested. +     * @param boolean $value +     */  +    public function setValue($value) { +        $this->value = $value; +    } + +    /** +     * return the inverted value; +     * @throws BuildException if someone forgot to spec a value +     */  +    public function evaluate() { +        if ($this->value === null) { +            throw new BuildException("Nothing to test for falsehood"); +        } +        return $this->value; +    } + +} + diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php new file mode 100644 index 00000000..c76ef2b8 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php @@ -0,0 +1,48 @@ +<?php +/* + *  $Id: NotCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  <not> condition. + * + *  Evaluates to true if the single condition nested into it is false + *  and vice versa. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.6 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @access    public + *  @package   phing.tasks.system.condition + */ +class NotCondition extends ConditionBase implements Condition { + +    function evaluate() { +        if ($this->countConditions() > 1) { +            throw new BuildException("You must not nest more than one condition into <not>"); +        } +        if ($this->countConditions() < 1) { +            throw new BuildException("You must nest a condition into <not>"); +        } +        $conds = $this->getIterator(); +        return !$conds->current()->evaluate(); +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php new file mode 100644 index 00000000..778abfd0 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php @@ -0,0 +1,46 @@ +<?php +/* + *  $Id: OrCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  <or> condition container. + * + *  Iterates over all conditions and returns true as soon as one + *  evaluates to true. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright  2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.8 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @access    public + *  @package   phing.tasks.system.condition + */ +class OrCondition extends ConditionBase implements Condition { + +    function evaluate() { +        foreach($this as $c) { // ConditionBase implements IteratorAggregator +              if ($c->evaluate()) { +                return true; +            } +        } +        return false; +    } +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php new file mode 100644 index 00000000..d80729e7 --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php @@ -0,0 +1,63 @@ +<?php +/* + *  $Id: OsCondition.php 59 2006-04-28 14:49:47Z mrook $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/condition/ConditionBase.php'; + +/** + *  Condition that tests the OS type. + * + *  @author    Andreas Aderhold <andi@binarycloud.com> + *  @copyright © 2001,2002 THYRELL. All rights reserved + *  @version   $Revision: 1.8 $ $Date: 2006-04-28 10:49:47 -0400 (Fri, 28 Apr 2006) $ + *  @access    public + *  @package   phing.tasks.system.condition + */ +class OsCondition implements Condition { + +    private $family; + +    function setFamily($f) { +        $this->family = strtolower($f); +    } + +    function evaluate() { +        $osName = strtolower(Phing::getProperty("os.name")); +		 +        if ($this->family !== null) { +            if ($this->family === "windows") { +                return StringHelper::startsWith("win", $osName); +            } elseif ($this->family === "mac") { +                return (strpos($osName, "mac") !== false || strpos($osName, "darwin") !== false); +            } elseif ($this->family === ("unix")) { +				return ( +					StringHelper::endsWith("ix", $osName) || +					StringHelper::endsWith("ux", $osName) || +					StringHelper::endsWith("bsd", $osName) || +					StringHelper::startsWith("sunos", $osName) || +					StringHelper::startsWith("darwin", $osName) +				); +            } +            throw new BuildException("Don't know how to detect os family '" . $this->family . "'"); +        } +        return false; +    } + +} diff --git a/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php b/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php new file mode 100644 index 00000000..04c1cbbd --- /dev/null +++ b/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php @@ -0,0 +1,52 @@ +<?php
 +/*
 + *  $Id: ReferenceExistsCondition.php 59 2006-04-28 14:49:47Z mrook $
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + *
 + * This software consists of voluntary contributions made by many individuals
 + * and is licensed under the LGPL. For more information please see
 + * <http://phing.info>.
 + */
 +
 +require_once 'phing/ProjectComponent.php'; require_once 'phing/tasks/system/condition/Condition.php';
 +
 +/**
 + * Condition that tests whether a given reference exists.
 + *
 + * @author Matthias Pigulla <mp@webfactory.de> (Phing)
 + * @version $Revision: 1.1 $
 + * @package phing.tasks.system.condition  */
 +class ReferenceExistsCondition extends ProjectComponent implements Condition {
 +    
 +    private $refid;
 +
 +    public function setRef($id) {
 +      $this->refid = (string) $id;
 +    }
 +
 +    /**
 +     * Check whether the reference exists.
 +     * @throws BuildException
 +     */
 +    public function evaluate()  {
 +        if ($this->refid === null) {
 +            throw new BuildException("No ref attribute specified for reference-exists "
 +                                     . "condition");
 +        }        
 +        $refs = $this->project->getReferences();
 +        return isset($refs[$this->refid]);
 +    }
 +
 +}
 +
 diff --git a/buildscripts/phing/classes/phing/types/AbstractFileSet.php b/buildscripts/phing/classes/phing/types/AbstractFileSet.php new file mode 100644 index 00000000..6d640705 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/AbstractFileSet.php @@ -0,0 +1,570 @@ +<?php +/* + *  $Id: AbstractFileSet.php,v 1.15 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/system/io/PhingFile.php'; +include_once 'phing/types/DataType.php'; +include_once 'phing/types/PatternSet.php'; +include_once 'phing/types/selectors/BaseSelector.php'; +include_once 'phing/types/selectors/SelectorContainer.php'; +include_once 'phing/types/selectors/BaseSelectorContainer.php'; + +// Load all of the selectors (not really necessary but +// helps reveal parse errors right away) + +include_once 'phing/types/selectors/AndSelector.php'; +include_once 'phing/types/selectors/ContainsSelector.php'; +include_once 'phing/types/selectors/ContainsRegexpSelector.php'; +include_once 'phing/types/selectors/DateSelector.php'; +include_once 'phing/types/selectors/DependSelector.php'; +include_once 'phing/types/selectors/DepthSelector.php'; +include_once 'phing/types/selectors/ExtendSelector.php'; +include_once 'phing/types/selectors/FilenameSelector.php'; +include_once 'phing/types/selectors/MajoritySelector.php'; +include_once 'phing/types/selectors/NoneSelector.php'; +include_once 'phing/types/selectors/NotSelector.php'; +include_once 'phing/types/selectors/OrSelector.php'; +include_once 'phing/types/selectors/PresentSelector.php'; +include_once 'phing/types/selectors/SizeSelector.php'; +include_once 'phing/types/selectors/TypeSelector.php'; + +include_once 'phing/util/DirectoryScanner.php'; + +/** + * The FileSet class provides methods and properties for accessing + * and managing filesets. It extends ProjectComponent and thus inherits + * all methods and properties (not explicitly declared). See ProjectComponent + * for further detail. + * + * TODO: + *   - merge this with patternsets: FileSet extends PatternSet !!! + *     requires additional mods to the parsing algo + *         [HL] .... not sure if that really makes so much sense.  I think + *            that perhaps they should use common utility class if there really + *            is that much shared functionality + * + * @author    Andreas Aderhold <andi@binarycloud.com> + * @author    Hans Lellelid <hans@xmpl.org> + * @version    $Revision: 1.15 $ $Date: 2005/05/26 13:10:53 $ + * @see        ProjectComponent + * @package    phing.types + */ +class AbstractFileSet extends DataType implements SelectorContainer { +     +    // These vars are public for cloning purposes +     +    /** +     * @var boolean +     */ +    public $useDefaultExcludes = true; +     +    /** +     * @var PatternSet +     */ +    public $defaultPatterns; +     +    public $additionalPatterns = array(); +    public $dir; +    public $isCaseSensitive = true;     +    public $selectors = array(); +     +    function __construct($fileset = null) { +        if ($fileset !== null && ($fileset instanceof FileSet)) { +            $this->dir = $fileset->dir; +            $this->defaultPatterns = $fileset->defaultPatterns; +            $this->additionalPatterns = $fileset->additionalPatterns; +            $this->useDefaultExcludes = $fileset->useDefaultExcludes; +            $this->isCaseSensitive = $fileset->isCaseSensitive; +            $this->selectors = $fileset->selectors; +        } +        $this->defaultPatterns = new PatternSet(); +    } + + +    /** +    * Makes this instance in effect a reference to another PatternSet +    * instance. +    * You must not set another attribute or nest elements inside +    * this element if you make it a reference. +    */ +    function setRefid(Reference $r) { +        if ((isset($this->dir) && !is_null($this->dir)) || $this->defaultPatterns->hasPatterns()) { +            throw $this->tooManyAttributes(); +        } +        if (!empty($this->additionalPatterns)) { +            throw $this->noChildrenAllowed(); +        } +        if (!empty($this->selectors)) { +            throw $this->noChildrenAllowed(); +        } +        parent::setRefid($r); +    } + + +    function setDir($dir) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($dir instanceof PhingFile) { +            $dir = $dir->getPath(); +        } +        $this->dir = new PhingFile((string) $dir); +    } + + +    function getDir(Project $p) { +        if ($this->isReference()) { +            return $this->getRef($p)->getDir($p); +        } +        return $this->dir; +    } + + +    function createPatternSet() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $num = array_push($this->additionalPatterns, new PatternSet()); +        return $this->additionalPatterns[$num-1]; +    } + +    /** +    * add a name entry on the include list +    */ +    function createInclude() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->defaultPatterns->createInclude(); +    } + +    /** +     * add a name entry on the include files list +     */ +    function createIncludesFile() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->defaultPatterns->createIncludesFile(); +    } + +    /** +     * add a name entry on the exclude list +     */ +    function createExclude() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->defaultPatterns->createExclude(); +    } + +    /** +     * add a name entry on the include files list +     */ +    function createExcludesFile() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +            return; +        } +        return $this->defaultPatterns->createExcludesFile(); +    } + +    /** +     * Sets the set of include patterns. Patterns may be separated by a comma +     * or a space. +     */ +    function setIncludes($includes) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->defaultPatterns->setIncludes($includes); +    } + +    /** +     * Sets the set of exclude patterns. Patterns may be separated by a comma +     * or a space. +     */ +    function setExcludes($excludes) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->defaultPatterns->setExcludes($excludes); +    } + +    /** +     * Sets the name of the file containing the includes patterns. +     * +     * @param $incl The file to fetch the include patterns from. +     * @throws BE +     */ +    function setIncludesfile($incl) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->defaultPatterns->setIncludesfile($incl); +    } + +    /** +     * Sets the name of the file containing the includes patterns. +     * +     * @param $excl The file to fetch the exclude patterns from. +     * @throws BE +     */ +    function setExcludesfile($excl) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->defaultPatterns->setExcludesfile($excl); +    } + +    /** +     * Sets whether default exclusions should be used or not. +     * +     * @param $useDefaultExcludes "true"|"on"|"yes" when default exclusions +     *                           should be used, "false"|"off"|"no" when they +     *                           shouldn't be used. +     */ +    function setDefaultexcludes($useDefaultExcludes) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->useDefaultExcludes = $useDefaultExcludes; +    } + +    /** +     * Sets case sensitivity of the file system +     */ +    function setCaseSensitive($isCaseSensitive) { +        $this->isCaseSensitive = $isCaseSensitive; +    } + +    /** returns a reference to the dirscanner object belonging to this fileset */ +    function getDirectoryScanner(Project $p) { +        if ($this->isReference()) { +            $o = $this->getRef($p); +            return $o->getDirectoryScanner($p); +        } + +        if ($this->dir === null) { +            throw new BuildException("No directory specified for fileset."); +        } +        if (!$this->dir->exists()) { +            throw new BuildException("Directory ".$this->dir->getAbsolutePath()." not found."); +        } +        if (!$this->dir->isDirectory()) { +            throw new BuildException($this->dir->getAbsolutePath()." is not a directory."); +        } +        $ds = new DirectoryScanner(); +        $this->setupDirectoryScanner($ds, $p); +        $ds->scan(); +        return $ds; +    } + +    /** feed dirscanner with infos defined by this fileset */ +    protected function setupDirectoryScanner(DirectoryScanner $ds, Project $p) { +        if ($ds === null) { +            throw new Exception("DirectoryScanner cannot be null"); +        } +        // FIXME - pass dir directly wehn dirscanner supports File +        $ds->setBasedir($this->dir->getPath()); +         +        foreach($this->additionalPatterns as $addPattern) { +            $this->defaultPatterns->append($addPattern, $p); +        }               + +        $ds->setIncludes($this->defaultPatterns->getIncludePatterns($p)); +        $ds->setExcludes($this->defaultPatterns->getExcludePatterns($p)); + +        $p->log("FileSet: Setup file scanner in dir " . $this->dir->__toString() . " with " . $this->defaultPatterns->toString(), PROJECT_MSG_DEBUG); +         +        if ($ds instanceof SelectorScanner) { +            $ds->setSelectors($this->getSelectors($p)); +        } +         +        if ($this->useDefaultExcludes) { +            $ds->addDefaultExcludes(); +        } +        $ds->setCaseSensitive($this->isCaseSensitive); +    } + + +    /** +     * Performs the check for circular references and returns the +     * referenced FileSet. +     */ +    function getRef(Project $p) { +        if (!$this->checked) { +            $stk = array(); +            array_push($stk, $this); +            $this->dieOnCircularReference($stk, $p);             +        } + +        $o = $this->ref->getReferencedObject($p); +        if (!($o instanceof FileSet)) { +            $msg = $this->ref->getRefId()." doesn't denote a fileset"; +            throw new BuildException($msg); +        } else { +            return $o; +        } +    } +     +    // SelectorContainer methods + +    /** +     * Indicates whether there are any selectors here. +     * +     * @return boolean Whether any selectors are in this container +     */ +    public function hasSelectors() { +        if ($this->isReference() && $this->getProject() !== null) { +            return $this->getRef($this->getProject())->hasSelectors(); +        } +        return !empty($this->selectors); +    } + +    /** +     * Indicates whether there are any patterns here. +     * +     * @return boolean Whether any patterns are in this container. +     */ +    public function hasPatterns() { +     +        if ($this->isReference() && $this->getProject() !== null) { +            return $this->getRef($this->getProject())->hasPatterns();             +        } + +        if ($this->defaultPatterns->hasPatterns($this->getProject())) { +            return true; +        } + +        for($i=0,$size=count($this->additionalPatterns); $i < $size; $i++) { +            $ps = $this->additionalPatterns[$i]; +            if ($ps->hasPatterns($this->getProject())) { +                return true; +            } +        } + +        return false; +    } +     +    /** +     * Gives the count of the number of selectors in this container +     * +     * @return int The number of selectors in this container +     */ +    public function selectorCount() { +        if ($this->isReference() && $this->getProject() !== null) { +            try { +                return $this->getRef($this->getProject())->selectorCount(); +            } catch (Exception $e) { +                throw $e; +            } +        } +        return count($this->selectors); +    } + +    /** +     * Returns the set of selectors as an array. +     * +     * @return an array of selectors in this container +     */ +    public function getSelectors(Project $p) { +        if ($this->isReference()) { +            return $this->getRef($p)->getSelectors($p);             +        } else { +            // *copy* selectors +            $result = array(); +            for($i=0,$size=count($this->selectors); $i < $size; $i++) { +                $result[] = clone $this->selectors[$i]; +            } +            return $result; +        } +    } + +    /** +     * Returns an array for accessing the set of selectors. +     * +     * @return array The array of selectors +     */ +    public function selectorElements() { +        if ($this->isReference() && $this->getProject() !== null) { +            return $this->getRef($this->getProject())->selectorElements();             +        } +        return $this->selectors; +    } + +    /** +     * Add a new selector into this container. +     * +     * @param selector the new selector to add +     */ +    public function appendSelector(FileSelector $selector) { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $this->selectors[] = $selector; +    }     + +    /* Methods below all add specific selectors */ + +    /** +     * add a "Select" selector entry on the selector list +     */ +    public function createSelector() { +        $o = new SelectSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an "And" selector entry on the selector list +     */ +    public function createAnd() { +        $o = new AndSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an "Or" selector entry on the selector list +     */ +    public function createOr() { +        $o = new OrSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a "Not" selector entry on the selector list +     */ +    public function createNot() { +        $o = new NotSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a "None" selector entry on the selector list +     */ +    public function createNone() { +        $o = new NoneSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a majority selector entry on the selector list +     */ +    public function createMajority() { +        $o = new MajoritySelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector date entry on the selector list +     */ +    public function createDate() { +        $o = new DateSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector size entry on the selector list +     */ +    public function createSize() { +        $o = new SizeSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector filename entry on the selector list +     */ +    public function createFilename() { +        $o = new FilenameSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an extended selector entry on the selector list +     */ +    public function createCustom() { +        $o = new ExtendSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a contains selector entry on the selector list +     */ +    public function createContains() { +        $o = new ContainsSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a contains selector entry on the selector list +     */ +    public function createContainsRegexp() { +        $o = new ContainsRegexpSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a present selector entry on the selector list +     */ +    public function createPresent() { +        $o = new PresentSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a depth selector entry on the selector list +     */ +    public function createDepth() { +        $o = new DepthSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a depends selector entry on the selector list +     */ +    public function createDepend() {         +        $o = new DependSelector(); +        $this->appendSelector($o); +        return $o; +    } +     +    /** +     * add a type selector entry on the selector list +     */ +    public function createType() { +        $o = new TypeSelector(); +        $this->appendSelector($o); +        return $o; +    } +} diff --git a/buildscripts/phing/classes/phing/types/Commandline.php b/buildscripts/phing/classes/phing/types/Commandline.php new file mode 100644 index 00000000..877179d0 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Commandline.php @@ -0,0 +1,467 @@ +<?php +/* + *  $Id: Commandline.php,v 1.11 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  + +/** + * Commandline objects help handling command lines specifying processes to + * execute. + * + * The class can be used to define a command line as nested elements or as a + * helper to define a command line by an application. + * <p> + * <code> + * <someelement><br> + *   <acommandline executable="/executable/to/run"><br> + *     <argument value="argument 1" /><br> + *     <argument line="argument_1 argument_2 argument_3" /><br> + *     <argument value="argument 4" /><br> + *   </acommandline><br> + * </someelement><br> + * </code> + * The element <code>someelement</code> must provide a method + * <code>createAcommandline</code> which returns an instance of this class. + * + * @author thomas.haas@softwired-inc.com + * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> + */ +class Commandline { + +    /** +     * @var array CommandlineArguments[] +     */ +    public $arguments = array(); // public so "inner" class can access +     +    /** +     * Full path (if not on %PATH% env var) to executable program. +     * @var string +     */ +    public $executable; // public so "inner" class can access + +    const DISCLAIMER = "The ' characters around the executable and arguments are not part of the command."; + +    public function __construct($to_process = null) { +        if ($to_process !== null) {                  +            $tmp = $this->translateCommandline($to_process); +            if ($tmp) { +                $this->setExecutable(array_shift($tmp)); // removes first el +                foreach($tmp as $arg) { // iterate through remaining elements +                    $this->createArgument()->setValue($arg); +                } +            } +        }     +    } + + +    /** +     * Creates an argument object and adds it to our list of args. +     * +     * <p>Each commandline object has at most one instance of the +     * argument class.</p> +     * +     * @param boolean $insertAtStart if true, the argument is inserted at the +     * beginning of the list of args, otherwise it is appended. +     * @return CommandlineArgument +     */ +    public function createArgument($insertAtStart = false) { +        $argument = new CommandlineArgument($this); +        if ($insertAtStart) { +            array_unshift($this->arguments, $argument); +        } else { +            array_push($this->arguments, $argument); +        } +        return $argument; +    } + +    /** +     * Sets the executable to run. +     */ +    public function setExecutable($executable) { +        if (!$executable) { +            return; +        } +        $this->executable = $executable; +        $this->executable = strtr($this->executable, '/', DIRECTORY_SEPARATOR); +        $this->executable = strtr($this->executable, '\\', DIRECTORY_SEPARATOR); +    } + +    public function getExecutable() { +        return $this->executable; +    } + +    public function addArguments($line) { +        foreach($line as $arg) { +            $this->createArgument()->setValue($arg); +        } +    } + +    /** +     * Returns the executable and all defined arguments. +     * @return array +     */ +    public function getCommandline() { +        $args = $this->getArguments(); +        if ($this->executable === null) { +            return $args; +        } +        return array_merge(array($this->executable), $args); +    } + + +    /** +     * Returns all arguments defined by <code>addLine</code>, +     * <code>addValue</code> or the argument object. +     */ +    public function getArguments() { +        $result = array(); +        foreach($this->arguments as $arg) { +            $parts = $arg->getParts(); +            if ($parts !== null) {                            +                foreach($parts as $part) { +                    $result[] = $part; +                } +            } +        } +        return $result; +    } + +    public function __toString() { +        return self::toString($this->getCommandline()); +    } + +    /** +     * Put quotes around the given String if necessary. +     * +     * <p>If the argument doesn't include spaces or quotes, return it +     * as is. If it contains double quotes, use single quotes - else +     * surround the argument by double quotes.</p> +     * +     * @exception BuildException if the argument contains both, single +     *                           and double quotes. +     */ +    public static function quoteArgument($argument) { +        if (strpos($argument, "\"") !== false) { +            if (strpos($argument, "'") !== false) { +                throw new BuildException("Can't handle single and double quotes in same argument"); +            } else { +                return escapeshellarg($argument); +            } +        } elseif (strpos($argument, "'") !== false || strpos($argument, " ") !== false) { +            return escapeshellarg($argument); +            //return '\"' . $argument . '\"'; +        } else { +            return $argument; +        } +    } +         +    /** +     * Quotes the parts of the given array in way that makes them +     * usable as command line arguments. +     */ +    public static function toString($lines) { +        // empty path return empty string +        if (!$lines) { +            return ""; +        } + +        // path containing one or more elements +        $result = ""; +        for ($i = 0, $len=count($lines); $i < $len; $i++) { +            if ($i > 0) { +                $result .= ' '; +            } +            $result .= self::quoteArgument($lines[$i]); +        } +        return $result; +    } +     +    /** +     * +     * @param string $to_process +     * @return array +     */ +    public static function translateCommandline($to_process) { +         +        if (!$to_process) { +            return array(); +        } +             +        // parse with a simple finite state machine + +        $normal = 0; +        $inQuote = 1; +        $inDoubleQuote = 2; +         +        $state = $normal; +        $args = array(); +        $current = ""; +        $lastTokenHasBeenQuoted = false; +         +        $tok = strtok($to_process, ""); +        $tokens = preg_split('/(["\' ])/', $to_process, -1, PREG_SPLIT_DELIM_CAPTURE); +        while(($nextTok = array_shift($tokens)) !== null) { +            switch ($state) { +            case $inQuote: +                if ("'" == $nextTok) { +                    $lastTokenHasBeenQuoted = true; +                    $state = $normal; +                } else { +                    $current .= $nextTok; +                } +                break; +            case $inDoubleQuote: +                if ("\"" == $nextTok) { +                    $lastTokenHasBeenQuoted = true; +                    $state = $normal; +                } else { +                    $current .= $nextTok; +                } +                break; +            default: +                if ("'" == $nextTok) { +                    $state = $inQuote; +                } elseif ("\"" == $nextTok) { +                    $state = $inDoubleQuote; +                } elseif (" " == $nextTok) { +                    if ($lastTokenHasBeenQuoted || strlen($current) != 0) { +                        $args[] = $current; +                        $current = ""; +                    } +                } else { +                    $current .= $nextTok; +                } +                $lastTokenHasBeenQuoted = false; +                break; +            } +        } + +        if ($lastTokenHasBeenQuoted || strlen($current) != 0) { +            $args[] = $current; +        } + +        if ($state == $inQuote || $state == $inDoubleQuote) { +            throw new BuildException("unbalanced quotes in " . $to_process); +        } + +        return $args; +    } + +    /** +     * @return int Number of components in current commandline. +     */ +    public function size() { +        return count($this->getCommandline()); +    } + +    public function __copy() { +        $c = new Commandline(); +        $c->setExecutable($this->executable); +        $c->addArguments($this->getArguments()); +        return $c; +    } + +    /** +     * Clear out the whole command line.  */ +    public function clear() { +        $this->executable = null; +        $this->arguments->removeAllElements(); +    } + +    /** +     * Clear out the arguments but leave the executable in place for +     * another operation. +     */ +    public function clearArgs() { +        $this->arguments = array(); +    } + +    /** +     * Return a marker. +     * +     * <p>This marker can be used to locate a position on the +     * commandline - to insert something for example - when all +     * parameters have been set.</p> +     * @return CommandlineMarker +     */ +    public function createMarker() { +        return new CommandlineMarker($this, count($this->arguments)); +    } + +    /** +     * Returns a String that describes the command and arguments +     * suitable for verbose output before a call to +     * <code>Runtime.exec(String[])<code>. +     * +     * <p>This method assumes that the first entry in the array is the +     * executable to run.</p> +     * @param array $args CommandlineArgument[] to use +     * @return string +     */ +    public function describeCommand($args = null) { +        +        if ($args === null) { +            $args = $this->getCommandline(); +        } +            +        if (!$args) { +            return ""; +        } +         +        $buf = "Executing '"; +        $buf .= $args[0]; +        $buf .= "'"; +        if (count($args) > 0) { +            $buf .= " with "; +            $buf .= $this->describeArguments($args, 1); +        } else { +            $buf .= self::DISCLAIMER; +        } +        return $buf; +    } + +    /** +     * Returns a String that describes the arguments suitable for +     * verbose output before a call to +     * <code>Runtime.exec(String[])<code> +     * @param $args arguments to use (default is to use current class args) +     * @param $offset ignore entries before this index +     * @return string +     */ +    protected function describeArguments($args = null, $offset = 0) { +        if ($args === null) { +            $args = $this->getArguments(); +        }                 +         +        if ($args === null || count($args) <= $offset) { +            return ""; +        } +         +        $buf = "argument"; +        if (count($args) > $offset) { +            $buf .= "s"; +        } +        $buf .= ":" . Phing::getProperty("line.separator"); +        for ($i = $offset, $alen=count($args); $i < $alen; $i++) { +            $buf .= "'" . $args[$i] . "'" . Phing::getProperty("line.separator"); +        } +        $buf .= self::DISCLAIMER; +        return $buf; +    } +} + + +/** + * "Inner" class used for nested xml command line definitions. + */ +class CommandlineArgument { + +    private $parts = array(); +    private $outer; +     +    public function __construct(Commandline $outer) { +        $this->outer = $outer; +    } +     +    /** +     * Sets a single commandline argument. +     * +     * @param string $value a single commandline argument. +     */ +    public function setValue($value) { +        $this->parts = array($value); +    } + +    /** +     * Line to split into several commandline arguments. +     * +     * @param line line to split into several commandline arguments +     */ +    public function setLine($line) { +        if ($line === null) { +            return; +        } +        $this->parts = $this->outer->translateCommandline($line); +    } + +    /** +     * Sets a single commandline argument and treats it like a +     * PATH - ensures the right separator for the local platform +     * is used. +     * +     * @param value a single commandline argument. +     */ +    public function setPath($value) { +        $this->parts = array( (string) $value ); +    } + +    /** +     * Sets a single commandline argument to the absolute filename +     * of the given file. +     * +     * @param value a single commandline argument. +     */ +    public function setFile(PhingFile $value) { +        $this->parts = array($value->getAbsolutePath()); +    } + +    /** +     * Returns the parts this Argument consists of. +     * @return array string[] +     */ +    public function getParts() { +        return $this->parts; +    } +} + +/** + * Class to keep track of the position of an Argument. + */ +// <p>This class is there to support the srcfile and targetfile +// elements of <execon> and <transform> - don't know +// whether there might be additional use cases.</p> --SB +class CommandlineMarker { + +    private $position; +    private $realPos = -1; +    private $outer; +     +    public function __construct(Comandline $outer, $position) { +        $this->outer = $outer; +        $this->position = $position; +    } + +    /** +     * Return the number of arguments that preceeded this marker. +     * +     * <p>The name of the executable - if set - is counted as the +     * very first argument.</p> +     */ +    public function getPosition() { +        if ($this->realPos == -1) { +            $realPos = ($this->outer->executable === null ? 0 : 1); +            for ($i = 0; $i < $position; $i++) { +                $arg = $this->arguments[$i]; +                $realPos += count($arg->getParts()); +            } +        } +        return $this->realPos; +    } +} + diff --git a/buildscripts/phing/classes/phing/types/DataType.php b/buildscripts/phing/classes/phing/types/DataType.php new file mode 100644 index 00000000..2c06b80d --- /dev/null +++ b/buildscripts/phing/classes/phing/types/DataType.php @@ -0,0 +1,182 @@ +<?php +/* + *  $Id: DataType.php,v 1.9 2005/11/02 13:55:34 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/ProjectComponent.php'; +include_once 'phing/BuildException.php'; + +/** + * Base class for those classes that can appear inside the build file + * as stand alone data types. + * + * This class handles the common description attribute and provides + * a default implementation for reference handling and checking for + * circular references that is appropriate for types that can not be + * nested inside elements of the same type (i.e. patternset but not path) + * + * @package   phing.types + */ +class DataType extends ProjectComponent { + +    /** The descriptin the user has set. */ +    public $description = null; + +    /** Value to the refid attribute. Type of Reference*/ +    public $ref = null; + +    /** +     * Are we sure we don't hold circular references? +     * +     * Subclasses are responsible for setting this value to false +     * if we'd need to investigate this condition (usually because a +     * child element has been added that is a subclass of DataType). +     * @var boolean +     */ +    protected $checked = true; +   +    /** +     * Sets a description of the current data type. It will be useful +     * in commenting what we are doing. +     */ +    function setDescription($desc) { +        $this->description = (string) $desc; +    } + +    /** Return the description for the current data type. */ +    function getDescription() { +        return $this->description; +    } + +    /** Has the refid attribute of this element been set? */ +    function isReference() { +        return ($this->ref !== null); +    } + +    /** +     * Set the value of the refid attribute. +     * +     * Subclasses may need to check whether any other attributes +     * have been set as well or child elements have been created and +     * thus override this method. if they do they must call parent::setRefid() +	 *  +	 * @param Reference $r +	 * @return void +     */ +    function setRefid(Reference $r) { +        $this->ref = $r; +        $this->checked = false; +    } + +    /** +     * Check to see whether any DataType we hold references to is +     * included in the Stack (which holds all DataType instances that +     * directly or indirectly reference this instance, including this +     * instance itself). +     * +     * If one is included, throw a BuildException created by circularReference +     * +     * This implementation is appropriate only for a DataType that +     * cannot hold other DataTypes as children. +     * +     * The general contract of this method is that it shouldn't do +     * anything if checked is true and set it to true on exit. +     */ +    function dieOnCircularReference(&$stk, Project $p) { +        if ($this->checked || !$this->isReference()) { +            return; +        } + +        $o = $this->ref->getReferencedObject($p); + +        if ($o instanceof DataType) { +             +            // TESTME - make sure that in_array() works just as well here +            // +            // check if reference is in stack +            //$contains = false; +            //for ($i=0, $size=count($stk); $i < $size; $i++) { +            //    if ($stk[$i] === $o) { +            //        $contains = true; +            //        break; +            //    } +            //} + +            if (in_array($o, $stk, true)) { +                // throw build exception +                throw $this->circularReference(); +            } else { +                array_push($stk, $o); +                $o->dieOnCircularReference($stk, $p); +                array_pop($stk); +            } +        } +        $this->checked = true; +    } + +    /** Performs the check for circular references and returns the referenced object. */ +    function getCheckedRef($requiredClass, $dataTypeName) { +     +        if (!$this->checked) { +            // should be in stack +            $stk = array(); +            $stk[] = $this; +            $this->dieOnCircularReference($stk, $this->getProject());             +        } + +        $o = $this->ref->getReferencedObject($this->getProject()); +        if (!($o instanceof $requiredClass) ) { +            throw new BuildException($this->ref->getRefId()." doesn't denote a " . $dataTypeName); +        } else { +            return $o; +        } +    } + +    /** +     * Creates an exception that indicates that refid has to be the +     * only attribute if it is set. +     */ +    function tooManyAttributes() { +        return new BuildException( "You must not specify more than one attribute when using refid" ); +    } + +    /** +     * Creates an exception that indicates that this XML element must +     * not have child elements if the refid attribute is set. +     */ +    function noChildrenAllowed() { +        return new BuildException("You must not specify nested elements when using refid"); +    } + +    /** +     * Creates an exception that indicates the user has generated a +     * loop of data types referencing each other. +     */ +    function circularReference() { +        return new BuildException("This data type contains a circular reference."); +    } +     +    /** +     * Template method being called when the data type has been  +     * parsed completely. +     * @return void +     */ +    function parsingComplete() {} +} + diff --git a/buildscripts/phing/classes/phing/types/Description.php b/buildscripts/phing/classes/phing/types/Description.php new file mode 100644 index 00000000..e69f8da4 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Description.php @@ -0,0 +1,53 @@ +<?php + +/* + *  $Id: Description.php,v 1.4 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Description is used to provide a project-wide description element + * (that is, a description that applies to a buildfile as a whole). + * If present, the <description> element is printed out before the + * target descriptions. + *  + * Description has no attributes, only text.  There can only be one + * project description per project.  A second description element will + * overwrite the first. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Craeg Strong <cstrong@arielpartners.com> (Ant) + * @package phing.types + */ +class Description extends DataType { + +    /** +     * Adds descriptive text to the project. +     * +     * @return void +     */ +    public function addText($text) { +        $currentDescription = $this->project->getDescription(); +        if ($currentDescription === null) { +            $this->project->setDescription($text); +        } else { +            $this->project->setDescription($currentDescription . $text); +        } +    } +     +} diff --git a/buildscripts/phing/classes/phing/types/DirSet.php b/buildscripts/phing/classes/phing/types/DirSet.php new file mode 100644 index 00000000..45bcc636 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/DirSet.php @@ -0,0 +1,49 @@ +<?php + +/* + * $Id: DirSet.php,v 1.3 2003/11/19 05:48:30 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +include_once 'phing/types/AbstractFileSet.php'; + +/** + * Subclass as hint for supporting tasks that the included directories + * instead of files should be used. + * + * @package phing.types + */ +class DirSet extends AbstractFileSet { +     +    public function __construct($dirset = null) { +        parent::__construct($dirset); +    }     + +    /** +     * Return a DirSet that has the same basedir and same patternsets +     * as this one. +     */ +    public function __clone() { +        if ($this->isReference()) { +            return new DirSet($this->getRef($this->getProject())); +        } else { +            return new DirSet($this); +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/types/FileList.php b/buildscripts/phing/classes/phing/types/FileList.php new file mode 100644 index 00000000..1ec1273f --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FileList.php @@ -0,0 +1,223 @@ +<?php +/* + *  $Id: FileList.php,v 1.10 2005/11/01 15:26:09 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/types/DataType.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * FileList represents an explicitly named list of files. FileLists + * are useful when you want to capture a list of files regardless of + * whether they currently exist. + * + * <filelist  + *    id="docfiles"  + *   dir="${phing.docs.dir}" + *   files="chapters/Installation.html,chapters/Setup.html"/>  + * + * OR  + *  + * <filelist + *         dir="${doc.src.dir}" + *         listfile="${phing.docs.dir}/PhingGuide.book"/> + *  + * (or a mixture of files="" and listfile="" can be used) + *  + * @author Hans Lellelid <hans@xmpl.org> + * @version $Revision: 1.10 $ + * @package phing.types + */ +class FileList extends DataType { +         +    // public for "cloning" purposes +     +    /** Array containing all filenames. */ +    public $filenames = array(); +     +    /** Base directory for this file list. */ +    public $dir; +     +    /** PhingFile that contains a list of files (one per line). */ +    public $listfile; +     +    /** +     * Construct a new FileList. +     * @param array $filelist; +     */ +    function __construct($filelist = null) { +        if ($filelist !== null) { +            $this->dir       = $filelist->dir; +            $this->filenames = $filelist->filenames; +            $this->listfile = $filelist->listfile; +        } +    } + +    /** +     * Makes this instance in effect a reference to another FileList +     * instance. +     */ +    function setRefid(Reference $r) { +        if ($this->dir !== null || count($this->filenames) !== 0) { +            throw $this->tooManyAttributes(); +        } +        parent::setRefid($r); +    } + +    /** +     * Base directory for files in list. +     * @param PhingFile $dir +     */ +    function setDir(PhingFile $dir) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if (!($dir instanceof PhingFile)) { +            $dir = new PhingFile($dir); +        } +        $this->dir = $dir; +    } +     +    /** +     * Get the basedir for files in list. +     * @return PhingFile +     */ +    function getDir(Project $p) { +        if ($this->isReference()) { +            $ref = $this->getRef($p); +            return $ref->getDir($p); +        } +        return $this->dir; +    } +     +    /** +     * Set the array of files in list. +     * @param array $filenames +     */ +    function setFiles($filenames) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if (!empty($filenames)) { +            $tok = strtok($filenames, ", \t\n\r");             +            while ($tok !== false) { +                $fname = trim($tok); +                if ($fname !== "") { +                    $this->filenames[] = $tok; +                } +                $tok = strtok(", \t\n\r"); +            } +        } +    } +     +    /** +     * Sets a source "list" file that contains filenames to add -- one per line. +     * @param string $file +     */ +    function setListFile($file) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if (!($file instanceof PhingFile)) { +            $file = new PhingFile($file); +        } +        $this->listfile = $file; +    } +     +    /** +     * Get the source "list" file that contains file names. +     * @return PhingFile +     */ +    function getListFile() { +        if ($this->isReference()) { +            $ref = $this->getRef($p); +            return $ref->getListFile($p); +        } +        return $this->listfile; +    } + +    /** +     * Returns the list of files represented by this FileList. +     * @param Project $p +     * @return array +     */ +    function getFiles(Project $p) { +     +        if ($this->isReference()) { +            $ret = $this->getRef($p); +            $ret = $ret->getFiles($p); +            return $ret; +        } +         +        if ($this->listfile !== null) { +            $this->readListFile($p); +        } +         +        return $this->filenames; +    } + + +    /** +      * Performs the check for circular references and returns the +      * referenced FileSet. +      * @param Project $p +      */ +    function getRef(Project $p) { +        if (!$this->checked) { +            $stk = array(); +            array_push($stk, $this); +            $this->dieOnCircularReference($stk, $p);             +        } + +        $o = $this->ref->getReferencedObject($p); +        if (!($o instanceof FileList)) { +            throw new BuildException($this->ref->getRefId()." doesn't denote a filelist"); +        } else { +            return $o; +        } +    } + +    /** +     * Reads file names from a file and adds them to the files array. +     * @param Project $p +     */ +    private function readListFile(Project $p) { +        $listReader = null; +        try { +            // Get a FileReader +            $listReader = new BufferedReader(new FileReader($this->listfile));  +         +            $line = $listReader->readLine(); +            while ($line !== null) { +                if (!empty($line)) { +                    $line = $p->replaceProperties($line); +                    $this->filenames[] = trim($line); +                } +                $line = $listReader->readLine(); +            }             +        } catch (Exception $e)  { +            if ($listReader) $listReader->close();             +            throw new BuildException("An error occured while reading from list file " . $this->listfile->__toString() . ": " . $e->getMessage());  +        }  +         +        $listReader->close();         +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/FileSet.php b/buildscripts/phing/classes/phing/types/FileSet.php new file mode 100644 index 00000000..8cfb54dc --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FileSet.php @@ -0,0 +1,56 @@ +<?php + +/* + * $Id: FileSet.php,v 1.5 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/AbstractFileSet.php'; + +/** + * Moved out of MatchingTask to make it a standalone object that could + * be referenced (by scripts for example). + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Arnout J. Kuiper <ajkuiper@wxs.nl> (Ant) + * @author Stefano Mazzocchi <stefano@apache.org> (Ant) + * @author Sam Ruby <rubys@us.ibm.com> (Ant) + * @author Jon S. Stevens <jon@clearink.com> (Ant) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @author Magesh Umasankar (Ant) + * @package phing.types + */ +class FileSet extends AbstractFileSet { +     +    function __construct($fileset = null) { +        parent::__construct($fileset); +    } + +    /** +     * Return a FileSet that has the same basedir and same patternsets +     * as this one. +     */ +    public function __clone() { +        if ($this->isReference()) { +            return new FileSet($this->getRef($this->getProject())); +        } else { +            return new FileSet($this); +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/types/FilterChain.php b/buildscripts/phing/classes/phing/types/FilterChain.php new file mode 100644 index 00000000..4f2d702b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/FilterChain.php @@ -0,0 +1,164 @@ +<?php +/* + *  $Id: FilterChain.php,v 1.11 2005/12/08 16:03:49 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/types/DataType.php'; +include_once 'phing/filters/HeadFilter.php'; +include_once 'phing/filters/TailFilter.php'; +include_once 'phing/filters/LineContains.php'; +include_once 'phing/filters/LineContainsRegexp.php'; +include_once 'phing/filters/ExpandProperties.php'; +include_once 'phing/filters/PrefixLines.php'; +include_once 'phing/filters/ReplaceRegexp.php'; +include_once 'phing/filters/ReplaceTokens.php'; +include_once 'phing/filters/StripPhpComments.php'; +include_once 'phing/filters/StripLineBreaks.php'; +include_once 'phing/filters/StripLineComments.php'; +include_once 'phing/filters/TabToSpaces.php'; +include_once 'phing/filters/TidyFilter.php'; +include_once 'phing/filters/TranslateGettext.php'; +include_once 'phing/filters/XsltFilter.php'; + +/* + * FilterChain may contain a chained set of filter readers. + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @version   $Revision: 1.11 $ + * @package   phing.types + */ +class FilterChain extends DataType { + +    private $filterReaders = array(); + +    function __construct(Project $project) { +        $this->project = $project; +    } + +    function getFilterReaders() { +        return $this->filterReaders; +    } + +    function addExpandProperties(ExpandProperties $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } + +    function addGettext(TranslateGettext $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addHeadFilter(HeadFilter $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addTailFilter(TailFilter $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addLineContains(LineContains $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addLineContainsRegExp(LineContainsRegExp $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addPrefixLines(PrefixLines $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addReplaceTokens(ReplaceTokens $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } + +    function addReplaceRegexp(ReplaceRegexp $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addStripPhpComments(StripPhpComments $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addStripLineBreaks(StripLineBreaks $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addStripLineComments(StripLineComments $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o;         +    } +     +	function addTidyFilter(TidyFilter $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +	 +    function addTabToSpaces(TabToSpaces $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addXsltFilter(XsltFilter $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } +     +    function addFilterReader(PhingFilterReader $o) { +        $o->setProject($this->project); +        $this->filterReaders[] = $o; +    } + +    /* +     * Makes this instance in effect a reference to another FilterChain  +     * instance. +     * +     * <p>You must not set another attribute or nest elements inside +     * this element if you make it a reference.</p> +     * +     * @param r the reference to which this instance is associated +     * @throw BuildException if this instance already has been configured. +    */ +    function setRefid(Reference $r) { +     +        if ( count($this->filterReaders) === 0 ) { +            throw $this->tooManyAttributes(); +        } + +        // change this to get the objects from the other reference +        $o = $r->getReferencedObject($this->getProject()); +        if ( $o instanceof FilterChain ) { +            $this->filterReaders = $o->getFilterReaders(); +        } else { +            throw new BuildException($r->getRefId()." doesn't refer to a FilterChain"); +        } +        parent::setRefid($r); +    } +     +} diff --git a/buildscripts/phing/classes/phing/types/Mapper.php b/buildscripts/phing/classes/phing/types/Mapper.php new file mode 100644 index 00000000..f0df6d24 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Mapper.php @@ -0,0 +1,207 @@ +<?php +/* + *  $Id: Mapper.php,v 1.11 2004/03/15 17:11:16 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/types/DataType.php'; +include_once 'phing/types/Path.php'; + +/** + * Filename Mapper maps source file name(s) to target file name(s). + *  + * Built-in mappers can be accessed by specifying they "type" attribute: + * <code> + * <mapper type="glob" from="*.php" to="*.php.bak"/> + * </code> + * Custom mappers can be specified by providing a dot-path to a include_path-relative + * class: + * <code> + * <mapper classname="myapp.mappers.DevToProdMapper" from="*.php" to="*.php"/> + * <!-- maps all PHP files from development server to production server, for example --> + * </code> + * + * @author Hans Lellelid <hans@xmpl.org> + * @package phing.types + */ +class Mapper extends DataType { + +    protected $type;     +    protected $classname; +    protected $from; +    protected $to; +    protected $classpath; +    protected $classpathId; + +     +    function __construct(Project $project) { +        $this->project = $project; +    } +     +    /** +     * Set the classpath to be used when searching for component being defined +     *  +     * @param Path $classpath An Path object containing the classpath. +     */ +    public function setClasspath(Path $classpath) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($this->classpath === null) { +            $this->classpath = $classpath; +        } else { +            $this->classpath->append($classpath); +        } +    } + +    /** +     * Create the classpath to be used when searching for component being defined +     */  +    public function createClasspath() { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($this->classpath === null) { +            $this->classpath = new Path($this->project); +        } +        return $this->classpath->createPath(); +    } + +    /** +     * Reference to a classpath to use when loading the files. +     */ +    public function setClasspathRef(Reference $r) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->classpathId = $r->getRefId(); +        $this->createClasspath()->setRefid($r); +    } + +    /** Set the type of FileNameMapper to use. */ +    function setType($type) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->type = $type; +    } + +    /** Set the class name of the FileNameMapper to use. */ +    function setClassname($classname) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->classname = $classname; +    } + +    /** +     * Set the argument to FileNameMapper.setFrom +     */ +    function setFrom($from) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->from = $from; +    } + +    /** +     * Set the argument to FileNameMapper.setTo +     */ +    function setTo($to) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->to = $to; +    } + +    /** +     * Make this Mapper instance a reference to another Mapper. +     * +     * You must not set any other attribute if you make it a reference. +     */ +    function setRefid($r) { +        if ($this->type !== null || $this->from !== null || $this->to !== null) { +            throw DataType::tooManyAttributes(); +        } +        parent::setRefid($r); +    } + +    /** Factory, returns inmplementation of file name mapper as new instance */ +    function getImplementation() { +        if ($this->isReference()) { +            $tmp = $this->getRef(); +            return $tmp->getImplementation(); +        } + +        if ($this->type === null && $this->classname === null) { +            throw new BuildException("either type or classname attribute must be set for <mapper>"); +        } +         +        if ($this->type !== null) { +            switch($this->type) { +            case 'identity': +                $this->classname = 'phing.mappers.IdentityMapper'; +                break; +            case 'flatten': +                $this->classname = 'phing.mappers.FlattenMapper'; +                break; +            case 'glob': +                $this->classname = 'phing.mappers.GlobMapper'; +                break; +            case 'regexp': +            case 'regex': +                $this->classname = 'phing.mappers.RegexpMapper';             +                break; +            case 'merge': +                $this->classname = 'phing.mappers.MergeMapper';                 +                break; +            default: +                throw new BuildException("Mapper type {$this->type} not known"); +                break; +            } +        } + +        // get the implementing class +        $cls = Phing::import($this->classname, $this->classpath); +         +        $m = new $cls; +        $m->setFrom($this->from); +        $m->setTo($this->to); +         +        return $m; +    } + +    /** Performs the check for circular references and returns the referenced Mapper. */ +    private function getRef() { +        if (!$this->checked) { +            $stk = array(); +            $stk[] = $this; +            $this->dieOnCircularReference($stk, $this->project);             +        } + +        $o = $this->ref->getReferencedObject($this->project); +        if (!($o instanceof Mapper)) { +            $msg = $this->ref->getRefId()." doesn't denote a mapper"; +            throw new BuildException($msg); +        } else { +            return $o; +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Parameter.php b/buildscripts/phing/classes/phing/types/Parameter.php new file mode 100644 index 00000000..6892ed7e --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Parameter.php @@ -0,0 +1,99 @@ +<?php +/* + *  $Id: Parameter.php,v 1.6 2005/10/05 20:23:22 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/types/DataType.php'; + +/* + * A parameter is composed of a name, type and value. Nested + * Parameters are also possible, but the using task/type has + * to support them + * + * @author    Manuel Holtgrewe + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @package   phing.types +*/ +class Parameter extends DataType { + +    /** Parameter name */ +    protected $name; +     +    /** Paramter type */ +    protected $type; +     +    /** Parameter value */ +    protected $value; +     +    /** Nested parameters */ +    protected $parameters = array(); + +    function setName($name) { +        $this->name = (string) $name; +    } +     +    function setType($type) { +        $this->type = (string) $type; +    } + +	/** +     * Sets value to dynamic register slot. +     * @param RegisterSlot $value +     */ +    public function setListeningValue(RegisterSlot $value) { +        $this->value = $value; +    } +	 +    function setValue($value) { +        $this->value = (string) $value; +    } + +    function getName() { +        return $this->name; +    } + +    function getType() { +        return $this->type; +    } + +    function getValue() { +		if ($this->value instanceof RegisterSlot) { +            return $this->value->getValue(); +        } else { +            return $this->value; +        } +    } +     +    /** +     * @return Parameter +     */ +    function createParam() { +        $num = array_push($this->parameters, new Parameter()); +        return $this->parameters[$num-1]; +    } + +    /** +     * @return array Nested parameters. +     */ +    function getParams() { +        return $this->parameters; +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Parameterizable.php b/buildscripts/phing/classes/phing/types/Parameterizable.php new file mode 100644 index 00000000..b24aa38b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Parameterizable.php @@ -0,0 +1,32 @@ +<?php + +/* + * $Id: Parameterizable.php,v 1.3 2003/11/19 05:48:30 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Parameterizable objects take genric key value pairs. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Magesh Umasankar (Ant) + * @package phing.types + */ +interface Parameterizable { +    function setParameters($parameters); +} diff --git a/buildscripts/phing/classes/phing/types/Path.php b/buildscripts/phing/classes/phing/types/Path.php new file mode 100644 index 00000000..196fe9c4 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Path.php @@ -0,0 +1,456 @@ +<?php +/* + *  $Id: Path.php,v 1.13 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/types/DataType.php'; +include_once 'phing/util/PathTokenizer.php'; +include_once 'phing/types/FileSet.php'; + +/** + * This object represents a path as used by include_path or PATH + * environment variable. + * + * This class has been adopted from the Java Ant equivalent.  The ability have + * path structures in Phing is important; however, because of how PHP classes interact + * the ability to specify CLASSPATHs makes less sense than Java.Rather than providing + * CLASSPATH for any tasks that take classes as parameters, perhaps a better + * solution in PHP is to have an IncludePath task, which prepends paths to PHP's include_path + * INI variable. This gets around the problem that simply using a path to load the initial + * PHP class is not enough (in most cases the loaded class may assume that it is on the global + * PHP include_path, and will try to load dependent classes accordingly).  The other option is + * to provide a way for this class to add paths to the include path, if desired -- or to create + * an IncludePath subclass.  Once added, though, when would a path be removed from the include path? + *  + * <p> + * <code> + * <sometask><br> + *   <somepath><br> + *     <pathelement location="/path/to/file" /><br> + *     <pathelement path="/path/to/class2;/path/to/class3" /><br> + *     <pathelement location="/path/to/file3" /><br> + *   </somepath><br> + * </sometask><br> + * </code> + * <p> + * The object implemention <code>sometask</code> must provide a method called + * <code>createSomepath</code> which returns an instance of <code>Path</code>. + * Nested path definitions are handled by the Path object and must be labeled + * <code>pathelement</code>.<p> + * + * The path element takes a parameter <code>path</code> which will be parsed + * and split into single elements. It will usually be used + * to define a path from an environment variable. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Thomas.Haas@softwired-inc.com (Ant) + * @author Stefan Bodewig <stefan.bodewig@epost.de> (Ant) + * @package phing.types + */ +class Path extends DataType { + +    private $elements = array();     +     +    /** +     * Constructor for internally instantiated objects sets project. +     * @param Project $project +     * @param string $path (for use by IntrospectionHelper) +     */ +    public function __construct($project = null, $path = null) { +        if ($project !== null) { +            $this->setProject($project); +        } +        if ($path !== null) { +            $this->createPathElement()->setPath($path); +        }         +    } + +    /** +     * Adds a element definition to the path. +     * @param $location the location of the element to add (must not be +     * <code>null</code> nor empty. +     * @throws BuildException +     */ +    public function setDir(PhingFile $location) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        }         +        $this->createPathElement()->setDir($location); +    } + +    /** +     * Parses a path definition and creates single PathElements. +     * @param path the path definition. +     * @throws BuildException +     */ +    public function setPath($path) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        $this->createPathElement()->setPath($path); +    } + +    /** +     * Makes this instance in effect a reference to another Path instance. +     * +     * <p>You must not set another attribute or nest elements inside +     * this element if you make it a reference.</p> +     * @throws BuildException +     */ +    public function setRefid(Reference $r)  { +        if (!empty($this->elements)) { +            throw $this->tooManyAttributes(); +        } +        $this->elements[] = $r; +        parent::setRefid($r); +    } + +    /** +     * Creates the nested <code><pathelement></code> element. +     * @throws BuildException  +     */ +    public function createPathElement() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $pe = new PathElement($this); +        $this->elements[] = $pe; +        return $pe; +    } + +    /** +     * Adds a nested <code><fileset></code> element. +     * @throws BuildException  +     */ +    public function addFileset(FileSet $fs) { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $this->elements[] = $fs; +        $this->checked = false; +    } + +    /** +     * Adds a nested <code><dirset></code> element. +     * @throws BuildException  +     */ +    public function addDirset(DirSet $dset) { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $this->elements[] = $dset; +        $this->checked = false; +    } + +    /** +     * Creates a nested <code><path></code> element. +     * @throws BuildException +     */ +    public function createPath() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        $p = new Path($this->project); +        $this->elements[] = $p; +        $this->checked = false; +        return $p; +    } + +    /** +     * Append the contents of the other Path instance to this. +     */ +    public function append(Path $other) { +        if ($other === null) { +            return; +        } +        $l = $other->listPaths(); +        foreach($l as $path) { +            if (!in_array($path, $this->elements, true)) { +                $this->elements[] = $path; +            } +        } +    } + +     /** +     * Adds the components on the given path which exist to this +     * Path. Components that don't exist, aren't added. +     * +     * @param Path $source - Source path whose components are examined for existence. +     */ +    public function addExisting(Path $source) { +        $list = $source->listPaths(); +        foreach($list as $el) { +            $f = null; +            if ($this->project !== null) { +                $f = $this->project->resolveFile($el); +            } else { +                $f = new PhingFile($el); +            } + +            if ($f->exists()) { +                $this->setDir($f); +            } else { +                $this->log("dropping " . $f->__toString() . " from path as it doesn't exist",  +                    PROJECT_MSG_VERBOSE); +            } +        } +    } + +    /** +     * Returns all path elements defined by this and nested path objects. +     * @return array List of path elements. +     */ +    public function listPaths() { +        if (!$this->checked) { +            // make sure we don't have a circular reference here +            $stk = array(); +            array_push($stk, $this); +            $this->dieOnCircularReference($stk, $this->project); +        } + +        $result = array(); +        for ($i = 0, $elSize=count($this->elements); $i < $elSize; $i++) { +            $o = $this->elements[$i]; +            if ($o instanceof Reference) { +                $o = $o->getReferencedObject($this->project); +                // we only support references to paths right now +                if (!($o instanceof Path)) { +                    $msg = $r->getRefId() . " doesn't denote a path"; +                    throw new BuildException($msg); +                } +            } +             +            if (is_string($o)) { +                $result[] = $o; +            } elseif ($o instanceof PathElement) { +                $parts = $o->getParts(); +                if ($parts === null) { +                    throw new BuildException("You must either set location or"  +                        . " path on <pathelement>"); +                } +                foreach($parts as $part) { +                    $result[] = $part; +                } +            } elseif ($o instanceof Path) { +                $p = $o; +                if ($p->getProject() === null) { +                    $p->setProject($this->getProject()); +                } +                $parts = $p->listPaths(); +                foreach($parts as $part) { +                    $result[] = $part; +                } +            } elseif ($o instanceof DirSet) { +                $dset = $o; +                $ds = $dset->getDirectoryScanner($this->project); +                $dirstrs = $ds->getIncludedDirectories(); +                $dir = $dset->getDir($this->project); +                $this->addUnlessPresent($result, $dir, $s);   +                 +                foreach($dirstrs as $dstr) { +                    $d = new PhingFile($dir, $dstr); +                    $result[] = $d->getAbsolutePath(); +                }                 +                      +            } elseif ($o instanceof FileList) { +                $fl = $o; +                $dirstrs = $fl->getFiles($this->project); +                $dir = $fl->getDir($this->project); +                foreach($dirstrs as $dstr) { +                    $d = new PhingFile($dir, $dstr); +                    $result[] = $d->getAbsolutePath(); +                } +            } +        } +         +        return array_unique($result); +    } + + +    /** +     * Returns a textual representation of the path, which can be used as +     * CLASSPATH or PATH environment variable definition. +     * @return string A textual representation of the path. +     */ +    public function __toString() { +         +        $list = $this->listPaths(); + +        // empty path return empty string +        if (empty($list)) { +            return ""; +        } +         +        return implode(PATH_SEPARATOR, $list); +    } + +    /** +     * Splits a PATH (with : or ; as separators) into its parts. +     * @param Project $project +     * @param string $source +     */ +    public static function translatePath(Project $project, $source) { +        $result = array(); +        if ($source == null) { +          return ""; +        } + +        $tok = new PathTokenizer($source); +        $element = ""; +        while ($tok->hasMoreTokens()) {             +            $pathElement = $tok->nextToken(); +            try { +                $element .= self::resolveFile($project, $pathElement); +            } catch (BuildException $e) { +                $this->project->log("Dropping path element " . $pathElement  +                    . " as it is not valid relative to the project",  +                    PROJECT_MSG_VERBOSE); +            } +             +            for ($i = 0, $_i=strlen($element); $i < $_i; $i++) { +                self::translateFileSep($element, $i); +            } +            $result[] = $element; +        } +         +        return $result; +    } + +    /** +     * Returns its argument with all file separator characters +     * replaced so that they match the local OS conventions.   +     */ +    public static function translateFile($source) { +        if ($source == null) { +          return ""; +        } + +        $result = $source; +        for ($i = 0, $_i=strlen($source); $i < $_i; $i++) { +            self::translateFileSep($result, $i); +        } +         +        return $result; +    } + +    /** +     * Translates all occurrences of / or \ to correct separator of the +     * current platform and returns whether it had to do any +     * replacements.   +     */ +    protected static function translateFileSep(&$buffer, $pos) { +        if ($buffer{$pos} == '/' || $buffer{$pos} == '\\') { +            $buffer{$pos} = DIRECTORY_SEPARATOR; +            return true; +        } +        return false; +    } + +    /** +     * How many parts does this Path instance consist of. +     * DEV NOTE: expensive call! list is generated, counted, and then +     * discareded. +     * @return int +     */ +    public function size() { +        return count($this->listPaths()); +    } + +    /** +     * Return a Path that holds the same elements as this instance. +     */ +    public function __clone() { +        $p = new Path($this->project); +        $p->append($this); +        return $p; +    } + +    /** +     * Overrides the version of DataType to recurse on all DataType +     * child elements that may have been added.   +     * @throws BuildException +     */ +    public function dieOnCircularReference(&$stk, Project $p) { + +        if ($this->checked) { +            return; +        } +     +        // elements can contain strings, FileSets, Reference, etc. +        foreach($this->elements as $o) { +             +            if ($o instanceof Reference) { +                $o = $o->getReferencedObject($p); +            } + +            if ($o instanceof DataType) { +                if (in_array($o, $stk, true)) { +                    throw $this->circularReference(); +                } else { +                    array_push($stk, $o); +                    $o->dieOnCircularReference($stk, $p); +                    array_pop($stk); +                } +            } +        } +         +        $this->checked = true; +    } + +    /** +     * Resolve a filename with Project's help - if we know one that is. +     * +     * <p>Assume the filename is absolute if project is null.</p> +     */ +    private static function resolveFile(Project $project, $relativeName) { +        if ($project !== null) { +            $f = $project->resolveFile($relativeName); +            return $f->getAbsolutePath(); +        } +        return $relativeName; +    }     + +} + + +/** + * Helper class, holds the nested <code><pathelement></code> values. + */ +class PathElement { + +    private $parts = array(); +    private $outer; +     +    public function __construct(Path $outer) { +        $this->outer = $outer; +    } +     +    public function setDir(PhingFile $loc) { +        $this->parts = array(Path::translateFile($loc->getAbsolutePath())); +    } + +    public function setPath($path) { +        $this->parts = Path::translatePath($this->outer->getProject(), $path); +    } + +    public function getParts() { +        return $this->parts; +    } +} +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/types/PatternSet.php b/buildscripts/phing/classes/phing/types/PatternSet.php new file mode 100644 index 00000000..2963ab9e --- /dev/null +++ b/buildscripts/phing/classes/phing/types/PatternSet.php @@ -0,0 +1,449 @@ +<?php +/* + *  $Id: PatternSet.php,v 1.8 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +include_once 'phing/system/io/FileReader.php'; +include_once 'phing/types/DataType.php'; + +/** + * The patternset storage component. Carries all necessary data and methods + * for the patternset stuff. + * + * @author   Andreas Aderhold, andi@binarycloud.com + * @version  $Revision: 1.8 $ + * @package  phing.types + */ +class PatternSet extends DataType { + +    private $includeList = array(); +    private $excludeList = array(); +    private $includesFileList = array(); +    private $excludesFileList = array(); + +    /** +     * Makes this instance in effect a reference to another PatternSet +     * instance. +     * You must not set another attribute or nest elements inside +     * this element if you make it a reference. +     */ +    function setRefid(Reference $r) { +        if (!empty($this->includeList) || !empty($this->excludeList)) { +            throw $this->tooManyAttributes(); +        } +        parent::setRefid($r); +    } + + +    /** +    * Add a name entry on the include list +    * +    * @returns PatternSetNameEntry Reference to object +    * @throws  BuildException +    */ +    function createInclude() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->addPatternToList($this->includeList); +    } + + +    /** +    * Add a name entry on the include files list +    * +    * @returns PatternSetNameEntry Reference to object +    * @throws  BuildException +    */ +    function createIncludesFile() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->addPatternToList($this->includesFileList); +    } + +    /** +    * Add a name entry on the exclude list +    * +    * @returns PatternSetNameEntry Reference to object +    * @throws  BuildException +    */ +    function createExclude() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        return $this->addPatternToList($this->excludeList); +    } + +    /** +     * add a name entry on the exclude files list +    * +    * @returns PatternSetNameEntry Reference to object +    * @throws  BuildException +     */ + +    function createExcludesFile() { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +            return; +        } +        return $this->addPatternToList($this->excludesFileList); +    } + + +    /** +     * Sets the set of include patterns. Patterns may be separated by a comma +     * or a space. +     * +     * @param   string the string containing the include patterns +     * @returns void +     * @throws  BuildException +     */ +    function setIncludes($includes) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($includes !== null && strlen($includes) > 0) { +            $tok = strtok($includes, ", "); +            while ($tok !== false) { +                $o = $this->createInclude(); +                $o->setName($tok); +                $tok = strtok(", "); +            } +        } +    } + + +    /** +     * Sets the set of exclude patterns. Patterns may be separated by a comma +     * or a space. +     * +     * @param string the string containing the exclude patterns +    * @returns void +    * @throws  BuildException +     */ + +    function setExcludes($excludes) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($excludes !== null && strlen($excludes) > 0) { +            $tok = strtok($excludes, ", "); +            while ($tok !== false) { +                $o = $this->createExclude(); +                $o->setName($tok); +                $tok = strtok(", "); +            } +        } +    } + +    /** +     * add a name entry to the given list +     * +     * @param array List onto which the nameentry should be added +     * @returns PatternSetNameEntry  Reference to the created PsetNameEntry instance +     */ +    private function addPatternToList(&$list) { +        $num = array_push($list, new PatternSetNameEntry()); +        return $list[$num-1]; +    } + +    /** +     * Sets the name of the file containing the includes patterns. +     * +     * @param includesFile The file to fetch the include patterns from. +     */ +    function setIncludesFile($includesFile) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($includesFile instanceof File) { +            $includesFile = $includesFile->getPath(); +        } +        $o = $this->createIncludesFile(); +        $o->setName($includesFile); +    } + +    /** +     * Sets the name of the file containing the excludes patterns. +     * +     * @param excludesFile The file to fetch the exclude patterns from. +     */ +    function setExcludesFile($excludesFile) { +        if ($this->isReference()) { +            throw $this->tooManyAttributes(); +        } +        if ($excludesFile instanceof File) { +            $excludesFile = $excludesFile->getPath(); +        }         +        $o = $this->createExcludesFile(); +        $o->setName($excludesFile); +    } + + +    /** +     *  Reads path matching patterns from a file and adds them to the +     *  includes or excludes list +     */ +    private function readPatterns(PhingFile $patternfile, &$patternlist, Project $p) { +        $patternReader = null; +        try { +            // Get a FileReader +            $patternReader = new BufferedReader(new FileReader($patternfile));  +         +            // Create one NameEntry in the appropriate pattern list for each  +            // line in the file. +            $line = $patternReader->readLine(); +            while ($line !== null) { +                if (!empty($line)) { +                    $line = $p->replaceProperties($line); +                    $this->addPatternToList($patternlist)->setName($line); +                } +                $line = $patternReader->readLine(); +            } +             +        } catch (IOException $ioe)  { +            $msg = "An error occured while reading from pattern file: " . $patternfile->__toString();  +            if($patternReader) $patternReader->close();             +            throw new BuildException($msg, $ioe); +        }  +         +        $patternReader->close();                 +    } + + +    /** Adds the patterns of the other instance to this set. */ +    function append($other, $p) { +        if ($this->isReference()) { +            throw new BuildException("Cannot append to a reference"); +        } + +        $incl = $other->getIncludePatterns($p); +        if ($incl !== null) { +            foreach($incl as $incl_name) { +                $o = $this->createInclude(); +                $o->setName($incl_name); +            } +        } + +        $excl = $other->getExcludePatterns($p); +        if ($excl !== null) { +            foreach($excl as $excl_name) { +                $o = $this->createExclude(); +                $o->setName($excl_name); +            } +        } +    } + +    /** Returns the filtered include patterns. */ +    function getIncludePatterns(Project $p) { +        if ($this->isReference()) { +            $o = $this->getRef($p); +            return $o->getIncludePatterns($p); +        } else { +            $this->readFiles($p); +            return $this->makeArray($this->includeList, $p); +        } +    } + +    /** Returns the filtered exclude patterns. */ +    function getExcludePatterns(Project $p) { +        if ($this->isReference()) { +            $o = $this->getRef($p); +            return $o->getExcludePatterns($p); +        } else { +            $this->readFiles($p); +            return $this->makeArray($this->excludeList, $p); +        } +    } + +    /** helper for FileSet. */ +    function hasPatterns() { +        return (boolean) count($this->includesFileList) > 0 || count($this->excludesFileList) > 0 +               || count($this->includeList) > 0 || count($this->excludeList) > 0; +    } + +    /** +     * Performs the check for circular references and returns the +     * referenced PatternSet. +     */ +    function getRef(Project $p) { +        if (!$this->checked) { +            $stk = array(); +            array_push($stk, $this); +            $this->dieOnCircularReference($stk, $p); +        } +        $o = $this->ref->getReferencedObject($p); +        if (!($o instanceof PatternSet)) { +            $msg = $this->ref->getRefId()." doesn't denote a patternset"; +            throw new BuildException($msg); +        } else { +            return $o; +        } +    } + +    /** Convert a array of PatternSetNameEntry elements into an array of Strings. */ +    private function makeArray(&$list, Project $p) { + +        if (count($list) === 0) { +            return null; +        } + +        $tmpNames = array(); +        foreach($list as $ne) { +            $pattern = (string) $ne->evalName($p); +            if ($pattern !== null && strlen($pattern) > 0) { +                array_push($tmpNames, $pattern); +            } +        } +        return $tmpNames; +    } + +    /** Read includesfile or excludesfile if not already done so. */ +    private function readFiles(Project $p) { +        if (!empty($this->includesFileList)) { +            foreach($this->includesFileList as $ne) { +                $fileName = (string) $ne->evalName($p); +                if ($fileName !== null) { +                    $inclFile = $p->resolveFile($fileName); +                    if (!$inclFile->exists()) { +                        throw new BuildException("Includesfile ".$inclFile->getAbsolutePath()." not found."); +                    } +                    $this->readPatterns($inclFile, $this->includeList, $p); +                } +            } +            $this->includesFileList = array(); +        } + +        if (!empty($this->excludesFileList)) { +            foreach($this->excludesFileList as $ne) {                +                $fileName = (string) $ne->evalName($p); +                if ($fileName !== null) { +                    $exclFile = $p->resolveFile($fileName); +                    if (!$exclFile->exists()) { +                        throw new BuildException("Excludesfile ".$exclFile->getAbsolutePath()." not found."); +                        return; +                    } +                    $this->readPatterns($exclFile, $this->excludeList, $p); +                } +            } +            $this->excludesFileList = array(); +        } +    } + + +    function toString() { +         +        // We can't compile includeList into array because, toString() does +        // not know about project: +        // +        // $includes = $this->makeArray($this->includeList, $this->project); +        // $excludes = $this->makeArray($this->excludeList, $this->project); +             +        if (empty($this->includeList)) { +            $includes = "empty"; +        } else { +            $includes = ""; +            foreach($this->includeList as $ne) { +                $includes .= $ne->toString() . ","; +            } +            $includes = rtrim($includes, ","); +        } +         +        if (empty($this->excludeList)) { +            $excludes = "empty"; +        } else { +            $excludes = ""; +            foreach($this->excludeList as $ne) { +                $excludes .= $ne->toString() . ","; +            } +            $excludes = rtrim($excludes, ","); +        } +                +        return "patternSet{ includes: $includes  excludes: $excludes }"; +    } +} + + +/* + * Note, this class here should become a nested class to + * PatternSet (PatternSet:NameEntry) as it is only needed + * internally. + * This is not possible with php 4.x right now so we place + * this class (against good style) in this file. + */ + +class PatternSetNameEntry { + +    private $name       = null; +    private $ifCond     = null; +    private $unlessCond = null; + +    function setName($name) { +        $this->name = (string) $name; +    } + + +    function setIf($cond) { +        $this->ifCond = (string) $cond; +    } + + +    function setUnless($cond) { +        $this->unlessCond = (string) $cond; +    } + + +    function getName() { +        return $this->name; +    } + + +    function evalName($project) { +        return $this->valid($project) ? $this->name : null; +    } + + +    function valid($project) { +        if ($this->ifCond !== null && $project->getProperty($this->ifCond) === null) { +            return false; +        } else if ($this->unlessCond !== null && $project->getProperty($this->unlessCond) !== null) { +            return false; +        } +        return true; +    } + + +    function toString() { +        $buf = $this->name; +        if (($this->ifCond !== null) || ($this->unlessCond !== null)) { +            $buf .= ":"; +            $connector = ""; + +            if ($this->ifCond !== null) { +                $buf .= "if->{$this->ifCond}"; +                $connector = ";"; +            } +            if ($this->unlessCond !== null) { +                $buf .= "$connector unless->{$this->unlessCond}"; +            } +        } +        return $buf; +    } +} diff --git a/buildscripts/phing/classes/phing/types/PhingFilterReader.php b/buildscripts/phing/classes/phing/types/PhingFilterReader.php new file mode 100644 index 00000000..eb45f894 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/PhingFilterReader.php @@ -0,0 +1,136 @@ +<?php +/* + *  $Id: PhingFilterReader.php,v 1.9 2005/10/05 20:23:22 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/types/DataType.php'; +include_once 'phing/types/Parameter.php'; + +/* + * A PhingFilterReader is a wrapper class that encloses the className + * and configuration of a Configurable FilterReader. + * + * @author    Yannick Lecaillez <yl@seasonfive.com> + * @version   $Revision: 1.9 $ + * @see       FilterReader + * @package   phing.types +*/ +class PhingFilterReader extends DataType { + +    private $className; +    private $parameters = array(); +    private $classPath; + +    function setClassName($className) { +        $this->className = $className; +    } + +    function getClassName() { +        return $this->className; +    } + +    /** +     * Set the classpath to load the FilterReader through (attribute). +     * @param Path $classpath +     */ +    function setClasspath(Path $classpath) { +        if ( $this->isReference() ) { +            throw $this->tooManyAttributes(); +        } +        if ( $this->classPath === null ) { +            $this->classPath = $classpath; +        } else { +            $this->classPath->append($classpath); +        } +    } + +    /* +     * Set the classpath to load the FilterReader through (nested element). +    */ +    function createClasspath() { +        if ( $this->isReference() ) { +            throw $this->noChildrenAllowed(); +        }         +        if ( $this->classPath === null ) { +            $this->classPath = new Path($this->project); +        } +        return $this->classPath->createPath(); +    } + +    function getClasspath() { +        return $this->classPath; +    } + +    function setClasspathRef(Reference $r) { +        if ( $this->isReference() ) { +            throw $this->tooManyAttributes(); +        } +        $o = $this->createClasspath(); +        $o->setRefid($r); +    } +	 +	function addParam(Parameter $param) { +		$this->parameters[] = $param; +	} + +    function createParam() { +        $num = array_push($this->parameters, new Parameter()); +        return $this->parameters[$num-1]; +    } +		 +    function getParams() { +        // We return a COPY +        $ret = array(); +        for($i=0,$size=count($this->parameters); $i < $size; $i++) { +            $ret[] = clone $this->parameters[$i]; +        } +        return $ret; +    } + +    /* +     * Makes this instance in effect a reference to another PhingFilterReader  +     * instance. +     * +     * <p>You must not set another attribute or nest elements inside +     * this element if you make it a reference.</p> +     * +     * @param Reference $r the reference to which this instance is associated +     * @exception BuildException if this instance already has been configured. +    */ +    function setRefid(Reference $r) { +        if ( (count($this->parameters) !== 0) || ($this->className !== null) ) { +            throw $this->tooManyAttributes(); +        } +        $o = $r->getReferencedObject($this->getProject()); +        if ( $o instanceof PhingFilterReader ) { +            $this->setClassName($o->getClassName()); +            $this->setClasspath($o->getClassPath()); +            foreach($o->getParams() as $p) { +                $this->addParam($p); +            } +        } else { +            $msg = $r->getRefId()." doesn\'t refer to a PhingFilterReader"; +            throw new BuildException($msg); +        } + +        parent::setRefid($r); +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/Reference.php b/buildscripts/phing/classes/phing/types/Reference.php new file mode 100644 index 00000000..c226917d --- /dev/null +++ b/buildscripts/phing/classes/phing/types/Reference.php @@ -0,0 +1,56 @@ +<?php +/* + * $Id: Reference.php,v 1.4 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** Class to hold a reference to another object in the project. + * @package phing.types + */ +class Reference { + +    protected $refid; + +    function __construct($id = null) { +        if ($id !== null) { +            $this->setRefId($id); +        } +    } + +    function setRefId($id) { +        $this->refid = (string) $id; +    } + +    function getRefId() { +        return $this->refid; +    } + +    /** returns reference to object in references container of project */ +    function getReferencedObject($project) {     +        if ($this->refid === null) { +            throw new BuildException("No reference specified"); +        } +        $refs = $project->getReferences(); +        $o = @$refs[$this->refid]; +        if (!is_object($o)) {        +            throw new BuildException("Reference {$this->refid} not found."); +        } +        return $o; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/types/RegularExpression.php b/buildscripts/phing/classes/phing/types/RegularExpression.php new file mode 100644 index 00000000..67850c23 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/RegularExpression.php @@ -0,0 +1,105 @@ +<?php +/* + *  $Id: RegularExpression.php,v 1.6 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +include_once 'phing/types/DataType.php'; +include_once 'phing/Project.php'; +include_once 'phing/util/regexp/Regexp.php'; + +/* + * A regular expression datatype.  Keeps an instance of the + * compiled expression for speed purposes.  This compiled + * expression is lazily evaluated (it is compiled the first + * time it is needed).  The syntax is the dependent on which + * regular expression type you are using. + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @version   $Revision: 1.6 $ $Date: 2003/12/24 12:38:42 $ + * @access    public + * @see       phing.util.regex.RegexMatcher + * @package   phing.types +*/ +class RegularExpression extends DataType { + +    private $regexp   = null; +    private $ignoreCase = false; +     +    function __construct() { +        $this->regexp  = new Regexp(); +    } + +    function setPattern($pattern) { +        $this->regexp->setPattern($pattern); +    } + +    function setReplace($replace) { +        $this->regexp->setReplace($replace); +    } +     +    function getPattern($p) { +        if ( $this->isReference() ) { +            $ref = $this->getRef($p); +            return $ref->getPattern($p); +        } +        return $this->regexp->getPattern(); +    } + +    function getReplace($p) { +        if ( $this->isReference() ) { +            $ref = $this->getRef($p); +            return $ref->getReplace($p); +        } + +        return $this->regexp->getReplace(); +    } +     +    function setIgnoreCase($bit) { +        $this->regexp->setIgnoreCase($bit); +    } +     +    function getIgnoreCase() { +        return $this->regexp->getIgnoreCase(); +    } +     +    function getRegexp(Project $p) { +        if ( $this->isReference() ) { +            $ref = $this->getRef($p); +            return $ref->getRegexp($p); +        } +        return $this->regexp; +    } + +    function getRef(Project $p) { +        if ( !$this->checked ) { +            $stk = array(); +            array_push($stk, $this); +            $this->dieOnCircularReference($stk, $p);             +        } + +        $o = $this->ref->getReferencedObject($p); +        if ( !($o instanceof RegularExpression) ) { +            throw new BuildException($this->ref->getRefId()." doesn't denote a RegularExpression"); +        } else { +            return $o; +        } +    } +} + +?> diff --git a/buildscripts/phing/classes/phing/types/TokenReader.php b/buildscripts/phing/classes/phing/types/TokenReader.php new file mode 100644 index 00000000..acd7d616 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/TokenReader.php @@ -0,0 +1,66 @@ +<?php +/* + *  $Id: TokenReader.php,v 1.5 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +// include_once 'phing/system/io/Reader.php'; // really this is unrelated to Reader +include_once 'phing/system/io/IOException.php'; +include_once 'phing/filters/ReplaceTokens.php'; // For class Token + +/** + * Abstract class for TokenReaders. + *  + * @author    Manuel Holtgewe + * @version   $Revision: 1.5 $ + * @package   phing.filters.util + */ +abstract class TokenReader { + +    /** +     * Reference to the Project the TokenReader is used in. +     * @var Project  +     */ +    protected $project; + +    /** +     * Constructor +     * @param   object  Reference to the project the TokenReader is used in. +     */ +    function __construct(Project $project) { +        $this->project = $project; +    } + +    /** +     * Utility function for logging +     */ +    function log($level, $msg) { +        $this->project->log($level, $msg); +    } + +    /** +     * Reads the next token from the Reader +     * +     * @throws IOException - On error +     * @return string +     */ +    abstract public function readToken(); +     +} + +?> diff --git a/buildscripts/phing/classes/phing/types/TokenSource.php b/buildscripts/phing/classes/phing/types/TokenSource.php new file mode 100644 index 00000000..c073ece0 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/TokenSource.php @@ -0,0 +1,157 @@ +<?php +/* + *  $Id: TokenSource.php,v 1.7 2004/03/18 20:44:26 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. +*/ + +require_once 'phing/types/DataType.php'; +include_once 'phing/util/StringHelper.php'; + +/** + * A parameter is composed of a name, type and value. + * + * Example of usage: + * + * <replacetokens> + *   <tokensource classname="phing.filters.util.IniFileTokenReader"> + *     <!-- all params for the TokenReader here --> + *     <param name="file" value="tokens.ini" /> + *   </tokensource> + * </replacetokens> + * + * or: + *  + * <filterreader classname="phing.filters.ReplaceTokens"> + *   <param type="tokensource> + *     <param name="classname" value="phing.filters.util.IniFileTokenReader" /> + *     <param name="file" value="tokens.ini" /> + *   </param> + * </filterreader> + * + * @author    <a href="mailto:yl@seasonfive.com">Yannick Lecaillez</a> + * @package   phing.types + */ +class TokenSource extends DataType { + +    /** +     * String to hold the path to the TokenReader +     * @var     string +     */ +    protected $classname = null; + +    /** +     * Array holding parameters for the wrapped TokenReader. +     * @var array +     */ +    protected $parameters = array(); + +    /** +     * Reference to the TokenReader used by this TokenSource +     * @var TokenReader +     */ +    protected $reader; + +    /** +     * Array with key/value pairs of tokens +     */ +    protected $tokens = array(); + +    /** +     * This method is called to load the sources from the reader +     * into the buffer of the source. +     */ +    function load() { +        // Create new Reader +        if ($this->classname === null) { +            throw new BuildException("No Classname given to TokenSource."); +        } +         +        $classname = Phing::import($this->classname);         +        $this->reader = new $classname($this->project); + +        // Configure Reader +        $this->configureTokenReader($this->reader); + +        // Load Tokens +        try { +            while ($token = $this->reader->readToken()) { +                $this->tokens[] = $token; +            } +        } catch (BuildException $e) { +            $this->log("Error reading TokenSource: " . $e->getMessage(), PROJECT_MSG_WARN); +        } catch (IOException $e) { +            $this->log("Error reading TokenSource: " . $e->getMessage(), PROJECT_MSG_WARN); +        } +    } + +    /** +     * This function uses the wrapper to read the tokens and then +     * returns them. +     * +     * @access  public +     */ +    function getTokens() { +        if ($this->tokens === null) +            $this->Load(); + +        return $this->tokens; +    } + +    /** +     * Configures a TokenReader with the parameters passed to the +     * TokenSource. +     * @param TokenReader $reader +     */ +    private function configureTokenReader(TokenReader $reader) { +        $count = count($this->parameters); +        for ($i = 0; $i < $count; $i++) { +            $method_name = "Set" . $this->parameters[$i]->getName(); +            $value = $this->parameters[$i]->getValue(); +            $reader->$method_name($value); +        } +    } +     +    /** +     * Set the classname (dot-path) to use for handling token replacement. +     * @param string $c +     */ +    function setClassname($c) { +        $this->classname = $c; +    } +     +    /** +     * Returns the qualified classname (dot-path) to use for handling token replacement. +     * @return string +     */ +    function getClassname() { +        return $this->classname; +    } + +    /** +     * Create nested <param> tag. +     * Uses standard name/value Parameter class. +     * @return Parameter +     */ +    function createParam() { +        $num = array_push($this->parameters, new Parameter()); +        return $this->parameters[$num-1]; +    } +} + + +?> diff --git a/buildscripts/phing/classes/phing/types/defaults.properties b/buildscripts/phing/classes/phing/types/defaults.properties new file mode 100644 index 00000000..a2d86350 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/defaults.properties @@ -0,0 +1,13 @@ +# phing default types +commandline=phing.types.Commandline +fileset=phing.types.FileSet +dirset=phing.types.DirSet +filelist=phing.types.FileList +patternset=phing.types.PatternSet +mapper=phing.types.Mapper +filterchain=phing.types.FilterChain +filterreader=phing.types.PhingFilterReader +regexp=phing.types.RegularExpression +param=phing.types.Parameter +path=phing.types.Path +selector=phing.types.selectors.SelectSelector
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/types/selectors/AndSelector.php b/buildscripts/phing/classes/phing/types/selectors/AndSelector.php new file mode 100644 index 00000000..3801091f --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/AndSelector.php @@ -0,0 +1,67 @@ +<?php +/* + * $Id: AndSelector.php,v 1.9 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseSelectorContainer.php'; + +/** + * This selector has a collection of other selectors, all of which have to + * select a file in order for this selector to select it. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> (Ant) + * @package phing.types.selectors + */ +class AndSelector extends BaseSelectorContainer { + +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{andselect: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    /** +     * Returns true (the file is selected) only if all other selectors +     * agree that the file should be selected. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename the name of the file to check +     * @param file a PhingFile object for the filename that the selector +     * can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +        $this->validate(); +        $selectors = $this->selectorElements();        +           for($i=0,$size=count($selectors); $i < $size; $i++) { +            $result = $selectors[$i]->isSelected($basedir, $filename, $file); +            if (!$result) { +                return false; +            } +        } +        return true; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php b/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php new file mode 100644 index 00000000..5acc54dd --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php @@ -0,0 +1,62 @@ +<?php + +/* + * $Id: BaseExtendSelector.php,v 1.5 2004/02/16 05:28:40 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/types/selectors/ExtendFileSelector.php'; +require_once 'phing/types/selectors/BaseSelector.php'; +include_once 'phing/types/Parameter.php'; + +/** + * Convenience base class for all selectors accessed through ExtendSelector. + * It provides support for gathering the parameters together as well as for + * assigning an error message and throwing a build exception if an error is + * detected. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +abstract class BaseExtendSelector extends BaseSelector implements ExtendFileSelector { + +    /** The passed in parameter array. */ +    protected $parameters = null; + +    /** +     * Set all the Parameters for this custom selector, collected by +     * the ExtendSelector class. +     * +     * @param parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        $this->parameters = $parameters; +    } + +    /** +     * Allows access to the parameters gathered and set within the +     * <custom> tag. +     * +     * @return the set of parameters defined for this selector +     */ +    protected function getParameters() { +        return $this->parameters; +    } +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php b/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php new file mode 100644 index 00000000..e229fc24 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php @@ -0,0 +1,84 @@ +<?php +/* + * $Id: BaseSelector.php,v 1.4 2004/02/16 04:56:24 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/FileSelector.php'; + +/** + * A convenience base class that you can subclass Selectors from. It + * provides some helpful common behaviour. Note that there is no need + * for Selectors to inherit from this class, it is only necessary that + * they implement FileSelector. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @package phing.types.selectors + */ +abstract class BaseSelector extends DataType implements FileSelector { + +    private $errmsg = null; + +    /** +     * Allows all selectors to indicate a setup error. Note that only +     * the first error message is recorded. +     * +     * @param msg The error message any BuildException should throw. +     */ +    public function setError($msg) { +        if ($this->errmsg === null) { +            $this->errmsg = $msg; +        } +    } + +    /** +     * Returns any error messages that have been set. +     * +     * @return the error condition +     */ +    public function getError() { +        return $this->errmsg; +    } + + +    /** +     * <p>Subclasses can override this method to provide checking of their +     * state. So long as they call validate() from isSelected(), this will +     * be called automatically (unless they override validate()).</p> +     * <p>Implementations should check for incorrect settings and call +     * setError() as necessary.</p> +     */ +    public function verifySettings() { +    } + +    /** +     * Subclasses can use this to throw the requisite exception +     * in isSelected() in the case of an error condition. +     */ +    public function validate() { +        if ($this->getError() === null) { +            $this->verifySettings(); +        } +        if ($this->getError() !== null) { +            throw new BuildException($this->errmsg); +        } +    }    + +} + + diff --git a/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php b/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php new file mode 100644 index 00000000..19b84b00 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php @@ -0,0 +1,270 @@ +<?php + +/* + * $Id: BaseSelectorContainer.php,v 1.9 2004/02/16 04:56:24 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/SelectorContainer.php'; +require_once 'phing/types/selectors/BaseSelector.php'; + +/** + * This is the base class for selectors that can contain other selectors. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> (Ant) + * @package phing.types.selectors + */ +abstract class BaseSelectorContainer extends BaseSelector implements SelectorContainer { + +    private $selectorsList = array(); + +    /** +     * Indicates whether there are any selectors here. +     */ +    public function hasSelectors() { +        return !(empty($this->selectorsList)); +    } + +    /** +     * Gives the count of the number of selectors in this container +     */ +    public function selectorCount() { +        return count($this->selectorsList); +    } + +    /** +     * Returns a copy of the selectors as an array. +     */ +    public function getSelectors(Project $p) { +        $result = array(); +        for($i=0,$size=count($this->selectorsList); $i < $size; $i++) { +            $result[] = clone $this->selectorsList[$i]; +        } +        return $result; +    } + +    /** +     * Returns an array for accessing the set of selectors (not a copy). +     */ +    public function selectorElements() { +        return $this->selectorsList; +    } + +    /** +     * Convert the Selectors within this container to a string. This will +     * just be a helper class for the subclasses that put their own name +     * around the contents listed here. +     * +     * @return comma separated list of Selectors contained in this one +     */ +    public function toString() { +        $buf = ""; +        $arr = $this->selectorElements(); +        for($i=0,$size=count($arr); $i < $size; $i++) { +            $buf .= $arr[$i]->toString() . (isset($arr[$i+1]) ? ', ' : ''); +        } +        return $buf; +    } + +    /** +     * Add a new selector into this container. +     * +     * @param selector the new selector to add +     * @return the selector that was added +     */ +    public function appendSelector(FileSelector $selector) { +        $this->selectorsList[] = $selector; +    } + +    /** +     * <p>This implementation validates the container by calling +     * verifySettings() and then validates each contained selector +     * provided that the selector implements the validate interface. +     * </p> +     * <p>Ordinarily, this will validate all the elements of a selector +     * container even if the isSelected() method of some elements is +     * never called. This has two effects:</p> +     * <ul> +     * <li>Validation will often occur twice. +     * <li>Since it is not required that selectors derive from +     * BaseSelector, there could be selectors in the container whose +     * error conditions are not detected if their isSelected() call +     * is never made. +     * </ul> +     */ +    public function validate() { +        $this->verifySettings(); +        $errmsg = $this->getError(); +        if ($errmsg !== null) { +            throw new BuildException($errmsg); +        } +        foreach($this->selectorsList as $o) { +            if ($o instanceof BaseSelector) { +                $o->validate(); +            } +        }     +    } + +    /* Methods below all add specific selectors */ + +    /** +     * add a "Select" selector entry on the selector list +     */ +    public function createSelector() { +        $o = new SelectSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an "And" selector entry on the selector list +     */ +    public function createAnd() { +        $o = new AndSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an "Or" selector entry on the selector list +     */ +    public function createOr() { +        $o = new OrSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a "Not" selector entry on the selector list +     */ +    public function createNot() { +        $o = new NotSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a "None" selector entry on the selector list +     */ +    public function createNone() { +        $o = new NoneSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a majority selector entry on the selector list +     */ +    public function createMajority() { +        $o = new MajoritySelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector date entry on the selector list +     */ +    public function createDate() { +        $o = new DateSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector size entry on the selector list +     */ +    public function createSize() { +        $o = new SizeSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a selector filename entry on the selector list +     */ +    public function createFilename() { +        $o = new FilenameSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add an extended selector entry on the selector list +     */ +    public function createCustom() { +        $o = new ExtendSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a contains selector entry on the selector list +     */ +    public function createContains() { +        $o = new ContainsSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a contains selector entry on the selector list +     */ +    public function createContainsRegexp() { +        $o = new ContainsRegexpSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a present selector entry on the selector list +     */ +    public function createPresent() { +        $o = new PresentSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a depth selector entry on the selector list +     */ +    public function createDepth() { +        $o = new DepthSelector(); +        $this->appendSelector($o); +        return $o; +    } + +    /** +     * add a depends selector entry on the selector list +     */ +    public function createDepend() { +        $o = new DependSelector(); +        $this->appendSelector($o); +        return $o; +    } +     +    /** +     * add a type selector entry on the selector list +     */ +    public function createType() { +        $o = new TypeSelector(); +        $this->appendSelector($o); +        return $o; +    } +     +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php b/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php new file mode 100644 index 00000000..39afd2fa --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php @@ -0,0 +1,164 @@ +<?php + +/* + * $Id: ContainsRegexpSelector.php,v 1.3 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; +include_once 'phing/types/RegularExpression.php'; + +/** + * Selector that filters files based on whether they contain a + * particular string using regexp. + *  + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.3 $ + * @package   phing.types.selectors + */ +class ContainsRegexpSelector extends BaseExtendSelector { + +    /** @var string The expression set from XML. */ +    private $userProvidedExpression; +     +    /** @var Regexp */ +    private $myExpression; +      +    private $casesensitive = true; +     +    /** @var RegularExpression */ +    private $myRegExp; +     +    const EXPRESSION_KEY = "expression"; +     +    const CASE_KEY = "casesensitive"; +     +    public function toString() { +        $buf = "{containsregexpselector expression: "; +        $buf .= $this->userProvidedExpression; +        $buf .= " casesensitive: "; +        if ($this->casesensitive) { +            $buf .= "true"; +        } else { +            $buf .= "false"; +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The expression to match on within a file. +     * +     * @param string $exp the string that a file must contain to be selected. +     */ +    public function setExpression($exp) { +        $this->userProvidedExpression = $exp; +    } + +    /** +     * Whether to ignore case in the regex match. +     * +     * @param boolean $casesensitive whether to pay attention to case sensitivity +     */ +    public function setCasesensitive($casesensitive) { +        $this->casesensitive = $casesensitive; +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param array $parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i=0,$size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::EXPRESSION_KEY: +                        $this->setExpression($parameters[$i]->getValue()); +                        break; +                    case self::CASE_KEY: +                        $this->setCasesensitive($parameters[$i]->getValue()); +                        break; +                    default: +                        $this->setError("Invalid parameter " . $paramname); +                }                 +            } // for each param +        } // if params +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the pattern attribute has been set. +     * +     */ +    public function verifySettings() { +        if ($this->userProvidedExpression === null) { +            $this->setError("The expression attribute is required"); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); + +        if ($file->isDirectory()) { +            return true; +        } +         +        if ($this->myRegExp === null) { +            $this->myRegExp = new RegularExpression(); +            $this->myRegExp->setPattern($this->userProvidedExpression);             +            if (!$this->casesensitive) { +                $this->myRegExp->setIgnoreCase(true); +            } +            $this->myExpression = $this->myRegExp->getRegexp($this->getProject()); +        } +                         +        $in = null; +        try { +            $in = new BufferedReader(new FileReader($file));         +            $teststr = $in->readLine(); +            while ($teststr !== null) { +                if ($this->myExpression->matches($teststr)) { +                    return true; +                } +                $teststr = $in->readLine(); +            } +            return false; +        } catch (IOException $ioe) { +            if ($in) $in->close(); +            throw new BuildException("Could not read file " . $filename); +        } +        $in->close();                 +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php b/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php new file mode 100644 index 00000000..d00ce995 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php @@ -0,0 +1,151 @@ +<?php + +/* + * $Id: ContainsSelector.php,v 1.9 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on whether they contain a + * particular string. + *  + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class ContainsSelector extends BaseExtendSelector { + +    private $contains = null; +    private $casesensitive = true; +    const CONTAINS_KEY = "text"; +    const CASE_KEY = "casesensitive"; + +    public function toString() { +        $buf = "{containsselector text: "; +        $buf .= $this->contains; +        $buf .= " casesensitive: "; +        if ($this->casesensitive) { +            $buf .= "true"; +        } else { +            $buf .= "false"; +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The string to search for within a file. +     * +     * @param string $contains the string that a file must contain to be selected. +     */ +    public function setText($contains) { +        $this->contains = $contains; +    } + +    /** +     * Whether to ignore case in the string being searched. +     * +     * @param boolean $casesensitive whether to pay attention to case sensitivity +     */ +    public function setCasesensitive($casesensitive) { +        $this->casesensitive = $casesensitive; +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param array $parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i=0,$size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::CONTAINS_KEY: +                        $this->setText($parameters[$i]->getValue()); +                        break; +                    case self::CASE_KEY: +                        $this->setCasesensitive($parameters[$i]->getValue()); +                        break; +                    default: +                        $this->setError("Invalid parameter " . $paramname); +                }                 +            } // for each param +        } // if params +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the pattern attribute has been set. +     * +     */ +    public function verifySettings() { +        if ($this->contains === null) { +            $this->setError("The text attribute is required"); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); + +        if ($file->isDirectory()) { +            return true; +        } + +        $userstr = $this->contains; +        if (!$this->casesensitive) { +            $userstr = strtolower($this->contains); +        } +         +        $in = null; +        try { +            $in = new BufferedReader(new FileReader($file));         +            $teststr = $in->readLine(); +            while ($teststr !== null) { +                if (!$this->casesensitive) { +                    $teststr = strtolower($teststr); +                } +                if (strpos($teststr, $userstr) !== false) { +                    return true; +                } +                $teststr = $in->readLine(); +            } +            return false; +        } catch (IOException $ioe) { +            if ($in) $in->close(); +            throw new BuildException("Could not read file " . $filename); +        } +        $in->close();                 +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/DateSelector.php b/buildscripts/phing/classes/phing/types/selectors/DateSelector.php new file mode 100644 index 00000000..96e5c3ba --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DateSelector.php @@ -0,0 +1,214 @@ +<?php + +/* + * $Id: DateSelector.php,v 1.10 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that chooses files based on their last modified date. Ant uses + * millisecond precision (thanks to Java); PHP is forced to use only seconds + * precision. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.10 $ + * @package   phing.types.selecctors + */ +class DateSelector extends BaseExtendSelector { + +    private $seconds = -1; // millis in Ant, but PHP doesn't support that level of precision +    private $dateTime = null; +    private $includeDirs = false; +    private $granularity = 0; +    private $cmp = 2; +    const MILLIS_KEY = "millis"; +    const DATETIME_KEY = "datetime"; +    const CHECKDIRS_KEY = "checkdirs"; +    const GRANULARITY_KEY = "granularity"; +    const WHEN_KEY = "when"; +    private static $timeComparisons = array("before", "after", "equal"); +     +    public function __construct() { +        //if (Os.isFamily("dos")) { +        //    granularity = 2000; +        //} +    } + +    public function toString() { +        $buf = "{dateselector date: "; +        $buf .= $this->dateTime; +        $buf .= " compare: "; +        if ($this->cmp === 0) { +            $buf .= "before"; +        } elseif ($this->cmp === 1) { +            $buf .= "after"; +        } else { +            $buf .= "equal"; +        } +        $buf .= " granularity: "; +        $buf .= $this->granularity; +        $buf .= "}"; +        return $buf; +    } + +    /** +     * For users that prefer to express time in seconds since 1970 +     * +     * @param int $seconds the time to compare file's last modified date to, +     *        expressed in milliseconds +     */ +    public function setSeconds($seconds) { +        $this->seconds = (int) $seconds; +    } + +    /** +     * Returns the seconds value the selector is set for. +     */ +    public function getSeconds() { +        return $this->seconds; +    } + +    /** +     * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM +     * format +     * +     * @param string $dateTime a string in MM/DD/YYYY HH:MM AM_PM format +     */ +    public function setDatetime($dateTime) {         +        $dt = strtotime($dateTime); +        if ($dt == -1) { +            $this->setError("Date of " . $dateTime +                        . " Cannot be parsed correctly. It should be in" +                        . " a format parsable by PHP's strtotime() function."); +        } else {         +            $this->dateTime = $dateTime; +            $this->setSeconds($dt); +        } +    } + +    /** +     * Should we be checking dates on directories? +     * +     * @param boolean $includeDirs whether to check the timestamp on directories +     */ +    public function setCheckdirs($includeDirs) { +        $this->includeDirs = (boolean) $includeDirs; +    } + +    /** +     * Sets the number of milliseconds leeway we will give before we consider +     * a file not to have matched a date. +     * @param int $granularity +     */ +    public function setGranularity($granularity) { +        $this->granularity = (int) $granularity; +    } + +    /** +     * Sets the type of comparison to be done on the file's last modified +     * date. +     * +     * @param string $cmp The comparison to perform +     */ +    public function setWhen($cmp) { +        $idx = array_search($cmp, self::$timeComparisons, true); +        if ($idx === null) { +            $this->setError("Invalid value for ".WHEN_KEY.": ".$cmp); +        } else { +            $this->cmp = $idx; +        } +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param array $parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i=0,$size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::MILLIS_KEY: +                        $this->setMillis($parameters[$i]->getValue()); +                        break; +                    case self::DATETIME_KEY: +                        $this->setDatetime($parameters[$i]->getValue()); +                        break; +                    case self::CHECKDIRS_KEY: +                        $this->setCheckdirs($parameters[$i]->getValue()); +                        break;                     +                    case self::GRANULARITY_KEY: +                        $this->setGranularity($parameters[$i]->getValue()); +                        break; +                    case self::WHEN_KEY: +                        $this->setWhen($parameters[$i]->getValue()); +                        break; +                    default: +                        $this->setError("Invalid parameter " . $paramname); +                } // switch +            } +        } +    } + +    /** +     * This is a consistency check to ensure the selector's required +     * values have been set. +     */ +    public function verifySettings() { +        if ($this->dateTime === null && $this->seconds < 0) { +            $this->setError("You must provide a datetime or the number of " +                . "seconds."); +        } elseif ($this->seconds < 0) { +            $this->setError("Date of " . $this->dateTime +                . " results in negative seconds" +                . " value relative to epoch (January 1, 1970, 00:00:00 GMT)."); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param PhingFile $basedir the base directory the scan is being done from +     * @param string $filename is the name of the file to check +     * @param PhingFile $file is a PhingFile object the selector can use +     * @return boolean Whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +        $this->validate(); +        if ($file->isDirectory() && ($this->includeDirs === false)) { +            return true; +        } +        if ($this->cmp === 0) { +            return (($file->lastModified() - $this->granularity) < $this->seconds); +        } elseif ($this->cmp === 1) { +            return (($file->lastModified() . $this->granularity) > $this->seconds); +        } else { +            return (abs($file->lastModified() -  $this->seconds) <= $this->granularity); +        } +    } + +} + + diff --git a/buildscripts/phing/classes/phing/types/selectors/DependSelector.php b/buildscripts/phing/classes/phing/types/selectors/DependSelector.php new file mode 100644 index 00000000..db73c512 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DependSelector.php @@ -0,0 +1,151 @@ +<?php + +/* + * $Id: DependSelector.php,v 1.8 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseSelector.php'; +  +/** + * Selector that filters files based on whether they are newer than + * a matching file in another directory tree. It can contain a mapper + * element, so isn't available as an ExtendSelector (since those + * parameters can't hold other elements). + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.8 $ + * @package   phing.types.selectors + */ +class DependSelector extends BaseSelector { + +    private $targetdir = null; +    private $mapperElement = null; +    private $map = null; +    private $granularity = 0; + +    public function __construct() { +        // not yet supported: +        //if (Os.isFamily("dos")) { +        //    $this->granularity = 2000; +        //} +    } + +    public function toString() { +        $buf = "{dependselector targetdir: "; +        if ($this->targetdir === null) { +            $buf .= "NOT YET SET"; +        } else { +            $buf .= $this->targetdir->getName(); +        }         +        $buf .= " granularity: "; +        $buf .= $this->granularity; +        if ($this->map !== null) { +            $buf .= " mapper: "; +            $buf .= $this->map->toString(); +        } elseif ($this->mapperElement !== null) { +            $buf .= " mapper: "; +            $buf .= $this->mapperElement->toString(); +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The name of the file or directory which is checked for out-of-date +     * files. +     * +     * @param targetdir the directory to scan looking for files. +     */ +    public function setTargetdir(PhingFile $targetdir) { +        $this->targetdir = $targetdir; +    } + +    /** +     * Sets the number of milliseconds leeway we will give before we consider +     * a file out of date. +     */ +    public function setGranularity($granularity) { +        $this->granularity = (int) granularity; +    } + +    /** +     * Defines the FileNameMapper to use (nested mapper element). +     * @throws BuildException +     */ +    public function createMapper() { +        if ($this->mapperElement !== null) { +            throw new BuildException("Cannot define more than one mapper"); +        } +        $this->mapperElement = new Mapper($this->project); +        return $this->mapperElement; +    } + + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the dest attribute has been set and we have a mapper. +     */ +    public function verifySettings() { +        if ($this->targetdir === null) { +            $this->setError("The targetdir attribute is required."); +        } +        if ($this->mapperElement === null) { +            $this->map = new IdentityMapper(); +        } else { +            $this->map = $this->mapperElement->getImplementation(); +        } +        if ($this->map === null) { +            $this->setError("Could not set <mapper> element."); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); +         +        // Determine file whose out-of-dateness is to be checked +        $destfiles = $this->map->main($filename); +         +        // If filename does not match the To attribute of the mapper +        // then filter it out of the files we are considering +        if ($destfiles === null) { +            return false; +        } +        // Sanity check +        if (count($destfiles) !== 1 || $destfiles[0] === null) { +            throw new BuildException("Invalid destination file results for " . $this->targetdir . " with filename " . $filename); +        } +        $destname = $destfiles[0]; +        $destfile = new PhingFile($this->targetdir, $destname); + +        return SelectorUtils::isOutOfDate($file, $destfile, $this->granularity); +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php b/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php new file mode 100644 index 00000000..3faafe96 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php @@ -0,0 +1,158 @@ +<?php +/* + * $Id: DepthSelector.php,v 1.7 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on the how deep in the directory + * tree they are. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.7 $ + * @package   phing.types.selectors + */ +class DepthSelector extends BaseExtendSelector { + +    public $min = -1; +    public $max = -1; +    const MIN_KEY = "min"; +    const MAX_KEY = "max"; + +    public function toString() { +        $buf = "{depthselector min: "; +        $buf .= $this->min; +        $buf .= " max: "; +        $buf .= $this->max; +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The minimum depth below the basedir before a file is selected. +     * +     * @param min minimum directory levels below basedir to go +     */ +    public function setMin($min) { +        $this->min = (int) $min; +    } + +    /** +     * The minimum depth below the basedir before a file is selected. +     * +     * @param min maximum directory levels below basedir to go +     */ +    public function setMax($max) { +        $this->max = (int) $max; +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i = 0, $size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::MIN_KEY: +                        $this->setMin($parameters[$i]->getValue()); +                        break; +                    case self::MAX_KEY: +                        $this->setMax($parameters[$i]->getValue()); +                        break; +                         +                    default: +                        $this->setError("Invalud parameter " . $paramname); +                } // switch                 +            } +        } +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the max depth is not lower than the min depth. +     */ +    public function verifySettings() { +        if ($this->min < 0 && $this->max < 0) { +            $this->setError("You must set at least one of the min or the " . +                    "max levels."); +        } +        if ($this->max < $this->min && $this->max > -1) { +            $this->setError("The maximum depth is lower than the minimum."); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. Most of the work +     * for this selector is offloaded into SelectorUtils, a static class +     * that provides the same services for both FilenameSelector and +     * DirectoryScanner. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); + +        $depth = -1; +        // If you felt daring, you could cache the basedir absolute path +        $abs_base = $basedir->getAbsolutePath(); +        $abs_file = $file->getAbsolutePath(); +         +        $tok_base = explode(DIRECTORY_SEPARATOR, $abs_base); +        $tok_file = explode(DIRECTORY_SEPARATOR, $abs_file); +         +        for($i=0,$size=count($tok_file); $i < $size; $i++) { +            $filetoken = $tok_file[$i]; +            if (isset($tok_base[$i])) { +                $basetoken = $tok_base[$i]; +                // Sanity check. Ditch it if you want faster performance +                if ($basetoken !== $filetoken) { +                    throw new BuildException("File " . $filename . +                        " does not appear within " . $abs_base . "directory"); +                } +            } else { // no more basepath tokens +                $depth++; +                if ($this->max > -1 && $depth > $this->max) { +                    return false; +                } +            } +        } +        if (isset($tok_base[$i + 1])) { +            throw new BuildException("File " . $filename . +                " is outside of " . $abs_base . "directory tree"); +        } +        if ($this->min > -1 && $depth < $this->min) { +            return false; +        } +        return true; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php b/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php new file mode 100644 index 00000000..84a3ee5b --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php @@ -0,0 +1,43 @@ +<?php + +/* + * $Id: ExtendFileSelector.php,v 1.5 2004/02/16 05:28:40 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/Parameterizable.php'; +require_once 'phing/types/selectors/FileSelector.php'; + +/** + * This is the interface to be used by all custom selectors, those that are + * called through the <custom> tag. It is the amalgamation of two + * interfaces, the FileSelector and the Paramterizable interface. Note that + * you will almost certainly want the default behaviour for handling + * Parameters, so you probably want to use the BaseExtendSelector class + * as the base class for your custom selector rather than implementing + * this interface from scratch. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +interface ExtendFileSelector extends Parameterizable, FileSelector { +  // No further methods necessary. This is just an amalgamation of two other +  // interfaces. +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php b/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php new file mode 100644 index 00000000..cc939254 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php @@ -0,0 +1,127 @@ +<?php + +/* + * $Id: ExtendSelector.php,v 1.10 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/util/StringHelper.php'; + +/** + * Selector that selects files by forwarding the request on to other classes. + * + * TODO: + *        Consider adding Path (org.apache.tools.ant.types.Path) support to this class + *         and to the Mappers class.  See Ant versions for implimentation details. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @package phing.types.selectors + */ +class ExtendSelector extends BaseSelector { + +    private $classname; +    private $dynselector; +    private $parameters = array(); + +    /** +     * Sets the classname of the custom selector. +     * +     * @param classname is the class which implements this selector +     */ +    public function setClassname($classname) { +        $this->classname = $classname; +    } + +    /** +     * Instantiates the identified custom selector class. +     */ +    public function selectorCreate() { +        if ($this->classname !== null && $this->classname !== "") {       +            try { +                // assume it's fully qualified, import it +                $cls = Phing::import($this->classname); +        +                // make sure class exists +                if (class_exists($cls)) { +                    $this->dynselector = new $cls(); +                } else { +                    $this->setError("Selector " . $this->classname . " not initialized, no such class"); +                }             +            } catch (Exception $e) { +                $this->setError("Selector " . $this->classname . " not initialized, could not create class: " . $e->getMessage()); +            }             +        } else { +            $this->setError("There is no classname specified"); +        } +    } + +    /** +     * Create new parameters to pass to custom selector. +     * +     * @param p The new Parameter object +     */ +    public function addParam(Parameter $p) { +        $this->parameters[] = $p; +    } + +    /** +     * These are errors specific to ExtendSelector only. If there are +     * errors in the custom selector, it should throw a BuildException +     * when isSelected() is called. +     */ +    public function verifySettings() { +        // Creation is done here rather than in isSelected() because some +        // containers may do a validation pass before running isSelected(), +        // but we need to check for the existence of the created class. +        if ($this->dynselector === null) { +            $this->selectorCreate(); +        } +         +        if (empty($this->classname)) { +            $this->setError("The classname attribute is required"); +        } elseif ($this->dynselector === null) { +            $this->setError("Internal Error: The custom selector was not created"); +        } elseif ( !($this->dynselector instanceof ExtendFileSelector) && (count($this->parameters) > 0)) { +            $this->setError("Cannot set parameters on custom selector that does not " +                   . "implement ExtendFileSelector."); +        } +    } + + +    /** +     * Allows the custom selector to choose whether to select a file. This +     * is also where the Parameters are passed to the custom selector, +     * since we know we must have them all by now. And since we must know +     * both classpath and classname, creating the class is deferred to here +     * as well. +     * +     * @throws BuildException +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +         +        $this->validate(); +         +        if (count($this->parameters) > 0 && $this->dynselector instanceof ExtendFileSelector) {             +            // We know that dynselector must be non-null if no error message +            $this->dynselector->setParameters($this->parameters); +        } +        return $this->dynselector->isSelected($basedir, $filename, $file); +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/FileSelector.php b/buildscripts/phing/classes/phing/types/selectors/FileSelector.php new file mode 100644 index 00000000..05926c86 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/FileSelector.php @@ -0,0 +1,47 @@ +<?php + +/* + * $Id: FileSelector.php,v 1.4 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * This is the interface to be used by all selectors. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +interface FileSelector { + +    /** +     * Method that each selector will implement to create their +     * selection behaviour. If there is a problem with the setup +     * of a selector, it can throw a BuildException to indicate +     * the problem. +     * +     * @param basedir A PhingFile object for the base directory +     * @param filename The name of the file to check +     * @param file A PhingFile object for this filename +     * @return whether the file should be selected or not +     * @throws BuildException if the selector was not configured correctly +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file); + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php b/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php new file mode 100644 index 00000000..2315c888 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php @@ -0,0 +1,157 @@ +<?php + +/* + * $Id: FilenameSelector.php,v 1.8 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +include_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that filters files based on the filename. + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +class FilenameSelector extends BaseExtendSelector { + +    private $pattern = null; +    private $casesensitive = true; +    private $negated = false; +    const NAME_KEY = "name"; +    const CASE_KEY = "casesensitive"; +    const NEGATE_KEY = "negate"; + +    public function toString() { +        $buf = "{filenameselector name: "; +        $buf .= $this->pattern; +        $buf .= " negate: "; +        if ($this->negated) { +            $buf .= "true"; +        } else { +            $buf .= "false"; +        } +        $buf .= " casesensitive: "; +        if ($this->casesensitive) { +            $buf .= "true"; +        } else { +            $buf .= "false"; +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The name of the file, or the pattern for the name, that +     * should be used for selection. +     * +     * @param pattern the file pattern that any filename must match +     *                against in order to be selected. +     */ +    public function setName($pattern) { +        $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $pattern); +        $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); +                 +        if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { +            $pattern .= "**"; +        } +        $this->pattern = $pattern; +    } + +    /** +     * Whether to ignore case when checking filenames. +     * +     * @param casesensitive whether to pay attention to case sensitivity +     */ +    public function setCasesensitive($casesensitive) { +        $this->casesensitive = $casesensitive; +    } + +    /** +     * You can optionally reverse the selection of this selector, +     * thereby emulating an <exclude> tag, by setting the attribute +     * negate to true. This is identical to surrounding the selector +     * with <not></not>. +     * +     * @param negated whether to negate this selection +     */ +    public function setNegate($negated) { +        $this->negated = $negated; +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param array $parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i=0, $len=count($parameters); $i < $len; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::NAME_KEY: +                        $this->setName($parameters[$i]->getValue()); +                        break; +                    case self::CASE_KEY: +                        $this->setCasesensitive($parameters[$i]->getValue()); +                        break; +                    case self::NEGATE_KEY: +                        $this->setNegate($parameters[$i]->getValue()); +                        break; +                    default: +                        $this->setError("Invalid parameter " . $paramname); +                } +            } // for each param +        } // if params +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the name attribute has been set. +     * +     */ +    public function verifySettings() { +        if ($this->pattern === null) { +            $this->setError("The name attribute is required"); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. Most of the work +     * for this selector is offloaded into SelectorUtils, a static class +     * that provides the same services for both FilenameSelector and +     * DirectoryScanner. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +        $this->validate(); +        return (SelectorUtils::matchPath($this->pattern, $filename, $this->casesensitive)  +            === !($this->negated)); +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php b/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php new file mode 100644 index 00000000..19e0fb76 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php @@ -0,0 +1,92 @@ +<?php + +/* + * $Id: MajoritySelector.php,v 1.6 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +/** + * This selector is here just to shake up your thinking a bit. Don't get + * too caught up in boolean, there are other ways you can evaluate a + * collection of selectors. This one takes a vote of the selectors it + * contains, and majority wins. You could also have an "all-but-one" + * selector, a "weighted-average" selector, and so on. These are left + * as exercises for the reader (as are the usecases where this would + * be necessary). + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class MajoritySelector extends BaseSelectorContainer { + +    private $allowtie = true; + +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{majorityselect: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    public function setAllowtie($tiebreaker) { +        $this->allowtie = $tiebreaker; +    } + +    /** +     * Returns true (the file is selected) if most of the other selectors +     * agree. In case of a tie, go by the allowtie setting. That defaults +     * to true, meaning in case of a tie, the file is selected. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a PhingFile object for the filename that the selector +     * can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +         +        $this->validate(); +         +        $yesvotes = 0; +        $novotes = 0; +         +        $selectors = $this->selectorElements(); +        for($i=0,$size=count($selectors); $i < $size; $i++) { +            $result = $selectors[$i]->isSelected($basedir,$filename,$file); +            if ($result) { +                $yesvotes = $yesvotes + 1; +            } else { +                $novotes = $novotes + 1; +            } +        } +        if ($yesvotes > $novotes) { +            return true; +        } +        else if ($novotes > $yesvotes) { +            return false; +        } +        // At this point, we know we have a tie. +        return $this->allowtie; +    } +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php b/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php new file mode 100644 index 00000000..844078a5 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php @@ -0,0 +1,71 @@ +<?php +/* + * $Id: NoneSelector.php,v 1.6 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +require_once 'phing/types/selectors/BaseSelectorContainer.php'; + +/** + * This selector has a collection of other selectors. All of those selectors + * must refuse to select a file before the file is considered selected by + * this selector. + * + * @author Hans Lellelid <hans@xmpl.org> + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class NoneSelector extends BaseSelectorContainer { + +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{noneselect: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    /** +     * Returns true (the file is selected) only if all other selectors +     * agree that the file should not be selected. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a java.io.File object for the filename that the selector +     * can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +         +        $this->validate(); +         +        $selectors = $this->selectorElements();         + +        for($i=0,$size=count($selectors); $i < $size; $i++) { +            $result = $selectors[$i]->isSelected($basedir, $filename, $file); +            if ($result) { +                return false; +            } +        } +        return true; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/NotSelector.php b/buildscripts/phing/classes/phing/types/selectors/NotSelector.php new file mode 100644 index 00000000..90237084 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/NotSelector.php @@ -0,0 +1,59 @@ +<?php + +/* + * $Id: NotSelector.php,v 1.4 2003/12/24 17:43:26 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/NoneSelector.php'; + +/** + * This selector has one other selectors whose meaning it inverts. It + * actually relies on NoneSelector for its implementation of the + * isSelected() method, but it adds a check to ensure there is only one + * other selector contained within. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class NotSelector extends NoneSelector { + +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{notselect: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    /** +     * Makes sure that there is only one entry, sets an error message if +     * not. +     */ +    public function verifySettings() { +        if ($this->selectorCount() != 1) { +            $this->setError("One and only one selector is allowed within the " . +                    "<not> tag"); +        } +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/OrSelector.php b/buildscripts/phing/classes/phing/types/selectors/OrSelector.php new file mode 100644 index 00000000..6a8778fa --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/OrSelector.php @@ -0,0 +1,72 @@ +<?php +/* + * $Id: OrSelector.php,v 1.7 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseSelectorContainer.php'; +  +/** + * This selector has a collection of other selectors, any of which have to + * select a file in order for this selector to select it. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class OrSelector extends BaseSelectorContainer { + +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{orselect: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    /** +     * Returns true (the file is selected) if any of the other selectors +     * agree that the file should be selected. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename the name of the file to check +     * @param file a PhingFile object for the filename that the selector +     * can use +     * @return boolean Whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { +         +        $this->validate(); +         +        $selectors = $this->selectorElements(); + +        // First, check that all elements are correctly configured +         +        for($i=0,$size=count($selectors); $i < $size; $i++) { +            $result = $selectors[$i]->isSelected($basedir, $filename, $file); +            if ($result) { +                return true; +            } +        } +        return false; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php b/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php new file mode 100644 index 00000000..f5f4c880 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php @@ -0,0 +1,154 @@ +<?php + +/* + * $Id: PresentSelector.php,v 1.9 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +/** + * Selector that filters files based on whether they appear in another + * directory tree. It can contain a mapper element, so isn't available + * as an ExtendSelector (since those parameters can't hold other + * elements). + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class PresentSelector extends BaseSelector { + +    private $targetdir = null; +    private $mapperElement = null; +    private $map = null; +    private $destmustexist = true; +    private static $filePresence = array("srconly", "both"); +     +    public function toString() { +        $buf = "{presentselector targetdir: "; +        if ($this->targetdir === null) { +            $buf .= "NOT YET SET"; +        } else { +            $buf .= $this->targetdir->getName(); +        } +        $buf .= " present: "; +        if ($this->destmustexist) { +            $buf .= "both"; +        } else { +            $buf .= "srconly"; +        } +        if ($this->map !== null) { +            $buf .= $this->map->toString(); +        } elseif ($this->mapperElement !== null) { +            $buf .= $this->mapperElement->toString(); +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * The name of the file or directory which is checked for matching +     * files. +     * +     * @param targetdir the directory to scan looking for matching files. +     */ +    public function setTargetdir(PhingFile $targetdir) { +        $this->targetdir = $targetdir; +    } + +    /** +     * Defines the FileNameMapper to use (nested mapper element). +     * @throws BuildException  +     */ +    public function createMapper() { +        if ($this->mapperElement !== null) { +            throw new BuildException("Cannot define more than one mapper"); +        } +        $this->mapperElement = new Mapper($this->getProject()); +        return $this->mapperElement; +    } + + +    /** +     * This sets whether to select a file if its dest file is present. +     * It could be a <code>negate</code> boolean, but by doing things +     * this way, we get some documentation on how the system works. +     * A user looking at the documentation should clearly understand +     * that the ONLY files whose presence is being tested are those +     * that already exist in the source directory, hence the lack of +     * a <code>destonly</code> option. +     * +     * @param string $fp An attribute set to either <code>srconly</code or +     *           ><code>both</code>. +     */ +    public function setPresent($fp) { +        $idx = array_search($fp, self::$filePresence, true); +        if ( $idx === 0 ) { +            $this->destmustexist = false; +        } +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the targetdir attribute has been set and we have a mapper. +     */ +    public function verifySettings() { +        if ($this->targetdir === null) { +            $this->setError("The targetdir attribute is required."); +        } +        if ($this->mapperElement === null) { +            $this->map = new IdentityMapper(); +        } else { +            $this->map = $this->mapperElement->getImplementation(); +        } +        if ($this->map === null) { +            $this->setError("Could not set <mapper> element."); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param basedir the base directory the scan is being done from +     * @param filename is the name of the file to check +     * @param file is a PhingFile object the selector can use +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); + +        // Determine file whose existence is to be checked +        $destfiles = $this->map->main($filename); +        // If filename does not match the To attribute of the mapper +        // then filter it out of the files we are considering +        if ($destfiles === null) { +            return false; +        } +        // Sanity check +        if (count($destfiles) !== 1 || $destfiles[0] === null) { +            throw new BuildException("Invalid destination file results for " +                . $this->targetdir . " with filename " . $filename); +        } +        $destname = $destfiles[0]; +        $destfile = new PhingFile($this->targetdir, $destname); +        return $destfile->exists() === $this->destmustexist; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php b/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php new file mode 100644 index 00000000..a7644447 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php @@ -0,0 +1,124 @@ +<?php + +/* + * $Id: SelectSelector.php,v 1.6 2003/12/24 17:43:26 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/AndSelector.php'; + +/** + * This selector just holds one other selector and forwards all + * requests to it. It exists so that there is a single selector + * type that can exist outside of any targets, as an element of + * project. It overrides all of the reference stuff so that it + * works as expected. Note that this is the only selector you + * can reference. + * + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Bruce Atherton <bruce@callenish.com> (Ant) + * @version   $Revision: 1.6 $ + * @package   phing.types.selectors + */ +class SelectSelector extends AndSelector { +          +    public function toString() { +        $buf = ""; +        if ($this->hasSelectors()) { +            $buf .= "{select: "; +            $buf .= parent::toString(); +            $buf .= "}"; +        } +        return $buf; +    } + +    /** +     * Performs the check for circular references and returns the +     * referenced Selector. +     */ +    private function getRef() { +        $o = $this->getCheckedRef(get_class($this), "SelectSelector"); +        return $o; +    } + +    /** +     * Indicates whether there are any selectors here. +     */ +    public function hasSelectors() { +        if ($this->isReference()) { +            return $this->getRef()->hasSelectors(); +        } +        return parent::hasSelectors(); +    } + +    /** +     * Gives the count of the number of selectors in this container +     */ +    public function selectorCount() { +        if ($this->isReference()) { +            return $this->getRef()->selectorCount(); +        } +        return parent::selectorCount(); +    } + +    /** +     * Returns the set of selectors as an array. +     */ +    public function getSelectors(Project $p) { +        if ($this->isReference()) { +            return $this->getRef()->getSelectors($p); +        } +        return parent::getSelectors($p); +    } + +    /** +     * Returns an enumerator for accessing the set of selectors. +     */ +    public function selectorElements() { +        if ($this->isReference()) { +            return $this->getRef()->selectorElements(); +        } +        return parent::selectorElements(); +    } + +    /** +     * Add a new selector into this container. +     * +     * @param selector the new selector to add +     * @return the selector that was added +     */ +    public function appendSelector(FileSelector $selector) { +        if ($this->isReference()) { +            throw $this->noChildrenAllowed(); +        } +        parent::appendSelector($selector); +    } + +    /** +     * Makes sure that there is only one entry, sets an error message if +     * not. +     */ +    public function verifySettings() { +        if ($this->selectorCount() != 1) { +            $this->setError("One and only one selector is allowed within the " +            . "<selector> tag"); +        } +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php b/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php new file mode 100644 index 00000000..4a73b113 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php @@ -0,0 +1,141 @@ +<?php + +/* + * $Id: SelectorContainer.php,v 1.3 2003/11/19 05:48:30 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +/** + * This is the interface for selectors that can contain other selectors. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @package phing.types.selectors + */ +interface SelectorContainer { + +    /** +     * Indicates whether there are any selectors here. +     * +     * @return whether any selectors are in this container +     */ +    public function hasSelectors(); + +    /** +     * Gives the count of the number of selectors in this container +     * +     * @return the number of selectors in this container +     */ +    public function selectorCount(); + +    /** +     * Returns a *copy* of the set of selectors as an array. +     * +     * @return an array of selectors in this container +     */ +    public function getSelectors(Project $p); + +    /** +     * Returns an array for accessing the set of selectors. +     * +     * @return an enumerator that goes through each of the selectors +     */ +    public function selectorElements(); + +    /** +     * Add a new selector into this container. +     * +     * @param selector the new selector to add +     * @return the selector that was added +     */ +    public function appendSelector(FileSelector $selector); + +    /* Methods below all add specific selectors */ + +    /** +     * add a "Select" selector entry on the selector list +     */ +    public function createSelector(); + +    /** +     * add an "And" selector entry on the selector list +     */ +    public function createAnd(); + +    /** +     * add an "Or" selector entry on the selector list +     */ +    public function createOr(); + +    /** +     * add a "Not" selector entry on the selector list +     */ +    public function createNot(); + +    /** +     * add a "None" selector entry on the selector list +     */ +    public function createNone(); + +    /** +     * add a majority selector entry on the selector list +     */ +    public function createMajority(); + +    /** +     * add a selector date entry on the selector list +     */ +    public function createDate(); + +    /** +     * add a selector size entry on the selector list +     */ +    public function createSize(); + +    /** +     * add a selector filename entry on the selector list +     */ +    public function createFilename(); + +    /** +     * add an extended selector entry on the selector list +     */ +    public function createCustom(); + +    /** +     * add a contains selector entry on the selector list +     */ +    public function createContains(); + +    /** +     * add a present selector entry on the selector list +     */ +    public function createPresent(); + +    /** +     * add a depth selector entry on the selector list +     */ +    public function createDepth(); + +    /** +     * add a depends selector entry on the selector list +     */ +    public function createDepend(); + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php b/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php new file mode 100644 index 00000000..f5bb898a --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php @@ -0,0 +1,55 @@ +<?php + +/* + * $Id: SelectorScanner.php,v 1.3 2003/11/19 05:48:30 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +/** + * An interface used to describe the actions required by any type of + * directory scanner that supports Selecters. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +interface SelectorScanner { + +    /** +     * Sets the selectors the scanner should use. +     * +     * @param selectors the list of selectors +     */ +    public function setSelectors($selectors); + +    /** +     * Directories which were selected out of a scan. +     * +     * @param selectors list selector objects +     */ +    public function getDeselectedDirectories(); + +    /** +     * Files which were selected out of a scan. +     * +     * @param selectors list selector objects +     */ +    public function getDeselectedFiles(); + +} diff --git a/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php b/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php new file mode 100644 index 00000000..87247e97 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php @@ -0,0 +1,440 @@ +<?php + +/* + * $Id: SelectorUtils.php,v 1.5 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ +  +include_once 'phing/util/StringHelper.php'; + +/** + * <p>This is a utility class used by selectors and DirectoryScanner. The + * functionality more properly belongs just to selectors, but unfortunately + * DirectoryScanner exposed these as protected methods. Thus we have to + * support any subclasses of DirectoryScanner that may access these methods. + * </p> + * <p>This is a Singleton.</p> + * + * @author Hans Lellelid, hans@xmpl.org (Phing) + * @author Arnout J. Kuiper, ajkuiper@wxs.nl (Ant) + * @author Magesh Umasankar + * @author Bruce Atherton, bruce@callenish.com (Ant) + * @package phing.types.selectors + */ +class SelectorUtils { + +    private static $instance; + +     /** +      * Retrieves the instance of the Singleton. +      */ +    public function getInstance() { +        if (!isset(self::$instance)) { +            self::$instance = new SelectorUtils(); +        } +        return self::$instance; +    } + +    /** +     * Tests whether or not a given path matches the start of a given +     * pattern up to the first "**". +     * <p> +     * This is not a general purpose test and should only be used if you +     * can live with false positives. For example, <code>pattern=**\a</code> +     * and <code>str=b</code> will yield <code>true</code>. +     * +     * @param pattern The pattern to match against. Must not be +     *                <code>null</code>. +     * @param str     The path to match, as a String. Must not be +     *                <code>null</code>. +     * @param isCaseSensitive Whether or not matching should be performed +     *                        case sensitively. +     * +     * @return whether or not a given path matches the start of a given +     * pattern up to the first "**". +     */ +    public function matchPatternStart($pattern, $str, $isCaseSensitive = true) { + +        // When str starts with a DIRECTORY_SEPARATOR, pattern has to start with a +        // DIRECTORY_SEPARATOR. +        // When pattern starts with a DIRECTORY_SEPARATOR, str has to start with a +        // DIRECTORY_SEPARATOR. +        if (StringHelper::startsWith(DIRECTORY_SEPARATOR, $str) !== +            StringHelper::startsWith(DIRECTORY_SEPARATOR, $pattern)) { +            return false; +        } + +        $patDirs = explode(DIRECTORY_SEPARATOR, $pattern); +        $strDirs = explode(DIRECTORY_SEPARATOR, $str); + +        $patIdxStart = 0; +        $patIdxEnd   = count($patDirs)-1; +        $strIdxStart = 0; +        $strIdxEnd   = count($strDirs)-1; + +        // up to first '**' +        while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { +            $patDir = $patDirs[$patIdxStart]; +            if ($patDir == "**") { +                break; +            } +            if (!self::match($patDir, $strDirs[$strIdxStart], $isCaseSensitive)) { +                return false; +            } +            $patIdxStart++; +            $strIdxStart++; +        } + +        if ($strIdxStart > $strIdxEnd) { +            // String is exhausted +            return true; +        } elseif ($patIdxStart > $patIdxEnd) { +            // String not exhausted, but pattern is. Failure. +            return false; +        } else { +            // pattern now holds ** while string is not exhausted +            // this will generate false positives but we can live with that. +            return true; +        } +    } +     +    /** +     * Tests whether or not a given path matches a given pattern. +     * +     * @param pattern The pattern to match against. Must not be +     *                <code>null</code>. +     * @param str     The path to match, as a String. Must not be +     *                <code>null</code>. +     * @param isCaseSensitive Whether or not matching should be performed +     *                        case sensitively. +     * +     * @return <code>true</code> if the pattern matches against the string, +     *         or <code>false</code> otherwise. +     */ +    public function matchPath($pattern, $str, $isCaseSensitive = true) { +     +        // When str starts with a DIRECTORY_SEPARATOR, pattern has to start with a +        // DIRECTORY_SEPARATOR. +        // When pattern starts with a DIRECTORY_SEPARATOR, str has to start with a +        // DIRECTORY_SEPARATOR. +        if (StringHelper::startsWith(DIRECTORY_SEPARATOR, $str) !== +            StringHelper::startsWith(DIRECTORY_SEPARATOR, $pattern)) { +            return false; +        } + +        $patDirs = explode(DIRECTORY_SEPARATOR, $pattern); +        $strDirs = explode(DIRECTORY_SEPARATOR, $str); + +        $patIdxStart = 0; +        $patIdxEnd   = count($patDirs)-1; +        $strIdxStart = 0; +        $strIdxEnd   = count($strDirs)-1; +         +        // up to first '**' +        while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { +            $patDir = $patDirs[$patIdxStart]; +            if ($patDir == "**") { +                break; +            } +            if (!self::match($patDir, $strDirs[$strIdxStart], $isCaseSensitive)) { +                return false; +            } +            $patIdxStart++; +            $strIdxStart++; +        } +        if ($strIdxStart > $strIdxEnd) { +            // String is exhausted +            for ($i=$patIdxStart; $i <= $patIdxEnd; $i++) { +                if ($patDirs[$i] != "**") { +                    return false; +                } +            } +            return true; +        } elseif ($patIdxStart > $patIdxEnd) { +            // String not exhausted, but pattern is. Failure. +            return false; +        } + +        // up to last '**' +        while ($patIdxStart <= $patIdxEnd && $strIdxStart <= $strIdxEnd) { +            $patDir = $patDirs[$patIdxEnd]; +            if ($patDir == "**") { +                break; +            } +            if (!self::match($patDir, $strDirs[$strIdxEnd], $isCaseSensitive)) { +                return false; +            } +            $patIdxEnd--; +            $strIdxEnd--; +        } +         +        if ($strIdxStart > $strIdxEnd) { +            // String is exhausted +            for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { +                if ($patDirs[$i] != "**") { +                    return false; +                } +            } +            return true; +        } + +        while ($patIdxStart != $patIdxEnd && $strIdxStart <= $strIdxEnd) { +            $patIdxTmp = -1; +            for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { +                if ($patDirs[$i] == "**") { +                    $patIdxTmp = $i; +                    break; +                } +            } +            if ($patIdxTmp == $patIdxStart+1) { +                // '**/**' situation, so skip one +                $patIdxStart++; +                continue; +            } +            // Find the pattern between padIdxStart & padIdxTmp in str between +            // strIdxStart & strIdxEnd +            $patLength = ($patIdxTmp-$patIdxStart-1); +            $strLength = ($strIdxEnd-$strIdxStart+1); +            $foundIdx  = -1; + +            //strLoop:    (start of outer loop) +            for ($i=0; $i <= $strLength - $patLength; $i++) {                 +                for ($j = 0; $j < $patLength; $j++) { +                    $subPat = $patDirs[$patIdxStart+$j+1]; +                    $subStr = $strDirs[$strIdxStart+$i+$j]; +                    if (!self::match($subPat, $subStr, $isCaseSensitive)) { +                        continue 2; // continue up two levels (to strLoop:) +                    } +                }                                 +                $foundIdx = $strIdxStart+$i; // only reached if all sub patterns matched +                break; +            } + +            if ($foundIdx == -1) { +                return false; +            } + +            $patIdxStart = $patIdxTmp; +            $strIdxStart = $foundIdx + $patLength; +        } + +        for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { +            if ($patDirs[$i] != "**") { +                return false; +            } +        } + +        return true; +    } + +    /** +     * Tests whether or not a string matches against a pattern. +     * The pattern may contain two special characters:<br> +     * '*' means zero or more characters<br> +     * '?' means one and only one character +     * +     * @param pattern The pattern to match against. +     *                Must not be <code>null</code>. +     * @param str     The string which must be matched against the pattern. +     *                Must not be <code>null</code>. +     * @param isCaseSensitive Whether or not matching should be performed +     *                        case sensitively. +     * +     * +     * @return <code>true</code> if the string matches against the pattern, +     *         or <code>false</code> otherwise. +     */ +    public function match($pattern, $str, $isCaseSensitive = true) { +     +        $patArr = StringHelper::toCharArray($pattern); +        $strArr = StringHelper::toCharArray($str); +        $patIdxStart = 0; +        $patIdxEnd   = count($patArr)-1; +        $strIdxStart = 0; +        $strIdxEnd   = count($strArr)-1; +         +        $containsStar = false; +        for ($i = 0, $size=count($patArr); $i < $size; $i++) { +            if ($patArr[$i] == '*') { +                $containsStar = true; +                break; +            } +        } + +        if (!$containsStar) { +            // No '*'s, so we make a shortcut +            if ($patIdxEnd != $strIdxEnd) { +                return false; // Pattern and string do not have the same size +            } +            for ($i = 0; $i <= $patIdxEnd; $i++) { +                $ch = $patArr[$i]; +                if ($ch != '?') { +                    if ($isCaseSensitive && $ch !== $strArr[$i]) { +                        return false;// Character mismatch +                    } +                    if (!$isCaseSensitive && strtoupper($ch) !== +                        strtoupper($strArr[$i])) { +                        return false; // Character mismatch +                    } +                } +            } +            return true; // String matches against pattern +        } + +        if ($patIdxEnd == 0) { +            return true; // Pattern contains only '*', which matches anything +        } + +        // Process characters before first star +        while(($ch = $patArr[$patIdxStart]) != '*' && $strIdxStart <= $strIdxEnd) { +            if ($ch != '?') { +                if ($isCaseSensitive && $ch !== $strArr[$strIdxStart]) { +                    return false;// Character mismatch +                } +                if (!$isCaseSensitive && strtoupper($ch) !== +                    strtoupper($strArr[$strIdxStart])) { +                    return false;// Character mismatch +                } +            } +            $patIdxStart++; +            $strIdxStart++; +        } +         +        if ($strIdxStart > $strIdxEnd) { +            // All characters in the string are used. Check if only '*'s are +            // left in the pattern. If so, we succeeded. Otherwise failure. +            for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { +                if ($patArr[$i] != '*') { +                    return false; +                } +            } +            return true; +        } + +        // Process characters after last star +        while(($ch = $patArr[$patIdxEnd]) != '*' && $strIdxStart <= $strIdxEnd) { +            if ($ch != '?') { +                if ($isCaseSensitive && $ch !== $strArr[$strIdxEnd]) { +                    return false;// Character mismatch +                } +                if (!$isCaseSensitive && strtoupper($ch) !== +                    strtoupper($strArr[$strIdxEnd])) { +                    return false;// Character mismatch +                } +            } +            $patIdxEnd--; +            $strIdxEnd--; +        } +        if ($strIdxStart > $strIdxEnd) { +            // All characters in the string are used. Check if only '*'s are +            // left in the pattern. If so, we succeeded. Otherwise failure. +            for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { +                if ($patArr[$i] != '*') { +                    return false; +                } +            } +            return true; +        } + +        // process pattern between stars. padIdxStart and patIdxEnd point +        // always to a '*'. +        while ($patIdxStart !== $patIdxEnd && $strIdxStart <= $strIdxEnd) { +            $patIdxTmp = -1; +            for ($i = $patIdxStart+1; $i <= $patIdxEnd; $i++) { +                if ($patArr[$i] == '*') { +                    $patIdxTmp = $i; +                    break; +                } +            } +            if ($patIdxTmp === $patIdxStart + 1) { +                // Two stars next to each other, skip the first one. +                $patIdxStart++; +                continue; +            } +            // Find the pattern between padIdxStart & padIdxTmp in str between +            // strIdxStart & strIdxEnd +            $patLength = ($patIdxTmp - $patIdxStart - 1); +            $strLength = ($strIdxEnd - $strIdxStart + 1); +            $foundIdx  = -1; +             +            //strLoop: +            for ($i = 0; $i <= $strLength - $patLength; $i++) { +                for ($j = 0; $j < $patLength; $j++) { +                    $ch = $patArr[$patIdxStart+$j+1]; +                    if ($ch != '?') { +                        if ($isCaseSensitive && $ch !== $strArr[$strIdxStart+$i+$j]) { +                               continue 2; //continue to strLoop: +                        } +                        if (!$isCaseSensitive && strtoupper($ch) !== +                            strtoupper($strArr[$strIdxStart+$i+$j])) { +                               continue 2; //continue to strLoop: +                        } +                    } +                } +                // only reached if sub loop completed w/o invoking continue 2 +                $foundIdx = $strIdxStart + $i; +                break; +            } + +            if ($foundIdx == -1) { +                return false; +            } + +            $patIdxStart = $patIdxTmp; +            $strIdxStart = $foundIdx + $patLength; +        } + +        // All characters in the string are used. Check if only '*'s are left +        // in the pattern. If so, we succeeded. Otherwise failure. +        for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { +            if ($patArr[$i] != '*') { +                return false; +            } +        } +        return true; +    } + +    /** +     * Returns dependency information on these two files. If src has been +     * modified later than target, it returns true. If target doesn't exist, +     * it likewise returns true. Otherwise, target is newer than src and +     * is not out of date, thus the method returns false. It also returns +     * false if the src file doesn't even exist, since how could the +     * target then be out of date. +     * +     * @param PhingFile $src the original file +     * @param PhingFile $target the file being compared against +     * @param int $granularity the amount in seconds of slack we will give in +     *        determining out of dateness +     * @return whether the target is out of date +     */ +    public function isOutOfDate(PhingFile $src, PhingFile $target, $granularity) { +        if (!$src->exists()) { +            return false; +        } +        if (!$target->exists()) { +            return true; +        } +        if (($src->lastModified() - $granularity) > $target->lastModified()) { +            return true; +        } +        return false; +    } + +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php b/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php new file mode 100644 index 00000000..bbc26423 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php @@ -0,0 +1,228 @@ +<?php + +/* + * $Id: SizeSelector.php,v 1.8 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + + +/** + * Selector that filters files based on their size. + * + * @author Hans Lellelid <hans@xmpl.org> (Phing) + * @author Bruce Atherton <bruce@callenish.com> (Ant) + * @package phing.types.selectors + */ +class SizeSelector extends BaseExtendSelector { + +    private $size = -1; +    private $multiplier = 1; +    private $sizelimit = -1; +    private $cmp = 2; +    const SIZE_KEY = "value"; +    const UNITS_KEY = "units"; +    const WHEN_KEY = "when"; + +    private static $sizeComparisons =  array("less", "more", "equal"); +    private static $byteUnits = array("K", "k", "kilo", "KILO", +                                 "Ki", "KI", "ki", "kibi", "KIBI", +                                 "M", "m", "mega", "MEGA", +                                 "Mi", "MI", "mi", "mebi", "MEBI", +                                 "G", "g", "giga", "GIGA", +                                 "Gi", "GI", "gi", "gibi", "GIBI", +                                 "T", "t", "tera", "TERA", +            /* You wish! */      "Ti", "TI", "ti", "tebi", "TEBI" +                                 ); + +    public function toString() { +        $buf = "{sizeselector value: "; +        $buf .= $this->sizelimit; +        $buf .= "compare: "; +        if ($this->cmp === 0) { +            $buf .= "less"; +        } elseif ($this->cmp === 1) { +            $buf .= "more"; +        } else { +            $buf .= "equal"; +        } +        $buf .= "}"; +        return $buf; +    } + +    /** +     * A size selector needs to know what size to base its selecting on. +     * This will be further modified by the multiplier to get an +     * actual size limit. +     * +     * @param size the size to select against expressed in units +     */ +    public function setValue($size) { +        $this->size = $size; +        if (($this->multiplier !== 0) && ($this->size > -1)) { +            $this->sizelimit = $size * $this->multiplier; +        } +    } + +    /** +     * Sets the units to use for the comparison. This is a little +     * complicated because common usage has created standards that +     * play havoc with capitalization rules. Thus, some people will +     * use "K" for indicating 1000's, when the SI standard calls for +     * "k". Others have tried to introduce "K" as a multiple of 1024, +     * but that falls down when you reach "M", since "m" is already +     * defined as 0.001. +     * <p> +     * To get around this complexity, a number of standards bodies +     * have proposed the 2^10 standard, and at least one has adopted +     * it. But we are still left with a populace that isn't clear on +     * how capitalization should work. +     * <p> +     * We therefore ignore capitalization as much as possible. +     * Completely mixed case is not possible, but all upper and lower +     * forms are accepted for all long and short forms. Since we have +     * no need to work with the 0.001 case, this practice works here. +     * <p> +     * This function translates all the long and short forms that a +     * unit prefix can occur in and translates them into a single +     * multiplier. +     * +     * @param $units The units to compare the size to. +     * @return void +     */ +    public function setUnits($units) { +        $i = array_search($units, self::$byteUnits, true); +        if ($i === false) $i = -1; // make it java-like +         +        $this->multiplier = 0; +        if (($i > -1) && ($i < 4)) { +            $this->multiplier = 1000; +        } elseif (($i > 3) && ($i < 9)) { +            $this->multiplier = 1024; +        } elseif (($i > 8) && ($i < 13)) { +            $this->multiplier = 1000000; +        } elseif (($i > 12) && ($i < 18)) { +            $this->multiplier = 1048576; +        } elseif (($i > 17) && ($i < 22)) { +            $this->multiplier = 1000000000; +        } elseif (($i > 21) && ($i < 27)) { +            $this->multiplier = 1073741824; +        } elseif (($i > 26) && ($i < 31)) { +            $this->multiplier = 1000000000000; +        } elseif (($i > 30) && ($i < 36)) { +            $this->multiplier = 1099511627776; +        } +        if (($this->multiplier > 0) && ($this->size > -1)) { +            $this->sizelimit = $this->size * $this->multiplier; +        } +    } + +    /** +     * This specifies when the file should be selected, whether it be +     * when the file matches a particular size, when it is smaller, +     * or whether it is larger. +     * +     * @param cmp The comparison to perform, an EnumeratedAttribute +     */ +    public function setWhen($cmp) { +        $c = array_search($cmp, self::$sizeComparisons, true); +        if ($c !== false) { +            $this->cmp = $c; +        } +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i = 0, $size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                switch(strtolower($paramname)) { +                    case self::SIZE_KEY: +                        try { +                            $this->setValue($parameters[$i]->getValue()); +                           } catch (Exception $nfe) { +                               $this->setError("Invalid size setting " +                                . $parameters[$i]->getValue()); +                           } +                        break; +                    case self::UNITS_KEY:                                                 +                        $this->setUnits($parameters[$i]->getValue()); +                        break; +                    case self::WHEN_KEY: +                        $this->setWhen($parameters[$i]->getValue()); +                        break; +                    default:     +                        $this->setError("Invalid parameter " . $paramname); +                } +            } +        } +    } + +    /** +     * <p>Checks to make sure all settings are kosher. In this case, it +     * means that the size attribute has been set (to a positive value), +     * that the multiplier has a valid setting, and that the size limit +     * is valid. Since the latter is a calculated value, this can only +     * fail due to a programming error. +     * </p> +     * <p>If a problem is detected, the setError() method is called. +     * </p> +     */ +    public function verifySettings() { +        if ($this->size < 0) { +            $this->setError("The value attribute is required, and must be positive"); +        } elseif ($this->multiplier < 1) { +            $this->setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti"); +        } elseif ($this->sizelimit < 0) { +            $this->setError("Internal error: Code is not setting sizelimit correctly"); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param basedir A PhingFile object for the base directory +     * @param filename The name of the file to check +     * @param file A PhingFile object for this filename +     * @return whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        $this->validate(); + +        // Directory size never selected for +        if ($file->isDirectory()) { +            return true; +        } +        if ($this->cmp === 0) { +            return ($file->length() < $this->sizelimit); +        } elseif ($this->cmp === 1) { +            return ($file->length() > $this->sizelimit); +        } else { +            return ($file->length() === $this->sizelimit); +        } +    } +     +} + diff --git a/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php b/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php new file mode 100644 index 00000000..f1532308 --- /dev/null +++ b/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php @@ -0,0 +1,113 @@ +<?php + +/* + * $Id: TypeSelector.php,v 1.3 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/BaseExtendSelector.php'; + +/** + * Selector that selects a certain kind of file: directory or regular file. + *  + * @author    Hans Lellelid <hans@xmpl.org> (Phing) + * @author    Jeff Turner <jefft@apache.org> (Ant) + * @version   $Revision: 1.3 $ + * @package   phing.types.selectors + */ +class TypeSelector extends BaseExtendSelector { + +    private $type; + +    /** Key to used for parameterized custom selector */ +    const TYPE_KEY = "type"; +     +    /** Valid types */ +    private static $types = array('file', 'dir'); +     +    /** +     * @return string A string describing this object +     */ +    public function toString() { +        $buf = "{typeselector type: " . $this->type . "}"; +        return $buf; +    } + +    /** +     * Set the type of file to require. +     * @param string $type The type of file - 'file' or 'dir' +     */ +    public function setType($type) {        +        $this->type = $type; +    } + +    /** +     * When using this as a custom selector, this method will be called. +     * It translates each parameter into the appropriate setXXX() call. +     * +     * @param array $parameters the complete set of parameters for this selector +     */ +    public function setParameters($parameters) { +        parent::setParameters($parameters); +        if ($parameters !== null) { +            for ($i = 0, $size=count($parameters); $i < $size; $i++) { +                $paramname = $parameters[$i]->getName(); +                if (self::TYPE_KEY == strtolower($paramname)) { +                    $this->setType($parameters[$i]->getValue()); +                } else { +                    $this->setError("Invalid parameter " . $paramname); +                } +            } +        } +    } + +    /** +     * Checks to make sure all settings are kosher. In this case, it +     * means that the pattern attribute has been set. +     * +     */ +    public function verifySettings() { +        if ($this->type === null) { +            $this->setError("The type attribute is required"); +        } elseif (!in_array($this->type, self::$types, true)) { +            $this->setError("Invalid type specified; must be one of (" . implode(self::$types) . ")"); +        } +    } + +    /** +     * The heart of the matter. This is where the selector gets to decide +     * on the inclusion of a file in a particular fileset. +     * +     * @param PhingFile $basedir the base directory the scan is being done from +     * @param string $filename is the name of the file to check +     * @param PhingFile $file is a PhingFile object the selector can use +     * @return boolean Whether the file should be selected or not +     */ +    public function isSelected(PhingFile $basedir, $filename, PhingFile $file) { + +        // throw BuildException on error +        $this->validate(); + +        if ($file->isDirectory()) { +            return $this->type === 'dir'; +        } else { +            return $this->type === 'file'; +        } +    } + +} diff --git a/buildscripts/phing/classes/phing/util/DirectoryScanner.php b/buildscripts/phing/classes/phing/util/DirectoryScanner.php new file mode 100644 index 00000000..e04c4880 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/DirectoryScanner.php @@ -0,0 +1,710 @@ +<?php +/* + *  $Id: DirectoryScanner.php,v 1.15 2005/12/13 21:56:26 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/types/selectors/SelectorScanner.php';  +include_once 'phing/util/StringHelper.php'; +include_once 'phing/types/selectors/SelectorUtils.php'; + +/** + * Class for scanning a directory for files/directories that match a certain + * criteria. + * + * These criteria consist of a set of include and exclude patterns. With these + * patterns, you can select which files you want to have included, and which + * files you want to have excluded. + * + * The idea is simple. A given directory is recursively scanned for all files + * and directories. Each file/directory is matched against a set of include + * and exclude patterns. Only files/directories that match at least one + * pattern of the include pattern list, and don't match a pattern of the + * exclude pattern list will be placed in the list of files/directories found. + * + * When no list of include patterns is supplied, "**" will be used, which + * means that everything will be matched. When no list of exclude patterns is + * supplied, an empty list is used, such that nothing will be excluded. + * + * The pattern matching is done as follows: + * The name to be matched is split up in path segments. A path segment is the + * name of a directory or file, which is bounded by DIRECTORY_SEPARATOR + * ('/' under UNIX, '\' under Windows). + * E.g. "abc/def/ghi/xyz.php" is split up in the segments "abc", "def", "ghi" + * and "xyz.php". + * The same is done for the pattern against which should be matched. + * + * Then the segments of the name and the pattern will be matched against each + * other. When '**' is used for a path segment in the pattern, then it matches + * zero or more path segments of the name. + * + * There are special case regarding the use of DIRECTORY_SEPARATOR at + * the beginning of the pattern and the string to match: + * When a pattern starts with a DIRECTORY_SEPARATOR, the string + * to match must also start with a DIRECTORY_SEPARATOR. + * When a pattern does not start with a DIRECTORY_SEPARATOR, the + * string to match may not start with a DIRECTORY_SEPARATOR. + * When one of these rules is not obeyed, the string will not + * match. + * + * When a name path segment is matched against a pattern path segment, the + * following special characters can be used: + *   '*' matches zero or more characters, + *   '?' matches one character. + * + * Examples: + * + * "**\*.php" matches all .php files/dirs in a directory tree. + * + * "test\a??.php" matches all files/dirs which start with an 'a', then two + * more characters and then ".php", in a directory called test. + * + * "**" matches everything in a directory tree. + * + * "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where + * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123"). + * + * Case sensitivity may be turned off if necessary.  By default, it is + * turned on. + * + * Example of usage: + *   $ds = new DirectroyScanner(); + *   $includes = array("**\*.php"); + *   $excludes = array("modules\*\**"); + *   $ds->SetIncludes($includes); + *   $ds->SetExcludes($excludes); + *   $ds->SetBasedir("test"); + *   $ds->SetCaseSensitive(true); + *   $ds->Scan(); + * + *   print("FILES:"); + *   $files = ds->GetIncludedFiles(); + *   for ($i = 0; $i < count($files);$i++) { + *     println("$files[$i]\n"); + *   } + * + * This will scan a directory called test for .php files, but excludes all + * .php files in all directories under a directory called "modules" + * + * This class is complete preg/ereg free port of the Java class + * org.apache.tools.ant.DirectoryScanner. Even functions that use preg/ereg + * internally (like split()) are not used. Only the _fast_ string functions + * and comparison operators (=== !=== etc) are used for matching and tokenizing. + * + *  @author   Arnout J. Kuiper, ajkuiper@wxs.nl + *  @author   Magesh Umasankar, umagesh@rediffmail.com + *  @author   Andreas Aderhold, andi@binarycloud.com + * + *  @version   $Revision: 1.15 $ + *  @package   phing.util + */ +class DirectoryScanner implements SelectorScanner { + +    /** default set of excludes */ +    protected $DEFAULTEXCLUDES = array( +        "**/*~", +        "**/#*#", +        "**/.#*", +        "**/%*%", +        "**/CVS", +        "**/CVS/**", +        "**/.cvsignore", +        "**/SCCS", +        "**/SCCS/**", +        "**/vssver.scc", +		"**/.svn", +		"**/.svn/**", +		"**/._*", +		"**/.DS_Store", +    ); + +    /** The base directory which should be scanned. */ +    protected $basedir; + +    /** The patterns for the files that should be included. */ +    protected $includes = null; + +    /** The patterns for the files that should be excluded. */ +    protected $excludes = null; + +    /** +     * The files that where found and matched at least one includes, and matched +     * no excludes. +     */ +    protected $filesIncluded; + +    /** The files that where found and did not match any includes. Trie */ +    protected $filesNotIncluded; + +    /** +     * The files that where found and matched at least one includes, and also +     * matched at least one excludes. Trie object. +     */ +    protected $filesExcluded; + +    /** +     * The directories that where found and matched at least one includes, and +     * matched no excludes. +     */ +    protected $dirsIncluded; + +    /** The directories that where found and did not match any includes. */ +    protected $dirsNotIncluded; + +    /** +     * The files that where found and matched at least one includes, and also +     * matched at least one excludes. +     */ +    protected $dirsExcluded; + +    /** Have the vars holding our results been built by a slow scan? */ +    protected $haveSlowResults = false; + +    /** Should the file system be treated as a case sensitive one? */ +    protected $isCaseSensitive = true; + +    /** Selectors */ +    protected $selectors = null; +     +    protected $filesDeselected; +    protected $dirsDeselected; +     +    /** if there are no deselected files */ +    protected $everythingIncluded = true;         + +    /** +     * Does the path match the start of this pattern up to the first "**". +     * This is a static mehtod and should always be called static +     * +     * This is not a general purpose test and should only be used if you +     * can live with false positives. +     * +     * pattern=**\a and str=b will yield true. +     * +     * @param   pattern             the (non-null) pattern to match against +     * @param   str                 the (non-null) string (path) to match +     * @param   isCaseSensitive     must matches be case sensitive? +     * @return  boolean             true if matches, otherwise false +     */ +    function matchPatternStart($pattern, $str, $isCaseSensitive = true) { +        return SelectorUtils::matchPatternStart($pattern, $str, $isCaseSensitive); +    } + +    /** +     * Matches a path against a pattern. Static +     * +     * @param pattern            the (non-null) pattern to match against +     * @param str                the (non-null) string (path) to match +     * @param isCaseSensitive    must a case sensitive match be done? +     * +     * @return true when the pattern matches against the string. +     *         false otherwise. +     */ +    function matchPath($pattern, $str, $isCaseSensitive = true) { +        return SelectorUtils::matchPath($pattern, $str, $isCaseSensitive); +    } + +    /** +     * Matches a string against a pattern. The pattern contains two special +     * characters: +     * '*' which means zero or more characters, +     * '?' which means one and only one character. +     * +     * @param  pattern the (non-null) pattern to match against +     * @param  str     the (non-null) string that must be matched against the +     *                 pattern +     * +     * @return boolean true when the string matches against the pattern, +     *                 false otherwise. +     * @access public +     */ +    function match($pattern, $str, $isCaseSensitive = true) { +        return SelectorUtils::match($pattern, $str, $isCaseSensitive); +    } + +    /** +     * Sets the basedir for scanning. This is the directory that is scanned +     * recursively. All '/' and '\' characters are replaced by +     * DIRECTORY_SEPARATOR +     * +     * @param basedir the (non-null) basedir for scanning +     */ +    function setBasedir($_basedir) { +        $_basedir = str_replace('\\', DIRECTORY_SEPARATOR, $_basedir); +        $_basedir = str_replace('/', DIRECTORY_SEPARATOR, $_basedir); +        $this->basedir = $_basedir; +    } + +    /** +     * Gets the basedir that is used for scanning. This is the directory that +     * is scanned recursively. +     * +     * @return the basedir that is used for scanning +     */ +    function getBasedir() { +        return $this->basedir; +    } + +    /** +     * Sets the case sensitivity of the file system +     * +     * @param specifies if the filesystem is case sensitive +     */ +    function setCaseSensitive($_isCaseSensitive) { +        $this->isCaseSensitive = ($_isCaseSensitive) ? true : false; +    } + +    /** +     * Sets the set of include patterns to use. All '/' and '\' characters are +     * replaced by DIRECTORY_SEPARATOR. So the separator used need +     * not match DIRECTORY_SEPARATOR. +     * +     * When a pattern ends with a '/' or '\', "**" is appended. +     * +     * @param includes list of include patterns +     */ +    function setIncludes($_includes = array()) { +        if (empty($_includes) || is_null($_includes)) { +            $this->includes = null; +        } else { +            for ($i = 0; $i < count($_includes); $i++) { +                $pattern = null; +                $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_includes[$i]); +                $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); +                if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { +                    $pattern .= "**"; +                } +                $this->includes[] = $pattern; +            } +        } +    } + +    /** +     * Sets the set of exclude patterns to use. All '/' and '\' characters are +     * replaced by <code>File.separatorChar</code>. So the separator used need +     * not match <code>File.separatorChar</code>. +     * +     * When a pattern ends with a '/' or '\', "**" is appended. +     * +     * @param excludes list of exclude patterns +     */ + +    function setExcludes($_excludes = array()) { +        if (empty($_excludes) || is_null($_excludes)) { +            $this->excludes = null; +        } else { +            for ($i = 0; $i < count($_excludes); $i++) { +                $pattern = null; +                $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $_excludes[$i]); +                $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); +                if (StringHelper::endsWith(DIRECTORY_SEPARATOR, $pattern)) { +                    $pattern .= "**"; +                } +                $this->excludes[] = $pattern; +            } +        } +    } + +    /** +     * Scans the base directory for files that match at least one include +     * pattern, and don't match any exclude patterns. +     * +     */ +    function scan() { +     +        if ((empty($this->basedir)) || (!@is_dir($this->basedir))) { +            return false; +        } + +        if ($this->includes === null) { +            // No includes supplied, so set it to 'matches all' +            $this->includes = array("**"); +        } +        if (is_null($this->excludes)) { +            $this->excludes = array(); +        } + +        $this->filesIncluded = array(); +        $this->filesNotIncluded = array(); +        $this->filesExcluded = array(); +        $this->dirsIncluded = array(); +        $this->dirsNotIncluded = array(); +        $this->dirsExcluded = array(); +        $this->dirsDeselected = array(); +        $this->filesDeselected = array(); +         +        if ($this->isIncluded("")) { +            if (!$this->isExcluded("")) { +                if ($this->isSelected("", $this->basedir)) { +                    $this->dirsIncluded[] = ""; +                } else { +                    $this->dirsDeselected[] = ""; +                }                 +            } else { +                $this->dirsExcluded[] = ""; +            } +        } else { +            $this->dirsNotIncluded[] = ""; +        } + +        $this->scandir($this->basedir, "", true); +        return true; +    } + +    /** +     * Toplevel invocation for the scan. +     * +     * Returns immediately if a slow scan has already been requested. +     */ +    protected function slowScan() { + +        if ($this->haveSlowResults) { +            return; +        } + +        // copy trie object add CopyInto() method +        $excl    = $this->dirsExcluded; +        $notIncl = $this->dirsNotIncluded; + +        for ($i=0, $_i=count($excl); $i < $_i; $i++) { +            if (!$this->couldHoldIncluded($excl[$i])) { +                $this->scandir($this->basedir.$excl[$i], $excl[$i].DIRECTORY_SEPARATOR, false); +            } +        } + +        for ($i=0, $_i=count($notIncl); $i < $_i; $i++) { +            if (!$this->couldHoldIncluded($notIncl[$i])) { +                $this->scandir($this->basedir.$notIncl[$i], $notIncl[$i].DIRECTORY_SEPARATOR, false); +            } +        } + +        $this->haveSlowResults = true; +    } + +    /** +     * Lists contens of a given directory and returns array with entries +     * +     * @param   src String. Source path and name file to copy. +     * +     * @access  public +     * @return  array  directory entries +     * @author  Albert Lash, alash@plateauinnovation.com +     */ + +    function listDir($_dir) { +        $d = dir($_dir); +        $list = array(); +        while($entry = $d->read()) { +            if ($entry != "." && $entry != "..") { +                $list[] = $entry; +            } +        } +        $d->close(); +        return $list; +    } + +    /** +     * Scans the passed dir for files and directories. Found files and +     * directories are placed in their respective collections, based on the +     * matching of includes and excludes. When a directory is found, it is +     * scanned recursively. +     * +     * @param dir   the directory to scan +     * @param vpath the path relative to the basedir (needed to prevent +     *              problems with an absolute path when using dir) +     * +     * @access private +     * @see #filesIncluded +     * @see #filesNotIncluded +     * @see #filesExcluded +     * @see #dirsIncluded +     * @see #dirsNotIncluded +     * @see #dirsExcluded +     */ +    private function scandir($_rootdir, $_vpath, $_fast) { +         +        if (!is_readable($_rootdir)) { +            return; +        }                                 +         +        $newfiles = self::listDir($_rootdir); +         +        for ($i=0,$_i=count($newfiles); $i < $_i; $i++) { +             +            $file = $_rootdir . DIRECTORY_SEPARATOR . $newfiles[$i]; +            $name = $_vpath . $newfiles[$i]; + +            if (@is_dir($file)) { +                if ($this->isIncluded($name)) { +                    if (!$this->isExcluded($name)) { +                        if ($this->isSelected($name, $file)) { +                            $this->dirsIncluded[] = $name; +                            if ($_fast) { +                                $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); +                            } +                        } else { +                            $this->everythingIncluded = false; +                            $this->dirsDeselected[] = $name; +                            if ($_fast && $this->couldHoldIncluded($name)) { +                                $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); +                            }                             +                        }                                                 +                    } else { +                        $this->everythingIncluded = false; +                        $this->dirsExcluded[] = $name; +                        if ($_fast && $this->couldHoldIncluded($name)) { +                            $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); +                        } +                    } +                } else { +                    $this->everythingIncluded = false; +                    $this->dirsNotIncluded[] = $name; +                    if ($_fast && $this->couldHoldIncluded($name)) { +                        $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); +                    } +                } +                 +                if (!$_fast) { +                    $this->scandir($file, $name.DIRECTORY_SEPARATOR, $_fast); +                } +                 +            } elseif (@is_file($file)) { +                if ($this->isIncluded($name)) { +                    if (!$this->isExcluded($name)) { +                        if ($this->isSelected($name, $file)) { +                            $this->filesIncluded[] = $name; +                        } else { +                            $this->everythingIncluded = false; +                            $this->filesDeselected[] = $name; +                        }                         +                    } else { +                        $this->everythingIncluded = false; +                        $this->filesExcluded[] = $name; +                    } +                } else { +                    $this->everythingIncluded = false; +                    $this->filesNotIncluded[] = $name; +                } +            } +        } +    } + +    /** +     * Tests whether a name matches against at least one include pattern. +     * +     * @param name the name to match +     * @return <code>true</code> when the name matches against at least one +     *         include pattern, <code>false</code> otherwise. +     */ +    protected function isIncluded($_name) { +        for ($i=0, $_i=count($this->includes); $i < $_i; $i++) { +            if (DirectoryScanner::matchPath($this->includes[$i], $_name, $this->isCaseSensitive)) { +                return true; +            } +        } +        return false; +    } + +    /** +     * Tests whether a name matches the start of at least one include pattern. +     * +     * @param name the name to match +     * @return <code>true</code> when the name matches against at least one +     *         include pattern, <code>false</code> otherwise. +     */ +    protected function couldHoldIncluded($_name) { +        for ($i = 0; $i < count($this->includes); $i++) { +            if (DirectoryScanner::matchPatternStart($this->includes[$i], $_name, $this->isCaseSensitive)) { +                return true; +            } +        } +        return false; +    } + +    /** +     * Tests whether a name matches against at least one exclude pattern. +     * +     * @param name the name to match +     * @return <code>true</code> when the name matches against at least one +     *         exclude pattern, <code>false</code> otherwise. +     */ +    protected function isExcluded($_name) { +        for ($i = 0; $i < count($this->excludes); $i++) { +            if (DirectoryScanner::matchPath($this->excludes[$i], $_name, $this->isCaseSensitive)) { +                return true; +            } +        } +        return false; +    } + +    /** +     * Get the names of the files that matched at least one of the include +     * patterns, and matched none of the exclude patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the files +     */ +    function getIncludedFiles() { +        return $this->filesIncluded;         +    } + +    /** +     * Get the names of the files that matched at none of the include patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the files +     */ +    function getNotIncludedFiles() { +        $this->slowScan(); +        return $this->filesNotIncluded; +    } + +    /** +     * Get the names of the files that matched at least one of the include +     * patterns, an matched also at least one of the exclude patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the files +     */ + +    function getExcludedFiles() { +        $this->slowScan(); +        return $this->filesExcluded; +    } + +    /** +     * <p>Returns the names of the files which were selected out and +     * therefore not ultimately included.</p> +     * +     * <p>The names are relative to the base directory. This involves +     * performing a slow scan if one has not already been completed.</p> +     * +     * @return the names of the files which were deselected. +     * +     * @see #slowScan +     */ +    public function getDeselectedFiles() { +        $this->slowScan();         +        return $this->filesDeselected; +    } + +    /** +     * Get the names of the directories that matched at least one of the include +     * patterns, an matched none of the exclude patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the directories +     */ + +    function getIncludedDirectories() { +        return $this->dirsIncluded;         +    } + +    /** +     * Get the names of the directories that matched at none of the include +     * patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the directories +     */ +    function getNotIncludedDirectories() { +        $this->slowScan(); +        return $this->dirsNotIncluded;         +    } + +    /** +     * <p>Returns the names of the directories which were selected out and +     * therefore not ultimately included.</p> +     * +     * <p>The names are relative to the base directory. This involves +     * performing a slow scan if one has not already been completed.</p> +     * +     * @return the names of the directories which were deselected. +     * +     * @see #slowScan +     */ +    public function getDeselectedDirectories() { +        $this->slowScan(); +        return $this->dirsDeselected; +    } +     +    /** +     * Get the names of the directories that matched at least one of the include +     * patterns, an matched also at least one of the exclude patterns. +     * The names are relative to the basedir. +     * +     * @return the names of the directories +     */ +    function getExcludedDirectories() { +        $this->slowScan(); +        return $this->dirsExcluded;         +    } + +    /** +     * Adds the array with default exclusions to the current exclusions set. +     * +     */ +    function addDefaultExcludes() { +        //$excludesLength = ($this->excludes == null) ? 0 : count($this->excludes); +        foreach($this->DEFAULTEXCLUDES as $pattern) { +            $pattern = str_replace('\\', DIRECTORY_SEPARATOR, $pattern); +            $pattern = str_replace('/', DIRECTORY_SEPARATOR, $pattern); +            $this->excludes[] = $pattern; +        } +    } +     +    /** +     * Sets the selectors that will select the filelist. +     * +     * @param selectors specifies the selectors to be invoked on a scan +     */ +    public function setSelectors($selectors) { +        $this->selectors = $selectors; +    } + +    /** +     * Returns whether or not the scanner has included all the files or +     * directories it has come across so far. +     * +     * @return <code>true</code> if all files and directories which have +     *         been found so far have been included. +     */ +    public function isEverythingIncluded() { +        return $this->everythingIncluded; +    } +         +    /** +     * Tests whether a name should be selected. +     * +     * @param string $name The filename to check for selecting. +     * @param string $file The full file path. +     * @return boolean False when the selectors says that the file +     *         should not be selected, True otherwise. +     */ +    protected function isSelected($name, $file) { +        if ($this->selectors !== null) { +            for ($i=0,$size=count($this->selectors); $i < $size; $i++) { +                if (($this->selectors[$i]->isSelected(new PhingFile($this->basedir), $name, new PhingFile($file))) === false) { +                    return false; +                } +            } +        } +        return true; +    } + +} diff --git a/buildscripts/phing/classes/phing/util/ExtendedFileStream.php b/buildscripts/phing/classes/phing/util/ExtendedFileStream.php new file mode 100644 index 00000000..5fdcae47 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/ExtendedFileStream.php @@ -0,0 +1,133 @@ +<?php + +	include_once 'phing/system/io/PhingFile.php'; + +	/** +	 * $Id: ExtendedFileStream.php,v 1.5 2005/12/27 15:51:26 hlellelid Exp $ +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +	 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +	 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +	 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +	 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +	 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +	 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +	 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +	 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +	 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 * +	 * This software consists of voluntary contributions made by many individuals +	 * and is licensed under the LGPL. For more information please see +	 * <http://phing.info>. +	 */ + +	/** +	 * Extended file stream wrapper class which auto-creates directories +	 * +	 * @author Michiel Rook <michiel@trendserver.nl> +	 * @version $Id: ExtendedFileStream.php,v 1.5 2005/12/27 15:51:26 hlellelid Exp $ +	 * @package phing.util +	 */ +	class ExtendedFileStream +	{ +		private $fp = NULL; +		 +		static function registerStream() +		{ +			if (!in_array("efile", stream_get_wrappers())) +			{ +				stream_wrapper_register("efile", "ExtendedFileStream"); +			} +		} +		 +		private function createDirectories($path) +		{ +			$f = new PhingFile($path); +			if (!$f->exists()) { +				$f->mkdirs(); +			} +		} +		 +		function stream_open($path, $mode, $options, &$opened_path) +		{ +			/** Small fix for Windows */ +			if ($path[8] == DIRECTORY_SEPARATOR) +			{ +				$filepath = substr($path, 7); +			} +			else +			{ +				$filepath = substr($path, 8); +			} +			 +			$this->createDirectories(dirname($filepath)); +			 +			$this->fp = fopen($filepath, $mode); +			 +			return true; +		} +		 +		function stream_close() +		{ +			fclose($this->fp); +			$this->fp = NULL; +		} +		 +		function stream_read($count) +		{ +			return fread($this->fp, $count); +		} +		 +		function stream_write($data) +		{ +			return fwrite($this->fp, $data); +		} +		 +		function stream_eof() +		{ +			return feof($this->fp); +		} +		 +		function stream_tell() +		{ +			return ftell($this->fp); +		} +		 +		function stream_seek($offset, $whence) +		{ +			return fseek($this->fp, $offset, $whence); +		} +		 +		function stream_flush() +		{ +			return fflush($this->fp); +		} +		 +		function stream_stat() +		{ +			return fstat($this->fp); +		} +		 +		function unlink($path) +		{ +			return FALSE; +		} +		 +		function rename($path_from, $path_to) +		{ +			return FALSE; +		} +		 +		function mkdir($path, $mode, $options) +		{ +			return FALSE; +		} +		 +		function rmdir($path, $options) +		{ +			return FALSE; +		}		 +	}; + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/FileUtils.php b/buildscripts/phing/classes/phing/util/FileUtils.php new file mode 100644 index 00000000..0f5ff19a --- /dev/null +++ b/buildscripts/phing/classes/phing/util/FileUtils.php @@ -0,0 +1,294 @@ +<?php +/* + *  $Id: FileUtils.php,v 1.10 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +include_once 'phing/system/lang/Character.php'; +include_once 'phing/util/StringHelper.php'; +include_once 'phing/system/io/BufferedReader.php'; +include_once 'phing/system/io/BufferedWriter.php'; +include_once 'phing/filters/util/ChainReaderHelper.php'; +include_once 'phing/system/io/PhingFile.php'; + +/** + * File utility class. + * - handles os independent stuff etc + * - mapper stuff + * - filter stuff + * + * @package  phing.util + * @version  $Revision: 1.10 $ + */ +class FileUtils { +         +    /** +     * Returns a new Reader with filterchains applied.  If filterchains are empty, +     * simply returns passed reader. +     *  +     * @param Reader $in Reader to modify (if appropriate). +     * @param array &$filterChains filter chains to apply. +     * @param Project $project +     * @return Reader Assembled Reader (w/ filter chains). +     */ +    function getChainedReader(Reader $in, &$filterChains, Project $project) { +        if (!empty($filterChains)) { +            $crh = new ChainReaderHelper(); +            $crh->setBufferSize(65536); // 64k buffer, but isn't being used (yet?) +            $crh->setPrimaryReader($in); +            $crh->setFilterChains($filterChains); +            $crh->setProject($project); +            $rdr = $crh->getAssembledReader(); +            return $rdr; +        } else { +            return $in; +        } +    } +     +    /** +     * Copies a file using filter chains. +     *  +     * @param PhingFile $sourceFile +     * @param PhingFile $destFile +     * @param boolean $overwrite +     * @param boolean $preserveLastModified +     * @param array $filterChains  +     * @param Project $project +     * @return void +     */ +    function copyFile(PhingFile $sourceFile, PhingFile $destFile, $overwrite = false, $preserveLastModified = true, &$filterChains = null, Project $project) { +        +        if ($overwrite || !$destFile->exists() || $destFile->lastModified() < $sourceFile->lastModified()) { +            if ($destFile->exists() && $destFile->isFile()) { +                $destFile->delete(); +            } + +            // ensure that parent dir of dest file exists! +            $parent = $destFile->getParentFile(); +            if ($parent !== null && !$parent->exists()) { +                $parent->mkdirs(); +            } + +            if ((is_array($filterChains)) && (!empty($filterChains))) { +                 +                $in = self::getChainedReader(new BufferedReader(new FileReader($sourceFile)), $filterChains, $project); +                $out = new BufferedWriter(new FileWriter($destFile));                 +                 +                // New read() methods returns a big buffer.                 +                while(-1 !== ($buffer = $in->read())) { // -1 indicates EOF +                    $out->write($buffer); +                } +                 +                if ( $in !== null ) +                    $in->close(); +                if ( $out !== null ) +                    $out->close(); +            } else { +                // simple copy (no filtering) +                $sourceFile->copyTo($destFile); +            } + +            if ($preserveLastModified) { +                $destFile->setLastModified($sourceFile->lastModified()); +            } + +        } +    } + +    /** +     * Interpret the filename as a file relative to the given file - +     * unless the filename already represents an absolute filename. +     * +     * @param  $file the "reference" file for relative paths. This +     *         instance must be an absolute file and must not contain +     *         ./ or ../ sequences (same for \ instead of /). +     * @param  $filename a file name +     * +     * @return PhingFile A PhingFile object pointing to an absolute file that doesn't contain ./ or ../ sequences +     *         and uses the correct separator for the current platform. +     */ +    function resolveFile($file, $filename) { +        // remove this and use the static class constant File::seperator +        // as soon as ZE2 is ready +        $fs = FileSystem::getFileSystem(); + +        $filename = str_replace('/', $fs->getSeparator(), str_replace('\\', $fs->getSeparator(), $filename)); + +        // deal with absolute files +        if (StringHelper::startsWith($fs->getSeparator(), $filename) || +                (strlen($filename) >= 2 && Character::isLetter($filename{0}) && $filename{1} === ':')) { +            return new PhingFile($this->normalize($filename)); +        } + +        if (strlen($filename) >= 2 && Character::isLetter($filename{0}) && $filename{1} === ':') { +            return new PhingFile($this->normalize($filename)); +        } + +        $helpFile = new PhingFile($file->getAbsolutePath()); + +        $tok = strtok($filename, $fs->getSeparator()); +        while ($tok !== false) { +            $part = $tok; +            if ($part === '..') { +                $parentFile = $helpFile->getParent(); +                if ($parentFile === null) { +                    $msg = "The file or path you specified ($filename) is invalid relative to ".$file->getPath(); +                    throw new IOException($msg); +                } +                $helpFile = new PhingFile($parentFile); +            } else if ($part === '.') { +                // Do nothing here +            } else { +                $helpFile = new PhingFile($helpFile, $part); +            } +            $tok = strtok($fs->getSeparator()); +        } +        return new PhingFile($helpFile->getAbsolutePath()); +    } + +    /** +     * Normalize the given absolute path. +     * +     * This includes: +     *   - Uppercase the drive letter if there is one. +     *   - Remove redundant slashes after the drive spec. +     *   - resolve all ./, .\, ../ and ..\ sequences. +     *   - DOS style paths that start with a drive letter will have +     *     \ as the separator. +     * @param string $path Path to normalize. +     * @return string +     */ +    function normalize($path) { +     +        $path = (string) $path; +        $orig = $path; + +        $path = str_replace('/', DIRECTORY_SEPARATOR, str_replace('\\', DIRECTORY_SEPARATOR, $path)); + +        // make sure we are dealing with an absolute path +        if (!StringHelper::startsWith(DIRECTORY_SEPARATOR, $path) +                && !(strlen($path) >= 2 && Character::isLetter($path{0}) && $path{1} === ':')) { +            throw new IOException("$path is not an absolute path"); +        } + +        $dosWithDrive = false; +        $root = null; + +        // Eliminate consecutive slashes after the drive spec + +        if (strlen($path) >= 2 && Character::isLetter($path{0}) && $path{1} === ':') { +            $dosWithDrive = true; + +            $ca = str_replace('/', '\\', $path); +            $ca = StringHelper::toCharArray($ca); + +            $path = strtoupper($ca[0]).':'; +             +            for ($i=2, $_i=count($ca); $i < $_i; $i++) { +                if (($ca[$i] !== '\\') || +                        ($ca[$i] === '\\' && $ca[$i - 1] !== '\\') +                   ) { +                    $path .= $ca[$i]; +                } +            } +          +            $path = str_replace('\\', DIRECTORY_SEPARATOR, $path); + +            if (strlen($path) == 2) { +                $root = $path; +                $path = ""; +            } else { +                $root = substr($path, 0, 3); +                $path = substr($path, 3); +            } + +        } else { +            if (strlen($path) == 1) { +                $root = DIRECTORY_SEPARATOR; +                $path = ""; +            } else if ($path{1} == DIRECTORY_SEPARATOR) { +                // UNC drive +                $root = DIRECTORY_SEPARATOR.DIRECTORY_SEPARATOR; +                $path = substr($path, 2); +            } +            else { +                $root = DIRECTORY_SEPARATOR; +                $path = substr($path, 1); +            } +        } + +        $s = array(); +        array_push($s, $root); +        $tok = strtok($path, DIRECTORY_SEPARATOR); +        while ($tok !== false) {             +            $thisToken = $tok; +            if ("." === $thisToken) { +                $tok = strtok(DIRECTORY_SEPARATOR); +                continue; +            } elseif (".." === $thisToken) { +                if (count($s) < 2) { +                    // using '..' in path that is too short +                    throw new IOException("Cannot resolve path: $orig"); +                } else { +                    array_pop($s); +                } +            } else { // plain component +                array_push($s, $thisToken); +            } +            $tok = strtok(DIRECTORY_SEPARATOR); +        } + +        $sb = ""; +        for ($i=0,$_i=count($s); $i < $_i; $i++) { +            if ($i > 1) { +                // not before the filesystem root and not after it, since root +                // already contains one +                $sb .= DIRECTORY_SEPARATOR; +            } +            $sb .= (string) $s[$i]; +        } + + +        $path = (string) $sb; +        if ($dosWithDrive === true) { +            $path = str_replace('/', '\\', $path); +        } +        return $path; +    } +     +    /** +     * @return boolean Whether contents of two files is the same. +     */ +    public function contentEquals(PhingFile $file1, PhingFile $file2) { +         +        if (!($file1->exists() || $file2->exists())) { +            return false; +        } + +        if (!($file1->canRead() || $file2->canRead())) { +            return false; +        } +         +        $c1 = file_get_contents($file1->getAbsolutePath()); +        $c2 = file_get_contents($file2->getAbsolutePath()); +         +        return trim($c1) == trim($c2);     +    } +     +} +?> diff --git a/buildscripts/phing/classes/phing/util/LogWriter.php b/buildscripts/phing/classes/phing/util/LogWriter.php new file mode 100644 index 00000000..9e704fc3 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/LogWriter.php @@ -0,0 +1,96 @@ +<?php + +	/** +	 * $Id: LogWriter.php,v 1.2 2004/11/09 13:16:11 hlellelid Exp $ +	 * +	 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +	 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +	 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +	 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +	 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +	 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +	 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +	 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +	 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +	 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +	 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +	 * +	 * This software consists of voluntary contributions made by many individuals +	 * and is licensed under the LGPL. For more information please see +	 * <http://phing.info>. +	 */ +	 +	require_once 'phing/system/io/Writer.php'; +	require_once 'phing/Task.php'; + +	/** +	 * Extends the Writer class to output messages to Phing's log +	 * +	 * @author Michiel Rook <michiel@trendserver.nl> +	 * @version $Id: LogWriter.php,v 1.2 2004/11/09 13:16:11 hlellelid Exp $ +	 * @package phing.util +	 */ +	class LogWriter extends Writer +	{ +		private $task = NULL; +		 +		private $level = NULL; +		 +		/** +		 * Constructs a new LogWriter object +		 */ +		function __construct(Task $task, $level = PROJECT_MSG_INFO) +		{ +			$this->task = $task; +			$this->level = $level; +		} +		 +		/** +		 * @see Writer::write() +		 */ +		function write($buf, $off = null, $len = null) +		{ +			$lines = explode("\n", $buf); +			 +			foreach ($lines as $line) +			{ +				if ($line == "") +				{ +					continue; +				} +				 +				$this->task->log($line, $this->level); +			} +		} +		 +		/** +		 * @see Writer::reset() +		 */ +		function reset() +		{ +		} + +		/** +		 * @see Writer::close() +		 */ +		function close() +		{ +		} +		 +		/** +		 * @see Writer::open() +		 */ +		function open() +		{ +		} +		 +		/** +		 * @see Writer::getResource() +		 */ +		function getResource() +		{ +			return $this->task; +		} +	} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/PathTokenizer.php b/buildscripts/phing/classes/phing/util/PathTokenizer.php new file mode 100644 index 00000000..29c0f059 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/PathTokenizer.php @@ -0,0 +1,245 @@ +<?php +/* + *  $Id: PathTokenizer.php,v 1.3 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + + + +include_once 'phing/util/StringHelper.php'; + + + +/** + + * A Path tokenizer takes a path and returns the components that make up + + * that path. + + * + + * The path can use path separators of either ':' or ';' and file separators + + * of either '/' or '\'. + + * + + * @author Hans Lellelid <hans@xmpl.org> (Phing) + + * @author Conor MacNeill (Ant) + + * @author Jeff Tulley <jtulley@novell.com>  (Ant) + + * @pacakge phing.util + + */  + +class PathTokenizer { + +     + +    /** + +     * A array of tokens, created by preg_split(). + +     */ + +    private $tokens = array(); + +     + +    /** + +     * A string which stores any path components which have been read ahead + +     * due to DOS filesystem compensation. + +     * @var string + +     */ + +    private $lookahead; + +     + +    /** + +     * Flag to indicate whether or not we are running on a platform with a + +     * DOS style filesystem + +     * @var boolean + +     */ + +    private $dosStyleFilesystem; + + + +    /** + +     * Constructs a path tokenizer for the specified path. + +     *  + +     * @param path The path to tokenize. Must not be <code>null</code>. + +     */ + +    public function __construct($path) { + +        // on Windows and Unix, we can ignore delimiters and still have + +        // enough information to tokenize correctly.     + +        $this->tokens = preg_split("/[;:]/", $path, -1, PREG_SPLIT_NO_EMPTY); + +        $this->dosStyleFilesystem = ( PATH_SEPARATOR == ';'); + +    } + + + +    /** + +     * Tests if there are more path elements available from this tokenizer's + +     * path. If this method returns <code>true</code>, then a subsequent call  + +     * to nextToken will successfully return a token. + +     *  + +     * @return <code>true</code> if and only if there is at least one token  + +     * in the string after the current position; <code>false</code> otherwise. + +     */ + +    public function hasMoreTokens() { + +        if ($this->lookahead !== null) { + +            return true; + +        }         + +        return !empty($this->tokens); + +    } + +     + +    /** + +     * Returns the next path element from this tokenizer. + +     *  + +     * @return the next path element from this tokenizer. + +     *  + +     * @throws Exception if there are no more elements in this tokenizer's path. + +     */ + +    public function nextToken() { + +             + +        if ($this->lookahead !== null) { + +            $token = $this->lookahead; + +            $this->lookahead = null; + +        } else { + +            $token = trim(array_shift($this->tokens)); + +        } + +             + + + +        if (strlen($token) === 1 && Character::isLetter($token{0}) + +                                && $this->dosStyleFilesystem + +                                && !empty($this->tokens)) { + +            // we are on a dos style system so this path could be a drive + +            // spec. We look at the next token + +            $nextToken = trim(array_shift($this->tokens)); + +            if (StringHelper::startsWith('\\', $nextToken) || StringHelper::startsWith('/', $nextToken)) { + +                // we know we are on a DOS style platform and the next path + +                // starts with a slash or backslash, so we know this is a  + +                // drive spec + +                $token .= ':' . $nextToken; + +            } else { + +                // store the token just read for next time + +                $this->lookahead = $nextToken; + +            } + +        } + +         + +        return $token; + +    } + + + +    /** + +     * Non StringTokenizer function, that indicates whether the specified path is contained in loaded tokens. + +     * We can do this easily because in PHP implimentation we're using arrays. + +     * @param string $path path to search for. + +     * @return boolean + +     */ + +    public function contains($path) { + +        return in_array($path, $this->tokens, true);         + +    } + +     + +} + + + diff --git a/buildscripts/phing/classes/phing/util/SourceFileScanner.php b/buildscripts/phing/classes/phing/util/SourceFileScanner.php new file mode 100644 index 00000000..b157dcb9 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/SourceFileScanner.php @@ -0,0 +1,159 @@ +<?php +/* + *  $Id: SourceFileScanner.php,v 1.11 2005/05/26 13:10:53 mrook Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + *  Utility class that collects the functionality of the various + *  scanDir methods that have been scattered in several tasks before. + * + *  The only method returns an array of source files. The array is a + *  subset of the files given as a parameter and holds only those that + *  are newer than their corresponding target files. + *  @package   phing.util + */ +class SourceFileScanner { + +    /** Instance of FileUtils */ +    private $fileUtils; +     +    /** Task this class is working for -- for logging purposes. */ +    private $task; + +    /** +     * @param task The task we should log messages through +     */ +    function __construct($task) { +        $this->task = $task; +        $this->fileUtils = new FileUtils(); +    } + +    /** +     * Restrict the given set of files to those that are newer than +     * their corresponding target files. +     * +     * @param files   the original set of files +     * @param srcDir  all files are relative to this directory +     * @param destDir target files live here. if null file names +     *                returned by the mapper are assumed to be absolute. +     * @param FilenameMapper  knows how to construct a target file names from +     *                source file names. +     * @param force   Boolean that determines if the files should be +     *                forced to be copied. +     */ +    function restrict(&$files, $srcDir, $destDir, $mapper, $force = false) { +        $now = time(); +        $targetList = ""; + +        /* +          If we're on Windows, we have to munge the time up to 2 secs to +          be able to check file modification times. +          (Windows has a max resolution of two secs for modification times) +        */ +        $osname = strtolower(Phing::getProperty('os.name')); + +        // indexOf() +        $index = ((($res = strpos($osname, 'win')) === false) ? -1 : $res); +        if ($index  >= 0 ) { +            $now += 2000; +        } + +        $v = array(); + +        for ($i=0, $size=count($files); $i < $size; $i++) { +         +            $targets = $mapper->main($files[$i]); +            if (empty($targets)) { +                $this->task->log($files[$i]." skipped - don't know how to handle it", PROJECT_MSG_VERBOSE); +                continue; +            } + +            $src = null; +            try { +                if ($srcDir === null) { +                    $src = new PhingFile($files[$i]); +                } else { +                    $src = $this->fileUtils->resolveFile($srcDir, $files[$i]); +                } +     +                if ($src->lastModified() > $now) { +                    $this->task->log("Warning: ".$files[$i]." modified in the future (".$src->lastModified()." > ".$now.")", PROJECT_MSG_WARN); +                } +            } catch (IOException $ioe) { +                $this->task->log("Unable to read file ".$files[$i]." (skipping): " . $ioe->getMessage()); +                continue; +            } +             +            $added = false; +            $targetList = ""; + +            for ($j=0,$_j=count($targets); (!$added && $j < $_j); $j++) { + +                $dest = null; +                if ($destDir === null) { +                    $dest = new PhingFile($targets[$j]); +                } else { +                    $dest = $this->fileUtils->resolveFile($destDir, $targets[$j]); +                } + +                if (!$dest->exists()) { +                    $this->task->log($files[$i]." added as " . $dest->__toString() . " doesn't exist.", PROJECT_MSG_VERBOSE); +                    $v[] =$files[$i]; +                    $added = true; +                } elseif ($src->lastModified() > $dest->lastModified()) { +                    $this->task->log($files[$i]." added as " . $dest->__toString() . " is outdated.", PROJECT_MSG_VERBOSE ); +                    $v[]=$files[$i]; +                    $added = true; +                } elseif ($force === true) { +                    $this->task->log($files[$i]." added as " . $dest->__toString() . " is forced to be overwritten.", PROJECT_MSG_VERBOSE ); +                    $v[]=$files[$i]; +                    $added = true; +                } else { +                    if (strlen($targetList) > 0) { +                        $targetList .= ", "; +                    } +                    $targetList .= $dest->getAbsolutePath(); +                } +            } + +            if (!$added) { +                $this->task->log($files[$i]." omitted as ".$targetList." ".(count($targets) === 1 ? " is " : " are ")."up to date.",  PROJECT_MSG_VERBOSE); +            } + +        } +        $result = array(); +        $result = $v; +        return $result; +    } + +    /** +     * Convenience layer on top of restrict that returns the source +     * files as PhingFile objects (containing absolute paths if srcDir is +     * absolute). +     */ +    function restrictAsFiles(&$files, &$srcDir, &$destDir, &$mapper) { +        $res = $this->restrict($files, $srcDir, $destDir, $mapper); +        $result = array(); +        for ($i=0; $i<count($res); $i++) { +            $result[$i] = new PhingFile($srcDir, $res[$i]); +        } +        return $result; +    } +} +?> diff --git a/buildscripts/phing/classes/phing/util/StringHelper.php b/buildscripts/phing/classes/phing/util/StringHelper.php new file mode 100644 index 00000000..5d4bfd7a --- /dev/null +++ b/buildscripts/phing/classes/phing/util/StringHelper.php @@ -0,0 +1,209 @@ +<?php + +/** + * String helper utility class. + * + * This class includes some Java-like functions for parsing strings, + * as well as some functions for getting qualifiers / unqualifying phing-style + * classpaths.  (e.g. "phing.util.StringHelper"). + * + * @author Hans Lellelid <hans@xmpl.org> + * @package phing.system.util + */ +class StringHelper { + +    private static $TRUE_VALUES = array("on", "true", "t", "yes"); +    private static $FALSE_VALUES = array("off", "false", "f", "no"); +     +    /** +     * Replaces identifier tokens with corresponding text values in passed string. +     * +     * @params array $strings Array of strings to multiply. (If string is passed, will convert to array) +     * @params array $tokens The tokens to search for. +     * @params array $replacements The values with which to replace found tokens. +     * @return string +     */ +    public static function multiply($strings, $tokens, $replacements) { +        $strings = (array) $strings; +        $results = array(); +        foreach ($strings as $string) { +            $results[] = str_replace($tokens, $replacements, $string); +        }         +        return $results; +    } + +    /** +     * Remove qualification to name. +     * E.g. eg.Cat -> Cat +     * @param string $qualifiedName +     * @param string $separator Character used to separate. +     */ +    public static function unqualify($qualifiedName, $separator = '.') { +        // if false, then will be 0 +        $pos = strrpos($qualifiedName, $separator); +        if ($pos === false) {  +            return $qualifiedName;  // there is no '.' in the qualifed name +        } else { +            return substr($qualifiedName, $pos + 1); // start just after '.' +        } +    } + +    /**  +     * Converts a string to an indexed array of chars +     * There's really no reason for this to be used in PHP, since strings +     * are all accessible using the $string{0} notation. +     * @param string $string +     * @return array +     * @deprecated +     */ +    public static function toCharArray($str) { +        $ret=array(); +        $len=strlen($str); +        for ($i=0; $i < $len; $i++) { +            $ret[] = $str{$i}; +        } +        return $ret; +    } +     +    /** +     * Get the qualifier part of a qualified name. +     * E.g. eg.Cat -> eg +     * @return string +     */     +    public static function qualifier($qualifiedName, $seperator = '.') { +        $pos = strrchr($qualifiedName, $seperator); +        if ($pos === false) { +            return ''; +        } else { +            return substr($qualifiedName, 0, $pos); +        } +    } +     +    /** +     * @param array $columns String[] +     * @param string $prefix +     * @return array String[] +     */  +    public static function prefix( $columns, $prefix) { +        if ($prefix == null) return $columns; +        $qualified = array(); +        foreach($columns as $key => $column) { +            $qualified[$key] = $prefix . $column; +        }         +        return $qualified; +    } +     +    /** +     * +     * @return string +     */  +    public static function root($qualifiedName, $separator = '.') { +        $loc = strpos($qualifiedName, $separator); +        return ($loc === false) ? $qualifiedName : substr($qualifiedName, 0, $loc); +    } +     +    /** +     * @return int +     */ +    public static function hashCode($string) { +        return crc32($string); +    } +     +    /** +     * @return boolean +     */  +    public static function booleanValue($s) { +        if (is_bool($s)) { +            return $s; // it's already boolean (not a string) +        } +        // otherwise assume it's something like "true" or "t" +        $trimmed = strtolower(trim($s)); +        return (boolean) in_array($trimmed, self::$TRUE_VALUES); +    } + +    /** tests if a string is a representative of a boolean */ +    public static function isBoolean($s) { + +        if (is_bool($s)) { +            return true; // it already is boolean +        } +         +        if ($s === "" || $s === null || !is_string($s)) { +            return false; // not a valid string for testing +        } + +        $test = trim(strtolower($s)); +        return (boolean) in_array($test, array_merge(self::$FALSE_VALUES, self::$TRUE_VALUES)); +    } +         +    /** +     * Creates a key based on any number of passed params. +     * @return string +     */ +    public static function key() { +        $args = func_get_args(); +        return serialize($args); +    }     +     +    /** tests if a string starts with a given string */ +    public static function startsWith($check, $string) { +        if ($check === "" || $check === $string) { +            return true; +        } else { +            return (strpos($string, $check) === 0) ? true : false; +        } +    } +     +    /** tests if a string ends with a given string */ +    public static function endsWith($check, $string) { +        if ($check === "" || $check === $string) { +            return true; +        } else { +            return (strpos(strrev($string), strrev($check)) === 0) ? true : false; +        } +    }             + +    /** +     * a natural way of getting a subtring, php's circular string buffer and strange +     * return values suck if you want to program strict as of C or friends  +     */ +    public static function substring($string, $startpos, $endpos = -1) { +        $len    = strlen($string); +        $endpos = (int) (($endpos === -1) ? $len-1 : $endpos); +        if ($startpos > $len-1 || $startpos < 0) { +            trigger_error("substring(), Startindex out of bounds must be 0<n<$len", E_USER_ERROR); +        } +        if ($endpos > $len-1 || $endpos < $startpos) { +            trigger_error("substring(), Endindex out of bounds must be $startpos<n<".($len-1), E_USER_ERROR); +        } +        if ($startpos === $endpos) { +            return (string) $string{$startpos}; +        } else { +            $len = $endpos-$startpos; +        } +        return substr($string, $startpos, $len+1); +    } + +    /** +     * Does the value correspond to a slot variable? +     * @param string $value     +     */ +    public static function isSlotVar($value) { +        $value = trim($value); +        if ($value === "") return false; +        return preg_match('/^%\{([\w\.\-]+)\}$/', $value); +    } +     +    /** +     * Extracts the variable name for a slot var in the format %{task.current_file} +     * @param string $var The var from build file. +     * @return string Extracted name part. +     */ +    public static function slotVar($var) { +        return trim($var, '%{} '); +    } +     +} + + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/PregEngine.php b/buildscripts/phing/classes/phing/util/regexp/PregEngine.php new file mode 100644 index 00000000..758b40f3 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/PregEngine.php @@ -0,0 +1,105 @@ +<?php +/*  + *  $Id: PregEngine.php,v 1.6 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +require_once 'phing/util/regexp/RegexpEngine.php'; + +/** + * PREG Regexp Engine. + * Implements a regexp engine using PHP's preg_match(), preg_match_all(), and preg_replace() functions. + *  + * @author hans lellelid, hans@velum.net + * @package phing.util.regex + */ +class PregEngine implements RegexpEngine { + +    /** +     * @var boolean +     */ +    private $ignoreCase = false; +         +    /** +     * Sets whether or not regex operation is case sensitive. +     * @param boolean $bit +     * @return void +     */ +    function setIgnoreCase($bit) { +        $this->ignoreCase = (boolean) $bit; +    } + +    /** +     * Gets whether or not regex operation is case sensitive. +     * @return boolean +     */ +    function getIgnoreCase() { +        return $this->ignoreCase; +    } +         +    /** +     * The pattern needs to be converted into PREG style -- which includes adding expression delims & any flags, etc. +     * @param string $pattern +     * @return string prepared pattern. +     */ +    private function preparePattern($pattern) +    { +        return '/'.$pattern.'/'.($this->ignoreCase ? 'i' : ''); +    } +     +    /** +     * Matches pattern against source string and sets the matches array. +     * @param string $pattern The regex pattern to match. +     * @param string $source The source string. +     * @param array $matches The array in which to store matches. +     * @return boolean Success of matching operation. +     */ +    function match($pattern, $source, &$matches) {  +        return preg_match($this->preparePattern($pattern), $source, $matches); +    } + +    /** +     * Matches all patterns in source string and sets the matches array. +     * @param string $pattern The regex pattern to match. +     * @param string $source The source string. +     * @param array $matches The array in which to store matches. +     * @return boolean Success of matching operation. +     */         +    function matchAll($pattern, $source, &$matches) { +        return preg_match_all($this->preparePattern($pattern), $source, $matches); +    } + +    /** +     * Replaces $pattern with $replace in $source string. +     * References to \1 group matches will be replaced with more preg-friendly +     * $1. +     * @param string $pattern The regex pattern to match. +     * @param string $replace The string with which to replace matches. +     * @param string $source The source string. +     * @return string The replaced source string. +     */         +    function replace($pattern, $replace, $source) { +        // convert \1 -> $1, because we want to use the more generic \1 in the XML +        // but PREG prefers $1 syntax. +        $replace = preg_replace('/[^\\\]\\\(\d+)/', '$1', $replace); +        return preg_replace($this->preparePattern($pattern), $replace, $source); +    } + +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/Regexp.php b/buildscripts/phing/classes/phing/util/regexp/Regexp.php new file mode 100644 index 00000000..68c06668 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/Regexp.php @@ -0,0 +1,168 @@ +<?php +/*  + *  $Id: Regexp.php,v 1.5 2003/12/24 18:40:33 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * A factory class for regex functions. + * @author Hans Lellelid <hans@xmpl.org> + * @package  phing.util.regexp + * @version $Revision: 1.5 $ + */ +class Regexp { + +    /** +     * Matching groups found.  +     * @var array +     */ +    private $groups = array(); +      +    /** +     * Pattern to match. +     * @var string +     */ +    private $pattern; +     +    /** +     * Replacement pattern. +     * @var string +     */ +    private $replace; +     +    /** +     * The regex engine -- e.g. 'preg' or 'ereg'; +     * @var RegexpEngine +     */ +    private $engine; +     +    /** +     * Constructor sets the regex engine to use (preg by default). +     * @param string $_engineType The regex engine to use. +     */ +    function __construct($engineType='preg') {         +        if ($engineType == 'preg') { +            include_once 'phing/util/regexp/PregEngine.php'; +            $this->engine = new PregEngine(); +        } elseif ($engineType == 'ereg') { +            include_once 'phing/util/regexp/EregEngine.php'; +            $this->engine = new EregEngine(); +        } else { +            throw new BuildException("Invalid engine type for Regexp: " . $engineType); +        }                 +    } + +    /** +     * Sets pattern to use for matching. +     * @param string $pat The pattern to match on. +     * @return void +     */ +    public function setPattern($pat) { +        $this->pattern = (string) $pat;         +    } +     +     +    /** +     * Gets pattern to use for matching. +     * @return string The pattern to match on. +     */ +    public function getPattern() { +        return $this->pattern; +    } +     +    /** +     * Sets replacement string. +     * @param string $rep The pattern to replace matches with. +     * @return void +     */ +    public function setReplace($rep) { +        $this->replace = (string) $rep; +    } +     +    /** +     * Gets replacement string. +     * @return string The pattern to replace matches with. +     * @return void +     */ +    public function getReplace() { +        return $this->replace; +    } +     +    /** +     * Performs match of specified pattern against $subject. +     * @param string $subject The subject, on which to perform matches. +     * @return boolean Whether or not pattern matches subject string passed. +     */ +    public function matches($subject) { +        if($this->pattern === null) {             +            throw new Exception("No pattern specified for regexp match()."); +        } +        return $this->engine->match($this->pattern, $subject, $this->groups); +    } +     +    /** +     * Performs replacement of specified pattern and replacement strings. +     * @param string $subject Text on which to perform replacement. +     * @return string subject after replacement has been performed. +     */ +    public function replace($subject) { +        if ($this->pattern === null || $this->replace === null) { +            throw new Exception("Missing pattern or replacement string regexp replace()."); +        }         +        return $this->engine->replace($this->pattern, $this->replace, $subject); +    } +     +    /** +     * Get array of matched groups. +     * @return array Matched groups +     */  +    function getGroups() { +        return $this->groups; +    } + +    /** +     * Get specific matched group.  +     * @param integer $idx +     * @return string specified group or NULL if group is not set. +     */  +    function getGroup($idx) {  +        if (!isset($this->groups[$idx])) { +            return null; +        } +        return $this->groups[$idx]; +    } +     +    /** +     * Sets whether the regexp matching is case insensitive. +     * (default is false -- i.e. case sensisitive) +     * @param boolean $bit +     */  +    function setIgnoreCase($bit) { +        $this->engine->setIgnoreCase($bit); +    } +     +    /** +     * Gets whether the regexp matching is case insensitive. +     * @return boolean +     */ +    function getIgnoreCase() { +        return $this->engine->getIgnoreCase(); +    } +}  + +?>
\ No newline at end of file diff --git a/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php new file mode 100644 index 00000000..7d323466 --- /dev/null +++ b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php @@ -0,0 +1,74 @@ +<?php +/*  + *  $Id: RegexpEngine.php,v 1.4 2003/12/24 12:38:42 hlellelid Exp $ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>.  + */ + +/** + * Contains some shared attributes and methods -- and some abstract methods with + * engine-specific implementations that sub-classes must override. + *  + * @author Hans Lellelid <hans@velum.net> + * @package phing.util.regex + * @version $Revision: 1.4 $ + */ +interface RegexpEngine { +     +    /** +     * Sets whether or not regex operation should ingore case. +     * @param boolean $bit +     * @return void +     */ +    public function setIgnoreCase($bit); +     +    /** +     * Returns status of ignore case flag. +     * @return boolean +     */ +    public function getIgnoreCase(); +     +    /** +     * Matches pattern against source string and sets the matches array. +     * @param string $pattern The regex pattern to match. +     * @param string $source The source string. +     * @param array $matches The array in which to store matches. +     * @return boolean Success of matching operation. +     */ +    function match($pattern, $source, &$matches); +     +    /** +     * Matches all patterns in source string and sets the matches array. +     * @param string $pattern The regex pattern to match. +     * @param string $source The source string. +     * @param array $matches The array in which to store matches. +     * @return boolean Success of matching operation. +     */     +    function matchAll($pattern, $source, &$matches); + +    /** +     * Replaces $pattern with $replace in $source string. +     * @param string $pattern The regex pattern to match. +     * @param string $replace The string with which to replace matches. +     * @param string $source The source string. +     * @return string The replaced source string. +     */         +    function replace($pattern, $replace, $source); + +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/etc/VERSION.TXT b/buildscripts/phing/etc/VERSION.TXT new file mode 100644 index 00000000..00fa3b83 --- /dev/null +++ b/buildscripts/phing/etc/VERSION.TXT @@ -0,0 +1 @@ +Phing 2.2 BRANCH (SVN)
\ No newline at end of file diff --git a/buildscripts/phing/etc/coverage-frames.xsl b/buildscripts/phing/etc/coverage-frames.xsl new file mode 100644 index 00000000..5e8d8e3e --- /dev/null +++ b/buildscripts/phing/etc/coverage-frames.xsl @@ -0,0 +1,669 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" +    xmlns:exsl="http://exslt.org/common" +    xmlns:date="http://exslt.org/dates-and-times" +    extension-element-prefixes="exsl date"> +<xsl:output method="html" indent="yes"/> +<xsl:decimal-format decimal-separator="." grouping-separator="," /> +<!-- +    Copyright  2001-2004 The Apache Software Foundation +    +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at +    +         http://www.apache.org/licenses/LICENSE-2.0 +    +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. +    +--> + +<!-- + + Sample stylesheet to be used with Xdebug/Phing code coverage output. + Based on JProbe stylesheets from Apache Ant. + + It creates a set of HTML files a la javadoc where you can browse easily + through all packages and classes. + + @author Michiel Rook <a href="mailto:michiel@trendserver.nl"/> + @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/> + +--> + +<!-- default output directory is current directory --> +<xsl:param name="output.dir" select="'.'"/> + +<!-- ====================================================================== +    Root element +    ======================================================================= --> +<xsl:template match="/snapshot"> +    <!-- create the index.html --> +    <exsl:document href="efile://{$output.dir}/index.html"> +        <xsl:call-template name="index.html"/> +    </exsl:document> + +    <!-- create the stylesheet.css --> +    <exsl:document href="efile://{$output.dir}/stylesheet.css"> +        <xsl:call-template name="stylesheet.css"/> +    </exsl:document> + +    <!-- create the overview-packages.html at the root --> +    <exsl:document href="efile://{$output.dir}/overview-summary.html"> +        <xsl:apply-templates select="." mode="overview.packages"/> +    </exsl:document> + +    <!-- create the all-packages.html at the root --> +    <exsl:document href="efile://{$output.dir}/overview-frame.html"> +        <xsl:apply-templates select="." mode="all.packages"/> +    </exsl:document> + +    <!-- create the all-classes.html at the root --> +    <exsl:document href="efile://{$output.dir}/allclasses-frame.html"> +        <xsl:apply-templates select="." mode="all.classes"/> +    </exsl:document> + +    <!-- process all packages --> +    <xsl:apply-templates select="./package" mode="write"/> +</xsl:template> + +<!-- ======================================================================= +    Frameset definition. Entry point for the report. +    3 frames: packageListFrame, classListFrame, classFrame +    ======================================================================= --> +<xsl:template name="index.html"> +<html> +    <head><title>Coverage Results.</title></head> +    <frameset cols="20%,80%"> +        <frameset rows="30%,70%"> +            <frame src="overview-frame.html" name="packageListFrame"/> +            <frame src="allclasses-frame.html" name="classListFrame"/> +        </frameset> +        <frame src="overview-summary.html" name="classFrame"/> +    </frameset> +    <noframes> +        <h2>Frame Alert</h2> +        <p> +        This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +        </p> +    </noframes> +</html> +</xsl:template> + +<!-- ======================================================================= +    Stylesheet CSS used +    ======================================================================= --> +<!-- this is the stylesheet css to use for nearly everything --> +<xsl:template name="stylesheet.css"> +    .bannercell { +      border: 0px; +      padding: 0px; +    } +    body { +      margin-left: 10; +      margin-right: 10; +      background-color:#FFFFFF; +      font-family: verdana,arial,sanserif; +      color:#000000; +    } +    a { +      color: #003399; +    } +    a:hover { +      color: #888888; +    } +    .a td { +      background: #efefef; +    } +    .b td { +      background: #fff; +    } +    th, td { +      text-align: left; +      vertical-align: top; +    } +    th { +      font-weight:bold; +      background: #ccc; +      color: black; +    } +    table, th, td { +      font-size: 12px; +      border: none +    } +    table.log tr td, tr th { +    } +    h2 { +      font-weight:bold; +      font-size: 12px; +      margin-bottom: 5; +    } +    h3 { +      font-size:100%; +      font-weight: 12px; +       background: #DFDFDF +      color: white; +      text-decoration: none; +      padding: 5px; +      margin-right: 2px; +      margin-left: 2px; +      margin-bottom: 0; +    } +    .small { +       font-size: 9px; +    } +TD.empty { +    FONT-SIZE: 2px; BACKGROUND: #c0c0c0; BORDER:#9c9c9c 1px solid; +    color: #c0c0c0; +} +TD.fullcover { +    FONT-SIZE: 2px; BACKGROUND: #00df00; BORDER:#9c9c9c 1px solid; +    color: #00df00; +} +TD.covered { +    FONT-SIZE: 2px; BACKGROUND: #00df00; BORDER-LEFT:#9c9c9c 1px solid;BORDER-TOP:#9c9c9c 1px solid;BORDER-BOTTOM:#9c9c9c 1px solid; +    color: #00df00; +} +TD.uncovered { +    FONT-SIZE: 2px; BACKGROUND: #df0000; BORDER:#9c9c9c 1px solid; +    color: #df0000; +} +PRE.srcLine { +  BACKGROUND: #ffffff; MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px;  +} +td.lineCount, td.coverageCount { +      BACKGROUND: #F0F0F0; PADDING-RIGHT: 3px; +      text-align: right; +} +td.lineCountHighlight { +      background: #C8C8F0; PADDING-RIGHT: 3px; +      text-align: right; +} +td.coverageCountHighlight { +      background: #F0C8C8; PADDING-RIGHT: 3px; +      text-align: right; +} +span.srcLineHighlight { +      background: #F0C8C8; +} +span.srcLine { +      background: #C8C8F0; +} +TD.srcLineClassStart { +   WIDTH: 100%; BORDER-TOP:#dcdcdc 1px solid; FONT-WEIGHT: bold;     +} +.srcLine , .srcLine ol, .srcLine ol li {margin: 0;} +.srcLine .de1, .srcLine .de2 {font-family: 'Courier New', Courier, monospace; font-weight: normal;} +.srcLine .imp {font-weight: bold; color: red;} +.srcLine .kw1 {color: #b1b100;} +.srcLine .kw2 {color: #000000; font-weight: bold;} +.srcLine .kw3 {color: #000066;} +.srcLine .co1 {color: #808080; font-style: italic;} +.srcLine .co2 {color: #808080; font-style: italic;} +.srcLine .coMULTI {color: #808080; font-style: italic;} +.srcLine .es0 {color: #000099; font-weight: bold;} +.srcLine .br0 {color: #66cc66;} +.srcLine .st0 {color: #ff0000;} +.srcLine .nu0 {color: #cc66cc;} +.srcLine .me1 {color: #006600;} +.srcLine .me2 {color: #006600;} +.srcLine .re0 {color: #0000ff;} +</xsl:template> + +<!-- ======================================================================= +    List of all classes in all packages +    This will be the first page in the classListFrame +    ======================================================================= --> +<xsl:template match="snapshot" mode="all.classes"> +    <html> +        <head> +            <xsl:call-template name="create.stylesheet.link"/> +        </head> +        <body> +            <h2>All Classes</h2> +            <table width="100%"> +                <xsl:for-each select="package/class"> +                    <xsl:sort select="@name"/> +                    <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/> +                    <xsl:variable name="link"> +                        <xsl:if test="not($package.name='')"> +                            <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text> +                        </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text> +                    </xsl:variable> +                    <tr> +                        <td nowrap="nowrap"> +                            <a target="classFrame" href="{$link}"><xsl:value-of select="@name"/></a> +                            <xsl:choose> +								<xsl:when test="@totalcount=0"> +									<i> (-)</i> +								</xsl:when> +								<xsl:otherwise> +									<i> (<xsl:value-of select="format-number(@totalcovered div @totalcount, '0.0%')"/>)</i> +								</xsl:otherwise> +							</xsl:choose> +                        </td> +                    </tr> +                </xsl:for-each> +            </table> +        </body> +    </html> +</xsl:template> + +<!-- list of all packages --> +<xsl:template match="snapshot" mode="all.packages"> +    <html> +        <head> +            <xsl:call-template name="create.stylesheet.link"/> +        </head> +        <body> +            <h2><a href="overview-summary.html" target="classFrame">Overview</a></h2> +            <h2>All Packages</h2> +            <table width="100%"> +                <xsl:for-each select="package"> +                    <xsl:sort select="@name" order="ascending"/> +                    <tr> +                        <td nowrap="nowrap"> +                            <a href="{translate(@name,'.','/')}/package-summary.html" target="classFrame"> +                                <xsl:value-of select="@name"/> +                            </a> +                        </td> +                    </tr> +                </xsl:for-each> +            </table> +        </body> +    </html> +</xsl:template> + +<!-- overview of statistics in packages --> +<xsl:template match="snapshot" mode="overview.packages"> +    <html> +        <head> +            <xsl:call-template name="create.stylesheet.link"/> +        </head> +        <body onload="open('allclasses-frame.html','classListFrame')"> +        <xsl:call-template name="pageHeader"/> +        <table class="log" cellpadding="5" cellspacing="0" width="100%"> +            <tr class="a"> +                <td class="small">Packages: <xsl:value-of select="count(package)"/></td> +                <td class="small">Classes: <xsl:value-of select="count(package/class)"/></td> +                <td class="small">Methods: <xsl:value-of select="@methodcount"/></td> +                <td class="small">LOC: <xsl:value-of select="count(package/class/sourcefile/sourceline)"/></td> +                <td class="small">Statements: <xsl:value-of select="@statementcount"/></td> +            </tr> +        </table>         +        <br/> + +        <table class="log" cellpadding="5" cellspacing="0" width="100%"> +            <tr> +                <th width="100%" nowrap="nowrap"></th> +                <th>Statements</th> +                <th>Methods</th> +                <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> +            </tr> +            <tr class="a"> +        	<td><b>Project</b></td> +                <xsl:call-template name="stats.formatted"/> +            </tr> +            <tr> +                <td colspan="3"><br/></td> +            </tr> +            <tr> +                <th width="100%">Packages</th> +                <th>Statements</th> +                <th>Methods</th> +                <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> +            </tr> +            <!-- display packages and sort them via their coverage rate --> +            <xsl:for-each select="package"> +                <xsl:sort data-type="number" select="@totalcovered div @totalcount"/> +                <tr> +                  <xsl:call-template name="alternate-row"/> +                    <td><a href="{translate(@name,'.','/')}/package-summary.html"><xsl:value-of select="@name"/></a></td> +                    <xsl:call-template name="stats.formatted"/> +                </tr> +            </xsl:for-each> +        </table> +        <xsl:call-template name="pageFooter"/> +        </body> +        </html> +</xsl:template> + +<!-- + detailed info for a package. It will output the list of classes +, the summary page, and the info for each class +--> +<xsl:template match="package" mode="write"> +    <xsl:variable name="package.dir"> +        <xsl:if test="not(@name = '')"><xsl:value-of select="translate(@name,'.','/')"/></xsl:if> +        <xsl:if test="@name = ''">.</xsl:if> +    </xsl:variable> + +    <!-- create a classes-list.html in the package directory --> +    <exsl:document href="efile://{$output.dir}/{$package.dir}/package-frame.html"> +        <xsl:apply-templates select="." mode="classes.list"/> +    </exsl:document> + +    <!-- create a package-summary.html in the package directory --> +    <exsl:document href="efile://{$output.dir}/{$package.dir}/package-summary.html"> +        <xsl:apply-templates select="." mode="package.summary"/> +    </exsl:document> + +    <!-- for each class, creates a @name.html --> +    <xsl:for-each select="class"> +        <exsl:document href="efile://{$output.dir}/{$package.dir}/{@name}.html"> +            <xsl:apply-templates select="." mode="class.details"/> +        </exsl:document> +    </xsl:for-each> +</xsl:template> + +<!-- list of classes in a package --> +<xsl:template match="package" mode="classes.list"> +    <html> +        <HEAD> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="@name"/> +            </xsl:call-template> +        </HEAD> +        <BODY> +            <table width="100%"> +                <tr> +                    <td nowrap="nowrap"> +                        <H2><a href="package-summary.html" target="classFrame"><xsl:value-of select="@name"/></a></H2> +                    </td> +                </tr> +            </table> + +            <H2>Classes</H2> +            <TABLE WIDTH="100%"> +                <xsl:for-each select="class"> +                    <xsl:sort select="@name"/> +                    <tr> +                        <td nowrap="nowrap"> +                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a> +                            <xsl:choose> +								<xsl:when test="@totalcount=0"> +									<i> (-)</i> +								</xsl:when> +								<xsl:otherwise> +                            		<i>(<xsl:value-of select="format-number(@totalcovered div @totalcount, '0.0%')"/>)</i> +                            	</xsl:otherwise> +                            </xsl:choose> +                        </td> +                    </tr> +                </xsl:for-each> +            </TABLE> +        </BODY> +    </html> +</xsl:template> + +<!-- summary of a package --> +<xsl:template match="package" mode="package.summary"> +    <HTML> +        <HEAD> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="@name"/> +            </xsl:call-template> +        </HEAD> +        <!-- when loading this package, it will open the classes into the frame --> +        <BODY onload="open('package-frame.html','classListFrame')"> +            <xsl:call-template name="pageHeader"/> +            <table class="log" cellpadding="5" cellspacing="0" width="100%"> +                <tr class="a"> +                    <td class="small">Classes: <xsl:value-of select="count(class)"/></td> +                    <td class="small">Methods: <xsl:value-of select="@methodcount"/></td> +                    <td class="small">LOC: <xsl:value-of select="count(class/sourcefile/sourceline)"/></td> +                    <td class="small">Statements: <xsl:value-of select="@statementcount"/></td> +                </tr> +            </table>         +            <br/> + +            <table class="log" cellpadding="5" cellspacing="0" width="100%"> +                <tr> +                    <th width="100%">Package</th> +                    <th>Statements</th> +                    <th>Methods</th> +                    <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> +                </tr> +                <xsl:apply-templates select="." mode="stats"/> + +                <xsl:if test="count(class) > 0"> +                    <tr> +                        <td colspan="3"><br/></td> +                    </tr> +                    <tr> +                        <th width="100%">Classes</th> +                        <th>Statements</th> +                        <th>Methods</th> +                        <th width="350" colspan="2" nowrap="nowrap">Total coverage</th> +                    </tr> +                    <xsl:apply-templates select="class" mode="stats"> +                        <xsl:sort data-type="number" select="@totalcovered div @totalcount"/> +                    </xsl:apply-templates> +                </xsl:if> +            </table> +            <xsl:call-template name="pageFooter"/> +        </BODY> +    </HTML> +</xsl:template> + +<!-- details of a class --> +<xsl:template match="class" mode="class.details"> +    <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/> +    <HTML> +        <HEAD> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="$package.name"/> +            </xsl:call-template> +        </HEAD> +        <BODY> +            <xsl:call-template name="pageHeader"/> +            <table class="log" cellpadding="5" cellspacing="0" width="100%"> +                <tr class="a"> +                    <td class="small">Methods: <xsl:value-of select="@methodcount"/></td> +                    <td class="small">LOC: <xsl:value-of select="count(sourcefile/sourceline)"/></td> +                    <td class="small">Statements: <xsl:value-of select="@statementcount"/></td> +                </tr> +            </table>         +            <br/> + +            <!-- class summary --> +            <table class="log" cellpadding="5" cellspacing="0" width="100%"> +                <tr> +                    <th width="100%">Source file</th> +                    <th>Statements</th> +                    <th>Methods</th> +                    <th width="250" colspan="2" nowrap="nowrap">Total coverage</th> +                </tr> +                <tr> +                    <xsl:call-template name="alternate-row"/> +                    <td><xsl:value-of select="sourcefile/@name"/></td> +                    <xsl:call-template name="stats.formatted"/> +                </tr> +            </table> +            <table cellspacing="0" cellpadding="0" width="100%"> +                <xsl:apply-templates select="sourcefile/sourceline"/> +            </table> +            <br/> +            <xsl:call-template name="pageFooter"/> +        </BODY> +    </HTML> + +</xsl:template> + +<!-- Page Header --> +<xsl:template name="pageHeader"> +  <!-- jakarta logo --> +  <table border="0" cellpadding="0" cellspacing="0" width="100%"> +  <tr> +    <td class="bannercell" rowspan="2"> +      <a href="http://phing.info/"> +      <img src="http://phing.info/images/phing.gif" alt="http://phing.info/" align="left" border="0"/> +      </a> +    </td> +        <td style="text-align:right"><h2>Source Code Coverage</h2></td> +        </tr> +        <tr> +        <td style="text-align:right">Designed for use with <a href='http://pear.php.net/package/PHPUnit2'>PHPUnit2</a>, <a href='http://www.xdebug.org/'>Xdebug</a> and <a href='http://phing.info/'>Phing</a>.</td> +        </tr> +  </table> +    <hr size="1"/> +</xsl:template> + +<!-- Page Footer --> +<xsl:template name="pageFooter"> +    <table width="100%"> +      <tr><td><hr noshade="yes" size="1"/></td></tr> +      <tr><td class="small">Report generated at <xsl:value-of select="date:date-time()"/></td></tr> +    </table> +</xsl:template> + +<xsl:template match="package" mode="stats"> +    <tr> +      <xsl:call-template name="alternate-row"/> +        <td><xsl:value-of select="@name"/></td> +        <xsl:call-template name="stats.formatted"/> +    </tr> +</xsl:template> + +<xsl:template match="class" mode="stats"> +    <tr> +      <xsl:call-template name="alternate-row"/> +        <td><a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a></td> +        <xsl:call-template name="stats.formatted"/> +    </tr> +</xsl:template> + +<xsl:template name="stats.formatted"> +    <xsl:choose> +        <xsl:when test="@statementcount=0"> +            <td>-</td> +        </xsl:when> +        <xsl:otherwise> +            <td> +            <xsl:value-of select="format-number(@statementscovered div @statementcount,'0.0%')"/> +            </td> +        </xsl:otherwise> +    </xsl:choose> +    <xsl:choose> +        <xsl:when test="@methodcount=0"> +            <td>-</td> +        </xsl:when> +        <xsl:otherwise> +            <td> +            <xsl:value-of select="format-number(@methodscovered div @methodcount,'0.0%')"/> +            </td> +        </xsl:otherwise> +    </xsl:choose> +    <xsl:choose> +        <xsl:when test="@totalcount=0"> +            <td>-</td> +            <td> +            <table cellspacing="0" cellpadding="0" border="0" width="100%" style="display: inline"> +                <tr> +                    <td class="empty" width="200" height="12"> </td> +                </tr> +            </table> +            </td> +        </xsl:when> +        <xsl:otherwise> +            <td> +            <xsl:value-of select="format-number(@totalcovered div @totalcount,'0.0%')"/> +            </td> +            <td> +            <xsl:variable name="leftwidth"><xsl:value-of select="format-number((@totalcovered * 200) div @totalcount,'0')"/></xsl:variable> +            <xsl:variable name="rightwidth"><xsl:value-of select="format-number(200 - (@totalcovered * 200) div @totalcount,'0')"/></xsl:variable> +            <table cellspacing="0" cellpadding="0" border="0" width="100%" style="display: inline"> +                <tr> +                    <xsl:choose> +                        <xsl:when test="$leftwidth=200"> +                            <td class="fullcover" width="200" height="12"> </td> +                        </xsl:when> +                        <xsl:otherwise> +                            <xsl:if test="not($leftwidth=0)"> +                                <td class="covered" width="{$leftwidth}" height="12"> </td> +                            </xsl:if> +                            <xsl:if test="not($rightwidth=0)"> +                                <td class="uncovered" width="{$rightwidth}" height="12"> </td> +                            </xsl:if> +                        </xsl:otherwise> +                    </xsl:choose> +                </tr> +            </table> +            </td> +        </xsl:otherwise> +    </xsl:choose> +</xsl:template> + +<xsl:template match="sourceline"> +    <tr> +        <xsl:if test="@coveredcount>0"> +            <td class="lineCountHighlight"><xsl:value-of select="position()"/></td> +            <td class="lineCountHighlight"><xsl:value-of select="@coveredcount"/></td> +        </xsl:if> +        <xsl:if test="@coveredcount<0"> +            <td class="lineCountHighlight"><xsl:value-of select="position()"/></td> +            <td class="coverageCountHighlight">0</td> +        </xsl:if> +        <xsl:if test="@coveredcount=0"> +            <td class="lineCount"><xsl:value-of select="position()"/></td> +            <td class="coverageCount"></td> +        </xsl:if> +        <td> +        	<xsl:if test="@startclass=1">        	 +            	<xsl:attribute name="class">srcLineClassStart</xsl:attribute> +            </xsl:if> +            <xsl:if test="@coveredcount>0"> +                <span class="srcLine"> +                <pre class="srcLine"><xsl:value-of select="."/></pre> +                </span> +            </xsl:if> +            <xsl:if test="@coveredcount<0"> +                <span class="srcLineHighlight"> +                <pre class="srcLine"><xsl:value-of select="."/></pre> +                </span> +            </xsl:if> +            <xsl:if test="@coveredcount=0"> +                <pre class="srcLine"><xsl:value-of select="."/></pre> +            </xsl:if> +        </td> +    </tr> +</xsl:template> + +<!-- +    transform string like a.b.c to ../../../ +    @param path the path to transform into a descending directory path +--> +<xsl:template name="path"> +    <xsl:param name="path"/> +    <xsl:if test="contains($path,'.')"> +        <xsl:text>../</xsl:text> +        <xsl:call-template name="path"> +            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param> +        </xsl:call-template> +    </xsl:if> +    <xsl:if test="not(contains($path,'.')) and not($path = '')"> +        <xsl:text>../</xsl:text> +    </xsl:if> +</xsl:template> + + +<!-- create the link to the stylesheet based on the package name --> +<xsl:template name="create.stylesheet.link"> +    <xsl:param name="package.name"/> +    <LINK REL ="stylesheet" TYPE="text/css" TITLE="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></LINK> +</xsl:template> + +<!-- alternated row style --> +<xsl:template name="alternate-row"> +<xsl:attribute name="class"> +  <xsl:if test="position() mod 2 = 1">a</xsl:if> +  <xsl:if test="position() mod 2 = 0">b</xsl:if> +</xsl:attribute> +</xsl:template> + +</xsl:stylesheet> + + diff --git a/buildscripts/phing/etc/log.xsl b/buildscripts/phing/etc/log.xsl new file mode 100644 index 00000000..a460b667 --- /dev/null +++ b/buildscripts/phing/etc/log.xsl @@ -0,0 +1,216 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="html" indent="yes" encoding="US-ASCII"/> +<!-- +    Copyright  2000-2004 The Apache Software Foundation +    +     Licensed under the Apache License, Version 2.0 (the "License"); +     you may not use this file except in compliance with the License. +     You may obtain a copy of the License at +    +         http://www.apache.org/licenses/LICENSE-2.0 +    +     Unless required by applicable law or agreed to in writing, software +     distributed under the License is distributed on an "AS IS" BASIS, +     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +     See the License for the specific language governing permissions and +     limitations under the License. +    +--> +  +<!-- + +  The purpose have this XSL is to provide a nice way to look at the output +  from the Ant XmlLogger (ie: ant -listener org.apache.tools.ant.XmlLogger ) +   +  @author <a href="mailto:michiel@trendserver.nl>Michiel Rook</a> +  @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a> +   +--> +<xsl:decimal-format decimal-separator="." grouping-separator="," /> + +<xsl:template match="/"> +<html> +  <head> +    <title>Phing Build Log</title> +    <style type="text/css"> +    .bannercell { +      border: 0px; +      padding: 0px; +    } +    body { +      margin: 0; +      font:normal 100% arial,helvetica,sanserif; +      background-color:#FFFFFF; +      color:#000000; +    } +    table.status { +      font:bold 80% arial,helvetica,sanserif; +      background-color:#525D76; +      color:#ffffff; +    } +    table.log tr td, tr th { +      font-size: 80%; +    } +    .error { +      color:red; +    } +    .warn { +      color:brown; +    } +    .info { +      color:gray; +    } +    .debug{ +      color:gray; +    } +    .failed { +      font-size:80%; +      background-color: red; +      color:#FFFFFF; +      font-weight: bold +    } +    .complete { +      font-size:80%; +      background-color: #525D76; +      color:#FFFFFF; +      font-weight: bold +    } +    .a td {  +      background: #efefef; +    } +    .b td {  +      background: #fff; +    } +    th, td { +      text-align: left; +      vertical-align: top; +    } +    th { +      background: #ccc; +      color: black; +    } +    table, th, td { +      border: none +    } +    h3 { +      font:bold 80% arial,helvetica,sanserif; +      background: #525D76; +      color: white; +      text-decoration: none; +      padding: 5px; +      margin-right: 2px; +      margin-left: 2px; +      margin-bottom: 0; +    } +    a { +      color: #003399; +    } +    a:hover { +      color: #888888; +    } +    </style> +  </head> +  <body> +    <!-- jakarta logo --> +    <table border="0" cellpadding="0" cellspacing="0" width="100%"> +    <tr> +      <td valign="top" class="bannercell"> +        <a href="http://phing.info/"> +        <img src="http://phing.info/images/phing.gif" alt="http://phing.info/" align="left" border="0"/> +        </a> +      </td> +      <td style="text-align:right;vertical-align:bottom"> +        <a href="http://phing.info/">Phing</a> +      </td> +    </tr> +    </table> +       +    <table border="0" width="100%"> +    <tr><td><hr noshade="yes" size="1"/></td></tr> +    </table> + +    <xsl:apply-templates select="build"/> + +    <!-- FOOTER --> +    <table width="100%"> +      <tr><td><hr noshade="yes" size="1"/></td></tr> +      <tr><td> +      <div align="center"><font color="#525D76" size="-1"><em> +      <a href="http://phing.info/">Phing</a> +      </em></font></div> +      </td></tr> +    </table> +  </body> +</html> +</xsl:template> + +<xsl:template match="build"> +  <!-- build status --> +  <table width="100%"> +    <xsl:attribute name="class"> +      <xsl:if test="@error">failed</xsl:if> +      <xsl:if test="not(@error)">complete</xsl:if> +    </xsl:attribute> +    <tr> +      <xsl:if test="@error"> +        <td nowrap="yes">Build Failed</td>  +      </xsl:if> +      <xsl:if test="not(@error)"> +        <td nowrap="yes">Build Complete</td> +      </xsl:if> +        <td style="text-align:right" nowrap="yes">Total Time: <xsl:value-of select="@time"/></td> +    </tr> +    <tr> +      <td colspan="2"> +        <xsl:if test="@error"> +          <tt><xsl:value-of select="@error"/></tt><br/> +          <i style="font-size:80%">See the <a href="#stacktrace" alt="Click for details">stacktrace</a>.</i> +        </xsl:if> +      </td> +    </tr> +  </table> +  <table border="1" cellspacing="2" cellpadding="3" width="100%" style="font-size:80%"> +    <tr class="a"><td width="1">phing.file</td><td><xsl:value-of select="substring-after(//message[contains(text(),'phing.file')], '->')"/></td></tr> +    <tr class="b"><td width="1">phing.version</td><td><xsl:value-of select="substring-after(//message[contains(text(),'phing.version')], '->')"/></td></tr> +  </table> +  <!-- build information --> +  <h3>Build events</h3> +  <table class="log" border="1" cellspacing="2" cellpadding="3" width="100%"> +  <tr> +    <th nowrap="yes" align="left" width="1%">target</th> +    <th nowrap="yes" align="left" width="1%">task</th> +    <th nowrap="yes" align="left">message</th> +  </tr> +  <xsl:apply-templates select=".//message[@priority != 'debug']"/> +  </table> +  <p> +  <!-- stacktrace --> +  <xsl:if test="stacktrace"> +  <a name="stacktrace"/> +  <h3>Error details</h3> +  <table width="100%"> +    <tr><td> +      <pre><xsl:value-of select="stacktrace"/></pre> +    </td></tr> +  </table> +  </xsl:if> +  </p> +</xsl:template> + +<!-- report every message but those with debug priority --> +<xsl:template match="message[@priority!='debug']"> +  <tr valign="top"> +    <!-- alternated row style --> +    <xsl:attribute name="class"> +      <xsl:if test="position() mod 2 = 1">a</xsl:if> +      <xsl:if test="position() mod 2 = 0">b</xsl:if> +    </xsl:attribute> +    <td nowrap="yes" width="1%"><xsl:value-of select="../../@name"/></td> +    <td nowrap="yes" style="text-align:right" width="1%">[ <xsl:value-of select="../@name"/> ]</td> +    <td class="{@priority}" nowrap="yes"> +            <xsl:value-of select="text()"/> +    </td> +  </tr> +</xsl:template> + +</xsl:stylesheet> diff --git a/buildscripts/phing/etc/phpunit2-frames.xsl b/buildscripts/phing/etc/phpunit2-frames.xsl new file mode 100644 index 00000000..7ccc4f33 --- /dev/null +++ b/buildscripts/phing/etc/phpunit2-frames.xsl @@ -0,0 +1,677 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" +    xmlns:exsl="http://exslt.org/common" +    xmlns:str="http://exslt.org/strings" +    xmlns:date="http://exslt.org/dates-and-times" +    extension-element-prefixes="exsl str date"> +<xsl:include href="str.replace.function.xsl"/> +<xsl:output method="html" indent="yes" encoding="US-ASCII"/> +<xsl:decimal-format decimal-separator="." grouping-separator=","/> +<!-- +   Copyright 2001-2004 The Apache Software Foundation + +   Licensed under the Apache License, Version 2.0 (the "License"); +   you may not use this file except in compliance with the License. +   You may obtain a copy of the License at + +       http://www.apache.org/licenses/LICENSE-2.0 + +   Unless required by applicable law or agreed to in writing, software +   distributed under the License is distributed on an "AS IS" BASIS, +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +   See the License for the specific language governing permissions and +   limitations under the License. + --> + +<!-- + + Sample stylesheet to be used with Phing/PHPUnit2 output. + Based on JUnit stylesheets from Apache Ant. + + It creates a set of HTML files a la javadoc where you can browse easily + through all packages and classes. + + @author Michiel Rook <a href="mailto:michiel@trendserver.nl"/> + @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/> + @author Erik Hatcher <a href="mailto:ehatcher@apache.org"/> + @author Martijn Kruithof <a href="mailto:martijn@kruithof.xs4all.nl"/> + +--> +<xsl:param name="output.dir" select="'.'"/> + + +<xsl:template match="testsuites"> +    <!-- create the index.html --> +    <exsl:document href="efile://{$output.dir}/index.html"> +        <xsl:call-template name="index.html"/> +    </exsl:document> + +    <!-- create the stylesheet.css --> +    <exsl:document href="efile://{$output.dir}/stylesheet.css"> +        <xsl:call-template name="stylesheet.css"/> +    </exsl:document> + +    <!-- create the overview-packages.html at the root --> +    <exsl:document href="efile://{$output.dir}/overview-summary.html"> +        <xsl:apply-templates select="." mode="overview.packages"/> +    </exsl:document> + +    <!-- create the all-packages.html at the root --> +    <exsl:document href="efile://{$output.dir}/overview-frame.html"> +        <xsl:apply-templates select="." mode="all.packages"/> +    </exsl:document> + +    <!-- create the all-classes.html at the root --> +    <exsl:document href="efile://{$output.dir}/allclasses-frame.html"> +        <xsl:apply-templates select="." mode="all.classes"/> +    </exsl:document> + +    <!-- process all packages --> +    <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]"> +        <xsl:call-template name="package"> +            <xsl:with-param name="name" select="@package"/> +        </xsl:call-template> +    </xsl:for-each> +</xsl:template> + + +<xsl:template name="package"> +    <xsl:param name="name"/> +    <xsl:variable name="package.dir"> +        <xsl:if test="not($name = '')"><xsl:value-of select="translate($name,'.','/')"/></xsl:if> +        <xsl:if test="$name = ''">.</xsl:if> +    </xsl:variable> +    <!--Processing package <xsl:value-of select="@name"/> in <xsl:value-of select="$output.dir"/> --> +    <!-- create a classes-list.html in the package directory --> +    <exsl:document href="efile://{$output.dir}/{$package.dir}/package-frame.html"> +        <xsl:call-template name="classes.list"> +            <xsl:with-param name="name" select="$name"/> +        </xsl:call-template> +    </exsl:document> + +    <!-- create a package-summary.html in the package directory --> +    <exsl:document href="efile://{$output.dir}/{$package.dir}/package-summary.html"> +        <xsl:call-template name="package.summary"> +            <xsl:with-param name="name" select="$name"/> +        </xsl:call-template> +    </exsl:document> + +    <!-- for each class, creates a @name.html --> +    <!-- @bug there will be a problem with inner classes having the same name, it will be overwritten --> +    <xsl:for-each select="/testsuites/testsuite[@package = $name]"> +        <exsl:document href="efile://{$output.dir}/{$package.dir}/{@name}.html"> +            <xsl:apply-templates select="." mode="class.details"/> +        </exsl:document> +        <xsl:if test="string-length(./system-out)!=0"> +            <exsl:document href="efile://{$output.dir}/{$package.dir}/{@name}-out.txt"> +                <xsl:value-of select="./system-out" /> +            </exsl:document> +        </xsl:if> +        <xsl:if test="string-length(./system-err)!=0"> +            <exsl:document href="efile://{$output.dir}/{$package.dir}/{@name}-err.txt"> +                <xsl:value-of select="./system-err" /> +            </exsl:document> +        </xsl:if> +    </xsl:for-each> +</xsl:template> + +<xsl:template name="index.html"> +<html> +    <head> +        <title>Unit Test Results.</title> +    </head> +    <frameset cols="20%,80%"> +        <frameset rows="30%,70%"> +            <frame src="overview-frame.html" name="packageListFrame"/> +            <frame src="allclasses-frame.html" name="classListFrame"/> +        </frameset> +        <frame src="overview-summary.html" name="classFrame"/> +        <noframes> +            <h2>Frame Alert</h2> +            <p> +                This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +            </p> +        </noframes> +    </frameset> +</html> +</xsl:template> + +<!-- this is the stylesheet css to use for nearly everything --> +<xsl:template name="stylesheet.css"> +body { +    font-family: verdana,arial,helvetica; +    color:#000000; +    font-size: 12px; +} +table tr td, table tr th { +    font-family: verdana,arial,helvetica; +    font-size: 12px; +} +table.details tr th{ +    font-family: verdana,arial,helvetica; +    font-weight: bold; +    text-align:left; +    background:#a6caf0; +} +table.details tr td{ +    background:#eeeee0; +} + +p { +    line-height:1.5em; +    margin-top:0.5em; margin-bottom:1.0em; +    font-size: 12px; +} +h1 { +    margin: 0px 0px 5px; +    font-family: verdana,arial,helvetica; +} +h2 { +    margin-top: 1em; margin-bottom: 0.5em; +    font-family: verdana,arial,helvetica; +} +h3 { +    margin-bottom: 0.5em; +    font-family: verdana,arial,helvetica; +} +h4 { +    margin-bottom: 0.5em; +    font-family: verdana,arial,helvetica; +} +h5 { +    margin-bottom: 0.5em; +    font-family: verdana,arial,helvetica; +} +h6 { +    margin-bottom: 0.5em; +    font-family: verdana,arial,helvetica; +} +.Error { +    font-weight:bold; color:red; +} +.Failure { +    font-weight:bold; color:purple; +} +.small { +   font-size: 9px; +} +a { +  color: #003399; +} +a:hover { +  color: #888888; +} +</xsl:template> + + +<!-- ====================================================================== +    This page is created for every testsuite class. +    It prints a summary of the testsuite and detailed information about +    testcase methods. +     ====================================================================== --> +<xsl:template match="testsuite" mode="class.details"> +    <xsl:variable name="package.name" select="@package"/> +    <xsl:variable name="class.name"><xsl:if test="not($package.name = '')"><xsl:value-of select="$package.name"/>.</xsl:if><xsl:value-of select="@name"/></xsl:variable> +    <html> +        <head> +          <title>Unit Test Results: <xsl:value-of select="$class.name"/></title> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="$package.name"/> +            </xsl:call-template> +        </head> +        <body> +            <xsl:call-template name="pageHeader"/> +            <h3>Class <xsl:value-of select="$class.name"/></h3> + + +            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +                <xsl:call-template name="testsuite.test.header"/> +                <xsl:apply-templates select="." mode="print.test"/> +            </table> + +            <h2>Tests</h2> +            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +        <xsl:call-template name="testcase.test.header"/> +              <!-- +              test can even not be started at all (failure to load the class) +              so report the error directly +              --> +                <xsl:if test="./error"> +                    <tr class="Error"> +                        <td colspan="4"><xsl:apply-templates select="./error"/></td> +                    </tr> +                </xsl:if> +                <xsl:apply-templates select="./testcase" mode="print.test"/> +            </table> +            <xsl:call-template name="pageFooter"/> +        </body> +    </html> +</xsl:template> + +<!-- ====================================================================== +    This page is created for every package. +    It prints the name of all classes that belongs to this package. +    @param name the package name to print classes. +     ====================================================================== --> +<!-- list of classes in a package --> +<xsl:template name="classes.list"> +    <xsl:param name="name"/> +    <html> +        <head> +            <title>Unit Test Classes: <xsl:value-of select="$name"/></title> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="$name"/> +            </xsl:call-template> +        </head> +        <body> +            <table width="100%"> +                <tr> +                    <td nowrap="nowrap"> +                        <h2><a href="package-summary.html" target="classFrame"> +                            <xsl:value-of select="$name"/> +                            <xsl:if test="$name = ''"><none></xsl:if> +                        </a></h2> +                    </td> +                </tr> +            </table> + +            <h2>Classes</h2> +            <table width="100%"> +                <xsl:for-each select="/testsuites/testsuite[./@package = $name]"> +                    <xsl:sort select="@name"/> +                    <tr> +                        <td nowrap="nowrap"> +                            <a href="{@name}.html" target="classFrame"><xsl:value-of select="@name"/></a> +                        </td> +                    </tr> +                </xsl:for-each> +            </table> +        </body> +    </html> +</xsl:template> + + +<!-- +    Creates an all-classes.html file that contains a link to all package-summary.html +    on each class. +--> +<xsl:template match="testsuites" mode="all.classes"> +    <html> +        <head> +            <title>All Unit Test Classes</title> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name"/> +            </xsl:call-template> +        </head> +        <body> +            <h2>Classes</h2> +            <table width="100%"> +                <xsl:apply-templates select="testsuite" mode="all.classes"> +                    <xsl:sort select="@name"/> +                </xsl:apply-templates> +            </table> +        </body> +    </html> +</xsl:template> + +<xsl:template match="testsuite" mode="all.classes"> +    <xsl:variable name="package.name" select="@package"/> +    <tr> +        <td nowrap="nowrap"> +            <a target="classFrame"> +                <xsl:attribute name="href"> +                    <xsl:if test="not($package.name='')"> +                        <xsl:value-of select="translate($package.name,'.','/')"/><xsl:text>/</xsl:text> +                    </xsl:if><xsl:value-of select="@name"/><xsl:text>.html</xsl:text> +                </xsl:attribute> +                <xsl:value-of select="@name"/> +            </a> +        </td> +    </tr> +</xsl:template> + + +<!-- +    Creates an html file that contains a link to all package-summary.html files on +    each package existing on testsuites. +    @bug there will be a problem here, I don't know yet how to handle unnamed package :( +--> +<xsl:template match="testsuites" mode="all.packages"> +    <html> +        <head> +            <title>All Unit Test Packages</title> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name"/> +            </xsl:call-template> +        </head> +        <body> +            <h2><a href="overview-summary.html" target="classFrame">Home</a></h2> +            <h2>Packages</h2> +            <table width="100%"> +                <xsl:apply-templates select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]" mode="all.packages"> +                    <xsl:sort select="@package"/> +                </xsl:apply-templates> +            </table> +        </body> +    </html> +</xsl:template> + +<xsl:template match="testsuite" mode="all.packages"> +    <tr> +        <td nowrap="nowrap"> +            <a href="./{translate(@package,'.','/')}/package-summary.html" target="classFrame"> +                <xsl:value-of select="@package"/> +                <xsl:if test="@package = ''"><none></xsl:if> +            </a> +        </td> +    </tr> +</xsl:template> + + +<xsl:template match="testsuites" mode="overview.packages"> +    <html> +        <head> +            <title>Unit Test Results: Summary</title> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name"/> +            </xsl:call-template> +        </head> +        <body> +        <xsl:attribute name="onload">open('allclasses-frame.html','classListFrame')</xsl:attribute> +        <xsl:call-template name="pageHeader"/> +        <h2>Summary</h2> +        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/> +        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/> +        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/> +        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/> +        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/> +        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +        <tr valign="top"> +            <th>Tests</th> +            <th>Failures</th> +            <th>Errors</th> +            <th>Success rate</th> +            <th>Time</th> +        </tr> +        <tr valign="top"> +            <xsl:attribute name="class"> +                <xsl:choose> +                    <xsl:when test="$errorCount > 0">Error</xsl:when> +                    <xsl:when test="$failureCount > 0">Failure</xsl:when> +                    <xsl:otherwise>Pass</xsl:otherwise> +                </xsl:choose> +            </xsl:attribute> +            <td><xsl:value-of select="$testCount"/></td> +            <td><xsl:value-of select="$failureCount"/></td> +            <td><xsl:value-of select="$errorCount"/></td> +            <td> +                <xsl:call-template name="display-percent"> +                    <xsl:with-param name="value" select="$successRate"/> +                </xsl:call-template> +            </td> +            <td> +                <xsl:call-template name="display-time"> +                    <xsl:with-param name="value" select="$timeCount"/> +                </xsl:call-template> +            </td> + +        </tr> +        </table> +        <table border="0" width="95%"> +        <tr> +        <td style="text-align: justify;"> +        Note: <em>failures</em> are anticipated and checked for with assertions while <em>errors</em> are unanticipated. +        </td> +        </tr> +        </table> + +        <h2>Packages</h2> +        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +            <xsl:call-template name="testsuite.test.header"/> +            <xsl:for-each select="testsuite[not(./@package = preceding-sibling::testsuite/@package)]"> +                <xsl:sort select="@package" order="ascending"/> +                <!-- get the node set containing all testsuites that have the same package --> +                <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = current()/@package]"/> +                <tr valign="top"> +                    <!-- display a failure if there is any failure/error in the package --> +                    <xsl:attribute name="class"> +                        <xsl:choose> +                            <xsl:when test="sum($insamepackage/@errors) > 0">Error</xsl:when> +                            <xsl:when test="sum($insamepackage/@failures) > 0">Failure</xsl:when> +                            <xsl:otherwise>Pass</xsl:otherwise> +                        </xsl:choose> +                    </xsl:attribute> +                    <td><a href="./{translate(@package,'.','/')}/package-summary.html"> +                        <xsl:value-of select="@package"/> +                        <xsl:if test="@package = ''"><none></xsl:if> +                    </a></td> +                    <td><xsl:value-of select="sum($insamepackage/@tests)"/></td> +                    <td><xsl:value-of select="sum($insamepackage/@errors)"/></td> +                    <td><xsl:value-of select="sum($insamepackage/@failures)"/></td> +                    <td> +                    <xsl:call-template name="display-time"> +                        <xsl:with-param name="value" select="sum($insamepackage/@time)"/> +                    </xsl:call-template> +                    </td> +                </tr> +            </xsl:for-each> +        </table> +        <xsl:call-template name="pageFooter"/> +        </body> +        </html> +</xsl:template> + + +<xsl:template name="package.summary"> +    <xsl:param name="name"/> +    <html> +        <head> +            <xsl:call-template name="create.stylesheet.link"> +                <xsl:with-param name="package.name" select="$name"/> +            </xsl:call-template> +        </head> +        <body> +            <xsl:attribute name="onload">open('package-frame.html','classListFrame')</xsl:attribute> +            <xsl:call-template name="pageHeader"/> +            <h3>Package <xsl:value-of select="$name"/></h3> + +            <!--table border="0" cellpadding="5" cellspacing="2" width="95%"> +                <xsl:call-template name="class.metrics.header"/> +                <xsl:apply-templates select="." mode="print.metrics"/> +            </table--> + +            <xsl:variable name="insamepackage" select="/testsuites/testsuite[./@package = $name]"/> +            <xsl:if test="count($insamepackage) > 0"> +                <h2>Classes</h2> +                <p> +                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +                    <xsl:call-template name="testsuite.test.header"/> +                    <xsl:apply-templates select="$insamepackage" mode="print.test"> +                        <xsl:sort select="@name"/> +                    </xsl:apply-templates> +                </table> +                </p> +            </xsl:if> +            <xsl:call-template name="pageFooter"/> +        </body> +    </html> +</xsl:template> + + +<!-- +    transform string like a.b.c to ../../../ +    @param path the path to transform into a descending directory path +--> +<xsl:template name="path"> +    <xsl:param name="path"/> +    <xsl:if test="contains($path,'.')"> +        <xsl:text>../</xsl:text> +        <xsl:call-template name="path"> +            <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'.')"/></xsl:with-param> +        </xsl:call-template> +    </xsl:if> +    <xsl:if test="not(contains($path,'.')) and not($path = '')"> +        <xsl:text>../</xsl:text> +    </xsl:if> +</xsl:template> + + +<!-- create the link to the stylesheet based on the package name --> +<xsl:template name="create.stylesheet.link"> +    <xsl:param name="package.name"/> +    <link rel="stylesheet" type="text/css" title="Style"><xsl:attribute name="href"><xsl:if test="not($package.name = 'unnamed package')"><xsl:call-template name="path"><xsl:with-param name="path" select="$package.name"/></xsl:call-template></xsl:if>stylesheet.css</xsl:attribute></link> +</xsl:template> + + +<!-- Page HEADER --> +<xsl:template name="pageHeader"> +    <h1>Unit Test Results</h1> +    <table width="100%"> +    <tr> +        <td align="left"></td> +        <td align="right">Designed for use with <a href='http://pear.php.net/package/PHPUnit2'>PHPUnit2</a> and <a href='http://phing.info/'>Phing</a>.</td> +    </tr> +    </table> +    <hr size="1"/> +</xsl:template> + +<!-- Page Footer --> +<xsl:template name="pageFooter"> +    <table width="100%"> +      <tr><td><hr noshade="yes" size="1"/></td></tr> +      <tr><td class="small">Report generated at <xsl:value-of select="date:date-time()"/></td></tr> +    </table> +</xsl:template> + +<!-- class header --> +<xsl:template name="testsuite.test.header"> +    <tr valign="top"> +        <th width="80%">Name</th> +        <th>Tests</th> +        <th>Errors</th> +        <th>Failures</th> +        <th nowrap="nowrap">Time(s)</th> +    </tr> +</xsl:template> + +<!-- method header --> +<xsl:template name="testcase.test.header"> +    <tr valign="top"> +        <th>Name</th> +        <th>Status</th> +        <th width="80%">Type</th> +        <th nowrap="nowrap">Time(s)</th> +    </tr> +</xsl:template> + + +<!-- class information --> +<xsl:template match="testsuite" mode="print.test"> +    <tr valign="top"> +        <xsl:attribute name="class"> +            <xsl:choose> +                <xsl:when test="@errors[.> 0]">Error</xsl:when> +                <xsl:when test="@failures[.> 0]">Failure</xsl:when> +                <xsl:otherwise>Pass</xsl:otherwise> +            </xsl:choose> +        </xsl:attribute> +        <td><a href="{@name}.html"><xsl:value-of select="@name"/></a></td> +        <td><xsl:apply-templates select="@tests"/></td> +        <td><xsl:apply-templates select="@errors"/></td> +        <td><xsl:apply-templates select="@failures"/></td> +        <td><xsl:call-template name="display-time"> +                <xsl:with-param name="value" select="@time"/> +            </xsl:call-template> +        </td> +    </tr> +</xsl:template> + +<xsl:template match="testcase" mode="print.test"> +    <tr valign="top"> +        <xsl:attribute name="class"> +            <xsl:choose> +                <xsl:when test="error">Error</xsl:when> +                <xsl:when test="failure">Failure</xsl:when> +                <xsl:otherwise>TableRowColor</xsl:otherwise> +            </xsl:choose> +        </xsl:attribute> +        <td><xsl:value-of select="@name"/></td> +        <xsl:choose> +            <xsl:when test="failure"> +                <td>Failure</td> +                <td><xsl:apply-templates select="failure"/></td> +            </xsl:when> +            <xsl:when test="error"> +                <td>Error</td> +                <td><xsl:apply-templates select="error"/></td> +            </xsl:when> +            <xsl:otherwise> +                <td>Success</td> +                <td></td> +            </xsl:otherwise> +        </xsl:choose> +        <td> +            <xsl:call-template name="display-time"> +                <xsl:with-param name="value" select="@time"/> +            </xsl:call-template> +        </td> +    </tr> +</xsl:template> + + +<!-- Note : the below template error and failure are the same style +            so just call the same style store in the toolkit template --> +<xsl:template match="failure"> +    <xsl:call-template name="display-failures"/> +</xsl:template> + +<xsl:template match="error"> +    <xsl:call-template name="display-failures"/> +</xsl:template> + +<!-- Style for the error and failure in the testcase template --> +<xsl:template name="display-failures"> +    <xsl:choose> +        <xsl:when test="not(@message)">N/A</xsl:when> +        <xsl:otherwise> +            <xsl:value-of select="@message"/> +        </xsl:otherwise> +    </xsl:choose> +    <!-- display the stacktrace --> +    <br/><br/> +    <code> +        <xsl:call-template name="br-replace"> +            <xsl:with-param name="word" select="."/> +        </xsl:call-template> +    </code> +</xsl:template> + +<!-- +    template that will convert a carriage return into a br tag +    @param word the text from which to convert CR to BR tag +--> +<xsl:template name="br-replace"> +    <xsl:choose> +         <xsl:when test="contains($word,'
')"> +             <xsl:value-of select="substring-before($word,'
')"/> +             <br /> +             <xsl:call-template name="br-replace"> +                 <xsl:with-param name="word" select="substring-after($word,'
')"/> +             </xsl:call-template> +         </xsl:when> +         <xsl:otherwise> +             <xsl:value-of select="$word"/> +         </xsl:otherwise> +    </xsl:choose> +</xsl:template> + +<xsl:template name="display-time"> +    <xsl:param name="value"/> +    <xsl:value-of select="format-number($value,'0.000')"/> +</xsl:template> + +<xsl:template name="display-percent"> +    <xsl:param name="value"/> +    <xsl:value-of select="format-number($value,'0.00%')"/> +</xsl:template> +</xsl:stylesheet> + diff --git a/buildscripts/phing/etc/phpunit2-noframes.xsl b/buildscripts/phing/etc/phpunit2-noframes.xsl new file mode 100644 index 00000000..d2c772da --- /dev/null +++ b/buildscripts/phing/etc/phpunit2-noframes.xsl @@ -0,0 +1,436 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" +    xmlns:exsl="http://exslt.org/common" +    xmlns:str="http://exslt.org/strings" +    xmlns:date="http://exslt.org/dates-and-times" +    extension-element-prefixes="exsl str date"> +<xsl:include href="str.replace.function.xsl"/> +<xsl:output method="html" indent="yes" encoding="US-ASCII" +  doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" /> +<xsl:decimal-format decimal-separator="." grouping-separator="," /> +<!-- +   Copyright 2001-2004 The Apache Software Foundation + +   Licensed under the Apache License, Version 2.0 (the "License"); +   you may not use this file except in compliance with the License. +   You may obtain a copy of the License at + +       http://www.apache.org/licenses/LICENSE-2.0 + +   Unless required by applicable law or agreed to in writing, software +   distributed under the License is distributed on an "AS IS" BASIS, +   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +   See the License for the specific language governing permissions and +   limitations under the License. + --> +  +<!-- +  + Sample stylesheet to be used with Phing/PHPUnit2 output. + Based on JUnit stylesheets from Apache Ant. +  + It creates a non-framed report that can be useful to send via + e-mail or such. +  + @author Michiel Rook <a href="mailto:michiel@trendserver.nl"/> + @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/> + @author Erik Hatcher <a href="mailto:ehatcher@apache.org"/> +  +--> +<xsl:template match="testsuites"> +    <html> +        <head> +            <title>Unit Test Results</title> +    <style type="text/css"> +    body { +        font-family: verdana,arial,helvetica; +        color:#000000; +        font-size: 12px; +    } +    table tr td, table tr th { +        font-family: verdana,arial,helvetica; +        font-size: 12px; +    } +    table.details tr th{ +        font-family: verdana,arial,helvetica; +        font-weight: bold; +        text-align:left; +        background:#a6caf0; +    } +    table.details tr td{ +        background:#eeeee0; +    } + +    p { +        line-height:1.5em; +        margin-top:0.5em; margin-bottom:1.0em; +        font-size: 12px; +    } +    h1 { +        margin: 0px 0px 5px; +        font-family: verdana,arial,helvetica; +    } +    h2 { +        margin-top: 1em; margin-bottom: 0.5em; +        font-family: verdana,arial,helvetica; +    } +    h3 { +        margin-bottom: 0.5em; +        font-family: verdana,arial,helvetica; +    } +    h4 { +        margin-bottom: 0.5em; +        font-family: verdana,arial,helvetica; +    } +    h5 { +        margin-bottom: 0.5em; +        font-family: verdana,arial,helvetica; +    } +    h6 { +        margin-bottom: 0.5em; +        font-family: verdana,arial,helvetica; +    } +    .Error { +        font-weight:bold; color:red; +    } +    .Failure { +        font-weight:bold; color:purple; +    } +    .small { +       font-size: 9px; +    } +    a { +      color: #003399; +    } +    a:hover { +      color: #888888; +    } +    </style> +        </head> +        <body> +            <a name="top"></a> +            <xsl:call-template name="pageHeader"/>   +             +            <!-- Summary part --> +            <xsl:call-template name="summary"/> +            <hr size="1" width="95%" align="left"/> +             +            <!-- Package List part --> +            <xsl:call-template name="packagelist"/> +            <hr size="1" width="95%" align="left"/> +             +            <!-- For each package create its part --> +            <xsl:call-template name="packages"/> +            <hr size="1" width="95%" align="left"/> +             +            <!-- For each class create the  part --> +            <xsl:call-template name="classes"/> +             +            <xsl:call-template name="pageFooter"/>   +        </body> +    </html> +</xsl:template> +     +     +     +    <!-- ================================================================== --> +    <!-- Write a list of all packages with an hyperlink to the anchor of    --> +    <!-- of the package name.                                               --> +    <!-- ================================================================== --> +    <xsl:template name="packagelist">    +        <h2>Packages</h2> +        Note: package statistics are not computed recursively, they only sum up all of its testsuites numbers. +        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +            <xsl:call-template name="testsuite.test.header"/> +            <!-- list all packages recursively --> +            <xsl:for-each select="./testsuite[not(./@package = preceding-sibling::testsuite/@package)]"> +                <xsl:sort select="@package"/> +                <xsl:variable name="testsuites-in-package" select="/testsuites/testsuite[./@package = current()/@package]"/> +                <xsl:variable name="testCount" select="sum($testsuites-in-package/@tests)"/> +                <xsl:variable name="errorCount" select="sum($testsuites-in-package/@errors)"/> +                <xsl:variable name="failureCount" select="sum($testsuites-in-package/@failures)"/> +                <xsl:variable name="timeCount" select="sum($testsuites-in-package/@time)"/> +                 +                <!-- write a summary for the package --> +                <tr valign="top"> +                    <!-- set a nice color depending if there is an error/failure --> +                    <xsl:attribute name="class"> +                        <xsl:choose> +                            <xsl:when test="$failureCount > 0">Failure</xsl:when> +                            <xsl:when test="$errorCount > 0">Error</xsl:when> +                        </xsl:choose> +                    </xsl:attribute> +                    <td><a href="#{@package}"><xsl:value-of select="@package"/></a></td> +                    <td><xsl:value-of select="$testCount"/></td> +                    <td><xsl:value-of select="$errorCount"/></td> +                    <td><xsl:value-of select="$failureCount"/></td> +                    <td> +                    <xsl:call-template name="display-time"> +                        <xsl:with-param name="value" select="$timeCount"/> +                    </xsl:call-template> +                    </td> +                </tr> +            </xsl:for-each> +        </table>         +    </xsl:template> +     +     +    <!-- ================================================================== --> +    <!-- Write a package level report                                       --> +    <!-- It creates a table with values from the document:                  --> +    <!-- Name | Tests | Errors | Failures | Time                            --> +    <!-- ================================================================== --> +    <xsl:template name="packages"> +        <!-- create an anchor to this package name --> +        <xsl:for-each select="/testsuites/testsuite[not(./@package = preceding-sibling::testsuite/@package)]"> +            <xsl:sort select="@package"/> +                <a name="{@package}"></a> +                <h3>Package <xsl:value-of select="@package"/></h3> +                 +                <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +                    <xsl:call-template name="testsuite.test.header"/> +             +                    <!-- match the testsuites of this package --> +                    <xsl:apply-templates select="/testsuites/testsuite[./@package = current()/@package]" mode="print.test"/> +                </table> +                <a href="#top">Back to top</a> +                <p/> +                <p/> +        </xsl:for-each> +    </xsl:template> +     +    <xsl:template name="classes"> +        <xsl:for-each select="testsuite"> +            <xsl:sort select="@name"/> +            <!-- create an anchor to this class name --> +            <a name="{@name}"></a> +            <h3>TestCase <xsl:value-of select="@name"/></h3> +             +            <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +              <xsl:call-template name="testcase.test.header"/> +              <!-- +              test can even not be started at all (failure to load the class) +              so report the error directly +              --> +                <xsl:if test="./error"> +                    <tr class="Error"> +                        <td colspan="4"><xsl:apply-templates select="./error"/></td> +                    </tr> +                </xsl:if> +                <xsl:apply-templates select="./testcase" mode="print.test"/> +            </table> +            <p/> +             +            <a href="#top">Back to top</a> +        </xsl:for-each> +    </xsl:template> +     +    <xsl:template name="summary"> +        <h2>Summary</h2> +        <xsl:variable name="testCount" select="sum(testsuite/@tests)"/> +        <xsl:variable name="errorCount" select="sum(testsuite/@errors)"/> +        <xsl:variable name="failureCount" select="sum(testsuite/@failures)"/> +        <xsl:variable name="timeCount" select="sum(testsuite/@time)"/> +        <xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/> +        <table class="details" border="0" cellpadding="5" cellspacing="2" width="95%"> +        <tr valign="top"> +            <th>Tests</th> +            <th>Failures</th> +            <th>Errors</th> +            <th>Success rate</th> +            <th>Time</th> +        </tr> +        <tr valign="top"> +            <xsl:attribute name="class"> +                <xsl:choose> +                    <xsl:when test="$failureCount > 0">Failure</xsl:when> +                    <xsl:when test="$errorCount > 0">Error</xsl:when> +                </xsl:choose> +            </xsl:attribute> +            <td><xsl:value-of select="$testCount"/></td> +            <td><xsl:value-of select="$failureCount"/></td> +            <td><xsl:value-of select="$errorCount"/></td> +            <td> +                <xsl:call-template name="display-percent"> +                    <xsl:with-param name="value" select="$successRate"/> +                </xsl:call-template> +            </td> +            <td> +                <xsl:call-template name="display-time"> +                    <xsl:with-param name="value" select="$timeCount"/> +                </xsl:call-template> +            </td> + +        </tr> +        </table> +        <table border="0" width="95%"> +        <tr> +        <td style="text-align: justify;"> +        Note: <i>failures</i> are anticipated and checked for with assertions while <i>errors</i> are unanticipated. +        </td> +        </tr> +        </table> +    </xsl:template> +       +<!-- Page HEADER --> +<xsl:template name="pageHeader"> +    <h1>Unit Test Results</h1> +    <table width="100%"> +    <tr> +        <td align="left"></td> +        <td align="right">Designed for use with <a href='http://pear.php.net/package/PHPUnit2'>PHPUnit2</a> and <a href='http://phing.info/'>Phing</a>.</td> +    </tr> +    </table> +    <hr size="1"/> +</xsl:template> + +<!-- Page Footer --> +<xsl:template name="pageFooter"> +    <table width="100%"> +      <tr><td><hr noshade="yes" size="1"/></td></tr> +      <tr><td class="small">Report generated at <xsl:value-of select="date:date-time()"/></td></tr> +    </table> +</xsl:template> + +<xsl:template match="testsuite" mode="header"> +    <tr valign="top"> +        <th width="80%">Name</th> +        <th>Tests</th> +        <th>Errors</th> +        <th>Failures</th> +        <th nowrap="nowrap">Time(s)</th> +    </tr> +</xsl:template> + +<!-- class header --> +<xsl:template name="testsuite.test.header"> +    <tr valign="top"> +        <th width="80%">Name</th> +        <th>Tests</th> +        <th>Errors</th> +        <th>Failures</th> +        <th nowrap="nowrap">Time(s)</th> +    </tr> +</xsl:template> + +<!-- method header --> +<xsl:template name="testcase.test.header"> +    <tr valign="top"> +        <th>Name</th> +        <th>Status</th> +        <th width="80%">Type</th> +        <th nowrap="nowrap">Time(s)</th> +    </tr> +</xsl:template> + + +<!-- class information --> +<xsl:template match="testsuite" mode="print.test"> +    <tr valign="top"> +        <!-- set a nice color depending if there is an error/failure --> +        <xsl:attribute name="class"> +            <xsl:choose> +                <xsl:when test="@failures[.> 0]">Failure</xsl:when> +                <xsl:when test="@errors[.> 0]">Error</xsl:when> +            </xsl:choose> +        </xsl:attribute> +     +        <!-- print testsuite information --> +        <td><a href="#{@name}"><xsl:value-of select="@name"/></a></td> +        <td><xsl:value-of select="@tests"/></td> +        <td><xsl:value-of select="@errors"/></td> +        <td><xsl:value-of select="@failures"/></td> +        <td> +            <xsl:call-template name="display-time"> +                <xsl:with-param name="value" select="@time"/> +            </xsl:call-template> +        </td> +    </tr> +</xsl:template> + +<xsl:template match="testcase" mode="print.test"> +    <tr valign="top"> +        <xsl:attribute name="class"> +            <xsl:choose> +                <xsl:when test="failure | error">Error</xsl:when> +            </xsl:choose> +        </xsl:attribute> +        <td><xsl:value-of select="@name"/></td> +        <xsl:choose> +            <xsl:when test="failure"> +                <td>Failure</td> +                <td><xsl:apply-templates select="failure"/></td> +            </xsl:when> +            <xsl:when test="error"> +                <td>Error</td> +                <td><xsl:apply-templates select="error"/></td> +            </xsl:when> +            <xsl:otherwise> +                <td>Success</td> +                <td></td> +            </xsl:otherwise> +        </xsl:choose> +        <td> +            <xsl:call-template name="display-time"> +                <xsl:with-param name="value" select="@time"/> +            </xsl:call-template> +        </td> +    </tr> +</xsl:template> + + +<xsl:template match="failure"> +    <xsl:call-template name="display-failures"/> +</xsl:template> + +<xsl:template match="error"> +    <xsl:call-template name="display-failures"/> +</xsl:template> + +<!-- Style for the error and failure in the tescase template --> +<xsl:template name="display-failures"> +    <xsl:choose> +        <xsl:when test="not(@message)">N/A</xsl:when> +        <xsl:otherwise> +            <xsl:value-of select="@message"/> +        </xsl:otherwise> +    </xsl:choose> +    <!-- display the stacktrace --> +    <code> +        <br/><br/> +        <xsl:call-template name="br-replace"> +            <xsl:with-param name="word" select="."/> +        </xsl:call-template> +    </code> +</xsl:template> + +<!-- +    template that will convert a carriage return into a br tag +    @param word the text from which to convert CR to BR tag +--> +<xsl:template name="br-replace"> +    <xsl:choose> +         <xsl:when test="contains($word,'
')"> +             <xsl:value-of select="substring-before($word,'
')"/> +             <br /> +             <xsl:call-template name="br-replace"> +                 <xsl:with-param name="word" select="substring-after($word,'
')"/> +             </xsl:call-template> +         </xsl:when> +         <xsl:otherwise> +             <xsl:value-of select="$word"/> +         </xsl:otherwise> +    </xsl:choose> +</xsl:template> + +<xsl:template name="display-time"> +    <xsl:param name="value"/> +    <xsl:value-of select="format-number($value,'0.000')"/> +</xsl:template> + +<xsl:template name="display-percent"> +    <xsl:param name="value"/> +    <xsl:value-of select="format-number($value,'0.00%')"/> +</xsl:template> + +</xsl:stylesheet> + diff --git a/buildscripts/phing/etc/str.replace.function.xsl b/buildscripts/phing/etc/str.replace.function.xsl new file mode 100644 index 00000000..5d74e86c --- /dev/null +++ b/buildscripts/phing/etc/str.replace.function.xsl @@ -0,0 +1,105 @@ +<?xml version="1.0"?>
 +<xsl:stylesheet version="1.0"
 +                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 +                xmlns:str="http://exslt.org/strings"
 +                xmlns:func="http://exslt.org/functions"
 +                xmlns:exsl="http://exslt.org/common"
 +                extension-element-prefixes="str exsl func">
 +
 +<func:function name="str:replace">
 +	<xsl:param name="string" select="''" />
 +   <xsl:param name="search" select="/.." />
 +   <xsl:param name="replace" select="/.." />
 +   <xsl:choose>
 +      <xsl:when test="not($string)">
 +        <func:result select="/.." />
 +      </xsl:when>
 +      <xsl:when test="function-available('exsl:node-set')">
 +         <!-- this converts the search and replace arguments to node sets
 +              if they are one of the other XPath types -->
 +         <xsl:variable name="search-nodes-rtf">
 +           <xsl:copy-of select="$search" />
 +         </xsl:variable>
 +         <xsl:variable name="replace-nodes-rtf">
 +           <xsl:copy-of select="$replace" />
 +         </xsl:variable>
 +         <xsl:variable name="replacements-rtf">
 +            <xsl:for-each select="exsl:node-set($search-nodes-rtf)/node()">
 +               <xsl:variable name="pos" select="position()" />
 +               <replace search="{.}">
 +                  <xsl:copy-of select="exsl:node-set($replace-nodes-rtf)/node()[$pos]" />
 +               </replace>
 +            </xsl:for-each>
 +         </xsl:variable>
 +         <xsl:variable name="sorted-replacements-rtf">
 +            <xsl:for-each select="exsl:node-set($replacements-rtf)/replace">
 +               <xsl:sort select="string-length(@search)" data-type="number" order="descending" />
 +               <xsl:copy-of select="." />
 +            </xsl:for-each>
 +         </xsl:variable>
 +         <xsl:variable name="result">
 +           <xsl:choose>
 +              <xsl:when test="not($search)">
 +                <xsl:value-of select="$string" />
 +              </xsl:when>
 +             <xsl:otherwise>
 +               <xsl:call-template name="str:_replace">
 +                  <xsl:with-param name="string" select="$string" />
 +                  <xsl:with-param name="replacements" select="exsl:node-set($sorted-replacements-rtf)/replace" />
 +               </xsl:call-template>
 +             </xsl:otherwise>
 +           </xsl:choose>
 +         </xsl:variable>
 +         <func:result select="exsl:node-set($result)/node()" />
 +      </xsl:when>
 +      <xsl:otherwise>
 +         <xsl:message terminate="yes">
 +            ERROR: function implementation of str:replace() relies on exsl:node-set().
 +         </xsl:message>
 +      </xsl:otherwise>
 +   </xsl:choose>
 +</func:function>
 +
 +<xsl:template name="str:_replace">
 +  <xsl:param name="string" select="''" />
 +  <xsl:param name="replacements" select="/.." />
 +  <xsl:choose>
 +    <xsl:when test="not($string)" />
 +    <xsl:when test="not($replacements)">
 +      <xsl:value-of select="$string" />
 +    </xsl:when>
 +    <xsl:otherwise>
 +      <xsl:variable name="replacement" select="$replacements[1]" />
 +      <xsl:variable name="search" select="$replacement/@search" />
 +      <xsl:choose>
 +        <xsl:when test="not(string($search))">
 +          <xsl:value-of select="substring($string, 1, 1)" />
 +          <xsl:copy-of select="$replacement/node()" />
 +          <xsl:call-template name="str:_replace">
 +            <xsl:with-param name="string" select="substring($string, 2)" />
 +            <xsl:with-param name="replacements" select="$replacements" />
 +          </xsl:call-template>
 +        </xsl:when>
 +        <xsl:when test="contains($string, $search)">
 +          <xsl:call-template name="str:_replace">
 +            <xsl:with-param name="string" select="substring-before($string, $search)" />
 +            <xsl:with-param name="replacements" select="$replacements[position() > 1]" />
 +          </xsl:call-template>      
 +          <xsl:copy-of select="$replacement/node()" />
 +          <xsl:call-template name="str:_replace">
 +            <xsl:with-param name="string" select="substring-after($string, $search)" />
 +            <xsl:with-param name="replacements" select="$replacements" />
 +          </xsl:call-template>
 +        </xsl:when>
 +        <xsl:otherwise>
 +          <xsl:call-template name="str:_replace">
 +            <xsl:with-param name="string" select="$string" />
 +            <xsl:with-param name="replacements" select="$replacements[position() > 1]" />
 +          </xsl:call-template>
 +        </xsl:otherwise>
 +      </xsl:choose>
 +    </xsl:otherwise>
 +  </xsl:choose>
 +</xsl:template>
 +
 +</xsl:stylesheet>
\ No newline at end of file diff --git a/buildscripts/phing/pear/BuildPhingPEARPackageTask.php b/buildscripts/phing/pear/BuildPhingPEARPackageTask.php new file mode 100644 index 00000000..6ac6ad51 --- /dev/null +++ b/buildscripts/phing/pear/BuildPhingPEARPackageTask.php @@ -0,0 +1,270 @@ +<?php +/* + *  $Id$ + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This software consists of voluntary contributions made by many individuals + * and is licensed under the LGPL. For more information please see + * <http://phing.info>. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; +include_once 'phing/types/FileSet.php'; +include_once 'phing/tasks/ext/pearpackage/Fileset.php'; + +/** + * + * @author   Hans Lellelid <hans@xmpl.org> + * @package  phing.tasks.ext + * @version  $Revision$ + */ +class BuildPhingPEARPackageTask extends MatchingTask { + +    /** Base directory for reading files. */ +    private $dir; + +	private $version; +	private $state = 'stable'; +	private $notes; +	 +	private $filesets = array(); +	 +    /** Package file */ +    private $packageFile; + +    public function init() { +        include_once 'PEAR/PackageFileManager2.php'; +        if (!class_exists('PEAR_PackageFileManager2')) { +            throw new BuildException("You must have installed PEAR_PackageFileManager2 (PEAR_PackageFileManager >= 1.6.0) in order to create a PEAR package.xml file."); +        } +    } + +    private function setOptions($pkg){ + +		$options['baseinstalldir'] = 'phing'; +        $options['packagedirectory'] = $this->dir->getAbsolutePath(); + +        if (empty($this->filesets)) { +			throw new BuildException("You must use a <fileset> tag to specify the files to include in the package.xml"); +		} + +		$options['filelistgenerator'] = 'Fileset'; + +		// Some PHING-specific options needed by our Fileset reader +		$options['phing_project'] = $this->getProject(); +		$options['phing_filesets'] = $this->filesets; +		 +		if ($this->packageFile !== null) { +            // create one w/ full path +            $f = new PhingFile($this->packageFile->getAbsolutePath()); +            $options['packagefile'] = $f->getName(); +            // must end in trailing slash +            $options['outputdirectory'] = $f->getParent() . DIRECTORY_SEPARATOR; +            $this->log("Creating package file: " . $f->getPath(), PROJECT_MSG_INFO); +        } else { +            $this->log("Creating [default] package.xml file in base directory.", PROJECT_MSG_INFO); +        } +		 +		// add install exceptions +		$options['installexceptions'] = array(	'bin/phing.php' => '/', +												'bin/pear-phing' => '/', +												'bin/pear-phing.bat' => '/', +												); + +		$options['dir_roles'] = array(	'phing_guide' => 'doc', +										'etc' => 'data', +										'example' => 'doc'); + +		$options['exceptions'] = array(	'bin/pear-phing.bat' => 'script', +										'bin/pear-phing' => 'script', +										'CREDITS' => 'doc', +										'CHANGELOG' => 'doc', +										'README' => 'doc', +										'TODO' => 'doc'); + +		$pkg->setOptions($options); + +    } + +    /** +     * Main entry point. +     * @return void +     */ +    public function main() { + +        if ($this->dir === null) { +            throw new BuildException("You must specify the \"dir\" attribute for PEAR package task."); +        } + +		if ($this->version === null) { +            throw new BuildException("You must specify the \"version\" attribute for PEAR package task."); +        } + +		$package = new PEAR_PackageFileManager2(); + +		$this->setOptions($package); + +		// the hard-coded stuff +		$package->setPackage('phing'); +		$package->setSummary('PHP5 project build system based on Apache Ant'); +		$package->setDescription('PHing Is Not GNU make; it\'s a project build system based on Apache Ant.  +You can do anything with it that you could do with a traditional build system like GNU make, and its use of  +simple XML build files and extensible PHP "task" classes make it an easy-to-use and highly flexible build framework.  +Features include file transformations (e.g. token replacement, XSLT transformation, Smarty template transformations,  +etc.), file system operations, interactive build support, SQL execution, and much more.'); +		$package->setChannel('pear.phing.info'); +		$package->setPackageType('php'); + +		$package->setReleaseVersion($this->version); +		$package->setAPIVersion($this->version); +		 +		$package->setReleaseStability($this->state); +		$package->setAPIStability($this->state); +		 +		$package->setNotes($this->notes); +		 +		$package->setLicense('LGPL', 'http://www.gnu.org/licenses/lgpl.html'); +		 +		// Add package maintainers +		$package->addMaintainer('lead', 'hans', 'Hans Lellelid', 'hans@xmpl.org'); +		$package->addMaintainer('lead', 'mrook', 'Michiel Rook', 'michiel@trendserver.nl'); +		 +		 +		 +		// (wow ... this is a poor design ...) +		// +		// note that the order of the method calls below is creating +		// sub-"release" sections which have specific rules.  This replaces +		// the platformexceptions system in the older version of PEAR's package.xml +		// +		// Programmatically, I feel the need to re-iterate that this API for PEAR_PackageFileManager +		// seems really wrong.  Sub-sections should be encapsulated in objects instead of having +		// a "flat" API that does not represent the structure being created.... +		 +		 +		// creating a sub-section for 'windows' +			$package->addRelease(); +			$package->setOSInstallCondition('windows'); +			$package->addInstallAs('bin/phing.php', 'phing.php'); +			$package->addInstallAs('bin/pear-phing.bat', 'phing.bat'); +			$package->addIgnoreToRelease('bin/pear-phing'); +		 +		// creating a sub-section for non-windows +			$package->addRelease(); +			//$package->setOSInstallCondition('(*ix|*ux|darwin*|*BSD|SunOS*)'); +			$package->addInstallAs('bin/phing.php', 'phing.php'); +			$package->addInstallAs('bin/pear-phing', 'phing'); +			$package->addIgnoreToRelease('bin/pear-phing.bat'); +		 + +		// "core" dependencies +		$package->setPhpDep('5.0.0'); +		$package->setPearinstallerDep('1.4.0'); +		 +		// "package" dependencies +		$package->addPackageDepWithChannel( 'optional', 'VersionControl_SVN', 'pear.php.net', '0.3.0alpha1'); +		$package->addPackageDepWithChannel( 'optional', 'PHPUnit2', 'pear.php.net', '2.3.0'); +		$package->addPackageDepWithChannel( 'optional', 'PhpDocumentor', 'pear.php.net', '1.3.0RC3'); +		$package->addPackageDepWithChannel( 'optional', 'Xdebug', 'pear.php.net', '2.0.0beta2'); +		$package->addPackageDepWithChannel( 'optional', 'Archive_Tar', 'pear.php.net', '1.3.0'); +		$package->addPackageDepWithChannel( 'optional', 'PEAR_PackageFileManager', 'pear.php.net', '1.5.2'); + +		// now add the replacements .... +		$package->addReplacement('Phing.php', 'pear-config', '@DATA-DIR@', 'data_dir'); +		$package->addReplacement('bin/pear-phing.bat', 'pear-config', '@PHP-BIN@', 'php_bin'); +		$package->addReplacement('bin/pear-phing.bat', 'pear-config', '@BIN-DIR@', 'bin_dir'); +		$package->addReplacement('bin/pear-phing.bat', 'pear-config', '@PEAR-DIR@', 'php_dir'); +		$package->addReplacement('bin/pear-phing', 'pear-config', '@PHP-BIN@', 'php_bin'); +		$package->addReplacement('bin/pear-phing', 'pear-config', '@BIN-DIR@', 'bin_dir'); +		$package->addReplacement('bin/pear-phing', 'pear-config', '@PEAR-DIR@', 'php_dir'); +		 +		// now we run this weird generateContents() method that apparently  +		// is necessary before we can add replacements ... ? +		$package->generateContents(); +		 +        $e = $package->writePackageFile(); + +        if (PEAR::isError($e)) { +            throw new BuildException("Unable to write package file.", new Exception($e->getMessage())); +        } + +    } + +    /** +     * Used by the PEAR_PackageFileManager_PhingFileSet lister. +     * @return array FileSet[] +     */ +    public function getFileSets() { +        return $this->filesets; +    } + +    // ------------------------------- +    // Set properties from XML +    // ------------------------------- + +    /** +     * Nested creator, creates a FileSet for this task +     * +     * @return FileSet The created fileset object +     */ +    function createFileSet() { +        $num = array_push($this->filesets, new FileSet()); +        return $this->filesets[$num-1]; +    } + +	/** +     * Set the version we are building. +     * @param string $v +     * @return void +     */ +	public function setVersion($v){ +		$this->version = $v; +	} + +	/** +     * Set the state we are building. +     * @param string $v +     * @return void +     */ +	public function setState($v) { +		$this->state = $v; +	} +	 +	/** +	 * Sets release notes field. +	 * @param string $v +	 * @return void +	 */ +	public function setNotes($v) { +		$this->notes = $v; +	} +    /** +     * Sets "dir" property from XML. +     * @param PhingFile $f +     * @return void +     */ +    public function setDir(PhingFile $f) { +        $this->dir = $f; +    } + +    /** +     * Sets the file to use for generated package.xml +     */ +    public function setDestFile(PhingFile $f) { +        $this->packageFile = $f; +    } + +} + + diff --git a/buildscripts/phing/pear/build.xml b/buildscripts/phing/pear/build.xml new file mode 100644 index 00000000..128dcd03 --- /dev/null +++ b/buildscripts/phing/pear/build.xml @@ -0,0 +1,156 @@ +<?xml version="1.0"?> +<!-- +	This build file packages the phing files, builds a package.xml (version 2) for installation +	using PEAR and creates the TAR and TGZ files. +--> +<project name="phing" basedir="." default="main"> + +	<property name="phing.home" value=".."/> +	<property name="build.base.dir" value="build"/> +	<property name="pkgname" value="phing-${version}"/> +	<property name="build.src.dir" value="${build.base.dir}/${pkgname}"/> + +	<!-- some default properties --> +	<property name="notes">This is the latest release of Phing.</property> +	<property name="state" value="stable"/> + +	<taskdef +    name="pear-package" +    classname="BuildPhingPEARPackageTask" classpath="."/> + +	<fileset dir="${phing.home}/classes/phing" id="classes"> +		<include name="**"/> +	</fileset> + +	<fileset dir="${phing.home}/docs" id="docs"> +		<include name="example/**"/> +		<include name="phing_guide/book/**"/> +	</fileset> + +	<fileset dir="${phing.home}" id="etc"> +		<include name="etc/**"/> +		<exclude name="etc/VERSION.TXT"/> +	</fileset> + +	<fileset dir="${phing.home}" id="scripts"> +		<include name="bin/pear-*"/> +		<include name="bin/phing.php"/> +	</fileset> + +	<fileset dir="${phing.home}" id="misc"> +		<include name="CHANGELOG"/> +		<include name="CREDITS"/> +		<include name="README"/> +		<include name="TODO"/> +		<exclude name="INSTALL*"/> +	</fileset> + +	<!-- +		============================================== +		Main entry point +		============================================== +	--> +	<target name="main" if="version" depends="versioncheck,copy-files,create-package-xml,tar"/> + +	<!-- +	 =================================================================== +	 Target: checks if language was given, otherwise fail +	 =================================================================== +	--> +	<target name="versioncheck" unless="version"> +		<echo message="====================================================="/> +		<echo message="Version not specified. You must enter a version. In"/> +		<echo message="the future you can add this to build.properties or"/> +		<echo message="enter it on the command line: "/> +		<echo message=" "/> +		<echo message="-Dversion=2.0.0b1"/> +		<echo message="====================================================="/> +		<input propertyname="version" promptChar=":">Phing version for package</input> + +		<property name="pkgname" value="phing-${version}" override="true"/> +		<property name="build.src.dir" value="${build.base.dir}/${pkgname}" override="true"/> + +	</target> + +	<!-- +		============================================== +		Copy the desired files into the build/ dir +		making sure to put them in the directory +		structure that will be needed for PEAR install +		============================================== +	--> +	<target name="copy-files"> + +		<echo>-----------------------------</echo> +		<echo>| Creating directory layout |</echo> +		<echo>-----------------------------</echo> + +		<delete dir="${build.base.dir}"/> + +		<copy todir="${build.src.dir}"> +			<fileset refid="classes"/> +			<fileset refid="docs"/> +			<fileset refid="etc"/> +			<fileset refid="scripts"/> +			<fileset refid="misc"/> +		</copy> + +		<append destFile="${build.src.dir}/etc/VERSION.TXT">Phing version ${version}</append> + +		<chmod file="${build.src.dir}/bin/pear-phing" mode="755"/> + +	</target> + +	<!-- +		============================================== +		Create a PEAR package.xml which will guide the +		installation. +		============================================== +	--> +	<target name="create-package-xml" depends="versioncheck" if="version"> + +		<echo>-----------------------------</echo> +		<echo>| Creating PEAR package.xml |</echo> +		<echo>-----------------------------</echo> +		<echo></echo> +		<echo>... (This step may take some time) ...</echo> + +		<delete	file="${tarfile}"/> +		<pear-package dir="${build.src.dir}" destFile="${build.base.dir}/package.xml" version="${version}" state="${state}" notes="${notes}"> + +			<fileset refid="classes"/> +			<fileset refid="docs"/> +			<fileset refid="etc"/> +			<fileset refid="misc"/> +			<fileset refid="scripts"/> + +			<fileset dir="${build.src.dir}"> +				<include name="etc/VERSION.TXT"/> +			</fileset> + +		</pear-package> + +	</target> + +	<!-- +		============================================== +		Create a tar.gz of the files, which will be +		installed by pear package manager. +		============================================== +	--> +	<target name="tar"> +		<echo>-----------------------------</echo> +		<echo>| Creating TAR packages     |</echo> +		<echo>-----------------------------</echo> + +		<property name="tgzfile" value="${build.base.dir}/${pkgname}.tgz"/> +		<delete	file="${tgzfile}"/> +		<tar compression="gzip" destFile="${tgzfile}" basedir="${build.base.dir}" /> + +		<property name="tarfile" value="${build.base.dir}/${pkgname}.tar"/> +		<delete	file="${tarfile}"/> +		<tar compression="none" destFile="${tarfile}" basedir="${build.base.dir}" /> + +	</target> + +</project>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/ManualIndexTask.php b/buildscripts/phing/tasks/ManualIndexTask.php new file mode 100644 index 00000000..1725880f --- /dev/null +++ b/buildscripts/phing/tasks/ManualIndexTask.php @@ -0,0 +1,38 @@ +<?php
 +
 +require_once 'phing/Task.php';
 +
 +/**
 + * Task to index PRADO API docs.
 + */	
 +class ManualIndexTask extends Task
 +{
 +	private $docdir;
 +	private $todir;
 +	
 +	/**
 +	 * @param string the API documentation directory
 +	 */
 +	public function setDocdir($value)
 +	{
 +		$this->docdir=$value;
 +	}
 +	
 +	public function setTodir($value)
 +	{
 +		$this->todir=$value;
 +	}
 +
 +	public function main()
 +	{
 +		$srcdir=realpath(dirname(__FILE__).'/../../../');
 +		$zend_path = $srcdir.'/demos/quickstart/protected/index';
 +		set_include_path(get_include_path().PATH_SEPARATOR.realpath($zend_path));
 +		require_once ('Zend/Search/Lucene.php');
 +		require_once($srcdir.'/buildscripts/index/api_index.php');
 +		$api = new api_index($this->todir, realpath($this->docdir));
 +		$api->create_index();
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoDocTask.php b/buildscripts/phing/tasks/PradoDocTask.php new file mode 100644 index 00000000..3ab891bd --- /dev/null +++ b/buildscripts/phing/tasks/PradoDocTask.php @@ -0,0 +1,137 @@ +<?php
 +require_once 'phing/Task.php';
 +
 +/**
 + * Task to run phpDocumentor for PRADO API docs.
 + */	
 +class PradoDocTask extends Task
 +{
 +	private $phpdoc = 'phpdoc';
 +	
 +	private $title = "Default Title";
 +			
 +	private $destdir = ".";
 +			
 +	private $sourcepath = NULL;
 +	
 +	private $ignorelist = '';
 +	
 +	private $output = "";
 +			
 +	private $linksource = false;
 +	
 +	private $parseprivate = false;
 +
 +	function setPhpdoc($phpdoc)
 +	{
 +		$this->phpdoc=$phpdoc;
 +	}
 +	
 +	/**
 +	 * Set the title for the generated documentation
 +	 */
 +	function setTitle($title)
 +	{
 +		$this->title = $title;
 +	}
 +	
 +	/**
 +	 * Set the destination directory for the generated documentation
 +	 */
 +	function setDestdir($destdir)
 +	{
 +		$this->destdir = $destdir;
 +	}
 +	
 +	/**
 +	 * Set the source path
 +	 */
 +	function setSourcepath(Path $sourcepath)
 +	{
 +		if ($this->sourcepath === NULL)
 +		{
 +			$this->sourcepath = $sourcepath;
 +		}
 +		else
 +		{
 +			$this->sourcepath->append($sourcepath);
 +		}
 +	}
 +	
 +	/**
 +	 * Set the output type
 +	 */		
 +	function setOutput($output)
 +	{
 +		$this->output = $output;
 +	}
 +	
 +	/**
 +	 * Should sources be linked in the generated documentation
 +	 */
 +	function setLinksource($linksource)
 +	{
 +		$this->linksource = $linksource;
 +	}
 +
 +	function setIgnorelist($ignorelist)
 +	{
 +		$this->ignorelist=$ignorelist;
 +	}	
 +	
 +	/**
 +	 * Main entrypoint of the task
 +	 */
 +	function main()
 +	{
 +		$arguments = $this->constructArguments();
 +		exec($this->phpdoc . " " . $arguments, $output, $retval);
 +	}
 +	
 +	/**
 +	 * Constructs an argument string for phpDocumentor
 +	 */
 +	private function constructArguments()
 +	{
 +		$arguments = "-q \"on\" ";
 +		
 +		if ($this->title)
 +		{
 +			$arguments.= "-ti \"" . $this->title . "\" ";
 +		}
 +		
 +		if ($this->destdir)
 +		{
 +			$arguments.= "-t \"" . $this->destdir . "\" ";
 +		}
 +		
 +		if ($this->sourcepath !== NULL)
 +		{
 +			$arguments.= "-d \"" . $this->sourcepath->__toString() . "\" ";
 +		}
 +		
 +		if ($this->output)
 +		{
 +			$arguments.= "-o \"" . $this->output . "\" ";
 +		}
 +		
 +		if ($this->linksource)
 +		{
 +			$arguments.= "-s ";
 +		}
 +		
 +		if ($this->parseprivate)
 +		{
 +			$arguments.= "-pp ";
 +		}
 +
 +		if ($this->ignorelist)
 +		{
 +			$arguments.='-i "'.$this->ignorelist.'" ';
 +		}
 +
 +		return $arguments;
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoPearTask.php b/buildscripts/phing/tasks/PradoPearTask.php new file mode 100644 index 00000000..5d615084 --- /dev/null +++ b/buildscripts/phing/tasks/PradoPearTask.php @@ -0,0 +1,133 @@ +<?php + +require_once 'phing/Task.php'; +require_once('PEAR/PackageFileManager2.php'); + +/** + * Task to run phpDocumentor for PRADO API docs. + */ +class PradoPearTask extends Task +{ +	private $pkgdir; +	private $channel; +	private $version; +	private $state; +	private $category; +	private $package; +	private $summary; +	private $pkgdescription; +	private $notes; +	private $license; + +	function setPkgdir($value) +	{ +		$this->pkgdir=$value; +	} + +	function setChannel($value) +	{ +		$this->channel=$value; +	} + +	function setVersion($value) +	{ +		$this->version=$value; +	} + +	function setState($value) +	{ +		$this->state=$value; +	} + +	function setCategory($value) +	{ +		$this->category=$value; +	} + +	function setPackage($value) +	{ +		$this->package=$value; +	} + +	function setSummary($value) +	{ +		$this->summary=$value; +	} + +	function setPkgdescription($value) +	{ +		$this->pkgdescription=$value; +	} + +	function setNotes($value) +	{ +		$this->notes=$value; +	} + +	function setLicense($value) +	{ +		$this->license=$value; +	} + +	/** +	 * Main entrypoint of the task +	 */ +	function main() +	{ +		$pkg = new PEAR_PackageFileManager2(); + +		$e = $pkg->setOptions( +			array( +				'baseinstalldir'    => 'prado', +				'packagedirectory'  => $this->pkgdir, +				'pathtopackagefile' => $this->pkgdir, +				'filelistgenerator' => 'file', +				'simpleoutput'      => true, +				'ignore'            => array(), +				'dir_roles'         => +					array( +						'docs'          => 'doc', +						'examples'      => 'doc', +						'framework'     => 'php', +						'framework/js'  => 'doc', +						'framework/3rdParty' => 'doc', +					), +				'exceptions' => +					array( +						'requirements.php' => 'doc', +					), +			) +		); + +		// PEAR error checking +		if (PEAR::isError($e)) +			die($e->getMessage()); +		$pkg->setPackage($this->package); +		$pkg->setSummary($this->summary); +		$pkg->setDescription($this->pkgdescription); +		$pkg->setChannel($this->channel); + +		$pkg->setReleaseStability($this->state); +		$pkg->setAPIStability($this->state); +		$pkg->setReleaseVersion($this->version); +		$pkg->setAPIVersion($this->version); + +		$pkg->setLicense($this->license); +		$pkg->setNotes($this->notes); +		$pkg->setPackageType('php'); +		$pkg->setPhpDep('5.0.0'); +		$pkg->setPearinstallerDep('1.4.2'); + +		$pkg->addRelease(); +		$pkg->addMaintainer('lead','qxue','Qiang (Charlie) Xue','qiang.xue@gmail.com'); + +		$test = $pkg->generateContents(); + +		$e = $pkg->writePackageFile(); + +		if (PEAR::isError($e)) +			echo $e->getMessage(); +	} +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoTestTask.php b/buildscripts/phing/tasks/PradoTestTask.php new file mode 100644 index 00000000..ba1e06be --- /dev/null +++ b/buildscripts/phing/tasks/PradoTestTask.php @@ -0,0 +1,18 @@ +<?php
 +require_once 'phing/Task.php';
 +require_once 'phing/tasks/ext/phpunit2/PHPUnit2Task.php';
 +
 +/**
 + * Task to run PRADO unit tests
 + */	
 +class PradoTestTask extends PHPUnit2Task
 +{
 +	function init()
 +	{
 +		$phpunit2_path = realpath(dirname(__FILE__).'/../..');
 +		set_include_path(get_include_path().PATH_SEPARATOR.$phpunit2_path);		
 +		parent::init();
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/PradoVersionTask.php b/buildscripts/phing/tasks/PradoVersionTask.php new file mode 100644 index 00000000..911b68d4 --- /dev/null +++ b/buildscripts/phing/tasks/PradoVersionTask.php @@ -0,0 +1,56 @@ +<?php +require_once 'phing/Task.php'; +include_once 'phing/tasks/system/PropertyTask.php'; + +class PradoVersionTask extends PropertyTask +{ +	/** +	* Execute lint check against PhingFile or a FileSet +	*/ +	public function main() +	{ +		$this->addProperty('prado.version',$this->getPradoVersion()); +		$this->addProperty('prado.revision',$this->getPradoRevision()); +		if(substr(PHP_OS, 0, 3) == 'WIN') +			$this->addProperty('prado.winbuild','true'); +		else +			$this->addProperty('prado.winbuild','false'); +	} + +	/** +	 * @return string Prado version +	 */ +	private function getPradoVersion() +	{ +		$coreFile=dirname(__FILE__).'/../../../framework/PradoBase.php'; +		if(is_file($coreFile)) +		{ +			$contents=file_get_contents($coreFile); +			$matches=array(); +			if(preg_match('/public static function getVersion.*?return \'(.*?)\'/ms',$contents,$matches)>0) +				return $matches[1]; +		} +		return 'unknown'; +	} + +	/** +	 * @return string Prado SVN revision +	 */ +	private function getPradoRevision() +	{ +		$svnPath=dirname(__FILE__).'/../../../.svn'; +		if(is_file($svnPath.'/all-wcprops')) +			$propFile=$svnPath.'/all-wcprops'; +		else if(is_file($svnPath.'/dir-wcprops')) +			$propFile=$svnPath.'/dir-wcprops'; +		else +			return 'unknown'; +		$contents=file_get_contents($propFile); +		if(preg_match('/\\/repos\\/prado\\/\\!svn\\/ver\\/(\d+)\\//ms',$contents,$matches)>0) +			return $matches[1]; +		else +			return 'unknown'; +	} +} + +?>
\ No newline at end of file diff --git a/buildscripts/phing/tasks/QuickstartIndexTask.php b/buildscripts/phing/tasks/QuickstartIndexTask.php new file mode 100644 index 00000000..f3107fd3 --- /dev/null +++ b/buildscripts/phing/tasks/QuickstartIndexTask.php @@ -0,0 +1,32 @@ +<?php
 +
 +require_once 'phing/Task.php';
 +
 +/**
 + * Task to index quickstart
 + */	
 +class QuickstartIndexTask extends Task
 +{
 +	private $todir;
 +
 +	public function setTodir($value)
 +	{
 +		$this->todir=$value;
 +	}
 +
 +	public function main()
 +	{
 +		$srcdir=realpath(dirname(__FILE__).'/../../../');
 +		$zend_path = $srcdir.'/demos/quickstart/protected/index';
 +		set_include_path(get_include_path().PATH_SEPARATOR.realpath($zend_path));
 +		require_once ('Zend/Search/Lucene.php');
 +		
 +		require_once($srcdir.'/buildscripts/index/quickstart_index.php');
 +		$quickstart_source = $srcdir.'/buildscripts/texbuilder/pages.php';
 +		$quickstart_base = $srcdir.'/demos/quickstart/protected/pages/';
 +		$quickstart = new quickstart_index($this->todir, realpath($quickstart_base), realpath($quickstart_source));
 +		$quickstart->create_index();
 +	}
 +}
 +
 +?>
\ No newline at end of file  | 
