summaryrefslogtreecommitdiff
path: root/buildscripts
diff options
context:
space:
mode:
authorctrlaltca <>2012-11-18 17:18:54 +0000
committerctrlaltca <>2012-11-18 17:18:54 +0000
commitcfd546c6b3240bd9d1ef34a9f6201b360fac3261 (patch)
tree626b0885f54cc5a066e92b3d6b4307756ace09c2 /buildscripts
parent17139224a1f1f2bbdcc1f1a98cb20f60a12bdfab (diff)
update ping. Part 2: added ping 2.4.12, fixed caller script
Diffstat (limited to 'buildscripts')
-rw-r--r--buildscripts/phing/CHANGELOG.md789
-rw-r--r--buildscripts/phing/CREDITS.md51
-rw-r--r--buildscripts/phing/LICENSE165
-rw-r--r--buildscripts/phing/README.md64
-rwxr-xr-xbuildscripts/phing/bin/phing87
-rw-r--r--buildscripts/phing/bin/phing.bat58
-rwxr-xr-xbuildscripts/phing/bin/phing.php56
-rwxr-xr-xbuildscripts/phing/classes/phing/BuildEvent.php198
-rwxr-xr-xbuildscripts/phing/classes/phing/BuildException.php124
-rwxr-xr-xbuildscripts/phing/classes/phing/BuildListener.php91
-rwxr-xr-xbuildscripts/phing/classes/phing/BuildLogger.php70
-rwxr-xr-xbuildscripts/phing/classes/phing/ConfigurationException.php85
-rwxr-xr-xbuildscripts/phing/classes/phing/IntrospectionHelper.php575
-rwxr-xr-xbuildscripts/phing/classes/phing/Phing.php1414
-rwxr-xr-xbuildscripts/phing/classes/phing/Project.php1050
-rwxr-xr-xbuildscripts/phing/classes/phing/ProjectComponent.php70
-rwxr-xr-xbuildscripts/phing/classes/phing/RuntimeConfigurable.php116
-rwxr-xr-xbuildscripts/phing/classes/phing/Target.php375
-rwxr-xr-xbuildscripts/phing/classes/phing/Task.php272
-rwxr-xr-xbuildscripts/phing/classes/phing/TaskAdapter.php85
-rwxr-xr-xbuildscripts/phing/classes/phing/TaskContainer.php44
-rwxr-xr-xbuildscripts/phing/classes/phing/UnknownElement.php215
-rw-r--r--buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Manager.php304
-rw-r--r--buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/README.md106
-rw-r--r--buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Worker.php203
-rw-r--r--buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/WorkerPipe.php127
-rw-r--r--buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/example.php57
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/BaseFilterReader.php157
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/BaseParamFilterReader.php69
-rw-r--r--buildscripts/phing/classes/phing/filters/ChainableReader.php43
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/ExpandProperties.php99
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/HeadFilter.php161
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/IconvFilter.php155
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/LineContains.php260
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/LineContainsRegexp.php179
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/PrefixLines.php142
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/ReplaceRegexp.php129
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/ReplaceTokens.php435
-rw-r--r--buildscripts/phing/classes/phing/filters/ReplaceTokensWithFile.php361
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/StripLineBreaks.php148
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/StripLineComments.php207
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/StripPhpComments.php188
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/StripWhitespace.php95
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/TabToSpaces.php144
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/TailFilter.php157
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/TidyFilter.php162
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/TranslateGettext.php285
-rw-r--r--buildscripts/phing/classes/phing/filters/XincludeFilter.php176
-rw-r--r--buildscripts/phing/classes/phing/filters/XsltFilter.php408
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php183
-rwxr-xr-xbuildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php97
-rwxr-xr-xbuildscripts/phing/classes/phing/input/DefaultInputHandler.php85
-rwxr-xr-xbuildscripts/phing/classes/phing/input/InputHandler.php45
-rwxr-xr-xbuildscripts/phing/classes/phing/input/InputRequest.php107
-rwxr-xr-xbuildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php58
-rwxr-xr-xbuildscripts/phing/classes/phing/input/YesNoInputRequest.php47
-rwxr-xr-xbuildscripts/phing/classes/phing/lib/Capsule.php267
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/AnsiColorLogger.php234
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/DefaultLogger.php279
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/HtmlColorLogger.php175
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/MailLogger.php105
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/NoBannerLogger.php59
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/PearLogListener.php197
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/StreamRequiredBuildLogger.php39
-rwxr-xr-xbuildscripts/phing/classes/phing/listener/XmlLogger.php354
-rw-r--r--buildscripts/phing/classes/phing/listener/defaults.properties43
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/FileNameMapper.php59
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/FlattenMapper.php55
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/GlobMapper.php113
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/IdentityMapper.php54
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/MergeMapper.php69
-rwxr-xr-xbuildscripts/phing/classes/phing/mappers/RegexpMapper.php97
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/AbstractHandler.php98
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/AbstractSAXParser.php116
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/DataTypeHandler.php144
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/ExpatParseException.php31
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/ExpatParser.php140
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/Location.php76
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/NestedElementHandler.php186
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/PhingXMLContext.php81
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/ProjectConfigurator.php387
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/ProjectHandler.php176
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/RootHandler.php82
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/TargetHandler.php196
-rwxr-xr-xbuildscripts/phing/classes/phing/parser/TaskHandler.php234
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/BufferedReader.php168
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/BufferedWriter.php71
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/ConsoleReader.php84
-rw-r--r--buildscripts/phing/classes/phing/system/io/FileInputStream.php79
-rw-r--r--buildscripts/phing/classes/phing/system/io/FileOutputStream.php71
-rw-r--r--buildscripts/phing/classes/phing/system/io/FileReader.php41
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/FileSystem.php840
-rw-r--r--buildscripts/phing/classes/phing/system/io/FileWriter.php42
-rw-r--r--buildscripts/phing/classes/phing/system/io/FilterReader.php68
-rw-r--r--buildscripts/phing/classes/phing/system/io/IOException.php27
-rw-r--r--buildscripts/phing/classes/phing/system/io/InputStream.php178
-rw-r--r--buildscripts/phing/classes/phing/system/io/InputStreamReader.php127
-rw-r--r--buildscripts/phing/classes/phing/system/io/OutputStream.php108
-rw-r--r--buildscripts/phing/classes/phing/system/io/OutputStreamWriter.php84
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/PhingFile.php996
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/Reader.php91
-rw-r--r--buildscripts/phing/classes/phing/system/io/StringReader.php84
-rwxr-xr-xbuildscripts/phing/classes/phing/system/io/UnixFileSystem.php302
-rw-r--r--buildscripts/phing/classes/phing/system/io/Win32FileSystem.php477
-rw-r--r--buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php34
-rw-r--r--buildscripts/phing/classes/phing/system/io/Writer.php53
-rw-r--r--buildscripts/phing/classes/phing/system/lang/Character.php49
-rw-r--r--buildscripts/phing/classes/phing/system/lang/EventObject.php52
-rw-r--r--buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php26
-rw-r--r--buildscripts/phing/classes/phing/system/lang/NullPointerException.php26
-rw-r--r--buildscripts/phing/classes/phing/system/lang/SecurityException.php26
-rwxr-xr-xbuildscripts/phing/classes/phing/system/util/Properties.php314
-rwxr-xr-xbuildscripts/phing/classes/phing/system/util/Register.php149
-rwxr-xr-xbuildscripts/phing/classes/phing/system/util/Timer.php96
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/defaults.properties145
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php480
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ExportPropertiesTask.php141
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ExtractBaseTask.php199
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/FileHashTask.php147
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/FileSizeTask.php120
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/FtpDeployTask.php233
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/HttpGetTask.php170
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/HttpRequestTask.php286
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/JslLintTask.php284
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/MailTask.php159
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ManifestTask.php343
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php65
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/ParallelTask.php83
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/PatchTask.php301
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/PearPackage2Task.php279
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php504
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/PhpCodeSnifferTask.php648
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php278
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ReplaceRegexpTask.php204
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ScpTask.php380
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/Service/Amazon.php120
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3.php188
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3GetTask.php108
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3PutTask.php243
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php610
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/SshTask.php224
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/Arg.php96
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/SymfonyConsoleTask.php113
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/SymlinkTask.php309
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/TarTask.php445
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/UntarTask.php89
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/UnzipTask.php77
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/VersionTask.php217
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php179
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/XmlPropertyTask.php273
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php207
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/ZipTask.php301
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/apigen/ApiGenTask.php439
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php154
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php92
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php564
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php176
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php164
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageThresholdTask.php458
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/creole/CreoleSQLExecTask.php592
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/creole/CreoleTask.php242
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbDeployTask.php436
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntax.php34
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php67
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php37
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php37
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php37
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php36
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php37
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/docblox/DocBloxTask.php221
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitBaseTask.php134
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitBranchTask.php296
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitCheckoutTask.php256
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitCloneTask.php128
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitCommitTask.php179
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitFetchTask.php284
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitGcTask.php158
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitInitTask.php81
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitLogTask.php270
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitMergeTask.php258
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitPullTask.php373
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitPushTask.php255
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/git/GitTagTask.php406
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php43
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php642
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php208
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMin.php292
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMinTask.php145
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/AbstractLiquibaseTask.php184
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseChangeLogTask.php39
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDbDocTask.php86
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDiffTask.php137
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseRollbackTask.php72
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseTagTask.php75
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseUpdateTask.php39
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php109
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependLoggerElement.php105
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependTask.php506
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php151
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pdo/PDOQuerySplitter.php63
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdo/PDOResultFormatter.php84
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php313
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php606
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pdo/PDOTask.php215
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php291
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php130
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php141
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php228
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadata.php55
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadataElement.php80
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phar/PharPackageTask.php362
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageTask.php248
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccess.php57
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccessPath.php46
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php177
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDTask.php312
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php58
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php40
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php51
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php98
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php230
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentor2Task.php224
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorExternalTask.php265
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorTask.php480
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDFormatterElement.php181
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDTask.php284
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/BatchTest.php230
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/FormatterElement.php178
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitReportTask.php248
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTask.php378
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTestRunner.php312
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitUtil.php141
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php87
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php203
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php128
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php62
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php120
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/rSTTask.php476
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php51
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php119
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php68
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php95
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php161
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php53
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php264
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php178
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php347
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnCheckoutTask.php67
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnCommitTask.php113
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnCopyTask.php70
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php70
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnInfoTask.php112
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php120
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/svn/SvnListTask.php128
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/ext/svn/SvnLogTask.php108
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnSwitchTask.php73
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/svn/SvnUpdateTask.php67
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardEncodeTask.php510
-rw-r--r--buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardLicenseTask.php524
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/AdhocTask.php88
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php103
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php71
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/AppendTask.php240
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/AvailableTask.php172
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ChmodTask.php203
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ChownTask.php216
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ConditionTask.php74
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/CopyTask.php480
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/CvsPassTask.php173
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/CvsTask.php540
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/DeleteTask.php276
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/EchoTask.php152
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ExecTask.php516
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/FailTask.php118
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ForeachTask.php320
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/IfTask.php227
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ImportTask.php136
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/IncludePathTask.php115
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/InputTask.php150
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/LoadFileTask.php119
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/MatchingTask.php361
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/MkdirTask.php79
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/MoveTask.php202
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/PhingCallTask.php161
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/PhingTask.php627
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php192
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php234
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/PropertyTask.php438
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php155
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php159
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/SequentialTask.php58
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/TaskdefTask.php165
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/TouchTask.php170
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/TryCatchTask.php123
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/TstampTask.php171
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/TypedefTask.php127
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/UpToDateTask.php257
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/WaitForTask.php188
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/WarnTask.php35
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/XsltTask.php103
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php46
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/Condition.php38
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php197
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php76
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php78
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php60
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php53
-rw-r--r--buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php59
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php48
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php46
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php63
-rwxr-xr-xbuildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php52
-rwxr-xr-xbuildscripts/phing/classes/phing/types/AbstractFileSet.php587
-rwxr-xr-xbuildscripts/phing/classes/phing/types/Commandline.php475
-rw-r--r--buildscripts/phing/classes/phing/types/DataType.php182
-rw-r--r--buildscripts/phing/classes/phing/types/Description.php53
-rw-r--r--buildscripts/phing/classes/phing/types/DirSet.php49
-rw-r--r--buildscripts/phing/classes/phing/types/Excludes.php208
-rw-r--r--buildscripts/phing/classes/phing/types/ExcludesNameEntry.php81
-rwxr-xr-xbuildscripts/phing/classes/phing/types/FileList.php224
-rw-r--r--buildscripts/phing/classes/phing/types/FileSet.php56
-rwxr-xr-xbuildscripts/phing/classes/phing/types/FilterChain.php191
-rw-r--r--buildscripts/phing/classes/phing/types/IterableFileSet.php56
-rw-r--r--buildscripts/phing/classes/phing/types/Mapper.php207
-rw-r--r--buildscripts/phing/classes/phing/types/Parameter.php99
-rw-r--r--buildscripts/phing/classes/phing/types/Parameterizable.php32
-rw-r--r--buildscripts/phing/classes/phing/types/Path.php452
-rwxr-xr-xbuildscripts/phing/classes/phing/types/PatternSet.php493
-rw-r--r--buildscripts/phing/classes/phing/types/PearPackageFileSet.php179
-rwxr-xr-xbuildscripts/phing/classes/phing/types/PhingFilterReader.php136
-rw-r--r--buildscripts/phing/classes/phing/types/Reference.php56
-rwxr-xr-xbuildscripts/phing/classes/phing/types/RegularExpression.php128
-rwxr-xr-xbuildscripts/phing/classes/phing/types/TokenReader.php66
-rw-r--r--buildscripts/phing/classes/phing/types/TokenSource.php157
-rw-r--r--buildscripts/phing/classes/phing/types/defaults.properties13
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/AndSelector.php67
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php62
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/BaseSelector.php84
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php270
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php164
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php151
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/DateSelector.php214
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/DependSelector.php151
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/DepthSelector.php158
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php43
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php124
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/FileSelector.php47
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php157
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php92
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/NoneSelector.php71
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/NotSelector.php59
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/OrSelector.php72
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/PresentSelector.php154
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/SelectSelector.php124
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php141
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php55
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php200
-rw-r--r--buildscripts/phing/classes/phing/types/selectors/SizeSelector.php228
-rwxr-xr-xbuildscripts/phing/classes/phing/types/selectors/TypeSelector.php120
-rwxr-xr-xbuildscripts/phing/classes/phing/util/DataStore.php151
-rwxr-xr-xbuildscripts/phing/classes/phing/util/DirectoryScanner.php755
-rwxr-xr-xbuildscripts/phing/classes/phing/util/ExtendedFileStream.php129
-rwxr-xr-xbuildscripts/phing/classes/phing/util/FileUtils.php298
-rwxr-xr-xbuildscripts/phing/classes/phing/util/LogWriter.php95
-rw-r--r--buildscripts/phing/classes/phing/util/PathTokenizer.php245
-rw-r--r--buildscripts/phing/classes/phing/util/PearPackageScanner.php170
-rw-r--r--buildscripts/phing/classes/phing/util/SourceFileScanner.php159
-rw-r--r--buildscripts/phing/classes/phing/util/StringHelper.php208
-rw-r--r--buildscripts/phing/classes/phing/util/regexp/PregEngine.php167
-rwxr-xr-xbuildscripts/phing/classes/phing/util/regexp/Regexp.php203
-rwxr-xr-xbuildscripts/phing/classes/phing/util/regexp/RegexpEngine.php73
-rw-r--r--buildscripts/phing/composer.json23
-rw-r--r--buildscripts/phing/etc/VERSION.TXT1
-rwxr-xr-xbuildscripts/phing/etc/coverage-frames.xsl1067
-rwxr-xr-xbuildscripts/phing/etc/log.xsl216
-rw-r--r--buildscripts/phing/etc/phing-grammar.rng5015
-rwxr-xr-xbuildscripts/phing/etc/phpunit-frames.xsl694
-rwxr-xr-xbuildscripts/phing/etc/phpunit-noframes.xsl448
-rwxr-xr-xbuildscripts/phing/etc/str.replace.function.xsl105
379 files changed, 77424 insertions, 0 deletions
diff --git a/buildscripts/phing/CHANGELOG.md b/buildscripts/phing/CHANGELOG.md
new file mode 100644
index 00000000..f2667454
--- /dev/null
+++ b/buildscripts/phing/CHANGELOG.md
@@ -0,0 +1,789 @@
+P H I N G
+=========================
+
+
+Apr. 6, 2012 - Phing 2.4.12
+---------------------------
+
+ * [877] Add 'level' attribute to resolvepath task
+ * [876] JslLint Task is_executable() broken
+ * [874] ParallelTask.php is not PHP 5.2 compatible
+ * [860] SvnBaseTask: getRecursive
+ * [539] Custom build log mailer
+ * [406] an ability to turn phpLint verbose ON and OFF
+
+Apr. 4, 2012 - Phing 2.4.11
+---------------------------
+
+ * [870] Can't find ParallelTask.php
+
+Apr. 3, 2012 - Phing 2.4.10
+---------------------------
+
+ * [872] ReplaceTokens can't work with '/' char
+ * [870] Can't find ParallelTask.php
+ * [868] Git Clone clones into wrong directory
+ * [865] static call to a non-static function PhingFile.php::getTempdir()
+ * [854] PropertyTask with file. Can't use a comment delimiter in the value.
+ * [853] PHP Error with HttpGetTask
+ * [852] Several minor errors in documentation of core tasks
+ * [851] RNG grammar hasn't been updated to current version
+ * [850] Typo in documentation - required attributes for project
+ * [849] Symfony 2 Console Task
+ * [847] Add support for RNG grammar in task XmlLint
+ * [846] RNG grammar is wrong for task 'foreach'
+ * [844] symlink task - overwrite not working
+ * [843] "verbose" option should print fileset/filelist filenames before execution, not afterwards
+ * [840] Prevent weird bugs: raise warning when a target tag contains no ending tag
+ * [835] JSL-Check faulty
+ * [834] ExecTask documentation has incorrect escape attribute default value
+ * [833] Exec task args with special characters cannot be escaped
+ * [828] SelectorUtils::matchPath matches **/._* matches dir/file._name
+ * [820] Type selector should treat symlinks to directories as such
+ * [790] Make it easy to add new inherited types to phing: Use addFileset instead of createFileset
+ * [772] Support for filelist in UpToDateTask
+ * [671] fix CvsTask documentation
+ * [587] More detailed backtrace in debug mode (patch)
+ * [519] Extend mail task to include attachments
+ * [419] schema file for editors and validation
+ * [334] Run a task on BuildException
+
+Dec. 29, 2011 - Phing 2.4.9
+---------------------------
+
+ * [837] PHPMDTask should check external dep in main()
+ * [836] DocBlox task breaks with version 0.17.0: function getThemesPath not found
+ * [831] dbdeploy undo script SQL is not formatted correctly
+ * [822] rSTTask: add debug statement when creating target directory
+ * [821] phingcall using a lot of memory
+ * [819] Documentation for SvnUpdateTask is outdated
+ * [818] [patch] Add overwrite option to Symlink task
+ * [817] Adding the "trust-server-cert" option to SVN tasks
+ * [816] Fix notice in SimpleTestXmlResultFormatter
+ * [811] phpunitreport path fails on linux
+ * [810] AvailableTask resolving symbolic links
+ * [807] SVN tasks do not always show error message
+ * [795] Untar : allow overwriting of newer files when extracting
+ * [782] PharTask is very slow for big project
+ * [776] Add waitFor task
+ * [736] Incompatibility when copying from Windows to Linux on ScpTask
+ * [709] talk about invalid property values
+ * [697] More descriptive error messages in PharPackageTask
+ * [674] Properties: global or local in tasks?
+ * [653] Allow ChownTask to change only group
+ * [619] verbose level in ExpandPropertiesFilter
+
+Nov. 2, 2011 - Phing 2.4.8
+--------------------------
+
+ * [814] Class 'PHPCPD_Log_XML' not found in /home/m/www/elvis/vendor/phpcpd/PHPCPD/Log/XML/PMD.php on line 55
+ * [812] Fix PHPUnit 3.6 / PHP_CodeCoverage 1.1.0 compatibility
+ * [808] Bad example for the <or> selector
+ * [805] phing executable has bug in ENV/PHP_COMMAND
+ * [804] PhpUnitTask overwrites autoload stack
+ * [801] PhpCodeSnifferTask doesn't pass files encoding to PHP_CodeSniffer
+ * [800] CoverageReportTask fails with "runtime error" on PHP 5.4.0beta1
+ * [799] DbDeploy does not support pdo-dblib
+ * [798] ReplaceTokensWithFile - postfix attribute ignored
+ * [797] PhpLintTask performance improvement
+ * [794] Fix rSTTask to avoid the need of PEAR everytime
+ * [793] Corrected spelling of name
+ * [792] EchoTask: Fileset support
+ * [789] rSTTask unittests fix
+ * [788] rSTTask documentation: fix examples
+ * [787] Add pearPackageFileSet type
+ * [785] method execute doesn't exists in CvsTask.php
+ * [784] Refactor DocBlox task to work with DocBlox 0.14+
+ * [783] SvnExportTask impossible to export current version from working copy
+ * [779] phplint task error summary doesn't display the errors
+ * [775] ScpTask: mis-leading error message if 'host' attribute is not set
+ * [772] Support for filelist in UpToDateTask
+ * [770] Keep the RelaxNG grammar in sync with the code/doc
+ * [707] Writing Tasks/class properties: taskname not correctly used
+ * [655] PlainPHPUnitResultFormatter does not display errors if @dataProvider was used
+ * [578] [PATCH] Add mapper support to ForeachTask
+ * [552] 2 validargs to input task does not display defaults correctly
+
+Aug. 19, 2011 - Phing 2.4.7.1
+-----------------------------
+
+This is a hotfix release.
+
+ * [774] Fix PHP 5.3 dependency in CoverageReportTask
+ * [773] Fix for Ticket #744 breaks PHPCodeSnifferTask's nested formatters
+
+Aug. 18, 2011 - Phing 2.4.7
+---------------------------
+
+This release fixes and improves several tasks (particularly the DocBlox
+task), adds OCI/ODBC support to the dbdeploy task and introduces
+a task to render reStructuredText.
+
+ * [771] Undefined offset: 1 [line 204 of /usr/share/php/phing/tasks/ext/JslLintTask.php]
+ * [767] PharPackageTask: metadata should not be required
+ * [766] The DocBlox task does not load the markdown library.
+ * [765] CoverageReportTask incorrectly considers dead code to be unexecuted
+ * [762] Gratuitous unit test failures on Windows
+ * [760] SelectorUtils::matchPath() directory matching broken
+ * [759] DocBloxTask throws an error when using DocBlox 0.12.2
+ * [757] Grammar error in ChmodTask documentation
+ * [755] PharPackageTask Web/Cli stub path is incorrect
+ * [754] ExecTask: <arg> support
+ * [753] ExecTask: Unit tests and refactoring
+ * [752] Declaration of Win32FileSystem::compare()
+ * [750] Enable process isolation support in the PHPUnit task
+ * [747] Improve "can't load default task list" message
+ * [745] MkdirTask mode param mistake
+ * [744] PHP_CodeSniffer formatter doesn't work with summary
+ * [742] ExecTask docs: link os.name in os attribute
+ * [741] ExecTask: missing docs for "output", "error" and "level"
+ * [740] PHPMDTask: "InvalidArgumentException" with no globbed files.
+ * [739] Making the jsMin suffix optional
+ * [737] PHPCPDTask: omitting 'outfile' attribute with 'useFIle="false"'
+ * [735] CopyTask can't copy broken symlinks when included in fileset
+ * [733] DeleteTask cannot delete dangling symlinks
+ * [731] Implement filepath support in Available Task
+ * [720] rSTTask to render reStructuredText
+ * [658] Add support to Oracle (OCI) in DbDeployTask
+ * [580] ODBC in DbDeployTask
+ * [553] copy task bails on symbolic links (filemtime)
+ * [499] PDO cannot handle PL/Perl function creation statements in PostgreSQL
+
+Jul. 12, 2011 - Phing 2.4.6
+---------------------------
+
+This release fixes a large number of issues, improves a number of tasks
+and adds several new tasks (SVN log/list, DocBlox and LoadFile).
+
+ * [732] execTask fails to chdir if the chdir parameter is a symlink to a dir
+ * [730] phpunitreport: styledir not required
+ * [729] CopyTask fails when todir="" does not exist
+ * [725] Clarify documentation for using AvailableTask as a condition
+ * [723] setIni() fails with memory_limit not set in Megabytes
+ * [719] TouchTask: file not required?
+ * [718] mkdir: are parent directories created?
+ * [715] Fix for mail task documentation
+ * [712] expectSpecificBuildException fails to detect wrong exception message
+ * [708] typo in docs: "No you can set"
+ * [706] Advanced task example missing
+ * [705] Missing links in Writing Tasks: Summary
+ * [704] Case problem in "Writing Tasks" with setMessage
+ * [703] missing links in "Package Imports"
+ * [701] Setting more then two properties in command line not possible on windows
+ * [699] Add loadfile task
+ * [698] Add documentation for patternset element to user guide
+ * [696] CoverageReportTask doesn't recognize UTF-8 source code
+ * [695] phpunit Task doesn't support @codeCoverageIgnore[...] comments
+ * [692] Class 'GroupTest' not found in /usr/share/php/phing/tasks/ext/simpletest/SimpleTestTask.php on line 158
+ * [691] foreach doesn't work with filelists
+ * [690] Support DocBlox
+ * [689] Improve documentation about selectors
+ * [688] SshTask Adding (+propertysetter, +displaysetter)
+ * [685] SvnLogTask and SvnListTask
+ * [682] Loading custom tasks should use the autoloading mechanism
+ * [681] phpunit report does not work with a single testcase
+ * [680] phpunitreport: make tables sortable
+ * [679] IoncubeEncoderTask improved
+ * [673] new listener HtmlColorLogger
+ * [672] DbDeployTask::getDeltasFilesArray has undefined variable
+ * [671] fix CvsTask documentation
+ * [670] DirectoryScanner: add darcs to default excludes
+ * [668] Empty Default Value Behaves Like the Value is not set
+ * [667] Document how symbolic links and hidden files are treated in copy task
+ * [663] __toString for register slots
+ * [662] Hiding the command that is excecuted with "ExecTask"
+ * [659] optionally skip version check in codesniffer task
+ * [654] fileset not selecting folders
+ * [652] PDOSQLExec task doesn't close the DB connection before throw an exception or at the end of the task.
+ * [642] ERROR: option "-o" not known with phpcs version 1.3.0RC2 and phing/phpcodesniffer 2.4.4
+ * [639] Add verbose mode for SCPTask
+ * [635] ignored autocommit="false" in PDOTask?
+ * [632] CoverageThresholdTask needs exclusion option/attribute
+ * [626] Coverage threshold message is too detailed...
+ * [616] PhpDocumentor prematurely checks for executable
+ * [613] Would be nice to have -properties=<file> CLI option
+ * [611] Attribute "title" is wanted in CoverageReportTask
+ * [608] Tweak test failure message from PHPUnitTask
+ * [591] PhpLintTask don't log all errors for each file
+ * [563] Make PatchTask silent on FreeBSD
+ * [546] Support of filelist in CodeCoverageTask
+ * [527] pearpkg2: unable to specify different file roles
+ * [521] jslint warning logger
+
+Mar. 3, 2011 - Phing 2.4.5
+--------------------------
+
+This release fixes several issues, and reverts the changes
+that introduced the ComponentHelper class.
+
+ * [657] Wrong example of creating task in stable documentation.
+ * [656] Many erratas on the "Getting Started"-page.
+ * [651] Messages of ReplaceTokens should be verbose
+ * [641] 2.4.4 packages contains .rej and .orig files in release tarball
+ * [640] "phing -q" does not work: "Unknown argument: -q"
+ * [634] php print() statement outputting to stdout
+ * [624] PDOSQLExec fails with Fatal error: Class 'LogWriter' not found in [...]/PDOSQLExecFormatterElement
+ * [623] 2.4.5RC1 requires PHPUnit erroneously
+ * [621] PhpLintTask outputs all messages (info and errors) to same loglevel
+ * [614] phpcodesniffer task changes Phing build working directory
+ * [610] BUG: AdhocTaskdefTask fails when creating a task that extends from an existing task
+ * [607] v 2.4.4 broke taskdef for tasks following PEAR naming standard
+ * [603] Add support to PostgreSQL in DbDeployTask
+ * [601] Add HTTP_Request2 to optional dependencies
+ * [600] typo in ReplaceRegexpTask
+ * [598] Wrong version for optional Services_Amazon_S3 dependency
+ * [596] PhpDependTask no more compatible with PDepend since 0.10RC1
+ * [593] Ssh/scp task: Move ssh2_connect checking from init to main
+ * [564] command line "-D" switch not handled correctly under windows
+ * [544] Wrong file set when exclude test/**/** is used
+
+Dec. 2, 2010 - Phing 2.4.4
+--------------------------
+
+This release fixes several issues.
+
+ * [595] FilterChain without ReplaceTokensWithFile creator
+ * [594] Taskdef in phing 2.4.3 was broken!
+ * [590] PhpLintTask don't flag files that can't be parsed as bad files
+ * [589] Mail Task don't show recipients list on log
+ * [588] Add (optional) dependency to VersionControl_Git and Services_Amazon_S3 packages
+ * [585] Same line comments in property files are included in the property value
+ * [570] XmlLintTask - check well-formedness only
+ * [568] Boolean properties get incorrectly expanded
+ * [544] Wrong file set when exclude test/**/** is used
+ * [536] DbDeployTask: Undo script wrongly generated
+
+Nov. 12, 2010 - Phing 2.4.3
+---------------------------
+
+This release adds tasks to interface with Git and Amazon S3, adds support for PHPUnit 3.5,
+and fixes numerous issues.
+
+ * [583] UnixFileSystem::compare() is broken
+ * [582] Add haltonerror attribute to copy/move tasks
+ * [581] XmlProperty creating wrong properties
+ * [577] SVN commands fail on Windows XP
+ * [575] xmlproperty - misplaced xml attributes
+ * [574] Task "phpcodesniffer" broken, no output
+ * [572] ImportTask don't skipp file if optional is set to true
+ * [560] [PATCH] Compatibility with PHPUnit 3.5.
+ * [559] UpToDate not override value of property when target is called by phingcall
+ * [555] STRICT Declaration of UnixFileSystem::getBooleanAttributes() should be compatible with that of FileSystem::getBooleanAttributes()
+ * [554] Patch to force PhpDocumentor to log using phing
+ * [551] SVN Switch Task
+ * [550] Ability to convert encoding of files
+ * [549] ScpTask doesn't finish the transfer properly
+ * [547] The new attribute version does not work
+ * [543] d51PearPkg2Task: Docs link wrong
+ * [542] JslLintTask: wrap conf parameter with escapeshellarg
+ * [537] Install documentation incorrect/incomplete
+ * [536] DbDeployTask: Undo script wrongly generated
+ * [534] Task for downloading a file through HTTP
+ * [531] cachefile parameter of PhpLintTask also caches erroneous files
+ * [530] XmlLintTask does not stop buid process when schema validation fails
+ * [529] d51pearpkg2: setOptions() call does not check return value
+ * [526] pearpkg2: extdeps and replacements mappings not documented
+ * [525] pearpkg2: minimal version on dependency automatically set max and recommended
+ * [524] pearpkg2: maintainers mapping does not support "active" tag
+ * [520] Need SvnLastChangedRevisionTask to grab the last changed revision for the current working directory
+ * [518] [PHP Error] file_put_contents(): Filename cannot be empty in phpcpdesniffer task
+ * [513] Version tag doesn't increment bugfix portion of the version
+ * [511] Properties not being set on subsequent sets.
+ * [510] to show test name when testing fails
+ * [501] formatter type "clover" of task "phpunit" doesn't generate coverage according to task "coverage-setup"
+ * [488] FtpDeployTask is very silent, error messages are not clear
+ * [455] Should be able to ignore a task when listing them from CLI
+ * [369] Add Git Support
+
+Jul. 28, 2010 - Phing 2.4.2
+---------------------------
+
+ * [509] Phing.php setIni() does not honor -1 as unlimited
+ * [506] Patch to allow -D<option> with no "=<value>"
+ * [503] PHP Documentor Task not correctly documented
+ * [502] Add repository url support to SvnLastRevisionTask
+ * [500] static function call in PHPCPDTask
+ * [498] References to Core types page are broken
+ * [496] __autoload not being called
+ * [492] Add executable attribute in JslLint task
+ * [489] PearPackage Task fatal error trying to process Fileset options
+ * [487] Allow files in subdirectories in ReplaceTokensWithFile filter
+ * [486] PHP Errors in PDOSQLExecTask
+ * [485] ReplaceTokensWithFile filter does not allow HTML translation to be
+ switched off
+ * [484] Make handling of incomplete tests when logging XML configurable
+ * [483] Bug in FileUtils::copyFile() on Linux - when using FilterChains,
+ doesn't preserve attributes
+ * [482] Bug in ChownTask with verbose set to false
+ * [480] ExportPropertiesTask does not export all the initialized properties
+ * [477] HttpRequestTask should NOT validate output if regex is not provided
+ * [474] Bad Comparisons in FilenameSelector (possibly others)
+ * [473] CPanel can't read Phing's Zip Files
+ * [472] Add a multiline option to regex replace filter
+ * [471] ChownTask throws exception if group is given
+ * [468] CopyTask does not accept a FileList as only source of files
+ * [467] coverage of abstract class/method is always ZERO
+ * [466] incomplete logging in coverage-threshold
+ * [465] PatchTask should support more options
+ * [463] Broken Links in coverage report
+ * [461] version tag in project node
+
+Mar. 10, 2010 - Phing 2.4.1
+---------------------------
+
+ * [460] FtpDeployTask error
+ * [458] PHPCodeSniffer Task throws Exceptions
+ * [456] Fileset's dir should honor expandsymboliclinks
+ * [449] ZipTask creates ZIP file but doesn't set file/dir attributes
+ * [448] PatchTask
+ * [447] SVNCopy task is not documented
+ * [446] Add documentation describing phpdocext
+ * [444] PhpCodeSnifferTask fails to generate a checkstyle-like output
+ * [443] HttpRequestTask is very desirable
+ * [442] public key support for scp and ssh tasks
+ * [436] Windows phing.bat can't handle PHP paths with spaces
+ * [435] Phing download link broken in bibliography
+ * [433] Error in Documentation in Book under Writing a simple Buildfile
+ * [432] would be nice to create CoverateThresholdTask
+ * [431] integrate Phing with PHP Mess Detector and PHP_Depend
+ * [430] FtpDeployTask is extremely un-verbose...
+ * [428] Ability to specify the default build listener in build file
+ * [426] SvnExport task documentation does not mention "revision" property
+ * [421] ExportProperties class incorrectly named
+ * [420] Typo in setExcludeGroups function of PHPUnitTask
+ * [418] Minor improvement for PhpLintTask
+
+Jan. 17, 2010 - Phing 2.4.0
+---------------------------
+
+ * [414] PhpLintTask: retrieving bad files
+ * [413] PDOSQLExecTask does not recognize "delimiter" command
+ * [411] PhpEvalTask calculation should not always returns anything
+ * [410] Allow setting alias for Phar files as well as a custom stub
+ * [384] Delete directories fails on '[0]' name
+
+Dec. 17, 2009 - Phing 2.4.0 RC3
+-------------------------------
+
+ * [407] some error with svn info
+ * [406] an ability to turn phpLint verbose ON and OFF
+ * [405] I can't get a new version of Phing through PEAR
+ * [402] Add fileset/filelist support to scp tasks
+ * [401] PHPUnitTask 'summary' formatter produces a long list of results
+ * [400] Support for Clover coverage XML
+ * [399] PhpDocumentorExternal stops in method constructArguments
+ * [398] Error using ResolvePath on Windows
+ * [397] DbDeployTask only looks for -- //@UNDO (requires space)
+ * [396] PDOSQLExecTask requires both fileset and filelist, rather than either or
+ * [395] PharPackageTask fails to compress files
+ * [394] Fix differences in zip and tar tasks
+ * [393] prefix parameter for tar task
+ * [391] Docs: PharPackageTask 'compress' attribute wrong
+ * [389] Code coverage shows incorrect results Part2
+ * [388] Beautify directory names in zip archives
+ * [387] IoncubeEncoderTask noshortopentags
+ * [386] PhpCpd output to screen
+ * [385] Directory ignored in PhpCpdTask.php
+ * [382] Add prefix parameter to ZipTask
+ * [381] FtpDeployTask: invalid default transfer mode
+ * [380] How to use PhpDocumentorExternalTask
+ * [379] PHPUnit error handler issue
+ * [378] PHPUnit task bootstrap file included too late
+ * [377] Code coverage shows incorrect results
+ * [376] ReplaceToken boolean problems
+ * [375] error in docs for echo task
+ * [373] grammar errors
+ * [372] Use E_DEPRECATED
+ * [367] Can't build simple build.xml file
+ * [361] Bug in PHPCodeSnifferTask
+ * [360] &amp;&amp; transfers into & in new created task
+ * [309] startdir and 'current directory' not the same when build.xml not in current directory
+ * [268] Patch - xmlproperties Task
+ * [204] Resolve task class names with PEAR/ZEND/etc. naming convention
+ * [137] Excluded files may be included in Zip/Tar tasks
+
+Oct. 20, 2009 - Phing 2.4.0 RC2
+-------------------------------
+
+ * [370] Fatal error: Cannot redeclare class PHPUnit_Framework_TestSuite
+ * [366] Broken link in "Getting Started/More Complex Buildfile"
+ * [365] Phing 2.4rc1 via pear is not usable
+ * [364] 2.4.0-rc1 download links broken
+ * [363] PHPUnit task fails with formatter type 'xml'
+ * [359] 403 for Documentation (User Guide) Phing HEAD
+ * [355] PDOSQLExecTask should accept filelist subelement
+ * [352] Add API documentation
+
+Sep. 14, 2009 - Phing 2.4.0 RC1
+-------------------------------
+
+ * [362] Can't get phpunit code coverage to export as XML
+ * [361] Bug in PHPCodeSnifferTask
+ * [357] SvnLastRevisionTask fails when locale != EN
+ * [356] Documentation for tasks Chmod and Chown
+ * [349] JslLint task fails to escape shell argument
+ * [347] PHPUnit / Coverage tasks do not deal with bootstrap code
+ * [344] Phing ignores public static array named $browsers in Selenium tests
+ * [342] custom-made re-engine in SelectorUtils is awful slow
+ * [339] PHAR signature setting
+ * [336] Use intval to loop through files
+ * [333] XmlLogger doesn't ensure proper ut8 encoding of log messages
+ * [332] Conditions: uptodate does not work
+ * [331] UpToDateTask documentation says that nested FileSet tags are allowed
+ * [330] "DirectoryScanner cannot find a folder/file named ""0"" (zero)"
+ * [326] Add revision to svncheckout and svnupdate
+ * [325] "<filterchain id=""xxx""> and <filterchain refid=""xxx""> don't work"
+ * [322] phpdoc task not parsing and including RIC files in documentation output
+ * [319] Simpletest sometimes reports an undefined variable
+ * [317] PhpCodeSnifferTask lacks of haltonerror and haltonwarning attributes
+ * [316] Make haltonfailure attribute for ZendCodeAnalyzerTask
+ * [312] SimpleTestXMLResultFormatter
+ * [311] Fileset support for the TouchTask?
+ * [307] Replaceregexp filter works in Copy task but not Move task
+ * [306] Command-line option to output the <target> description attribute text
+ * [303] Documentation of Task Tag SimpleTest
+ * [300] ExecTask should return command output as a property (different from passthru)
+ * [299] PhingCall crashes if an AdhocTask is defined
+ * [292] Svn copy task
+ * [290] Add facility for setting resolveExternals property of DomDocument object in XML related tasks
+ * [289] Undefined property in XincludeFilter class
+ * [282] Import Task fix/improvement
+ * [280] Add Phar support (task) to Phing
+ * [279] Add documentation to PHK package task
+ * [278] Add PHK package task
+ * [277] PhpCodeSnifferTask has mis-named class, patch included
+ * [273] PHPUnit 3.3RC1 error in phpunit task adding files to filter
+ * [270] [patch] ReplaceRegExp
+ * [269] Allow properties to be recursively named.
+ * [263] phpunit code coverage file format change
+ * [262] Archive_Zip fails to extract on Windows
+ * [261] UnZip task reports success on failure on Windows
+ * [259] Unneeded warning in Untar task
+ * [256] Ignore dead code in code coverage
+ * [254] Add extra debug resultformatter to the simpletest task
+ * [252] foreach on a fileset
+ * [248] Extend taskdef task to allow property file style imports
+ * [247] New task: Import
+ * [246] Phing test brocken but no failure entry if test case class has no test method
+ * [245] TAR task
+ * [243] Delete task won't delete all files
+ * [240] phing test succesful while phpunit test is broken
+ * [233] Separate docs from phing package
+ * [231] File::exists() returns false on *existing* but broken symlinks
+ * [229] CopyTask shoul accept filelist subelement
+ * [226] <move> task doesn't support filters
+ * [222] Terminal output dissapears and/or changes color
+ * [221] Support for copying symlinks as is
+ * [212] Make file perms configurable in copy task
+ * [209] Cache the results of PHPLintTask so as to not check unmodified files
+ * [187] "ExecTask attribute ""passthru"" to make use of the PHP function ""passthru"""
+ * [21] svn tasks doesn't work
+
+Dec. 8, 2008 - Phing 2.3.3
+--------------------------
+
+ * [314] <phpunit> task does not work
+ * [313] Incorrect PhpDoc package of SimpleTestResultFormatter
+ * [302] Incorrect error detecting in XSLT filter
+ * [293] Contains condition fails on case-insensitive checks
+ * [291] The release package is not the one as the version(2.3.2) suppose to be
+
+Oct. 16, 2008 - Phing 2.3.2
+---------------------------
+
+ * [296] Problem with the Phing plugin with Hudson CI Tool
+ * [288] Comment syntax for dbdeploy violates standard
+
+Oct. 16, 2008 - Phing 2.3.1
+---------------------------
+
+ * [287] DateSelector.php bug
+ * [286] dbdeploy failes with MySQL strict mode
+ * [285] Syntax error in dbdeploy task
+ * [284] XSL Errors in coverage-report task
+ * [275] AnsiColorLogger should not be final
+ * [274] PHPUnit 3.3RC1 incompatibility with code coverage
+ * [272] Using CDATA with ReplaceTokens values
+ * [271] Warning on iterating over empty keys
+ * [264] Illeal use of max() with empty array
+ * [260] Error processing reults: SQLSTATE [HY000]: General error: 2053 when executing inserts or create statements.
+ * [258] getPhingVersion + printVersion should be public static
+ * [255] Timestamp in Phing Properties for Echo etc
+ * [253] CCS nav bug on PHING.info site
+ * [251] debug statement in Path datatype for DirSet
+ * [249] See failed tests in console
+ * [244] Phing pear install nor working
+ * [242] Log incomplete and skipped tests for phpunit3
+ * [241] FtpDeployTask reports FTP port as FTP server on error
+ * [239] ExecTask shows no output from running command
+ * [238] Bug in SummaryPHPUnit3ResultFormatter
+ * [237] Several PHP errors in XSLTProcessor
+ * [236] Do not show passwords for svn in log
+ * [234] typo in foreach task documentation
+ * [230] Fatal error: Call to undefined method PHPUnit2_Framework_TestResult::skippedCount() in /usr/local/lib/php/phing/tasks/ext/phpunit/PHPUnitTestRunner.php on line 120
+ * [227] simpletestformaterelement bad require
+ * [225] Missing Software Dependence in documentation
+ * [224] Path class duplicates absolute path on subsequent path includes
+ * [220] AnsiColorLogger colors cannot be changed by build.properties
+ * [219] Add new chown task
+ * [218] Clear support of PHPUnit versions
+ * [217] Memory limit in phpdoc
+ * [216] output messages about errors and warnings in JslLint task
+ * [215] boolean attributes of task PhpCodeSniffer are wrong
+ * [214] PhpCodeSnifferTask should be able to output file
+ * [213] Error in documentation task related to copy task
+ * [211] XSLT does not handle multiple testcase nodes for the same test method
+ * [210] Reworked PhpDocumentorExternalTask
+ * [208] ReplaceRegexp problem with newline as replace string
+ * [207] PhpLintTask: optional use a different PHP interpreter
+ * [206] Installation guide out of date (phing fails to run)
+ * [205] AvailableTask::_checkResource ends up with an exception if resource isn't found.
+ * [203] ExecTask returnProperty
+ * [202] Add PHP_CodeSniffer task
+ * [201] "Improve Phing's ability to work as an ""embedded"" process"
+ * [200] Additional attribute for SvnUpdateTask
+ * [199] Invalid error message in delete task when deleting directory fails.
+ * [198] PDO SQL exec task unable to handle multi-line statements
+ * [197] phing delete task sometimes fails to delete file that could be deleted
+ * [195] SvnLastRevisionTask fails if Subversion is localized (Spanish)
+ * [194] haltonincomplete attribute for phpunit task
+ * [193] Manifest Task
+ * [192] Error when skip test
+ * [191] Akismet says content is spam
+ * [190] Add test name in printsummary in PHPUnit task
+ * [185] PHPUnit_MAIN_METHOD defined more than once
+ * [184] PlainPHPUnit3ResultFormatter filteres test in stack trace
+ * [183] Undefined variable in PhingTask.php
+ * [182] Undefined variable in SummaryPHPUnit3ResultFormatter
+ * [181] PhingCallTask should call setHaltOnFailure
+ * [179] Add documentation for TidyFilter
+ * [178] printsummary doens work in PHP Unit task
+ * [177] Only write ConfigurationExceptions to stdout
+ * [176] Cleanup installation documentation.
+ * [175] passing aarguments to phing
+ * [169] Spurious PHP Error from XSLT Filter
+ * [150] unable to include phpdocumentor.ini in PHPDoc-Task
+ * [15] FTP upload task
+
+Nov. 3, 2007 - Phing 2.3.0
+--------------------------
+
+ * [174] Add differentiation for build loggers that require explicit streams to be set
+ * [173] Add 'value' alias to XSLTParam type.
+ * [172] broken phpunit2-frames.xsl
+ * [171] Allow results from selector to be loosely type matched to true/false
+ * [170] SvnLastRevisionTask cannot get SVN revision number on single file
+ * [168] XincludeFilter PHP Error
+ * [167] Add new formatter support for PDOSQLExecTask
+ * [166] Change CreoleTask to use <creole> tagname instead of <sql>
+ * [165] Add support for PHPUnit_Framework_TestSuite subclasses in fileset of test classes
+ * [164] Failed build results in empty log.xml
+ * [163] Add stripwhitespace filter
+ * [162] Add @pattern alias for @name in <fileset>
+ * [161] phing/etc directory missing (breaking PHPUnit)
+ * [157] Fatal error in PDOSQLExecTask when using filesets
+ * [155] <delete> fails when it encounters symlink pointing to non-writable file
+ * [154] Suggestion to add attribute to PDOSQLExecTask for fetch_style
+ * [153] sqlite select failure
+ * [152] result of PHP-Unit seems to be incorrect
+ * [151] add group-option to PHPUnit-Task
+ * [149] using TestSuites in fileset of PHPUnit-Task
+ * [148] remove dependency to PEAR in PHPUnit-Task
+ * [146] Illegal offset type PHP notice in CopyTask
+ * [143] Example for PhpDocumentor task has typographical errors and a wrong attribute.
+ * [142] SvnCheckout task only makes non-recursive checkouts.
+ * [141] Add 'recursive' attribute to svncheckout task.
+ * [136] Attribute os of ExecTask is not working
+ * [135] add source file attribute for code coverage xml report
+ * [133] Error in documenation: AppendTask
+ * [129] Typo in documentation
+ * [128] <pearpkg2> is missing in the doc completely
+ * [127] Error in documentation
+ * [126] Typo in documentation
+ * [122] PearPackage2Task Replacements don't seem to work
+ * [121] BUILD FAILED use JsLintTask
+ * [119] PhpDocumentorTask fails when trying to use parsePrivate attribute.
+ * [118] custom tasks have this->project == null
+ * [117] CoverageSetupTask and autoloaders
+ * [116] Test unit don't report notice or strict warnings
+ * [110] "Add ""errorproperty"" attribute to PhpLintTask"
+ * [107] SvnLastRevisionTask doesn't work with repositoryUrl
+ * [106] "document ""haltonfailure"" attribute for phplint task"
+ * [105] FileSystemUnix::normalize method: Improve handling
+ * [97] delete dir and mkdir are incompatible
+ * [92] Inconsistent newlines in PHP files
+ * [91] Improve detection for PHPUnit3
+ * [83] "XmlLogger improperly handling ""non-traditional"" buildfile execution paths"
+ * [82] Error when use markTestIncomplete in test
+ * [79] Allow escaped dots in classpaths
+ * [78] (SVN doc) ${phing.version} and ${php.version} are different!
+ * [77] taskdef doesn't support fileset
+ * [76] Overhaul PhpDocumentor task
+ * [75] files excluded by fileset end up in .tgz but not .zip
+ * [74] Phing commandline args don't support quoting / spaces
+ * [73] Semantical error in PhingFile::getParent()
+ * [72] "Remove use of getProperty(""line.separator"") in favor of PHP_EOL"
+ * [71] "Add ""-p"" alias for project help"
+ * [70] Create Project class constants for log levels (replacing PROJECT_MSG_*)
+ * [69] mkdir and delete tasks don't work properly together
+ * [68] Xinclude filter
+ * [67] Add PDO SQL execution task
+ * [66] Incorrectly set PHP_CLASSPATH in phing.bat
+ * [65] Convert all loggers/listeners to use streams
+ * [64] Build listeners currently not working
+ * [63] Configured -logger can get overridden
+ * [62] phing.buildfile.dirname built-in property
+ * [58] Path::listPaths() broken for DirSet objects.
+ * [57] FileList.getListFile method references undefined variable
+ * [56] TaskHandler passing incorrect param to ProjectConfigurator->configureId()
+ * [53] _makeCircularException seems to have an infinite loop
+ * [52] \<match>-syntax does not work correctly with preg_*()
+ * [51] Cannot get phing to work with PHPUnit 3
+ * [48] Supported PHPUnit2_Framework_TestSuite and PHPUnit2_Extensions_TestSetup sub-classes for the PHPUnit2Task and CoverageReportTask tasks
+ * [33] Implement changes to use PHPUnit2 3.0 code coverage information
+ * [22] Description about integrating into CruiseControl
+
+Aug. 21, 2006 - Phing 2.2.0
+---------------------------
+
+ * Refactored parser to support many tags as children of base <project> tag (HL)
+ * Added new IfTask (HL)
+ * Added "spawn" attribute to ExecTask (only applies to *nix)
+ * Several bugfixes & behavior imporvements to ExecTask (HL, MR, Ben Gollmer)
+ * Bugfixes & refactoring for SVNLastRevisionTask (MR, Knut Urdalen)
+ * Fixed reference copy bug (HL, Matthias Pigulla)
+ * Added SvnExportTask (MR)
+ * Added support for FileList in DeleteTask. (HL)
+ * Added support for using setting Properties using CDATA value of <property> tag. (HL)
+ * Added ReferenceExistsCondition (Matthias Pigulla)
+ * Added Phing::log() static method & integrated PHP error handling with Phing logging (HL)
+ * Added new task to run the ionCube Encoder (MR)
+ * Added new HTML Tidy filter (HL)
+ * Added PhpLintTask (Knut Urdalen)
+ * Added XmlLintTask (Knut Urdalen)
+ * Added ZendCodeAnalyzerTask (Knut Urdalen)
+ * Removed CoverageFormatter class (MR)
+ NOTE: This changes the usage of the collection of PHPUnit2 code coverage reports, see the
+ updated documentation for the CoverageSetupTask
+ * Added Unzip and Untar tasks contributed by Joakim Bodin
+ * [8], [49] Fixed bugs in TarTask related to including empty directories (HL)
+ * [44] Fixed bug related to copying empty dirs. (HL)
+ * [32] Fixed PHPUnit2 tasks to work with PHPUnit2-3.0.0 (MR)
+ * [31] Fixed bug with using PHPDocumentor 1.3.0RC6 (MR)
+ * [43] Fixed top-level (no target) IfTask behavior (Matthias Pigulla)
+ * [41] Removed some lingering E_STRICT errors, bugs with 5.1.x and PHP >= 5.0.5 (HL)
+ * [25] Fixed 'phing' script to also run on non-bash unix /bin/sh
+ * Numerous documentation improvements by many members of the community (Thanks!)
+
+Sept. 18, 2005 - Phing 2.1.1
+----------------------------
+
+ * Added support for specifying 4-char mask (e.g. 1777) to ChmodTask. (Hans Lellelid)
+ * Added .svn files to default excludes in DirectoryScanner.
+ * Updated PHPUnit2 BatchTest to use class detection and non-dot-path loader. (Michiel Rook)
+ * Added support for importing non dot-path files (Michiel Rook)
+ * Add better error message when build fails with exception (Hans Lellelid)
+ * Fixed runtime error when errors were encountered in AppendTask (Hans Lellelid)
+
+June 17, 2005 - Phing 2.1.0
+---------------------------
+
+ * Renamed File -> PhingFile to avoid namespace collisions (Michiel Rook)
+ * Add ZipTask to create .zip files (Michiel Rook)
+ * Removed redudant logging of build errors in Phing::start() (Michiel Rook)
+ * Added tasks to execute PHPUnit2 testsuites and generate coverage and
+ test reports. (Michiel Rook, Sebastian Bergmann)
+ * Added SvnLastRevisionTask that stores the number of the last revision
+ of a workingcopy in a property. (Michiel Rook)
+ * Added MailTask that sends a message by mail() (Michiel Rook, contributed by Francois Harvey)
+ * New IncludePathTask (<includepath/>) for adding values to PHP's include_path. (Hans Lellelid)
+ * Fix to Phing::import() to *not* attempt to invoke __autoload() in class_exists() check. (Hans Lellelid)
+ * Fixed AppendTask to allow use of only <fileset> as source. (Hans Lellelid)
+ * Removed dependency on posix, by changing posix_uname to php_uname if needed. (Christian Stocker)
+ * Fixed issues: (Michiel Rook)
+ 11 ExtendedFileStream does not work on Windows
+ 12 CoverageFormatter problem on Windows
+ 13 DOMElement warnings in PHPUnit2 tasks
+ 14 RuntimeException conflicts with SPL class
+ 15 It is not possible to execute it with PHP5.1
+ 16 Add Passthru option to ExecTask
+ 17 Blank list on foreach task will loop once
+ 19 Problem with <formatter outfile="...">
+ 20 Phpunit2report missing XSL stylesheets
+ 21 Warnings when output dir does not exist in PHPUnit2Report
+
+Oct 16, 2004 - Phing 2.0.0
+--------------------------
+
+ * Minor fixes to make Phing run under E_STRICT/PHP5.
+ * Fix to global/system properties not being set in project. (Matt Zandstra)
+ * Fixes to deprecated return by reference issues w/ PHP5.0.0
+
+June 8, 2004 - Phing 2.0.0b3
+----------------------------
+
+ * Brought up-to-date w/ PHP5.0.0RC3
+ * Fixed several bugs in ForeachTask
+ * Fixed runtime errors and incomplete inheriting of properties in PhingTask
+ * Added <fileset> support to AppendTask
+
+March 19, 2004 - Phing 2.0.0b2
+------------------------------
+
+ * Brought up-to-date w/ PHP5.0.0RC1 (Hans)
+ * Fixed bug in seting XSLT params using XSLTask (Hans, Jeff Moss)
+ * Fixed PHPUnit test framework for PHPUnit-2.0.0alpha3
+ * Added "Adhoc" tasks, which allow for defining PHP task or type classes within the
+ buildfile. (Hans)
+ * Added PhpEvalTask which allows property values to be set to simple PHP evaluations or
+ the results of function/method calls. (Hans)
+ * Added new phing.listener.PearLogger listener (logger). Also, the -logfile arg is now
+ supported. (Hans)
+ * Fixed broken ForeachTask task. (Manuel)
+
+Dec 24, 2003 - Phing 2.0.0b1
+----------------------------
+
+ * Added PEAR installation framework & ability to build Phing into PEAR package.
+ * Added TarTask using PEAR Archive_Tar
+ * Added PearPackageTask which creates a PEAR package.xml (using PEAR_PackageFileManager).
+ * Added ResolvePathTask which converts relative paths into absolute paths.
+ * Removed System class, due to namespace collision w/ PEAR.
+ * Basic "working?" tests performed with all selectors.
+ * Added selectors: TypeSelector, ContainsRegexpSelector
+ * CreoleSQLExec task is now operational.
+ * Corrected non-fatal bugs in: DeleteTask, ReflexiveTask
+ * All core Phing classes now in PHP5 syntax (no "var" used, etc.)
+ * CopyTask will not stop build execution if a file cannot be copied (will log and
+ continue to next file).
+ * New abstract MatchingTask task makes it easier to create your own tasks that use
+ selectors.
+ * Removed redundant calls in DirectoryScanner (<fileset> scanning now much faster).
+ * Fixed fatal errors in File::equals()
+
+Nov 24, 2003 - Phing 2.0.0a2
+----------------------------
+
+ * Fixed ReplaceTokens filter to correctly replace matched tokens
+ * Changed "project.basedir" property to be absolute path of basedir
+ * Made IntrospectionHelper more tollerant of add*() and addConfigured*() signatures
+ * New CvsTask and CvsPassTask for working with CVS repositories
+ * New TranslateGettext filter substitutes _("hello!") with "hola!" / "bonjour!" / etc.
+ * More consistent use of classhints to enable auto-casting by IntrospectionHelper
+ * Fixed infinite loop bug in FileUtils::normalize() for paths containing "/./"
+ * Fixed bug in CopyFile/fileset that caused termination of copy operation on encounter
+ of unreadable file
+
+Nov 6, 20003 - Phing 2.0.0a1
+----------------------------
+
+ * First release of Phing 2, an extensive rewrite and upgrade.
+ * Refactored much of codebase, using new PHP5 features (e.g. Interfaces, Exceptions!)
+ * Many, many, many bugfixes to existing functionality
+ * Restructuring for more intuitive directory layout, change the parser class names.
+ * Introduction of new tasks: AppendTask, ReflexiveTask, ExitTask, Input, PropertyPrompt
+ * Introduction of new types: Path, FileList, DirSet, selectors, conditions
+ * Introduction of new filters: ReplaceRegexp
+ * Introduction of new logger: AnsiColorLogger
+ * Many features from ANT 1.5 added to existing Tasks/Types
+ * New "Register Slot" functionality allows for tracking "inner" dynamic variables.
diff --git a/buildscripts/phing/CREDITS.md b/buildscripts/phing/CREDITS.md
new file mode 100644
index 00000000..caea650b
--- /dev/null
+++ b/buildscripts/phing/CREDITS.md
@@ -0,0 +1,51 @@
+P H I N G
+=========================
+
+
+Phing 2.x Development
+---------------------
+
+ - Michiel Rook <mrook@php.net>
+ - Hans Lellelid <hans@xmpl.org>
+ - Sebastian Bergmann <sb@sebastian-bergmann.de>
+ - Joakim Bodin <joakim.bodin+phing@gmail.com>
+ - Johan Van den Brande <johan@vandenbrande.com>
+ - Bryan Davis <bender@casadebender.com>
+ - Andrew Eddie <andrew.eddie@jamboworks.com>
+ - Markus Fischer <markus@fischer.name>
+ - David Giffin <david@giffin.org>
+ - Ryan Grove <ryan@wonko.com>
+ - Frank Kleine <mikey@stubbles.net>
+ - George Miroshnikov <laggy.luke@gmail.com>
+ - David Persson <davidpersson at qeweurope dot org>
+ - Stefan Priebsch <stefan.priebsch@e-novative.de>
+ - Jorrit Schippers <jorrit at ncode dot nl>
+ - Alexey Shockov <alexey@shockov.com>
+ - Dirk Thomas <dirk.thomas@4wdmedia.de>
+ - Knut Urdalen <knut.urdalen@gmail.com>
+ - Mike Wittje <mw@mike.wittje.de>
+ - Benjamin Schultz <bschultz@proqrent.de>
+ - Andrei Serdeliuc <andrei@serdeliuc.ro>
+ - Victor Farazdagi
+ - Christian Weiske
+ - Matthias Pigulla
+ - Lineke Kerckhoffs-Willems <lineke@phpassionate.com>
+
+ If you've done work on Phing and you are not listed here, please feel free
+ to add yourself.
+
+Original Phing 1.x 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>
diff --git a/buildscripts/phing/LICENSE b/buildscripts/phing/LICENSE
new file mode 100644
index 00000000..fc8a5de7
--- /dev/null
+++ b/buildscripts/phing/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ 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 that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU 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 as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/buildscripts/phing/README.md b/buildscripts/phing/README.md
new file mode 100644
index 00000000..91c9d0e4
--- /dev/null
+++ b/buildscripts/phing/README.md
@@ -0,0 +1,64 @@
+P H I N G
+=========================
+
+
+ (PH)ing (I)s (N)ot (G)NU make; it's a PHP project build system or build
+ tool 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 running PHPUnit and SimpleTest unit tests (including test
+ result and coverage reports), file transformations (e.g. token replacement,
+ XSLT transformation, Smarty template transformations),
+ file system operations, interactive build support, SQL execution,
+ CVS/SVN/GIT operations, tools for creating PEAR packages, documentation
+ generation (DocBlox, PhpDocumentor) and much, much more.
+
+ If you find yourself writing custom scripts to handle the packaging,
+ deploying, or testing of your applications, then we suggest looking at Phing.
+ Phing comes packaged with numerous out-of-the-box operation modules (tasks),
+ and an easy-to-use OO model to extend or add your own custom tasks.
+
+ Phing provides the following features:
+
+ * Simple XML buildfiles
+ * Rich set of provided tasks
+ * Easily extendable via PHP classes
+ * Platform-independent: works on UNIX, Windows, Mac OSX
+ * No required external dependencies
+ * Built for PHP5
+
+The Latest Version
+------------------
+
+ Details of the latest version can be found on the Phing homepage
+ <http://www.phing.info/>.
+
+Installation
+------------
+
+ The preferred method to install Phing is through PEAR and the Phing PEAR
+ channel. You can install Phing by adding the pear.phing.info channel
+ to your PEAR environment and then installing Phing using the *phing*
+ channel alias and *phing* package name:
+
+ $> pear channel-discover pear.phing.info
+ $> pear install [--alldeps] phing/phing
+
+Documentation
+-------------
+
+ Documentation is available in HTML format in the *docs* directory. In particular,
+ open the *docs/phing_guide/book/index.html* in a browser to see the
+ Phing User Guide.
+
+ For online documentation, you can also visit the Phing website: http://www.phing.info/
+
+Licensing
+---------
+
+ This software is licensed under the terms you may find in the file
+ named "LICENSE" in this directory.
+
+ Thank you for using PHING!
diff --git a/buildscripts/phing/bin/phing b/buildscripts/phing/bin/phing
new file mode 100755
index 00000000..bbc6eefe
--- /dev/null
+++ b/buildscripts/phing/bin/phing
@@ -0,0 +1,87 @@
+#!/bin/sh
+# Shell wrapper for Phing
+# $Id$
+#
+# 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
+
+
+# Put all args in quotes
+phing_exec_debug=false
+phing_exec_args=
+for arg in "$@" ; do
+ phing_exec_args="$phing_exec_args \"$arg\""
+done
+
+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
+
+phing_exec_cmd="exec $PHP_COMMAND -d html_errors=off -qC \"$PHING_HOME/bin/phing.php\" -logger phing.listener.AnsiColorLogger $phing_exec_args"
+if $phing_exec_debug ; then
+ echo $phing_exec_cmd
+fi
+eval $phing_exec_cmd \ No newline at end of file
diff --git a/buildscripts/phing/bin/phing.bat b/buildscripts/phing/bin/phing.bat
new file mode 100644
index 00000000..ea310470
--- /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$
+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" %*
+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 100755
index 00000000..3b70887a
--- /dev/null
+++ b/buildscripts/phing/bin/phing.php
@@ -0,0 +1,56 @@
+<?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 $Id$
+ */
+
+// Set any INI options for PHP
+// ---------------------------
+
+/* set classpath */
+if (getenv('PHP_CLASSPATH')) {
+ if (!defined('PHP_CLASSPATH')) { define('PHP_CLASSPATH', getenv('PHP_CLASSPATH') . PATH_SEPARATOR . get_include_path()); }
+ ini_set('include_path', PHP_CLASSPATH);
+} else {
+ if (!defined('PHP_CLASSPATH')) { define('PHP_CLASSPATH', get_include_path()); }
+}
+
+require_once 'phing/Phing.php';
+
+try {
+
+ /* Setup Phing environment */
+ Phing::startup();
+
+ // Set phing.home property to the value from environment
+ // (this may be NULL, but that's not a big problem.)
+ Phing::setProperty('phing.home', getenv('PHING_HOME'));
+
+ // Grab and clean up the CLI arguments
+ $args = isset($argv) ? $argv : $_SERVER['argv']; // $_SERVER['argv'] seems to not work (sometimes?) when argv is registered
+ array_shift($args); // 1st arg is script name, so drop it
+
+ // Invoke the commandline entry point
+ Phing::fire($args);
+
+ // Invoke any shutdown routines.
+ Phing::shutdown();
+
+} catch (ConfigurationException $x) {
+
+ Phing::printMessage($x);
+ exit(-1); // This was convention previously for configuration errors.
+
+} catch (Exception $x) {
+
+ // Assume the message was already printed as part of the build and
+ // exit with non-0 error code.
+
+ exit(1);
+
+}
+
+?>
diff --git a/buildscripts/phing/classes/phing/BuildEvent.php b/buildscripts/phing/classes/phing/BuildEvent.php
new file mode 100755
index 00000000..581f7cf4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/BuildEvent.php
@@ -0,0 +1,198 @@
+<?php
+/*
+ * $Id: 47c800dd15c2367bb5890065f96ffceb7ae9ba55 $
+ *
+ * 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 $Id$
+ * @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
+ */
+ protected $message = null;
+
+ /**
+ * The priority of the message
+ *
+ * @var string
+ * @see $message
+ */
+ protected $priority = Project::MSG_VERBOSE;
+
+ /**
+ * The execption that caused the event, if any
+ *
+ * @var object
+ */
+ protected $exception = null;
+
+ /**
+ * Construct a BuildEvent for a project, task or target source event
+ *
+ * @param object project the project that emitted the event.
+ */
+ 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
+ */
+ public 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
+ */
+ public 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
+ */
+ public 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 Target The target that fired this event
+ */
+ 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 Task The task that fired this event
+ */
+ public function getTask() {
+ return $this->task;
+ }
+
+ /**
+ * Returns the logging message. This field will only be set for
+ * "messageLogged" events.
+ *
+ * @return string The log message
+ */
+ 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
+ */
+ 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()
+ * @return Exception
+ */
+ public function getException() {
+ return $this->exception;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/BuildException.php b/buildscripts/phing/classes/phing/BuildException.php
new file mode 100755
index 00000000..dda1a05a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/BuildException.php
@@ -0,0 +1,124 @@
+<?php
+/*
+ * $Id: 5edc6b90e055d23ecceac1b6fd7e5fa80e86e006 $
+ *
+ * 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 $Id$
+ * @package phing
+ */
+class BuildException extends Exception {
+
+ /**
+ * Location in the xml file.
+ * @var Location
+ */
+ protected $location;
+
+ /**
+ * The nested "cause" exception.
+ * @var 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);
+ * @param Exception|string $p1
+ * @param Location|Exception|null $p2
+ * @param Location|null $p3
+ */
+ public 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);
+ }
+ }
+
+ /**
+ * Gets the cause exception.
+ *
+ * @return Exception
+ */
+ public function getCause() {
+ return $this->cause;
+ }
+
+ /**
+ * Gets the location of error in XML file.
+ *
+ * @return Location
+ */
+ public function getLocation() {
+ return $this->location;
+ }
+
+ /**
+ * Sets the location of error in XML file.
+ *
+ * @param Location $loc
+ */
+ public function setLocation(Location $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 100755
index 00000000..a4086aa3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/BuildListener.php
@@ -0,0 +1,91 @@
+<?php
+/*
+ * $Id: 46e871c830686838e509a3b0e173e7f4c0736ab3 $
+ *
+ * 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 $Id$
+ * @see BuildEvent
+ * @see Project::addBuildListener()
+ * @package phing
+ */
+interface BuildListener {
+
+ /**
+ * Fired before any targets are started.
+ *
+ * @param BuildEvent $event The BuildEvent
+ */
+ public function buildStarted(BuildEvent $event);
+
+ /**
+ * Fired after the last target has finished.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent::getException()
+ */
+ public function buildFinished(BuildEvent $event);
+
+ /**
+ * Fired when a target is started.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent::getTarget()
+ */
+ public function targetStarted(BuildEvent $event);
+
+ /**
+ * Fired when a target has finished.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent#getException()
+ */
+ public function targetFinished(BuildEvent $event);
+
+ /**
+ * Fired when a task is started.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent::getTask()
+ */
+ public function taskStarted(BuildEvent $event);
+
+ /**
+ * Fired when a task has finished.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent::getException()
+ */
+ public function taskFinished(BuildEvent $event);
+
+ /**
+ * Fired whenever a message is logged.
+ *
+ * @param BuildEvent $event The BuildEvent
+ * @see BuildEvent::getMessage()
+ */
+ public function messageLogged(BuildEvent $event);
+}
diff --git a/buildscripts/phing/classes/phing/BuildLogger.php b/buildscripts/phing/classes/phing/BuildLogger.php
new file mode 100755
index 00000000..03458159
--- /dev/null
+++ b/buildscripts/phing/classes/phing/BuildLogger.php
@@ -0,0 +1,70 @@
+<?php
+/*
+ * $Id: 64eb45bf98f65e415da03c93c4f0d89573a5e29c $
+ *
+ * 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 for build loggers.
+ *
+ * Build loggers are build listeners but with some additional functionality:
+ * - They can be configured with a log level (below which they will ignore messages)
+ * - They have error and output streams
+ *
+ * Classes that implement a listener must implement this interface.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Id$
+ * @see BuildEvent
+ * @see Project::addBuildListener()
+ * @package phing
+ */
+interface BuildLogger extends BuildListener {
+
+ /**
+ * Sets the min log level that this logger should respect.
+ *
+ * Messages below this level are ignored.
+ *
+ * Constants for the message levels are in Project.php. The order of
+ * the levels, from least to most verbose, is:
+ * - Project::MSG_ERR
+ * - Project::MSG_WARN
+ * - Project::MSG_INFO
+ * - Project::MSG_VERBOSE
+ * - Project::MSG_DEBUG
+ *
+ * @param int $level The log level integer (e.g. Project::MSG_VERBOSE, etc.).
+ */
+ public function setMessageOutputLevel($level);
+
+ /**
+ * Sets the standard output stream to use.
+ * @param OutputStream $output Configured output stream (e.g. STDOUT) for standard output.
+ */
+ public function setOutputStream(OutputStream $output);
+
+ /**
+ * Sets the output stream to use for errors.
+ * @param OutputStream $err Configured output stream (e.g. STDERR) for errors.
+ */
+ public function setErrorStream(OutputStream $err);
+
+}
diff --git a/buildscripts/phing/classes/phing/ConfigurationException.php b/buildscripts/phing/classes/phing/ConfigurationException.php
new file mode 100755
index 00000000..81735e1b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/ConfigurationException.php
@@ -0,0 +1,85 @@
+<?php
+/*
+ * $Id: 6070efdfa67cb145fd48525e88737d39c8eff4b2 $
+ *
+ * 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>.
+ */
+
+/**
+ * ConfigurationException is thrown by Phing during the configuration and setup phase of the project.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Id$
+ * @package phing
+ */
+class ConfigurationException extends Exception {
+
+ /**
+ * Location in the xml file.
+ * @var Location
+ */
+ protected $location;
+
+ /**
+ * The nested "cause" exception.
+ * @var Exception
+ */
+ protected $cause;
+
+ /**
+ * Construct a ConfigurationException.
+ * Supported signatures:
+ * throw new BuildException($causeExc);
+ * throw new BuildException($msg);
+ * throw new BuildException($msg, $causeExc);
+ * @param Exception|string $p1
+ * @param Exception|null $p2
+ */
+ public function __construct($p1, $p2 = null) {
+
+ $cause = null;
+ $msg = "";
+
+ if ($p2 !== null) {
+ if ($p2 instanceof Exception) {
+ $cause = $p2;
+ $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() ."]";
+ }
+ }
+
+ /**
+ * Gets the cause exception.
+ *
+ * @return Exception
+ */
+ public function getCause() {
+ return $this->cause;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/IntrospectionHelper.php b/buildscripts/phing/classes/phing/IntrospectionHelper.php
new file mode 100755
index 00000000..8bcf2456
--- /dev/null
+++ b/buildscripts/phing/classes/phing/IntrospectionHelper.php
@@ -0,0 +1,575 @@
+<?php
+
+/*
+ * $Id: a5f2dbd71bafd2c363026d911132c3b47bf44239 $
+ *
+ * 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 $Id: a5f2dbd71bafd2c363026d911132c3b47bf44239 $
+ * @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 $class The classname for this IH.
+ */
+ public 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 ($method->getNumberOfRequiredParameters() > 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.
+ * @param Project $project
+ * @param string $element
+ * @param string $attributeName
+ * @param mixed $value
+ */
+ public 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 {
+ // 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.
+ *
+ * @param Project $project
+ * @param string $element
+ * @param string $text
+ */
+ public 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).
+ *
+ * @param Project $project
+ * @param string $element
+ * @param string $elementName
+ * @return object Returns the nested element.
+ * @throws BuildException
+ */
+ public 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.
+ *
+ * @param Project $project
+ * @param string $element
+ * @param string $child
+ * @param string|null $elementName
+ * @return void
+ * @throws BuildException
+ */
+ public 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?
+ * @return boolean
+ */
+ public function supportsCharacters() {
+ return ($this->methodAddText !== null);
+ }
+
+ /**
+ * Return all attribues supported by the introspected class.
+ * @return string[]
+ */
+ public 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.
+ * @return string[]
+ */
+ public 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.
+ */
+ public 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.
+ *
+ * @param string $methodName
+ * @param string $prefix
+ * @return string
+ */
+ public function getPropertyName($methodName, $prefix) {
+ $start = strlen($prefix);
+ return strtolower(substr($methodName, $start));
+ }
+
+ /**
+ * Prints warning message to screen if -debug was used.
+ * @param string $msg
+ */
+ public 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 100755
index 00000000..d663ee42
--- /dev/null
+++ b/buildscripts/phing/classes/phing/Phing.php
@@ -0,0 +1,1414 @@
+<?php
+/*
+ * $Id: 1ad418f51ac07c9afaadf1c1f4befd5535f5b390 $
+ *
+ * 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/ConfigurationException.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/OutputStream.php';
+include_once 'phing/system/io/FileOutputStream.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 $Id: 1ad418f51ac07c9afaadf1c1f4befd5535f5b390 $
+ * @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();
+
+ /**
+ * @var OUtputStream Stream for standard output.
+ */
+ private static $out;
+
+ /**
+ * @var OutputStream Stream for error output.
+ */
+ private static $err;
+
+ /**
+ * @var boolean Whether we are using a logfile.
+ */
+ private static $isLogFileUsed = false;
+
+ /**
+ * Array to hold original ini settings that Phing changes (and needs
+ * to restore in restoreIni() method).
+ *
+ * @var array Struct of array(setting-name => setting-value)
+ * @see restoreIni()
+ */
+ private static $origIniSettings = array();
+
+ /**
+ * 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
+ * @see execute()
+ * @see runBuild()
+ * @throws Exception - if there is an error during build
+ */
+ public static function start($args, array $additionalUserProperties = null) {
+
+ try {
+ $m = new Phing();
+ $m->execute($args);
+ } catch (Exception $exc) {
+ self::handleLogfile();
+ throw $exc;
+ }
+
+ if ($additionalUserProperties !== null) {
+ foreach($additionalUserProperties as $key => $value) {
+ $m->setDefinedProperty($key, $value);
+ }
+ }
+
+ try {
+ $m->runBuild();
+ } catch(Exception $exc) {
+ self::handleLogfile();
+ throw $exc;
+ }
+
+ // everything fine, shutdown
+ self::handleLogfile();
+ }
+
+ /**
+ * Prints the message of the Exception if it's not null.
+ * @param Exception $t
+ */
+ public static function printMessage(Exception $t) {
+ if (self::$err === null) { // Make sure our error output is initialized
+ self::initializeOutputStreams();
+ }
+ if (self::getMsgOutputLevel() >= Project::MSG_VERBOSE) {
+ self::$err->write($t->__toString() . PHP_EOL);
+ } else {
+ self::$err->write($t->getMessage() . PHP_EOL);
+ }
+ }
+
+ /**
+ * Sets the stdout and stderr streams if they are not already set.
+ */
+ private static function initializeOutputStreams() {
+ if (self::$out === null) {
+ self::$out = new OutputStream(fopen("php://stdout", "w"));
+ }
+ if (self::$err === null) {
+ self::$err = new OutputStream(fopen("php://stderr", "w"));
+ }
+ }
+
+ /**
+ * Sets the stream to use for standard (non-error) output.
+ * @param OutputStream $stream The stream to use for standard output.
+ */
+ public static function setOutputStream(OutputStream $stream) {
+ self::$out = $stream;
+ }
+
+ /**
+ * Gets the stream to use for standard (non-error) output.
+ * @return OutputStream
+ */
+ public static function getOutputStream() {
+ return self::$out;
+ }
+
+ /**
+ * Sets the stream to use for error output.
+ * @param OutputStream $stream The stream to use for error output.
+ */
+ public static function setErrorStream(OutputStream $stream) {
+ self::$err = $stream;
+ }
+
+ /**
+ * Gets the stream to use for error output.
+ * @return OutputStream
+ */
+ public static function getErrorStream() {
+ return self::$err;
+ }
+
+ /**
+ * Close logfiles, if we have been writing to them.
+ *
+ * @since Phing 2.3.0
+ */
+ private static function handleLogfile() {
+ if (self::$isLogFileUsed) {
+ self::$err->close();
+ self::$out->close();
+ }
+ }
+
+ /**
+ * 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;
+
+ // 1) First handle any options which should always
+ // Note: The order in which these are executed is important (if multiple of these options are specified)
+
+ if (in_array('-help', $args) || in_array('-h', $args)) {
+ $this->printUsage();
+ return;
+ }
+
+ if (in_array('-version', $args) || in_array('-v', $args)) {
+ $this->printVersion();
+ return;
+ }
+
+ // 2) Next pull out stand-alone args.
+ // Note: The order in which these are executed is important (if multiple of these options are specified)
+
+ if (false !== ($key = array_search('-quiet', $args, true)) || false !== ($key = array_search('-q', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_WARN;
+ unset($args[$key]);
+ }
+
+ if (false !== ($key = array_search('-verbose', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_VERBOSE;
+ unset($args[$key]);
+ }
+
+ if (false !== ($key = array_search('-debug', $args, true))) {
+ self::$msgOutputLevel = Project::MSG_DEBUG;
+ unset($args[$key]);
+ }
+
+ // 3) Finally, cycle through to parse remaining args
+ //
+ $keys = array_keys($args); // Use keys and iterate to max(keys) since there may be some gaps
+ $max = $keys ? max($keys) : -1;
+ for($i=0; $i <= $max; $i++) {
+
+ if (!array_key_exists($i, $args)) {
+ // skip this argument, since it must have been removed above.
+ continue;
+ }
+
+ $arg = $args[$i];
+
+ if ($arg == "-logfile") {
+ try {
+ // see: http://phing.info/trac/ticket/65
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a log file when using the -logfile argument\n";
+ throw new ConfigurationException($msg);
+ } else {
+ $logFile = new PhingFile($args[++$i]);
+ $out = new FileOutputStream($logFile); // overwrite
+ self::setOutputStream($out);
+ self::setErrorStream($out);
+ self::$isLogFileUsed = true;
+ }
+ } catch (IOException $ioe) {
+ $msg = "Cannot write on the specified log file. Make sure the path exists and you have write permissions.";
+ throw new ConfigurationException($msg, $ioe);
+ }
+ } elseif ($arg == "-buildfile" || $arg == "-file" || $arg == "-f") {
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a buildfile when using the -buildfile argument.";
+ throw new ConfigurationException($msg);
+ } else {
+ $this->buildFile = new PhingFile($args[++$i]);
+ }
+ } elseif ($arg == "-listener") {
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a listener class when using the -listener argument";
+ throw new ConfigurationException($msg);
+ } 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 && !StringHelper::startsWith("-D", $args[$i + 1])) {
+ $value = $args[++$i];
+ }
+ self::$definedProps->setProperty($name, $value);
+ } elseif ($arg == "-logger") {
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a classname when using the -logger argument";
+ throw new ConfigurationException($msg);
+ } else {
+ $this->loggerClassname = $args[++$i];
+ }
+ } elseif ($arg == "-inputhandler") {
+ if ($this->inputHandlerClassname !== null) {
+ throw new ConfigurationException("Only one input handler class may be specified.");
+ }
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a classname when using the -inputhandler argument";
+ throw new ConfigurationException($msg);
+ } else {
+ $this->inputHandlerClassname = $args[++$i];
+ }
+ } elseif ($arg == "-propertyfile") {
+ if (!isset($args[$i+1])) {
+ $msg = "You must specify a filename when using the -propertyfile argument";
+ throw new ConfigurationException($msg);
+ } else {
+ $p = new Properties();
+ $p->load(new PhingFile($args[++$i]));
+ foreach ($p->getProperties() as $prop => $value) {
+ $this->setProperty($prop, $value);
+ }
+ }
+ } elseif ($arg == "-longtargets") {
+ self::$definedProps->setProperty('phing.showlongtargets', 1);
+ } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l" || $arg == "-p") {
+ // 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
+ self::$err->write("Unknown argument: $arg" . PHP_EOL);
+ self::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 ConfigurationException("Buildfile: " . $this->buildFile->__toString() . " does not exist!");
+ }
+
+ // make sure it's not a directory
+ if ($this->buildFile->isDirectory()) {
+ throw new ConfigurationException("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
+ */
+ private function _getParentFile(PhingFile $file) {
+ $filename = $file->getAbsolutePath();
+ $file = new PhingFile($filename);
+ $filename = $file->getParent();
+ 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
+ */
+ private function _findBuildFile($start, $suffix) {
+ $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 ConfigurationException("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();
+ }
+
+ // make sure that minimum required phing version is satisfied
+ try {
+ $this->comparePhingVersion($project->getPhingVersion());
+ } catch(Exception $exc) {
+ $project->fireBuildFinished($exc);
+ restore_error_handler();
+ self::unsetCurrentProject();
+ throw $exc;
+ }
+
+ // 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();
+ }
+
+ private function comparePhingVersion($version) {
+ $current = strtolower(self::getPhingVersion());
+ $current = trim(str_replace('phing', '', $current));
+
+ // make sure that version checks are not applied to trunk
+ if('dev' === $current) {
+ return 1;
+ }
+
+ if(-1 == version_compare($current, $version)) {
+ throw new BuildException(
+ sprintf('Incompatible Phing version (%s). Version "%s" required.', $current, $version));
+ }
+ }
+
+ /**
+ * Bind any registered build listeners to this project.
+ *
+ * This means adding the logger and any build listeners that were specified
+ * with -listener arg.
+ *
+ * @param Project $project
+ * @return void
+ */
+ private function addBuildListeners(Project $project) {
+ // Add the default listener
+ $project->addBuildListener($this->createLogger());
+
+ foreach($this->listeners as $listenerClassname) {
+ try {
+ $clz = Phing::import($listenerClassname);
+ } catch (Exception $x) {
+ $msg = "Unable to instantiate specified listener "
+ . "class " . $listenerClassname . " : "
+ . $e->getMessage();
+ throw new ConfigurationException($msg);
+ }
+
+ $listener = new $clz();
+
+ if ($listener instanceof StreamRequiredBuildLogger) {
+ throw new ConfigurationException("Unable to add " . $listenerClassname . " as a listener, since it requires explicit error/output streams. (You can specify it as a -logger.)");
+ }
+ $project->addBuildListener($listener);
+ }
+ }
+
+ /**
+ * 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 ConfigurationException($msg);
+ }
+ }
+ $project->setInputHandler($handler);
+ }
+
+ /**
+ * Creates the default build logger for sending build events to the log.
+ * @return BuildLogger 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;
+ if (!($logger instanceof BuildLogger)) {
+ throw new BuildException($classname . ' does not implement the BuildLogger interface.');
+ }
+ } else {
+ require_once 'phing/listener/DefaultLogger.php';
+ $logger = new DefaultLogger();
+ }
+ $logger->setMessageOutputLevel(self::$msgOutputLevel);
+ $logger->setOutputStream(self::$out);
+ $logger->setErrorStream(self::$err);
+ 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 16384: // E_USER_DEPRECATED
+ case 8192: // E_DEPRECATED
+ 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 */
+ public static function printUsage() {
+
+ $msg = "";
+ $msg .= "phing [options] [target [target2 [target3] ...]]" . PHP_EOL;
+ $msg .= "Options: " . PHP_EOL;
+ $msg .= " -h -help print this message" . PHP_EOL;
+ $msg .= " -l -list list available targets in this project" . PHP_EOL;
+ $msg .= " -v -version print the version information and exit" . PHP_EOL;
+ $msg .= " -q -quiet be extra quiet" . PHP_EOL;
+ $msg .= " -verbose be extra verbose" . PHP_EOL;
+ $msg .= " -debug print debugging information" . PHP_EOL;
+ $msg .= " -longtargets show target descriptions during build" . PHP_EOL;
+ $msg .= " -logfile <file> use given file for log" . PHP_EOL;
+ $msg .= " -logger <classname> the class which is to perform logging" . PHP_EOL;
+ $msg .= " -f -buildfile <file> use given buildfile" . PHP_EOL;
+ $msg .= " -D<property>=<value> use value for given property" . PHP_EOL;
+ $msg .= " -propertyfile <file> load all properties from file" . PHP_EOL;
+ $msg .= " -find <file> search for buildfile towards the root of the" . PHP_EOL;
+ $msg .= " filesystem and use it" . PHP_EOL;
+ $msg .= " -inputhandler <file> the class to use to handle user input" . PHP_EOL;
+ //$msg .= " -recursive <file> search for buildfile downwards and use it" . PHP_EOL;
+ $msg .= PHP_EOL;
+ $msg .= "Report bugs to <dev@phing.tigris.org>".PHP_EOL;
+ self::$err->write($msg);
+ }
+
+ /**
+ * Prints the current Phing version.
+ */
+ public static function printVersion() {
+ self::$out->write(self::getPhingVersion().PHP_EOL);
+ }
+
+ /**
+ * Gets the current Phing version based on VERSION.TXT file.
+ * @return string
+ * @throws BuildException - if unable to find version file.
+ */
+ public static function getPhingVersion() {
+ $versionPath = self::getResourcePath("phing/etc/VERSION.TXT");
+ if ($versionPath === null) {
+ $versionPath = self::getResourcePath("etc/VERSION.TXT");
+ }
+ if ($versionPath === null) {
+ throw new ConfigurationException("No VERSION.TXT file found; try setting phing.home environment variable.");
+ }
+ 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) {
+ throw new ConfigurationException("Can't read version information file");
+ }
+ return $phingVersion;
+ }
+
+ /**
+ * Print the project description, if any
+ */
+ public static function printDescription(Project $project) {
+ if ($project->getDescription() !== null) {
+ self::$out->write($project->getDescription() . PHP_EOL);
+ }
+ }
+
+ /** 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();
+ if ($currentTarget->isHidden()) {
+ continue;
+ }
+
+ // 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) {
+
+ $spaces = ' ';
+ while (strlen($spaces) < $maxlen) {
+ $spaces .= $spaces;
+ }
+ $msg = "";
+ $msg .= $heading . PHP_EOL;
+ $msg .= str_repeat("-",79) . PHP_EOL;
+
+ $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 .= PHP_EOL;
+ }
+ if ($total > 0) {
+ self::$out->write($msg . PHP_EOL);
+ }
+ }
+
+ /**
+ * 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) {
+
+ /// check if this is a PEAR-style path (@link http://pear.php.net/manual/en/standards.naming.php)
+ if (strpos($dotPath, '.') === false && strpos($dotPath, '_') !== false) {
+ $classname = $dotPath;
+ $dotPath = str_replace('_', '.', $dotPath);
+ } else {
+ $classname = StringHelper::unqualify($dotPath);
+ }
+
+ // 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)
+ if (class_exists($classname)) {
+ return $classname;
+ }
+
+ $dotClassname = basename($dotPath);
+ $dotClassnamePos = strlen($dotPath) - strlen($dotClassname);
+
+ // 1- temporarily replace escaped '.' with another illegal char (#)
+ $tmp = str_replace('\.', '##', $dotClassname);
+ // 2- swap out the remaining '.' with DIR_SEP
+ $tmp = strtr($tmp, '.', DIRECTORY_SEPARATOR);
+ // 3- swap back the escaped '.'
+ $tmp = str_replace('##', '.', $tmp);
+
+ $classFile = $tmp . ".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, get_include_path());
+ $add_parts = explode(PATH_SEPARATOR, $classpath);
+ $new_parts = array_diff($add_parts, $curr_parts);
+ if ($new_parts) {
+ set_include_path(implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts)));
+ }
+ }
+
+ $ret = include_once($path);
+
+ if ($ret === false) {
+ $msg = "Error importing $path";
+ if (self::getMsgOutputLevel() >= Project::MSG_DEBUG) {
+ $x = new Exception("for-path-trace-only");
+ $msg .= $x->getTraceAsString();
+ }
+ throw new ConfigurationException($msg);
+ }
+ }
+
+ /**
+ * 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 = 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) {
+ $testPath = $prefix . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ }
+
+ // Check for the property phing.home
+ $homeDir = self::getProperty('phing.home');
+ if ($homeDir) {
+ $testPath = $homeDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ }
+
+ // 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.
+ $dataDir = '@DATA-DIR@';
+ if ($dataDir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted.
+ if (!file_exists($dataDir)) {
+ self::log("The PEAR data_dir setting is incorrect: {$dataDir}.", Project::MSG_ERR);
+ self::log("Please edit using 'pear config-set data_dir ...' and re-install Phing.", Project::MSG_ERR);
+ return null;
+ }
+
+ $testPath = $dataDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ } else {
+ // We're not using PEAR, so do one additional check based on path of
+ // current file (Phing.php)
+ $maybeHomeDir = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..');
+ $testPath = $maybeHomeDir . DIRECTORY_SEPARATOR . $path;
+ if (file_exists($testPath)) {
+ return $testPath;
+ }
+ }
+
+ 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.interpreter', getenv('PHP_COMMAND'));
+ self::setProperty('line.separator', PHP_EOL);
+ self::setProperty('php.version', PHP_VERSION);
+ self::setProperty('user.home', getenv('HOME'));
+ self::setProperty('application.startdir', getcwd());
+ self::setProperty('phing.startTime', gmdate('D, d M Y H:i:s', time()) . ' GMT');
+
+ // 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 application.startdir,
+ * 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 to PHP_CLASSPATH constant (if this has been defined).
+ * @return void
+ * @throws ConfigurationException - if the include_path could not be set (for some bizarre reason)
+ */
+ private static function setIncludePaths() {
+ if (defined('PHP_CLASSPATH')) {
+ $result = set_include_path(PHP_CLASSPATH);
+ if ($result === false) {
+ throw new ConfigurationException("Could not set PHP include_path.");
+ }
+ self::$origIniSettings['include_path'] = $result; // save original value for setting back later
+ }
+ }
+
+ /**
+ * Converts shorthand notation values as returned by ini_get()
+ * @see http://www.php.net/ini_get
+ * @param string $val
+ */
+ private static function convertShorthand($val)
+ {
+ $val = trim($val);
+ $last = strtolower($val[strlen($val) - 1]);
+
+ switch($last) {
+ // The 'G' modifier is available since PHP 5.1.0
+ case 'g':
+ $val *= 1024;
+ case 'm':
+ $val *= 1024;
+ case 'k':
+ $val *= 1024;
+ }
+
+ return $val;
+ }
+
+ /**
+ * Sets PHP INI values that Phing needs.
+ * @return void
+ */
+ private static function setIni() {
+
+ self::$origIniSettings['error_reporting'] = error_reporting(E_ALL);
+
+ // We won't bother storing original max_execution_time, since 1) the value in
+ // php.ini may be wrong (and there's no way to get the current value) and
+ // 2) it would mean something very strange to set it to a value less than time script
+ // has already been running, which would be the likely change.
+
+ set_time_limit(0);
+
+ self::$origIniSettings['magic_quotes_gpc'] = ini_set('magic_quotes_gpc', 'off');
+ self::$origIniSettings['short_open_tag'] = ini_set('short_open_tag', 'off');
+ self::$origIniSettings['default_charset'] = ini_set('default_charset', 'iso-8859-1');
+ self::$origIniSettings['register_globals'] = ini_set('register_globals', 'off');
+ self::$origIniSettings['allow_call_time_pass_reference'] = ini_set('allow_call_time_pass_reference', 'on');
+ self::$origIniSettings['track_errors'] = ini_set('track_errors', 1);
+
+ $mem_limit = (int) self::convertShorthand(ini_get('memory_limit'));
+ if ($mem_limit < (32 * 1024 * 1024) && $mem_limit > -1) {
+ // We do *not* need to save the original value here, since we don't plan to restore
+ // this after shutdown (we don't trust the effectiveness of PHP's garbage collection).
+ ini_set('memory_limit', '32M'); // nore: this may need to be higher for many projects
+ }
+ }
+
+ /**
+ * Restores [most] PHP INI values to their pre-Phing state.
+ *
+ * Currently the following settings are not restored:
+ * - max_execution_time (because getting current time limit is not possible)
+ * - memory_limit (which may have been increased by Phing)
+ *
+ * @return void
+ */
+ private static function restoreIni()
+ {
+ foreach(self::$origIniSettings as $settingName => $settingValue) {
+ switch($settingName) {
+ case 'error_reporting':
+ error_reporting($settingValue);
+ break;
+ default:
+ ini_set($settingName, $settingValue);
+ }
+ }
+ }
+
+ /**
+ * 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 but does not initiate the build process.
+ * @return void
+ * @throws Exception - If the Phing environment cannot be initialized.
+ */
+ public static function startup() {
+
+ // setup STDOUT and STDERR defaults
+ self::initializeOutputStreams();
+
+ // some init stuff
+ self::getTimer()->start();
+
+ self::setSystemConstants();
+ self::setIncludePaths();
+ self::setIni();
+ }
+
+ /**
+ * Halts the system.
+ * @deprecated This method is deprecated and is no longer called by Phing internally. Any
+ * normal shutdown routines are handled by the shutdown() method.
+ * @see shutdown()
+ */
+ public static function halt() {
+ self::shutdown();
+ }
+
+ /**
+ * Performs any shutdown routines, such as stopping timers.
+ * @return void
+ */
+ public static function shutdown() {
+ self::restoreIni();
+ self::getTimer()->stop();
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/Project.php b/buildscripts/phing/classes/phing/Project.php
new file mode 100755
index 00000000..8e662543
--- /dev/null
+++ b/buildscripts/phing/classes/phing/Project.php
@@ -0,0 +1,1050 @@
+<?php
+/*
+ * $Id: 7e67218e8e616860f9c746f9ab600f523089ea2e $
+ *
+ * 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/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 $Id: 7e67218e8e616860f9c746f9ab600f523089ea2e $
+ * @package phing
+ */
+class Project {
+
+ // Logging level constants.
+ const MSG_DEBUG = 4;
+ const MSG_VERBOSE = 3;
+ const MSG_INFO = 2;
+ const MSG_WARN = 1;
+ const MSG_ERR = 0;
+
+ /** 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;
+
+ /** require phing version */
+ private $phingVersion;
+
+ /** a FileUtils object */
+ private $fileUtils;
+
+ /** Build listeneers */
+ private $listeners = array();
+
+ /**
+ * Constructor, sets any default vars.
+ */
+ public function __construct() {
+ $this->fileUtils = new FileUtils();
+ $this->inputHandler = new DefaultInputHandler();
+ }
+
+ /**
+ * Sets the input handler
+ * @param InputHandler $handler
+ */
+ public function setInputHandler(InputHandler $handler) {
+ $this->inputHandler = $handler;
+ }
+
+ /**
+ * Retrieves the current input handler.
+ * @return InputHandler
+ */
+ public function getInputHandler() {
+ return $this->inputHandler;
+ }
+
+ /** inits the project, called from main app */
+ public 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) */
+ public 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;
+ }
+ $found = $this->properties[$name];
+ // check to see if there are unresolved property references
+ if (false !== strpos($found, '${')) {
+ // attempt to resolve properties
+ $found = $this->replaceProperties($found);
+ // save resolved value
+ $this->properties[$name] = $found;
+ }
+ return $found;
+ }
+
+ /**
+ * 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 Project $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
+ // ---------------------------------------------------------
+
+
+ /**
+ * Sets default target
+ * @param string $targetName
+ */
+ public function setDefaultTarget($targetName) {
+ $this->defaultTarget = (string) trim($targetName);
+ }
+
+ /**
+ * Returns default target
+ * @return string
+ */
+ public function getDefaultTarget() {
+ return (string) $this->defaultTarget;
+ }
+
+ /**
+ * Sets the name of the current project
+ *
+ * @param string $name name of project
+ * @return void
+ * @access public
+ * @author Andreas Aderhold, andi@binarycloud.com
+ */
+ public function setName($name) {
+ $this->name = (string) trim($name);
+ $this->setProperty("phing.project.name", $this->name);
+ }
+
+ /**
+ * Returns the name of this project
+ *
+ * @return string projectname
+ * @access public
+ * @author Andreas Aderhold, andi@binarycloud.com
+ */
+ public function getName() {
+ return (string) $this->name;
+ }
+
+ /**
+ * Set the projects description
+ * @param string $description
+ */
+ public function setDescription($description) {
+ $this->description = (string) trim($description);
+ }
+
+ /**
+ * return the description, null otherwise
+ * @return string|null
+ */
+ public function getDescription() {
+ return $this->description;
+ }
+
+ /**
+ * Set the minimum required phing version
+ * @param string $version
+ */
+ public function setPhingVersion($version) {
+ $version = str_replace('phing', '', strtolower($version));
+ $this->phingVersion = (string)trim($version);
+ }
+
+ /**
+ * Get the minimum required phing version
+ * @return string
+ */
+ public function getPhingVersion() {
+ if($this->phingVersion === null) {
+ $this->setPhingVersion(Phing::getPhingVersion());
+ }
+ return $this->phingVersion;
+ }
+
+ /**
+ * Set basedir object from xm
+ * @param PhingFile|string $dir
+ */
+ public 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
+ *
+ * @return PhingFile Basedir PhingFile object
+ * @access public
+ * @throws BuildException
+ * @author Andreas Aderhold, andi@binarycloud.com
+ */
+ public 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
+ */
+ public 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.
+ */
+ public 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);
+ }
+ }
+
+ /**
+ * Returns the task definitions
+ * @return array
+ */
+ public function getTaskDefinitions() {
+ return $this->taskdefs;
+ }
+
+ /**
+ * Adds a data type definition.
+ * @param string $typeName Name of the type.
+ * @param string $typeClass The class to use.
+ * @param string $classpath The classpath to use.
+ */
+ public 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 $typeName ($typeClass) already registerd, skipping", Project::MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * Returns the data type definitions
+ * @return array
+ */
+ public function getDataTypeDefinitions() {
+ return $this->typedefs;
+ }
+
+ /**
+ * Add a new target to the project
+ * @param string $targetName
+ * @param Target $target
+ */
+ public function addTarget($targetName, &$target) {
+ if (isset($this->targets[$targetName])) {
+ throw new BuildException("Duplicate target: $targetName");
+ }
+ $this->addOrReplaceTarget($targetName, $target);
+ }
+
+ /**
+ * Adds or replaces a target in the project
+ * @param string $targetName
+ * @param Target $target
+ */
+ public function addOrReplaceTarget($targetName, &$target) {
+ $this->log(" +Target: $targetName", Project::MSG_DEBUG);
+ $target->setProject($this);
+ $this->targets[$targetName] = $target;
+
+ $ctx = $this->getReference("phing.parsing.context");
+ $current = $ctx->getConfigurator()->getCurrentTargets();
+ $current[$targetName] = $target;
+ }
+
+ /**
+ * Returns the available targets
+ * @return array
+ */
+ public 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
+ * @return Task A task object
+ * @throws BuildException
+ * Exception
+ */
+ public function createTask($taskType) {
+ try {
+ $classname = "";
+ $tasklwr = strtolower($taskType);
+ foreach ($this->taskdefs as $name => $class) {
+ if (strtolower($name) === $tasklwr) {
+ $classname = $class;
+ break;
+ }
+ }
+
+ if ($classname === "") {
+ return null;
+ }
+
+ $cls = Phing::import($classname);
+
+ 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 datatype instance and return reference to it
+ * See createTask() for explanation how this works
+ *
+ * @param string $typeName Type name
+ * @return object A datatype object
+ * @throws BuildException
+ * Exception
+ */
+ public 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 $targetNames List of target names to execute
+ * @return void
+ * @throws BuildException
+ */
+ public function executeTargets($targetNames) {
+ foreach($targetNames as $tname) {
+ $this->executeTarget($tname);
+ }
+ }
+
+ /**
+ * Executes a target
+ *
+ * @param string $targetName Name of Target to execute
+ * @return void
+ * @throws BuildException
+ */
+ public 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);
+ }
+
+ /**
+ * Helper function
+ */
+ public 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 string $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 array $targets is a array representing a "name to Target" mapping
+ * @return An array of Strings with the names of the targets in
+ * sorted order.
+ */
+ public 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.
+
+ public 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 a dependency of 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;
+ }
+
+ public function _makeCircularException($end, $stk) {
+ $sb = "Circular dependency: $end";
+ do {
+ $c = (string) array_pop($stk);
+ $sb .= " <- ".$c;
+ } 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
+ * @param string $name
+ * @param object $object
+ */
+ public 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
+ */
+ public function getReferences() {
+ return $this->references;
+ }
+
+ /**
+ * Returns a specific reference.
+ * @param string $key The reference id/key.
+ * @return object Reference or null if not defined
+ */
+ public 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
+ * @param string $msg
+ * @param int $level
+ */
+ public 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 100755
index 00000000..343e3a6c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/ProjectComponent.php
@@ -0,0 +1,70 @@
+<?php
+/*
+ * $Id: 9b2bbe8e58b0a7de3d426b1dcc88b8cac4bc69e2 $
+ *
+ * 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 $Id$
+ * @package phing
+ */
+abstract class ProjectComponent {
+
+ /**
+ * Holds a reference to the project that a project component
+ * (a task, a target, etc.) belongs to
+ *
+ * @var Project A reference to the current project instance
+ */
+ protected $project = null;
+
+ /**
+ * References the project to the current component.
+ *
+ * @param Project $project The reference to the current project
+ */
+ public function setProject($project) {
+ $this->project = $project;
+ }
+
+ /**
+ * Returns a reference to current project
+ *
+ * @return Project Reference to current porject object
+ */
+ public function getProject() {
+ return $this->project;
+ }
+
+ /**
+ * Logs a message with the given priority.
+ *
+ * @param string $msg The message to be logged.
+ * @param integer $level 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 100755
index 00000000..305a35f3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/RuntimeConfigurable.php
@@ -0,0 +1,116 @@
+<?php
+/*
+ * $Id: 5dd4f1cae5f6da32a48370cf9cfaa39e1124c91c $
+ *
+ * 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 $Id$
+ * @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"];
+ }
+
+ 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 100755
index 00000000..342d11cb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/Target.php
@@ -0,0 +1,375 @@
+<?php
+/*
+ * $Id: b6779ff7860ec7a7a84d74a40ffcc9efa75255f7 $
+ *
+ * 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 $Id: b6779ff7860ec7a7a84d74a40ffcc9efa75255f7 $
+ * @access public
+ * @see TaskContainer
+ * @package phing
+ */
+
+class Target implements TaskContainer {
+
+ /**
+ * Name of target
+ * @var string
+ */
+ private $name;
+
+ /**
+ * Dependencies
+ * @var array
+ */
+ private $dependencies = array();
+
+ /**
+ * Holds objects of children of this target
+ * @var array
+ */
+ private $children = array();
+
+ /**
+ * The if condition from xml
+ * @var string
+ */
+ private $ifCondition = "";
+
+ /**
+ * The unless condition from xml
+ * @var string
+ */
+ private $unlessCondition = "";
+
+ /**
+ * Description of this target
+ * @var string
+ */
+ private $description;
+
+ /**
+ * Whether to hide target in targets list (-list -p switches)
+ * @var boolean
+ */
+ private $hidden = false;
+
+ /**
+ * Rreference to project
+ * @var Project
+ */
+ private $project;
+
+ /**
+ * References the project to the current component.
+ *
+ * @param Project $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 $dependency 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 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
+ */
+ public function getName() {
+ return (string) $this->name;
+ }
+
+ /**
+ * Set target status. If true, target does not come in phing -list
+ *
+ * @param boolean $flag
+ * @return Target
+ */
+ public function setHidden($flag)
+ {
+ $this->hidden = (boolean) $flag;
+ return $this;
+ }
+
+ /**
+ * Get target status. If true, target does not come in phing -list
+ *
+ * @return boolean
+ */
+ public function getHidden()
+ {
+ return $this->hidden;
+ }
+
+ /**
+ * Alias for getHidden()
+ *
+ * @return boolean
+ */
+ public function isHidden()
+ {
+ return $this->getHidden();
+ }
+
+ /**
+ * Adds a task element to the list of this targets child elements
+ *
+ * @param Task $task The task object to add
+ * @access public
+ */
+ public function addTask(Task $task) {
+ $this->children[] = $task;
+ }
+
+ /**
+ * Adds a runtime configurable element to the list of this targets child
+ * elements.
+ *
+ * @param RuntimeConfigurable $rtc The RuntimeConfigurable object
+ * @access public
+ */
+ 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 $property 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 $property 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 $description 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
+ */
+ public 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 (BuildException $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 100755
index 00000000..d2490a90
--- /dev/null
+++ b/buildscripts/phing/classes/phing/Task.php
@@ -0,0 +1,272 @@
+<?php
+/*
+ * $Id: 65e76e7a86e08ce1f1d4ef0f7cda011bc9efee5e $
+ *
+ * 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 $Id$
+ * @see Project#createTask()
+ * @package phing
+ */
+abstract class Task extends ProjectComponent {
+
+ /**
+ * Owning Target object
+ * @var Target
+ */
+ protected $target;
+
+ /**
+ * Description of the task
+ * @var string
+ */
+ protected $description;
+
+ /**
+ * Internal taskname (req)
+ * @var string
+ */
+ protected $taskType;
+
+ /**
+ * Taskname for logger
+ * @var string
+ */
+ protected $taskName;
+
+ /**
+ * Stored buildfile location
+ * @var Location
+ */
+ protected $location;
+
+ /**
+ * Wrapper of the task
+ * @var RuntimeConfigurable
+ */
+ protected $wrapper;
+
+ /**
+ * Sets the owning target this task belongs to.
+ *
+ * @param Target Reference to owning target
+ */
+ public function setOwningTarget(Target $target) {
+ $this->target = $target;
+ }
+
+ /**
+ * Returns the owning target of this task.
+ *
+ * @return Target The target object that owns this task
+ */
+ public function getOwningTarget() {
+ return $this->target;
+ }
+
+ /**
+ * Returns the name of task, used only for log messages
+ *
+ * @return string Name of this task
+ */
+ 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
+ *
+ * @param string $name
+ * @return string A string representing the name of this task for log
+ */
+ 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)
+ */
+ public 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)
+ */
+ public function setTaskType($name) {
+ $this->taskType = (string) $name;
+ }
+
+ /**
+ * Returns a name
+ * @param string $slotName
+ */
+ 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 $desc 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.
+ */
+ abstract public 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.
+ *
+ * @param Location $location The location object describing the position of this
+ * task within the buildfile.
+ */
+ function setLocation(Location $location) {
+ $this->location = $location;
+ }
+
+ /**
+ * Returns the wrapper object for runtime configuration
+ *
+ * @return RuntimeConfigurable The wrapper object used by this task
+ */
+ 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 RuntimeConfigurable $wrapper The wrapper object this task should use
+ */
+ function setRuntimeConfigurableWrapper(RuntimeConfigurable $wrapper) {
+ $this->wrapper = $wrapper;
+ }
+
+ /**
+ * Configure this task if it hasn't been done already.
+ */
+ public function maybeConfigure() {
+ if ($this->wrapper !== null) {
+ $this->wrapper->maybeConfigure($this->project);
+ }
+ }
+
+ /**
+ * Perfrom this task
+ */
+ 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 100755
index 00000000..ba323c56
--- /dev/null
+++ b/buildscripts/phing/classes/phing/TaskAdapter.php
@@ -0,0 +1,85 @@
+<?php
+/*
+ * $Id: 8cd2a3322c659a5de7fcb47e21192730e5cc863d $
+ *
+ * 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 $Id$
+ * @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);
+ $this->log($ex->getTraceAsString(), Project::MSG_DEBUG);
+ 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 100755
index 00000000..4be2ef41
--- /dev/null
+++ b/buildscripts/phing/classes/phing/TaskContainer.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * $Id: c31c503eb573b2f454071e9a97fa6a2323c128eb $
+ *
+ * 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
+ */
+
+/**
+ * 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 $Id$
+ * @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 100755
index 00000000..b04365e7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/UnknownElement.php
@@ -0,0 +1,215 @@
+<?php
+/*
+ * $Id: a4e6c2e3f776c5a353e52fb8518b3533f14a97c4 $
+ *
+ * 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 $Id$
+ * @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 {
+ $project = $this->project === null ? $parent->project : $this->project;
+ $realChild = $ih->createElement($project, $parent, $child->getTag());
+ }
+
+ $childWrapper->setProxy($realChild);
+ if ($realChild instanceof Task) {
+ $realChild->setRuntimeConfigurableWrapper($childWrapper);
+ }
+
+ if ($realChild instanceof ProjectComponent) {
+ $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/contrib/DocBlox/Parallel/Manager.php b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Manager.php
new file mode 100644
index 00000000..6fe71107
--- /dev/null
+++ b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Manager.php
@@ -0,0 +1,304 @@
+<?php
+/**
+ * DocBlox
+ *
+ * PHP Version 5
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+
+/**
+ * Manager class for Parallel processes.
+ *
+ * This class will manage the workers and make sure all processes are executed
+ * in parallel and not too many at the same time.
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+class DocBlox_Parallel_Manager extends ArrayObject
+{
+ /** @var int The maximum number of processes to run simultaneously */
+ protected $process_limit = 2;
+
+ /** @var boolean Tracks whether this manager is currently executing */
+ protected $is_running = false;
+
+ /**
+ * Tries to autodetect the optimal number of process by counting the number
+ * of processors.
+ *
+ * @param array $input Input for the array object.
+ * @param int $flags flags for the array object.
+ * @param string $iterator_class Iterator class for this array object.
+ */
+ public function __construct(
+ $input = array(), $flags = 0, $iterator_class = "ArrayIterator"
+ ) {
+ parent::__construct($input, $flags, $iterator_class);
+
+ if (is_readable('/proc/cpuinfo')) {
+ $processors = 0;
+ exec("cat /proc/cpuinfo | grep processor | wc -l", $processors);
+ $this->setProcessLimit(reset($processors));
+ }
+ }
+
+ /**
+ * Adds a worker to to the queue.
+ *
+ * This method will prepare a worker to be executed in parallel once the
+ * execute method is invoked.
+ * A fluent interface is provided so that you can chain multiple workers
+ * in one call.
+ *
+ * Example:
+ *
+ * $cb1 = function() { var_dump('a'); sleep(1); };
+ * $cb2 = function() { var_dump('b'); sleep(1); };
+ *
+ * $mgr = new DocBlox_Parallel_Manager();
+ * $mgr->setProcessLimit(2)
+ * ->addWorker(new DocBlox_Parallel_Worker($cb1))
+ * ->addWorker(new DocBlox_Parallel_Worker($cb2))
+ * ->execute();
+ *
+ * @param int $index The key for this worker.
+ * @param DocBlox_Parallel_Worker $newval The worker to add onto the queue.
+ *
+ * @see DocBlox_Parallel_Manager::execute()
+ *
+ * @throws RuntimeException if this method is invoked while the
+ * manager is busy executing tasks.
+ * @throws InvalidArgumentException if the provided element is not of type
+ * DocBlox_Parallel_Worker.
+ *
+ * @return void
+ */
+ public function offsetSet($index, $newval)
+ {
+ if (!$newval instanceof DocBlox_Parallel_Worker) {
+ throw new InvalidArgumentException(
+ 'Provided element must be of type DocBlox_Parallel_Worker'
+ );
+ }
+ if ($this->isRunning()) {
+ throw new RuntimeException(
+ 'Workers may not be added during execution of the manager'
+ );
+ }
+
+ parent::offsetSet($index, $newval);
+ }
+
+ /**
+ * Convenience method to make the addition of workers explicit and allow a
+ * fluent interface.
+ *
+ * @param DocBlox_Parallel_Worker $worker The worker to add onto the queue.
+ *
+ * @return self
+ */
+ public function addWorker(DocBlox_Parallel_Worker $worker)
+ {
+ $this[] = $worker;
+
+ return $this;
+ }
+
+ /**
+ * Sets how many processes at most to execute at the same time.
+ *
+ * A fluent interface is provided so that you can chain multiple workers
+ * in one call.
+ *
+ * @param int $process_limit The limit, minimum of 1
+ *
+ * @see DocBlox_Parallel_Manager::addWorker() for an example
+ *
+ * @return self
+ */
+ public function setProcessLimit($process_limit)
+ {
+ if ($process_limit < 1) {
+ throw new InvalidArgumentException(
+ 'Number of simultaneous processes may not be less than 1'
+ );
+ }
+
+ $this->process_limit = $process_limit;
+
+ return $this;
+ }
+
+ /**
+ * Returns the current limit on the amount of processes that can be
+ * executed at the same time.
+ *
+ * @return int
+ */
+ public function getProcessLimit()
+ {
+ return $this->process_limit;
+ }
+
+ /**
+ * Returns whether the manager is executing the workers.
+ *
+ * @return boolean
+ */
+ public function isRunning()
+ {
+ return $this->is_running;
+ }
+
+ /**
+ * Executes each worker.
+ *
+ * This method loops through the list of workers and tries to fork as
+ * many times as the ProcessLimit dictates at the same time.
+ *
+ * @return void
+ */
+ public function execute()
+ {
+ /** @var int[] $processes */
+ $processes = $this->startExecution();
+
+ /** @var DocBlox_Parallel_Worker $worker */
+ foreach ($this as $worker) {
+
+ // if requirements are not met, execute workers in series.
+ if (!$this->checkRequirements()) {
+ $worker->execute();
+ continue;
+ }
+
+ $this->forkAndRun($worker, $processes);
+ }
+
+ $this->stopExecution($processes);
+ }
+
+ /**
+ * Notifies manager that execution has started, checks requirements and
+ * returns array for child processes.
+ *
+ * If forking is not available because library requirements are not met
+ * than the list of workers is processed in series and a E_USER_NOTICE is
+ * triggered.
+ *
+ * @return int[]
+ */
+ protected function startExecution()
+ {
+ $this->is_running = true;
+
+ // throw a E_USER_NOTICE if the requirements are not met.
+ if (!$this->checkRequirements()) {
+ trigger_error(
+ 'The PCNTL extension is not available, running workers in series '
+ . 'instead of parallel',
+ E_USER_NOTICE
+ );
+ }
+
+ return array();
+ }
+
+ /**
+ * Waits for all processes to have finished and notifies the manager that
+ * execution has stopped.
+ *
+ * @param int[] &$processes List of running processes.
+ *
+ * @return void
+ */
+ protected function stopExecution(array &$processes)
+ {
+ // starting of processes has ended but some processes might still be
+ // running wait for them to finish
+ while (!empty($processes)) {
+ pcntl_waitpid(array_shift($processes), $status);
+ }
+
+ /** @var DocBlox_Parallel_Worker $worker */
+ foreach ($this as $worker) {
+ $worker->pipe->push();
+ }
+
+ $this->is_running = false;
+ }
+
+ /**
+ * Forks the current process and calls the Worker's execute method OR
+ * handles the parent process' execution.
+ *
+ * This is the really tricky part of the forking mechanism. Here we invoke
+ * {@link http://www.php.net/manual/en/function.pcntl-fork.php pcntl_fork}
+ * and either execute the forked process or deal with the parent's process
+ * based on in which process we are.
+ *
+ * To fully understand what is going on here it is recommended to read the
+ * PHP manual page on
+ * {@link http://www.php.net/manual/en/function.pcntl-fork.php pcntl_fork}
+ * and associated articles.
+ *
+ * If there are more workers than may be ran simultaneously then this method
+ * will wait until a slot becomes available and then starts the next worker.
+ *
+ * @param DocBlox_Parallel_Worker $worker The worker to process.
+ * @param int[] &$processes The list of running processes.
+ *
+ * @throws RuntimeException if we are unable to fork.
+ *
+ * @return void
+ */
+ protected function forkAndRun(
+ DocBlox_Parallel_Worker $worker, array &$processes
+ ) {
+ $worker->pipe = new DocBlox_Parallel_WorkerPipe($worker);
+
+ // fork the process and register the PID
+ $pid = pcntl_fork();
+
+ switch ($pid) {
+ case -1:
+ throw new RuntimeException('Unable to establish a fork');
+ case 0: // Child process
+ $worker->execute();
+
+ $worker->pipe->pull();
+
+ // Kill -9 this process to prevent closing of shared file handlers.
+ // Not doing this causes, for example, MySQL connections to be cleaned.
+ posix_kill(getmypid(), SIGKILL);
+ default: // Parent process
+ // Keep track if the worker children
+ $processes[] = $pid;
+
+ if (count($processes) >= $this->getProcessLimit()) {
+ pcntl_waitpid(array_shift($processes), $status);
+ }
+ break;
+ }
+ }
+
+ /**
+ * Returns true when all requirements are met.
+ *
+ * @return bool
+ */
+ protected function checkRequirements()
+ {
+ return (bool)(extension_loaded('pcntl'));
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/README.md b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/README.md
new file mode 100644
index 00000000..272d7191
--- /dev/null
+++ b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/README.md
@@ -0,0 +1,106 @@
+Parallel
+========
+
+This is a library for introducing Parallelization into your project.
+See the `example.php` file for an example how to use this library.
+
+Theory of Operation
+-------------------
+
+This library will enable the developer to execute a given amount of tasks
+(workers) in parallel. This is achieved by adding workers onto a manager,
+optionally defining how many processes to run simultaneously and then execute
+the manager.
+
+Under Linux this library will try to detect the number of processors and allow
+a maximum number of processes to run equal to the number of processors. If this
+cannot be determined or the user is running Windows then a default of 2 is used.
+
+Requirements and graceful degradation
+-------------------------------------
+
+Parallelization has several requirements. But to allow distribution, without
+adding several requirements to your application, will this library execute the
+given tasks in serie if the requirements are not met. And throw a E_USER_NOTICE
+php error that explains to the user that dependencies are missing.
+
+The requirements for this library are:
+
+* A *NIX compatible operating system
+* Scripts must not run from an apache module
+* the PCNTL PHP extension (http://php.net/manual/en/book.pcntl.php)
+
+Workers
+-------
+
+Workers are basically wrappers around callback functions or methods. As such you
+can use anything in your existing project and parallelize it.
+
+Do note that each parallel process is a duplicate of the original. This means
+that, for example, if you pass an object (or other reference) and change that,
+that the changes that you have made do not carry over to the caller.
+
+The return value of the given callback is stored as result on the worker and
+can be read using the `getResult()` method.
+
+Any exception that is thrown will result in an error, where the `getReturnCode()`
+method will return the exception code (be warned: this may be 0!) and the
+`getError()` method will return the exception message.
+
+Errors and exceptions
+---------------------
+
+if a task throws an exception it is caught and registered as an error. The
+exception's code is used as error number, where the message is used as error
+message.
+
+By using this, instead of dying, you can continue execution of the other parallel
+processes and handle errors yourself after all processes have been executed.
+
+Examples
+--------
+
+### Fluent interface
+
+ $mgr = new DocBlox_Parallel_Manager();
+ $mgr
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'a'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'b'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'c'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'd'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'e'; }))
+ ->execute();
+
+ /** @var DocBlox_Parallel_Worker $worker */
+ foreach ($mgr as $worker) {
+ var_dump($worker->getResult());
+ }
+
+### Array interface
+
+ $mgr = new DocBlox_Parallel_Manager();
+ $mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'f'; });
+ $mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'g'; });
+ $mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'h'; });
+ $mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'i'; });
+ $mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'j'; });
+ $mgr->execute();
+
+ /** @var DocBlox_Parallel_Worker $worker */
+ foreach ($mgr as $worker) {
+ var_dump($worker->getResult());
+ }
+
+TODO
+----
+
+* Improve docs
+* More intelligent process slots; currently only the oldest in a 'set' of slots
+ is waited on but if this runs for a longer time then the other slots than
+ those will not be filled as long as the first slot is occupied.
+* Last parts of IPC (Inter-Process Communication), to be able to return
+ information from Workers to the Manager.
+
+ * STDOUT
+ * STDERR
+
diff --git a/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Worker.php b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Worker.php
new file mode 100644
index 00000000..338f4b25
--- /dev/null
+++ b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Worker.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * DocBlox
+ *
+ * PHP Version 5
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+
+/**
+ * Class that represents the execution of a single task within a parallelized
+ * frame.
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+class DocBlox_Parallel_Worker
+{
+ /** @var callback the task to execute for this worker */
+ protected $task = null;
+
+ /** @var mixed[] A list of argument to pass to the task */
+ protected $arguments = array();
+
+ /** @var int The return code to tell the parent process how it went */
+ protected $return_code = -1;
+
+ /** @var mixed The result of the given task */
+ protected $result = '';
+
+ /** @var string The error message, if an error occurred */
+ protected $error = '';
+
+ /**
+ * Creates the worker and sets the task to execute optionally including
+ * the arguments that need to be passed to the task.
+ *
+ * @param callback $task The task to invoke upon execution.
+ * @param mixed[] $arguments The arguments to provide to the task.
+ */
+ function __construct($task, array $arguments = array())
+ {
+ $this->setTask($task);
+ $this->arguments = $arguments;
+ }
+
+ /**
+ * Returns the list of arguments as provided int he constructor.
+ *
+ * @see DocBlox_Parallel_Worker::__construct()
+ *
+ * @return mixed[]
+ */
+ public function getArguments()
+ {
+ return $this->arguments;
+ }
+
+ /**
+ * Returns the task as provided in the constructor.
+ *
+ * @see DocBlox_Parallel_Worker::__construct()
+ *
+ * @return callback
+ */
+ public function getTask()
+ {
+ return $this->task;
+ }
+
+ /**
+ * Returns the available return code.
+ *
+ * This method may return -1 if no return code is available yet.
+ *
+ * @return int
+ */
+ public function getReturnCode()
+ {
+ return $this->return_code;
+ }
+
+ /**
+ * Sets the return code for this worker.
+ *
+ * Recommended is to use the same codes as are used with
+ * {@link http://www.gnu.org/software/bash/manual/html_node/Exit-Status.html
+ * exit codes}.
+ *
+ * In short: 0 means that the task succeeded and a any other positive value
+ * indicates an error condition.
+ *
+ * @param int $return_code Recommended to be a positive number
+ *
+ * @throw InvalidArgumentException if the code is not a number or negative
+ *
+ * @return void
+ */
+ public function setReturnCode($return_code)
+ {
+ if (!is_numeric($return_code) || ($return_code < 0)) {
+ throw new InvalidArgumentException(
+ 'Expected the return code to be a positive number'
+ );
+ }
+
+ $this->return_code = $return_code;
+ }
+
+ /**
+ * Returns the error message associated with the return code.
+ *
+ * @return string
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Sets the error message.
+ *
+ * @param string $error The error message.
+ *
+ * @return void
+ */
+ public function setError($error)
+ {
+ $this->error = $error;
+ }
+
+ /**
+ * Returns the result for this task run.
+ *
+ * @return null|mixed
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * Sets the result for this task run.
+ *
+ * @param mixed $result The value that is returned by the task; can be anything.
+ *
+ * @return void
+ */
+ public function setResult($result)
+ {
+ $this->result = $result;
+ }
+
+ /**
+ * Invokes the task with the given arguments and processes the output.
+ *
+ * @return void.
+ */
+ public function execute()
+ {
+ $this->setReturnCode(0);
+ try {
+ $this->setResult(
+ call_user_func_array($this->getTask(), $this->getArguments())
+ );
+ } catch (Exception $e) {
+ $this->setError($e->getMessage());
+ $this->setReturnCode($e->getCode());
+ }
+ }
+
+ /**
+ * Sets the task for this worker and validates whether it is callable.
+ *
+ * @param callback $task The task to execute when the execute method
+ * is invoked.
+ *
+ * @throws InvalidArgumentException if the given argument is not a callback.
+ *
+ * @see DocBlox_Parallel_Worker::__construct()
+ * @see DocBlox_Parallel_Worker::execute()
+ *
+ * @return void
+ */
+ protected function setTask($task)
+ {
+ if (!is_callable($task)) {
+ throw new InvalidArgumentException(
+ 'Worker task is not a callable object'
+ );
+ }
+
+ $this->task = $task;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/WorkerPipe.php b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/WorkerPipe.php
new file mode 100644
index 00000000..3b7eb7fe
--- /dev/null
+++ b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/WorkerPipe.php
@@ -0,0 +1,127 @@
+<?php
+/**
+ * DocBlox
+ *
+ * PHP Version 5
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+
+/**
+ * Class that represents a named pipe for a Worker.
+ *
+ * This class manages the named pipe for a worker and is able to push and pull
+ * specific data to facilitate IPC (interprocess communication).
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+class DocBlox_Parallel_WorkerPipe
+{
+ /** @var DocBlox_Parallel_Worker worker class that is associated */
+ protected $worker;
+
+ /** @var string Path to the pipe */
+ protected $path;
+
+ /**
+ * Initializes the named pipe.
+ *
+ * @param DocBlox_Parallel_Worker $worker Associated worker.
+ */
+ public function __construct(DocBlox_Parallel_Worker $worker)
+ {
+ $this->worker = $worker;
+
+ $this->path = tempnam(sys_get_temp_dir(), 'dpm_');
+ posix_mkfifo($this->path, 0750);
+ }
+
+ /**
+ * If the named pipe was not cleaned up, do so now.
+ */
+ public function __destruct()
+ {
+ if (file_exists($this->path)) {
+ $this->release();
+ }
+ }
+
+ /**
+ * Pull the worker data into the named pipe.
+ *
+ * @return void
+ */
+ public function pull()
+ {
+ $this->writePipeContents();
+ }
+
+ /**
+ * Push the worker data back onto the worker and release the pipe.
+ *
+ * @return void
+ */
+ public function push()
+ {
+ list($result, $error, $return_code) = $this->readPipeContents();
+ $this->release();
+
+ $this->worker->setResult($result);
+ $this->worker->setError($error);
+ $this->worker->setReturnCode($return_code);
+ }
+
+ /**
+ * Convenience method to show relation to readPipeContents.
+ *
+ * @return void
+ */
+ protected function writePipeContents()
+ {
+ // push the gathered data onto a name pipe
+ $pipe = fopen($this->path, 'w');
+ fwrite(
+ $pipe, serialize(
+ array(
+ $this->worker->getResult(),
+ $this->worker->getError(),
+ $this->worker->getReturnCode()
+ )
+ )
+ );
+ fclose($pipe);
+ }
+
+ /**
+ * Returns the unserialized contents of the pipe.
+ *
+ * @return array
+ */
+ protected function readPipeContents()
+ {
+ $pipe = fopen($this->path, 'r+');
+ $result = unserialize(fread($pipe, filesize($this->path)));
+ fclose($pipe);
+
+ return $result;
+ }
+
+ /**
+ * Releases the pipe.
+ *
+ * @return void
+ */
+ protected function release()
+ {
+ unlink($this->path);
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/example.php b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/example.php
new file mode 100644
index 00000000..3bdcd408
--- /dev/null
+++ b/buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/example.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * DocBlox
+ *
+ * PHP Version 5
+ *
+ * @category DocBlox
+ * @package Parallel
+ * @author Mike van Riel <mike.vanriel@naenius.com>
+ * @copyright 2010-2011 Mike van Riel / Naenius (http://www.naenius.com)
+ * @license http://www.opensource.org/licenses/mit-license.php MIT
+ * @link http://docblox-project.org
+ */
+
+/** Include the manager as we do not autoload */
+require_once 'Manager.php';
+
+/** Include the worker as we do not autoload */
+require_once 'Worker.php';
+
+/** Include the worker's pipe as we do not autoload */
+require_once 'WorkerPipe.php';
+
+// -----------------------------------------------------------------------------
+// method 1: using a fluent interface and the addWorker helper.
+// -----------------------------------------------------------------------------
+
+$mgr = new DocBlox_Parallel_Manager();
+$mgr
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'a'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'b'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'c'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'd'; }))
+ ->addWorker(new DocBlox_Parallel_Worker(function() { sleep(1); return 'e'; }))
+ ->execute();
+
+/** @var DocBlox_Parallel_Worker $worker */
+foreach ($mgr as $worker) {
+ var_dump($worker->getResult());
+}
+
+// -----------------------------------------------------------------------------
+// method 2: using the manager as worker array
+// -----------------------------------------------------------------------------
+
+$mgr = new DocBlox_Parallel_Manager();
+$mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'f'; });
+$mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'g'; });
+$mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'h'; });
+$mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'i'; });
+$mgr[] = new DocBlox_Parallel_Worker(function() { sleep(1); return 'j'; });
+$mgr->execute();
+
+/** @var DocBlox_Parallel_Worker $worker */
+foreach ($mgr as $worker) {
+ var_dump($worker->getResult());
+}
diff --git a/buildscripts/phing/classes/phing/filters/BaseFilterReader.php b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php
new file mode 100755
index 00000000..4489b16e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php
@@ -0,0 +1,157 @@
+<?php
+
+/*
+ * $Id: a1da135c09abf5cf07a53b3a327baf3497cfb697 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..8d3b0810
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * $Id: 412cc012db35b1dcf3545b93d5053e727d66b61f $
+ *
+ * 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 $Id$
+ * @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..2b773dbe
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/ChainableReader.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * $Id: fb9ebbb44f13ecc3693265e1b793ab17cea543a1 $
+ *
+ * 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
+ * @package phing.filters
+ */
+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 100755
index 00000000..2517783f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/ExpandProperties.php
@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * $Id: d6bb7717db7cf2b122cbdcb93e5bb0f45d97ec52 $
+ *
+ * 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 $Id: d6bb7717db7cf2b122cbdcb93e5bb0f45d97ec52 $
+ * @see BaseFilterReader
+ * @package phing.filters
+ */
+class ExpandProperties extends BaseFilterReader implements ChainableReader {
+ protected $logLevel = Project::MSG_VERBOSE;
+
+ /**
+ * Set level of log messages generated (default = info)
+ * @param string $level
+ */
+ public function setLevel($level)
+ {
+ switch ($level)
+ {
+ case "error": $this->logLevel = Project::MSG_ERR; break;
+ case "warning": $this->logLevel = Project::MSG_WARN; break;
+ case "info": $this->logLevel = Project::MSG_INFO; break;
+ case "verbose": $this->logLevel = Project::MSG_VERBOSE; break;
+ case "debug": $this->logLevel = Project::MSG_DEBUG; break;
+ }
+ }
+
+ /**
+ * 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(), $this->logLevel);
+
+ 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 100755
index 00000000..3cbcb51b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/HeadFilter.php
@@ -0,0 +1,161 @@
+<?php
+
+/*
+ * $Id: e3e9c0a171b4416545e57fe42b45b4eec14914ce $
+ *
+ * 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 $Id$
+ * @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/IconvFilter.php b/buildscripts/phing/classes/phing/filters/IconvFilter.php
new file mode 100755
index 00000000..c9883b17
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/IconvFilter.php
@@ -0,0 +1,155 @@
+<?php
+
+/*
+ * $Id: 9c0d703f08f0160b6a699d328a6025587877e104 $
+ *
+ * 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';
+
+/**
+ * Encode data from <code>in</code> encoding to <code>out</code> encoding.
+ *
+ * Example:
+ * <pre>
+ * <iconvfilter inputencoding="UTF-8" outputencoding="CP1251" />
+ * </pre>
+ * Or:
+ * <pre>
+ * <filterreader classname="phing.filters.IconvFilter">
+ * <param name="inputencoding" value="UTF-8" />
+ * <param name="outputencoding" value="CP1251" />
+ * </filterreader>
+ * </pre>
+ *
+ * @author Alexey Shockov, <alexey@shockov.com>
+ * @version $Id$
+ * @package phing.filters
+ */
+class IconvFilter
+ extends BaseParamFilterReader
+ implements ChainableReader {
+
+ private $_inputEncoding;
+
+ private $_outputEncoding;
+
+ /**
+ * 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) {
+ $this->_initialize();
+
+ // Process whole text at once.
+ $text = null;
+ while (($data = $this->in->read($len)) !== -1) {
+ $text .= $data;
+ }
+
+ // At the end.
+ if (null === $text) {
+ return -1;
+ }
+
+ $this->log(
+ "Encoding " . $this->in->getResource() . " from " . $this->getInputEncoding() . " to " . $this->getOutputEncoding(),
+ Project::MSG_VERBOSE
+ );
+
+ return iconv($this->_inputEncoding, $this->_outputEncoding, $text);
+ }
+
+ /**
+ *
+ * @param string $encoding Input encoding.
+ */
+ public function setInputEncoding($encoding) {
+ $this->_inputEncoding = $encoding;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getInputEncoding() {
+ return $this->_inputEncoding;
+ }
+
+ /**
+ *
+ * @param string $encoding Output encoding.
+ */
+ public function setOutputEncoding($encoding) {
+ $this->_outputEncoding = $encoding;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getOutputEncoding() {
+ return $this->_outputEncoding;
+ }
+
+ /**
+ * Creates a new IconvFilter 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) {
+ $filter = new self($reader);
+
+ $filter->setInputEncoding($this->getInputEncoding());
+ $filter->setOutputEncoding($this->getOutputEncoding());
+
+ $filter->setInitialized(true);
+ $filter->setProject($this->getProject());
+
+ return $filter;
+ }
+
+ /**
+ * Configuring object from the parameters list.
+ */
+ private function _initialize() {
+ if ($this->getInitialized()) {
+ return;
+ }
+
+ $params = $this->getParameters();
+ if ($params !== null) {
+ foreach ($params as $param) {
+ if ('in' == $param->getName()) {
+ $this->setInputEncoding($param->getValue());
+ } else if ('out' == $param->getName()) {
+ $this->setOutputEncoding($param->getValue());
+ }
+ }
+ }
+
+ $this->setInitialized(true);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/filters/LineContains.php b/buildscripts/phing/classes/phing/filters/LineContains.php
new file mode 100755
index 00000000..b84b62c1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/LineContains.php
@@ -0,0 +1,260 @@
+<?php
+
+/*
+ * $Id: 2e783b14ff093df7de21477479a123403d630984 $
+ *
+ * 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 $Id$
+ * @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.
+ *
+ * @package phing.filters
+ */
+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 100755
index 00000000..c603978f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php
@@ -0,0 +1,179 @@
+<?php
+/*
+ * $Id: 0a881c0b67c96c20345980fd033f006379949dda $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..9edcc02a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/PrefixLines.php
@@ -0,0 +1,142 @@
+<?php
+
+/*
+ * $Id: 744d8766d5aba397c0a8efd61afb8e60bd77b0c3 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..70e8940f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php
@@ -0,0 +1,129 @@
+<?php
+
+/*
+ * $Id: 3ea7f569d0f0b1c4d0f057c9f7f8969cb829f2cb $
+ *
+ * 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 $Id$
+ * @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->getModifiers(), 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 100755
index 00000000..a5cd7521
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php
@@ -0,0 +1,435 @@
+<?php
+
+/*
+ * $Id: 6c5d97f2254de3c08ac34baaabf6119c54a49a7d $
+ *
+ * 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 $Id: 6c5d97f2254de3c08ac34baaabf6119c54a49a7d $
+ * @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."\"", Project::MSG_VERBOSE);
+ }
+
+ 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.
+ *
+ * @package phing.filters
+ */
+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) {
+ // special case for boolean values
+ if (is_bool($value)) {
+ if ($value) {
+ $this->_value = "true";
+ } else {
+ $this->_value = "false";
+ }
+ } else {
+ $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;
+ }
+
+ /**
+ * Sets the token value from text.
+ *
+ * @param string $value The value for this token. Must not be <code>null</code>.
+ */
+ function addText($value) {
+ $this->setValue($value);
+ }
+}
+
+
diff --git a/buildscripts/phing/classes/phing/filters/ReplaceTokensWithFile.php b/buildscripts/phing/classes/phing/filters/ReplaceTokensWithFile.php
new file mode 100644
index 00000000..580b8d84
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/ReplaceTokensWithFile.php
@@ -0,0 +1,361 @@
+<?php
+
+/*
+ * $Id: 164a2d9eeba3673653086b32e9fa2045168c992c $
+ *
+ * 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';
+
+/**
+ * Replaces tokens in the original input with the contents of a file.
+ * The file to be used is controlled by the name of the token which
+ * corresponds to the basename of the file to be used together with
+ * the optional pre and postfix strings that is possible to set.
+ *
+ * By default all HTML entities in the file is replaced by the
+ * corresponding HTML entities. This behaviour can be controlled by
+ * the "translatehtml" parameter.
+ *
+ * Supported parameters are:
+ * <pre>
+ * prefix string Text to be prefixed to token before using as filename
+ * postfix string Text to be prefixed to token before using as filename
+ * dir string The directory where the files should be read from
+ * translatehtml bool If we should translate all HTML entities in the file.
+ * </pre>
+ * Example:
+ *
+ * <pre><filterreader classname="phing.filters.ReplaceTokensWithFile">
+ * <param name="dir" value="examples/" />
+ * <param name="postfix" value=".php" />
+ * </filterreader></pre>
+ *
+ * @author johan persson, johanp@aditus.nu
+ * @version $Id: 164a2d9eeba3673653086b32e9fa2045168c992c $
+ * @access public
+ * @see ReplaceTokensWithFile
+ * @package phing.filters
+ */
+class ReplaceTokensWithFile extends BaseParamFilterReader implements ChainableReader {
+
+ /**
+ * Default "begin token" character.
+ * @var string
+ */
+ const DEFAULT_BEGIN_TOKEN = "#@#";
+
+ /**
+ * Default "end token" character.
+ * @var string
+ */
+ const DEFAULT_END_TOKEN = "#@#";
+
+ /**
+ * Array to hold the token sources that make tokens from
+ * different sources available
+ * @var array
+ */
+ private $_tokensources = array();
+
+ /**
+ * Character marking the beginning of a token.
+ * @var string
+ */
+ private $_beginToken = ReplaceTokensWithFile::DEFAULT_BEGIN_TOKEN;
+
+ /**
+ * Character marking the end of a token.
+ * @var string
+ */
+ private $_endToken = ReplaceTokensWithFile::DEFAULT_END_TOKEN;
+
+ /**
+ * File prefix to be inserted in front of the token to create the
+ * file name to be used.
+ * @var string
+ */
+ private $_prefix = '';
+
+ /**
+ * File postfix to be inserted in front of the token to create the
+ * file name to be used.
+ * @var string
+ */
+ private $_postfix = '';
+
+ /**
+ * Directory where to look for the files. The default is to look in the
+ * current file.
+ *
+ * @var string
+ */
+ private $_dir = './';
+
+ /**
+ * Translate all HTML entities in the file to the corresponding HTML
+ * entities before it is used as replacements. For example all '<'
+ * will be translated to &lt; before the content is inserted.
+ *
+ * @var boolean
+ */
+ private $_translatehtml = true;
+
+
+ /**
+ * Sets the drectory where to look for the files to use for token replacement
+ *
+ * @param string $dir
+ */
+ function setTranslateHTML($translate) {
+ $this->_translatehtml = (bool) $translate;
+ }
+
+ /**
+ * Returns the drectory where to look for the files to use for token replacement
+ */
+ function getTranslateHTML() {
+ return $this->_translatehtml;
+ }
+
+ /**
+ * Sets the drectory where to look for the files to use for token replacement
+ *
+ * @param string $dir
+ */
+ function setDir($dir) {
+ $this->_dir = (string) $dir;
+ }
+
+ /**
+ * Returns the drectory where to look for the files to use for token replacement
+ */
+ function getDir() {
+ return $this->_dir;
+ }
+
+ /**
+ * Sets the prefix that is prepended to the token in order to create the file
+ * name. For example if the token is 01 and the prefix is "example" then
+ * the filename to look for will be "example01"
+ *
+ * @param string $prefix
+ */
+ function setPrefix($prefix) {
+ $this->_prefix = (string) $prefix;
+ }
+
+ /*
+ * Returns the prefix that is prepended to the token in order to create the file
+ * name. For example if the token is 01 and the prefix is "example" then
+ * the filename to look for will be "example01"
+ */
+ function getPrefix() {
+ return $this->_prefix;
+ }
+
+ /**
+ * Sets the postfix that is added to the token in order to create the file
+ * name. For example if the token is 01 and the postfix is ".php" then
+ * the filename to look for will be "01.php"
+ *
+ * @param string $postfix
+ */
+ function setPostfix($postfix) {
+ $this->_postfix = (string) $postfix;
+ }
+
+ /**
+ * Returns the postfix that is added to the token in order to create the file
+ * name. For example if the token is 01 and the postfix is ".php" then
+ * the filename to look for will be "01.php"
+ */
+ function getPostfix() {
+ return $this->_postfix;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Replace the token found with the appropriate file contents
+ * @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) {
+
+ $filetoken = $matches[1];
+
+ // We look in all specified directories for the named file and use
+ // the first directory which has the file.
+ $dirs = explode(';',$this->_dir);
+
+ $ndirs = count($dirs);
+ $n = 0;
+ $file = $dirs[$n] . $this->_prefix . $filetoken . $this->_postfix;
+
+ while ( $n < $ndirs && ! is_readable($file) ) {
+ ++$n;
+ }
+
+ if( ! is_readable($file) || $n >= $ndirs ) {
+ $this->log("Can not read or find file \"$file\". Searched in directories: {$this->_dir}", Project::MSG_WARN);
+ //return $this->_beginToken . $filetoken . $this->_endToken;
+ return "[Phing::Filters::ReplaceTokensWithFile: Can not find file " . '"' . $filetoken . $this->_postfix . '"' . "]";
+ }
+
+ $buffer = file_get_contents($file);
+ if( $this->_translatehtml ) {
+ $buffer = htmlentities($buffer);
+ }
+
+ if ($buffer === null) {
+ $buffer = $this->_beginToken . $filetoken . $this->_endToken;
+ $this->log("No corresponding file found for key \"$buffer\"", Project::MSG_WARN);
+ } else {
+ $this->log("Replaced \"".$this->_beginToken . $filetoken . $this->_endToken."\" with content from file \"$file\"");
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Creates a new ReplaceTokensWithFile 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 ReplaceTokensWithFile($reader);
+ $newFilter->setProject($this->getProject());
+ $newFilter->setTranslateHTML($this->getTranslateHTML());
+ $newFilter->setDir($this->getDir());
+ $newFilter->setPrefix($this->getPrefix());
+ $newFilter->setPostfix($this->getPostfix());
+ $newFilter->setBeginToken($this->getBeginToken());
+ $newFilter->setEndToken($this->getEndToken());
+ $newFilter->setInitialized(true);
+ return $newFilter;
+ }
+
+ /**
+ * Initializes parameters
+ * This method is only called when this filter is used through
+ * a <filterreader> tag in build file.
+ */
+ private function _initialize() {
+ $params = $this->getParameters();
+ $n = count($params);
+
+ if ( $params !== null ) {
+ for($i = 0 ; $i < $n ; $i++) {
+ if ( $params[$i] !== null ) {
+ $name = $params[$i]->getName();
+ switch( $name ) {
+ case 'begintoken' :
+ $this->_beginToken = $params[$i]->getValue();
+ break;
+ case 'endtoken' :
+ $this->_endToken = $params[$i]->getValue();
+ break;
+ case 'dir':
+ $this->_dir = $params[$i]->getValue();
+ break;
+ case 'prefix':
+ $this->_prefix = $params[$i]->getValue();
+ break;
+ case 'postfix':
+ $this->_postfix = $params[$i]->getValue();
+ break;
+ case 'translatehtml':
+ $this->_translatehtml = $params[$i]->getValue();
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/buildscripts/phing/classes/phing/filters/StripLineBreaks.php b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php
new file mode 100755
index 00000000..08d1aa6b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php
@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * $Id: 84767114c6fcf8abe5fcc0dce48513faf18d6306 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..2a19ca25
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/StripLineComments.php
@@ -0,0 +1,207 @@
+<?php
+
+/*
+ * $Id: b0b2b1dc67fff8bd5285e43e9d11b15f4ef44ae7 $
+ *
+ * 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 $Id$
+ * @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.
+ *
+ * @package phing.filters
+ */
+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 100755
index 00000000..0abb8a67
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/StripPhpComments.php
@@ -0,0 +1,188 @@
+<?php
+
+/*
+ * $Id: 6c68ae0ad1aa7f2f7825087c1c54233bd2462124 $
+ *
+ * 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 $Id$
+ * @access public
+ * @see FilterReader
+ * @package phing.filters
+ */
+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 StripPhpComments 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;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/filters/StripWhitespace.php b/buildscripts/phing/classes/phing/filters/StripWhitespace.php
new file mode 100755
index 00000000..d7b6113f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/StripWhitespace.php
@@ -0,0 +1,95 @@
+<?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>.
+*/
+
+include_once 'phing/filters/BaseFilterReader.php';
+include_once 'phing/filters/ChainableReader.php';
+
+/**
+ * Strips whitespace from [php] files using PHP stripwhitespace() method.
+ *
+ * @author Hans Lellelid, hans@velum.net
+ * @version $Id$
+ * @see FilterReader
+ * @package phing.filters
+ * @todo -c use new PHP functions to perform this instead of regex.
+ */
+class StripWhitespace extends BaseFilterReader implements ChainableReader {
+
+ private $processed = false;
+
+ /**
+ * Returns the stream without Php comments and whitespace.
+ *
+ * @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 ($this->processed === true) {
+ return -1; // EOF
+ }
+
+ // Read XML
+ $php = null;
+ while ( ($buffer = $this->in->read($len)) !== -1 ) {
+ $php .= $buffer;
+ }
+
+ if ($php === null ) { // EOF?
+ return -1;
+ }
+
+ if(empty($php)) {
+ $this->log("PHP file is empty!", Project::MSG_WARN);
+ return ''; // return empty string, don't attempt to strip whitespace
+ }
+
+ // write buffer to a temporary file, since php_strip_whitespace() needs a filename
+ $file = new PhingFile(tempnam(PhingFile::getTempDir(), 'stripwhitespace'));
+ file_put_contents($file->getAbsolutePath(), $php);
+ $output = php_strip_whitespace($file->getAbsolutePath());
+ unlink($file->getAbsolutePath());
+
+ $this->processed = true;
+
+ return $output;
+ }
+
+ /**
+ * Creates a new StripWhitespace 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 StripWhitespace($reader);
+ $newFilter->setProject($this->getProject());
+ return $newFilter;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/filters/TabToSpaces.php b/buildscripts/phing/classes/phing/filters/TabToSpaces.php
new file mode 100755
index 00000000..80d3c215
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/TabToSpaces.php
@@ -0,0 +1,144 @@
+<?php
+
+/*
+ * $Id: 71dc074faa0ed97b47c49fec5449233ea485120c $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..95a9c6f5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/TailFilter.php
@@ -0,0 +1,157 @@
+<?php
+
+/*
+ * $Id: 3c108d45a4b3be6f6b9a395477e7641d8e17c44b $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..22abcee5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/TidyFilter.php
@@ -0,0 +1,162 @@
+<?php
+/*
+ * $Id: a612fea7722441639c6dfdc69b43ad65ec02652f $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..b2a4264c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/TranslateGettext.php
@@ -0,0 +1,285 @@
+<?php
+
+/*
+ * $Id: 7dc28b63ed7f57bcf86d92f2b669bd386c2076a6 $
+ *
+ * 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 $Id$
+ * @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/XincludeFilter.php b/buildscripts/phing/classes/phing/filters/XincludeFilter.php
new file mode 100644
index 00000000..e2b3cd00
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/XincludeFilter.php
@@ -0,0 +1,176 @@
+<?php
+
+/*
+ * $Id: 6c47e03d52cf26c183b05e347dac83735dd8c8dd $
+ *
+ * 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 Xinclude parsing to incoming text.
+ *
+ * Uses PHP DOM XML support
+ *
+ * @author Bill Karwin <bill@karwin.com>
+ * @version $Id: 6c47e03d52cf26c183b05e347dac83735dd8c8dd $
+ * @see FilterReader
+ * @package phing.filters
+ */
+class XincludeFilter extends BaseParamFilterReader implements ChainableReader {
+
+ private $basedir = null;
+
+ /**
+ * @var bool
+ */
+ private $processed = false;
+
+ /**
+ * Whether to resolve entities.
+ *
+ * @var bool
+ *
+ * @since 2.4
+ */
+ private $resolveExternals = false;
+
+ /**
+ * Whether to resolve entities.
+ *
+ * @param $resolveExternals
+ *
+ * @since 2.4
+ */
+ public function setResolveExternals($resolveExternals)
+ {
+ $this->resolveExternals = (bool)$resolveExternals;
+ }
+
+ /**
+ * @return bool
+ *
+ * @since 2.4
+ */
+ public function getResolveExternals()
+ {
+ return $this->resolveExternals;
+ }
+
+ public function setBasedir(PhingFile $dir)
+ {
+ $this->basedir = $dir;
+ }
+
+ public function getBasedir()
+ {
+ return $this->basedir;
+ }
+
+ /**
+ * 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('DomDocument')) {
+ throw new BuildException("Could not find the DomDocument class. Make sure PHP has been compiled/configured to support DOM XML.");
+ }
+
+ if ($this->processed === true) {
+ return -1; // EOF
+ }
+
+ // 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 '';
+ }
+
+ $this->log("Transforming XML " . $this->in->getResource() . " using Xinclude ", Project::MSG_VERBOSE);
+
+ $out = '';
+ try {
+ $out = $this->process($_xml);
+ $this->processed = true;
+ } catch (IOException $e) {
+ throw new BuildException($e);
+ }
+
+ return $out;
+ }
+
+ /**
+ * Try to process the Xinclude transformation
+ *
+ * @param string XML to process.
+ *
+ * @throws BuildException On errors
+ */
+ protected function process($xml) {
+
+ if ($this->basedir) {
+ $cwd = getcwd();
+ chdir($this->basedir);
+ }
+
+ // Create and setup document.
+ $xmlDom = new DomDocument();
+ $xmlDom->resolveExternals = $this->resolveExternals;
+
+ $xmlDom->loadXML($xml);
+
+ $xmlDom->xinclude();
+
+ if ($this->basedir) {
+ chdir($cwd);
+ }
+
+ return $xmlDom->saveXML();
+ }
+
+ /**
+ * Creates a new XincludeFilter 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 XincludeFilter($reader);
+ $newFilter->setProject($this->getProject());
+ $newFilter->setBasedir($this->getBasedir());
+ return $newFilter;
+ }
+
+}
+
+
diff --git a/buildscripts/phing/classes/phing/filters/XsltFilter.php b/buildscripts/phing/classes/phing/filters/XsltFilter.php
new file mode 100644
index 00000000..8866bff7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/XsltFilter.php
@@ -0,0 +1,408 @@
+<?php
+
+/*
+ * $Id: 057af49d450e4c137127acc0f5331368e7a76183 $
+ *
+ * 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 $Id: 057af49d450e4c137127acc0f5331368e7a76183 $
+ * @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;
+
+ /**
+ * Whether to resolve entities in the XML document (see
+ * {@link http://www.php.net/manual/en/class.domdocument.php#domdocument.props.resolveexternals}
+ * for more details).
+ *
+ * @var bool
+ *
+ * @since 2.4
+ */
+ private $resolveDocumentExternals = false;
+
+ /**
+ * Whether to resolve entities in the stylesheet.
+ *
+ * @var bool
+ *
+ * @since 2.4
+ */
+ private $resolveStylesheetExternals = 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;
+ }
+
+ /**
+ * Whether to resolve entities in document.
+ *
+ * @param bool $resolveExternals
+ *
+ * @since 2.4
+ */
+ function setResolveDocumentExternals($resolveExternals) {
+ $this->resolveDocumentExternals = (bool)$resolveExternals;
+ }
+
+ /**
+ * @return bool
+ *
+ * @since 2.4
+ */
+ function getResolveDocumentExternals() {
+ return $this->resolveDocumentExternals;
+ }
+
+ /**
+ * Whether to resolve entities in stylesheet.
+ *
+ * @param bool $resolveExternals
+ *
+ * @since 2.4
+ */
+ function setResolveStylesheetExternals($resolveExternals) {
+ $this->resolveStylesheetExternals = (bool)$resolveExternals;
+ }
+
+ /**
+ * @return bool
+ *
+ * @since 2.4
+ */
+ function getResolveStylesheetExternals() {
+ return $this->resolveStylesheetExternals;
+ }
+
+ /**
+ * 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();
+
+ // Create and setup document.
+ $xmlDom = new DOMDocument();
+ $xmlDom->resolveExternals = $this->resolveDocumentExternals;
+
+ // Create and setup stylesheet.
+ $xslDom = new DOMDocument();
+ $xslDom->resolveExternals = $this->resolveStylesheetExternals;
+
+ 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());
+ }
+
+ $errorlevel = error_reporting();
+ error_reporting($errorlevel & ~E_WARNING);
+ @$result = $processor->transformToXML($xmlDom);
+ error_reporting($errorlevel);
+
+ if (false === $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.
+ *
+ * @package phing.filters
+ */
+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 (alias to the setExpression()) method.
+ *
+ * @param string $v
+ * @see setExpression()
+ */
+ public function setValue($v)
+ {
+ $this->setExpression($v);
+ }
+
+ /**
+ * Gets expression value (alias to the getExpression()) method.
+ *
+ * @param string $v
+ * @see getExpression()
+ */
+ public function getValue()
+ {
+ return $this->getExpression();
+ }
+
+ /**
+ * 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;
+ }
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php
new file mode 100755
index 00000000..c465d0a1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php
@@ -0,0 +1,183 @@
+<?php
+/*
+ * $Id: c1709ddb9da44ce62fbe072c61d29dba4814e3f6 $
+ *
+ * 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 $Id$
+ * @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;
+ }
+
+}
+
diff --git a/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php
new file mode 100755
index 00000000..f47e155c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php
@@ -0,0 +1,97 @@
+<?php
+/*
+ * $Id: e709765b4c0c1be330183f462ab527fa8354b555 $
+ *
+ * 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 $Id$
+ * @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
+ * @return Token
+ */
+ 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 100755
index 00000000..5e53c878
--- /dev/null
+++ b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * $Id: 5d3d4fb125da3344b5aafec31ba330969bdbdb42 $
+ *
+ * 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 $Id$
+ * @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();
+ $defaultValue = $request->getDefaultValue();
+
+ if ($request instanceof YesNoInputRequest) {
+ $choices = $request->getChoices();
+ $defaultValue = $choices[(int) !$request->getDefaultValue()];
+ $prompt .= '(' . implode('/', $request->getChoices()) .')';
+ } elseif ($request instanceof MultipleChoiceInputRequest) { // (a,b,c,d)
+ $prompt .= '(' . implode(',', $request->getChoices()) . ')';
+ }
+
+ if ($request->getDefaultValue() !== null) {
+ $prompt .= ' ['.$defaultValue.']';
+ }
+ $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 100755
index 00000000..9a414fd4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/input/InputHandler.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * $Id: c7412bfab167852910c4dfe935769e4b0c7ec9fe $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..1d9e156d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/input/InputRequest.php
@@ -0,0 +1,107 @@
+<?php
+
+/*
+ * $Id: f74cb3768bf512aeb0156b8de3e3b65c824cd0dc $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..24e93b58
--- /dev/null
+++ b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php
@@ -0,0 +1,58 @@
+<?php
+/*
+ * $Id: 12fcf735b10cae890d51bce8d3aebb637d9b6928 $
+ *
+ * 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 $Id$
+ * @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/YesNoInputRequest.php b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php
new file mode 100755
index 00000000..1a712327
--- /dev/null
+++ b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php
@@ -0,0 +1,47 @@
+<?php
+/*
+ * $Id: 659526fec1ed2e66d5b9308fba48924ea3dda494 $
+ *
+ * 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 $Id: 659526fec1ed2e66d5b9308fba48924ea3dda494 $
+ * @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 100755
index 00000000..e6885a6a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/lib/Capsule.php
@@ -0,0 +1,267 @@
+<?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 $Id$
+ * @package phing.lib
+ */
+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/listener/AnsiColorLogger.php b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php
new file mode 100755
index 00000000..fc12c9d2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php
@@ -0,0 +1,234 @@
+<?php
+/*
+ * $Id: bea608bad3f8bd5733c7eac6451d15b1c937115c $
+ *
+ * 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
+ * phing/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 $Id$
+ */
+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_NORMAL . self::SEPARATOR . self::FG_RED . self::SUFFIX;
+ $this->warnColor = self::PREFIX . self::ATTR_NORMAL . self::SEPARATOR . self::FG_MAGENTA . self::SUFFIX;
+ $this->infoColor = self::PREFIX . self::ATTR_NORMAL . self::SEPARATOR . self::FG_CYAN . self::SUFFIX;
+ $this->verboseColor = self::PREFIX . self::ATTR_NORMAL . self::SEPARATOR . self::FG_GREEN . self::SUFFIX;
+ $this->debugColor = self::PREFIX . self::ATTR_NORMAL . 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) {
+ $this->errColor = self::PREFIX . $err . self::SUFFIX;
+ }
+ if ($warn !== null) {
+ $this->warnColor = self::PREFIX . $warn . self::SUFFIX;
+ }
+ if ($info !== null) {
+ $this->infoColor = self::PREFIX . $info . self::SUFFIX;
+ }
+ if ($verbose !== null) {
+ $this->verboseColor = self::PREFIX . $verbose . self::SUFFIX;
+ }
+ if ($debug !== null) {
+ $this->debugColor = self::PREFIX . $debug . self::SUFFIX;
+ }
+ } catch (IOException $ioe) {
+ //Ignore exception - we will use the defaults.
+ }
+ }
+
+ /**
+ * @see DefaultLogger#printMessage
+ * @param string $message
+ * @param OutputStream $stream
+ * @param int $priority
+ */
+ protected final function printMessage($message, OutputStream $stream, $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;
+ }
+
+ $stream->write($message . PHP_EOL);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/DefaultLogger.php b/buildscripts/phing/classes/phing/listener/DefaultLogger.php
new file mode 100755
index 00000000..31051a75
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/DefaultLogger.php
@@ -0,0 +1,279 @@
+<?php
+/*
+ * $Id: e7f902228f55a3be17b42eed785137cb97e7a29e $
+ *
+ * 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/StreamRequiredBuildLogger.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 $Id$
+ * @see BuildEvent
+ * @package phing.listener
+ */
+class DefaultLogger implements StreamRequiredBuildLogger {
+
+ /**
+ * 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;
+
+ /**
+ * @var OutputStream Stream to use for standard output.
+ */
+ protected $out;
+
+ /**
+ * @var OutputStream Stream to use for error output.
+ */
+ protected $err;
+
+ /**
+ * Construct a new default logger.
+ */
+ public function __construct() {
+
+ }
+
+ /**
+ * 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 int $level The logging level for the logger.
+ * @see BuildLogger#setMessageOutputLevel()
+ */
+ public function setMessageOutputLevel($level) {
+ $this->msgOutputLevel = (int) $level;
+ }
+
+ /**
+ * Sets the output stream.
+ * @param OutputStream $output
+ * @see BuildLogger#setOutputStream()
+ */
+ public function setOutputStream(OutputStream $output) {
+ $this->out = $output;
+ }
+
+ /**
+ * Sets the error stream.
+ * @param OutputStream $err
+ * @see BuildLogger#setErrorStream()
+ */
+ public function setErrorStream(OutputStream $err) {
+ $this->err = $err;
+ }
+
+ /**
+ * Sets the start-time when the build started. Used for calculating
+ * the build-time.
+ *
+ * @param object The BuildEvent
+ * @access public
+ */
+ public function buildStarted(BuildEvent $event) {
+ $this->startTime = Phing::currentTimeMillis();
+ if ($this->msgOutputLevel >= Project::MSG_INFO) {
+ $this->printMessage("Buildfile: ".$event->getProject()->getProperty("phing.file"), $this->out, 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
+ * @see BuildEvent::getException()
+ */
+ public function buildFinished(BuildEvent $event) {
+ $error = $event->getException();
+ if ($error === null) {
+ $msg = PHP_EOL . $this->getBuildSuccessfulMessage() . PHP_EOL;
+ } else {
+ $msg = PHP_EOL . $this->getBuildFailedMessage() . PHP_EOL;
+ if (Project::MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) {
+ $msg .= $error->__toString().PHP_EOL;
+ } else {
+ $msg .= $error->getMessage();
+ }
+ }
+ $msg .= PHP_EOL . "Total time: " .self::formatTime(Phing::currentTimeMillis() - $this->startTime) . PHP_EOL;
+
+ if ($error === null) {
+ $this->printMessage($msg, $this->out, Project::MSG_VERBOSE);
+ } else {
+ $this->printMessage($msg, $this->err, Project::MSG_ERR);
+ }
+ }
+
+ /**
+ * Get the message to return when a build failed.
+ * @return string The classic "BUILD FAILED"
+ */
+ protected function getBuildFailedMessage() {
+ return "BUILD FAILED";
+ }
+
+ /**
+ * Get the message to return when a build succeeded.
+ * @return string The classic "BUILD FINISHED"
+ */
+ protected function getBuildSuccessfulMessage() {
+ return "BUILD FINISHED";
+ }
+
+ /**
+ * Prints the current target name
+ *
+ * @param object The BuildEvent
+ * @access public
+ * @see BuildEvent::getTarget()
+ */
+ public function targetStarted(BuildEvent $event) {
+ if (Project::MSG_INFO <= $this->msgOutputLevel) {
+ $showLongTargets = $event->getProject()->getProperty("phing.showlongtargets");
+ $msg = PHP_EOL . $event->getProject()->getName() . ' > ' . $event->getTarget()->getName() . ($showLongTargets ? ' [' . $event->getTarget()->getDescription() . ']' : '') . ':' . PHP_EOL;
+ $this->printMessage($msg, $this->out, $event->getPriority());
+ }
+ }
+
+ /**
+ * Fired when a target has finished. We don't need specific action on this
+ * event. So the methods are empty.
+ *
+ * @param object The BuildEvent
+ * @see BuildEvent::getException()
+ */
+ public 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()
+ */
+ public 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()
+ */
+ public function taskFinished(BuildEvent $event) {}
+
+ /**
+ * Print a message to the stdout.
+ *
+ * @param object The BuildEvent
+ * @access public
+ * @see BuildEvent::getMessage()
+ */
+ public function messageLogged(BuildEvent $event) {
+ $priority = $event->getPriority();
+ if ($priority <= $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();
+
+ if ($priority != Project::MSG_ERR) {
+ $this->printMessage($msg, $this->out, $priority);
+ } else {
+ $this->printMessage($msg, $this->err, $priority);
+ }
+ }
+ }
+
+ /**
+ * Formats a time micro integer to human readable format.
+ *
+ * @param integer The time stamp
+ * @access private
+ */
+ public static 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 resource $stream The stream to use for message printing.
+ * @param int $priority The priority of the message.
+ * (Ignored in this implementation.)
+ * @return void
+ */
+ protected function printMessage($message, OutputStream $stream, $priority) {
+ $stream->write($message . PHP_EOL);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/HtmlColorLogger.php b/buildscripts/phing/classes/phing/listener/HtmlColorLogger.php
new file mode 100755
index 00000000..6514f8d1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/HtmlColorLogger.php
@@ -0,0 +1,175 @@
+<?php
+/*
+ * $Id: 4b57f4d435b61b6501688394f1ff8534d4b7e93f $
+ *
+ * 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 CSS class that must be defined in the HTML page
+ * where the Phing output is displayed.
+ *
+ * If used with the -logfile option, the output
+ * will contain the text wrapped in html <span> elements
+ * with those css classes.
+ *
+ * The default classes used for differentiating
+ * the message levels can be changed by editing the
+ * phing/listener/defaults.properties file.
+ *
+ * This file can contain 5 key/value pairs:
+ * HtmlColorLogger.ERROR_CLASS=_your_css_class_name_
+ * HtmlColorLogger.WARNING_CLASS=_your_css_class_name_
+ * HtmlColorLogger.INFO_CLASS=_your_css_class_name_
+ * HtmlColorLogger.VERBOSE_CLASS=_your_css_class_name_
+ * HtmlColorLogger.DEBUG_CLASS=_your_css_class_name_
+ *
+ * This stems from the Ansi Color Logger done by Hans Lellelid:
+ *
+ * @author Anton Stöckl <anton@stoeckl.de> (Phing HTML Color Logger)
+ * @author Hans Lellelid <hans@xmpl.org> (Phing Ansi Color Logger)
+ * @author Magesh Umasankar (Ant)
+ * @package phing.listener
+ * @version $Id: 4b57f4d435b61b6501688394f1ff8534d4b7e93f $
+ */
+class HtmlColorLogger extends DefaultLogger {
+
+ const CLASS_ERR = 'phing_err';
+ const CLASS_VERBOSE = 'phing_verbose';
+ const CLASS_DEBUG = 'phing_debug';
+ const CLASS_WARN = 'phing_warn';
+ const CLASS_INFO = 'phing_info';
+
+ const PREFIX = '<span class="';
+ const SUFFIX = '">';
+ const END_COLOR = '</span>';
+
+ private $errColor;
+ private $warnColor;
+ private $infoColor;
+ private $verboseColor;
+ private $debugColor;
+
+ private $colorsSet = false;
+
+ /**
+ * Construct new HtmlColorLogger
+ * Perform initializations that cannot be done in var declarations.
+ */
+ public function __construct() {
+ parent::__construct();
+ $this->errColor = self::PREFIX . self::CLASS_ERR . self::SUFFIX;
+ $this->warnColor = self::PREFIX . self::CLASS_WARN . self::SUFFIX;
+ $this->infoColor = self::PREFIX . self::CLASS_INFO . self::SUFFIX;
+ $this->verboseColor = self::PREFIX . self::CLASS_VERBOSE . self::SUFFIX;
+ $this->debugColor = self::PREFIX . self::CLASS_DEBUG . self::SUFFIX;
+ }
+
+ /**
+ * Set the colors to use from a property file specified in the
+ * special phing property file "phing/listener/defaults.properties".
+ */
+ private final function setColors() {
+
+ $systemColorFile = new PhingFile(Phing::getResourcePath("phing/listener/defaults.properties"));
+
+ try {
+ $prop = new Properties();
+
+ $prop->load($systemColorFile);
+
+ $err = $prop->getProperty("HtmlColorLogger.ERROR_CLASS");
+ $warn = $prop->getProperty("HtmlColorLogger.WARNING_CLASS");
+ $info = $prop->getProperty("HtmlColorLogger.INFO_CLASS");
+ $verbose = $prop->getProperty("HtmlColorLogger.VERBOSE_CLASS");
+ $debug = $prop->getProperty("HtmlColorLogger.DEBUG_CLASS");
+ if ($err !== null) {
+ $this->errColor = self::PREFIX . $err . self::SUFFIX;
+ }
+ if ($warn !== null) {
+ $this->warnColor = self::PREFIX . $warn . self::SUFFIX;
+ }
+ if ($info !== null) {
+ $this->infoColor = self::PREFIX . $info . self::SUFFIX;
+ }
+ if ($verbose !== null) {
+ $this->verboseColor = self::PREFIX . $verbose . self::SUFFIX;
+ }
+ if ($debug !== null) {
+ $this->debugColor = self::PREFIX . $debug . self::SUFFIX;
+ }
+ } catch (IOException $ioe) {
+ //Ignore exception - we will use the defaults.
+ }
+ }
+
+ /**
+ * @see DefaultLogger#printMessage
+ * @param string $message
+ * @param OutputStream $stream
+ * @param int $priority
+ */
+ protected final function printMessage($message, OutputStream $stream, $priority) {
+ if ($message !== null) {
+
+ if (!$this->colorsSet) {
+ $this->setColors();
+ $this->colorsSet = true;
+ }
+
+ $search = array('<', '>');
+ $replace = array('&lt;', '&gt;');
+ $message = str_replace($search, $replace, $message);
+
+ $search = array("\t", "\n", "\r");
+ $replace = array('&nbsp;&nbsp;&nbsp;', '<br>', '');
+ $message = str_replace($search, $replace, $message);
+
+ if (preg_match('@^( +)([^ ].+)@', $message, $matches)) {
+ $len = strlen($matches[1]);
+ $space = '&nbsp;';
+ for ($i = 1; $i < $len; $i++) {
+ $space .= '&nbsp;';
+ }
+ $message = $space . $matches[2];
+ }
+
+ 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;
+ }
+
+ $stream->write($message . '<br/>');
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/MailLogger.php b/buildscripts/phing/classes/phing/listener/MailLogger.php
new file mode 100755
index 00000000..344f3de4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/MailLogger.php
@@ -0,0 +1,105 @@
+<?php
+/*
+ * $Id: bea608bad3f8bd5733c7eac6451d15b1c937115c $
+ *
+ * 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 PEAR Mail package to send the build log to one or
+ * more recipients.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @package phing.listener
+ * @version $Id$
+ */
+class MailLogger extends DefaultLogger
+{
+ private $_mailMessage = "";
+
+ private $_from = "phing@phing.info";
+ private $_subject = "Phing build result";
+ private $_tolist = null;
+
+ /**
+ * Construct new MailLogger
+ */
+ public function __construct() {
+ parent::__construct();
+
+ @require_once 'Mail.php';
+
+ if (!class_exists('Mail')) {
+ throw new BuildException('Need the PEAR Mail package to send logs');
+ }
+
+ $from = Phing::getDefinedProperty('phing.log.mail.from');
+ $subject = Phing::getDefinedProperty('phing.log.mail.subject');
+ $tolist = Phing::getDefinedProperty('phing.log.mail.recipients');
+
+ if (!empty($from)) {
+ $this->_from = $from;
+ }
+
+ if (!empty($subject)) {
+ $this->_subject = $subject;
+ }
+
+ if (!empty($tolist)) {
+ $this->_tolist = $tolist;
+ }
+ }
+
+ /**
+ * @see DefaultLogger#printMessage
+ * @param string $message
+ * @param OutputStream $stream
+ * @param int $priority
+ */
+ protected final function printMessage($message, OutputStream $stream, $priority)
+ {
+ if ($message !== null) {
+ $this->_mailMessage .= $message . "\n";
+ }
+ }
+
+ /**
+ * Sends the mail
+ *
+ * @see DefaultLogger#buildFinished
+ * @param BuildEvent $event
+ */
+ public function buildFinished(BuildEvent $event)
+ {
+ parent::buildFinished($event);
+
+ if (empty($this->_tolist)) {
+ return;
+ }
+
+ $hdrs = array(
+ 'From' => $this->_from,
+ 'Subject' => $this->_subject . (empty($event) ? " (build succesful)" : " (build failed)")
+ );
+
+ $mail = Mail::factory('mail');
+ $mail->send($this->_tolist, $hdrs, $this->_mailMessage);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/NoBannerLogger.php b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php
new file mode 100755
index 00000000..887f6678
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php
@@ -0,0 +1,59 @@
+<?php
+/*
+ * $Id: d74783e6edb73c6f11fbb93701f0bb6e7ccf06b1 $
+ *
+ * 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';
+
+/**
+ * Extends DefaultLogger to strip out empty targets.
+ *
+ * @author Andreas Aderhold <andi@binarycloud.com>
+ * @copyright 2001,2002 THYRELL. All rights reserved
+ * @version $Id$
+ * @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) {
+ $msg = PHP_EOL . $event->getProject()->getName() . ' > ' . $this->targetName . ':' . PHP_EOL;
+ $this->printMessage($msg, $this->out, $event->getPriority());
+ $this->targetName = null;
+ }
+
+ parent::messageLogged($event);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/PearLogListener.php b/buildscripts/phing/classes/phing/listener/PearLogListener.php
new file mode 100755
index 00000000..76efdbbb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/PearLogListener.php
@@ -0,0 +1,197 @@
+<?php
+/*
+ * $Id: d2d1a761c30c120a07e419622bcbcb9b5e067c24 $
+ *
+ * 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';
+
+/**
+ * Writes build 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 $Id$
+ * @see BuildEvent
+ * @package phing.listener
+ */
+class PearLogListener implements BuildListener {
+
+ /**
+ * Size of the left column in output. The default char width is 12.
+ * @var int
+ */
+ const LEFT_COLUMN_SIZE = 12;
+
+ /**
+ * 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;
+
+ /**
+ * @var Log PEAR Log object.
+ */
+ protected $logger;
+
+ /**
+ * 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();
+
+ include_once 'Log.php';
+ if (!class_exists('Log')) {
+ throw new BuildException("Cannot find PEAR Log class for use by PearLogger.");
+ }
+
+ $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;
+ }
+
+ /**
+ * Sets the start-time when the build started. Used for calculating
+ * the build-time.
+ *
+ * @param BuildEvent The BuildEvent
+ */
+ 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"));
+ }
+
+ /**
+ * Logs whether the build succeeded or failed, and any errors that
+ * occured during the build. Also outputs the total build-time.
+ *
+ * @param BuildEvent The BuildEvent
+ * @see BuildEvent::getException()
+ */
+ public 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: " . DefaultLogger::formatTime(Phing::currentTimeMillis() - $this->startTime));
+ }
+
+ /**
+ * Logs the current target name
+ *
+ * @param BuildEvent The BuildEvent
+ * @see BuildEvent::getTarget()
+ */
+ public 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 BuildEvent The BuildEvent
+ * @access public
+ * @see BuildEvent::getException()
+ */
+ public 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 BuildEvent The BuildEvent
+ * @access public
+ * @see BuildEvent::getTask()
+ */
+ public 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 BuildEvent The BuildEvent
+ * @see BuildEvent::getException()
+ */
+ public function taskFinished(BuildEvent $event) {}
+
+ /**
+ * Logs a message to the configured PEAR logger.
+ *
+ * @param BuildEvent The BuildEvent
+ * @see BuildEvent::getMessage()
+ */
+ public 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()]);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/listener/StreamRequiredBuildLogger.php b/buildscripts/phing/classes/phing/listener/StreamRequiredBuildLogger.php
new file mode 100755
index 00000000..c463a59d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/StreamRequiredBuildLogger.php
@@ -0,0 +1,39 @@
+<?php
+/*
+ * $Id: e0daef8de8e5be892b2eaaa7a42fa5d04ad540b5 $
+ *
+ * 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/BuildLogger.php';
+
+/**
+ * Interface for build loggers that require that out/err streams be set in order to function.
+ *
+ * This is just an empty sub-interface to BuildLogger, but is used by Phing to throw
+ * graceful errors when classes like phing.listener.DefaultLogger are being used as
+ * -listener.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Id$
+ * @see BuildEvent
+ * @see Project::addBuildListener()
+ * @package phing
+ */
+interface StreamRequiredBuildLogger extends BuildLogger {
+
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/listener/XmlLogger.php b/buildscripts/phing/classes/phing/listener/XmlLogger.php
new file mode 100755
index 00000000..25ff0ba2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/listener/XmlLogger.php
@@ -0,0 +1,354 @@
+<?php
+/**
+ * $Id: aaf7d77e9952319b9598d786c556be005d34c188 $
+ *
+ * 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/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 <mrook@php.net>
+ * @version $Id: aaf7d77e9952319b9598d786c556be005d34c188 $
+ * @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";
+
+ /**
+ * @var DOMDocument The XML document created by this logger.
+ */
+ private $doc;
+
+ /**
+ * @var int Start time for entire build.
+ */
+ private $buildTimerStart = 0;
+
+ /**
+ * @var DOMElement Top-level (root) build element
+ */
+ private $buildElement;
+
+ /**
+ * @var array DOMElement[] The parent of the element being processed.
+ */
+ private $elementStack = array();
+
+ /**
+ * @var array int[] Array of millisecond times for the various elements being processed.
+ */
+ private $timesStack = array();
+
+ /**
+ * @var int
+ */
+ private $msgOutputLevel = Project::MSG_DEBUG;
+
+ /**
+ * @var OutputStream Stream to use for standard output.
+ */
+ private $out;
+
+ /**
+ * @var OutputStream Stream to use for error output.
+ */
+ private $err;
+
+ /**
+ * @var string Name of filename to create.
+ */
+ private $outFilename;
+
+ /**
+ * Constructs a new BuildListener that logs build events to an XML file.
+ */
+ public function __construct() {
+ $this->doc = new DOMDocument("1.0", "UTF-8");
+ $this->doc->formatOutput = true;
+ }
+
+ /**
+ * 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);
+ array_push($this->elementStack, $this->buildElement);
+ array_push($this->timesStack, $this->buildTimerStart);
+ }
+
+ /**
+ * 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 $event An event with any relevant extra information.
+ * Will not be <code>null</code>.
+ */
+ public function buildFinished(BuildEvent $event) {
+
+ $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()->getMessage());
+ $errText = $this->doc->createCDATASection($event->getException()->getTraceAsString());
+ $stacktrace = $this->doc->createElement(XmlLogger::STACKTRACE_TAG);
+ $stacktrace->appendChild($errText);
+ $this->buildElement->appendChild($stacktrace);
+ }
+
+ $this->doc->appendChild($this->buildElement);
+
+ $outFilename = $event->getProject()->getProperty("XmlLogger.file");
+ if ($outFilename == null) {
+ $outFilename = "log.xml";
+ }
+
+ try {
+ $stream = $this->out;
+ if ($stream === null) {
+ $stream = new FileOutputStream($outFilename);
+ }
+
+ // Yes, we could just stream->write() but this will eventually be the better
+ // way to do this (when we need to worry about charset conversions.
+ $writer = new OutputStreamWriter($stream);
+ $writer->write($this->doc->saveXML());
+ $writer->close();
+ } catch (IOException $exc) {
+ try {
+ $stream->close(); // in case there is a stream open still ...
+ } catch (Exception $x) {}
+ throw new BuildException("Unable to write log file.", $exc);
+ }
+
+ // cleanup:remove the buildElement
+ $this->buildElement = null;
+
+ array_pop($this->elementStack);
+ array_pop($this->timesStack);
+ }
+
+
+ /**
+ * Fired when a target starts building, remembers the current time and the name of the target.
+ *
+ * @param BuildEvent $event An event with any relevant extra information.
+ * Will not be <code>null</code>.
+ */
+ public function targetStarted(BuildEvent $event) {
+ $target = $event->getTarget();
+
+ $targetElement = $this->doc->createElement(XmlLogger::TARGET_TAG);
+ $targetElement->setAttribute(XmlLogger::NAME_ATTR, $target->getName());
+
+ array_push($this->timesStack, Phing::currentTimeMillis());
+ array_push($this->elementStack, $targetElement);
+ }
+
+ /**
+ * Fired when a target finishes building, this adds the time taken
+ * to the appropriate target element in the log.
+ *
+ * @param BuildEvent $event An event with any relevant extra information.
+ * Will not be <code>null</code>.
+ */
+ public function targetFinished(BuildEvent $event) {
+ $targetTimerStart = array_pop($this->timesStack);
+ $targetElement = array_pop($this->elementStack);
+
+ $elapsedTime = Phing::currentTimeMillis() - $targetTimerStart;
+ $targetElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::formatTime($elapsedTime));
+
+ $parentElement = $this->elementStack[ count($this->elementStack) - 1 ];
+ $parentElement->appendChild($targetElement);
+ }
+
+ /**
+ * Fired when a task starts building, remembers the current time and the name of the task.
+ *
+ * @param BuildEvent $event An event with any relevant extra information.
+ * Will not be <code>null</code>.
+ */
+ public function taskStarted(BuildEvent $event) {
+ $task = $event->getTask();
+
+ $taskElement = $this->doc->createElement(XmlLogger::TASK_TAG);
+ $taskElement->setAttribute(XmlLogger::NAME_ATTR, $task->getTaskName());
+ $taskElement->setAttribute(XmlLogger::LOCATION_ATTR, $task->getLocation()->toString());
+
+ array_push($this->timesStack, Phing::currentTimeMillis());
+ array_push($this->elementStack, $taskElement);
+ }
+
+ /**
+ * Fired when a task finishes building, this adds the time taken
+ * to the appropriate task element in the log.
+ *
+ * @param BuildEvent $event An event with any relevant extra information.
+ * Will not be <code>null</code>.
+ */
+ public function taskFinished(BuildEvent $event) {
+ $taskTimerStart = array_pop($this->timesStack);
+ $taskElement = array_pop($this->elementStack);
+
+ $elapsedTime = Phing::currentTimeMillis() - $taskTimerStart;
+ $taskElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::formatTime($elapsedTime));
+
+ $parentElement = $this->elementStack[ count($this->elementStack) - 1 ];
+ $parentElement->appendChild($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>.
+ */
+ public 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);
+
+ if (function_exists('mb_convert_encoding'))
+ {
+ $messageConverted = mb_convert_encoding($event->getMessage(), 'UTF-8');
+ }
+ else
+ {
+ $messageConverted = utf8_encode($event->getMessage());
+ }
+
+ $messageText = $this->doc->createCDATASection($messageConverted);
+
+ $messageElement->appendChild($messageText);
+
+ if (!empty($this->elementStack)) {
+ $this->elementStack[count($this->elementStack)-1]->appendChild($messageElement);
+ }
+ }
+
+ /**
+ * 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 int $level The logging level for the logger.
+ * @see BuildLogger#setMessageOutputLevel()
+ */
+ public function setMessageOutputLevel($level) {
+ $this->msgOutputLevel = (int) $level;
+ }
+
+ /**
+ * Sets the output stream.
+ * @param OutputStream $output
+ * @see BuildLogger#setOutputStream()
+ */
+ public function setOutputStream(OutputStream $output) {
+ $this->out = $output;
+ }
+
+ /**
+ * Sets the error stream.
+ * @param OutputStream $err
+ * @see BuildLogger#setErrorStream()
+ */
+ public function setErrorStream(OutputStream $err) {
+ $this->err = $err;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/listener/defaults.properties b/buildscripts/phing/classes/phing/listener/defaults.properties
new file mode 100644
index 00000000..4a4dec68
--- /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=01;31
+AnsiColorLogger.WARNING_COLOR=01;35
+AnsiColorLogger.INFO_COLOR=00;36
+AnsiColorLogger.VERBOSE_COLOR=00;32
+AnsiColorLogger.DEBUG_COLOR=01;34
diff --git a/buildscripts/phing/classes/phing/mappers/FileNameMapper.php b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php
new file mode 100755
index 00000000..f4306b4c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php
@@ -0,0 +1,59 @@
+<?php
+/*
+ * $Id: 24c9367363b11f9ab97509532739bf2353023034 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..55ed4113
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php
@@ -0,0 +1,55 @@
+<?php
+/*
+ * $Id: c18f079545fa2c53e9a129ec1dcf32447b597c09 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..79df94d6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/GlobMapper.php
@@ -0,0 +1,113 @@
+<?php
+/*
+ * $Id: 464f98975210eee84faed74ef4a53c83d23aa079 $
+ *
+ * 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 $Id$
+ * @package phing.mappers
+ */
+class GlobMapper implements FileNameMapper {
+
+ /**
+ * Part of &quot;from&quot; pattern before the *.
+ */
+ private $fromPrefix = null;
+
+ /**
+ * Part of &quot;from&quot; pattern after the *.
+ */
+ private $fromPostfix = null;
+
+ /**
+ * Length of the prefix (&quot;from&quot; pattern).
+ */
+ private $prefixLength;
+
+ /**
+ * Length of the postfix (&quot;from&quot; pattern).
+ */
+ private $postfixLength;
+
+ /**
+ * Part of &quot;to&quot; pattern before the *.
+ */
+ private $toPrefix = null;
+
+ /**
+ * Part of &quot;to&quot; 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 &quot;to&quot; 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 100755
index 00000000..e608a71d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/IdentityMapper.php
@@ -0,0 +1,54 @@
+<?php
+/*
+ * $Id: aa11e8f44255c1b191df3230336c57664daf5f4f $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..dc60ab34
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/MergeMapper.php
@@ -0,0 +1,69 @@
+<?php
+/*
+ * $Id: 9f014a901932e99fd50820d3f3a78387929f06ee $
+ *
+ * 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 $Id$
+ * @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
+ * @return 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
+ * @return 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 100755
index 00000000..ca387241
--- /dev/null
+++ b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php
@@ -0,0 +1,97 @@
+<?php
+/*
+ * $Id: 96aee1ffd32ba919d42e1141129068006e709976 $
+ *
+ * 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 $Id$
+ * @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 &quot;from&quot; pattern. Required.
+ */
+ function setFrom($from) {
+ $this->reg->SetPattern($from);
+ }
+
+ /**
+ * Sets the &quot;to&quot; 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 100755
index 00000000..1837bbbf
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/AbstractHandler.php
@@ -0,0 +1,98 @@
+<?php
+
+/*
+ * $Id: 3d81ac2784333ce8108cf32818b8dfc335993507 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..449386e7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php
@@ -0,0 +1,116 @@
+<?php
+/*
+ * $Id: 948cef29e65fb684d99cbddc7c633183740a91a8 $
+ *
+ * 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 $Id$
+ * @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 functions and registered
+ * in the actual parser implementation.
+ * It gives control to the current active handler object by calling the
+ * <code>startElement()</code> method.
+ *
+ * @param object the php's internal parser handle
+ * @param string the open tag name
+ * @param array the tag's attributes if any
+ * @throws Exception - Exceptions may be thrown by the Handler
+ */
+ function startElement($parser, $name, $attribs) {
+ $this->handler->startElement($name, $attribs);
+ }
+
+ /**
+ * 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.
+ *
+ * @param object the php's internal parser handle
+ * @param string the closing tag name
+ * @throws Exception - Exceptions may be thrown by the Handler
+ */
+ function endElement($parser, $name) {
+ $this->handler->endElement($name);
+ }
+
+ /**
+ * 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.
+ *
+ * @param resource $parser php's internal parser handle.
+ * @param string $data the CDATA
+ * @throws Exception - Exceptions may be thrown by the Handler
+ */
+ function characters($parser, $data) {
+ $this->handler->characters($data);
+ }
+
+ /**
+ * 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 100755
index 00000000..7531baaf
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php
@@ -0,0 +1,144 @@
+<?php
+/*
+ * $Id: dbae47cfbf1ad4a3ac68909118f69175cf1d45f4 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..65461576
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/ExpatParseException.php
@@ -0,0 +1,31 @@
+<?php
+/*
+ * $Id: c384bde6ba2bb6902b1f943e35afd9f8b5d4efd8 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..ef5348e5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/ExpatParser.php
@@ -0,0 +1,140 @@
+<?php
+/*
+ * $Id: 0363c59b524447dc74014b03d913fa5a25ada33a $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..4110bd00
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/Location.php
@@ -0,0 +1,76 @@
+<?php
+/*
+ * $Id: ffb9bc98eef0f4e535f60388d52b7495c539f682 $
+ *
+ * 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 $Id$
+ * @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;
+ }
+
+ function __toString () {
+ return $this->toString();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/parser/NestedElementHandler.php b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php
new file mode 100755
index 00000000..15d0e173
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php
@@ -0,0 +1,186 @@
+<?php
+/*
+ * $Id: 94cdf9380aea8a52cb09663489c2d2c5e28740aa $
+ *
+ * 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 $Id$
+ * @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/PhingXMLContext.php b/buildscripts/phing/classes/phing/parser/PhingXMLContext.php
new file mode 100755
index 00000000..0e2dd0f4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/PhingXMLContext.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * $Id: bfc85569ff437f8ee382c9dee6fc8eb55ecb9839 $
+ *
+ * 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>.
+ */
+
+/**
+ * Track the current state of the Xml parse operation.
+ *
+ * @author Bryan Davis <bpd@keynetics.com>
+ * @version $Id$
+ * @access public
+ * @package phing.parser
+ */
+class PhingXMLContext {
+
+ /**
+ * Constructor
+ * @param $project the project to which this antxml context belongs to
+ */
+ public function __construct ($project) {
+ $this->project = $project;
+ }
+
+ /** The project to configure. */
+ private $project;
+
+ private $configurators = array();
+
+ public function startConfigure ($cfg) {
+ $this->configurators[] = $cfg;
+ }
+
+ public function endConfigure () {
+ array_pop($this->configurators);
+ }
+
+ public function getConfigurator () {
+ $l = count($this->configurators);
+ if (0 == $l) {
+ return null;
+ } else {
+ return $this->configurators[$l - 1];
+ }
+ }
+
+ /** Impoerted files */
+ private $importStack = array();
+
+ public function addImport ($file) {
+ $this->importStack[] = $file;
+ }
+
+ public function getImportStack () {
+ return $this->importStack;
+ }
+
+ /**
+ * find out the project to which this context belongs
+ * @return project
+ */
+ public function getProject() {
+ return $this->project;
+ }
+
+} //end PhingXMLContext
diff --git a/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php
new file mode 100755
index 00000000..90471336
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php
@@ -0,0 +1,387 @@
+<?php
+/*
+ * $Id: ae9b63bef4c1423d88bb36ddfc5196763828123e $
+ *
+ * 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';
+include_once 'phing/parser/PhingXMLContext.php';
+include_once 'phing/IntrospectionHelper.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 $Id: ae9b63bef4c1423d88bb36ddfc5196763828123e $
+ * @access public
+ * @package phing.parser
+ */
+class ProjectConfigurator {
+
+ public $project;
+ public $locator;
+
+ public $buildFile;
+ public $buildFileParent;
+
+ /** Targets in current file */
+ private $currentTargets;
+
+ /** Synthetic target that will be called at the end to the parse phase */
+ private $parseEndTarget;
+
+ /** Name of the current project */
+ private $currentProjectName;
+
+ private $isParsing = true;
+
+ /**
+ * Indicates whether the project tag attributes are to be ignored
+ * when processing a particular build file.
+ */
+ private $ignoreProjectTag = false;
+
+ /**
+ * 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());
+ $this->currentTargets = array();
+ $this->parseEndTarget = new Target();
+ }
+
+ /**
+ * find out the build file
+ * @return the build file to which the xml context belongs
+ */
+ public function getBuildFile() {
+ return $this->buildFile;
+ }
+
+ /**
+ * find out the parent build file of this build file
+ * @return the parent build file of this build file
+ */
+ public function getBuildFileParent() {
+ return $this->buildFileParent;
+ }
+
+ /**
+ * find out the current project name
+ * @return current project name
+ */
+ public function getCurrentProjectName() {
+ return $this->currentProjectName;
+ }
+
+ /**
+ * set the name of the current project
+ * @param name name of the current project
+ */
+ public function setCurrentProjectName($name) {
+ $this->currentProjectName = $name;
+ }
+
+ /**
+ * tells whether the project tag is being ignored
+ * @return whether the project tag is being ignored
+ */
+ public function isIgnoringProjectTag() {
+ return $this->ignoreProjectTag;
+ }
+
+ /**
+ * sets the flag to ignore the project tag
+ * @param flag to ignore the project tag
+ */
+ public function setIgnoreProjectTag($flag) {
+ $this->ignoreProjectTag = $flag;
+ }
+
+ public function &getCurrentTargets () {
+ return $this->currentTargets;
+ }
+
+ public function isParsing () {
+ return $this->isParsing;
+ }
+
+ /**
+ * 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 {
+ // get parse context
+ $ctx = $this->project->getReference("phing.parsing.context");
+ if (null == $ctx) {
+ // make a new context and register it with project
+ $ctx = new PhingXMLContext($this->project);
+ $this->project->addReference("phing.parsing.context", $ctx);
+ }
+
+ //record this parse with context
+ $ctx->addImport($this->buildFile);
+
+ if (count($ctx->getImportStack()) > 1) {
+ // this is an imported file
+ // modify project tag parse behavior
+ $this->setIgnoreProjectTag(true);
+ }
+ // push action onto global stack
+ $ctx->startConfigure($this);
+
+ $reader = new BufferedReader(new FileReader($this->buildFile));
+ $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();
+
+ // mark parse phase as completed
+ $this->isParsing = false;
+ // execute delayed tasks
+ $this->parseEndTarget->main();
+ // pop this action from the global stack
+ $ctx->endConfigure();
+ } catch (Exception $exc) {
+ throw new BuildException("Error reading project file", $exc);
+ }
+ }
+
+ /**
+ * Delay execution of a task until after the current parse phase has
+ * completed.
+ *
+ * @param Task $task Task to execute after parse
+ */
+ public function delayTaskUntilParseEnd ($task) {
+ $this->parseEndTarget->addTask($task);
+ }
+
+ /**
+ * 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
+ */
+ public static 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
+ */
+ public static 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
+ */
+ public static function storeChild($project, $parent, $child, $tag) {
+ $ih = IntrospectionHelper::getHelper(get_class($parent));
+ $ih->storeElement($project, $parent, $child, $tag);
+ }
+
+ // The following three 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;
+ private static $propReplaceLogLevel = Project::MSG_VERBOSE;
+
+ /**
+ * Replace ${} style constructions in the given value with the
+ * string value of the corresponding data types. This method is
+ * static.
+ *
+ * @param object $project the project that should be used for property look-ups
+ * @param string $value the string to be scanned for property references
+ * @param array $keys property keys
+ * @param integer $logLevel the level of generated log messages
+ * @return string the replaced string or <code>null</code> if the string
+ * itself was null
+ */
+ public static function replaceProperties(Project $project, $value, $keys, $logLevel = Project::MSG_VERBOSE) {
+
+ 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;
+ self::$propReplaceLogLevel = $logLevel;
+
+ // 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 = $value;
+ $iteration = 0;
+
+ // loop to recursively replace tokens
+ while (strpos($sb, '${') !== false)
+ {
+ $sb = preg_replace_callback('/\$\{([^\$}]+)\}/', array('ProjectConfigurator', 'replacePropertyCallback'), $sb);
+
+ // keep track of iterations so we can break out of otherwise infinite loops.
+ $iteration++;
+ if ($iteration == 5)
+ {
+ return $sb;
+ }
+ }
+
+ 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.', self::$propReplaceLogLevel);
+ return $matches[0];
+ } else {
+ self::$propReplaceProject->log('Property ${'.$propertyName.'} => ' . self::$propReplaceProperties[$propertyName], self::$propReplaceLogLevel);
+ }
+
+ $propertyValue = self::$propReplaceProperties[$propertyName];
+
+ if (is_bool($propertyValue)) {
+ if ($propertyValue === true) {
+ $propertyValue = "true";
+ } else {
+ $propertyValue = "false";
+ }
+ }
+
+ return $propertyValue;
+ }
+
+ /**
+ * 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
+ */
+ public 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 100755
index 00000000..a027c1e6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/ProjectHandler.php
@@ -0,0 +1,176 @@
+<?php
+/*
+ * $Id: 393b1f3d8758281af2fd0153ffc6151333457527 $
+ *
+ * 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 $Id: 393b1f3d8758281af2fd0153ffc6151333457527 $
+ * @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;
+ $desc = null;
+ $baseDir = null;
+ $ver = 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;
+ } elseif ($key === "description") {
+ $desc = $value;
+ } elseif ($key === "phingVersion") {
+ $ver = $value;
+ } else {
+ throw new ExpatParseException("Unexpected attribute '$key'");
+ }
+ }
+ // these things get done no matter what
+ if (null != $name) {
+ $canonicalName = self::canonicalName($name);
+ $this->configurator->setCurrentProjectName($canonicalName);
+ $project->setUserProperty("phing.file.{$canonicalName}",
+ (string) $this->configurator->getBuildFile());
+ }
+
+ if (!$this->configurator->isIgnoringProjectTag()) {
+ 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 ($desc !== null) {
+ $project->setDescription($desc);
+ }
+
+ if($ver !== null) {
+ $project->setPhingVersion($ver);
+ }
+
+ 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, new PhingFile(getcwd())));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ static function canonicalName ($name) {
+ return preg_replace('/\W/', '_', strtolower($name));
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/parser/RootHandler.php b/buildscripts/phing/classes/phing/parser/RootHandler.php
new file mode 100755
index 00000000..435aae40
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/RootHandler.php
@@ -0,0 +1,82 @@
+<?php
+/*
+ * $Id: 061d3ffe06257d551822050020d0e64689663334 $
+ *
+ * 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 $Id$
+ * @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 &lt;project&gt; element. The
+ * root filter handles this element if it occurs, creates ProjectHandler
+ * to handle any nested tags & attributes of the &lt;project&gt; 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 &gt;project&lt; 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 100755
index 00000000..a6c4d037
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/TargetHandler.php
@@ -0,0 +1,196 @@
+<?php
+/*
+ * $Id: f73d7c67a353cf16f048af3ba013d84ec726a926 $
+ *
+ * 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 $Id: f73d7c67a353cf16f048af3ba013d84ec726a926 $
+ * @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;
+ $isHidden = false;
+
+ 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==="hidden") {
+ $isHidden = ($value == 'true' || $value == '1') ? true : false;
+ } 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;
+
+ // check to see if this target is a dup within the same file
+ if (isset($this->configurator->getCurrentTargets[$name])) {
+ throw new BuildException("Duplicate target: $targetName",
+ $this->parser->getLocation());
+ }
+
+ $this->target = new Target();
+ $this->target->setName($name);
+ $this->target->setHidden($isHidden);
+ $this->target->setIf($ifCond);
+ $this->target->setUnless($unlessCond);
+ $this->target->setDescription($description);
+ // take care of dependencies
+ if (strlen($depends) > 0) {
+ $this->target->setDepends($depends);
+ }
+
+ $usedTarget = false;
+ // check to see if target with same name is already defined
+ $projectTargets = $project->getTargets();
+ if (isset($projectTargets[$name])) {
+ $project->log("Already defined in main or a previous import, " .
+ "ignore {$name}", Project::MSG_VERBOSE);
+ } else {
+ $project->addTarget($name, $this->target);
+ if ($id !== null && $id !== "") {
+ $project->addReference($id, $this->target);
+ }
+ $usedTarget = true;
+ }
+
+ if ($this->configurator->isIgnoringProjectTag() &&
+ $this->configurator->getCurrentProjectName() != null &&
+ strlen($this->configurator->getCurrentProjectName()) != 0) {
+ // In an impored file (and not completely
+ // ignoring the project tag)
+ $newName = $this->configurator->getCurrentProjectName() . "." . $name;
+ if ($usedTarget) {
+ // clone needs to make target->children a shared reference
+ $newTarget = clone $this->target;
+ } else {
+ $newTarget = $this->target;
+ }
+ $newTarget->setName($newName);
+ $ct = $this->configurator->getCurrentTargets();
+ $ct[$newName] = $newTarget;
+ $project->addTarget($newName, $newTarget);
+ }
+ }
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * Checks if this target has dependencies and/or nested tasks.
+ * If the target has neither, show a warning.
+ */
+ protected function finished()
+ {
+ if (!count($this->target->getDependencies()) && !count($this->target->getTasks())) {
+ $this->configurator->project->log("Warning: target '" . $this->target->getName() .
+ "' has no tasks or dependencies", Project::MSG_WARN);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/parser/TaskHandler.php b/buildscripts/phing/classes/phing/parser/TaskHandler.php
new file mode 100755
index 00000000..53e07a56
--- /dev/null
+++ b/buildscripts/phing/classes/phing/parser/TaskHandler.php
@@ -0,0 +1,234 @@
+<?php
+/*
+ * $Id: 3b31bb3e2c1ae122411833c67617e7cebf6967b8 $
+ *
+ * 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 $Id: 3b31bb3e2c1ae122411833c67617e7cebf6967b8 $
+ * @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 &lt;project&gt;
+ * 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($this->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);
+ /*
+ Commenting this out as per thread on Premature configurate of ReuntimeConfigurables
+ with Matthias Pigulla: http://phing.tigris.org/servlets/ReadMsg?list=dev&msgNo=251
+
+ 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 && $this->container === null) {
+ try {
+ $this->task->perform();
+ } 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 100755
index 00000000..a392f5be
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/BufferedReader.php
@@ -0,0 +1,168 @@
+<?php
+/*
+ * $Id: 98ea5952d7a41ce47ce95008e336f38758946aaa $
+ *
+ * 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 $Id$
+ * @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 a chunk of data.
+ * @param int $len Number of bytes to read. Default is to read configured buffer size number of bytes.
+ * @return mixed buffer or -1 if EOF.
+ */
+ function read($len = null) {
+
+ // if $len is specified, we'll use that; otherwise, use the configured buffer size.
+ if ($len === null) $len = $this->bufferSize;
+
+ if ( ($data = $this->in->read($len)) !== -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 forget 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 100755
index 00000000..88520ce9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php
@@ -0,0 +1,71 @@
+<?php
+/*
+ * $Id: 8a155d3b04ca1a938bc22f59aba8509e0910ad33 $
+ *
+ * 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 $Id$
+ * @package phing.system.io
+ */
+class BufferedWriter extends Writer {
+
+ /**
+ * The size of the buffer in kb.
+ */
+ private $bufferSize = 0;
+
+ /**
+ * @var Writer The Writer we are buffering output to.
+ */
+ private $out;
+
+ public function __construct(Writer $writer, $buffsize = 8192) {
+ $this->out = $writer;
+ $this->bufferSize = $buffsize;
+ }
+
+ public function write($buf, $off = null, $len = null) {
+ return $this->out->write($buf, $off, $len);
+ }
+
+ public function newLine() {
+ $this->write(PHP_EOL);
+ }
+
+ public function getResource() {
+ return $this->out->getResource();
+ }
+
+ public function flush() {
+ $this->out->flush();
+ }
+
+ /**
+ * Close attached stream.
+ */
+ public function close() {
+ return $this->out->close();
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/system/io/ConsoleReader.php b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php
new file mode 100755
index 00000000..048f1866
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php
@@ -0,0 +1,84 @@
+<?php
+/*
+ * $Id: 7abe7afba50cc541e695c323da811186549ba1d9 $
+ *
+ * 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 $Id$
+ * @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/FileInputStream.php b/buildscripts/phing/classes/phing/system/io/FileInputStream.php
new file mode 100644
index 00000000..64778860
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FileInputStream.php
@@ -0,0 +1,79 @@
+<?php
+/*
+ * $Id: 9ddd30a90f5a934a1294f912ae881a4523b74e18 $
+ *
+ * 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/InputStream.php';
+require_once 'phing/system/io/PhingFile.php';
+
+/**
+ * Input stream subclass for file streams.
+ *
+ * @package phing.system.io
+ */
+class FileInputStream extends InputStream {
+
+ /**
+ * The associated file.
+ * @var PhingFile
+ */
+ protected $file;
+
+ /**
+ * Construct a new FileInputStream.
+ *
+ * @param PhingFile|string $file Path to the file
+ * @param boolean $append Whether to append (ignored)
+ * @throws Exception - if invalid argument specified.
+ * @throws IOException - if unable to open file.
+ */
+ public function __construct($file, $append = 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.");
+ }
+
+ $stream = @fopen($this->file->getAbsolutePath(), "rb");
+ if ($stream === false) {
+ throw new IOException("Unable to open " . $this->file->__toString() . " for reading: " . $php_errormsg);
+ }
+
+ parent::__construct($stream);
+ }
+
+ /**
+ * Returns a string representation of the attached file.
+ * @return string
+ */
+ public function __toString() {
+ return $this->file->getPath();
+ }
+
+ /**
+ * Mark is supported by FileInputStream.
+ * @return boolean TRUE
+ */
+ public function markSupported() {
+ return true;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/system/io/FileOutputStream.php b/buildscripts/phing/classes/phing/system/io/FileOutputStream.php
new file mode 100644
index 00000000..35457d17
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FileOutputStream.php
@@ -0,0 +1,71 @@
+<?php
+/*
+ * $Id: 9c9b6bc291caf11baf9d5eeef38c50bf155b2099 $
+ *
+ * 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/OutputStream.php';
+require_once 'phing/system/io/PhingFile.php';
+
+/**
+ * Output stream subclass for file streams.
+ *
+ * @package phing.system.io
+ */
+class FileOutputStream extends OutputStream {
+
+ /**
+ * @var PhingFile The associated file.
+ */
+ protected $file;
+
+ /**
+ * Construct a new FileOutputStream.
+ * @param mixed $file
+ * @param boolean $append Whether to append bytes to end of file rather than beginning.
+ * @throws Exception - if invalid argument specified.
+ * @throws IOException - if unable to open file.
+ */
+ public function __construct($file, $append = 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.");
+ }
+ if ($append) {
+ $stream = @fopen($this->file->getAbsolutePath(), "ab");
+ } else {
+ $stream = @fopen($this->file->getAbsolutePath(), "wb");
+ }
+ if ($stream === false) {
+ throw new IOException("Unable to open " . $this->file->__toString() . " for writing: " . $php_errormsg);
+ }
+ parent::__construct($stream);
+ }
+
+ /**
+ * Returns a string representation of the attached file.
+ * @return string
+ */
+ public function __toString() {
+ return $this->file->getPath();
+ }
+}
+
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..43ebda69
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FileReader.php
@@ -0,0 +1,41 @@
+<?php
+/*
+ * $Id: e7142ab98e9562743781ba0cc4005e08fd62ae83 $
+ *
+ * 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/InputStreamReader.php';
+require_once 'phing/system/io/FileInputStream.php';
+
+/**
+ * Convenience class for reading files.
+ * @package phing.system.io
+ */
+class FileReader extends InputStreamReader {
+
+ /**
+ * Construct a new FileReader.
+ * @param mixed $file PhingFile or string pathname.
+ */
+ public function __construct($file) {
+ $in = new FileInputStream($file);
+ parent::__construct($in);
+ }
+
+}
+
diff --git a/buildscripts/phing/classes/phing/system/io/FileSystem.php b/buildscripts/phing/classes/phing/system/io/FileSystem.php
new file mode 100755
index 00000000..284be830
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FileSystem.php
@@ -0,0 +1,840 @@
+<?php
+
+/*
+ * $Id: 235081905c0eafcd98da2fec63404fa2ebee090a $
+ *
+ * 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 exceptions
+ * more precise errorhandling is done by the PhingFile class
+ *
+ * @author Charlie Killian <charlie@tizac.com>
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @version $Id$
+ * @package phing.system.io
+ */
+abstract class FileSystem {
+
+ /**
+ * @var int
+ */
+ const BA_EXISTS = 0x01;
+
+ /**
+ * @var int
+ */
+ const BA_REGULAR = 0x02;
+
+ /**
+ * @var int
+ */
+ const BA_DIRECTORY = 0x04;
+
+ /**
+ * @var int
+ */
+ const BA_HIDDEN = 0x08;
+
+ /**
+ * Instance for getFileSystem() method.
+ * @var FileSystem
+ */
+ private static $fs;
+
+ /**
+ * Static method to return the FileSystem singelton representing
+ * this platform's local filesystem driver.
+ *
+ * @return FileSystem
+ * @throws IOException
+ */
+ public static 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 IOException("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.
+ *
+ * @param string $strPath
+ */
+ abstract function normalize($strPath);
+
+ /**
+ * Compute the length of this pathname string's prefix. The pathname
+ * string must be in normal form.
+ *
+ * @param string $pathname
+ */
+ 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.
+ *
+ * @param string $parent
+ * @param string $child
+ */
+ abstract function resolve($parent, $child);
+
+ /**
+ * Resolve the given abstract pathname into absolute form. Invoked by the
+ * getAbsolutePath and getCanonicalPath methods in the PhingFile class.
+ *
+ * @param PhingFile $f
+ */
+ 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.
+ *
+ * @param string $path
+ */
+ abstract function fromURIPath($path);
+
+ /* -- Path operations -- */
+
+ /**
+ * Tell whether or not the given abstract pathname is absolute.
+ *
+ * @param PhingFile $f
+ */
+ abstract function isAbsolute(PhingFile $f);
+
+ /**
+ * canonicalize filename by checking on disk
+ * @param string $strPath
+ * @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.
+ *
+ * @param PhingFile $f
+ */
+ function getBooleanAttributes($f) {
+ throw new IOException("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.
+ *
+ * @param PhingFile $f
+ * @param boolean $write
+ */
+ 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);
+ }
+ }
+
+ /**
+ * Whether file can be deleted.
+ * @param PhingFile $f
+ * @return boolean
+ */
+ function canDelete(PhingFile $f)
+ {
+ clearstatcache();
+ $dir = dirname($f->getAbsolutePath());
+ return (bool) @is_writable($dir);
+ }
+
+ /**
+ * 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.
+ *
+ * @param PhingFile $f
+ * @return int
+ * @throws IOException
+ */
+ function getLastModifiedTime(PhingFile $f) {
+
+ if (!$f->exists()) {
+ return 0;
+ }
+
+ @clearstatcache();
+ $strPath = (string) $f->getPath();
+
+ if (@is_link($strPath)) {
+ $stats = @lstat($strPath);
+
+ if (!isset($stats['mtime'])) {
+ $mtime = false;
+ } else {
+ $mtime = $stats['mtime'];
+ }
+ } else {
+ $mtime = @filemtime($strPath);
+ }
+
+ if (false === $mtime) {
+ $msg = "FileSystem::getLastModifiedTime() FAILED. Can not get modified time of $strPath. $php_errormsg";
+ throw new IOException($msg);
+ }
+
+ 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.
+ *
+ * @param PhingFile $f
+ * @throws IOException
+ * @return int
+ */
+ 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 IOException($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 $strPathname Path of the file to be created.
+ * @throws IOException
+ * @return boolean
+ */
+ 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.
+ *
+ * @param PhingFile $f
+ * @param boolean $recursive
+ * @return void
+ */
+ function delete(PhingFile $f, $recursive = false) {
+ if ($f->isDirectory()) {
+ return $this->rmdir($f->getPath(), $recursive);
+ } 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.
+ *
+ * @param PhingFile $f
+ * @throws IOException
+ */
+ function deleteOnExit($f) {
+ throw new IOException("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>.
+ *
+ * @param PhingFile $f
+ */
+ 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.
+ *
+ * NOTE: umask() is reset to 0 while executing mkdir(), and restored afterwards
+ *
+ * @param PhingFile $f
+ * @param int $mode
+ * @return boolean
+ */
+ function createDirectory(&$f, $mode = 0755) {
+ $old_umask = umask(0);
+ $return = @mkdir($f->getAbsolutePath(), $mode);
+ umask($old_umask);
+ return $return;
+ }
+
+ /**
+ * 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 IOException 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 IOException($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.
+ *
+ * @param PhingFile $f
+ * @param int $time
+ * @return void
+ * @throws IOException
+ */
+ function setLastModifiedTime(PhingFile $f, $time) {
+ $path = $f->getPath();
+ $success = @touch($path, $time);
+ if (!$success) {
+ throw new IOException("Could not touch '" . $path . "' 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.
+ *
+ * @param PhingFile $f
+ * @throws IOException
+ */
+ function setReadOnly($f) {
+ throw new IOException("setReadonly() not implemented by local fs driver");
+ }
+
+ /* -- Filesystem interface -- */
+
+ /**
+ * List the available filesystem roots, return array of PhingFile objects
+ * @throws IOException
+ */
+ function listRoots() {
+ throw new IOException("listRoots() not implemented by local fs driver");
+ }
+
+ /* -- Basic infrastructure -- */
+
+ /**
+ * Compare two abstract pathnames lexicographically.
+ *
+ * @param PhingFile $f1
+ * @param PhingFile $f2
+ */
+ function compare(PhingFile $f1, PhingFile $f2) {
+ throw new IOException("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 IOException if file cannot be copied.
+ */
+ function copy(PhingFile $src, PhingFile $dest) {
+ global $php_errormsg;
+
+ // Recursively copy a directory
+ if($src->isDirectory()) {
+ return $this->copyr($src->getAbsolutePath(), $dest->getAbsolutePath());
+ }
+
+ $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 IOException($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.
+ }
+ }
+
+ /**
+ * Copy a file, or recursively copy a folder and its contents
+ *
+ * @author Aidan Lister <aidan@php.net>
+ * @version 1.0.1
+ * @link http://aidanlister.com/repos/v/function.copyr.php
+ * @param string $source Source path
+ * @param string $dest Destination path
+ * @return bool Returns TRUE on success, FALSE on failure
+ */
+ function copyr($source, $dest)
+ {
+ // Check for symlinks
+ if (is_link($source)) {
+ return symlink(readlink($source), $dest);
+ }
+
+ // Simple copy for a file
+ if (is_file($source)) {
+ return copy($source, $dest);
+ }
+
+ // Make destination directory
+ if (!is_dir($dest)) {
+ mkdir($dest);
+ }
+
+ // Loop through the folder
+ $dir = dir($source);
+ while (false !== $entry = $dir->read()) {
+ // Skip pointers
+ if ($entry == '.' || $entry == '..') {
+ continue;
+ }
+
+ // Deep copy directories
+ $this->copyr("$source/$entry", "$dest/$entry");
+ }
+
+ // Clean up
+ $dir->close();
+ return true;
+ }
+
+ /**
+ * Change the ownership on a file or directory.
+ *
+ * @param string $pathname Path and name of file or directory.
+ * @param string $user The user name or number of the file or directory. See http://us.php.net/chown
+ *
+ * @return void
+ * @throws Exception if operation failed.
+ */
+ function chown($pathname, $user) {
+ if (false === @chown($pathname, $user)) {// FAILED.
+ $msg = "FileSystem::chown() FAILED. Cannot chown $pathname. User $user." . (isset($php_errormsg) ? ' ' . $php_errormsg : "");
+ throw new IOException($msg);
+ }
+ }
+
+ /**
+ * Change the group on a file or directory.
+ *
+ * @param string $pathname Path and name of file or directory.
+ * @param string $group The group of the file or directory. See http://us.php.net/chgrp
+ *
+ * @return void
+ * @throws IOException if operation failed.
+ */
+ function chgrp($pathname, $group) {
+ if (false === @chgrp($pathname, $group)) {// FAILED.
+ $msg = "FileSystem::chgrp() FAILED. Cannot chown $pathname. Group $group." . (isset($php_errormsg) ? ' ' . $php_errormsg : "");
+ throw new IOException($msg);
+ }
+ }
+
+ /**
+ * Change the permissions on a file or directory.
+ *
+ * @param string $pathname Path and name of file or directory.
+ * @param int $mode 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 IOException 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." . (isset($php_errormsg) ? ' ' . $php_errormsg : "");
+ throw new IOException($msg);
+ }
+ }
+
+ /**
+ * Locks a file and throws an Exception if this is not possible.
+ *
+ * @param PhingFile $f
+ * @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 IOException("Could not lock file '$filename'");
+ }
+ }
+
+ /**
+ * Unlocks a file and throws an IO Error if this is not possible.
+ *
+ * @param PhingFile $f
+ * @throws IOException
+ * @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 string $file Path and/or name of file to delete.
+ *
+ * @return void
+ * @throws IOException - 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 IOException($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 IOException($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..d58b0513
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FileWriter.php
@@ -0,0 +1,42 @@
+<?php
+/*
+ * $Id: 52ca0f8163c260b3f9f14cd83fa292292674a060 $
+ *
+ * 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/OutputStreamWriter.php';
+require_once 'phing/system/io/FileOutputStream.php';
+
+/**
+ * Convenience class for performing file write operations.
+ *
+ * @package phing.system.io
+ */
+class FileWriter extends OutputStreamWriter {
+
+ /**
+ * Construct a new FileWriter.
+ * @param mixed $file PhingFile or string pathname.
+ * @param boolean $append Append to existing file?
+ */
+ function __construct($file, $append = false) {
+ $out = new FileOutputStream($file, $append);
+ parent::__construct($out);
+ }
+}
+
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..527ce17f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/FilterReader.php
@@ -0,0 +1,68 @@
+<?php
+/*
+ * $Id: 70652dbec76165f9ab0311daffde790df58eaf8e $
+ *
+ * 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/Reader.php';
+
+/**
+ * Wrapper class for readers, which can be used to apply filters.
+ * @package phing.system.io
+ */
+class FilterReader extends Reader {
+
+ /**
+ * @var Reader
+ */
+ protected $in;
+
+ function __construct(Reader $in = null) {
+ $this->in = $in;
+ }
+
+ 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();
+ }
+
+ 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..8aa1465f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/IOException.php
@@ -0,0 +1,27 @@
+<?php
+/*
+ * $Id: 8a019e4034b2236c19058ea849b12fb88d3e2f43 $
+ *
+ * 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 {}
diff --git a/buildscripts/phing/classes/phing/system/io/InputStream.php b/buildscripts/phing/classes/phing/system/io/InputStream.php
new file mode 100644
index 00000000..f25fbe61
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/InputStream.php
@@ -0,0 +1,178 @@
+<?php
+/*
+ * $Id: 3ec0be3a0e0c81568513a11cbf4d4b453928a338 $
+ *
+ * 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 for PHP stream that supports read operations.
+ *
+ * @package phing.system.io
+ */
+class InputStream {
+
+ /**
+ * @var resource The attached PHP stream.
+ */
+ protected $stream;
+
+ /**
+ * @var int Position of stream cursor.
+ */
+ protected $currentPosition = 0;
+
+ /**
+ * @var int Marked position of stream cursor.
+ */
+ protected $mark = 0;
+
+ /**
+ * Construct a new InputStream.
+ * @param resource $stream Configured PHP stream for writing.
+ */
+ public function __construct($stream) {
+ if (!is_resource($stream)) {
+ throw new IOException("Passed argument is not a valid stream.");
+ }
+ $this->stream = $stream;
+ }
+
+ /**
+ * Skip over $n bytes.
+ * @param int $n
+ */
+ public function skip($n) {
+ $start = $this->currentPosition;
+
+ $ret = @fseek($this->stream, $n, SEEK_CUR);
+ if ( $ret === -1 )
+ return -1;
+
+ $this->currentPosition = ftell($this->stream);
+
+ if ( $start > $this->currentPosition )
+ $skipped = $start - $this->currentPosition;
+ else
+ $skipped = $this->currentPosition - $start;
+
+ return $skipped;
+ }
+
+ /**
+ * Read data from stream until $len chars or EOF.
+ * @param int $len Num chars to read. If not specified this stream will read until EOF.
+ * @return string chars read or -1 if eof.
+ */
+ public function read($len = null) {
+
+ if ($this->eof()) {
+ return -1;
+ }
+
+ if ($len === null) { // we want to keep reading until we get an eof
+ $out = "";
+ while(!$this->eof()) {
+ $out .= fread($this->stream, 8192);
+ $this->currentPosition = ftell($this->stream);
+ }
+ } else {
+ $out = fread($this->stream, $len); // adding 1 seems to ensure that next call to read() will return EOF (-1)
+ $this->currentPosition = ftell($this->stream);
+ }
+
+ return $out;
+ }
+
+ /**
+ * Marks the current position in this input stream.
+ * @throws IOException - if the underlying stream doesn't support this method.
+ */
+ public function mark() {
+ if (!$this->markSupported()) {
+ throw new IOException(get_class($this) . " does not support mark() and reset() methods.");
+ }
+ $this->mark = $this->currentPosition;
+ }
+
+ /**
+ * Whether the input stream supports mark and reset methods.
+ * @return boolean
+ */
+ public function markSupported() {
+ return false;
+ }
+
+ /**
+ * Repositions this stream to the position at the time the mark method was last called on this input stream.
+ * @throws IOException - if the underlying stream doesn't support this method.
+ */
+ function reset() {
+ if (!$this->markSupported()) {
+ throw new IOException(get_class($this) . " does not support mark() and reset() methods.");
+ }
+ // goes back to last mark, by default this would be 0 (i.e. rewind file).
+ fseek($this->stream, SEEK_SET, $this->mark);
+ $this->mark = 0;
+ }
+
+ /**
+ * Closes stream.
+ * @throws IOException if stream cannot be closed (note that calling close() on an already-closed stream will not raise an exception)
+ */
+ public function close() {
+ if ($this->stream === null) {
+ return;
+ }
+ if (false === @fclose($this->stream)) {
+ // FAILED.
+ $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg";
+ throw new IOException($msg);
+ }
+ $this->stream = null;
+ }
+
+ /**
+ * Whether eof has been reached with stream.
+ * @return boolean
+ */
+ public function eof() {
+ return feof($this->stream);
+ }
+
+ /**
+ * Reads a entire until EOF and places contents in passed-in variable. Stream is closed after read.
+ *
+ * @param string &$rBuffer String variable where read contents will be put.
+ * @return TRUE on success.
+ * @author Charlie Killian, charlie@tizac.com
+ * @throws IOException - if there is an error reading from stream.
+ * @deprecated - Instead, use the read() method or a BufferedReader.
+ */
+ public function readInto(&$rBuffer) {
+ $rBuffer = $this->read();
+ $this->close();
+ }
+
+ /**
+ * Returns string representation of attached stream.
+ * @return string
+ */
+ public function __toString() {
+ return (string) $this->stream;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/system/io/InputStreamReader.php b/buildscripts/phing/classes/phing/system/io/InputStreamReader.php
new file mode 100644
index 00000000..a21f9f05
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/InputStreamReader.php
@@ -0,0 +1,127 @@
+<?php
+/*
+ * $Id: 823f584f1834166724cd370f91fa1bd2c66b0e94 $
+ *
+ * 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';
+
+/**
+ * Writer class for OutputStream objects.
+ *
+ * Unlike the Java counterpart, this class does not (yet) handle
+ * character set transformations. This will be an important function
+ * of this class with move to supporting PHP6.
+ *
+ * @package phing.system.io
+ */
+class InputStreamReader extends Reader {
+
+ /**
+ * @var InputStream
+ */
+ protected $inStream;
+
+ /**
+ * Construct a new InputStreamReader.
+ * @param InputStream $$inStream InputStream to read from
+ */
+ public function __construct(InputStream $inStream) {
+ $this->inStream = $inStream;
+ }
+
+ /**
+ * Close the stream.
+ */
+ public function close() {
+ return $this->inStream->close();
+ }
+
+ /**
+ * Skip over $n bytes.
+ * @param int $n
+ */
+ public function skip($n) {
+ return $this->inStream->skip($n);
+ }
+
+ /**
+ * Read data from file.
+ * @param int $len Num chars to read.
+ * @return string chars read or -1 if eof.
+ */
+ public function read($len = null) {
+ return $this->inStream->read($len);
+ }
+
+ /**
+ * Marks the current position in this input stream.
+ * @throws IOException - if the underlying stream doesn't support this method.
+ */
+ public function mark() {
+ $this->inStream->mark();
+ }
+
+ /**
+ * Whether the attached stream supports mark/reset.
+ * @return boolean
+ */
+ public function markSupported() {
+ return $this->inStream->markSupported();
+ }
+
+ /**
+ * Repositions this stream to the position at the time the mark method was last called on this input stream.
+ * @throws IOException - if the underlying stream doesn't support this method.
+ */
+ public function reset() {
+ $this->inStream->reset();
+ }
+
+ /**
+ * Whether eof has been reached with stream.
+ * @return boolean
+ */
+ public function eof() {
+ return $this->inStream->eof();
+ }
+
+ /**
+ * 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
+ * @deprecated Use read() or BufferedReader instead.
+ */
+ public function readInto(&$rBuffer) {
+ return $this->inStream->readInto($rBuffer);
+ }
+
+ /**
+ * Returns string representation of attached stream.
+ * @return string
+ */
+ public function getResource() {
+ return $this->inStream->__toString();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/system/io/OutputStream.php b/buildscripts/phing/classes/phing/system/io/OutputStream.php
new file mode 100644
index 00000000..09e15c0e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/OutputStream.php
@@ -0,0 +1,108 @@
+<?php
+/*
+ * $Id: 3ef1bb9c45c0e679debf227c5e4699f88f692943 $
+ *
+ * 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 for PHP stream that supports write operations.
+ *
+ * @package phing.system.io
+ */
+class OutputStream {
+
+ /**
+ * @var resource The configured PHP stream.
+ */
+ protected $stream;
+
+ /**
+ * Construct a new OutputStream.
+ * @param resource $stream Configured PHP stream for writing.
+ */
+ public function __construct($stream) {
+ if (!is_resource($stream)) {
+ throw new IOException("Passed argument is not a valid stream.");
+ }
+ $this->stream = $stream;
+ }
+
+ /**
+ * Closes attached stream, flushing output first.
+ * @throws IOException if cannot close stream (note that attempting to close an already closed stream will not raise an IOException)
+ * @return void
+ */
+ public function close() {
+ if ($this->stream === null) {
+ return;
+ }
+ $this->flush();
+ if (false === @fclose($this->stream)) {
+ $msg = "Cannot close " . $this->getResource() . ": $php_errormsg";
+ throw new IOException($msg);
+ }
+ $this->stream = null;
+ }
+
+ /**
+ * Flushes stream.
+ *
+ * @throws IOException if unable to flush data (e.g. stream is not open).
+ */
+ public function flush() {
+ if (false === @fflush($this->stream)) {
+ throw new IOException("Could not flush stream: " . $php_errormsg);
+ }
+ }
+
+ /**
+ * Writes data to stream.
+ *
+ * @param string $buf Binary/character data to write.
+ * @param int $off (Optional) offset.
+ * @param int $len (Optional) number of bytes/chars to write.
+ * @return void
+ * @throws IOException - if there is an error writing to stream
+ */
+ public function write($buf, $off = null, $len = null) {
+ if ( $off === null && $len === null ) {
+ $to_write = $buf;
+ } elseif ($off !== null && $len === null) {
+ $to_write = substr($buf, $off);
+ } elseif ($off === null && $len !== null) {
+ $to_write = substr($buf, 0, $len);
+ } else {
+ $to_write = substr($buf, $off, $len);
+ }
+
+ $result = @fwrite($this->stream, $to_write);
+
+ if ( $result === false ) {
+ throw new IOException("Error writing to stream.");
+ }
+ }
+
+ /**
+ * Returns a string representation of the attached PHP stream.
+ * @return string
+ */
+ public function __toString() {
+ return (string) $this->stream;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/system/io/OutputStreamWriter.php b/buildscripts/phing/classes/phing/system/io/OutputStreamWriter.php
new file mode 100644
index 00000000..0b821e67
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/OutputStreamWriter.php
@@ -0,0 +1,84 @@
+<?php
+/*
+ * $Id: c1446fc1a19aef45f74766420ec89c2c37b32e01 $
+ *
+ * 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';
+require_once 'phing/system/io/Writer.php';
+
+/**
+ * Writer class for OutputStream objects.
+ *
+ * Unlike the Java counterpart, this class does not (yet) handle
+ * character set transformations. This will be an important function
+ * of this class with move to supporting PHP6.
+ *
+ * @package phing.system.io
+ */
+class OutputStreamWriter extends Writer {
+
+ /**
+ * @var OutputStream
+ */
+ protected $outStream;
+
+ /**
+ * Construct a new OutputStreamWriter.
+ * @param OutputStream $outStream OutputStream to write to
+ */
+ public function __construct(OutputStream $outStream) {
+ $this->outStream = $outStream;
+ }
+
+ /**
+ * Close the stream.
+ */
+ public function close() {
+ return $this->outStream->close();
+ }
+
+ /**
+ * Write char data to stream.
+ *
+ * @param unknown_type $buf
+ * @param unknown_type $off
+ * @param unknown_type $len
+ * @return unknown
+ */
+ public function write($buf, $off = null, $len = null) {
+ return $this->outStream->write($buf, $off, $len);
+ }
+
+ /**
+ * Flush output to the stream.
+ */
+ public function flush() {
+ $this->outStream->flush();
+ }
+
+ /**
+ * Gets a string representation of attached stream resource.
+ *
+ * @return string String representation of output stream
+ */
+ public function getResource() {
+ return $this->outStream->__toString();
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/system/io/PhingFile.php b/buildscripts/phing/classes/phing/system/io/PhingFile.php
new file mode 100755
index 00000000..871afedd
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/PhingFile.php
@@ -0,0 +1,996 @@
+<?php
+/*
+ * $Id: d2cfaf834a2cc605a3aedf37285f547010b8b4f4 $
+ *
+ * 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 $Id$
+ * @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.
+ * @var int
+ */
+ 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.
+ *
+ * @return int
+ */
+ function getPrefixLength() {
+ return (int) $this->prefixLength;
+ }
+
+ /* -- constructors not called by signature match, so we need some helpers --*/
+
+ /**
+ *
+ * Enter description here ...
+ * @param unknown_type $pathname
+ */
+ protected 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);
+ }
+
+ /**
+ *
+ * Enter description here ...
+ * @param unknown_type $parent
+ * @param unknown_type $child
+ */
+ protected 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);
+ }
+
+ /**
+ *
+ * Enter description here ...
+ * @param unknown_type $parent
+ * @param unknown_type $child
+ */
+ protected 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 string The string form of this abstract pathname
+ */
+ function getPath() {
+ return (string) $this->path;
+ }
+
+ /**
+ * Returns path without leading basedir.
+ *
+ * @param string $basedir Base directory to strip
+ *
+ * @return string Path without basedir
+ *
+ * @uses getPath()
+ */
+ function getPathWithoutBase($basedir)
+ {
+ if (!StringHelper::endsWith(self::$separator, $basedir)) {
+ $basedir .= self::$separator;
+ }
+ $path = $this->getPath();
+ if (!substr($path, 0, strlen($basedir)) == $basedir) {
+ //path does not begin with basedir, we don't modify it
+ return $path;
+ }
+ return substr($path, strlen($basedir));
+ }
+
+ /**
+ * 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 boolean 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 string 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 string 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 string 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 void A URL object representing the equivalent file URL
+ * @todo Not implemented yet
+ *
+ */
+ 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.
+ * @todo Not implemented yet
+ * @return void
+ */
+ 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);
+ */
+ }
+
+ /**
+ *
+ * Enter description here ...
+ * @param PhingFile|string $path
+ * @param boolean $isDirectory
+ * @return string
+ */
+ 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 boolean 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_link($this->getAbsolutePath()) || @is_readable($this->getAbsolutePath());
+ }
+ return false;
+ }
+
+ /**
+ * Tests whether the application can modify to the file denoted by this
+ * abstract pathname.
+ *
+ * @return boolean 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 boolean true if and only if the file denoted by this
+ * abstract pathname exists; false otherwise
+ */
+ function exists() {
+ clearstatcache();
+
+ if (is_link($this->path)) {
+ return true;
+ } else if ($this->isFile()) {
+ return @file_exists($this->path) || is_link($this->path);
+ } else {
+ return @is_dir($this->path);
+ }
+ }
+
+ /**
+ * Tests whether the file denoted by this abstract pathname is a
+ * directory.
+ *
+ * @return boolean true if and only if the file denoted by this
+ * abstract pathname exists and is a directory;
+ * false otherwise
+ */
+ function isDirectory() {
+ clearstatcache();
+ $fs = FileSystem::getFileSystem();
+ if ($fs->checkAccess($this) !== true) {
+ throw new IOException("No read access to ".$this->path);
+ }
+ return @is_dir($this->path) && !@is_link($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 boolean true if and only if the file denoted by this
+ * abstract pathname exists and is a normal file;
+ * false otherwise
+ */
+ function isFile() {
+ clearstatcache();
+ //$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 boolean 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);
+ }
+
+ /**
+ * Tests whether the file denoted by this abstract pathname is a symbolic link.
+ *
+ * @return boolean true if and only if the file denoted by this
+ * abstract pathname exists and is a symbolic link;
+ * false otherwise
+ */
+ public function isLink()
+ {
+ clearstatcache();
+ $fs = FileSystem::getFileSystem();
+ if ($fs->checkAccess($this) !== true) {
+ throw new IOException("No read access to ".$this->path);
+ }
+ return @is_link($this->path);
+ }
+
+ /**
+ * Returns the target of the symbolic link denoted by this abstract pathname
+ *
+ * @return string the target of the symbolic link denoted by this abstract pathname
+ */
+ public function getLinkTarget()
+ {
+ return @readlink($this->path);
+ }
+
+ /**
+ * Returns the time that the file denoted by this abstract pathname was
+ * last modified.
+ *
+ * @return int An 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 int 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 boolean 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 boolean true if and only if the file or directory is
+ * successfully deleted; false otherwise
+ */
+ function delete($recursive = false) {
+ $fs = FileSystem::getFileSystem();
+ if ($fs->canDelete($this) !== true) {
+ throw new IOException("Cannot delete " . $this->path . "\n");
+ }
+ return $fs->delete($this, $recursive);
+ }
+
+ /**
+ * 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.
+ *
+ * @param $filter string
+ * @return array 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);
+ }
+
+ /**
+ *
+ * Enter description here ...
+ * @param PhingFile[] $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 boolean true if and only if the directory was created,
+ * along with all necessary parent directories; false
+ * otherwise
+ * @throws IOException
+ */
+ function mkdirs($mode = 0755) {
+ if ($this->exists()) {
+ return false;
+ }
+ try {
+ if ($this->mkdir($mode)) {
+ return true;
+ }
+ } catch (IOException $ioe) {
+ // IOException from mkdir() means that directory propbably didn't exist.
+ }
+ $parentFile = $this->getParentFile();
+ return (($parentFile !== null) && ($parentFile->mkdirs($mode) && $this->mkdir($mode)));
+ }
+
+ /**
+ * Creates the directory named by this abstract pathname.
+ *
+ * @return boolean true if and only if the directory was created; false otherwise
+ * @throws IOException
+ */
+ function mkdir($mode = 0755) {
+ $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, $mode);
+ }
+
+ /**
+ * Renames the file denoted by this abstract pathname.
+ *
+ * @param PhingFile $destFile The new abstract pathname for the named file
+ * @return boolean 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 boolean 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 int $time The new last-modified time, measured in milliseconds since
+ * the epoch (00:00:00 GMT, January 1, 1970)
+ * @return boolean 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");
+ }
+
+ $fs = FileSystem::getFileSystem();
+ 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 boolean 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 owner of the file.
+ * @param mixed $user User name or number.
+ */
+ public function setUser($user) {
+ $fs = FileSystem::getFileSystem();
+ return $fs->chown($this->getPath(), $user);
+ }
+
+ /**
+ * Retrieve the owner of this file.
+ * @return int User ID of the owner of this file.
+ */
+ function getUser() {
+ return @fileowner($this->getPath());
+ }
+
+ /**
+ * Sets the group of the file.
+ * @param mixed $user User name or number.
+ */
+ public function setGroup($group) {
+ $fs = FileSystem::getFileSystem();
+ return $fs->chgrp($this->getPath(), $group);
+ }
+
+ /**
+ * Retrieve the group of this file.
+ * @return int User ID of the owner of this file.
+ */
+ function getGroup() {
+ return @filegroup($this->getPath());
+ }
+
+ /**
+ * 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 array 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.
+ * @return string
+ */
+ public static 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
+ * @return PhingFile
+ */
+ public static 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 - @see __toString()
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return $this->__toString();
+ }
+
+ /**
+ * Return string representation of the object
+ *
+ * @return string
+ */
+ public 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 100755
index 00000000..92159469
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/Reader.php
@@ -0,0 +1,91 @@
+<?php
+/*
+ * $Id: c6154b0ec9b7789f9e3f8b961e16e1b1ada091ed $
+ *
+ * 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 $Id$
+ * @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.
+ * @throws IOException if there is an error closing stream
+ */
+ abstract public function close();
+
+ /**
+ * 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() {
+ return false;
+ }
+
+ /**
+ * Is stream ready for reading.
+ * @return boolean
+ */
+ public function ready() {
+ return true;
+ }
+
+}
+
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..e8b493e9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/StringReader.php
@@ -0,0 +1,84 @@
+<?php
+/*
+ * $Id: 2fba6ccfe1849d1f94b1dd91daf51e64e05cace2 $
+ *
+ * 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 from string of characters.
+ * @package phing.system.io
+ */
+class StringReader extends Reader {
+
+ /**
+ * @var string
+ */
+ private $_string;
+
+ /**
+ * @var int
+ */
+ private $mark = 0;
+
+ /**
+ * @var int
+ */
+ 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/UnixFileSystem.php b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php
new file mode 100755
index 00000000..739ff6f6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php
@@ -0,0 +1,302 @@
+<?php
+/*
+ * $Id: ccfae0e7f76e6a02bfb20fc4b6f30eddf86d169f $
+ *
+ * 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 $Id$
+ * @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 (!strlen($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("IllegalArgumentType: Argument is not File");
+ }
+ }
+
+ /**
+ * compares file paths lexicographically
+ */
+ function compare(PhingFile $f1, PhingFile $f2) {
+ $f1Path = $f1->getPath();
+ $f2Path = $f2->getPath();
+ return strcmp((string) $f1Path, (string) $f2Path);
+ }
+
+ /**
+ * Copy a file, takes care of symbolic links
+ *
+ * @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;
+
+ if (!$src->isLink())
+ {
+ return parent::copy($src, $dest);
+ }
+
+ $srcPath = $src->getAbsolutePath();
+ $destPath = $dest->getAbsolutePath();
+
+ $linkTarget = $src->getLinkTarget();
+ if (false === @symlink($linkTarget, $destPath))
+ {
+ $msg = "FileSystem::copy() FAILED. Cannot create symlink from $destPath to $linkTarget.";
+ throw new Exception($msg);
+ }
+ }
+
+ /* -- 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;
+ }
+
+ /**
+ * Whether file can be deleted.
+ * @param PhingFile $f
+ * @return boolean
+ */
+ function canDelete(PhingFile $f)
+ {
+ @clearstatcache();
+ $dir = dirname($f->getAbsolutePath());
+ return (bool) @is_writable($dir);
+ }
+
+}
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..58331cde
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php
@@ -0,0 +1,477 @@
+<?php
+/*
+ * $Id: 0cb3f51d8745f08b64f6f394fc0abb84705f512e $
+ *
+ * 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..1eae49c4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php
@@ -0,0 +1,34 @@
+<?php
+/*
+ * $Id: de8f1d144dc3d34fa978937632a98625c3e5c15d $
+ *
+ * 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..86fa67e9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/io/Writer.php
@@ -0,0 +1,53 @@
+<?php
+/*
+ * $Id: 1dbdd04d4483e88c8e409811babeaa83c47f8418 $
+ *
+ * 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 {
+
+ /**
+ * Writes data to output stream.
+ * @param string $buf
+ * @param int $off
+ * @param int $len
+ */
+ abstract public function write($buf, $off = null, $len = null);
+
+ /**
+ * Close the stream.
+ * @throws IOException - if there is an error closing stream.
+ */
+ abstract public function close();
+
+ /**
+ * Flush the stream, if supported by the stream.
+ */
+ public function flush() {}
+
+ /**
+ * Returns a string representation of resource filename, url, etc. that is being written to.
+ * @return string
+ */
+ abstract public 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..60285df6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/lang/Character.php
@@ -0,0 +1,49 @@
+<?php
+/*
+ * $Id: afe71e9fbaaa9c49e543c338b5fdca1bc7c9d198 $
+ *
+ * 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
+
+ public static 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..489a82a8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/lang/EventObject.php
@@ -0,0 +1,52 @@
+<?php
+/*
+ * $Id: b844b1250c5bf730b5eeaccc01bdb24ebbb336e4 $
+ *
+ * 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..5da28838
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php
@@ -0,0 +1,26 @@
+<?php
+/*
+ * $Id: b5edc38a7438b81c032898ccf3c2be0e83d55203 $
+ *
+ * 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 {}
+
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..ccf080f5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php
@@ -0,0 +1,26 @@
+<?php
+/*
+ * $Id: b1e0bb7b6ed5dd7391d7c251e736bba1d14ce4b5 $
+ *
+ * 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 {}
+
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..74013bc0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/lang/SecurityException.php
@@ -0,0 +1,26 @@
+<?php
+/*
+ * $Id: 2df99e97af67f5f2cbe2ec930e8daddc8a10b406 $
+ *
+ * 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 {}
+
diff --git a/buildscripts/phing/classes/phing/system/util/Properties.php b/buildscripts/phing/classes/phing/system/util/Properties.php
new file mode 100755
index 00000000..4ffd04fc
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/util/Properties.php
@@ -0,0 +1,314 @@
+<?php
+
+/*
+ * $Id: 577374dcb65bb9a2614bc80f605ce49600d64778 $
+ *
+ * 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 $Id: 577374dcb65bb9a2614bc80f605ce49600d64778 $
+ */
+class Properties {
+
+ private $properties = array();
+
+ /**
+ * @var PhingFile
+ */
+ private $file = null;
+
+ /**
+ * Constructor
+ *
+ * @param array $properties
+ */
+ function __construct($properties = NULL)
+ {
+ if (is_array($properties)) {
+ foreach ($properties as $key => $value) {
+ $this->setProperty($key, $value);
+ }
+ }
+ }
+
+ /**
+ * 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);
+
+ $this->file = $file;
+ } 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) {
+ // strip comments and leading/trailing spaces
+ $line = trim(preg_replace("/\s+[;#]\s.+$/", "", $line));
+
+ if (empty($line) || $line[0] == ';' || $line[0] == '#') {
+ continue;
+ }
+
+ $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) . PHP_EOL;
+ }
+ 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 = null, $header = null) {
+ if ($file == null) {
+ $file = $this->file;
+ }
+
+ if ($file == null) {
+ throw new IOException("Unable to write to empty filename");
+ }
+
+ // 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);
+ if ($header !== null) {
+ $fw->write( "# " . $header . PHP_EOL );
+ }
+ $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 = null;
+ if (isset($this->properties[$key])) {
+ $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);
+ }
+
+ /**
+ * Appends a value to a property if it already exists with a delimiter
+ *
+ * If the property does not, it just adds it.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param string $delimiter
+ */
+ function append($key, $value, $delimiter = ',') {
+ $newValue = $value;
+ if (isset($this->properties[$key]) && !empty($this->properties[$key]) ) {
+ $newValue = $this->properties[$key] . $delimiter . $value;
+ }
+ $this->properties[$key] = $newValue;
+ }
+
+ /**
+ * 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 100755
index 00000000..56ab0e45
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/util/Register.php
@@ -0,0 +1,149 @@
+<?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 $Id$
+ * @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.
+ *
+ * @package phing.system.util
+ */
+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;
+ }
+
+ /**
+ * Recursively implodes an array to a comma-separated string
+ * @param array $arr
+ * @return string
+ */
+ private function implodeArray(array $arr) {
+ $values = array();
+
+ foreach ($arr as $value) {
+ if (is_array($value)) {
+ $values[] = $this->implodeArray($value);
+ } else {
+ $values[] = $value;
+ }
+ }
+
+ return "{" . implode(",", $values) . "}";
+ }
+
+ /**
+ * Returns the value at this slot as a string value.
+ * @return string
+ */
+ public function __toString()
+ {
+ if (is_array($this->value)) {
+ return $this->implodeArray($this->value);
+ } else {
+ return (string) $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 100755
index 00000000..2d2bcc01
--- /dev/null
+++ b/buildscripts/phing/classes/phing/system/util/Timer.php
@@ -0,0 +1,96 @@
+<?php
+/*
+ * $Id: 085b1a92f765375e97d2c09c7569ca5747a44634 $
+ *
+ * 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 $Id$
+ */
+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 100755
index 00000000..32a03295
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/defaults.properties
@@ -0,0 +1,145 @@
+; -------------------------------------
+; 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
+chown=phing.tasks.system.ChownTask
+concat=phing.tasks.system.AppendTask
+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.FailTask
+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
+import=phing.tasks.system.ImportTask
+loadfile=phing.tasks.system.LoadFileTask
+
+; "Core" contributed tasks
+; -- i.e. no taskdef needed.
+
+creole=phing.tasks.ext.creole.CreoleSQLExecTask
+pdo=phing.tasks.ext.pdo.PDOSQLExecTask
+pdosqlexec=phing.tasks.ext.pdo.PDOSQLExecTask
+package-as-path=phing.tasks.ext.PackageAsPathTask
+smarty=phing.tasks.ext.SmartyTask
+capsule=phing.tasks.ext.CapsuleTask
+tar=phing.tasks.ext.TarTask
+untar=phing.tasks.ext.UntarTask
+pearpkg=phing.tasks.ext.PearPackageTask
+pearpkg2=phing.tasks.ext.PearPackage2Task
+mail=phing.tasks.ext.MailTask
+zip=phing.tasks.ext.ZipTask
+unzip=phing.tasks.ext.UnzipTask
+waitfor=phing.tasks.system.WaitForTask
+trycatch=phing.tasks.system.TryCatchTask
+
+; "ext" tasks
+phpdoc=phing.tasks.ext.phpdoc.PhpDocumentorTask
+phpdocext=phing.tasks.ext.phpdoc.PhpDocumentorExternalTask
+svnlastrevision=phing.tasks.ext.svn.SvnLastRevisionTask
+svncheckout=phing.tasks.ext.svn.SvnCheckoutTask
+svnexport=phing.tasks.ext.svn.SvnExportTask
+svnupdate=phing.tasks.ext.svn.SvnUpdateTask
+svnswitch=phing.tasks.ext.svn.SvnSwitchTask
+svncopy=phing.tasks.ext.svn.SvnCopyTask
+svncommit=phing.tasks.ext.svn.SvnCommitTask
+svnlist=phing.tasks.ext.svn.SvnListTask
+svnlog=phing.tasks.ext.svn.SvnLogTask
+svninfo=phing.tasks.ext.svn.SvnInfoTask
+gitinit=phing.tasks.ext.git.GitInitTask
+gitclone=phing.tasks.ext.git.GitCloneTask
+gitgc=phing.tasks.ext.git.GitGcTask
+gitbranch=phing.tasks.ext.git.GitBranchTask
+gitfetch=phing.tasks.ext.git.GitFetchTask
+gitmerge=phing.tasks.ext.git.GitMergeTask
+gitcheckout=phing.tasks.ext.git.GitCheckoutTask
+gitpull=phing.tasks.ext.git.GitPullTask
+gitpush=phing.tasks.ext.git.GitPushTask
+gitlog=phing.tasks.ext.git.GitLogTask
+gittag=phing.tasks.ext.git.GitTagTask
+phpunit3=phing.tasks.ext.phpunit.PHPUnitTask
+phpunit3report=phing.tasks.ext.phpunit.PHPUnitReportTask
+phpunit=phing.tasks.ext.phpunit.PHPUnitTask
+phpunitreport=phing.tasks.ext.phpunit.PHPUnitReportTask
+coverage-setup=phing.tasks.ext.coverage.CoverageSetupTask
+coverage-merger=phing.tasks.ext.coverage.CoverageMergerTask
+coverage-report=phing.tasks.ext.coverage.CoverageReportTask
+coverage-threshold=phing.tasks.ext.coverage.CoverageThresholdTask
+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
+zendcodeanalyzer=phing.tasks.ext.ZendCodeAnalyzerTask
+jsllint=phing.tasks.ext.JslLintTask
+manifest=phing.tasks.ext.ManifestTask
+phpcodesniffer=phing.tasks.ext.PhpCodeSnifferTask
+phpcpd=phing.tasks.ext.phpcpd.PHPCPDTask
+phpmd=phing.tasks.ext.phpmd.PHPMDTask
+phpdepend=phing.tasks.ext.pdepend.PhpDependTask
+ftpdeploy=phing.tasks.ext.FtpDeployTask
+phkpackage=phing.tasks.ext.phk.PhkPackageTask
+pharpackage=phing.tasks.ext.phar.PharPackageTask
+scp=phing.tasks.ext.ScpTask
+; deprecate ScpSendTask
+scpsend=phing.tasks.ext.ScpTask
+ssh=phing.tasks.ext.SshTask
+replaceregexp=phing.tasks.ext.ReplaceRegexpTask
+jsmin=phing.tasks.ext.jsmin.JsMinTask
+version=phing.tasks.ext.VersionTask
+filehash=phing.tasks.ext.FileHashTask
+filesize=phing.tasks.ext.FileSizeTask
+xmlproperty=phing.tasks.ext.XmlPropertyTask
+exportproperties=phing.tasks.ext.ExportPropertiesTask
+http-request=phing.tasks.ext.HttpRequestTask
+httpget=phing.tasks.ext.HttpGetTask
+patch=phing.tasks.ext.PatchTask
+dbdeploy=phing.tasks.ext.dbdeploy.DbDeployTask
+symlink=phing.tasks.ext.SymlinkTask
+s3get=phing.tasks.ext.Service.Amazon.S3.S3GetTask
+s3put=phing.tasks.ext.Service.Amazon.S3.S3PutTask
+zendguardencode=phing.tasks.ext.zendguard.ZendGuardEncodeTask
+zendguardlicense=phing.tasks.ext.zendguard.ZendGuardLicenseTask
+docblox=phing.tasks.ext.docblox.DocBloxTask
+phpdoc2=phing.tasks.ext.phpdoc.PhpDocumentor2Task
+rST=phing.tasks.ext.rSTTask
+apigen=phing.tasks.ext.apigen.ApiGenTask
+parallel=phing.tasks.ext.ParallelTask
+symfonyconsole=phing.tasks.ext.SymfonyConsole.SymfonyConsoleTask
+; liquibase
+liquibase-changelog=phing.tasks.ext.liquibase.LiquibaseChangeLogTask
+liquibase-dbdoc=phing.tasks.ext.liquibase.LiquibaseDbDocTask
+liquibase-diff=phing.tasks.ext.liquibase.LiquibaseDiffTask
+liquibase-rollback=phing.tasks.ext.liquibase.LiquibaseRollbackTask
+liquibase-tag=phing.tasks.ext.liquibase.LiquibaseTagTask
+liquibase-update=phing.tasks.ext.liquibase.LiquibaseUpdateTask
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..13ccd73d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php
@@ -0,0 +1,480 @@
+<?php
+
+/*
+ * $Id: 205bc55fd1f7f36783d105ff2d0e27357282bbed $
+ *
+ * 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 $Id: 205bc55fd1f7f36783d105ff2d0e27357282bbed $
+ * @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($this->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.
+ *
+ * @package phing.tasks.ext
+ */
+class AssignedVar {
+
+ private $name;
+ private $value;
+
+ public function setName($v) {
+ $this->name = $v;
+ }
+
+ public function setValue($v) {
+ $this->value = $v;
+ }
+
+ public function getName() {
+ return $this->name;
+ }
+
+ public function getValue() {
+ return $this->value;
+ }
+
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ExportPropertiesTask.php b/buildscripts/phing/classes/phing/tasks/ext/ExportPropertiesTask.php
new file mode 100644
index 00000000..8bc64bbb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ExportPropertiesTask.php
@@ -0,0 +1,141 @@
+<?php
+
+/*
+ * $Id: 7d96a453b74edc40fdea85ba8befe6459334016d $
+ *
+ * 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";
+
+/**
+ * Saves currently defined properties into a specified file
+ *
+ * @author Andrei Serdeliuc
+ * @extends Task
+ * @version $Id: 7d96a453b74edc40fdea85ba8befe6459334016d $
+ * @package phing.tasks.ext
+ */
+class ExportPropertiesTask extends Task
+{
+ /**
+ * Array of project properties
+ *
+ * (default value: null)
+ *
+ * @var array
+ * @access private
+ */
+ private $_properties = null;
+
+ /**
+ * Target file for saved properties
+ *
+ * (default value: null)
+ *
+ * @var string
+ * @access private
+ */
+ private $_targetFile = null;
+
+ /**
+ * Exclude properties starting with these prefixes
+ *
+ * @var array
+ * @access private
+ */
+ private $_disallowedPropertyPrefixes = array(
+ 'host.',
+ 'phing.',
+ 'os.',
+ 'php.',
+ 'line.',
+ 'env.',
+ 'user.'
+ );
+
+ /**
+ * setter for _targetFile
+ *
+ * @access public
+ * @param string $file
+ * @return bool
+ */
+ public function setTargetFile($file)
+ {
+ if(!is_dir(dirname($file))) {
+ throw new BuildException("Parent directory of target file doesn't exist");
+ }
+
+ if(!is_writable(dirname($file)) && (file_exists($file) && !is_writable($file))) {
+ throw new BuildException("Target file isn't writable");
+ }
+
+ $this->_targetFile = $file;
+ return true;
+ }
+
+ /**
+ * setter for _disallowedPropertyPrefixes
+ *
+ * @access public
+ * @param string $file
+ * @return bool
+ */
+ public function setDisallowedPropertyPrefixes($prefixes)
+ {
+ $this->_disallowedPropertyPrefixes = explode(",", $prefixes);
+ return true;
+ }
+
+ public function main()
+ {
+ // Sets the currently declared properties
+ $this->_properties = $this->getProject()->getProperties();
+
+ if(is_array($this->_properties) && !empty($this->_properties) && null !== $this->_targetFile) {
+ $propertiesString = '';
+ foreach($this->_properties as $propertyName => $propertyValue) {
+ if(!$this->isDisallowedPropery($propertyName)) {
+ $propertiesString .= $propertyName . "=" . $propertyValue . PHP_EOL;
+ }
+ }
+
+ if(!file_put_contents($this->_targetFile, $propertiesString)) {
+ throw new BuildException('Failed writing to ' . $this->_targetFile);
+ }
+ }
+ }
+
+ /**
+ * Checks if a property name is disallowed
+ *
+ * @access protected
+ * @param string $propertyName
+ * @return bool
+ */
+ protected function isDisallowedPropery($propertyName)
+ {
+ foreach($this->_disallowedPropertyPrefixes as $property) {
+ if(substr($propertyName, 0, strlen($property)) == $property) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ExtractBaseTask.php b/buildscripts/phing/classes/phing/tasks/ext/ExtractBaseTask.php
new file mode 100644
index 00000000..e47acc24
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ExtractBaseTask.php
@@ -0,0 +1,199 @@
+<?php
+/*
+ *
+ * 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';
+
+/**
+ * Base class for extracting tasks such as Unzip and Untar.
+ *
+ * @author Joakim Bodin <joakim.bodin+phing@gmail.com>
+ * @version $Id: 8aa7996b72792da30f1ec94174f09b9c612bcc1a $
+ * @package phing.tasks.ext
+ * @since 2.2.0
+ */
+abstract class ExtractBaseTask extends MatchingTask {
+ /**
+ * @var PhingFile $file
+ */
+ protected $file;
+ /**
+ * @var PhingFile $todir
+ */
+ protected $todir;
+ protected $removepath;
+ protected $filesets = array(); // all fileset objects assigned to this task
+
+ /**
+ * Set to true to always extract (and possibly overwrite)
+ * all files from the archive
+ * @var boolean
+ */
+ protected $forceExtract = false;
+
+ /**
+ * Add a new fileset.
+ * @return FileSet
+ */
+ public function createFileSet() {
+ $this->fileset = new FileSet();
+ $this->filesets[] = $this->fileset;
+ return $this->fileset;
+ }
+
+ /**
+ * Set the name of the zip file to extract.
+ * @param PhingFile $file zip file to extract
+ */
+ public function setFile(PhingFile $file) {
+ $this->file = $file;
+ }
+
+ /**
+ * This is the base directory to look in for things to zip.
+ * @param PhingFile $baseDir
+ */
+ public function setToDir(PhingFile $todir) {
+ $this->todir = $todir;
+ }
+
+ public function setRemovePath($removepath)
+ {
+ $this->removepath = $removepath;
+ }
+
+ /**
+ * Sets the forceExtract attribute
+ * @param boolean $forceExtract
+ */
+ public function setForceExtract($forceExtract)
+ {
+ $this->forceExtract = (bool) $forceExtract;
+ }
+
+ /**
+ * do the work
+ * @throws BuildException
+ */
+ public function main() {
+
+ $this->validateAttributes();
+
+ $filesToExtract = array();
+ if ($this->file !== null) {
+ if(!$this->isDestinationUpToDate($this->file)) {
+ $filesToExtract[] = $this->file;
+ } else {
+ $this->log('Nothing to do: ' . $this->todir->getAbsolutePath() . ' is up to date for ' . $this->file->getCanonicalPath(), Project::MSG_INFO);
+ }
+ }
+
+ foreach($this->filesets as $compressedArchiveFileset) {
+ $compressedArchiveDirScanner = $compressedArchiveFileset->getDirectoryScanner($this->project);
+ $compressedArchiveFiles = $compressedArchiveDirScanner->getIncludedFiles();
+ $compressedArchiveDir = $compressedArchiveFileset->getDir($this->project);
+
+ foreach ($compressedArchiveFiles as $compressedArchiveFilePath) {
+ $compressedArchiveFile = new PhingFile($compressedArchiveDir, $compressedArchiveFilePath);
+ if($compressedArchiveFile->isDirectory())
+ {
+ throw new BuildException($compressedArchiveFile->getAbsolutePath() . ' compressed archive cannot be a directory.');
+ }
+
+ if ($this->forceExtract || !$this->isDestinationUpToDate($compressedArchiveFile)) {
+ $filesToExtract[] = $compressedArchiveFile;
+ } else {
+ $this->log('Nothing to do: ' . $this->todir->getAbsolutePath() . ' is up to date for ' . $compressedArchiveFile->getCanonicalPath(), Project::MSG_INFO);
+ }
+ }
+ }
+
+ foreach ($filesToExtract as $compressedArchiveFile) {
+ $this->extractArchive($compressedArchiveFile);
+ }
+ }
+
+ abstract protected function extractArchive(PhingFile $compressedArchiveFile);
+
+ /**
+ * @param array $files array of filenames
+ * @param PhingFile $dir
+ * @return boolean
+ */
+ protected function isDestinationUpToDate(PhingFile $compressedArchiveFile) {
+ if (!$compressedArchiveFile->exists()) {
+ throw new BuildException("Could not find file " . $compressedArchiveFile->__toString() . " to extract.");
+ }
+
+ $compressedArchiveContent = $this->listArchiveContent($compressedArchiveFile);
+ if(is_array($compressedArchiveContent)) {
+
+ $fileSystem = FileSystem::getFileSystem();
+ foreach ($compressedArchiveContent as $compressArchivePathInfo) {
+ $compressArchiveFilename = $compressArchivePathInfo['filename'];
+ if(!empty($this->removepath) && strlen($compressArchiveFilename) >= strlen($this->removepath))
+ {
+ $compressArchiveFilename = preg_replace('/^' . $this->removepath . '/','', $compressArchiveFilename);
+ }
+ $compressArchivePath = new PhingFile($this->todir, $compressArchiveFilename);
+
+ if(!$compressArchivePath->exists() ||
+ $fileSystem->compareMTimes($compressedArchiveFile->getCanonicalPath(), $compressArchivePath->getCanonicalPath()) == 1) {
+ return false;
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ abstract protected function listArchiveContent(PhingFile $compressedArchiveFile);
+
+ /**
+ * Validates attributes coming in from XML
+ *
+ * @access private
+ * @return void
+ * @throws BuildException
+ */
+ protected function validateAttributes() {
+
+ if ($this->file === null && count($this->filesets) === 0) {
+ throw new BuildException("Specify at least one source compressed archive - a file or a fileset.");
+ }
+
+ if ($this->todir === null) {
+ throw new BuildException("todir must be set.");
+ }
+
+ if ($this->todir !== null && $this->todir->exists() && !$this->todir->isDirectory()) {
+ throw new BuildException("todir must be a directory.");
+ }
+
+ if ($this->file !== null && $this->file->exists() && $this->file->isDirectory()) {
+ throw new BuildException("Compressed archive file cannot be a directory.");
+ }
+
+ if ($this->file !== null && !$this->file->exists()) {
+ throw new BuildException("Could not find compressed archive file " . $this->file->__toString() . " to extract.");
+ }
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/FileHashTask.php b/buildscripts/phing/classes/phing/tasks/ext/FileHashTask.php
new file mode 100644
index 00000000..5660e793
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/FileHashTask.php
@@ -0,0 +1,147 @@
+<?php
+/*
+ * $Id: c59aff266a03f0e2cf22dc33143f2decf2d5e05c $
+ *
+ * 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';
+
+/**
+ * fileHash
+ *
+ * Calculate either MD5 or SHA hash value of a specified file and retun the
+ * value in a property
+ *
+ * @author Johan Persson <johan162@gmail.com>
+ * @version $Id: c59aff266a03f0e2cf22dc33143f2decf2d5e05c $
+ * @package phing.tasks.ext
+ */
+class FileHashTask extends Task
+{
+ /**
+ * Property for File
+ * @var PhingFile file
+ */
+ private $file;
+
+ /**
+ * Property to be set
+ * @var string $property
+ */
+ private $propertyName = "filehashvalue";
+
+ /**
+ * Specify which hash algorithm to use.
+ * 0 = MD5
+ * 1 = SHA1
+ *
+ * @var integer $hashtype
+ */
+ private $hashtype=0;
+
+
+ /**
+ * Specify if MD5 or SHA1 hash should be used
+ * @param integer $type 0=MD5, 1=SHA1
+ */
+ public function setHashtype($type)
+ {
+ $this->hashtype = $type;
+ }
+
+ /**
+ * Which file to calculate the hash value of
+ * @param PhingFile $file
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Set the name of the property to store the hash value in
+ * @param $property
+ * @return void
+ */
+ public function setPropertyName($property)
+ {
+ $this->propertyName = $property;
+ }
+
+ /**
+ * Main-Method for the Task
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $this->checkFile();
+ $this->checkPropertyName();
+
+ // read file
+ if( (int)$this->hashtype === 0 ) {
+ $this->log("Calculating MD5 hash from: ".$this->file);
+ $hashValue = md5_file($this->file,false);
+ }
+ elseif( (int)$this->hashtype === 1 ) {
+ $this->log("Calculating SHA1 hash from: ".$this->file);
+ $hashValue = sha1_file($this->file,false);
+ }
+ else {
+ throw new BuildException(
+ sprintf('[FileHash] Unknown hashtype specified %d. Must be either 0 (=MD5) or 1 (=SHA1).',$this->hashtype));
+
+ }
+
+ // publish hash value
+ $this->project->setProperty($this->propertyName, $hashValue);
+
+ }
+
+ /**
+ * checks file attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkFile()
+ {
+ // check File
+ if ($this->file === null ||
+ strlen($this->file) == 0) {
+ throw new BuildException('[FileHash] You must specify an input file.', $this->file);
+ }
+
+ if( ! is_readable($this->file) ) {
+ throw new BuildException(sprintf('[FileHash] Input file does not exist or is not readable: %s',$this->file));
+ }
+
+ }
+
+ /**
+ * checks property attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkPropertyName()
+ {
+ if (is_null($this->propertyName) ||
+ strlen($this->propertyName) === 0) {
+ throw new BuildException('Property name for publishing hashvalue is not set');
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/FileSizeTask.php b/buildscripts/phing/classes/phing/tasks/ext/FileSizeTask.php
new file mode 100644
index 00000000..120197dd
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/FileSizeTask.php
@@ -0,0 +1,120 @@
+<?php
+/*
+ * $Id: 2a59c1a9b46f3fd71df0fd3b50908eff268fd630 $
+ *
+ * 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';
+
+/**
+ * fileHash
+ *
+ * Calculate either MD5 or SHA hash value of a specified file and retun the
+ * value in a property
+ *
+ * @author Johan Persson <johan162@gmail.com>
+ * @version $Id: 2a59c1a9b46f3fd71df0fd3b50908eff268fd630 $
+ * @package phing.tasks.ext
+ */
+class FileSizeTask extends Task
+{
+ /**
+ * Property for File
+ * @var PhingFile file
+ */
+ private $file;
+
+ /**
+ * Property where the file size will be stored
+ * @var string $property
+ */
+ private $propertyName = "filesize";
+
+ /**
+ * Which file to calculate the file size of
+ * @param PhingFile $file
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Set the name of the property to store the file size
+ * @param $property
+ * @return void
+ */
+ public function setPropertyName($property)
+ {
+ $this->propertyName = $property;
+ }
+
+ /**
+ * Main-Method for the Task
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $this->checkFile();
+ $this->checkPropertyName();
+
+ $size = filesize($this->file);
+
+ if( $size === false ) {
+ throw new BuildException(sprintf('[FileSize] Cannot determine size of file: %s',$this->file));
+
+ }
+
+ // publish hash value
+ $this->project->setProperty($this->propertyName, $size);
+
+ }
+
+ /**
+ * checks file attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkFile()
+ {
+ // check File
+ if ($this->file === null ||
+ strlen($this->file) == 0) {
+ throw new BuildException('[FileSize] You must specify an input file.', $this->file);
+ }
+
+ if( ! is_readable($this->file) ) {
+ throw new BuildException(sprintf('[FileSize] Input file does not exist or is not readable: %s',$this->file));
+ }
+
+ }
+
+ /**
+ * checks property attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkPropertyName()
+ {
+ if (is_null($this->propertyName) ||
+ strlen($this->propertyName) === 0) {
+ throw new BuildException('[FileSize] Property name for publishing file size is not set');
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/FtpDeployTask.php b/buildscripts/phing/classes/phing/tasks/ext/FtpDeployTask.php
new file mode 100644
index 00000000..136c0ac7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/FtpDeployTask.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * $Id: 87063ecf88b18eae74c2bca3918a1b4ac9f52807 $
+ *
+ * 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';
+
+/**
+ * FtpDeployTask
+ *
+ * Deploys a set of files to a remote FTP server.
+ *
+ *
+ * Example usage:
+ * <ftpdeploy host="host" port="21" username="user" password="password" dir="public_html" mode="ascii" clearfirst="true">
+ * <fileset dir=".">
+ * <include name="**"/>
+ * <exclude name="phing"/>
+ * <exclude name="build.xml"/>
+ * <exclude name="images/**.png"/>
+ * <exclude name="images/**.gif"/>
+ * <exclude name="images/**.jpg"/>
+ * </fileset>
+ * </ftpdeploy>
+ *
+ * @author Jorrit Schippers <jorrit at ncode dot nl>
+ * @version $Id: 87063ecf88b18eae74c2bca3918a1b4ac9f52807 $
+ * @since 2.3.1
+ * @package phing.tasks.ext
+ */
+class FtpDeployTask extends Task
+{
+ private $host = null;
+ private $port = 21;
+ private $username = null;
+ private $password = null;
+ private $dir = null;
+ private $filesets;
+ private $completeDirMap;
+ private $mode = FTP_BINARY;
+ private $clearFirst = false;
+ private $passive = false;
+
+ protected $logLevel = Project::MSG_VERBOSE;
+
+ public function __construct() {
+ $this->filesets = array();
+ $this->completeDirMap = array();
+ }
+
+ public function setHost($host) {
+ $this->host = $host;
+ }
+
+ public function setPort($port) {
+ $this->port = (int) $port;
+ }
+
+ public function setUsername($username) {
+ $this->username = $username;
+ }
+
+ public function setPassword($password) {
+ $this->password = $password;
+ }
+
+ public function setDir($dir) {
+ $this->dir = $dir;
+ }
+
+ public function setMode($mode) {
+ switch(strtolower($mode)) {
+ case 'ascii':
+ $this->mode = FTP_ASCII;
+ break;
+ case 'binary':
+ case 'bin':
+ $this->mode = FTP_BINARY;
+ break;
+ }
+ }
+
+ public function setPassive($passive)
+ {
+ $this->passive = (bool) $passive;
+ }
+
+ public function setClearFirst($clearFirst) {
+ $this->clearFirst = (bool) $clearFirst;
+ }
+
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Set level of log messages generated (default = info)
+ * @param string $level
+ */
+ public function setLevel($level)
+ {
+ switch ($level)
+ {
+ case "error": $this->logLevel = Project::MSG_ERR; break;
+ case "warning": $this->logLevel = Project::MSG_WARN; break;
+ case "info": $this->logLevel = Project::MSG_INFO; break;
+ case "verbose": $this->logLevel = Project::MSG_VERBOSE; break;
+ case "debug": $this->logLevel = Project::MSG_DEBUG; break;
+ }
+ }
+
+ /**
+ * The init method: check if Net_FTP is available
+ */
+ public function init() {
+ require_once 'PEAR.php';
+
+ $paths = explode(PATH_SEPARATOR, get_include_path());
+ foreach($paths as $path) {
+ if(file_exists($path.DIRECTORY_SEPARATOR.'Net'.DIRECTORY_SEPARATOR.'FTP.php')) {
+ return true;
+ }
+ }
+ throw new BuildException('The FTP Deploy task requires the Net_FTP PEAR package.');
+ }
+
+ /**
+ * The main entry point method.
+ */
+ public function main() {
+ $project = $this->getProject();
+
+ require_once 'Net/FTP.php';
+ $ftp = new Net_FTP($this->host, $this->port);
+ $ret = $ftp->connect();
+ if(@PEAR::isError($ret)) {
+ throw new BuildException('Could not connect to FTP server '.$this->host.' on port '.$this->port.': '.$ret->getMessage());
+ } else {
+ $this->log('Connected to FTP server ' . $this->host . ' on port ' . $this->port, $this->logLevel);
+ }
+
+ $ret = $ftp->login($this->username, $this->password);
+ if(@PEAR::isError($ret)) {
+ throw new BuildException('Could not login to FTP server '.$this->host.' on port '.$this->port.' with username '.$this->username.': '.$ret->getMessage());
+ } else {
+ $this->log('Logged in to FTP server with username ' . $this->username, $this->logLevel);
+ }
+
+ if ($this->passive) {
+ $this->log('Setting passive mode', $this->logLevel);
+ $ret = $ftp->setPassive();
+ if(@PEAR::isError($ret)) {
+ $ftp->disconnect();
+ throw new BuildException('Could not set PASSIVE mode: '.$ret->getMessage());
+ }
+ }
+
+ // append '/' to the end if necessary
+ $dir = substr($this->dir, -1) == '/' ? $this->dir : $this->dir.'/';
+
+ if($this->clearFirst) {
+ // TODO change to a loop through all files and directories within current directory
+ $this->log('Clearing directory '.$dir, $this->logLevel);
+ $ftp->rm($dir, true);
+ }
+
+ // Create directory just in case
+ $ret = $ftp->mkdir($dir, true);
+ if(@PEAR::isError($ret)) {
+ $ftp->disconnect();
+ throw new BuildException('Could not create directory '.$dir.': '.$ret->getMessage());
+ }
+
+ $ret = $ftp->cd($dir);
+ if(@PEAR::isError($ret)) {
+ $ftp->disconnect();
+ throw new BuildException('Could not change to directory '.$dir.': '.$ret->getMessage());
+ } else {
+ $this->log('Changed directory ' . $dir, $this->logLevel);
+ }
+
+ $fs = FileSystem::getFileSystem();
+ $convert = $fs->getSeparator() == '\\';
+
+ foreach($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($project);
+ $fromDir = $fs->getDir($project);
+ $srcFiles = $ds->getIncludedFiles();
+ $srcDirs = $ds->getIncludedDirectories();
+ foreach($srcDirs as $dirname) {
+ if($convert)
+ $dirname = str_replace('\\', '/', $dirname);
+ $this->log('Will create directory '.$dirname, $this->logLevel);
+ $ret = $ftp->mkdir($dirname, true);
+ if(@PEAR::isError($ret)) {
+ $ftp->disconnect();
+ throw new BuildException('Could not create directory '.$dirname.': '.$ret->getMessage());
+ }
+ }
+ foreach($srcFiles as $filename) {
+ $file = new PhingFile($fromDir->getAbsolutePath(), $filename);
+ if($convert)
+ $filename = str_replace('\\', '/', $filename);
+ $this->log('Will copy '.$file->getCanonicalPath().' to '.$filename, $this->logLevel);
+ $ret = $ftp->put($file->getCanonicalPath(), $filename, true, $this->mode);
+ if(@PEAR::isError($ret)) {
+ $ftp->disconnect();
+ throw new BuildException('Could not deploy file '.$filename.': '.$ret->getMessage());
+ }
+ }
+ }
+
+ $ftp->disconnect();
+ $this->log('Disconnected from FTP server', $this->logLevel);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/HttpGetTask.php b/buildscripts/phing/classes/phing/tasks/ext/HttpGetTask.php
new file mode 100755
index 00000000..114b80a1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/HttpGetTask.php
@@ -0,0 +1,170 @@
+<?php
+/*
+ * $Id: f3fa317b72e2f70f1e483fa49dbf089094e2a476 $
+ *
+ * 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';
+
+/**
+ * A HTTP request task.
+ * Making an HTTP request and try to match the response against an provided
+ * regular expression.
+ *
+ * @package phing.tasks.ext
+ * @author Ole Markus With <o.with@sportradar.com>
+ * @version $Id: f3fa317b72e2f70f1e483fa49dbf089094e2a476 $
+ */
+class HttpGetTask extends Task
+{
+ /**
+ * Holds the request URL
+ *
+ * @var string
+ */
+ protected $url = null;
+
+ /**
+ * Holds the filename to store the output in
+ *
+ * @var string
+ */
+ protected $filename = null;
+
+ /**
+ * Holds the save location
+ *
+ * @var string
+ */
+ protected $dir = null;
+
+ /**
+ * Holds the proxy
+ *
+ * @var string
+ */
+ protected $_proxy = null;
+
+ /**
+ * Load the necessary environment for running this task.
+ *
+ * @throws BuildException
+ */
+ public function init()
+ {
+ @include_once 'HTTP/Request2.php';
+
+ if (! class_exists('HTTP_Request2')) {
+ throw new BuildException(
+ 'HttpRequestTask depends on HTTP_Request2 being installed '
+ . 'and on include_path.',
+ $this->getLocation()
+ );
+ }
+ }
+
+
+ /**
+ * Make the GET request
+ *
+ * @throws BuildException
+ */
+ public function main()
+ {
+ if (!isset($this->url)) {
+ throw new BuildException("Missing attribute 'url'");
+ }
+
+ if (!isset($this->dir)) {
+ throw new BuildException("Missing attribute 'dir'");
+ }
+
+ $config = array();
+ if (isset($this->_proxy) && $url = parse_url($this->_proxy)) {
+ $config['proxy_user'] = $url['user'];
+ $config['proxy_password'] = $url['pass'];
+ $config['proxy_host'] = $url['host'];
+ $config['proxy_port'] = $url['port'];
+ }
+
+ $this->log("Fetching " . $this->url);
+
+ $request = new HTTP_Request2($this->url, '', $config);
+ $response = $request->send();
+ if ($response->getStatus() != 200) {
+ throw new BuildException("Request unsuccessful. Response from server: " . $response->getStatus() . " " . $response->getReasonPhrase());
+ }
+
+ $content = $response->getBody();
+ $disposition = $response->getHeader('content-disposition');
+
+ if ($this->filename) {
+ $filename = $this->filename;
+ } elseif ($disposition && 0 == strpos($disposition, 'attachment')
+ && preg_match('/filename="([^"]+)"/', $disposition, $m)) {
+ $filename = basename($m[1]);
+ } else {
+ $filename = basename(parse_url($this->url, PHP_URL_PATH));
+ }
+
+ if (!is_writable($this->dir)) {
+ throw new BuildException("Cannot write to directory: " . $this->dir);
+ }
+
+ $filename = $this->dir . "/" . $filename;
+ file_put_contents($filename, $content);
+
+ $this->log("Contents from " . $this->url . " saved to $filename");
+ }
+
+ /**
+ * Sets the request URL
+ *
+ * @param string $url
+ */
+ public function setUrl($url) {
+ $this->url = $url;
+ }
+
+ /**
+ * Sets the filename to store the output in
+ *
+ * @param string $filename
+ */
+ public function setFilename($filename) {
+ $this->filename = $filename;
+ }
+
+ /**
+ * Sets the save location
+ *
+ * @param string $dir
+ */
+ public function setDir($dir) {
+ $this->dir = $dir;
+ }
+
+ /**
+ * Sets the proxy
+ *
+ * @param string $proxy
+ */
+ public function setProxy($proxy) {
+ $this->_proxy = $proxy;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/HttpRequestTask.php b/buildscripts/phing/classes/phing/tasks/ext/HttpRequestTask.php
new file mode 100644
index 00000000..e6f15075
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/HttpRequestTask.php
@@ -0,0 +1,286 @@
+<?php
+/*
+ * $Id: 495c02bc3a90d24694d8a4bf2d43ac077e0f9ec6 $
+ *
+ * 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';
+
+/**
+ * A HTTP request task.
+ * Making an HTTP request and try to match the response against an provided
+ * regular expression.
+ *
+ * @package phing.tasks.ext
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 495c02bc3a90d24694d8a4bf2d43ac077e0f9ec6 $
+ * @since 2.4.1
+ */
+class HttpRequestTask extends Task
+{
+ /**
+ * Holds the request URL
+ *
+ * @var string
+ */
+ protected $_url = null;
+
+ /**
+ * Holds the regular expression that should match the response
+ *
+ * @var string
+ */
+ protected $_responseRegex = '';
+
+ /**
+ * Whether to enable detailed logging
+ *
+ * @var boolean
+ */
+ protected $_verbose = false;
+
+ /**
+ * Holds additional header data
+ *
+ * @var array<Parameter>
+ */
+ protected $_headers = array();
+
+ /**
+ * Holds additional config data for HTTP_Request2
+ *
+ * @var array<Parameter>
+ */
+ protected $_configData = array();
+
+ /**
+ * Holds the authentication user name
+ *
+ * @var string
+ */
+ protected $_authUser = null;
+
+ /**
+ * Holds the authentication password
+ *
+ * @var string
+ */
+ protected $_authPassword = '';
+
+ /**
+ * Holds the authentication scheme
+ *
+ * @var string
+ */
+ protected $_authScheme;
+
+ /**
+ * Holds the events that will be logged
+ *
+ * @var array<string>
+ */
+ protected $_observerEvents = array(
+ 'connect',
+ 'sentHeaders',
+ 'sentBodyPart',
+ 'receivedHeaders',
+ 'receivedBody',
+ 'disconnect',
+ );
+
+ /**
+ * Sets the request URL
+ *
+ * @param string $url
+ */
+ public function setUrl($url)
+ {
+ $this->_url = $url;
+ }
+
+ /**
+ * Sets the response regex
+ *
+ * @param string $regex
+ */
+ public function setResponseRegex($regex)
+ {
+ $this->_responseRegex = $regex;
+ }
+
+ /**
+ * Sets the authentication user name
+ *
+ * @param string $user
+ */
+ public function setAuthUser($user)
+ {
+ $this->_authUser = $user;
+ }
+
+ /**
+ * Sets the authentication password
+ *
+ * @param string $password
+ */
+ public function setAuthPassword($password)
+ {
+ $this->_authPassword = $password;
+ }
+
+ /**
+ * Sets the authentication scheme
+ *
+ * @param string $scheme
+ */
+ public function setAuthScheme($scheme)
+ {
+ $this->_authScheme = $scheme;
+ }
+
+ /**
+ * Sets whether to enable detailed logging
+ *
+ * @param boolean $verbose
+ */
+ public function setVerbose($verbose)
+ {
+ $this->_verbose = StringHelper::booleanValue($verbose);
+ }
+
+ /**
+ * Sets a list of observer events that will be logged
+ * if verbose output is enabled.
+ *
+ * @param string $observerEvents List of observer events
+ *
+ * @return void
+ */
+ public function setObserverEvents($observerEvents)
+ {
+ $this->_observerEvents = array();
+
+ $token = ' ,;';
+ $ext = strtok($observerEvents, $token);
+
+ while ($ext !== false) {
+ $this->_observerEvents[] = $ext;
+ $ext = strtok($token);
+ }
+ }
+
+ /**
+ * Creates an additional header for this task
+ *
+ * @return Parameter The created header
+ */
+ public function createHeader()
+ {
+ $num = array_push($this->_headers, new Parameter());
+ return $this->_headers[$num-1];
+ }
+
+ /**
+ * Creates a config parameter for this task
+ *
+ * @return Parameter The created parameter
+ */
+ public function createConfig()
+ {
+ $num = array_push($this->_configData, new Parameter());
+ return $this->_configData[$num-1];
+ }
+
+ /**
+ * Load the necessary environment for running this task.
+ *
+ * @throws BuildException
+ */
+ public function init()
+ {
+ @include_once 'HTTP/Request2.php';
+
+ if (! class_exists('HTTP_Request2')) {
+ throw new BuildException(
+ 'HttpRequestTask depends on HTTP_Request2 being installed '
+ . 'and on include_path.',
+ $this->getLocation()
+ );
+ }
+
+ $this->_authScheme = HTTP_Request2::AUTH_BASIC;
+
+ // Other dependencies that should only be loaded
+ // when class is actually used
+ require_once 'HTTP/Request2/Observer/Log.php';
+ }
+
+ /**
+ * Make the http request
+ */
+ public function main()
+ {
+ if (!isset($this->_url)) {
+ throw new BuildException("Missing attribute 'url' set");
+ }
+
+ $request = new HTTP_Request2($this->_url);
+
+ // set the authentication data
+ if (!empty($this->_authUser)) {
+ $request->setAuth(
+ $this->_authUser,
+ $this->_authPassword,
+ $this->_authScheme
+ );
+ }
+
+ foreach ($this->_configData as $config) {
+ $request->setConfig($config->getName(), $config->getValue());
+ }
+
+ foreach ($this->_headers as $header) {
+ $request->setHeader($header->getName(), $header->getValue());
+ }
+
+ if ($this->_verbose) {
+ $observer = new HTTP_Request2_Observer_Log();
+
+ // set the events we want to log
+ $observer->events = $this->_observerEvents;
+
+ $request->attach($observer);
+ }
+
+ $response = $request->send();
+
+ if ($this->_responseRegex !== '') {
+ $matches = array();
+ preg_match($this->_responseRegex, $response->getBody(), $matches);
+
+ if (count($matches) === 0) {
+ throw new BuildException(
+ 'The received response body did not match the '
+ . 'given regular expression'
+ );
+ } else {
+ $this->log('The response body matched the provided regex.');
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/JslLintTask.php b/buildscripts/phing/classes/phing/tasks/ext/JslLintTask.php
new file mode 100644
index 00000000..77a4aad5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/JslLintTask.php
@@ -0,0 +1,284 @@
+<?php
+/*
+ * $Id: 551de2e94aa21f44e19dd0806051f1eabf8b20f9 $
+ *
+ * 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/util/DataStore.php';
+
+/**
+ * A Javascript lint task. Checks syntax of Javascript files.
+ * Javascript lint (http://www.javascriptlint.com) must be in the system path.
+ * This class is based on Knut Urdalen's PhpLintTask.
+ *
+ * @author Stefan Priebsch <stefan.priebsch@e-novative.de>
+ * @version $Id: 551de2e94aa21f44e19dd0806051f1eabf8b20f9 $
+ * @package phing.tasks.ext
+ */
+class JslLintTask extends Task
+{
+ protected $file; // the source file (from xml attribute)
+ protected $filesets = array(); // all fileset objects assigned to this task
+
+ protected $showWarnings = true;
+ protected $haltOnFailure = false;
+ protected $hasErrors = false;
+ private $badFiles = array();
+
+ private $cache = null;
+ private $conf = null;
+
+ private $executable = "jsl";
+
+ /**
+ * @var PhingFile
+ */
+ protected $tofile = null;
+
+ /**
+ * Sets the flag if warnings should be shown
+ * @param boolean $show
+ */
+ public function setShowWarnings($show) {
+ $this->showWarnings = StringHelper::booleanValue($show);
+ }
+
+ /**
+ * The haltonfailure property
+ * @param boolean $aValue
+ */
+ public function setHaltOnFailure($aValue) {
+ $this->haltOnFailure = $aValue;
+ }
+
+ /**
+ * File to be performed syntax check on
+ * @param PhingFile $file
+ */
+ public function setFile(PhingFile $file) {
+ $this->file = $file;
+ }
+
+ /**
+ * Whether to store last-modified times in cache
+ *
+ * @param PhingFile $file
+ */
+ public function setCacheFile(PhingFile $file)
+ {
+ $this->cache = new DataStore($file);
+ }
+
+ /**
+ * jsl config file
+ *
+ * @param PhingFile $file
+ */
+ public function setConfFile(PhingFile $file)
+ {
+ $this->conf = $file;
+ }
+
+ public function setExecutable($path){
+ $this->executable = $path;
+
+ if (!@file_exists($path)) {
+ throw new BuildException("JavaScript Lint executable '{$path}' not found");
+ }
+ }
+
+ public function getExecutable(){
+ return $this->executable;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * File to save error messages to
+ *
+ * @param PhingFile $file
+ */
+ public function setToFile(PhingFile $tofile)
+ {
+ $this->tofile = $tofile;
+ }
+
+ /**
+ * 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 (empty($this->executable)) {
+ throw new BuildException("Missing the 'executable' attribute");
+ }
+
+ 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);
+ }
+ }
+ }
+
+ // write list of 'bad files' to file (if specified)
+ if ($this->tofile) {
+ $writer = new FileWriter($this->tofile);
+
+ foreach ($this->badFiles as $file => $messages) {
+ foreach ($messages as $msg) {
+ $writer->write($file . "=" . $msg . PHP_EOL);
+ }
+ }
+
+ $writer->close();
+ }
+
+ if ($this->haltOnFailure && $this->hasErrors) throw new BuildException('Syntax error(s) in JS files:' .implode(', ', array_keys($this->badFiles)));
+ }
+
+ /**
+ * Performs the actual syntax check
+ *
+ * @param string $file
+ * @return void
+ */
+ protected function lint($file)
+ {
+ $command = $this->executable . ' -output-format ' . escapeshellarg('file:__FILE__;line:__LINE__;message:__ERROR__') . ' ';
+
+ if (isset($this->conf)) {
+ $command .= '-conf ' . escapeshellarg($this->conf->getPath()) . ' ';
+ }
+
+ $command .= '-process ';
+
+ if(file_exists($file))
+ {
+ if(is_readable($file))
+ {
+ if ($this->cache)
+ {
+ $lastmtime = $this->cache->get($file);
+
+ if ($lastmtime >= filemtime($file))
+ {
+ $this->log("Not linting '" . $file . "' due to cache", Project::MSG_DEBUG);
+ return false;
+ }
+ }
+
+ $messages = array();
+ exec($command.'"'.$file.'"', $messages, $return);
+
+ if ($return > 100) {
+ throw new BuildException("Could not execute Javascript Lint executable '{$this->executable}'");
+ }
+
+ $summary = $messages[sizeof($messages) - 1];
+
+ preg_match('/(\d+)\serror/', $summary, $matches);
+ $errorCount = (count($matches) > 1 ? $matches[1] : 0);
+
+ preg_match('/(\d+)\swarning/', $summary, $matches);
+ $warningCount = (count($matches) > 1 ? $matches[1] : 0);
+
+ $errors = array();
+ $warnings = array();
+ if ($errorCount > 0 || $warningCount > 0) {
+ $last = false;
+ foreach ($messages as $message) {
+ $matches = array();
+ if (preg_match('/^(\.*)\^$/', $message)) {
+ $column = strlen($message);
+ if ($last == 'error') {
+ $errors[count($errors) - 1]['column'] = $column;
+ } else if ($last == 'warning') {
+ $warnings[count($warnings) - 1]['column'] = $column;
+ }
+ $last = false;
+ }
+ if (!preg_match('/^file:(.+);line:(\d+);message:(.+)$/', $message, $matches)) continue;
+ $msg = $matches[3];
+ $data = array('filename' => $matches[1], 'line' => $matches[2], 'message' => $msg);
+ if (preg_match('/^.*error:.+$/i', $msg)) {
+ $errors[] = $data;
+ $last = 'error';
+ } else if (preg_match('/^.*warning:.+$/i', $msg)) {
+ $warnings[] = $data;
+ $last = 'warning';
+ }
+ }
+ }
+
+ if($this->showWarnings && $warningCount > 0)
+ {
+ $this->log($file . ': ' . $warningCount . ' warnings detected', Project::MSG_WARN);
+ foreach ($warnings as $warning) {
+ $this->log('- line ' . $warning['line'] . (isset($warning['column']) ? ' column ' . $warning['column'] : '') . ': ' . $warning['message'], Project::MSG_WARN);
+ }
+ }
+
+ if($errorCount > 0)
+ {
+ $this->log($file . ': ' . $errorCount . ' errors detected', Project::MSG_ERR);
+ if (!isset($this->badFiles[$file])) {
+ $this->badFiles[$file] = array();
+ }
+
+ foreach ($errors as $error) {
+ $message = 'line ' . $error['line'] . (isset($error['column']) ? ' column ' . $error['column'] : '') . ': ' . $error['message'];
+ $this->log('- ' . $message, Project::MSG_ERR);
+ array_push($this->badFiles[$file], $message);
+ }
+ $this->hasErrors = true;
+ } else if (!$this->showWarnings || $warningCount == 0) {
+ $this->log($file . ': No syntax errors detected', Project::MSG_VERBOSE);
+
+ if ($this->cache)
+ {
+ $this->cache->put($file, filemtime($file));
+ }
+ }
+ } else {
+ throw new BuildException('Permission denied: '.$file);
+ }
+ } else {
+ throw new BuildException('File not found: '.$file);
+ }
+ }
+}
+
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/MailTask.php b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php
new file mode 100755
index 00000000..0fff88cc
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php
@@ -0,0 +1,159 @@
+<?php
+/*
+ * $Id: 901fb0efa435ae78d249a50ed0e0f6e5d31e0d32 $
+ *
+ * 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 an e-mail message
+ *
+ * <mail tolist="user@example.org" subject="build complete">The build process is a success...</mail>
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Francois Harvey at SecuriWeb (http://www.securiweb.net)
+ * @version $Id: 901fb0efa435ae78d249a50ed0e0f6e5d31e0d32 $
+ * @package phing.tasks.ext
+ */
+class MailTask extends Task
+{
+ protected $tolist = null;
+ protected $subject = null;
+ protected $msg = null;
+ protected $from = null;
+
+ protected $filesets = array();
+
+ public function main()
+ {
+ if (empty($this->from)) {
+ throw new BuildException('Missing "from" attribute');
+ }
+
+ $this->log('Sending mail to ' . $this->tolist);
+
+ if (!empty($this->filesets)) {
+ @require_once 'Mail.php';
+ @require_once 'Mail/mime.php';
+
+ if (!class_exists('Mail_mime')) {
+ throw new BuildException('Need the PEAR Mail_mime package to send attachments');
+ }
+
+ $mime = new Mail_mime();
+ $hdrs = array(
+ 'From' => $this->from,
+ 'Subject' => $this->subject
+ );
+ $mime->setTXTBody($this->msg);
+
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $fromDir = $fs->getDir($this->project);
+ $srcFiles = $ds->getIncludedFiles();
+
+ foreach ($srcFiles as $file) {
+ $mime->addAttachment($fromDir . DIRECTORY_SEPARATOR . $file, 'application/octet-stream');
+ }
+ }
+
+ $body = $mime->get();
+ $hdrs = $mime->headers($hdrs);
+
+ $mail = Mail::factory('mail');
+ $mail->send($this->tolist, $hdrs, $body);
+ } else {
+ mail($this->tolist, $this->subject, $this->msg, "From: {$this->from}\n");
+ }
+ }
+
+ /**
+ * Setter for message
+ */
+ public function setMsg($msg)
+ {
+ $this->setMessage($msg);
+ }
+
+ /**
+ * Alias setter
+ */
+ public function setMessage($msg)
+ {
+ $this->msg = (string) $msg;
+ }
+
+ /**
+ * Setter for subject
+ */
+ public function setSubject($subject)
+ {
+ $this->subject = (string) $subject;
+ }
+
+ /**
+ * Setter for tolist
+ */
+ public function setToList($tolist)
+ {
+ $this->tolist = $tolist;
+ }
+
+ /**
+ * Alias for (deprecated) recipient
+ */
+ public function setRecipient($recipient)
+ {
+ $this->tolist = (string) $recipient;
+ }
+
+ /**
+ * Alias for to
+ */
+ public function setTo($to)
+ {
+ $this->tolist = (string) $to;
+ }
+
+ /**
+ * Supports the <mail>Message</mail> syntax.
+ */
+ public function addText($msg)
+ {
+ $this->msg = (string) $msg;
+ }
+
+ /**
+ * Sets email address of sender
+ */
+ public function setFrom($from)
+ {
+ $this->from = $from;
+ }
+
+ /**
+ * Adds a fileset
+ */
+ public function createFileSet()
+ {
+ $fileset = new FileSet();
+ $this->filesets[] = $fileset;
+ return $fileset;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ManifestTask.php b/buildscripts/phing/classes/phing/tasks/ext/ManifestTask.php
new file mode 100644
index 00000000..b9cfae64
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ManifestTask.php
@@ -0,0 +1,343 @@
+<?php
+/**
+ * $Id: 7f8f119fe5dd44ca9f374e24d776a1a764260e33 $
+ *
+ * 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';
+
+/**
+ * ManifestTask
+ *
+ * Generates a simple Manifest file with optional checksums.
+ *
+ *
+ * Manifest schema:
+ * ...
+ * path/to/file CHECKSUM [CHECKSUM2] [CHECKSUM3]
+ * path/to/secondfile CHECKSUM [CHECKSUM2] [CHECKSUM3]
+ * ...
+ *
+ * Example usage:
+ * <manifest checksum="crc32" file="${dir_build}/Manifest">
+ * <fileset refid="files_build" />
+ * </manifest>
+ *
+ * <manifest checksum="md5,adler32,sha256" file="${dir_build}/Manifest">
+ * <fileset refid="files_build" />
+ * </manifest>
+ *
+ *
+ *
+ * @author David Persson <davidpersson at qeweurope dot org>
+ * @package phing.tasks.ext
+ * @version $Id: 7f8f119fe5dd44ca9f374e24d776a1a764260e33 $
+ * @since 2.3.1
+ */
+class ManifestTask extends Task
+{
+ var $taskname = 'manifest';
+
+ /**
+ * Action
+ *
+ * "w" for reading in files from fileSet
+ * and writing manifest
+ *
+ * or
+ *
+ * "r" for reading in files from fileSet
+ * and checking against manifest
+ *
+ * @var string "r" or "w"
+ */
+ private $action = 'w';
+
+ /**
+ * The target file passed in the buildfile.
+ */
+ private $destFile = null;
+
+ /**
+ * Holds filesets
+ *
+ * @var array An Array of objects
+ */
+ private $filesets = array();
+
+ /**
+ * Enable/Disable checksuming or/and select algorithm
+ * true defaults to md5
+ * false disables checksuming
+ * string "md5,sha256,..." enables generation of multiple checksums
+ * string "sha256" generates sha256 checksum only
+ *
+ * @var mixed
+ */
+ private $checksum = false;
+
+ /**
+ * A string used in hashing method
+ *
+ * @var string
+ */
+ private $salt = '';
+
+ /**
+ * Holds some data collected during runtime
+ *
+ * @var array
+ */
+ private $meta = array('totalFileCount' => 0,'totalFileSize' => 0);
+
+
+ /**
+ * The setter for the attribute "file"
+ * This is where the manifest will be written to/read from
+ *
+ * @param string Path to readable file
+ * @return void
+ */
+ public function setFile(PhingFile $file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * The setter for the attribute "checksum"
+ *
+ * @param mixed $mixed
+ * @return void
+ */
+ public function setChecksum($mixed)
+ {
+ if(is_string($mixed)) {
+ $data = array(strtolower($mixed));
+
+ if(strpos($data[0],',')) {
+ $data = explode(',',$mixed);
+ }
+
+ $this->checksum = $data;
+
+ } elseif($mixed === true) {
+ $this->checksum = array('md5');
+
+ }
+ }
+
+ /**
+ * The setter for the optional attribute "salt"
+ *
+ * @param string $string
+ * @return void
+ */
+ public function setSalt($string)
+ {
+ $this->salt = $string;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @access public
+ * @return object The created fileset object
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * The init method: Do init steps.
+ */
+ public function init()
+ {
+ // nothing to do here
+ }
+
+ /**
+ * Delegate the work
+ */
+ public function main()
+ {
+ $this->validateAttributes();
+
+ if($this->action == 'w') {
+ $this->write();
+
+ } elseif($this->action == 'r') {
+ $this->read();
+
+ }
+ }
+
+ /**
+ * Creates Manifest file
+ * Writes to $this->file
+ *
+ * @throws BuildException
+ */
+ private function write()
+ {
+ $project = $this->getProject();
+
+ if(!touch($this->file->getPath())) {
+ throw new BuildException("Unable to write to ".$this->file->getPath().".");
+ }
+
+ $this->log("Writing to " . $this->file->__toString(), Project::MSG_INFO);
+
+ if(is_array($this->checksum)) {
+ $this->log("Using " . implode(', ',$this->checksum)." for checksuming.", Project::MSG_INFO);
+ }
+
+ foreach($this->filesets as $fs) {
+
+ $dir = $fs->getDir($this->project)->getPath();
+
+ $ds = $fs->getDirectoryScanner($project);
+ $fromDir = $fs->getDir($project);
+ $srcFiles = $ds->getIncludedFiles();
+ $srcDirs = $ds->getIncludedDirectories();
+
+ foreach($ds->getIncludedFiles() as $file_path) {
+ $line = $file_path;
+ if($this->checksum) {
+ foreach($this->checksum as $algo) {
+ if(!$hash = $this->hashFile($dir.'/'.$file_path,$algo)) {
+ throw new BuildException("Hashing $dir/$file_path with $algo failed!");
+ }
+
+ $line .= "\t".$hash;
+ }
+ }
+ $line .= "\n";
+ $manifest[] = $line;
+ $this->log("Adding file ".$file_path,Project::MSG_VERBOSE);
+ $this->meta['totalFileCount'] ++;
+ $this->meta['totalFileSize'] += filesize($dir.'/'.$file_path);
+ }
+
+ }
+
+ file_put_contents($this->file,$manifest);
+
+ $this->log("Done. Total files: ".$this->meta['totalFileCount'].". Total file size: ".$this->meta['totalFileSize']." bytes.", Project::MSG_INFO);
+ }
+
+ /**
+ * @todo implement
+ */
+ private function read()
+ {
+ throw new BuildException("Checking against manifest not yet supported.");
+ }
+
+ /**
+ * Wrapper method for hash generation
+ * Automatically selects extension
+ * Falls back to built-in functions
+ *
+ * @link http://www.php.net/mhash
+ * @link http://www.php.net/hash
+ *
+ * @param string $msg The string that should be hashed
+ * @param string $algo Algorithm
+ * @return mixed String on success, false if $algo is not available
+ */
+ private function hash($msg,$algo)
+ {
+ if(extension_loaded('hash')) {
+ $algo = strtolower($algo);
+
+ if(in_array($algo,hash_algos())) {
+ return hash($algo,$this->salt.$msg);
+ }
+
+ }
+
+ if(extension_loaded('mhash')) {
+ $algo = strtoupper($algo);
+
+ if(defined('MHASH_'.$algo)) {
+ return mhash('MHASH_'.$algo,$this->salt.$msg);
+
+ }
+ }
+
+ switch(strtolower($algo)) {
+ case 'md5':
+ return md5($this->salt.$msg);
+ case 'crc32':
+ return abs(crc32($this->salt.$msg));
+ }
+
+ return false;
+ }
+
+ /**
+ * Hash a files contents
+ * plus it's size an modification time
+ *
+ * @param string $file
+ * @param string $algo
+ * @return mixed String on success, false if $algo is not available
+ */
+ private function hashFile($file,$algo)
+ {
+ if(!file_exists($file)) {
+ return false;
+ }
+
+ $msg = file_get_contents($file).filesize($file).filemtime($file);
+
+ return $this->hash($msg,$algo);
+ }
+
+ /**
+ * Validates attributes coming in from XML
+ *
+ * @access private
+ * @return void
+ * @throws BuildException
+ */
+ protected function validateAttributes()
+ {
+ if($this->action != 'r' && $this->action != 'w') {
+ throw new BuildException("'action' attribute has non valid value. Use 'r' or 'w'");
+ }
+
+ if(empty($this->salt)) {
+ $this->log("No salt provided. Specify one with the 'salt' attribute.", Project::MSG_WARN);
+ }
+
+ if (is_null($this->file) && count($this->filesets) === 0) {
+ throw new BuildException("Specify at least sources and destination - a file or a fileset.");
+ }
+
+ if (!is_null($this->file) && $this->file->exists() && $this->file->isDirectory()) {
+ throw new BuildException("Destination file cannot be a directory.");
+ }
+
+ }
+}
+
+
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..2db5ad69
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php
@@ -0,0 +1,65 @@
+<?php
+
+/*
+ * $Id: 976dafaf4cafd9ff8f47907a09943ae3963aea79 $
+ *
+ * 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 $Id: 976dafaf4cafd9ff8f47907a09943ae3963aea79 $
+ * @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/ParallelTask.php b/buildscripts/phing/classes/phing/tasks/ext/ParallelTask.php
new file mode 100755
index 00000000..b8da5cb4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ParallelTask.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * $Id: 860b2b6cdbd797754660fe2c1554e22ab2db4967 $
+ *
+ * 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.tasks.ext
+ */
+
+/**
+ * Uses the DocBlox_Parallel library to run nested Phing tasks concurrently.
+ *
+ * WARNING: this task is highly experimental!
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 860b2b6cdbd797754660fe2c1554e22ab2db4967 $
+ * @package phing.tasks.ext
+ * @see https://github.com/phpdocumentor/Parallel
+ * @since 2.4.10
+ */
+class ParallelTask extends SequentialTask
+{
+ /**
+ * Maximum number of threads / processes
+ * @var int
+ */
+ private $threadCount = 2;
+
+ /**
+ * Sets the maximum number of threads / processes to use
+ * @param int $threadCount
+ */
+ public function setThreadCount($threadCount)
+ {
+ $this->threadCount = $threadCount;
+ }
+
+ public function init()
+ {
+ }
+
+ public function main()
+ {
+ @include_once 'phing/contrib/DocBlox/Parallel/Manager.php';
+ @include_once 'phing/contrib/DocBlox/Parallel/Worker.php';
+ @include_once 'phing/contrib/DocBlox/Parallel/WorkerPipe.php';
+ if (!class_exists('DocBlox_Parallel_Worker')) {
+ throw new BuildException(
+ 'ParallelTask depends on DocBlox being installed and on include_path.',
+ $this->getLocation()
+ );
+ }
+
+ $mgr = new DocBlox_Parallel_Manager();
+ $mgr->setProcessLimit($this->threadCount);
+
+ foreach ($this->nestedTasks as $task) {
+ $worker = new DocBlox_Parallel_Worker(
+ array($task, 'perform'),
+ array($task)
+ );
+
+ $mgr->addWorker($worker);
+ }
+
+ $mgr->execute();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/PatchTask.php b/buildscripts/phing/classes/phing/tasks/ext/PatchTask.php
new file mode 100755
index 00000000..162f5fe5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PatchTask.php
@@ -0,0 +1,301 @@
+<?php
+/**
+ * Patches a file by applying a 'diff' file to it
+ *
+ * Requires "patch" to be on the execution path.
+ *
+ * Based on Apache Ant PatchTask:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+require_once 'phing/Task.php';
+
+/**
+ * Patches a file by applying a 'diff' file to it
+ *
+ * Requires "patch" to be on the execution path.
+ *
+ * @package phing.tasks.ext
+ */
+class PatchTask extends Task
+{
+ /**
+ * Base command to be executed (must end with a space character!)
+ * @var string
+ */
+ const CMD = 'patch --batch --silent ';
+
+ /**
+ * File to be patched
+ * @var string
+ */
+ private $originalFile;
+
+ /**
+ * Patch file
+ *
+ * @var string
+ */
+ private $patchFile;
+
+ /**
+ * Value for a "-p" option
+ * @var int
+ */
+ private $strip;
+
+ /**
+ * Command line arguments for patch binary
+ * @var array
+ */
+ private $cmdArgs = array();
+
+ /**
+ * Halt on error return value from patch invocation.
+ * @var bool
+ */
+ private $haltOnFailure = false;
+
+ /**
+ * The file containing the diff output
+ *
+ * Required.
+ *
+ * @param string $file File containing the diff output
+ * @return void
+ * @throws BuildException if $file not exists
+ */
+ public function setPatchFile($file)
+ {
+ if (!is_file($file))
+ {
+ throw new BuildException(sprintf('Patchfile %s doesn\'t exist', $file));
+ }
+ $this->patchFile = $file;
+ }
+
+ /**
+ * The file to patch
+ *
+ * Optional if it can be inferred from the diff file.
+ *
+ * @param string $file File to patch
+ * @return void
+ */
+ public function setOriginalFile($file)
+ {
+ $this->originalFile = $file;
+ }
+
+ /**
+ * The name of a file to send the output to, instead of patching
+ * the file(s) in place
+ *
+ * Optional.
+ *
+ * @param string $file File to send the output to
+ * @return void
+ */
+ public function setDestFile($file)
+ {
+ if ($file !== null)
+ {
+ $this->cmdArgs []= "--output=$file";
+ }
+ }
+
+ /**
+ * Flag to create backups
+ *
+ * Optional, default - false
+ *
+ * @param bool $backups If true create backups
+ * @return void
+ */
+ public function setBackups($backups)
+ {
+ if ($backups)
+ {
+ $this->cmdArgs []= '--backup';
+ }
+ }
+
+ /**
+ * Flag to ignore whitespace differences;
+ *
+ * Default - false
+ *
+ * @param bool $ignore If true ignore whitespace differences
+ * @return void
+ */
+ public function setIgnoreWhiteSpace($ignore)
+ {
+ if ($ignore)
+ {
+ $this->cmdArgs []= '--ignore-whitespace';
+ }
+ }
+
+ /**
+ * Strip the smallest prefix containing <i>num</i> leading slashes
+ * from filenames.
+ *
+ * patch's <i>--strip</i> option.
+ *
+ * @param int $num number of lines to strip
+ * @return void
+ * @throws BuildException if num is < 0, or other errors
+ */
+ public function setStrip($num)
+ {
+ if ($num < 0)
+ {
+ throw new BuildException('strip has to be >= 0');
+ }
+
+ $this->strip = $num;
+ }
+
+ /**
+ * Work silently unless an error occurs
+ *
+ * Optional, default - false
+ * @param bool $flag If true suppress set the -s option on the patch command
+ * @return void
+ */
+ public function setQuiet($flag)
+ {
+ if ($flag)
+ {
+ $this->cmdArgs []= '--silent';
+ }
+ }
+
+ /**
+ * Assume patch was created with old and new files swapped
+ *
+ * Optional, default - false
+ *
+ * @param bool $flag If true set the -R option on the patch command
+ * @return void
+ */
+ public function setReverse($flag)
+ {
+ if ($flag)
+ {
+ $this->cmdArgs []= '--reverse';
+ }
+ }
+
+ /**
+ * The directory to run the patch command in
+ *
+ * Defaults to the project's base directory.
+ *
+ * @param string $directory Directory to run the patch command in
+ * @return void
+ */
+ public function setDir($directory)
+ {
+ $this->cmdArgs []= "--directory=$directory";
+ }
+
+ /**
+ * Ignore patches that seem to be reversed or already applied
+ *
+ * @param bool $flag If true set the -N (--forward) option
+ * @return void
+ */
+ public function setForward($flag)
+ {
+ if ($flag)
+ {
+ $this->cmdArgs []= "--forward";
+ }
+ }
+
+ /**
+ * Set the maximum fuzz factor
+ *
+ * Defaults to 0
+ *
+ * @param string $value Value of a fuzz factor
+ * @return void
+ */
+ public function setFuzz($value)
+ {
+ $this->cmdArgs []= "--fuzz=$value";
+ }
+
+ /**
+ * If true, stop the build process if the patch command
+ * exits with an error status.
+ *
+ * The default is "false"
+ *
+ * @param bool $value "true" if it should halt, otherwise "false"
+ * @return void
+ */
+ public function setHaltOnFailure($value)
+ {
+ $this->haltOnFailure = $value;
+ }
+
+ /**
+ * Main task method
+ *
+ * @return void
+ * @throws BuildException when it all goes a bit pear shaped
+ */
+ public function main()
+ {
+ if ($this->patchFile == null)
+ {
+ throw new BuildException('patchfile argument is required');
+ }
+
+ // Define patch file
+ $this->cmdArgs []= '-i ' . $this->patchFile;
+ // Define strip factor
+ if ($this->strip != null)
+ {
+ $this->cmdArgs []= '--strip=' . $this->strip;
+ }
+ // Define original file if specified
+ if ($this->originalFile != null)
+ {
+ $this->cmdArgs []= $this->originalFile;
+ }
+
+ $cmd = self::CMD . implode(' ', $this->cmdArgs);
+
+ $this->log('Applying patch: ' . $this->patchFile);
+
+ exec($cmd, $output, $exitCode);
+
+ foreach ($output as $line)
+ {
+ $this->log($line, Project::MSG_VERBOSE);
+ }
+
+ if ($exitCode != 0 && $this->haltOnFailure)
+ {
+ throw new BuildException( "Task exited with code $exitCode" );
+ }
+
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/PearPackage2Task.php b/buildscripts/phing/classes/phing/tasks/ext/PearPackage2Task.php
new file mode 100644
index 00000000..f42231f7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PearPackage2Task.php
@@ -0,0 +1,279 @@
+<?php
+/*
+ * $Id: 1b20dbb6595bd4c41d1e5f1430900e3bf95de411 $
+ *
+ * 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/PearPackageTask.php';
+
+/**
+ * A task to create a PEAR package.xml version 2.0 file.
+ *
+ * This class uses the PEAR_PackageFileManager2 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_PackageFileManager2::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_PackageFileManager2::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>
+ * <pearpkg2 name="phing" dir="${build.src.dir}">
+ * <fileset dir="src">
+ * <include name="**"/>
+ * </fileset>
+ * <option name="outputdirectory" value="./build"/>
+ * <option name="packagefile" value="package2.xml"/>
+ * <option name="packagedirectory" value="./${build.dist.dir}"/>
+ * <option name="baseinstalldir" value="${pkg.prefix}"/>
+ * <option name="channel" value="my.pear-channel.com"/>
+ * <option name="summary" value="${pkg.summary}"/>
+ * <option name="description" value="${pkg.description}"/>
+ * <option name="apiversion" value="${pkg.version}"/>
+ * <option name="apistability" value="beta"/>
+ * <option name="releaseversion" value="${pkg.version}"/>
+ * <option name="releasestability" value="beta"/>
+ * <option name="license" value="none"/>
+ * <option name="phpdep" value="5.0.0"/>
+ * <option name="pearinstallerdep" value="1.4.6"/>
+ * <option name="packagetype" value="php"/>
+ * <option name="notes" value="${pkg.relnotes}"/>
+ * <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 key="active" value="yes"/>
+ * </element>
+ * </mapping>
+ * </pearpkg2>
+ * </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 Stuart Binge <stuart.binge@complinet.com>
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @package phing.tasks.ext
+ * @version $Id: 1b20dbb6595bd4c41d1e5f1430900e3bf95de411 $
+ */
+class PearPackage2Task extends PearPackageTask {
+
+ public function init() {
+ include_once 'PEAR/PackageFileManager2.php';
+ if (!class_exists('PEAR_PackageFileManager2')) {
+ throw new BuildException("You must have installed PEAR_PackageFileManager in order to create a PEAR package.xml version 2.0 file.");
+ }
+ }
+
+ protected function setVersion2Options()
+ {
+ $this->pkg->setPackage($this->package);
+ $this->pkg->setDate(strftime('%Y-%m-%d'));
+ $this->pkg->setTime(strftime('%H:%M:%S'));
+
+ $newopts = array();
+ foreach ($this->options as $opt) {
+ switch ($opt->getName()) {
+ case 'summary':
+ $this->pkg->setSummary($opt->getValue());
+ break;
+
+ case 'description':
+ $this->pkg->setDescription($opt->getValue());
+ break;
+
+ case 'uri':
+ $this->pkg->setUri($opt->getValue());
+ break;
+
+ case 'license':
+ $this->pkg->setLicense($opt->getValue());
+ break;
+
+ case 'channel':
+ $this->pkg->setChannel($opt->getValue());
+ break;
+
+ case 'apiversion':
+ $this->pkg->setAPIVersion($opt->getValue());
+ break;
+
+ case 'releaseversion':
+ $this->pkg->setReleaseVersion($opt->getValue());
+ break;
+
+ case 'releasestability':
+ $this->pkg->setReleaseStability($opt->getValue());
+ break;
+
+ case 'apistability':
+ $this->pkg->setAPIStability($opt->getValue());
+ break;
+
+ case 'notes':
+ $this->pkg->setNotes($opt->getValue());
+ break;
+
+ case 'packagetype':
+ $this->pkg->setPackageType($opt->getValue());
+ break;
+
+ case 'phpdep':
+ $this->pkg->setPhpDep($opt->getValue());
+ break;
+
+ case 'pearinstallerdep':
+ $this->pkg->setPearinstallerDep($opt->getValue());
+ break;
+
+ default:
+ $newopts[] = $opt;
+ break;
+ }
+ }
+ $this->options = $newopts;
+
+ $newmaps = array();
+ foreach ($this->mappings as $map) {
+ switch ($map->getName()) {
+ case 'deps':
+ $deps = $map->getValue();
+ foreach ($deps as $dep) {
+ $type = isset($dep['optional']) ? 'optional' : 'required';
+ $min = isset($dep['min']) ? $dep['min'] : $dep['version'];
+ $max = isset($dep['max']) ? $dep['max'] : null;
+ $rec = isset($dep['recommended']) ? $dep['recommended'] : null;
+ $channel = isset($dep['channel']) ? $dep['channel'] : false;
+ $uri = isset($dep['uri']) ? $dep['uri'] : false;
+
+ if (!empty($channel)) {
+ $this->pkg->addPackageDepWithChannel(
+ $type, $dep['name'], $channel, $min, $max, $rec
+ );
+ } elseif (!empty($uri)) {
+ $this->pkg->addPackageDepWithUri(
+ $type, $dep['name'], $uri
+ );
+ }
+ };
+ break;
+
+ case 'extdeps':
+ $deps = $map->getValue();
+ foreach ($deps as $dep) {
+ $type = isset($dep['optional']) ? 'optional' : 'required';
+ $min = isset($dep['min']) ? $dep['min'] : $dep['version'];
+ $max = isset($dep['max']) ? $dep['max'] : $dep['version'];
+ $rec = isset($dep['recommended']) ? $dep['recommended'] : $dep['version'];
+
+ $this->pkg->addExtensionDep(
+ $type, $dep['name'], $min, $max, $rec
+ );
+ };
+ break;
+
+ case 'maintainers':
+ $maintainers = $map->getValue();
+
+ foreach ($maintainers as $maintainer) {
+ if (!isset($maintainer['active'])) {
+ $maintainer['active'] = 'yes';
+ } else {
+ $maintainer['active'] = $maintainer['active'] === false ? 'no' : 'yes';
+ }
+ $this->pkg->addMaintainer(
+ $maintainer['role'],
+ $maintainer['handle'],
+ $maintainer['name'],
+ $maintainer['email'],
+ $maintainer['active']
+ );
+ }
+ break;
+
+ case 'replacements':
+ $replacements = $map->getValue();
+
+ foreach($replacements as $replacement) {
+ $this->pkg->addReplacement(
+ $replacement['path'],
+ $replacement['type'],
+ $replacement['from'],
+ $replacement['to']
+ );
+ }
+ break;
+
+ case 'role':
+ foreach ($map->getValue() as $role) {
+ $this->pkg->addRole($role['extension'], $role['role']);
+ }
+ break;
+
+ default:
+ $newmaps[] = $map;
+ }
+ }
+ $this->mappings = $newmaps;
+ }
+
+ /**
+ * Main entry point.
+ * @return void
+ */
+ public function main()
+ {
+ if ($this->dir === null) {
+ throw new BuildException("You must specify the \"dir\" attribute for PEAR package 2 task.");
+ }
+
+ if ($this->package === null) {
+ throw new BuildException("You must specify the \"name\" attribute for PEAR package 2 task.");
+ }
+
+ $this->pkg = new PEAR_PackageFileManager2();
+
+ $this->setVersion2Options();
+ $this->setOptions();
+
+ $this->pkg->addRelease();
+ $this->pkg->generateContents();
+ $e = $this->pkg->writePackageFile();
+ if (PEAR::isError($e)) {
+ throw new BuildException("Unable to write package file.", new Exception($e->getMessage()));
+ }
+ }
+
+}
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..47945998
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PearPackageTask.php
@@ -0,0 +1,504 @@
+<?php
+/*
+ * $Id: 2078fd5bab3dd6dcea0345a12fce86a24586c765 $
+ *
+ * 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 $Id: 2078fd5bab3dd6dcea0345a12fce86a24586c765 $
+ */
+class PearPackageTask extends MatchingTask {
+
+ /** */
+ protected $package;
+
+ /** Base directory for reading files. */
+ protected $dir;
+
+ /** Package file */
+ private $packageFile;
+
+ /** @var array FileSet[] */
+ private $filesets = array();
+
+ /** @var PEAR_PackageFileManager */
+ protected $pkg;
+
+ private $preparedOptions = array();
+
+ /** @var array PearPkgOption[] */
+ protected $options = array();
+
+ /** Nested <mapping> (complex options) types. */
+ protected $mappings = array();
+
+ /**
+ * Nested <role> elements
+ * @var PearPkgRole[]
+ */
+ protected $roles = 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
+ */
+ protected 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()));
+ }
+
+ // convert roles
+ foreach ($this->roles as $role) {
+ $this->pkg->addRole($role->getExtension(), $role->getRole());
+ }
+ }
+
+ /**
+ * 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
+ *
+ * @param FileSet $fileset Set of files to add to the package
+ *
+ * @return void
+ */
+ public function addFileSet(FileSet $fs) {
+ $this->filesets[] = $fs;
+ }
+
+ /**
+ * 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.
+ */
+ public function createOption() {
+ $o = new PearPkgOption();
+ $this->options[] = $o;
+ return $o;
+ }
+
+ /**
+ * Handles nested generic <option> elements.
+ */
+ public function createMapping() {
+ $o = new PearPkgMapping();
+ $this->mappings[] = $o;
+ return $o;
+ }
+
+ /**
+ * Handles nested <role> elements
+ * @return PearPkgRole
+ */
+ public function createRole()
+ {
+ $role = new PearPkgRole();
+ $this->roles[] = $role;
+ return $role;
+ }
+}
+
+
+
+/**
+ * Generic option class is used for non-complex options.
+ *
+ * @package phing.tasks.ext
+ */
+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).
+ *
+ * @package phing.tasks.ext
+ */
+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>.
+ *
+ * @package phing.tasks.ext
+ */
+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;
+ }
+
+}
+
+/**
+ * Encapsulates file roles
+ *
+ * @package phing.tasks.ext
+ */
+class PearPkgRole
+{
+ /**
+ * @var string
+ */
+ private $extension;
+
+ /**
+ * @var string
+ */
+ private $role;
+
+ /**
+ * Sets the file extension
+ * @param string $extension
+ */
+ public function setExtension($extension)
+ {
+ $this->extension = $extension;
+ }
+
+ /**
+ * Retrieves the file extension
+ * @return string
+ */
+ public function getExtension()
+ {
+ return $this->extension;
+ }
+
+ /**
+ * Sets the role
+ * @param string $role
+ */
+ public function setRole($role)
+ {
+ $this->role = $role;
+ }
+
+ /**
+ * Retrieves the role
+ * @return string
+ */
+ public function getRole()
+ {
+ return $this->role;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/PhpCodeSnifferTask.php b/buildscripts/phing/classes/phing/tasks/ext/PhpCodeSnifferTask.php
new file mode 100644
index 00000000..de40ae36
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PhpCodeSnifferTask.php
@@ -0,0 +1,648 @@
+<?php
+/*
+ * $Id: 8c8f9369e06a3467e34fc8d89f6355df048ece90 $
+ *
+ * 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';
+
+/**
+ * A PHP code sniffer task. Checking the style of one or more PHP source files.
+ *
+ * @author Dirk Thomas <dirk.thomas@4wdmedia.de>
+ * @version $Id: 8c8f9369e06a3467e34fc8d89f6355df048ece90 $
+ * @package phing.tasks.ext
+ */
+class PhpCodeSnifferTask extends Task {
+
+ protected $file; // the source file (from xml attribute)
+ protected $filesets = array(); // all fileset objects assigned to this task
+
+ // parameters for php code sniffer
+ protected $standard = 'Generic';
+ protected $sniffs = array();
+ protected $showWarnings = true;
+ protected $showSources = false;
+ protected $reportWidth = 80;
+ protected $verbosity = 0;
+ protected $tabWidth = 0;
+ protected $allowedFileExtensions = array('php');
+ protected $ignorePatterns = false;
+ protected $noSubdirectories = false;
+ protected $configData = array();
+ protected $encoding = 'iso-8859-1';
+
+ // parameters to customize output
+ protected $showSniffs = false;
+ protected $format = 'default';
+ protected $formatters = array();
+
+ /**
+ * Holds the type of the doc generator
+ *
+ * @var string
+ */
+ protected $docGenerator = '';
+
+ /**
+ * Holds the outfile for the documentation
+ *
+ * @var PhingFile
+ */
+ protected $docFile = null;
+
+ private $haltonerror = false;
+ private $haltonwarning = false;
+ private $skipversioncheck = false;
+
+ /**
+ * Load the necessary environment for running PHP_CodeSniffer.
+ *
+ * @return void
+ */
+ public function init()
+ {
+ }
+
+ /**
+ * 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
+ */
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Sets the coding standard to test for
+ *
+ * @param string $standard The coding standard
+ *
+ * @return void
+ */
+ public function setStandard($standard)
+ {
+ $this->standard = $standard;
+ }
+
+ /**
+ * Sets the sniffs which the standard should be restricted to
+ * @param string $sniffs
+ */
+ public function setSniffs($sniffs)
+ {
+ $token = ' ,;';
+ $sniff = strtok($sniffs, $token);
+ while ($sniff !== false) {
+ $this->sniffs[] = $sniff;
+ $sniff = strtok($token);
+ }
+ }
+
+ /**
+ * Sets the type of the doc generator
+ *
+ * @param string $generator HTML or Text
+ *
+ * @return void
+ */
+ public function setDocGenerator($generator)
+ {
+ $this->docGenerator = $generator;
+ }
+
+ /**
+ * Sets the outfile for the documentation
+ *
+ * @param PhingFile $file The outfile for the doc
+ *
+ * @return void
+ */
+ public function setDocFile(PhingFile $file)
+ {
+ $this->docFile = $file;
+ }
+
+ /**
+ * Sets the flag if warnings should be shown
+ * @param boolean $show
+ */
+ public function setShowWarnings($show)
+ {
+ $this->showWarnings = StringHelper::booleanValue($show);
+ }
+
+ /**
+ * Sets the flag if sources should be shown
+ *
+ * @param boolean $show Whether to show sources or not
+ *
+ * @return void
+ */
+ public function setShowSources($show)
+ {
+ $this->showSources = StringHelper::booleanValue($show);
+ }
+
+ /**
+ * Sets the width of the report
+ *
+ * @param int $width How wide the screen reports should be.
+ *
+ * @return void
+ */
+ public function setReportWidth($width)
+ {
+ $this->reportWidth = (int) $width;
+ }
+
+ /**
+ * Sets the verbosity level
+ * @param int $level
+ */
+ public function setVerbosity($level)
+ {
+ $this->verbosity = (int)$level;
+ }
+
+ /**
+ * Sets the tab width to replace tabs with spaces
+ * @param int $width
+ */
+ public function setTabWidth($width)
+ {
+ $this->tabWidth = (int)$width;
+ }
+
+ /**
+ * Sets file encoding
+ * @param string $encoding
+ */
+ public function setEncoding($encoding)
+ {
+ $this->encoding = $encoding;
+ }
+
+ /**
+ * Sets the allowed file extensions when using directories instead of specific files
+ * @param array $extensions
+ */
+ public function setAllowedFileExtensions($extensions)
+ {
+ $this->allowedFileExtensions = array();
+ $token = ' ,;';
+ $ext = strtok($extensions, $token);
+ while ($ext !== false) {
+ $this->allowedFileExtensions[] = $ext;
+ $ext = strtok($token);
+ }
+ }
+
+ /**
+ * Sets the ignore patterns to skip files when using directories instead of specific files
+ * @param array $extensions
+ */
+ public function setIgnorePatterns($patterns)
+ {
+ $this->ignorePatterns = array();
+ $token = ' ,;';
+ $pattern = strtok($patterns, $token);
+ while ($pattern !== false) {
+ $this->ignorePatterns[] = $pattern;
+ $pattern = strtok($token);
+ }
+ }
+
+ /**
+ * Sets the flag if subdirectories should be skipped
+ * @param boolean $subdirectories
+ */
+ public function setNoSubdirectories($subdirectories)
+ {
+ $this->noSubdirectories = StringHelper::booleanValue($subdirectories);
+ }
+
+ /**
+ * Creates a config parameter for this task
+ *
+ * @return Parameter The created parameter
+ */
+ public function createConfig() {
+ $num = array_push($this->configData, new Parameter());
+ return $this->configData[$num-1];
+ }
+
+ /**
+ * Sets the flag if the used sniffs should be listed
+ * @param boolean $show
+ */
+ public function setShowSniffs($show)
+ {
+ $this->showSniffs = StringHelper::booleanValue($show);
+ }
+
+ /**
+ * Sets the output format
+ * @param string $format
+ */
+ public function setFormat($format)
+ {
+ $this->format = $format;
+ }
+
+ /**
+ * Create object for nested formatter element.
+ * @return CodeSniffer_FormatterElement
+ */
+ public function createFormatter () {
+ $num = array_push($this->formatters,
+ new PhpCodeSnifferTask_FormatterElement());
+ return $this->formatters[$num-1];
+ }
+
+ /**
+ * Sets the haltonerror flag
+ * @param boolean $value
+ */
+ public function setHaltonerror($value)
+ {
+ $this->haltonerror = $value;
+ }
+
+ /**
+ * Sets the haltonwarning flag
+ * @param boolean $value
+ */
+ public function setHaltonwarning($value)
+ {
+ $this->haltonwarning = $value;
+ }
+
+ /**
+ * Sets the skipversioncheck flag
+ * @param boolean $value
+ */
+ public function setSkipVersionCheck($value)
+ {
+ $this->skipversioncheck = $value;
+ }
+
+ /**
+ * Executes PHP code sniffer against PhingFile or a FileSet
+ */
+ public function main() {
+ if (!class_exists('PHP_CodeSniffer')) {
+ @include_once 'PHP/CodeSniffer.php';
+
+ if (!class_exists('PHP_CodeSniffer')) {
+ throw new BuildException("This task requires the PHP_CodeSniffer package installed and available on the include path", $this->getLocation());
+ }
+ }
+
+ /**
+ * Determine PHP_CodeSniffer version number
+ */
+ if (!$this->skipversioncheck) {
+ preg_match('/\d\.\d\.\d/', shell_exec('phpcs --version'), $version);
+
+ if (version_compare($version[0], '1.2.2') < 0) {
+ throw new BuildException(
+ 'PhpCodeSnifferTask requires PHP_CodeSniffer version >= 1.2.2',
+ $this->getLocation()
+ );
+ }
+ }
+
+ if(!isset($this->file) and count($this->filesets) == 0) {
+ throw new BuildException("Missing either a nested fileset or attribute 'file' set");
+ }
+
+ if (PHP_CodeSniffer::isInstalledStandard($this->standard) === false) {
+ // They didn't select a valid coding standard, so help them
+ // out by letting them know which standards are installed.
+ $installedStandards = PHP_CodeSniffer::getInstalledStandards();
+ $numStandards = count($installedStandards);
+ $errMsg = '';
+
+ if ($numStandards === 0) {
+ $errMsg = 'No coding standards are installed.';
+ } else {
+ $lastStandard = array_pop($installedStandards);
+
+ if ($numStandards === 1) {
+ $errMsg = 'The only coding standard installed is ' . $lastStandard;
+ } else {
+ $standardList = implode(', ', $installedStandards);
+ $standardList .= ' and ' . $lastStandard;
+ $errMsg = 'The installed coding standards are ' . $standardList;
+ }
+ }
+
+ throw new BuildException(
+ 'ERROR: the "' . $this->standard . '" coding standard is not installed. ' . $errMsg,
+ $this->getLocation()
+ );
+ }
+
+ if (count($this->formatters) == 0) {
+ // turn legacy format attribute into formatter
+ $fmt = new PhpCodeSnifferTask_FormatterElement();
+ $fmt->setType($this->format);
+ $fmt->setUseFile(false);
+ $this->formatters[] = $fmt;
+ }
+
+ if (!isset($this->file))
+ {
+ $fileList = array();
+ $project = $this->getProject();
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($project);
+ $files = $ds->getIncludedFiles();
+ $dir = $fs->getDir($this->project)->getAbsolutePath();
+ foreach ($files as $file) {
+ $fileList[] = $dir.DIRECTORY_SEPARATOR.$file;
+ }
+ }
+ }
+
+ $cwd = getcwd();
+ // Save command line arguments because it confuses PHPCS (version 1.3.0)
+ $oldArgs = $_SERVER['argv'];
+ $_SERVER['argv'] = array();
+ $_SERVER['argc'] = 0;
+ $codeSniffer = new PHP_CodeSniffer($this->verbosity, $this->tabWidth, $this->encoding);
+ $codeSniffer->setAllowedFileExtensions($this->allowedFileExtensions);
+ if (is_array($this->ignorePatterns)) $codeSniffer->setIgnorePatterns($this->ignorePatterns);
+ foreach ($this->configData as $configData) {
+ $codeSniffer->setConfigData($configData->getName(), $configData->getValue(), true);
+ }
+
+ if ($this->file instanceof PhingFile) {
+ $codeSniffer->process($this->file->getPath(), $this->standard, $this->sniffs, $this->noSubdirectories);
+
+ } else {
+ $codeSniffer->process($fileList, $this->standard, $this->sniffs, $this->noSubdirectories);
+ }
+ // Restore command line arguments
+ $_SERVER['argv'] = $oldArgs;
+ $_SERVER['argc'] = count($oldArgs);
+ chdir($cwd);
+
+ $report = $this->printErrorReport($codeSniffer);
+
+ // generate the documentation
+ if ($this->docGenerator !== '' && $this->docFile !== null) {
+ ob_start();
+
+ $codeSniffer->generateDocs($this->standard, $this->sniffs, $this->docGenerator);
+
+ $output = ob_get_contents();
+ ob_end_clean();
+
+ // write to file
+ $outputFile = $this->docFile->getPath();
+ $check = file_put_contents($outputFile, $output);
+
+ if (is_bool($check) && !$check) {
+ throw new BuildException('Error writing doc to ' . $outputFile);
+ }
+ } elseif ($this->docGenerator !== '' && $this->docFile === null) {
+ $codeSniffer->generateDocs($this->standard, $this->sniffs, $this->docGenerator);
+ }
+
+ if ($this->haltonerror && $report['totals']['errors'] > 0)
+ {
+ throw new BuildException('phpcodesniffer detected ' . $report['totals']['errors']. ' error' . ($report['totals']['errors'] > 1 ? 's' : ''));
+ }
+
+ if ($this->haltonwarning && $report['totals']['warnings'] > 0)
+ {
+ throw new BuildException('phpcodesniffer detected ' . $report['totals']['warnings'] . ' warning' . ($report['totals']['warnings'] > 1 ? 's' : ''));
+ }
+ }
+
+ /**
+ * Prints the error report.
+ *
+ * @param PHP_CodeSniffer $phpcs The PHP_CodeSniffer object containing
+ * the errors.
+ *
+ * @return int The number of error and warning messages shown.
+ */
+ protected function printErrorReport($phpcs)
+ {
+ if ($this->showSniffs) {
+ $sniffs = $phpcs->getSniffs();
+ $sniffStr = '';
+ foreach ($sniffs as $sniff) {
+ $sniffStr .= '- ' . $sniff.PHP_EOL;
+ }
+ $this->log('The list of used sniffs (#' . count($sniffs) . '): ' . PHP_EOL . $sniffStr, Project::MSG_INFO);
+ }
+
+ $filesViolations = $phpcs->getFilesErrors();
+ $reporting = new PHP_CodeSniffer_Reporting();
+ $report = $reporting->prepare($filesViolations, $this->showWarnings);
+
+ // process output
+ foreach ($this->formatters as $fe) {
+ switch ($fe->getType()) {
+ case 'default':
+ // default format goes to logs, no buffering
+ $this->outputCustomFormat($report);
+ $fe->setUseFile(false);
+ break;
+
+ default:
+ $reportFile = null;
+
+ if ($fe->getUseFile()) {
+ $reportFile = $fe->getOutfile();
+ ob_start();
+ }
+
+ // Determine number of parameters required to
+ // ensure backwards compatibility
+ $rm = new ReflectionMethod('PHP_CodeSniffer_Reporting', 'printReport');
+
+ if ($rm->getNumberOfParameters() == 5) {
+ $reporting->printReport(
+ $fe->getType(),
+ $filesViolations,
+ $this->showSources,
+ $reportFile,
+ $this->reportWidth
+ );
+ } else {
+ $reporting->printReport(
+ $fe->getType(),
+ $filesViolations,
+ $this->showWarnings,
+ $this->showSources,
+ $reportFile,
+ $this->reportWidth
+ );
+ }
+
+ // reporting class uses ob_end_flush(), but we don't want
+ // an output if we use a file
+ if ($fe->getUseFile()) {
+ ob_end_clean();
+ }
+ break;
+ }
+ }
+
+ return $report;
+ }
+
+ /**
+ * Outputs the results with a custom format
+ *
+ * @param array $report Packaged list of all errors in each file
+ */
+ protected function outputCustomFormat($report) {
+ $files = $report['files'];
+ foreach ($files as $file => $attributes) {
+ $errors = $attributes['errors'];
+ $warnings = $attributes['warnings'];
+ $messages = $attributes['messages'];
+ if ($errors > 0) {
+ $this->log($file . ': ' . $errors . ' error' . ($errors > 1 ? 's' : '') . ' detected', Project::MSG_ERR);
+ $this->outputCustomFormatMessages($messages, 'ERROR');
+ } else {
+ $this->log($file . ': No syntax errors detected', Project::MSG_VERBOSE);
+ }
+ if ($warnings > 0) {
+ $this->log($file . ': ' . $warnings . ' warning' . ($warnings > 1 ? 's' : '') . ' detected', Project::MSG_WARN);
+ $this->outputCustomFormatMessages($messages, 'WARNING');
+ }
+ }
+
+ $totalErrors = $report['totals']['errors'];
+ $totalWarnings = $report['totals']['warnings'];
+ $this->log(count($files) . ' files where checked', Project::MSG_INFO);
+ if ($totalErrors > 0) {
+ $this->log($totalErrors . ' error' . ($totalErrors > 1 ? 's' : '') . ' detected', Project::MSG_ERR);
+ } else {
+ $this->log('No syntax errors detected', Project::MSG_INFO);
+ }
+ if ($totalWarnings > 0) {
+ $this->log($totalWarnings . ' warning' . ($totalWarnings > 1 ? 's' : '') . ' detected', Project::MSG_INFO);
+ }
+ }
+
+ /**
+ * Outputs the messages of a specific type for one file
+ * @param array $messages
+ * @param string $type
+ */
+ protected function outputCustomFormatMessages($messages, $type) {
+ foreach ($messages as $line => $messagesPerLine) {
+ foreach ($messagesPerLine as $column => $messagesPerColumn) {
+ foreach ($messagesPerColumn as $message) {
+ $msgType = $message['type'];
+ if ($type == $msgType) {
+ $logLevel = Project::MSG_INFO;
+ if ($msgType == 'ERROR') {
+ $logLevel = Project::MSG_ERR;
+ } else if ($msgType == 'WARNING') {
+ $logLevel = Project::MSG_WARN;
+ }
+ $text = $message['message'];
+ $string = $msgType . ' in line ' . $line . ' column ' . $column . ': ' . $text;
+ $this->log($string, $logLevel);
+ }
+ }
+ }
+ }
+ }
+
+} //end phpCodeSnifferTask
+
+/**
+ * @package phing.tasks.ext
+ */
+class PhpCodeSnifferTask_FormatterElement extends DataType {
+
+ /**
+ * Type of output to generate
+ * @var string
+ */
+ protected $type = "";
+
+ /**
+ * Output to file?
+ * @var bool
+ */
+ protected $useFile = true;
+
+ /**
+ * Output file.
+ * @var string
+ */
+ protected $outfile = "";
+
+ /**
+ * Validate config.
+ */
+ public function parsingComplete () {
+ if(empty($this->type)) {
+ throw new BuildException("Format missing required 'type' attribute.");
+ }
+ if ($useFile && empty($this->outfile)) {
+ throw new BuildException("Format requires 'outfile' attribute when 'useFile' is true.");
+ }
+
+ }
+
+ public function setType ($type) {
+ $this->type = $type;
+ }
+
+ public function getType () {
+ return $this->type;
+ }
+
+ public function setUseFile ($useFile) {
+ $this->useFile = $useFile;
+ }
+
+ public function getUseFile () {
+ return $this->useFile;
+ }
+
+ public function setOutfile ($outfile) {
+ $this->outfile = $outfile;
+ }
+
+ public function getOutfile () {
+ return $this->outfile;
+ }
+
+} //end FormatterElement
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..63ec1812
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/PhpLintTask.php
@@ -0,0 +1,278 @@
+<?php
+/*
+ * $Id: 524bae55e1007bc9778c232dd7b437964a66c5a4 $
+ *
+ * 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/util/DataStore.php';
+require_once 'phing/system/io/FileWriter.php';
+
+/**
+ * A PHP lint task. Checking syntax of one or more PHP source file.
+ *
+ * @author Knut Urdalen <knut.urdalen@telio.no>
+ * @author Stefan Priebsch <stefan.priebsch@e-novative.de>
+ * @version $Id: 524bae55e1007bc9778c232dd7b437964a66c5a4 $
+ * @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
+
+ protected $errorProperty;
+ protected $haltOnFailure = false;
+ protected $hasErrors = false;
+ protected $badFiles = array();
+ protected $interpreter = ''; // php interpreter to use for linting
+
+ protected $logLevel = Project::MSG_VERBOSE;
+
+ protected $cache = null;
+
+ protected $tofile = null;
+
+ protected $deprecatedAsError = false;
+
+ /**
+ * Initialize the interpreter with the Phing property
+ */
+ public function __construct() {
+ $this->setInterpreter(Phing::getProperty('php.interpreter'));
+ }
+
+ /**
+ * Override default php interpreter
+ * @todo Do some sort of checking if the path is correct but would
+ * require traversing the systems executeable path too
+ * @param string $sPhp
+ */
+ public function setInterpreter($sPhp) {
+ $this->Interpreter = $sPhp;
+ }
+
+ /**
+ * The haltonfailure property
+ * @param boolean $aValue
+ */
+ public function setHaltOnFailure($aValue) {
+ $this->haltOnFailure = $aValue;
+ }
+
+ /**
+ * File to be performed syntax check on
+ * @param PhingFile $file
+ */
+ public function setFile(PhingFile $file) {
+ $this->file = $file;
+ }
+
+ /**
+ * Set an property name in which to put any errors.
+ * @param string $propname
+ */
+ public function setErrorproperty($propname)
+ {
+ $this->errorProperty = $propname;
+ }
+
+ /**
+ * Whether to store last-modified times in cache
+ *
+ * @param PhingFile $file
+ */
+ public function setCacheFile(PhingFile $file)
+ {
+ $this->cache = new DataStore($file);
+ }
+
+ /**
+ * File to save error messages to
+ *
+ * @param PhingFile $file
+ */
+ public function setToFile(PhingFile $tofile)
+ {
+ $this->tofile = $tofile;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Set level of log messages generated (default = info)
+ * @param string $level
+ */
+ public function setLevel($level)
+ {
+ switch ($level)
+ {
+ case "error": $this->logLevel = Project::MSG_ERR; break;
+ case "warning": $this->logLevel = Project::MSG_WARN; break;
+ case "info": $this->logLevel = Project::MSG_INFO; break;
+ case "verbose": $this->logLevel = Project::MSG_VERBOSE; break;
+ case "debug": $this->logLevel = Project::MSG_DEBUG; break;
+ }
+ }
+
+ /**
+ * Sets whether to treat deprecated warnings (introduced in PHP 5.3) as errors
+ * @param boolean $deprecatedAsError
+ */
+ public function setDeprecatedAsError($deprecatedAsError)
+ {
+ $this->deprecatedAsError = $deprecatedAsError;
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
+
+ // write list of 'bad files' to file (if specified)
+ if ($this->tofile) {
+ $writer = new FileWriter($this->tofile);
+
+ foreach ($this->badFiles as $file => $messages) {
+ foreach ($messages as $msg) {
+ $writer->write($file . "=" . $msg . PHP_EOL);
+ }
+ }
+
+ $writer->close();
+ }
+
+ $message = '';
+ foreach ($this->badFiles as $file => $messages) {
+ foreach ($messages as $msg) {
+ $message .= $file . "=" . $msg . PHP_EOL;
+ }
+ }
+
+ // save list of 'bad files' with errors to property errorproperty (if specified)
+ if ($this->errorProperty) {
+ $this->project->setProperty($this->errorProperty, $message);
+ }
+
+ if (!empty($this->cache)) {
+ $this->cache->commit();
+ }
+
+ if ($this->haltOnFailure && $this->hasErrors) {
+ throw new BuildException('Syntax error(s) in PHP files: ' . $message);
+ }
+ }
+
+ /**
+ * Performs the actual syntax check
+ *
+ * @param string $file
+ * @return void
+ */
+ protected function lint($file) {
+ $command = $this->Interpreter == ''
+ ? 'php'
+ : $this->Interpreter;
+ $command .= ' -n -l ';
+
+ if ($this->deprecatedAsError) {
+ $command .= '-d error_reporting=32767 ';
+ }
+
+ if(file_exists($file)) {
+ if(is_readable($file)) {
+ if ($this->cache)
+ {
+ $lastmtime = $this->cache->get($file);
+
+ if ($lastmtime >= filemtime($file))
+ {
+ $this->log("Not linting '" . $file . "' due to cache", Project::MSG_DEBUG);
+ return false;
+ }
+ }
+
+ $messages = array();
+ $errorCount = 0;
+
+ exec($command.'"'.$file.'" 2>&1', $messages);
+
+ for ($i = 0; $i < count($messages) - 1; $i++) {
+ $message = $messages[$i];
+ if (trim($message) == '') {
+ continue;
+ }
+
+ if ((!preg_match('/^(.*)Deprecated:/', $message) || $this->deprecatedAsError) && !preg_match('/^No syntax errors detected/', $message)) {
+ $this->log($message, Project::MSG_ERR);
+
+ if (!isset($this->badFiles[$file])) {
+ $this->badFiles[$file] = array();
+ }
+
+ array_push($this->badFiles[$file], $message);
+
+ $this->hasErrors = true;
+ $errorCount++;
+ }
+ }
+
+ if (!$errorCount) {
+ $this->log($file.': No syntax errors detected', $this->logLevel);
+
+ if ($this->cache)
+ {
+ $this->cache->put($file, filemtime($file));
+ }
+ }
+ } else {
+ throw new BuildException('Permission denied: '.$file);
+ }
+ } else {
+ throw new BuildException('File not found: '.$file);
+ }
+ }
+}
+
+
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ReplaceRegexpTask.php b/buildscripts/phing/classes/phing/tasks/ext/ReplaceRegexpTask.php
new file mode 100644
index 00000000..dc4ccbf7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ReplaceRegexpTask.php
@@ -0,0 +1,204 @@
+<?php
+/*
+ * $Id: f81043cad2c0ffe0a2571a0a8dc16a98651eac51 $
+ *
+ * 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';
+
+/**
+ * ReplaceRegExp is a directory based task for replacing the occurrence of a given regular expression with a substitution
+ * pattern in a selected file or set of files.
+ *
+ * <code>
+ * <replaceregexp file="${src}/build.properties"
+ * match="OldProperty=(.*)"
+ * replace="NewProperty=\1"
+ * byline="true"/>
+ * </code>
+ *
+ * @author Jonathan Bond-Caron <jbondc@openmv.com>
+ * @version $Id: f81043cad2c0ffe0a2571a0a8dc16a98651eac51 $
+ * @package phing.tasks.system
+ * @link http://ant.apache.org/manual/OptionalTasks/replaceregexp.html
+ */
+class ReplaceRegexpTask extends Task {
+
+ /** Single file to process. */
+ private $file;
+
+ /** Any filesets that should be processed. */
+ private $filesets = array();
+
+ /**
+ * Regular expression
+ *
+ * @var RegularExpression
+ */
+ private $_regexp;
+
+ /**
+ * File to apply regexp on
+ *
+ * @param string $path
+ */
+ public function setFile(PhingFile $path)
+ {
+ $this->file = $path;
+ }
+
+ /**
+ * Sets the regexp match pattern
+ *
+ * @param string $regexp
+ */
+ public function setMatch( $regexp )
+ {
+ $this->_regexp->setPattern( $regexp );
+ }
+
+ /**
+ * @see setMatch()
+ */
+ public function setPattern( $regexp )
+ {
+ $this->setMatch( $regexp );
+ }
+
+ /**
+ * Sets the replacement string
+ *
+ * @param string $string
+ */
+ public function setReplace( $string )
+ {
+ $this->_regexp->setReplace( $string );
+ }
+
+ /**
+ * Sets the regexp flags
+ *
+ * @param string $flags
+ */
+ public function setFlags( $flags )
+ {
+ // TODO... $this->_regexp->setFlags( $flags );
+ }
+
+ /**
+ * Match only per line
+ *
+ * @param bool $yesNo
+ */
+ public function setByline( $yesNo )
+ {
+ // TODO... $this->_regexp->
+ }
+
+ /** Nested creator, adds a set of files (nested fileset attribute). */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ public function init()
+ {
+ $this->_regexp = new RegularExpression;
+ }
+
+ public function main()
+ {
+ if ($this->file === null && empty($this->filesets)) {
+ throw new BuildException("You must specify a file or fileset(s) for the <ReplaceRegexp> 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 Regexp 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");
+
+ $filter = new FilterChain($this->project);
+
+ $r = new ReplaceRegexp;
+ $r->setRegexps(array($this->_regexp));
+
+ $filter->addReplaceRegexp($r);
+ $filters = array($filter);
+
+ 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), $filters, $this->project);
+ while(-1 !== ($buffer = $in->read())) {
+ $contents .= $buffer;
+ }
+ $in->close();
+ } catch (Exception $e) {
+ if ($in) $in->close();
+ $this->log("Error 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 regexp 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);
+ }
+
+ }
+
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ScpTask.php b/buildscripts/phing/classes/phing/tasks/ext/ScpTask.php
new file mode 100644
index 00000000..f6ceadd1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ScpTask.php
@@ -0,0 +1,380 @@
+<?php
+/*
+ * $Id: 300efdab5b721c6312491450bc2ba93ffc8124b4 $
+ *
+ * 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';
+
+/**
+ * Copy files to and from a remote host using scp.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Johan Van den Brande <johan@vandenbrande.com>
+ * @version $Id: 300efdab5b721c6312491450bc2ba93ffc8124b4 $
+ * @package phing.tasks.ext
+ */
+
+class ScpTask extends Task
+{
+ protected $file = "";
+ protected $filesets = array(); // all fileset objects assigned to this task
+ protected $todir = "";
+ protected $mode = null;
+
+ protected $host = "";
+ protected $port = 22;
+ protected $username = "";
+ protected $password = "";
+ protected $autocreate = true;
+ protected $fetch = false;
+ protected $localEndpoint = "";
+ protected $remoteEndpoint = "";
+
+ protected $pubkeyfile = '';
+ protected $privkeyfile = '';
+ protected $privkeyfilepassphrase = '';
+
+ protected $connection = null;
+ protected $sftp = null;
+
+ protected $count = 0;
+
+ protected $logLevel = Project::MSG_VERBOSE;
+
+ /**
+ * Sets the remote host
+ */
+ public function setHost($h)
+ {
+ $this->host = $h;
+ }
+
+ /**
+ * Returns the remote host
+ */
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ /**
+ * Sets the remote host port
+ */
+ public function setPort($p)
+ {
+ $this->port = $p;
+ }
+
+ /**
+ * Returns the remote host port
+ */
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ /**
+ * Sets the mode value
+ */
+ public function setMode($value)
+ {
+ $this->mode = $value;
+ }
+
+ /**
+ * Returns the mode value
+ */
+ public function getMode()
+ {
+ return $this->mode;
+ }
+
+ /**
+ * Sets the username of the user to scp
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+ /**
+ * Returns the username
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Sets the password of the user to scp
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+
+ /**
+ * Returns the password
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Sets the public key file of the user to scp
+ */
+ public function setPubkeyfile($pubkeyfile)
+ {
+ $this->pubkeyfile = $pubkeyfile;
+ }
+
+ /**
+ * Returns the pubkeyfile
+ */
+ public function getPubkeyfile()
+ {
+ return $this->pubkeyfile;
+ }
+
+ /**
+ * Sets the private key file of the user to scp
+ */
+ public function setPrivkeyfile($privkeyfile)
+ {
+ $this->privkeyfile = $privkeyfile;
+ }
+
+ /**
+ * Returns the private keyfile
+ */
+ public function getPrivkeyfile()
+ {
+ return $this->privkeyfile;
+ }
+
+ /**
+ * Sets the private key file passphrase of the user to scp
+ */
+ public function setPrivkeyfilepassphrase($privkeyfilepassphrase)
+ {
+ $this->privkeyfilepassphrase = $privkeyfilepassphrase;
+ }
+
+ /**
+ * Returns the private keyfile passphrase
+ */
+ public function getPrivkeyfilepassphrase($privkeyfilepassphrase)
+ {
+ return $this->privkeyfilepassphrase;
+ }
+
+ /**
+ * Sets whether to autocreate remote directories
+ */
+ public function setAutocreate($autocreate)
+ {
+ $this->autocreate = (bool) $autocreate;
+ }
+
+ /**
+ * Returns whether to autocreate remote directories
+ */
+ public function getAutocreate()
+ {
+ return $this->autocreate;
+ }
+
+ /**
+ * Set destination directory
+ */
+ public function setTodir($todir)
+ {
+ $this->todir = $todir;
+ }
+
+ /**
+ * Returns the destination directory
+ */
+ public function getTodir()
+ {
+ return $this->todir;
+ }
+
+ /**
+ * Sets local filename
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Returns local filename
+ */
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+ /**
+ * Sets whether to send (default) or fetch files
+ */
+ public function setFetch($fetch)
+ {
+ $this->fetch = (bool) $fetch;
+ }
+
+ /**
+ * Returns whether to send (default) or fetch files
+ */
+ public function getFetch()
+ {
+ return $this->fetch;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Set level of log messages generated (default = verbose)
+ * @param string $level
+ */
+ public function setLevel($level)
+ {
+ switch ($level)
+ {
+ case "error": $this->logLevel = Project::MSG_ERR; break;
+ case "warning": $this->logLevel = Project::MSG_WARN; break;
+ case "info": $this->logLevel = Project::MSG_INFO; break;
+ case "verbose": $this->logLevel = Project::MSG_VERBOSE; break;
+ case "debug": $this->logLevel = Project::MSG_DEBUG; break;
+ }
+ }
+
+ public function init()
+ {
+ }
+
+ public function main()
+ {
+ if (!function_exists('ssh2_connect')) {
+ throw new BuildException("To use ScpTask, you need to install the PHP SSH2 extension.");
+ }
+
+ if ($this->file == "" && empty($this->filesets)) {
+ throw new BuildException("Missing either a nested fileset or attribute 'file'");
+ }
+
+ if ($this->host == "" || $this->username == "") {
+ throw new BuildException("Attribute 'host' and 'username' must be set");
+ }
+
+ $this->connection = ssh2_connect($this->host, $this->port);
+ if (is_null($this->connection)) {
+ throw new BuildException("Could not establish connection to " . $this->host . ":" . $this->port . "!");
+ }
+
+ $could_auth = null;
+ if ( $this->pubkeyfile ) {
+ $could_auth = ssh2_auth_pubkey_file($this->connection, $this->username, $this->pubkeyfile, $this->privkeyfile, $this->privkeyfilepassphrase);
+ } else {
+ $could_auth = ssh2_auth_password($this->connection, $this->username, $this->password);
+ }
+ if (!$could_auth) {
+ throw new BuildException("Could not authenticate connection!");
+ }
+
+ // prepare sftp resource
+ if ($this->autocreate) {
+ $this->sftp = ssh2_sftp($this->connection);
+ }
+
+ if ($this->file != "") {
+ $this->copyFile($this->file, basename($this->file));
+ } else {
+ if ($this->fetch) {
+ throw new BuildException("Unable to use filesets to retrieve files from remote server");
+ }
+
+ foreach($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $files = $ds->getIncludedFiles();
+ $dir = $fs->getDir($this->project)->getPath();
+ foreach($files as $file) {
+ $path = $dir.DIRECTORY_SEPARATOR.$file;
+
+ // Translate any Windows paths
+ $this->copyFile($path, strtr($file, '\\', '/'));
+ }
+ }
+ }
+
+ $this->log("Copied " . $this->counter . " file(s) " . ($this->fetch ? "from" : "to") . " '" . $this->host . "'");
+
+ // explicitly close ssh connection
+ @ssh2_exec($this->connection, 'exit');
+ }
+
+ protected function copyFile($local, $remote)
+ {
+ $path = rtrim($this->todir, "/") . "/";
+
+ if ($this->fetch) {
+ $localEndpoint = $path . $remote;
+ $remoteEndpoint = $local;
+
+ $this->log('Will fetch ' . $remoteEndpoint . ' to ' . $localEndpoint, $this->logLevel);
+
+ $ret = @ssh2_scp_recv($this->connection, $remoteEndpoint, $localEndpoint);
+
+ if ($ret === false) {
+ throw new BuildException("Could not fetch remote file '" . $remoteEndpoint . "'");
+ }
+ } else {
+ $localEndpoint = $local;
+ $remoteEndpoint = $path . $remote;
+
+ if ($this->autocreate) {
+ ssh2_sftp_mkdir($this->sftp, dirname($remoteEndpoint), (is_null($this->mode) ? 0777 : $this->mode), true);
+ }
+
+ $this->log('Will copy ' . $localEndpoint . ' to ' . $remoteEndpoint, $this->logLevel);
+
+ if (!is_null($this->mode)) {
+ $ret = @ssh2_scp_send($this->connection, $localEndpoint, $remoteEndpoint, $this->mode);
+ } else {
+ $ret = @ssh2_scp_send($this->connection, $localEndpoint, $remoteEndpoint);
+ }
+
+ if ($ret === false) {
+ throw new BuildException("Could not create remote file '" . $remoteEndpoint . "'");
+ }
+ }
+
+ $this->counter++;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon.php b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon.php
new file mode 100644
index 00000000..6e8fa8e0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon.php
@@ -0,0 +1,120 @@
+<?php
+
+/*
+ * $Id: 81e9d8cbc94bac15a6a32ed0bb23c04d2b0ff439 $
+ *
+ * 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 Service_Amazon class.
+ *
+ * Implements common methods & properties used by all Amazon services
+ *
+ * @extends Task
+ * @version $ID$
+ * @package phing.tasks.ext
+ * @author Andrei Serdeliuc <andrei@serdeliuc.ro>
+ * @abstract
+ */
+abstract class Service_Amazon extends Task
+{
+ /**
+ * Collection of set options
+ *
+ * We set these magically so we can also load then from the environment
+ *
+ * (default value: array())
+ *
+ * @var array
+ * @access protected
+ */
+ protected $_options = array();
+
+ public function __set($var, $val)
+ {
+ $this->_options[$var] = $val;
+ }
+
+ /**
+ * Property getter
+ *
+ * If the property hasn't been previously set (through the task call normally),
+ * it will try to load it from the project
+ *
+ * This way, we can define global properties for the "Amazon" service, like key and secret
+ *
+ * @access public
+ * @param mixed $var
+ * @return void
+ */
+ public function __get($var)
+ {
+ if(!isset($this->$var)) {
+ if(!($val = $this->getProject()->getProperty('amazon.' . strtolower($var)))) {
+ return false;
+ } else {
+ return $val;
+ }
+ }
+
+ return $this->_options[$var];
+ }
+
+ public function __isset($var)
+ {
+ return array_key_exists($var, $this->_options);
+ }
+
+ public function setKey($key)
+ {
+ if(empty($key) || !is_string($key)) {
+ throw new BuildException('Key must be a non empty string');
+ }
+
+ $this->key = $key;
+ }
+
+ public function getKey()
+ {
+ if(!($key = $this->key)) {
+ throw new BuildException('Key is not set');
+ }
+
+ return $key;
+ }
+
+ public function setSecret($secret)
+ {
+ if(empty($secret) || !is_string($secret)) {
+ throw new BuildException('Secret must be a non empty string');
+ }
+
+ $this->secret = $secret;
+ }
+
+ public function getSecret()
+ {
+ if(!($secret = $this->secret)) {
+ throw new BuildException('Secret is not set');
+ }
+
+ return $this->secret;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3.php b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3.php
new file mode 100644
index 00000000..7bed642e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3.php
@@ -0,0 +1,188 @@
+<?php
+
+/*
+ * $Id: a205dcffd1f42b70a8101808242d66620e3dabbd $
+ *
+ * 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 dirname(dirname(__FILE__)) . "/Amazon.php";
+
+/**
+ * Abstract Service_Amazon_S3 class.
+ *
+ * Provides common methods and properties to all of the S3 tasks
+ *
+ * @extends Service_Amazon
+ * @version $ID$
+ * @package phing.tasks.ext
+ * @author Andrei Serdeliuc <andrei@serdeliuc.ro>
+ * @abstract
+ */
+abstract class Service_Amazon_S3 extends Service_Amazon
+{
+ /**
+ * Services_Amazon_S3 client
+ *
+ * (default value: null)
+ *
+ * @var Services_Amazon_S3
+ * @see Services_Amazon_S3
+ * @access protected
+ */
+ protected $_client = null;
+
+ /**
+ * We only instantiate the client once per task call
+ *
+ * @access public
+ * @return Services_Amazon_S3
+ */
+ public function getClient()
+ {
+ require_once "Services/Amazon/S3.php";
+
+ if($this->_client === null) {
+ $this->_client = Services_Amazon_S3::getAccount($this->getKey(), $this->getSecret());
+ }
+
+ return $this->_client;
+ }
+
+ public function setBucket($bucket)
+ {
+ if(empty($bucket) || !is_string($bucket)) {
+ throw new BuildException('Bucket must be a non-empty string');
+ }
+
+ $this->bucket = (string) $bucket;
+ }
+
+ public function getBucket()
+ {
+ if(!($bucket = $this->bucket)) {
+ throw new BuildException('Bucket is not set');
+ }
+
+ return $this->bucket;
+ }
+
+ /**
+ * Returns an instance of Services_Amazon_S3_Resource_Object
+ *
+ * @access public
+ * @param mixed $object
+ * @return Services_Amazon_S3_Resource_Object
+ */
+ public function getObjectInstance($object)
+ {
+ return $this->getBucketInstance()->getObject($object);
+ }
+
+ /**
+ * Check if the object already exists in the current bucket
+ *
+ * @access public
+ * @param mixed $object
+ * @return bool
+ */
+ public function isObjectAvailable($object)
+ {
+ return (bool) $this->getObjectInstance($object)->load(Services_Amazon_S3_Resource_Object::LOAD_METADATA_ONLY);
+ }
+
+ /**
+ * Returns an instance of Services_Amazon_S3_Resource_Bucket
+ *
+ * @access public
+ * @return Services_Amazon_S3_Resource_Bucket
+ */
+ public function getBucketInstance()
+ {
+ return $this->getClient()->getBucket($this->getBucket());
+ }
+
+ /**
+ * Check if the current bucket is available
+ *
+ * @access public
+ * @return bool
+ */
+ public function isBucketAvailable()
+ {
+ return (bool) $this->getBucketInstance($this->getBucket())->load();
+ }
+
+ /**
+ * Get the contents of an object (by it's name)
+ *
+ * @access public
+ * @param string $object
+ * @return mixed
+ */
+ public function getObjectContents($object)
+ {
+ if(!$this->isBucketAvailable($this->getBucket())) {
+ throw new BuildException('Bucket doesn\'t exist or wrong permissions');
+ }
+
+ $bucket = $this->getClient()->getBucket($this->getBucket());
+ if(!$this->isObjectAvailable($object)) {
+ throw new BuildException('Object not available: ' . $object);
+ }
+
+ $object = $this->getObjectInstance($object);
+ $object->load();
+ return $object->data;
+ }
+
+ /**
+ * Create a bucket
+ *
+ * @access public
+ * @return void
+ */
+ public function createBucket()
+ {
+ $bucket = $this->getBucketInstance();
+ $bucket->name = $this->getBucket();
+ $bucket->save();
+
+ return $this->isBucketAvailable();
+ }
+
+ /**
+ * Main entry point, doesn't do anything
+ *
+ * @access public
+ * @final
+ * @return void
+ */
+ final public function main()
+ {
+ $this->execute();
+ }
+
+ /**
+ * Entry point to children tasks
+ *
+ * @access public
+ * @abstract
+ * @return void
+ */
+ abstract public function execute();
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3GetTask.php b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3GetTask.php
new file mode 100644
index 00000000..37b4e817
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3GetTask.php
@@ -0,0 +1,108 @@
+<?php
+
+/*
+ * $Id: 214ed107be71d8dbc0f68ffc90bfd8b11a76b36d $
+ *
+ * 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 dirname(dirname(__FILE__)) . '/S3.php';
+
+/**
+ * Downloads an object off S3
+ *
+ * @version $Id: 214ed107be71d8dbc0f68ffc90bfd8b11a76b36d $
+ * @package phing.tasks.ext
+ * @author Andrei Serdeliuc <andrei@serdeliuc.ro>
+ * @extends Service_Amazon_S3
+ */
+class S3GetTask extends Service_Amazon_S3
+{
+ /**
+ * This is where we'll store the object
+ *
+ * (default value: null)
+ *
+ * @var mixed
+ * @access protected
+ */
+ protected $_target = null;
+
+ /**
+ * The S3 object we're working with
+ *
+ * (default value: null)
+ *
+ * @var mixed
+ * @access protected
+ */
+ protected $_object = null;
+
+ public function setObject($object)
+ {
+ if(empty($object) || !is_string($object)) {
+ throw new BuildException('Object must be a non-empty string');
+ }
+
+ $this->_object = $object;
+ }
+
+ public function getObject()
+ {
+ if($this->_object === null) {
+ throw new BuildException('Object is not set');
+ }
+
+ return $this->_object;
+ }
+
+ public function setTarget($target)
+ {
+ if(!is_file($target) && !is_dir($target) && !is_link($target)) {
+ if(!is_writable(dirname($target))) {
+ throw new BuildException('Target is not writable: ' . $target);
+ }
+ } else {
+ if(!is_writable($target)) {
+ throw new BuildException('Target is not writable: ' . $target);
+ }
+ }
+
+ $this->_target = $target;
+ }
+
+ public function getTarget()
+ {
+ if($this->_target === null) {
+ throw new BuildException('Target is not set');
+ }
+
+ return $this->_target;
+ }
+
+ public function execute()
+ {
+ $target = $this->getTarget();
+
+ // Use the object name as the target if the current target is a directory
+ if(is_dir($target)) {
+ $target = rtrim($target, '/') . '/' . $this->getObject();
+ }
+
+ file_put_contents($target, $this->getObjectContents($this->getObject()));
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3PutTask.php b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3PutTask.php
new file mode 100644
index 00000000..dbb18b56
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3PutTask.php
@@ -0,0 +1,243 @@
+<?php
+/*
+ * $Id: 84b1d6039427591cbf43dbe1a82691063ae4238a $
+ *
+ * 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 dirname(dirname(__FILE__)) . '/S3.php';
+
+/**
+ * Stores an object on S3
+ *
+ * @version $Id: 84b1d6039427591cbf43dbe1a82691063ae4238a $
+ * @package phing.tasks.ext
+ * @author Andrei Serdeliuc <andrei@serdeliuc.ro>
+ * @extends Service_Amazon_S3
+ */
+class S3PutTask extends Service_Amazon_S3
+{
+ /**
+ * File we're trying to upload
+ *
+ * (default value: null)
+ *
+ * @var string
+ * @access protected
+ */
+ protected $_source = null;
+
+ /**
+ * Content we're trying to upload
+ *
+ * The user can specify either a file to upload or just a bit of content
+ *
+ * (default value: null)
+ *
+ * @var mixed
+ * @access protected
+ */
+ protected $_content = null;
+
+ /**
+ * Collection of filesets
+ * Used for uploading multiple files
+ *
+ * (default value: array())
+ *
+ * @var array
+ * @access protected
+ */
+ protected $_filesets = array();
+
+ /**
+ * Whether to try to create buckets or not
+ *
+ * (default value: false)
+ *
+ * @var bool
+ * @access protected
+ */
+ protected $_createBuckets = false;
+
+ public function setSource($source)
+ {
+ if(!is_readable($source)) {
+ throw new BuildException('Source is not readable: ' . $source);
+ }
+
+ $this->_source = $source;
+ }
+
+ public function getSource()
+ {
+ if($this->_source === null) {
+ throw new BuildException('Source is not set');
+ }
+
+ return $this->_source;
+ }
+
+ public function setContent($content)
+ {
+ if(empty($content) || !is_string($content)) {
+ throw new BuildException('Content must be a non-empty string');
+ }
+
+ $this->_content = $content;
+ }
+
+ public function getContent()
+ {
+ if($this->_content === null) {
+ throw new BuildException('Content is not set');
+ }
+
+ return $this->_content;
+ }
+
+ public function setObject($object)
+ {
+ if(empty($object) || !is_string($object)) {
+ throw new BuildException('Object must be a non-empty string');
+ }
+
+ $this->_object = $object;
+ }
+
+ public function getObject()
+ {
+ if($this->_object === null) {
+ throw new BuildException('Object is not set');
+ }
+
+ return $this->_object;
+ }
+
+ public function setCreateBuckets($createBuckets)
+ {
+ $this->_createBuckets = (bool) $createBuckets;
+ }
+
+ public function getCreateBuckets()
+ {
+ return (bool) $this->_createBuckets;
+ }
+
+ /**
+ * creator for _filesets
+ *
+ * @access public
+ * @return FileSet
+ */
+ public function createFileset()
+ {
+ $num = array_push($this->_filesets, new FileSet());
+ return $this->_filesets[$num-1];
+ }
+
+ /**
+ * getter for _filesets
+ *
+ * @access public
+ * @return array
+ */
+ public function getFilesets()
+ {
+ return $this->_filesets;
+ }
+
+ /**
+ * Determines what we're going to store in the object
+ *
+ * If _content has been set, this will get stored,
+ * otherwise, we read from _source
+ *
+ * @access public
+ * @return string
+ */
+ public function getObjectData()
+ {
+ try {
+ $content = $this->getContent();
+ } catch(BuildException $e) {
+ $source = $this->getSource();
+
+ if(!is_file($source)) {
+ throw new BuildException('Currently only files can be used as source');
+ }
+
+ $content = file_get_contents($source);
+ }
+
+ return $content;
+ }
+
+ /**
+ * Store the object on S3
+ *
+ * @access public
+ * @return void
+ */
+ public function execute()
+ {
+ if(!$this->isBucketAvailable()) {
+ if(!$this->getCreateBuckets()) {
+ throw new BuildException('Bucket doesn\'t exist and createBuckets not specified');
+ } else{
+ if(!$this->createBucket()) {
+ throw new BuildException('Bucket cannot be created');
+ }
+ }
+ }
+
+ // Filesets take precedence
+ if(!empty($this->_filesets)) {
+ $objects = array();
+
+ foreach($this->_filesets as $fs) {
+ if(!($fs instanceof FileSet)) {
+ continue;
+ }
+
+ $ds = $fs->getDirectoryScanner($this->getProject());
+ $objects = array_merge($objects, $ds->getIncludedFiles());
+ }
+
+ $fromDir = $fs->getDir($this->getProject())->getAbsolutePath();
+
+ foreach($objects as $object) {
+ $this->saveObject($object, file_get_contents($fromDir . DIRECTORY_SEPARATOR . $object));
+ }
+
+ return true;
+ }
+
+ $this->saveObject($this->getObject(), $this->getObjectData());
+ }
+
+ protected function saveObject($object, $data)
+ {
+ $object = $this->getObjectInstance($object);
+ $object->data = $data;
+ $object->save();
+
+ if(!$this->isObjectAvailable($object->key)) {
+ throw new BuildException('Upload failed');
+ }
+ }
+} \ 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..69c7b8f8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/SmartyTask.php
@@ -0,0 +1,610 @@
+<?php
+
+/*
+ * $Id: 1fe8b2aa2668db628554e59b3099520c0e1c03e4 $
+ *
+ * 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: 1fe8b2aa2668db628554e59b3099520c0e1c03e4 $
+ * @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($this->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/SshTask.php b/buildscripts/phing/classes/phing/tasks/ext/SshTask.php
new file mode 100644
index 00000000..9c2349a8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/SshTask.php
@@ -0,0 +1,224 @@
+<?php
+/*
+ * $Id: e0fe77ed287d359bd7449d459769370e6192417f $
+ *
+ * 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';
+
+/**
+ * Execute commands on a remote host using ssh.
+ *
+ * @author Johan Van den Brande <johan@vandenbrande.com>
+ * @version $Id: e0fe77ed287d359bd7449d459769370e6192417f $
+ * @package phing.tasks.ext
+ */
+class SshTask extends Task {
+
+ private $host = "";
+ private $port = 22;
+ private $username = "";
+ private $password = "";
+ private $command = "";
+ private $pubkeyfile = '';
+ private $privkeyfile = '';
+ private $privkeyfilepassphrase = '';
+
+ /**
+ * The name of the property to capture (any) output of the command
+ * @var string
+ */
+ private $property = "";
+
+ /**
+ * Whether to display the output of the command
+ * @var boolean
+ */
+ private $display = true;
+
+ public function setHost($host)
+ {
+ $this->host = $host;
+ }
+
+ public function getHost()
+ {
+ return $this->host;
+ }
+
+ public function setPort($port)
+ {
+ $this->port = $port;
+ }
+
+ public function getPort()
+ {
+ return $this->port;
+ }
+
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Sets the public key file of the user to scp
+ */
+ public function setPubkeyfile($pubkeyfile)
+ {
+ $this->pubkeyfile = $pubkeyfile;
+ }
+
+ /**
+ * Returns the pubkeyfile
+ */
+ public function getPubkeyfile()
+ {
+ return $this->pubkeyfile;
+ }
+
+ /**
+ * Sets the private key file of the user to scp
+ */
+ public function setPrivkeyfile($privkeyfile)
+ {
+ $this->privkeyfile = $privkeyfile;
+ }
+
+ /**
+ * Returns the private keyfile
+ */
+ public function getPrivkeyfile()
+ {
+ return $this->privkeyfile;
+ }
+
+ /**
+ * Sets the private key file passphrase of the user to scp
+ */
+ public function setPrivkeyfilepassphrase($privkeyfilepassphrase)
+ {
+ $this->privkeyfilepassphrase = $privkeyfilepassphrase;
+ }
+
+ /**
+ * Returns the private keyfile passphrase
+ */
+ public function getPrivkeyfilepassphrase($privkeyfilepassphrase)
+ {
+ return $this->privkeyfilepassphrase;
+ }
+
+ public function setCommand($command)
+ {
+ $this->command = $command;
+ }
+
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ /**
+ * Sets the name of the property to capture (any) output of the command
+ * @param string $property
+ */
+ public function setProperty($property)
+ {
+ $this->property = $property;
+ }
+
+ /**
+ * Sets whether to display the output of the command
+ * @param boolean $display
+ */
+ public function setDisplay($display)
+ {
+ $this->display = (boolean) $display;
+ }
+
+ public function init()
+ {
+ }
+
+ public function main()
+ {
+ if (!function_exists('ssh2_connect')) {
+ throw new BuildException("To use SshTask, you need to install the PHP SSH2 extension.");
+ }
+
+ $this->connection = ssh2_connect($this->host, $this->port);
+ if (is_null($this->connection)) {
+ throw new BuildException("Could not establish connection to " . $this->host . ":" . $this->port . "!");
+ }
+
+ $could_auth = null;
+ if ( $this->pubkeyfile ) {
+ $could_auth = ssh2_auth_pubkey_file($this->connection, $this->username, $this->pubkeyfile, $this->privkeyfile, $this->privkeyfilepassphrase);
+ } else {
+ $could_auth = ssh2_auth_password($this->connection, $this->username, $this->password);
+ }
+ if (!$could_auth) {
+ throw new BuildException("Could not authenticate connection!");
+ }
+
+ $stream = ssh2_exec($this->connection, $this->command);
+ if (!$stream) {
+ throw new BuildException("Could not execute command!");
+ }
+
+ $this->log("Executing command {$this->command}", Project::MSG_VERBOSE);
+
+ stream_set_blocking($stream, true);
+ $result = stream_get_contents($stream);
+
+ if (!strlen($result)) {
+ $stderr_stream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
+ stream_set_blocking($stderr_stream, true);
+ $result = stream_get_contents($stderr_stream);
+ }
+
+ if ($this->display) {
+ print($result);
+ }
+
+ if (!empty($this->property)) {
+ $this->project->setProperty($this->property, $result);
+ }
+
+ fclose($stream);
+ if (isset($stderr_stream)) {
+ fclose($stderr_stream);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/Arg.php b/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/Arg.php
new file mode 100644
index 00000000..564fdef4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/Arg.php
@@ -0,0 +1,96 @@
+<?php
+require_once "phing/types/DataType.php";
+
+
+/**
+ * Implementation of console argument
+ *
+ * @author nuno costa <nuno@francodacosta.com>
+ * @license GPL
+ */
+class Arg extends DataType
+{
+ private $name = null;
+ private $value = null;
+ private $quotes = false;
+
+ /**
+ * Gets the argment name
+ * @return String
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets the argument name
+ * @param String $name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Gets the argument value
+ * @return String
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Sets the argument value
+ * @param String $value
+ */
+ public function setValue($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Should the argument value be enclosed in double quotes
+ * @return boolean
+ */
+ public function getQuotes()
+ {
+ return $this->quotes;
+ }
+
+ /**
+ * Should the argument value be enclosed in double quotes
+ * @param boolean $quotes
+ */
+ public function setQuotes( $quotes)
+ {
+ $this->quotes = $quotes;
+ }
+
+ /**
+ * Transforms the argument object into a string, takes into consideration
+ * the quotes and the argument value
+ * @return String
+ */
+ public function __toString()
+ {
+ $name = "";
+ $value = "";
+ $quote = $this->getQuotes() ? '"' : '';
+
+ if (!is_null($this->getValue())) {
+ $value = $quote . $this->getValue() . $quote ;
+ }
+
+ if (!is_null($this->getName())) {
+ $name = '--' . $this->getName();
+ }
+
+ if (strlen($name) > 0 && strlen($value) > 0) {
+ $value = '=' . $value;
+ }
+ return $name . ' ' . $value;
+ }
+
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/SymfonyConsoleTask.php b/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/SymfonyConsoleTask.php
new file mode 100644
index 00000000..64c1f02b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/SymfonyConsoleTask.php
@@ -0,0 +1,113 @@
+<?php
+require_once "phing/Task.php";
+require_once dirname(__FILE__) . "/Arg.php";
+/**
+ * Symfony Console Task
+ * @author nuno costa <nuno@francodacosta.com>
+ * @license GPL
+ *
+ */
+class SymfonyConsoleTask extends Task
+{
+
+ /**
+ *
+ * @var Array of Arg a collection of Arg objects
+ */
+ private $args = array();
+
+ /**
+ *
+ * @var string the Symfony console command to execute
+ */
+ private $command = null;
+
+ /**
+ *
+ * @var string path to symfony console application
+ */
+ private $console = 'app/console';
+
+
+ /**
+ * sets the symfony console command to execute
+ * @param string $command
+ */
+ public function setCommand($command)
+ {
+ $this->command = $command;
+ }
+
+ /**
+ * return the symfony console command to execute
+ * @return String
+ */
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ /**
+ * sets the path to symfony console application
+ * @param string $console
+ */
+ public function setConsole($console)
+ {
+ $this->console = $console;
+ }
+
+ /**
+ * returns the path to symfony console application
+ * @return string
+ */
+ public function getConsole()
+ {
+ return $this->console;
+ }
+
+ /**
+ * appends an arg tag to the arguments stack
+ *
+ * @return Arg Argument object
+ */
+
+ public function createArg()
+ {
+ $num = array_push($this->args, new Arg());
+ return $this->args[$num-1];
+ }
+
+ /**
+ * return the argumments passed to this task
+ * @return array of Arg()
+ */
+ public function getArgs()
+ {
+ return $this->args;
+ }
+
+
+ /**
+ * Gets the command string to be executed
+ * @return string
+ */
+ public function getCmdString() {
+ $cmd = array(
+ $this->console,
+ $this->command,
+ implode(' ', $this->args)
+ );
+ $cmd = implode(' ', $cmd);
+ return $cmd;
+ }
+ /**
+ * executes the synfony consile application
+ */
+ public function main()
+ {
+ $cmd = $this->getCmdString();
+
+ $this->log("executing $cmd");
+ passthru ($cmd);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/SymlinkTask.php b/buildscripts/phing/classes/phing/tasks/ext/SymlinkTask.php
new file mode 100644
index 00000000..57738398
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/SymlinkTask.php
@@ -0,0 +1,309 @@
+<?php
+
+/*
+ * $Id: 6efb50d5b7cb94f2f22db6e876010e718aa25b22 $
+ *
+ * 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";
+
+/**
+ * Generates symlinks based on a target / link combination.
+ * Can also symlink contents of a directory, individually
+ *
+ * Single target symlink example:
+ * <code>
+ * <symlink target="/some/shared/file" link="${project.basedir}/htdocs/my_file" />
+ * </code>
+ *
+ * Symlink entire contents of directory
+ *
+ * This will go through the contents of "/my/shared/library/*"
+ * and create a symlink for each entry into ${project.basedir}/library/
+ * <code>
+ * <symlink link="${project.basedir}/library">
+ * <fileset dir="/my/shared/library">
+ * <include name="*" />
+ * </fileset>
+ * </symlink>
+ * </code>
+ *
+ * @author Andrei Serdeliuc <andrei@serdeliuc.ro>
+ * @extends Task
+ * @version $ID$
+ * @package phing.tasks.ext
+ */
+class SymlinkTask extends Task
+{
+ /**
+ * What we're symlinking from
+ *
+ * (default value: null)
+ *
+ * @var string
+ * @access private
+ */
+ private $_target = null;
+
+ /**
+ * Symlink location
+ *
+ * (default value: null)
+ *
+ * @var string
+ * @access private
+ */
+ private $_link = null;
+
+ /**
+ * Collection of filesets
+ * Used when linking contents of a directory
+ *
+ * (default value: array())
+ *
+ * @var array
+ * @access private
+ */
+ private $_filesets = array();
+
+ /**
+ * Whether to override the symlink if it exists but points
+ * to a different location
+ *
+ * (default value: false)
+ *
+ * @var boolean
+ * @access private
+ */
+ private $_overwrite = false;
+
+ /**
+ * setter for _target
+ *
+ * @access public
+ * @param string $target
+ * @return void
+ */
+ public function setTarget($target)
+ {
+ $this->_target = $target;
+ }
+
+ /**
+ * setter for _link
+ *
+ * @access public
+ * @param string $link
+ * @return void
+ */
+ public function setLink($link)
+ {
+ $this->_link = $link;
+ }
+
+ /**
+ * creator for _filesets
+ *
+ * @access public
+ * @return FileSet
+ */
+ public function createFileset()
+ {
+ $num = array_push($this->_filesets, new FileSet());
+ return $this->_filesets[$num-1];
+ }
+
+ /**
+ * setter for _overwrite
+ *
+ * @access public
+ * @param boolean $overwrite
+ * @return void
+ */
+ public function setOverwrite($overwrite)
+ {
+ $this->_overwrite = $overwrite;
+ }
+
+ /**
+ * getter for _target
+ *
+ * @access public
+ * @return string
+ */
+ public function getTarget()
+ {
+ if($this->_target === null) {
+ throw new BuildException('Target not set');
+ }
+
+ return $this->_target;
+ }
+
+ /**
+ * getter for _link
+ *
+ * @access public
+ * @return string
+ */
+ public function getLink()
+ {
+ if($this->_link === null) {
+ throw new BuildException('Link not set');
+ }
+
+ return $this->_link;
+ }
+
+ /**
+ * getter for _filesets
+ *
+ * @access public
+ * @return array
+ */
+ public function getFilesets()
+ {
+ return $this->_filesets;
+ }
+
+ /**
+ * getter for _overwrite
+ *
+ * @access public
+ * @return boolean
+ */
+ public function getOverwrite()
+ {
+ return $this->_overwrite;
+ }
+
+ /**
+ * Generates an array of directories / files to be linked
+ * If _filesets is empty, returns getTarget()
+ *
+ * @access protected
+ * @return array|string
+ */
+ protected function getMap()
+ {
+ $fileSets = $this->getFilesets();
+
+ // No filesets set
+ // We're assuming single file / directory
+ if(empty($fileSets)) {
+ return $this->getTarget();
+ }
+
+ $targets = array();
+
+ foreach($fileSets as $fs) {
+ if(!($fs instanceof FileSet)) {
+ continue;
+ }
+
+ // We need a directory to store the links
+ if(!is_dir($this->getLink())) {
+ throw new BuildException('Link must be an existing directory when using fileset');
+ }
+
+ $fromDir = $fs->getDir($this->getProject())->getAbsolutePath();
+
+ if(!is_dir($fromDir)) {
+ $this->log('Directory doesn\'t exist: ' . $fromDir, Project::MSG_WARN);
+ continue;
+ }
+
+ $fsTargets = array();
+
+ $ds = $fs->getDirectoryScanner($this->getProject());
+
+ $fsTargets = array_merge(
+ $fsTargets,
+ $ds->getIncludedDirectories(),
+ $ds->getIncludedFiles()
+ );
+
+ // Add each target to the map
+ foreach($fsTargets as $target) {
+ if(!empty($target)) {
+ $targets[$target] = $fromDir . DIRECTORY_SEPARATOR . $target;
+ }
+ }
+ }
+
+ return $targets;
+ }
+
+ /**
+ * Main entry point for task
+ *
+ * @access public
+ * @return bool
+ */
+ public function main()
+ {
+ $map = $this->getMap();
+
+ // Single file symlink
+ if(is_string($map)) {
+ return $this->symlink($map, $this->getLink());
+ }
+
+ // Multiple symlinks
+ foreach($map as $name => $targetPath) {
+ $this->symlink($targetPath, $this->getLink() . DIRECTORY_SEPARATOR . $name);
+ }
+
+ return true;
+ }
+
+ /**
+ * Create the actual link
+ *
+ * @access protected
+ * @param string $target
+ * @param string $link
+ * @return bool
+ */
+ protected function symlink($target, $link)
+ {
+ $fs = FileSystem::getFileSystem();
+
+ if (is_link($link) && readlink($link) == $target) {
+ $this->log('Link exists: ' . $link, Project::MSG_INFO);
+ return true;
+ } elseif (file_exists($link)) {
+ if (!$this->getOverwrite()) {
+ $this->log('Not overwriting existing link ' . $link, Project::MSG_ERR);
+ return false;
+ }
+
+ if (is_link($link) || is_file($link)) {
+ $fs->unlink($link);
+ $this->log('Link removed: ' . $link, Project::MSG_INFO);
+ } else {
+ $fs->rmdir($link, true);
+ $this->log('Directory removed: ' . $link, Project::MSG_INFO);
+ }
+ }
+
+ $this->log('Linking: ' . $target . ' to ' . $link, Project::MSG_INFO);
+
+ return $fs->symlink($target, $link);
+ }
+}
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..95d915d7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/TarTask.php
@@ -0,0 +1,445 @@
+<?php
+/*
+ * $Id: c3ac5fcdf4d7cdb199d57b021e3f015c9c7fd3f8 $
+ *
+ * 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 $Id: c3ac5fcdf4d7cdb199d57b021e3f015c9c7fd3f8 $
+ * @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 $includeEmpty = true; // Whether to include empty dirs in the TAR
+
+ 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;
+
+ /**
+ * File path prefix in the tar archive
+ *
+ * @var string
+ */
+ private $prefix = 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 the include empty dirs flag.
+ * @param boolean Flag if empty dirs should be tarred too
+ * @return void
+ * @access public
+ */
+ public function setIncludeEmptyDirs($bool) {
+ $this->includeEmpty = (boolean) $bool;
+ }
+
+ /**
+ * Set how to handle long files, those with a path&gt;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;
+ }
+ }
+
+ /**
+ * Sets the file path prefix for file in the tar file.
+ *
+ * @param string $prefix Prefix
+ *
+ * @return void
+ */
+ public function setPrefix($prefix) {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * 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 '" . (string) $this->baseDir . "' does not exist!", $this->getLocation());
+ }
+ if (empty($this->filesets)) { // if there weren't any explicit filesets specivied, then
+ // create a default, all-inclusive fileset using the specified basedir.
+ $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
+ if($this->tarFile->exists()) {
+ $upToDate = true;
+ foreach($this->filesets as $fs) {
+ $files = $fs->getFiles($this->project, $this->includeEmpty);
+ 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, $this->includeEmpty);
+ if (count($files) > 1 && strlen($fs->getFullpath()) > 0) {
+ throw new BuildException("fullpath attribute may only "
+ . "be specified for "
+ . "filesets that specify a "
+ . "single file.");
+ }
+ $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();
+ $this->log("Adding file " . $f->getPath() . " to archive.", Project::MSG_VERBOSE);
+ }
+ $tar->addModify($filesToTar, $this->prefix, $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.
+ *
+ * @package phing.tasks.ext
+ */
+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, $includeEmpty = true) {
+
+ if ($this->files === null) {
+
+ $ds = $this->getDirectoryScanner($p);
+ $this->files = $ds->getIncludedFiles();
+
+ if ($includeEmpty) {
+
+ // first any empty directories that will not be implicitly added by any of the files
+ $implicitDirs = array();
+ foreach($this->files as $file) {
+ $implicitDirs[] = dirname($file);
+ }
+
+ $incDirs = $ds->getIncludedDirectories();
+
+ // we'll need to add to that list of implicit dirs any directories
+ // that contain other *directories* (and not files), since otherwise
+ // we get duplicate directories in the resulting tar
+ foreach($incDirs as $dir) {
+ foreach($incDirs as $dircheck) {
+ if (!empty($dir) && $dir == dirname($dircheck)) {
+ $implicitDirs[] = $dir;
+ }
+ }
+ }
+
+ $implicitDirs = array_unique($implicitDirs);
+
+ // Now add any empty dirs (dirs not covered by the implicit dirs)
+ // to the files array.
+
+ foreach($incDirs as $dir) { // we cannot simply use array_diff() since we want to disregard empty/. dirs
+ if ($dir != "" && $dir != "." && !in_array($dir, $implicitDirs)) {
+ // it's an empty dir, so we'll add it.
+ $this->files[] = $dir;
+ }
+ }
+ } // if $includeEmpty
+
+ } // if ($this->files===null)
+
+ 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/UntarTask.php b/buildscripts/phing/classes/phing/tasks/ext/UntarTask.php
new file mode 100644
index 00000000..74777322
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/UntarTask.php
@@ -0,0 +1,89 @@
+<?php
+/*
+ *
+ * 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/ExtractBaseTask.php';
+
+/**
+ * Extracts one or several tar archives using PEAR Archive_Tar
+ *
+ * @author Joakim Bodin <joakim.bodin+phing@gmail.com>
+ * @version $Id: f77612833e0415725e7b816a0515db4a4f0f4c93 $
+ * @package phing.tasks.ext
+ * @since 2.2.0
+ */
+class UntarTask extends ExtractBaseTask {
+
+ /**
+ * 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 UntarTask.");
+ }
+ }
+
+ protected function extractArchive(PhingFile $tarfile)
+ {
+ $this->log("Extracting tar file: " . $tarfile->__toString() . ' to ' . $this->todir->__toString(), Project::MSG_INFO);
+
+ try {
+ $tar = $this->initTar($tarfile);
+ if(!$tar->extractModify($this->todir->getAbsolutePath(), $this->removepath)) {
+ throw new BuildException('Failed to extract tar file: ' . $tarfile->getAbsolutePath());
+ }
+ } catch (IOException $ioe) {
+ $msg = "Could not extract tar file: " . $ioe->getMessage();
+ throw new BuildException($msg, $ioe, $this->getLocation());
+ }
+ }
+
+ protected function listArchiveContent(PhingFile $tarfile)
+ {
+ $tar = $this->initTar($tarfile);
+ return $tar->listContent();
+ }
+
+ /**
+ * Init a Archive_Tar class with correct compression for the given file.
+ *
+ * @param PhingFile $tarfile
+ * @return Archive_Tar the tar class instance
+ */
+ private function initTar(PhingFile $tarfile)
+ {
+ $compression = null;
+ $tarfileName = $tarfile->getName();
+ $mode = strtolower(substr($tarfileName, strrpos($tarfileName, '.')));
+
+ $compressions = array(
+ 'gz' => array('.gz', '.tgz',),
+ 'bz2' => array('.bz2',),
+ );
+ foreach ($compressions as $algo => $ext) {
+ if (array_search($mode, $ext) !== false) {
+ $compression = $algo;
+ break;
+ }
+ }
+
+ return new Archive_Tar($tarfile->getAbsolutePath(), $compression);
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/UnzipTask.php b/buildscripts/phing/classes/phing/tasks/ext/UnzipTask.php
new file mode 100644
index 00000000..ef7c3e7d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/UnzipTask.php
@@ -0,0 +1,77 @@
+<?php
+/*
+ *
+ * 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/ExtractBaseTask.php';
+require_once 'phing/system/io/FileSystem.php';
+
+/**
+ * Extracts one or several zip archives using ZipArchive class.
+ *
+ * @author Joakim Bodin <joakim.bodin+phing@gmail.com>
+ * @author George Miroshnikov <laggy.luke@gmail.com>
+ * @version $Id: 9c4afd9af5e81250ca6c7afbc6e646c2a0f0148c $
+ * @package phing.tasks.ext
+ */
+class UnzipTask extends ExtractBaseTask
+{
+ /**
+ * Extract archive content into $this->todir directory
+ * @param PhingFile Zip file to extract
+ * @return boolean
+ */
+ protected function extractArchive(PhingFile $zipfile)
+ {
+ $this->log("Extracting zip: " . $zipfile->__toString() . ' to ' . $this->todir->__toString(), Project::MSG_INFO);
+
+ $zip = new ZipArchive();
+
+ $result = $zip->open($zipfile->getAbsolutePath());
+ if (!$result) {
+ $this->log("Unable to open zipfile " . $zipfile->__toString(), Project::MSG_ERR);
+ return false;
+ }
+
+ $result = $zip->extractTo($this->todir->getAbsolutePath());
+ if (!$result) {
+ $this->log("Unable to extract zipfile " . $zipfile->__toString(), Project::MSG_ERR);
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * List archive content
+ * @param PhingFile Zip file to list content
+ * @return array List of files inside $zipfile
+ */
+ protected function listArchiveContent(PhingFile $zipfile)
+ {
+ $zip = new ZipArchive();
+ $zip->open($zipfile->getAbsolutePath());
+
+ $content = array();
+ for ($i = 0; $i < $zip->numFiles; $i++) {
+ $content[] = $zip->getNameIndex($i);
+ }
+ return $content;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/VersionTask.php b/buildscripts/phing/classes/phing/tasks/ext/VersionTask.php
new file mode 100755
index 00000000..b8268870
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/VersionTask.php
@@ -0,0 +1,217 @@
+<?php
+/*
+ * $Id: 7fb6793b55e9c1c8c7b3cd8a87b694d720b32749 $
+ *
+ * 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';
+
+/**
+ * VersionTask
+ *
+ * Increments a three-part version number from a given file
+ * and writes it back to the file.
+ * Incrementing is based on given releasetype, which can be one
+ * of Major, Minor and Bugfix.
+ * Resulting version number is also published under supplied property.
+ *
+ * @author Mike Wittje <mw@mike.wittje.de>
+ * @version $Id: 7fb6793b55e9c1c8c7b3cd8a87b694d720b32749 $ $Rev $Id$ $Author$
+ * @package phing.tasks.ext
+ */
+class VersionTask extends Task
+{
+ /**
+ * Property for Releasetype
+ * @var string $releasetype
+ */
+ private $releasetype;
+
+ /**
+ * Property for File
+ * @var PhingFile file
+ */
+ private $file;
+
+ /**
+ * Property to be set
+ * @var string $property
+ */
+ private $property;
+
+ /* Allowed Releastypes */
+ const RELEASETYPE_MAJOR = 'MAJOR';
+ const RELEASETYPE_MINOR = 'MINOR';
+ const RELEASETYPE_BUGFIX = 'BUGFIX';
+
+ /**
+ * Set Property for Releasetype (Minor, Major, Bugfix)
+ * @param string $releasetype
+ */
+ public function setReleasetype($releasetype)
+ {
+ $this->releasetype = strtoupper($releasetype);
+ }
+
+ /**
+ * Set Property for File containing versioninformation
+ * @param PhingFile $file
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Set name of property to be set
+ * @param $property
+ * @return void
+ */
+ public function setProperty($property)
+ {
+ $this->property = $property;
+ }
+
+ /**
+ * Main-Method for the Task
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function main()
+ {
+ // check supplied attributes
+ $this->checkReleasetype();
+ $this->checkFile();
+ $this->checkProperty();
+
+ // read file
+ $filecontent = trim(file_get_contents($this->file));
+
+ // get new version
+ $newVersion = $this->getVersion($filecontent);
+
+ // write new Version to file
+ file_put_contents($this->file, $newVersion . "\n");
+
+ // publish new version number as property
+ $this->project->setProperty($this->property, $newVersion);
+
+ }
+
+ /**
+ * Returns new version number corresponding to Release type
+ *
+ * @param string $filecontent
+ * @return string
+ */
+ private function getVersion($filecontent)
+ {
+ // init
+ $newVersion = '';
+
+ // Extract version
+ list($major, $minor, $bugfix) = explode(".", $filecontent);
+
+ // Return new version number
+ switch ($this->releasetype) {
+ case self::RELEASETYPE_MAJOR:
+ $newVersion = sprintf("%d.%d.%d", ++$major,
+ 0,
+ 0);
+ break;
+
+ case self::RELEASETYPE_MINOR:
+ $newVersion = sprintf("%d.%d.%d", $major,
+ ++$minor,
+ 0);
+ break;
+
+ case self::RELEASETYPE_BUGFIX:
+ $newVersion = sprintf("%d.%d.%d", $major,
+ $minor,
+ ++$bugfix);
+ break;
+ }
+
+ return $newVersion;
+ }
+
+
+ /**
+ * checks releasetype attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkReleasetype()
+ {
+ // check Releasetype
+ if (is_null($this->releasetype)) {
+ throw new BuildException('releasetype attribute is required', $this->location);
+ }
+ // known releasetypes
+ $releaseTypes = array(
+ self::RELEASETYPE_MAJOR,
+ self::RELEASETYPE_MINOR,
+ self::RELEASETYPE_BUGFIX
+ );
+
+ if (!in_array($this->releasetype, $releaseTypes)) {
+ throw new BuildException(sprintf('Unknown Releasetype %s..Must be one of Major, Minor or Bugfix',
+ $this->releasetype), $this->location);
+ }
+ }
+
+ /**
+ * checks file attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkFile()
+ {
+ // check File
+ if ($this->file === null ||
+ strlen($this->file) == 0) {
+ throw new BuildException('You must specify a file containing the version number', $this->location);
+ }
+
+ $content = file_get_contents($this->file);
+ if (strlen($content) == 0) {
+ throw new BuildException(sprintf('Supplied file %s is empty', $this->file), $this->location);
+ }
+
+ // check for three-part number
+ $split = explode('.', $content);
+ if (count($split) !== 3) {
+ throw new BuildException('Unknown version number format', $this->location);
+ }
+
+ }
+
+ /**
+ * checks property attribute
+ * @return void
+ * @throws BuildException
+ */
+ private function checkProperty()
+ {
+ if (is_null($this->property) ||
+ strlen($this->property) === 0) {
+ throw new BuildException('Property for publishing version number is not set', $this->location);
+ }
+ }
+} \ No newline at end of file
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..15200d37
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/XmlLintTask.php
@@ -0,0 +1,179 @@
+<?php
+/*
+ * $Id: 6261b2f19844b353c379c46daf3ffb13b7a2ddb8 $
+ *
+ * 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';
+
+/**
+ * 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>
+ * @version $Id: 6261b2f19844b353c379c46daf3ffb13b7a2ddb8 $
+ * @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
+ protected $useRNG = false;
+
+ protected $haltonfailure = true;
+
+ /**
+ * 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;
+ }
+
+
+ /**
+ * Use RNG instead of DTD schema validation
+ *
+ * @param bool $bool
+ */
+ public function setUseRNG($bool) {
+ $this->useRNG = (boolean)$bool;
+ }
+
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Sets the haltonfailure attribute
+ *
+ * @param bool $haltonfailure
+ */
+ public function setHaltonfailure($haltonfailure) {
+ $this->haltonfailure = (bool) $haltonfailure;
+ }
+
+ /**
+ * Execute lint check against PhingFile or a FileSet
+ */
+ public function main() {
+ if(isset($this->schema) && !file_exists($this->schema->getPath())) {
+ throw new BuildException("Schema file not found: ".$this->schema->getPath());
+ }
+ 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();
+ }
+
+ protected function logError($message) {
+ if ($this->haltonfailure) {
+ throw new BuildException($message);
+ } else {
+ $this->log($message, Project::MSG_ERR);
+ }
+ }
+
+ /**
+ * Performs validation
+ *
+ * @param string $file
+ * @return void
+ */
+ protected function lint($file) {
+ if(file_exists($file)) {
+ if(is_readable($file)) {
+ $dom = new DOMDocument();
+ if ($dom->load($file) === false) {
+ $error = libxml_get_last_error();
+ $this->logError($file.' is not well-formed (See messages above)');
+ } else {
+ if(isset($this->schema)) {
+ if( $this->useRNG ) {
+ if($dom->relaxNGValidate($this->schema->getPath())) {
+ $this->log($file.' validated with RNG grammar', Project::MSG_INFO);
+ } else {
+ $this->logError($file.' fails to validate (See messages above)');
+ }
+ } else {
+ if($dom->schemaValidate($this->schema->getPath())) {
+ $this->log($file.' validated with schema', Project::MSG_INFO);
+ } else {
+ $this->logError($file.' fails to validate (See messages above)');
+ }
+ }
+ } else {
+ $this->log($file.' is well-formed (not validated due to missing schema specification)', Project::MSG_INFO);
+ }
+ }
+ } else {
+ $this->logError('Permission denied to read file: '.$file);
+ }
+ } else {
+ $this->logError('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);
+ }
+
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/XmlPropertyTask.php b/buildscripts/phing/classes/phing/tasks/ext/XmlPropertyTask.php
new file mode 100755
index 00000000..d32cd78e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/XmlPropertyTask.php
@@ -0,0 +1,273 @@
+<?php
+
+/*
+ * $Id: c7a3e7eff0b94828f9ec634c3612d89f2740fead $
+ *
+ * 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/tasks/system/PropertyTask.php';
+
+/**
+ * Task for setting properties from an XML file in buildfiles.
+ *
+ * @author Jonathan Bond-Caron <jbondc@openmv.com>
+ * @version $Id: c7a3e7eff0b94828f9ec634c3612d89f2740fead $
+ * @package phing.tasks.ext
+ * @since 2.4.0
+ * @link http://ant.apache.org/manual/CoreTasks/xmlproperty.html
+ */
+class XmlPropertyTask extends PropertyTask {
+
+ private $_keepRoot = true;
+ private $_collapseAttr = false;
+ private $_delimiter = ',';
+ private $_required = false;
+
+ /** Set a file to use as the source for properties. */
+ public function setFile($file) {
+ if (is_string($file)) {
+ $file = new PhingFile($file);
+ }
+ $this->file = $file;
+ }
+
+ /** Get the PhingFile that is being used as property source. */
+ public function getFile() {
+ return $this->file;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Keep the xml root tag as the first value in the property name
+ *
+ * @param bool $yesNo
+ */
+ public function setKeepRoot($yesNo) {
+ $this->_keepRoot = (bool)$yesNo;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getKeepRoot() {
+ return $this->_keepRoot;
+ }
+
+ /**
+ * Treat attributes as nested elements.
+ *
+ * @param bool $yesNo
+ */
+ public function setCollapseAttributes($yesNo) {
+ $this->_collapseAttr = (bool)$yesNo;
+ }
+
+ /**
+ * @return bool
+ */
+ public function getCollapseAttributes() {
+ return $this->_collapseAttr;
+ }
+
+ /**
+ * Delimiter for splitting multiple values.
+ *
+ * @param string $d
+ */
+ public function setDelimiter($d) {
+ $this->_delimiter = $d;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDelimiter() {
+ return $this->_delimiter;
+ }
+
+ /**
+ * File required or not.
+ *
+ * @param string $d
+ */
+ public function setRequired($d) {
+ $this->_required = $d;
+ }
+
+ /**
+ * @return string
+ */
+ public function getRequired() {
+ return $this->_required;
+ }
+
+ /**
+ * 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
+ */
+ public function main() {
+
+ if ($this->file === null ) {
+ throw new BuildException("You must specify file to load properties from", $this->getLocation());
+ }
+
+ $this->loadFile($this->file);
+ }
+
+ /**
+ * load properties from an XML 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()) {
+
+ $this->addProperties($this->_getProperties($file));
+
+ } else {
+ if ($this->getRequired()){
+ throw new BuildException("Could not load required properties file.", $ioe);
+ } 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);
+ }
+ }
+
+ /**
+ * Parses an XML file and returns properties
+ *
+ * @param string $filePath
+ *
+ * @return Properties
+ */
+ protected function _getProperties($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");
+ }
+
+ $prop = new Properties;
+
+ $xml = simplexml_load_file($filePath);
+
+ if($xml === false)
+ throw new IOException("Unable to parse XML file $filePath");
+
+ $path = array();
+
+ if($this->_keepRoot) {
+ $path[] = dom_import_simplexml($xml)->tagName;
+
+ $prefix = implode('.', $path);
+
+ if (!empty($prefix))
+ $prefix .= '.';
+
+ // Check for attributes
+ foreach($xml->attributes() as $attribute => $val) {
+ if($this->_collapseAttr)
+ $prop->setProperty($prefix . "$attribute", (string)$val);
+ else
+ $prop->setProperty($prefix . "($attribute)", (string)$val);
+ }
+ }
+
+ $this->_addNode($xml, $path, $prop);
+
+ return $prop;
+ }
+
+ /**
+ * Adds an XML node
+ *
+ * @param SimpleXMLElement $node
+ * @param array $path Path to this node
+ * @param Properties $prop Properties will be added as they are found (by reference here)
+ *
+ * @return void
+ */
+ protected function _addNode($node, $path, $prop) {
+ foreach($node as $tag => $value) {
+
+ $prefix = implode('.', $path);
+
+ if (!empty($prefix) > 0)
+ $prefix .= '.';
+
+ // Check for attributes
+ foreach($value->attributes() as $attribute => $val) {
+ if($this->_collapseAttr)
+ $prop->setProperty($prefix . "$tag.$attribute", (string)$val);
+ else
+ $prop->setProperty($prefix . "$tag($attribute)", (string)$val);
+ }
+
+ // Add tag
+ if(count($value->children())) {
+ $this->_addNode($value, array_merge($path, array($tag)), $prop);
+ } else {
+ $val = (string)$value;
+
+ /* Check for * and ** on 'exclude' and 'include' tag / ant seems to do this? could use FileSet here
+ if($tag == 'exclude') {
+ }*/
+
+ // When property already exists, i.e. multiple xml tag
+ // <project>
+ // <exclude>file/a.php</exclude>
+ // <exclude>file/a.php</exclude>
+ // </project>
+ //
+ // Would be come project.exclude = file/a.php,file/a.php
+ $p = empty($prefix) ? $tag : $prefix . $tag;
+ $prop->append($p, (string)$val, $this->_delimiter);
+ }
+ }
+ }
+}
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..5093fabe
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ZendCodeAnalyzerTask.php
@@ -0,0 +1,207 @@
+<?php
+/*
+ * $Id: 5b7e3fb304bb5f406c919407d6881449a70b8a28 $
+ *
+ * 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';
+
+/**
+ * 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@gmail.com>
+ * @version $Id: 5b7e3fb304bb5f406c919407d6881449a70b8a28 $
+ * @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 $counter = 0;
+ protected $disable = array();
+ protected $enable = array();
+
+ private $haltonwarning = false;
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Sets the haltonwarning flag
+ * @param boolean $value
+ */
+ public function setHaltonwarning($value)
+ {
+ $this->haltonwarning = $value;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @return FileSet The created fileset object
+ */
+ public 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);
+ }
+
+ $total = count($result) - 3;
+
+ if ($total > 0 && $this->haltonwarning) {
+ throw new BuildException('zendcodeanalyzer detected ' . $total . ' warning' . ($total > 1 ? 's' : '') . ' in ' . $file);
+ }
+ }
+ else
+ {
+ throw new BuildException('Permission denied: '.$file);
+ }
+ } else {
+ throw new BuildException('File not found: '.$file);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php
new file mode 100755
index 00000000..72bf42fd
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ZipTask.php
@@ -0,0 +1,301 @@
+<?php
+/*
+ * $Id: 6997b3f3abffedf1b2efabc40c3b2d012b2379cb $
+ *
+ * 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 zip archive using PHP ZipArchive extension/
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 6997b3f3abffedf1b2efabc40c3b2d012b2379cb $
+ * @package phing.tasks.ext
+ * @since 2.1.0
+ */
+class ZipTask extends MatchingTask {
+
+ /**
+ * @var PhingFile
+ */
+ private $zipFile;
+
+ /**
+ * @var PhingFile
+ */
+ private $baseDir;
+
+ /**
+ * Whether to include empty dirs in the archive.
+ */
+ private $includeEmpty = true;
+
+ private $filesets = array();
+ private $fileSetFiles = array();
+
+ /**
+ * File path prefix in zip archive
+ *
+ * @var string
+ */
+ private $prefix = null;
+
+ /**
+ * Add a new fileset.
+ * @return FileSet
+ */
+ public function createFileSet() {
+ $this->fileset = new ZipFileSet();
+ $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;
+ }
+
+ /**
+ * Sets the file path prefix for file in the zip file.
+ *
+ * @param string $prefix Prefix
+ *
+ * @return void
+ */
+ public function setPrefix($prefix) {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Set the include empty dirs flag.
+ * @param boolean Flag if empty dirs should be tarred too
+ * @return void
+ * @access public
+ */
+ public function setIncludeEmptyDirs($bool) {
+ $this->includeEmpty = (boolean) $bool;
+ }
+
+ /**
+ * 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 '" . (string) $this->baseDir . "' does not exist!", $this->getLocation());
+ }
+
+ if (empty($this->filesets))
+ {
+ // add the main fileset to the list of filesets to process.
+ $mainFileSet = new ZipFileSet($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) {
+ $files = $fs->getFiles($this->project, $this->includeEmpty);
+ 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 ZipArchive();
+ $res = $zip->open($this->zipFile->getAbsolutePath(), ZIPARCHIVE::CREATE);
+
+ if ($res !== true)
+ {
+ throw new Exception("ZipArchive::open() failed with code " . $res);
+ }
+
+ foreach($this->filesets as $fs) {
+ $fsBasedir = (null != $this->baseDir) ? $this->baseDir :
+ $fs->getDir($this->project);
+
+ $files = $fs->getFiles($this->project, $this->includeEmpty);
+
+ $filesToZip = array();
+ for ($i=0, $fcount=count($files); $i < $fcount; $i++) {
+ $f = new PhingFile($fsBasedir, $files[$i]);
+
+ $pathInZip = $this->prefix
+ . $f->getPathWithoutBase($fsBasedir);
+
+ $pathInZip = str_replace('\\', '/', $pathInZip);
+
+ if ($f->isDirectory()) {
+ if ($pathInZip != '.') {
+ $zip->addEmptyDir($pathInZip);
+ }
+ } else {
+ $zip->addFile($f->getPath(), $pathInZip);
+ }
+ $this->log("Adding " . $f->getPath() . " as " . $pathInZip . " to archive.", Project::MSG_VERBOSE);
+ }
+ }
+
+ $zip->close();
+ } 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;
+ }
+
+}
+
+
+
+
+/**
+ * This is a FileSet with the to specify permissions.
+ *
+ * Permissions are currently not implemented by PEAR Archive_Tar,
+ * but hopefully they will be in the future.
+ *
+ * @package phing.tasks.ext
+ */
+class ZipFileSet extends FileSet {
+
+ private $files = null;
+
+ /**
+ * 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, $includeEmpty = true) {
+
+ if ($this->files === null) {
+
+ $ds = $this->getDirectoryScanner($p);
+ $this->files = $ds->getIncludedFiles();
+
+ // build a list of directories implicitly added by any of the files
+ $implicitDirs = array();
+ foreach($this->files as $file) {
+ $implicitDirs[] = dirname($file);
+ }
+
+ $incDirs = $ds->getIncludedDirectories();
+
+ // we'll need to add to that list of implicit dirs any directories
+ // that contain other *directories* (and not files), since otherwise
+ // we get duplicate directories in the resulting tar
+ foreach($incDirs as $dir) {
+ foreach($incDirs as $dircheck) {
+ if (!empty($dir) && $dir == dirname($dircheck)) {
+ $implicitDirs[] = $dir;
+ }
+ }
+ }
+
+ $implicitDirs = array_unique($implicitDirs);
+
+ $emptyDirectories = array();
+
+ if ($includeEmpty) {
+ // Now add any empty dirs (dirs not covered by the implicit dirs)
+ // to the files array.
+
+ foreach($incDirs as $dir) { // we cannot simply use array_diff() since we want to disregard empty/. dirs
+ if ($dir != "" && $dir != "." && !in_array($dir, $implicitDirs)) {
+ // it's an empty dir, so we'll add it.
+ $emptyDirectories[] = $dir;
+ }
+ }
+ } // if $includeEmpty
+
+ $this->files = array_merge($implicitDirs, $emptyDirectories, $this->files);
+ sort($this->files);
+ } // if ($this->files===null)
+
+ return $this->files;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/apigen/ApiGenTask.php b/buildscripts/phing/classes/phing/tasks/ext/apigen/ApiGenTask.php
new file mode 100644
index 00000000..d8438b3e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/apigen/ApiGenTask.php
@@ -0,0 +1,439 @@
+<?php
+/*
+ * 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';
+
+/**
+ * ApiGen task (http://apigen.org).
+ *
+ * @package phing.tasks.ext.apigen
+ * @author Martin Srank <martin@smasty.net>
+ * @author Jaroslav Hanslík <kukulich@kukulich.cz>
+ * @since 2.4.10
+ */
+class ApiGenTask extends Task
+{
+ /**
+ * Default ApiGen executable name.
+ *
+ * @var string
+ */
+ private $executable = 'apigen';
+
+ /**
+ * Default options for ApiGen.
+ *
+ * @var array
+ */
+ private $options = array(
+ 'progressbar' => false,
+ 'colors' => false,
+ 'update-check' => false
+ );
+
+ /**
+ * Sets the ApiGen executable name.
+ *
+ * @param string $executable
+ */
+ public function setExecutable($executable)
+ {
+ $this->executable = (string) $executable;
+ }
+
+ /**
+ * Sets the config file name.
+ *
+ * @param string $config
+ */
+ public function setConfig($config)
+ {
+ $this->options['config'] = (string) $config;
+ }
+
+ /**
+ * Sets source files or directories.
+ *
+ * @param string $source
+ */
+ public function setSource($source)
+ {
+ $this->options['source'] = explode(',', $source);
+ }
+
+ /**
+ * Sets the destination directory.
+ *
+ * @param string $destination
+ */
+ public function setDestination($destination)
+ {
+ $this->options['destination'] = (string) $destination;
+ }
+
+ /**
+ * Sets list of allowed file extensions.
+ *
+ * @param string $extensions
+ */
+ public function setExtensions($extensions)
+ {
+ $this->options['extensions'] = explode(',', $extensions);
+ }
+
+ /**
+ * Sets masks (case sensitive) to exclude files or directories from processing.
+ *
+ * @param string $exclude
+ */
+ public function setExclude($exclude)
+ {
+ $this->options['exclude'] = explode(',', $exclude);
+ }
+
+ /**
+ * Sets masks to exclude elements from documentation generating.
+ *
+ * @param string $skipDocPath
+ */
+ public function setSkipDocPath($skipDocPath)
+ {
+ $this->options['skip-doc-path'] = explode(',', $skipDocPath);
+ }
+
+ /**
+ * Sets a name prefix to exclude elements from documentation generating.
+ *
+ * @param string $skipDocPrefix
+ */
+ public function setSkipDocPrefix($skipDocPrefix)
+ {
+ $this->options['skip-doc-prefix'] = explode(',', $skipDocPrefix);
+ }
+
+ /**
+ * Sets the character set of source files.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ $this->options['charset'] = explode(',', $charset);
+ }
+
+ /**
+ * Sets the main project name prefix.
+ *
+ * @param string $main
+ */
+ public function setMain($main)
+ {
+ $this->options['main'] = (string) $main;
+ }
+
+ /**
+ * Sets the title of generated documentation.
+ *
+ * @param string $title
+ */
+ public function setTitle($title)
+ {
+ $this->options['title'] = (string) $title;
+ }
+
+ /**
+ * Sets the documentation base URL.
+ *
+ * @param string $baseUrl
+ */
+ public function setBaseUrl($baseUrl)
+ {
+ $this->options['base-url'] = (string) $baseUrl;
+ }
+
+ /**
+ * Sets the Google Custom Search ID.
+ *
+ * @param string $googleCseId
+ */
+ public function setGoogleCseId($googleCseId)
+ {
+ $this->options['google-cse-id'] = (string) $googleCseId;
+ }
+
+ /**
+ * Sets the Google Custom Search label.
+ *
+ * @param string $googleCseLabel
+ */
+ public function setGoogleCseLabel($googleCseLabel)
+ {
+ $this->options['google-cse-label'] = (string) $googleCseLabel;
+ }
+
+ /**
+ * Sets the Google Analytics tracking code.
+ *
+ * @param string $googleAnalytics
+ */
+ public function setGoogleAnalytics($googleAnalytics)
+ {
+ $this->options['google-analytics'] = (string) $googleAnalytics;
+ }
+
+ /**
+ * Sets the template config file name.
+ *
+ * @param string $templateConfig
+ */
+ public function setTemplateConfig($templateConfig)
+ {
+ $this->options['template-config'] = (string) $templateConfig;
+ }
+
+ /**
+ * Sets a list of HTML tags allowed in the documentation.
+ *
+ * @param string $allowedHtml
+ */
+ public function setAllowedHtml($allowedHtml)
+ {
+ $this->options['allowed-html'] = (string) $allowedHtml;
+ }
+
+ /**
+ * Sets how elements should be grouped in the menu.
+ *
+ * @param string $groups
+ */
+ public function setGroups($groups)
+ {
+ $this->options['groups'] = (string) $groups;
+ }
+
+ /**
+ * Sets element types for search input autocomplete.
+ *
+ * @param string $autocomplete
+ */
+ public function setAutocomplete($autocomplete)
+ {
+ $this->options['autocomplete'] = (string) $autocomplete;
+ }
+
+ /**
+ * Sets the element access levels.
+ *
+ * Documentation only for methods and properties with the given access level will be generated.
+ *
+ * @param string $accessLevels
+ */
+ public function setAccessLevels($accessLevels)
+ {
+ $this->options['access-levels'] = (string) $accessLevels;
+ }
+
+ /**
+ * Sets if documentation for elements marked as internal and internal documentation parts should be generated.
+ *
+ * @param boolean $internal
+ */
+ public function setInternal($internal)
+ {
+ $this->options['internal'] = (bool) $internal;
+ }
+
+ /**
+ * Sets if documentation for PHP internal classes should be generated.
+ *
+ * @param boolean $php
+ */
+ public function setPhp($php)
+ {
+ $this->options['php'] = (bool) $php;
+ }
+
+ /**
+ * Sets if tree view of classes, interfaces, traits and exceptions should be generated.
+ *
+ * @param boolean $tree
+ */
+ public function setTree($tree)
+ {
+ $this->options['tree'] = (bool) $tree;
+ }
+
+ /**
+ * Sets if documentation for deprecated elements should be generated.
+ *
+ * @param boolean $deprecated
+ */
+ public function setDeprecated($deprecated)
+ {
+ $this->options['deprecated'] = (bool) $deprecated;
+ }
+
+ /**
+ * Sets if documentation of tasks should be generated.
+ *
+ * @param boolean $todo
+ */
+ public function setTodo($todo)
+ {
+ $this->options['todo'] = (bool) $todo;
+ }
+
+ /**
+ * Sets if highlighted source code files should be generated.
+ *
+ * @param boolean $sourceCode
+ */
+ public function setSourceCode($sourceCode)
+ {
+ $this->options['source-code'] = (bool) $sourceCode;
+ }
+
+ /**
+ * Sets if a link to download documentation as a ZIP archive should be generated.
+ *
+ * @param boolean $download
+ */
+ public function setDownload($download)
+ {
+ $this->options['download'] = (bool) $download;
+ }
+
+ /**
+ * Sets a file name for checkstyle report of poorly documented elements.
+ *
+ * @param string $report
+ */
+ public function setReport($report)
+ {
+ $this->options['report'] = (string) $report;
+ }
+
+ /**
+ * Sets if the destination directory should be wiped out first.
+ *
+ * @param boolean $wipeout
+ */
+ public function setWipeout($wipeout)
+ {
+ $this->options['wipeout'] = (bool) $wipeout;
+ }
+
+ /**
+ * Enables/disables scaning and generating messages.
+ *
+ * @param boolean $quiet
+ */
+ public function setQuiet($quiet)
+ {
+ $this->options['quiet'] = (bool) $quiet;
+ }
+
+ /**
+ * Enables/disables the check for ApiGen updates.
+ *
+ * @param boolean $updateCheck
+ */
+ public function setUpdateCheck($updateCheck)
+ {
+ $this->options['update-check'] = (bool) $updateCheck;
+ }
+
+ /**
+ * Enables/disables the debug mode.
+ *
+ * @param boolean $debug
+ */
+ public function setDebug($debug)
+ {
+ $this->options['debug'] = (bool) $debug;
+ }
+
+ /**
+ * Runs ApiGen.
+ *
+ * @throws BuildException If something is wrong.
+ * @see Task::main()
+ */
+ public function main()
+ {
+ if ('apigen' !== $this->executable && !is_file($this->executable)) {
+ throw new BuildException(sprintf('Executable %s not found', $this->executable), $this->getLocation());
+ }
+
+ if (!empty($this->options['config'])) {
+ // Config check
+ if (!is_file($this->options['config'])) {
+ throw new BuildException(sprintf('Config file %s doesn\'t exist', $this->options['config']), $this->getLocation());
+ }
+ } else {
+ // Source check
+ if (empty($this->options['source'])) {
+ throw new BuildException('Source is not set', $this->getLocation());
+ }
+ // Destination check
+ if (empty($this->options['destination'])) {
+ throw new BuildException('Destination is not set', $this->getLocation());
+ }
+ }
+
+ // Source check
+ if (!empty($this->options['source'])) {
+ foreach ($this->options['source'] as $source) {
+ if (!file_exists($source)) {
+ throw new BuildException(sprintf('Source %s doesn\'t exist', $source), $this->getLocation());
+ }
+ }
+ }
+
+ // Execute ApiGen
+ exec(escapeshellcmd($this->executable) . ' ' . $this->constructArguments(), $output, $return);
+
+ $logType = 0 === $return ? Project::MSG_INFO : Project::MSG_ERR;
+ foreach ($output as $line) {
+ $this->log($line, $logType);
+ }
+ }
+
+ /**
+ * Generates command line arguments for the ApiGen executable.
+ *
+ * @return string
+ */
+ protected function constructArguments()
+ {
+ $args = array();
+ foreach ($this->options as $option => $value) {
+ if (is_bool($value)) {
+ $args[] = '--' . $option . '=' . ($value ? 'yes' : 'no');
+ } elseif (is_array($value)) {
+ foreach ($value as $v) {
+ $args[] = '--' . $option . '=' . escapeshellarg($v);
+ }
+ } else {
+ $args[] = '--' . $option . '=' . escapeshellarg($value);
+ }
+ }
+ return implode(' ', $args);
+ }
+}
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 100755
index 00000000..71eba460
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * $Id: 83f3748d0690f9fc69c2618191f272e5661c0501 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: 83f3748d0690f9fc69c2618191f272e5661c0501 $
+ * @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) !== false && current($right) !== false) {
+ $linenr_left = key($left);
+ $linenr_right = key($right);
+
+ if ($linenr_left < $linenr_right) {
+ $coverageMerged[$linenr_left] = current($left);
+ next($left);
+ } elseif ($linenr_right < $linenr_left) {
+ $coverageMerged[$linenr_right] = current($right);
+ next($right);
+ } else {
+ if ((current($left) < 0) || (current($right) < 0)) {
+ $coverageMerged[$linenr_right] = current($right);
+ } else {
+ $coverageMerged[$linenr_right] = current($left) + current($right);
+ }
+
+ next($left);
+ next($right);
+ }
+ }
+
+ while (current($left) !== false) {
+ $coverageMerged[key($left)] = current($left);
+ next($left);
+ }
+
+ while (current($right) !== false) {
+ $coverageMerged[key($right)] = current($right);
+ next($right);
+ }
+
+ return $coverageMerged;
+ }
+
+ /**
+ * @param Project $project
+ * @return Properties
+ * @throws BuildException
+ */
+ protected static function _getDatabase($project)
+ {
+ $coverageDatabase = $project->getProperty('coverage.database');
+
+ if (!$coverageDatabase) {
+ throw new BuildException("Property coverage.database is not set - please include coverage-setup in your build file");
+ }
+
+ $database = new PhingFile($coverageDatabase);
+
+ $props = new Properties();
+ $props->load($database);
+
+ return $props;
+ }
+
+ public static function getWhiteList($project)
+ {
+ $whitelist = array();
+ $props = self::_getDatabase($project);
+
+ foreach ($props->getProperties() as $property) {
+ $data = unserialize($property);
+ $whitelist[] = $data['fullname'];
+ }
+
+ return $whitelist;
+ }
+
+ public static function merge($project, $codeCoverageInformation)
+ {
+ $props = self::_getDatabase($project);
+
+ $coverageTotal = $codeCoverageInformation;
+
+ foreach ($coverageTotal as $filename => $data) {
+ $ignoreLines = PHP_CodeCoverage_Util::getLinesToBeIgnored($filename);
+
+ $lines = array();
+ $filename = strtolower($filename);
+
+ if ($props->getProperty($filename) != null) {
+ foreach ($data as $_line => $_data) {
+ if (is_array($_data)) {
+ $count = count($_data);
+ } else if(isset($ignoreLines[$_line])) {
+ // line is marked as ignored
+ $count = 1;
+ } else if ($_data == -1) {
+ // not executed
+ $count = -1;
+ } else if ($_data == -2) {
+ // dead code
+ $count = -2;
+ }
+
+ $lines[$_line] = $count;
+ }
+
+ ksort($lines);
+
+ $file = unserialize($props->getProperty($filename));
+ $left = $file['coverage'];
+
+ $coverageMerged = CoverageMerger::mergeCodeCoverage($left, $lines);
+
+ $file['coverage'] = $coverageMerged;
+ $props->setProperty($filename, serialize($file));
+ }
+ }
+
+ $props->store();
+ }
+} \ 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 100755
index 00000000..fd141cb5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php
@@ -0,0 +1,92 @@
+<?php
+/**
+ * $Id: 324ec42a8015e3b82e90ee3bfaad1bc069fec409 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: 324ec42a8015e3b82e90ee3bfaad1bc069fec409 $
+ * @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 100755
index 00000000..dbfc3093
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php
@@ -0,0 +1,564 @@
+<?php
+/**
+ * $Id: 564bbde3ec5084ed2db570958548af2b9d1c1127 $
+ *
+ * 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/phpunit/PHPUnitUtil.php';
+require_once 'phing/tasks/ext/coverage/CoverageReportTransformer.php';
+
+/**
+ * Transforms information in a code coverage database to XML
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 564bbde3ec5084ed2db570958548af2b9d1c1127 $
+ * @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 = PHPUnitUtil::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);
+ }
+
+ /**
+ * Adds a subpackage to their package
+ *
+ * @param string $packageName The name of the package
+ * @param string $subpackageName The name of the subpackage
+ *
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @return void
+ */
+ protected function addSubpackageToPackage($packageName, $subpackageName)
+ {
+ $package = $this->getPackageElement($packageName);
+ $subpackage = $this->getSubpackageElement($subpackageName);
+
+ if ($package === null) {
+ $package = $this->doc->createElement('package');
+ $package->setAttribute('name', $packageName);
+ $this->doc->documentElement->appendChild($package);
+ }
+
+ if ($subpackage === null) {
+ $subpackage = $this->doc->createElement('subpackage');
+ $subpackage->setAttribute('name', $subpackageName);
+ }
+
+ $package->appendChild($subpackage);
+ }
+
+ /**
+ * Returns the subpackage element
+ *
+ * @param string $subpackageName The name of the subpackage
+ *
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @return DOMNode|null null when no DOMNode with the given name exists
+ */
+ protected function getSubpackageElement($subpackageName)
+ {
+ $subpackages = $this->doc->documentElement->getElementsByTagName('subpackage');
+
+ foreach ($subpackages as $subpackage) {
+ if ($subpackage->getAttribute('name') == $subpackageName) {
+ return $subpackage;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds a class to their subpackage
+ *
+ * @param string $classname The name of the class
+ * @param DOMNode $element The dom node to append to the subpackage element
+ *
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @return void
+ */
+ protected function addClassToSubpackage($classname, $element)
+ {
+ $subpackageName = PHPUnitUtil::getSubpackageName($classname);
+
+ $subpackage = $this->getSubpackageElement($subpackageName);
+
+ if ($subpackage === null) {
+ $subpackage = $this->doc->createElement('subpackage');
+ $subpackage->setAttribute('name', $subpackageName);
+ $this->doc->documentElement->appendChild($subpackage);
+ }
+
+ $subpackage->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 = preg_split("#</?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);
+
+ if (function_exists('mb_check_encoding') && mb_check_encoding($line, 'UTF-8')) {
+ $lines[$i] = $line;
+ }
+ else if (function_exists('mb_convert_encoding'))
+ {
+ $lines[$i] = mb_convert_encoding($line, 'UTF-8');
+ }
+ else
+ {
+ $lines[$i] = utf8_encode($line);
+ }
+ }
+
+ return $lines;
+ }
+ }
+
+ protected function transformSourceFile($filename, $coverageInformation, $classStartLine = 1)
+ {
+ $sourceElement = $this->doc->createElement('sourcefile');
+ $sourceElement->setAttribute('name', basename($filename));
+
+ /**
+ * Add original/full filename to document
+ */
+ $sourceElement->setAttribute('sourcefile', $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;
+ }
+
+ /**
+ * Transforms the coverage information
+ *
+ * @param string $filename The filename
+ * @param array $coverageInformation Array with covergae information
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @return void
+ */
+ protected function transformCoverageInformation($filename, $coverageInformation)
+ {
+ $classes = PHPUnitUtil::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());
+
+ $packageName = PHPUnitUtil::getPackageName($reflection->getName());
+ $subpackageName = PHPUnitUtil::getSubpackageName($reflection->getName());
+
+ if ($subpackageName !== null) {
+ $this->addSubpackageToPackage($packageName, $subpackageName);
+ $this->addClassToSubpackage($reflection->getName(), $classElement);
+ } else {
+ $this->addClassToPackage($reflection->getName(), $classElement);
+ }
+
+ $classStartLine = $reflection->getStartLine();
+
+ $methodscovered = 0;
+ $methodcount = 0;
+
+ // 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]);
+ }
+
+ // Remove out-of-bounds info
+ unset($coverageInformation[0]);
+
+ 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 !== null && $linenr < $method->getStartLine())
+ {
+ next($coverageInformation);
+ $linenr = key($coverageInformation);
+ }
+
+ $methodCoveredCount = 0;
+ $methodTotalCount = 0;
+
+ $methodHasCoveredLine = false;
+
+ while ($linenr !== null && $linenr <= $method->getEndLine()) {
+ $methodTotalCount++;
+ $methodHasCoveredLine = true;
+
+ // set covered when CODE is other than -1 (not executed)
+ if ($coverageInformation[$linenr] > 0 || $coverageInformation[$linenr] == -2) {
+ $methodCoveredCount++;
+ }
+
+ next($coverageInformation);
+ $linenr = key($coverageInformation);
+ }
+
+ if (($methodTotalCount == $methodCoveredCount) && $methodHasCoveredLine) {
+ $methodscovered++;
+ }
+
+ $methodcount++;
+ }
+
+ $statementcount = count(array_filter(
+ $coverageInformation,
+ create_function('$var', 'return ($var != -2);')
+ ));
+
+ $statementscovered = count(array_filter(
+ $coverageInformation,
+ create_function('$var', 'return ($var >= 0);')
+ ));
+
+ $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;
+
+ $subpackages = $package->getElementsByTagName('subpackage');
+
+ foreach ($subpackages as $subpackage) {
+ $subpackageMethodCount = 0;
+ $subpackageMethodsCovered = 0;
+
+ $subpackageStatementCount = 0;
+ $subpackageStatementsCovered = 0;
+
+ $subpackageClasses = $subpackage->getElementsByTagName('class');
+
+ foreach ($subpackageClasses as $subpackageClass) {
+ $subpackageMethodCount += $subpackageClass->getAttribute('methodcount');
+ $subpackageMethodsCovered += $subpackageClass->getAttribute('methodscovered');
+
+ $subpackageStatementCount += $subpackageClass->getAttribute('statementcount');
+ $subpackageStatementsCovered += $subpackageClass->getAttribute('statementscovered');
+ }
+
+ $subpackage->setAttribute('methodcount', $subpackageMethodCount);
+ $subpackage->setAttribute('methodscovered', $subpackageMethodsCovered);
+
+ $subpackage->setAttribute('statementcount', $subpackageStatementCount);
+ $subpackage->setAttribute('statementscovered', $subpackageStatementsCovered);
+
+ $subpackage->setAttribute('totalcount', $subpackageMethodCount + $subpackageStatementCount);
+ $subpackage->setAttribute('totalcovered', $subpackageMethodsCovered + $subpackageStatementsCovered);
+ }
+
+ $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()
+ {
+ $coverageDatabase = $this->project->getProperty('coverage.database');
+
+ if (!$coverageDatabase)
+ {
+ throw new BuildException("Property coverage.database is not set - please include coverage-setup in your build file");
+ }
+
+ $database = new PhingFile($coverageDatabase);
+
+ $this->log("Transforming coverage report");
+
+ $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();
+ }
+ }
+}
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 100755
index 00000000..cc37800f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * $Id: c1667521b5959687560a1bf015905d627785a3c6 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: c1667521b5959687560a1bf015905d627785a3c6 $
+ * @package phing.tasks.ext.coverage
+ * @since 2.1.0
+ */
+class CoverageReportTransformer
+{
+ private $task = NULL;
+ private $styleDir = "";
+
+ /**
+ * @var PhingFile
+ */
+ private $toDir = "";
+
+ private $document = NULL;
+
+ /** title of the project, used in the coverage report */
+ private $title = "";
+
+ /**
+ * Whether to use the sorttable JavaScript library, defaults to false
+ * See {@link http://www.kryogenix.org/code/browser/sorttable/)}
+ *
+ * @var boolean
+ */
+ private $useSortTable = false;
+
+ function __construct(Task $task)
+ {
+ $this->task = $task;
+ }
+
+ function setStyleDir($styleDir)
+ {
+ $this->styleDir = $styleDir;
+ }
+
+ function setToDir(PhingFile $toDir)
+ {
+ $this->toDir = $toDir;
+ }
+
+ function setXmlDocument($document)
+ {
+ $this->document = $document;
+ }
+
+ /**
+ * Setter for title parameter
+ */
+ function setTitle($title) {
+ $this->title = $title;
+ }
+
+ /**
+ * Sets whether to use the sorttable JavaScript library, defaults to false
+ * See {@link http://www.kryogenix.org/code/browser/sorttable/)}
+ *
+ * @param boolean $useSortTable
+ */
+ public function setUseSortTable($useSortTable)
+ {
+ $this->useSortTable = (boolean) $useSortTable;
+ }
+
+ function transform()
+ {
+ if (!$this->toDir->exists())
+ {
+ throw new BuildException("Directory '" . $this->toDir . "' does not exist");
+ }
+
+ $xslfile = $this->getStyleSheet();
+
+ $xsl = new DOMDocument();
+ $xsl->load($xslfile->getAbsolutePath());
+
+ $proc = new XSLTProcessor();
+ if (defined('XSL_SECPREF_WRITE_FILE'))
+ {
+ if (version_compare(PHP_VERSION,'5.4',"<"))
+ {
+ ini_set("xsl.security_prefs", XSL_SECPREF_WRITE_FILE | XSL_SECPREF_CREATE_DIRECTORY);
+ }
+ else
+ {
+ $proc->setSecurityPrefs(XSL_SECPREF_WRITE_FILE | XSL_SECPREF_CREATE_DIRECTORY);
+ }
+ }
+
+ $proc->importStyleSheet($xsl);
+
+ ExtendedFileStream::registerStream();
+
+ $toDir = (string) $this->toDir;
+
+ // urlencode() the path if we're on Windows
+ if (FileSystem::getFileSystem()->getSeparator() == '\\') {
+ $toDir = urlencode($toDir);
+ }
+
+ // no output for the framed report
+ // it's all done by extension...
+ $proc->setParameter('', 'output.dir', $toDir);
+
+ $proc->setParameter('', 'output.sorttable', $this->useSortTable);
+ $proc->setParameter('', 'document.title', $this->title);
+ $proc->transformToXML($this->document);
+
+ ExtendedFileStream::unregisterStream();
+ }
+
+ 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;
+ }
+}
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 100755
index 00000000..889a9042
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * $Id: da84ff4b224cdf3a8061e02d782320ccc492c253 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: da84ff4b224cdf3a8061e02d782320ccc492c253 $
+ * @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();
+
+ /** Any filelists of files containing the .php filenames */
+ private $filelists = 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;
+ }
+
+ /**
+ * Supports embedded <filelist> element.
+ * @return FileList
+ */
+ function createFileList() {
+ $num = array_push($this->filelists, new FileList());
+ return $this->filelists[$num-1];
+ }
+
+ /**
+ * 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.
+ *
+ * @return array an array of (basedir, filenames) pairs
+ */
+ private function getFilenames()
+ {
+ $files = array();
+
+ foreach($this->filelists as $fl) {
+ try {
+ $list = $fl->getFiles($this->project);
+ foreach($list as $file) {
+ $fs = new PhingFile(strval($fl->getDir($this->project)), $file);
+ $files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath());
+ }
+ } catch (BuildException $be) {
+ $this->log($be->getMessage(), Project::MSG_WARN);
+ }
+ }
+
+
+ foreach ($this->filesets as $fileset)
+ {
+ $ds = $fileset->getDirectoryScanner($this->project);
+ $ds->scan();
+
+ $includedFiles = $ds->getIncludedFiles();
+
+ foreach ($includedFiles as $file)
+ {
+ $fs = new PhingFile(realpath($ds->getBaseDir()), $file);
+
+ $files[] = array('key' => strtolower($fs->getAbsolutePath()), 'fullname' => $fs->getAbsolutePath());
+ }
+ }
+
+ return $files;
+ }
+
+ function init()
+ {
+ }
+
+ 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());
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageThresholdTask.php b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageThresholdTask.php
new file mode 100644
index 00000000..d9afbb00
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageThresholdTask.php
@@ -0,0 +1,458 @@
+<?php
+/**
+ * $Id: ed00d6f1d05bb5dc7c9967c9ec67fa6f958682ec $
+ *
+ * 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/util/Properties.php';
+require_once 'phing/types/Excludes.php';
+
+/**
+ * Stops the build if any of the specified coverage threshold was not reached
+ *
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: ed00d6f1d05bb5dc7c9967c9ec67fa6f958682ec $
+ * @package phing.tasks.ext.coverage
+ * @since 2.4.1
+ */
+class CoverageThresholdTask extends Task
+{
+ /**
+ * Holds an optional classpath
+ *
+ * @var Path
+ */
+ private $_classpath = null;
+
+ /**
+ * Holds the exclusions
+ *
+ * @var Excludes
+ */
+ private $_excludes = null;
+
+ /**
+ * Holds an optional database file
+ *
+ * @var PhingFile
+ */
+ private $_database = null;
+
+ /**
+ * Holds the coverage threshold for the entire project
+ *
+ * @var integer
+ */
+ private $_perProject = 25;
+
+ /**
+ * Holds the coverage threshold for any class
+ *
+ * @var integer
+ */
+ private $_perClass = 25;
+
+ /**
+ * Holds the coverage threshold for any method
+ *
+ * @var integer
+ */
+ private $_perMethod = 25;
+
+ /**
+ * Holds the minimum found coverage value for a class
+ *
+ * @var integer
+ */
+ private $_minClassCoverageFound = null;
+
+ /**
+ * Holds the minimum found coverage value for a method
+ *
+ * @var integer
+ */
+ private $_minMethodCoverageFound = null;
+
+ /**
+ * Number of statements in the entire project
+ *
+ * @var integer
+ */
+ private $_projectStatementCount = 0;
+
+ /**
+ * Number of covered statements in the entire project
+ *
+ * @var integer
+ */
+ private $_projectStatementsCovered = 0;
+
+ /**
+ * Whether to enable detailed logging
+ *
+ * @var boolean
+ */
+ private $_verbose = false;
+
+ /**
+ * Sets an optional classpath
+ *
+ * @param Path $classpath The classpath
+ */
+ public function setClasspath(Path $classpath)
+ {
+ if ($this->_classpath === null) {
+ $this->_classpath = $classpath;
+ } else {
+ $this->_classpath->append($classpath);
+ }
+ }
+
+ /**
+ * Sets the optional coverage database to use
+ *
+ * @param PhingFile The database file
+ */
+ public function setDatabase(PhingFile $database)
+ {
+ $this->_database = $database;
+ }
+
+ /**
+ * Create classpath object
+ *
+ * @return Path
+ */
+ public function createClasspath()
+ {
+ $this->classpath = new Path();
+ return $this->classpath;
+ }
+
+ /**
+ * Sets the coverage threshold for entire project
+ *
+ * @param integer $threshold Coverage threshold for entire project
+ */
+ public function setPerProject($threshold)
+ {
+ $this->_perProject = $threshold;
+ }
+
+ /**
+ * Sets the coverage threshold for any class
+ *
+ * @param integer $threshold Coverage threshold for any class
+ */
+ public function setPerClass($threshold)
+ {
+ $this->_perClass = $threshold;
+ }
+
+ /**
+ * Sets the coverage threshold for any method
+ *
+ * @param integer $threshold Coverage threshold for any method
+ */
+ public function setPerMethod($threshold)
+ {
+ $this->_perMethod = $threshold;
+ }
+
+ /**
+ * Sets whether to enable detailed logging or not
+ *
+ * @param boolean $verbose
+ */
+ public function setVerbose($verbose)
+ {
+ $this->_verbose = StringHelper::booleanValue($verbose);
+ }
+
+ /**
+ * Filter covered statements
+ *
+ * @param integer $var Coverage CODE/count
+ * @return boolean
+ */
+ protected function filterCovered($var)
+ {
+ return ($var >= 0 || $var === -2);
+ }
+
+ /**
+ * Create excludes object
+ *
+ * @return Excludes
+ */
+ public function createExcludes()
+ {
+ $this->_excludes = new Excludes($this->project);
+ return $this->_excludes;
+ }
+
+ /**
+ * Calculates the coverage threshold
+ *
+ * @param string $filename The filename to analyse
+ * @param array $coverageInformation Array with coverage information
+ */
+ protected function calculateCoverageThreshold($filename, $coverageInformation)
+ {
+ $classes = PHPUnitUtil::getDefinedClasses($filename, $this->_classpath);
+
+ if (is_array($classes)) {
+ foreach ($classes as $className) {
+ // Skip class if excluded from coverage threshold validation
+ if ($this->_excludes !== null) {
+ if (in_array($className, $this->_excludes->getExcludedClasses())) {
+ continue;
+ }
+ }
+
+ $reflection = new ReflectionClass($className);
+ $classStartLine = $reflection->getStartLine();
+
+ // 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);
+
+ $methods = $reflection->getMethods();
+
+ 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;
+ }
+
+ // Skip method if excluded from coverage threshold validation
+ if ($this->_excludes !== null) {
+ $excludedMethods = $this->_excludes->getExcludedMethods();
+
+ if (isset($excludedMethods[$className])) {
+ if (in_array($method->getName(), $excludedMethods[$className])
+ || in_array($method->getName() . '()', $excludedMethods[$className])
+ ) {
+ continue;
+ }
+ }
+ }
+
+ $methodStartLine = $method->getStartLine();
+ $methodEndLine = $method->getEndLine();
+
+ // small fix for XDEBUG_CC_UNUSED
+ if (isset($coverageInformation[$methodStartLine])) {
+ unset($coverageInformation[$methodStartLine]);
+ }
+
+ if (isset($coverageInformation[$methodEndLine])) {
+ unset($coverageInformation[$methodEndLine]);
+ }
+
+ if ($method->isAbstract()) {
+ continue;
+ }
+
+ $lineNr = key($coverageInformation);
+
+ while ($lineNr !== null && $lineNr < $methodStartLine) {
+ next($coverageInformation);
+ $lineNr = key($coverageInformation);
+ }
+
+ $methodStatementsCovered = 0;
+ $methodStatementCount = 0;
+
+ while ($lineNr !== null && $lineNr <= $methodEndLine) {
+ $methodStatementCount++;
+
+ $lineCoverageInfo = $coverageInformation[$lineNr];
+ // set covered when CODE is other than -1 (not executed)
+ if ($lineCoverageInfo > 0 || $lineCoverageInfo === -2) {
+ $methodStatementsCovered++;
+ }
+
+ next($coverageInformation);
+ $lineNr = key($coverageInformation);
+ }
+
+ if ($methodStatementCount > 0) {
+ $methodCoverage = ( $methodStatementsCovered
+ / $methodStatementCount) * 100;
+ } else {
+ $methodCoverage = 0;
+ }
+
+ if ($methodCoverage < $this->_perMethod
+ && !$method->isAbstract()
+ ) {
+ throw new BuildException(
+ 'The coverage (' . round($methodCoverage, 2) . '%) '
+ . 'for method "' . $method->getName() . '" is lower'
+ . ' than the specified threshold ('
+ . $this->_perMethod . '%), see file: "'
+ . $filename . '"'
+ );
+ } elseif ($methodCoverage < $this->_perMethod
+ && $method->isAbstract()
+ && $this->_verbose === true
+ ) {
+ $this->log(
+ 'Skipped coverage threshold for abstract method "'
+ . $method->getName() . '"'
+ );
+ }
+
+ // store the minimum coverage value for logging (see #466)
+ if ($this->_minMethodCoverageFound !== null) {
+ if ($this->_minMethodCoverageFound > $methodCoverage) {
+ $this->_minMethodCoverageFound = $methodCoverage;
+ }
+ } else {
+ $this->_minMethodCoverageFound = $methodCoverage;
+ }
+ }
+
+ $classStatementCount = count($coverageInformation);
+ $classStatementsCovered = count(
+ array_filter(
+ $coverageInformation,
+ array($this, 'filterCovered')
+ )
+ );
+
+ if ($classStatementCount > 0) {
+ $classCoverage = ( $classStatementsCovered
+ / $classStatementCount) * 100;
+ } else {
+ $classCoverage = 0;
+ }
+
+ if ($classCoverage < $this->_perClass
+ && !$reflection->isAbstract()
+ ) {
+ throw new BuildException(
+ 'The coverage (' . round($classCoverage, 2) . '%) for class "'
+ . $reflection->getName() . '" is lower than the '
+ . 'specified threshold (' . $this->_perClass . '%), '
+ . 'see file: "' . $filename . '"'
+ );
+ } elseif ($classCoverage < $this->_perClass
+ && $reflection->isAbstract()
+ && $this->_verbose === true
+ ) {
+ $this->log(
+ 'Skipped coverage threshold for abstract class "'
+ . $reflection->getName() . '"'
+ );
+ }
+
+ // store the minimum coverage value for logging (see #466)
+ if ($this->_minClassCoverageFound !== null) {
+ if ($this->_minClassCoverageFound > $classCoverage) {
+ $this->_minClassCoverageFound = $classCoverage;
+ }
+ } else {
+ $this->_minClassCoverageFound = $classCoverage;
+ }
+
+ $this->_projectStatementCount += $classStatementCount;
+ $this->_projectStatementsCovered += $classStatementsCovered;
+ }
+ }
+ }
+
+ public function main()
+ {
+ if ($this->_database === null) {
+ $coverageDatabase = $this->project
+ ->getProperty('coverage.database');
+
+ if (! $coverageDatabase) {
+ throw new BuildException(
+ 'Either include coverage-setup in your build file or set '
+ . 'the "database" attribute'
+ );
+ }
+
+ $database = new PhingFile($coverageDatabase);
+ } else {
+ $database = $this->_database;
+ }
+
+ $this->log(
+ 'Calculating coverage threshold: min. '
+ . $this->_perProject . '% per project, '
+ . $this->_perClass . '% per class and '
+ . $this->_perMethod . '% per method is required'
+ );
+
+ $props = new Properties();
+ $props->load($database);
+
+ foreach ($props->keys() as $filename) {
+ $file = unserialize($props->getProperty($filename));
+
+ // Skip file if excluded from coverage threshold validation
+ if ($this->_excludes !== null) {
+ if (in_array($file['fullname'], $this->_excludes->getExcludedFiles())) {
+ continue;
+ }
+ }
+
+ $this->calculateCoverageThreshold(
+ $file['fullname'],
+ $file['coverage']
+ );
+ }
+
+ if ($this->_projectStatementCount > 0) {
+ $coverage = ( $this->_projectStatementsCovered
+ / $this->_projectStatementCount) * 100;
+ } else {
+ $coverage = 0;
+ }
+
+ if ($coverage < $this->_perProject) {
+ throw new BuildException(
+ 'The coverage (' . round($coverage, 2) . '%) for the entire project '
+ . 'is lower than the specified threshold ('
+ . $this->_perProject . '%)'
+ );
+ }
+
+ $this->log(
+ 'Passed coverage threshold. Minimum found coverage values are: '
+ . round($coverage, 2) . '% per project, '
+ . round($this->_minClassCoverageFound, 2) . '% per class and '
+ . round($this->_minMethodCoverageFound, 2) . '% per method'
+ );
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/creole/CreoleSQLExecTask.php b/buildscripts/phing/classes/phing/tasks/ext/creole/CreoleSQLExecTask.php
new file mode 100755
index 00000000..1ea3d5ba
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/creole/CreoleSQLExecTask.php
@@ -0,0 +1,592 @@
+<?php
+/*
+ * $Id: f8f62d67a784faced2621d2ffc3b1c92e8703b05 $
+ *
+ * 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/creole/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.creole
+ * @version $Id: f8f62d67a784faced2621d2ffc3b1c92e8703b05 $
+ */
+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();
+
+ /**
+ * all filterchains objects assigned to this task
+ */
+ private $filterChains = 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;
+ }
+
+ /**
+ * 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];
+ }
+
+ /**
+ * 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 &quot;abort&quot;
+ */
+ 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 = "";
+
+ $buffer = '';
+
+ if ((is_array($this->filterChains)) && (!empty($this->filterChains))) {
+ $in = FileUtils::getChainedReader(new BufferedReader($reader), $this->filterChains, $this->getProject());
+ while(-1 !== ($read = $in->read())) { // -1 indicates EOF
+ $buffer .= $read;
+ }
+ $lines = explode("\n", $buffer);
+ } else {
+ $in = new BufferedReader($reader);
+
+ while (($line = $in->readLine()) !== null) {
+ $lines[] = $line;
+ }
+ }
+
+ try {
+ foreach ($lines as $line) {
+ $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)), $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.
+ * @throws SQLException
+ */
+ protected function printResults($out = null) {
+
+ $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.PHP_EOL);
+ }
+ $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 . PHP_EOL);
+ }
+ $line = "";
+
+ } // while rs->next()
+ }
+ } while ($this->statement->getMoreResults());
+ print(PHP_EOL);
+ 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.
+ *
+ * @package phing.tasks.ext.creole
+ */
+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/creole/CreoleTask.php b/buildscripts/phing/classes/phing/tasks/ext/creole/CreoleTask.php
new file mode 100755
index 00000000..6cff2033
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/creole/CreoleTask.php
@@ -0,0 +1,242 @@
+<?php
+
+/*
+ * $Id: 91a6dbbd682e6afa8befa95f01ae5fbaed11a72a $
+ *
+ * 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 $Id$
+ * @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/dbdeploy/DbDeployTask.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbDeployTask.php
new file mode 100755
index 00000000..a5cc23ff
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbDeployTask.php
@@ -0,0 +1,436 @@
+<?php
+/*
+ * $Id: 035d43c0c50ca9567e9c8a016fef6a3053164acb $
+ *
+ * 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/dbdeploy/DbmsSyntaxFactory.php';
+
+
+/**
+ * Generate SQL script for db using dbdeploy schema version table
+ * and delta scripts
+ *
+ * <dbdeploy url="mysql:host=localhost;dbname=test"
+ * userid="dbdeploy" password="dbdeploy" dir="db" outputfile="">
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+class DbDeployTask extends Task
+{
+ /**
+ * The tablename to use from the database for storing all changes
+ * This cannot be changed
+ *
+ * @var string
+ */
+ public static $TABLE_NAME = 'changelog';
+
+ /**
+ * Connection string for the database connection
+ *
+ * @var string
+ */
+ protected $url;
+
+ /**
+ * The userid for the database connection
+ *
+ * @var string
+ */
+ protected $userid;
+
+ /**
+ * The password of the database user
+ *
+ * @var string
+ */
+ protected $password;
+
+ /**
+ * Path to the directory that holds the database patch files
+ *
+ * @var string
+ */
+ protected $dir;
+
+ /**
+ * Output file for performing all database patches of this deployment
+ * Contains all the SQL statements that need to be executed
+ *
+ * @var string
+ */
+ protected $outputFile = 'dbdeploy_deploy.sql';
+
+ /**
+ * Outputfile for undoing the database patches of this deployment
+ * Contains all the SQL statements that need to be executed
+ *
+ * @var string
+ */
+ protected $undoOutputFile = 'dbdeploy_undo.sql';
+
+ /**
+ * The deltaset that's being used
+ *
+ * @var string
+ */
+ protected $deltaSet = 'Main';
+
+ /**
+ * The number of the last change to apply
+ *
+ * @var int
+ */
+ protected $lastChangeToApply = 999;
+
+ /**
+ * Contains the object for the DBMS that is used
+ *
+ * @var object
+ */
+ protected $dbmsSyntax = null;
+
+ /**
+ * Array with all change numbers that are applied already
+ *
+ * @var array
+ */
+ protected $appliedChangeNumbers = array();
+
+ /**
+ * Checkall attribute
+ * False means dbdeploy will only apply patches that have a higher number
+ * than the last patchnumber that was applied
+ * True means dbdeploy will apply all changes that aren't applied
+ * already (in ascending order)
+ *
+ * @var int
+ */
+ protected $checkall = false;
+
+ /**
+ * The main function for the task
+ *
+ * @throws BuildException
+ * @return void
+ */
+ public function main()
+ {
+ try {
+ // get correct DbmsSyntax object
+ $dbms = substr($this->url, 0, strpos($this->url, ':'));
+ $dbmsSyntaxFactory = new DbmsSyntaxFactory($dbms);
+ $this->dbmsSyntax = $dbmsSyntaxFactory->getDbmsSyntax();
+
+ // figure out which revisions are in the db already
+ $this->appliedChangeNumbers = $this->getAppliedChangeNumbers();
+ $this->log('Current db revision: '.$this->getLastChangeAppliedInDb());
+ $this->log('Checkall: ' . $this->checkall);
+
+ $this->deploy();
+
+ } catch (Exception $e) {
+ throw new BuildException($e);
+ }
+ }
+
+ /**
+ * Get the numbers of all the patches that are already applied according to
+ * the changelog table in the database
+ *
+ * @return array
+ */
+ protected function getAppliedChangeNumbers()
+ {
+ if (count($this->appliedChangeNumbers) == 0) {
+ $this->log('Getting applied changed numbers from DB: ' . $this->url);
+ $appliedChangeNumbers = array();
+ $dbh = new PDO($this->url, $this->userid, $this->password);
+ $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $sql = "SELECT *
+ FROM " . DbDeployTask::$TABLE_NAME . "
+ WHERE delta_set = '$this->deltaSet'
+ ORDER BY change_number";
+ foreach ($dbh->query($sql) as $change) {
+ $appliedChangeNumbers[] = $change['change_number'];
+ }
+ $this->appliedChangeNumbers = $appliedChangeNumbers;
+ }
+ return $this->appliedChangeNumbers;
+ }
+
+ /**
+ * Get the number of the last patch applied to the database
+ *
+ * @return int|mixed The highest patch number that is applied in the db
+ */
+ protected function getLastChangeAppliedInDb()
+ {
+ return (count($this->appliedChangeNumbers) > 0)
+ ? max($this->appliedChangeNumbers) : 0;
+ }
+
+ /**
+ * Create the deploy and undo deploy outputfiles
+ *
+ * @return void
+ */
+ protected function deploy()
+ {
+ // create deploy outputfile
+ $this->createOutputFile($this->outputFile, false);
+
+ // create undo deploy outputfile
+ $this->createOutputFile($this->undoOutputFile, true);
+ }
+
+ /**
+ * Generate the sql for doing/undoing the deployment and write it to a file
+ *
+ * @param string $file
+ * @param bool $undo
+ * @return void
+ */
+ protected function createOutputFile($file, $undo = false)
+ {
+ $fileHandle = fopen($file, "w+");
+ $sql = $this->generateSql($undo);
+ fwrite($fileHandle, $sql);
+ }
+
+ /**
+ * Generate the sql for doing/undoing this deployment
+ *
+ * @param bool $undo
+ * @return string The sql
+ */
+ protected function generateSql($undo = false)
+ {
+ $sql = '';
+ $lastChangeAppliedInDb = $this->getLastChangeAppliedInDb();
+ $files = $this->getDeltasFilesArray();
+ $this->sortFiles($files, $undo);
+
+ foreach ($files as $fileChangeNumber => $fileName) {
+ if ($this->fileNeedsToBeRead($fileChangeNumber, $lastChangeAppliedInDb)) {
+ $sql .= '-- Fragment begins: ' . $fileChangeNumber . ' --' . "\n";
+
+ if (!$undo) {
+ $sql .= 'INSERT INTO ' . DbDeployTask::$TABLE_NAME . '
+ (change_number, delta_set, start_dt, applied_by, description)' .
+ ' VALUES (' . $fileChangeNumber . ', \'' . $this->deltaSet . '\', ' .
+ $this->dbmsSyntax->generateTimestamp() .
+ ', \'dbdeploy\', \'' . $fileName . '\');' . "\n";
+ }
+
+ // read the file
+ $fullFileName = $this->dir . '/' . $fileName;
+ $fh = fopen($fullFileName, 'r');
+ $contents = fread($fh, filesize($fullFileName));
+ // allow construct with and without space added
+ $split = strpos($contents, '-- //@UNDO');
+ if ($split === false)
+ $split = strpos($contents, '--//@UNDO');
+
+ if ($undo) {
+ $sql .= substr($contents, $split + 10) . "\n";
+ $sql .= 'DELETE FROM ' . DbDeployTask::$TABLE_NAME . '
+ WHERE change_number = ' . $fileChangeNumber . '
+ AND delta_set = \'' . $this->deltaSet . '\';' . "\n";
+ } else {
+ $sql .= substr($contents, 0, $split);
+ $sql .= 'UPDATE ' . DbDeployTask::$TABLE_NAME . '
+ SET complete_dt = ' . $this->dbmsSyntax->generateTimestamp() . '
+ WHERE change_number = ' . $fileChangeNumber . '
+ AND delta_set = \'' . $this->deltaSet . '\';' . "\n";
+ }
+
+ $sql .= '-- Fragment ends: ' . $fileChangeNumber . ' --' . "\n";
+ }
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Get a list of all the patch files in the patch file directory
+ *
+ * @return array
+ */
+ protected function getDeltasFilesArray()
+ {
+ $files = array();
+ $baseDir = realpath($this->dir);
+ $dh = opendir($baseDir);
+ $fileChangeNumberPrefix = '';
+ while (($file = readdir($dh)) !== false) {
+ if (preg_match('[\d+]', $file, $fileChangeNumberPrefix)) {
+ $files[intval($fileChangeNumberPrefix[0])] = $file;
+ }
+ }
+ return $files;
+ }
+
+ /**
+ * Sort files in the patch files directory (ascending or descending depending on $undo boolean)
+ *
+ * @param array $files
+ * @param bool $undo
+ * @return void
+ */
+ protected function sortFiles(&$files, $undo)
+ {
+ if ($undo) {
+ krsort($files);
+ } else {
+ ksort($files);
+ }
+ }
+
+ /**
+ * Determine if this patch file need to be deployed
+ * (using fileChangeNumber, lastChangeAppliedInDb and $this->checkall)
+ *
+ * @param int $fileChangeNumber
+ * @param string $lastChangeAppliedInDb
+ * @return bool True or false if patch file needs to be deployed
+ */
+ protected function fileNeedsToBeRead($fileChangeNumber, $lastChangeAppliedInDb)
+ {
+ if ($this->checkall) {
+ return (!in_array($fileChangeNumber, $this->appliedChangeNumbers));
+ } else {
+ return ($fileChangeNumber > $lastChangeAppliedInDb && $fileChangeNumber <= $this->lastChangeToApply);
+ }
+ }
+
+ /**
+ * Set the url for the database connection
+ *
+ * @param string $url
+ * @return void
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ }
+
+ /**
+ * Set the userid for the database connection
+ *
+ * @param string $userid
+ * @return void
+ */
+ public function setUserId($userid)
+ {
+ $this->userid = $userid;
+ }
+
+ /**
+ * Set the password for the database connection
+ *
+ * @param string $password
+ * @return void
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+
+ /**
+ * Set the directory where to find the patchfiles
+ *
+ * @param string $dir
+ * @return void
+ */
+ public function setDir($dir)
+ {
+ $this->dir = $dir;
+ }
+
+ /**
+ * Set the outputfile which contains all patch sql statements for this deployment
+ *
+ * @param string $outputFile
+ * @return void
+ */
+ public function setOutputFile($outputFile)
+ {
+ $this->outputFile = $outputFile;
+ }
+
+ /**
+ * Set the undo outputfile which contains all undo statements for this deployment
+ *
+ * @param string $undoOutputFile
+ * @return void
+ */
+ public function setUndoOutputFile($undoOutputFile)
+ {
+ $this->undoOutputFile = $undoOutputFile;
+ }
+
+ /**
+ * Set the lastchangetoapply property
+ *
+ * @param int $lastChangeToApply
+ * @return void
+ */
+ public function setLastChangeToApply($lastChangeToApply)
+ {
+ $this->lastChangeToApply = $lastChangeToApply;
+ }
+
+ /**
+ * Set the deltaset property
+ *
+ * @param string $deltaSet
+ * @return void
+ */
+ public function setDeltaSet($deltaSet)
+ {
+ $this->deltaSet = $deltaSet;
+ }
+
+ /**
+ * Set the checkall property
+ *
+ * @param bool $checkall
+ * @return void
+ */
+ public function setCheckAll($checkall)
+ {
+ $this->checkall = (int)$checkall;
+ }
+
+ /**
+ * Add a new fileset.
+ * @return FileSet
+ */
+ public function createFileSet()
+ {
+ $this->fileset = new FileSet();
+ $this->filesets[] = $this->fileset;
+ return $this->fileset;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntax.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntax.php
new file mode 100755
index 00000000..f20d2df4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntax.php
@@ -0,0 +1,34 @@
+<?php
+/*
+ * $Id: 40826765e423da7500094b84f0025f75c8fdde87 $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+abstract class DbmsSyntax
+{
+ public abstract function generateTimestamp();
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php
new file mode 100755
index 00000000..1cc163f5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php
@@ -0,0 +1,67 @@
+<?php
+/*
+ * $Id: 0efe41b73233dd4396055518a125e4ff642693c5 $
+ *
+ * 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/dbdeploy/DbmsSyntax.php';
+
+/**
+ * Factory for generating dbms-specific syntax-generating objects
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+class DbmsSyntaxFactory
+{
+ private $dbms;
+
+ public function __construct($dbms)
+ {
+ $this->dbms = $dbms;
+ }
+
+ public function getDbmsSyntax()
+ {
+ switch ($this->dbms){
+ case('sqlite') :
+ require_once 'phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php';
+ return new DbmsSyntaxSQLite();
+ case('mysql'):
+ require_once 'phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php';
+ return new DbmsSyntaxMysql();
+ case 'odbc':
+ case('mssql'):
+ case 'dblib':
+ require_once 'phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php';
+ return new DbmsSyntaxMsSql();
+ case('pgsql'):
+ require_once 'phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php';
+ return new DbmsSyntaxPgSQL();
+ case 'oci':
+ require_once 'phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php';
+ return new DbmsSyntaxOracle();
+ default:
+ throw new Exception($this->dbms . ' is not supported by dbdeploy task.');
+ }
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php
new file mode 100755
index 00000000..0b505d8e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * $Id: 10012c2626ef9befc8c18efa5898704e269d6164 $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+class DbmsSyntaxMsSql extends DbmsSyntax
+{
+ public function generateTimestamp()
+ {
+ return "DATEDIFF(s, '19700101', GETDATE())";
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php
new file mode 100755
index 00000000..86bf8ae0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * $Id: 3a8bab5e99f20e29f5c7dfe7d02f7a91fb8ccecd $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+class DbmsSyntaxMysql extends DbmsSyntax
+{
+ public function generateTimestamp()
+ {
+ return "NOW()";
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php
new file mode 100755
index 00000000..15b0b0a0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * $Id: be6f99d787b94f7f2c1c8e359def3d465386bba9 $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+class DbmsSyntaxOracle extends DbmsSyntax
+{
+ public function generateTimestamp()
+ {
+ return "(sysdate - to_date('01-JAN-1970','DD-MON-YYYY')) * (86400)";
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php
new file mode 100755
index 00000000..6c07931c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php
@@ -0,0 +1,36 @@
+<?php
+/*
+ * $Id: 17845f06b311dbe508e7cb1244cd849a1d3fcada $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author R�my BREUILS
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+class DbmsSyntaxPgSQL extends DbmsSyntax
+{
+ public function generateTimestamp()
+ {
+ return "NOW()";
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php
new file mode 100755
index 00000000..32aa023e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php
@@ -0,0 +1,37 @@
+<?php
+/*
+ * $Id: a48723b4c3ef1e5c15417f5ea6e495960e5e018b $
+ *
+ * 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 for generating necessary server-specific SQL commands
+ *
+ * @author Luke Crouch at SourceForge (http://sourceforge.net)
+ * @version $Id$
+ * @package phing.tasks.ext.dbdeploy
+ */
+
+class DbmsSyntaxSQLite extends DbmsSyntax
+{
+ public function generateTimestamp()
+ {
+ return "strftime('%s','now')";
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/docblox/DocBloxTask.php b/buildscripts/phing/classes/phing/tasks/ext/docblox/DocBloxTask.php
new file mode 100755
index 00000000..0c1556c8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/docblox/DocBloxTask.php
@@ -0,0 +1,221 @@
+<?php
+/*
+ * $Id: eaa494390770adc752097a412d63fb863482fd5d $
+ *
+ * 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/FileOutputStream.php';
+
+/**
+ * DocBlox Task (http://www.docblox-project.org)
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: eaa494390770adc752097a412d63fb863482fd5d $
+ * @since 2.4.6
+ * @package phing.tasks.ext.docblox
+ */
+class DocBloxTask extends Task
+{
+ /**
+ * List of filesets
+ * @var FileSet[]
+ */
+ private $filesets = array();
+
+ /**
+ * Destination/target directory
+ * @var PhingFile
+ */
+ private $destDir = null;
+
+ /**
+ * name of the template to use
+ * @var string
+ */
+ private $template = "new_black";
+
+ /**
+ * Title of the project
+ * @var string
+ */
+ private $title = "";
+
+ /**
+ * Force DocBlox to be quiet
+ * @var boolean
+ */
+ private $quiet = true;
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ *
+ * @return FileSet
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Sets destination/target directory
+ * @param PhingFile $destDir
+ */
+ public function setDestDir(PhingFile $destDir)
+ {
+ $this->destDir = $destDir;
+ }
+
+ /**
+ * Convenience setter (@see setDestDir)
+ * @param PhingFile $output
+ */
+ public function setOutput(PhingFile $output)
+ {
+ $this->destDir = $output;
+ }
+
+ /**
+ * Sets the template to use
+ * @param strings $template
+ */
+ public function setTemplate($template)
+ {
+ $this->template = (string) $template;
+ }
+
+ /**
+ * Sets the title of the project
+ * @param strings $title
+ */
+ public function setTitle($title)
+ {
+ $this->title = (string) $title;
+ }
+
+ /**
+ * Forces DocBlox to be quiet
+ * @param boolean $quiet
+ */
+ public function setQuiet($quiet)
+ {
+ $this->quiet = (boolean) $quiet;
+ }
+
+ /**
+ * Finds and initializes the DocBlox installation
+ */
+ private function initializeDocBlox()
+ {
+ $docbloxPath = null;
+
+ foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) {
+ $testDocBloxPath = $path . DIRECTORY_SEPARATOR . 'DocBlox' . DIRECTORY_SEPARATOR . 'src';
+
+ if (file_exists($testDocBloxPath)) {
+ $docbloxPath = $testDocBloxPath;
+ }
+ }
+
+ if (empty($docbloxPath)) {
+ throw new BuildException("Please make sure DocBlox is installed and on the include_path.", $this->getLocation());
+ }
+
+ set_include_path($docbloxPath . PATH_SEPARATOR . get_include_path());
+
+ require_once $docbloxPath.'/DocBlox/Bootstrap.php';
+
+ $bootstrap = DocBlox_Bootstrap::createInstance();
+
+ $autoloader = $bootstrap->registerAutoloader();
+
+ if ($this->quiet) {
+ DocBlox_Core_Abstract::config()->logging->level = 'quiet';
+ } else {
+ DocBlox_Core_Abstract::config()->logging->level = 'debug';
+ }
+
+ $bootstrap->registerPlugins($autoloader);
+ }
+
+ /**
+ * Build a list of files (from the fileset elements) and call the DocBlox parser
+ * @return string
+ */
+ private function parseFiles()
+ {
+ $parser = new DocBlox_Parser();
+
+ //Only initialize the dispatcher when not already done
+ if (is_null(DocBlox_Parser_Abstract::$event_dispatcher)) {
+ DocBlox_Parser_Abstract::$event_dispatcher = new sfEventDispatcher();
+ }
+ $parser->setTitle($this->title);
+
+ $paths = array();
+
+ // filesets
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $dir = $fs->getDir($this->project);
+ $srcFiles = $ds->getIncludedFiles();
+
+ foreach ($srcFiles as $file) {
+ $paths[] = $dir . FileSystem::getFileSystem()->getSeparator() . $file;
+ }
+ }
+
+ $this->log("Will parse " . count($paths) . " file(s)", Project::MSG_VERBOSE);
+
+ $files = new DocBlox_Parser_Files();
+ $files->addFiles($paths);
+
+ $parser->setPath($files->getProjectRoot());
+
+ return $parser->parseFiles($files);
+ }
+
+ /**
+ * Task entry point
+ * @see Task::main()
+ */
+ public function main()
+ {
+ if (empty($this->destDir)) {
+ throw new BuildException("You must supply the 'destdir' attribute", $this->getLocation());
+ }
+
+ if (empty($this->filesets)) {
+ throw new BuildException("You have not specified any files to include (<fileset>)", $this->getLocation());
+ }
+
+ $this->initializeDocBlox();
+
+ $xml = $this->parseFiles();
+
+ $this->log("Transforming...", Project::MSG_VERBOSE);
+
+ $transformer = new DocBlox_Transformer();
+ $transformer->setTemplatesPath(DocBlox_Core_Abstract::config()->paths->templates);
+ $transformer->setTemplates($this->template);
+ $transformer->setSource($xml);
+ $transformer->setTarget($this->destDir->getAbsolutePath());
+ $transformer->execute();
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitBaseTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitBaseTask.php
new file mode 100644
index 00000000..8381cc64
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitBaseTask.php
@@ -0,0 +1,134 @@
+<?php
+/*
+ * $Id: 5ffc8c9c51dfa9bd0d691a88db670cdeb5f985c1 $
+ *
+ * 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/BuildException.php';
+
+/**
+ * Base class for Git tasks
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 5ffc8c9c51dfa9bd0d691a88db670cdeb5f985c1 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+abstract class GitBaseTask extends Task
+{
+ /**
+ * Bath to git binary
+ * @var string
+ */
+ private $gitPath = '/usr/bin/git';
+
+ /**
+ * @var VersionControl_Git
+ */
+ private $gitClient = null;
+
+ /**
+ * Current repository directory
+ * @var string
+ */
+ private $repository;
+
+ /**
+ * Initialize Task.
+ * Check and include necessary libraries.
+ */
+ public function init()
+ {
+ @include_once 'VersionControl/Git.php';
+ if (false == class_exists('VersionControl_Git')) {
+ throw new BuildException("The Git tasks depend on PEAR\'s "
+ . "VersionControl_Git package.", $this->getLocation());
+ }
+ }
+
+ /**
+ * Set repository directory
+ *
+ * @param string $repository Repo directory
+ * @return GitBaseTask
+ */
+ public function setRepository($repository)
+ {
+ $this->repository = $repository;
+ return $this;
+ }
+
+ /**
+ * Get repository directory
+ *
+ * @return string
+ */
+ public function getRepository()
+ {
+ return $this->repository;
+ }
+
+ /**
+ * Set path to git executable
+ *
+ * @param string $gitPath New path to git repository
+ * @return GitBaseTask
+ */
+ public function setGitPath($gitPath)
+ {
+ $this->gitPath = $gitPath;
+ return $this;
+ }
+
+ /**
+ * Get path to git executable
+ *
+ * @return string
+ */
+ public function getGitPath()
+ {
+ return $this->gitPath;
+ }
+
+ protected function getGitClient($reset = false, $repository = null)
+ {
+ $this->gitClient = ($reset === true) ? null : $this->gitClient;
+ $repository = (null === $repository)
+ ? $this->getRepository()
+ : $repository;
+
+ if(null === $this->gitClient) {
+ try {
+ $this->gitClient = new VersionControl_Git($repository);
+ } catch (VersionControl_Git_Exception $e) {
+ // re-package
+ throw new BuildException(
+ 'You must specify readable directory as repository.');
+
+ }
+ }
+ $this->gitClient->setGitCommandPath($this->getGitPath());
+
+ return $this->gitClient;
+ }
+}
+
+
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitBranchTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitBranchTask.php
new file mode 100644
index 00000000..54a0eb20
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitBranchTask.php
@@ -0,0 +1,296 @@
+<?php
+/*
+ * $Id: 88a8737d783614bcd5acb103738fafc23c509225 $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-branch
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 88a8737d783614bcd5acb103738fafc23c509225 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitBranchTask extends GitBaseTask
+{
+ /**
+ * Branch name
+ * @var string
+ */
+ private $branchname;
+
+ /**
+ * New Branch name for git-branch -m | -M
+ * @var string
+ */
+ private $newbranch;
+
+ /**
+ * If not HEAD, specify starting point
+ * @var string
+ */
+ private $startPoint;
+
+ /**
+ * --set-upstream key to git-branch
+ * @var boolean
+ */
+ private $setUpstream = false;
+
+ /**
+ * --track key to git-branch
+ * @var boolean
+ */
+ private $track = false;
+
+ /**
+ * --no-track key to git-branch
+ * @var boolean
+ */
+ private $noTrack = false;
+
+ /**
+ * --force, -f key to git-branch
+ * @var boolean
+ */
+ private $force = false;
+
+ /**
+ * -d, -D, -m, -M options to git-branch
+ * Respective task options:
+ * delete, forceDelete, move, forceMove
+ * @var array
+ */
+ private $extraOptions = array(
+ 'd' => false,
+ 'D' => false,
+ 'm' => false,
+ 'M' => false,
+ );
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+ if (null === $this->getBranchname()) {
+ throw new BuildException('"branchname" is required parameter');
+ }
+
+ // if we are moving branch, we need to know new name
+ if ($this->isMove() || $this->isForceMove()) {
+ if (null === $this->getNewbranch()) {
+ throw new BuildException('"newbranch" is required parameter');
+ }
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('branch');
+ $command
+ ->setOption('set-upstream', $this->isSetUpstream())
+ ->setOption('no-track', $this->isNoTrack())
+ ->setOption('force', $this->isForce());
+ if ($this->isNoTrack() == false) {
+ $command->setOption('track', $this->getTrack());
+ }
+
+ // check extra options (delete, move)
+ foreach ($this->extraOptions as $option => $flag) {
+ if ($flag) {
+ $command->setOption($option, true);
+ }
+ }
+
+ $command->addArgument($this->getBranchname());
+
+ if (null !== $this->getStartPoint()) {
+ $command->addArgument($this->getStartPoint());
+ }
+
+ if (null !== $this->getNewbranch()) {
+ $command->addArgument($this->getNewbranch());
+ }
+
+ $this->log('git-branch command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log(
+ sprintf('git-branch: branch "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ $this->log('git-branch output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setSetUpstream($flag)
+ {
+ $this->setUpstream = $flag;
+ }
+
+ public function getSetUpstream()
+ {
+ return $this->setUpstream;
+ }
+
+ public function isSetUpstream()
+ {
+ return $this->getSetUpstream();
+ }
+
+ public function setTrack($flag)
+ {
+ $this->track = $flag;
+ }
+
+ public function getTrack()
+ {
+ return $this->track;
+ }
+
+ public function isTrack()
+ {
+ return $this->getTrack();
+ }
+
+ public function setNoTrack($flag)
+ {
+ $this->noTrack = $flag;
+ }
+
+ public function getNoTrack()
+ {
+ return $this->noTrack;
+ }
+
+ public function isNoTrack()
+ {
+ return $this->getNoTrack();
+ }
+
+ public function setForce($flag)
+ {
+ $this->force = $flag;
+ }
+
+ public function getForce()
+ {
+ return $this->force;
+ }
+
+ public function isForce()
+ {
+ return $this->getForce();
+ }
+
+ public function setBranchname($branchname)
+ {
+ $this->branchname = $branchname;
+ }
+
+ public function getBranchname()
+ {
+ return $this->branchname;
+ }
+
+ public function setStartPoint($startPoint)
+ {
+ $this->startPoint = $startPoint;
+ }
+
+ public function getStartPoint()
+ {
+ return $this->startPoint;
+ }
+
+ public function setDelete($flag)
+ {
+ $this->extraOptions['d'] = $flag;
+ }
+
+ public function getDelete()
+ {
+ return $this->extraOptions['d'];
+ }
+
+ public function isDelete()
+ {
+ return $this->getDelete();
+ }
+
+ public function setForceDelete($flag)
+ {
+ $this->extraOptions['D'] = $flag;
+ }
+
+ public function getForceDelete()
+ {
+ return $this->extraOptions['D'];
+ }
+
+ public function setMove($flag)
+ {
+ $this->extraOptions['m'] = $flag;
+ }
+
+ public function getMove()
+ {
+ return $this->extraOptions['m'];
+ }
+
+ public function isMove()
+ {
+ return $this->getMove();
+ }
+
+ public function setForceMove($flag)
+ {
+ $this->extraOptions['M'] = $flag;
+ }
+
+ public function getForceMove()
+ {
+ return $this->extraOptions['M'];
+ }
+
+ public function isForceMove()
+ {
+ return $this->getForceMove();
+ }
+
+ public function setNewBranch($name)
+ {
+ $this->newbranch = $name;
+ }
+
+ public function getNewBranch()
+ {
+ return $this->newbranch;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitCheckoutTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitCheckoutTask.php
new file mode 100644
index 00000000..16a2bd9f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitCheckoutTask.php
@@ -0,0 +1,256 @@
+<?php
+/*
+ * $Id: a1dcb809b44bfd34c3af154683dd2200c814e5f0 $
+ *
+ * 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/git/GitBaseTask.php';
+/**
+ * Wrapper around git-checkout
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: a1dcb809b44bfd34c3af154683dd2200c814e5f0 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitCheckoutTask extends GitBaseTask
+{
+ /**
+ * Branch name
+ * @var string
+ */
+ private $branchname;
+
+ /**
+ * If not HEAD, specify starting point
+ * @var string
+ */
+ private $startPoint;
+
+ /**
+ * --force, -f key to git-checkout
+ * @var boolean
+ */
+ private $force = false;
+
+ /**
+ * --quiet, -q key to git-checkout
+ * @var boolean
+ */
+ private $quiet = false;
+
+ /**
+ * When creating a new branch, set up "upstream" configuration.
+ * --track key to git-checkout
+ * @var boolean
+ */
+ private $track = false;
+
+ /**
+ * Do not set up "upstream" configuration
+ * --no-track key to git-checkout
+ * @var boolean
+ */
+ private $noTrack = false;
+
+ /**
+ * -b, -B, -m options to git-checkout
+ * Respective task options:
+ * create, forceCreate, merge
+ * @var array
+ */
+ private $extraOptions = array(
+ 'b' => false,
+ 'B' => false,
+ 'm' => false,
+ );
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+ if (null === $this->getBranchname()) {
+ throw new BuildException('"branchname" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('checkout');
+ $command
+ ->setOption('no-track', $this->isNoTrack())
+ ->setOption('q', $this->isQuiet())
+ ->setOption('force', $this->isForce())
+ ->setOption('b', $this->isCreate())
+ ->setOption('B', $this->isForceCreate())
+ ->setOption('m', $this->isMerge());
+ if ($this->isNoTrack()) {
+ $command->setOption('track', $this->isTrack());
+ }
+
+ $command->addArgument($this->getBranchname());
+
+ if (null !== $this->getStartPoint()) {
+ $command->addArgument($this->getStartPoint());
+ }
+
+ $this->log('git-checkout command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log(
+ sprintf('git-checkout: checkout "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ $this->log('git-checkout output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setBranchname($branchname)
+ {
+ $this->branchname = $branchname;
+ }
+
+ public function getBranchname()
+ {
+ return $this->branchname;
+ }
+
+ public function setStartPoint($startPoint)
+ {
+ $this->startPoint = $startPoint;
+ }
+
+ public function getStartPoint()
+ {
+ return $this->startPoint;
+ }
+
+ public function setForce($flag)
+ {
+ $this->force = $flag;
+ }
+
+ public function getForce()
+ {
+ return $this->force;
+ }
+
+ public function isForce()
+ {
+ return $this->getForce();
+ }
+
+ public function setQuiet($flag)
+ {
+ $this->quiet = $flag;
+ }
+
+ public function getQuiet()
+ {
+ return $this->quiet;
+ }
+
+ public function isQuiet()
+ {
+ return $this->getQuiet();
+ }
+
+ public function setTrack($flag)
+ {
+ $this->track = $flag;
+ }
+
+ public function getTrack()
+ {
+ return $this->track;
+ }
+
+ public function isTrack()
+ {
+ return $this->getTrack();
+ }
+
+ public function setNoTrack($flag)
+ {
+ $this->noTrack = $flag;
+ }
+
+ public function getNoTrack()
+ {
+ return $this->noTrack;
+ }
+
+ public function isNoTrack()
+ {
+ return $this->getNoTrack();
+ }
+
+ public function setCreate($flag)
+ {
+ $this->extraOptions['b'] = $flag;
+ }
+
+ public function getCreate()
+ {
+ return $this->extraOptions['b'];
+ }
+
+ public function isCreate()
+ {
+ return $this->getCreate();
+ }
+
+ // -B flag is not found in all versions of git
+ // --force is present everywhere
+ public function setForceCreate($flag)
+ {
+ $this->setForce($flag);
+ }
+
+ public function getForceCreate()
+ {
+ return $this->extraOptions['B'];
+ }
+
+ public function isForceCreate()
+ {
+ return $this->getForceCreate();
+ }
+
+ public function setMerge($flag)
+ {
+ $this->extraOptions['m'] = $flag;
+ }
+
+ public function getMerge()
+ {
+ return $this->extraOptions['m'];
+ }
+
+ public function isMerge()
+ {
+ return $this->getMerge();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitCloneTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitCloneTask.php
new file mode 100644
index 00000000..3d1eb76f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitCloneTask.php
@@ -0,0 +1,128 @@
+<?php
+/*
+ * $Id: 0d9ce448c11e505885b9c5362f5c2d399e205f90 $
+ *
+ * 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/git/GitBaseTask.php';
+/**
+ * Wrapper around git-clone
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 0d9ce448c11e505885b9c5362f5c2d399e205f90 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitCloneTask extends GitBaseTask
+{
+ /**
+ * Whether --bare key should be set for git-init
+ * @var string
+ */
+ private $isBare = false;
+
+ /**
+ * Path to target directory
+ * @var string
+ */
+ private $targetPath;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ if (null === $this->getTargetPath()) {
+ throw new BuildException('"targetPath" is required parameter');
+ }
+
+ $files = @scandir($this->getTargetPath());
+ if (isset($files) && is_array($files) && (count($files) > 2)) {
+ throw new BuildException(
+ sprintf(
+ '"%s" target directory is not empty',
+ $this->getTargetPath())
+ );
+ }
+
+ $client = $this->getGitClient(false, getcwd());
+
+ try {
+ $client->createClone(
+ $this->getRepository(),
+ $this->isBare(),
+ $this->getTargetPath());
+ } catch (Exception $e) {
+ throw new BuildException('The remote end hung up unexpectedly');
+ }
+
+ $msg = 'git-clone: cloning '
+ . ($this->isBare() ? '(bare) ' : '')
+ . '"' . $this->getRepository() .'" repository'
+ . ' to "' . $this->getTargetPath() .'" directory';
+ $this->log($msg, Project::MSG_INFO);
+ }
+
+ /**
+ * Get path to target direcotry repo
+ *
+ * @return string
+ */
+ public function getTargetPath()
+ {
+ return $this->targetPath;
+ }
+
+ /**
+ * Set path to source repo
+ *
+ * @param string $targetPath Path to repository used as source
+ * @return void
+ */
+ public function setTargetPath($targetPath)
+ {
+ $this->targetPath = $targetPath;
+ }
+
+ /**
+ * Alias @see getBare()
+ *
+ * @return string
+ */
+ public function isBare()
+ {
+ return $this->getBare();
+ }
+
+ public function getBare()
+ {
+ return $this->isBare;
+ }
+
+ public function setBare($flag)
+ {
+ $this->isBare = (bool)$flag;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitCommitTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitCommitTask.php
new file mode 100644
index 00000000..71b26ab9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitCommitTask.php
@@ -0,0 +1,179 @@
+<?php
+/*
+ * $Id: 355a6d3cf8e182652b4acf3af0a6cd3eaa58fd02 $
+ *
+ * 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/git/GitBaseTask.php';
+/**
+ * Wrapper around git-commit
+ *
+ * @package Phing.tasks.ext.git
+ * @author Jonathan Creasy <jonathan.creasy@gmail.com>
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitCommitTask extends GitBaseTask
+{
+ /**
+ * Path to target directory
+ * @var string
+ */
+ private $targetPath;
+
+ private $allFiles;
+
+ private $message;
+
+ private $files;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ if (null === $this->getTargetPath()) {
+ throw new BuildException('"targetPath" is required parameter');
+ }
+
+ if ($this->allFiles !== true && empty($this->files))
+ {
+ throw new BuildException('"allFiles" cannot be false if no files are specified.');
+ }
+
+ $client = $this->getGitClient(false, $this->getTargetPath());
+
+ $options = Array();
+
+ if ($this->allFiles === true)
+ {
+ $options['all'] = true;
+ }
+
+ $arguments = Array();
+ if ($this->allFiles !== true && is_array($this->files))
+ {
+ foreach($files as $file)
+ {
+ $arguments[] = $file;
+ }
+ }
+
+ if (!empty($this->message))
+ {
+ $arguments[] = $this->message;
+ } else {
+ $options['allow-empty-message'] = true;
+ }
+
+ try {
+ $command = $git->Command('commit');
+ $command->setArguments($arguments);
+ $command->setOptions($options);
+ $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('The remote end hung up unexpectedly');
+ }
+
+ $msg = 'git-commit: Executed git commit ';
+ foreach ($options as $option=>$value)
+ {
+
+ $msg .= ' --' . $options . '=' . $value;
+ }
+
+ foreach ($arguments as $argument)
+ {
+ $msg .= ' ' . $argument;
+ }
+
+ $this->log($msg, Project::MSG_INFO);
+ }
+
+ /**
+ * Get path to target direcotry repo
+ *
+ * @return string
+ */
+ public function getTargetPath()
+ {
+ return $this->targetPath;
+ }
+
+ /**
+ * Set path to source repo
+ *
+ * @param string $targetPath Path to repository used as source
+ * @return void
+ */
+ public function setTargetPath($targetPath)
+ {
+ $this->targetPath = $targetPath;
+ }
+
+ /**
+ * Alias @see getAllFiles()
+ *
+ * @return string
+ */
+ public function isallFiles()
+ {
+ return $this->getallFiles();
+ }
+
+ public function getallFiles()
+ {
+ return $this->allFiles;
+ }
+
+ public function setallFiles($flag)
+ {
+ $this->allFiles = (bool)$flag;
+ }
+
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ public function setMessage($message)
+ {
+ $this->message = $message;
+ }
+
+ public function getFiles()
+ {
+ return $this->files;
+ }
+
+ public function setFiles($files)
+ {
+ if (!$empty($files) && is_array($files))
+ {
+ $this->setallfiles(false);
+ $this->Files = $files;
+ } else {
+ $this->Files = null;
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitFetchTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitFetchTask.php
new file mode 100644
index 00000000..4b3e8a3d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitFetchTask.php
@@ -0,0 +1,284 @@
+<?php
+/*
+ * $Id: bcddbc1cd2e77003746b048568da8111b48da2fb $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-fetch
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: bcddbc1cd2e77003746b048568da8111b48da2fb $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitFetchTask extends GitBaseTask
+{
+ /**
+ * --force, -f key to git-fetch
+ * @var boolean
+ */
+ private $force = false;
+
+ /**
+ * --quiet, -q key to git-fetch
+ * @var boolean
+ */
+ private $quiet = false;
+
+ /**
+ * Fetch all remotes
+ * --all key to git-fetch
+ * @var boolean
+ */
+ private $allRemotes = false;
+
+ /**
+ * Keep downloaded pack
+ * --keep key to git-fetch
+ * @var boolean
+ */
+ private $keepFiles = false;
+
+ /**
+ * After fetching, remove any remote tracking branches which no longer
+ * exist on the remote.
+ * --prune key to git fetch
+ * @var boolean
+ */
+ private $prune = false;
+
+ /**
+ * Disable/enable automatic tag following
+ * --no-tags key to git-fetch
+ * @var boolean
+ */
+ private $noTags = false;
+
+ /**
+ * Fetch all tags (even not reachable from branch heads)
+ * --tags key to git-fetch
+ * @var boolean
+ */
+ private $tags = false;
+
+ /**
+ * <group> argument to git-fetch
+ * @var string
+ */
+ private $group;
+
+ /**
+ * <repository> argument to git-fetch
+ * @var string
+ */
+ private $source = 'origin';
+
+ /**
+ * <refspec> argument to git-fetch
+ * @var string
+ */
+ private $refspec;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('fetch');
+ $command
+ ->setOption('tags', $this->isTags())
+ ->setOption('no-tags', $this->isNoTags())
+ ->setOption('prune', $this->isPrune())
+ ->setOption('keep', $this->isKeepFiles())
+ ->setOption('q', $this->isQuiet())
+ ->setOption('force', $this->isForce());
+
+ // set operation target
+ if ($this->isAllRemotes()) { // --all
+ $command->setOption('all', true);
+ } elseif ($this->getGroup()) { // <group>
+ $command->addArgument($this->getGroup());
+ } elseif ($this->getSource()) { // <repository> [<refspec>]
+ $command->addArgument($this->getSource());
+ if ($this->getRefspec()) {
+ $command->addArgument($this->getRefspec());
+ }
+ } else {
+ throw new BuildException('No remote repository specified');
+ }
+
+ $this->log('git-fetch command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log(
+ sprintf('git-fetch: branch "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ $this->log('git-fetch output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setForce($flag)
+ {
+ $this->force = $flag;
+ }
+
+ public function getForce()
+ {
+ return $this->force;
+ }
+
+ public function isForce()
+ {
+ return $this->getForce();
+ }
+
+ public function setQuiet($flag)
+ {
+ $this->quiet = $flag;
+ }
+
+ public function getQuiet()
+ {
+ return $this->quiet;
+ }
+
+ public function isQuiet()
+ {
+ return $this->getQuiet();
+ }
+
+ public function setAll($flag)
+ {
+ $this->allRemotes = $flag;
+ }
+
+ public function getAll()
+ {
+ return $this->allRemotes;
+ }
+
+ public function isAllRemotes()
+ {
+ return $this->getAll();
+ }
+
+ public function setKeep($flag)
+ {
+ $this->keepFiles = $flag;
+ }
+
+ public function getKeep()
+ {
+ return $this->keepFiles;
+ }
+
+ public function isKeepFiles()
+ {
+ return $this->getKeep();
+ }
+
+ public function setPrune($flag)
+ {
+ $this->prune = $flag;
+ }
+
+ public function getPrune()
+ {
+ return $this->prune;
+ }
+
+ public function isPrune()
+ {
+ return $this->getPrune();
+ }
+
+ public function setNoTags($flag)
+ {
+ $this->noTags = $flag;
+ }
+
+ public function getNoTags()
+ {
+ return $this->noTags;
+ }
+
+ public function isNoTags()
+ {
+ return $this->getNoTags();
+ }
+
+ public function setTags($flag)
+ {
+ $this->tags = $flag;
+ }
+
+ public function getTags()
+ {
+ return $this->tags;
+ }
+
+ public function isTags()
+ {
+ return $this->getTags();
+ }
+
+ public function setSource($source)
+ {
+ $this->source = $source;
+ }
+
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ public function setRefspec($spec)
+ {
+ $this->refspec = $spec;
+ }
+
+ public function getRefspec()
+ {
+ return $this->refspec;
+ }
+
+ public function setGroup($group)
+ {
+ $this->group = $group;
+ }
+
+ public function getGroup()
+ {
+ return $this->group;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitGcTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitGcTask.php
new file mode 100644
index 00000000..12de4119
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitGcTask.php
@@ -0,0 +1,158 @@
+<?php
+/*
+ * $Id: 13487520850c3a7ad71d85f02afbddfd408bfbba $
+ *
+ * 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/git/GitBaseTask.php';
+/**
+ * Wrapper around git-gc
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 13487520850c3a7ad71d85f02afbddfd408bfbba $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitGcTask extends GitBaseTask
+{
+ /**
+ * --aggressive key to git-gc
+ * @var boolean
+ */
+ private $isAggressive = false;
+
+ /**
+ * --auto key to git-gc
+ * @var boolean
+ */
+ private $isAuto = false;
+
+ /**
+ * --no-prune key to git-gc
+ * @var boolean
+ */
+ private $noPrune = false;
+
+ /**
+ * --prune=<date>option of git-gc
+ * @var string
+ */
+ private $prune = '2.weeks.ago';
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('gc');
+ $command
+ ->setOption('aggressive', $this->isAggressive())
+ ->setOption('auto', $this->isAuto())
+ ->setOption('no-prune', $this->isNoPrune());
+ if ($this->isNoPrune() == false) {
+ $command->setOption('prune', $this->getPrune());
+ }
+
+ // suppress output
+ $command->setOption('q');
+
+ $this->log('git-gc command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed');
+ }
+
+ $this->log(
+ sprintf('git-gc: cleaning up "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ }
+
+ /**
+ * @see getAggressive()
+ */
+ public function isAggressive()
+ {
+ return $this->getAggressive();
+ }
+
+ public function getAggressive()
+ {
+ return $this->isAggressive;
+ }
+
+ public function setAggressive($flag)
+ {
+ $this->isAggressive = (bool)$flag;
+ }
+
+ /**
+ * @see getAuto()
+ */
+ public function isAuto()
+ {
+ return $this->getAuto();
+ }
+
+ public function getAuto()
+ {
+ return $this->isAuto;
+ }
+
+ public function setAuto($flag)
+ {
+ $this->isAuto = (bool)$flag;
+ }
+
+ /**
+ * @see NoPrune()
+ */
+ public function isNoPrune()
+ {
+ return $this->getNoPrune();
+ }
+
+ public function getNoPrune()
+ {
+ return $this->noPrune;
+ }
+
+ public function setNoPrune($flag)
+ {
+ $this->noPrune = (bool)$flag;
+ }
+
+ public function getPrune()
+ {
+ return $this->prune;
+ }
+
+ public function setPrune($date)
+ {
+ $this->prune = $date;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitInitTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitInitTask.php
new file mode 100644
index 00000000..b4654cae
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitInitTask.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * $Id: 5e66bb51f299c733e4410258f40dcf61f6e96e2f $
+ *
+ * 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/BuildException.php';
+require_once 'phing/tasks/ext/git/GitBaseTask.php';
+
+/**
+ * Repository initialization task
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 5e66bb51f299c733e4410258f40dcf61f6e96e2f $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitInitTask extends GitBaseTask
+{
+
+ /**
+ * Whether --bare key should be set for git-init
+ * @var string
+ */
+ private $isBare = false;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient();
+ $client->initRepository($this->isBare());
+
+ $msg = 'git-init: initializing '
+ . ($this->isBare() ? '(bare) ' : '')
+ . '"' . $this->getRepository() .'" repository';
+ $this->log($msg, Project::MSG_INFO);
+ }
+
+ /**
+ * Alias @see getBare()
+ *
+ * @return string
+ */
+ public function isBare()
+ {
+ return $this->getBare();
+ }
+
+ public function getBare()
+ {
+ return $this->isBare;
+ }
+
+ public function setBare($flag)
+ {
+ $this->isBare = (bool)$flag;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitLogTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitLogTask.php
new file mode 100644
index 00000000..c1d8058a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitLogTask.php
@@ -0,0 +1,270 @@
+<?php
+/*
+ * $Id: 27b94c44aa26823164ce02628de06ff8b44717f7 $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-log
+ *
+ * @author Evan Kaufman <evan@digitalflophouse.com>
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 27b94c44aa26823164ce02628de06ff8b44717f7 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.5
+ */
+class GitLogTask extends GitBaseTask
+{
+ /**
+ * Generate a diffstat. See --stat of git-log
+ * @var string|boolean
+ */
+ private $stat = false;
+
+ /**
+ * Names + status of changed files. See --name-status of git-log
+ * @var boolean
+ */
+ private $nameStatus = false;
+
+ /**
+ * Number of commits to show. See -<n>|-n|--max-count of git-log
+ * @var integer
+ */
+ private $maxCount;
+
+ /**
+ * Don't show commits with more than one parent. See --no-merges of git-log
+ * @var boolean
+ */
+ private $noMerges = false;
+
+ /**
+ * Commit format. See --format of git-log
+ * @var string
+ */
+ private $format = 'medium';
+
+ /**
+ * Date format. See --date of git-log
+ * @var string
+ */
+ private $date;
+
+ /**
+ * <since> argument to git-log
+ * @var string
+ */
+ private $sinceCommit;
+
+ /**
+ * <until> argument to git-log
+ * @var string
+ */
+ private $untilCommit = 'HEAD';
+
+ /**
+ * <path> arguments to git-log
+ * Accepts one or more paths delimited by PATH_SEPARATOR
+ * @var string
+ */
+ private $paths;
+
+ /**
+ * Property name to set with output value from git-log
+ * @var string
+ */
+ private $outputProperty;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('log');
+ $command
+ ->setOption('stat', $this->getStat())
+ ->setOption('name-status', $this->isNameStatus())
+ ->setOption('no-merges', $this->isNoMerges())
+ ->setOption('format', $this->getFormat());
+
+ if (null !== $this->getMaxCount()) {
+ $command->setOption('max-count', $this->getMaxCount());
+ }
+
+ if (null !== $this->getDate()) {
+ $command->setOption('date', $this->getDate());
+ }
+
+ if (null !== $this->getSince()) {
+ $command->setOption('since', $this->getSince());
+ }
+ $command->setOption('until', $this->getUntil());
+
+ $command->addDoubleDash(true);
+ if (null !== $this->getPaths()) {
+ $command->addDoubleDash(false);
+ $paths = explode(PATH_SEPARATOR, $this->getPaths());
+ foreach ($paths as $path) {
+ $command->addArgument($path);
+ }
+ }
+
+ $this->log('git-log command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed');
+ }
+
+ if (null !== $this->outputProperty) {
+ $this->project->setProperty($this->outputProperty, $output);
+ }
+
+ $this->log(
+ sprintf('git-log: commit log for "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ $this->log('git-log output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setStat($stat)
+ {
+ $this->stat = $stat;
+ }
+
+ public function getStat()
+ {
+ return $this->stat;
+ }
+
+ public function setNameStatus($flag)
+ {
+ $this->nameStatus = (boolean)$flag;
+ }
+
+ public function getNameStatus()
+ {
+ return $this->nameStatus;
+ }
+
+ public function isNameStatus()
+ {
+ return $this->getNameStatus();
+ }
+
+ public function setMaxCount($count)
+ {
+ $this->maxCount = (int)$count;
+ }
+
+ public function getMaxCount()
+ {
+ return $this->maxCount;
+ }
+
+ public function setNoMerges($flag)
+ {
+ $this->noMerges = (bool)$flag;
+ }
+
+ public function getNoMerges()
+ {
+ return $this->noMerges;
+ }
+
+ public function isNoMerges()
+ {
+ return $this->getNoMerges();
+ }
+
+ public function setFormat($format)
+ {
+ $this->format = $format;
+ }
+
+ public function getFormat()
+ {
+ return $this->format;
+ }
+
+ public function setDate($date)
+ {
+ $this->date = $date;
+ }
+
+ public function getDate()
+ {
+ return $this->date;
+ }
+
+ public function setSince($since)
+ {
+ $this->sinceCommit = $since;
+ }
+
+ public function getSince()
+ {
+ return $this->sinceCommit;
+ }
+
+ public function setAfter($after)
+ {
+ $this->setSince($after);
+ }
+
+ public function setUntil($until)
+ {
+ $this->untilCommit = $until;
+ }
+
+ public function getUntil()
+ {
+ return $this->untilCommit;
+ }
+
+ public function setBefore($before)
+ {
+ $this->setUntil($before);
+ }
+
+ public function setPaths($paths)
+ {
+ $this->paths = $paths;
+ }
+
+ public function getPaths()
+ {
+ return $this->paths;
+ }
+
+ public function setOutputProperty($prop)
+ {
+ $this->outputProperty = $prop;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitMergeTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitMergeTask.php
new file mode 100644
index 00000000..7a3e17fb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitMergeTask.php
@@ -0,0 +1,258 @@
+<?php
+/*
+ * $Id: 82fabd65e9247cb37fa3fe16c122d525db4fc697 $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-merge
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 82fabd65e9247cb37fa3fe16c122d525db4fc697 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ * @link http://www.kernel.org/pub/software/scm/git/docs/git-merge.html
+ */
+class GitMergeTask extends GitBaseTask
+{
+ /**
+ * <commit> of git-merge
+ * @var string
+ */
+ private $remote;
+
+ /**
+ * Commit message
+ * @var string
+ */
+ private $message;
+
+ /**
+ * Merge strategy. See -s <strategy> of git-merge
+ * Available strategies are: octopus ours recursive resolve subtree
+ * @var string
+ */
+ private $strategy;
+
+ /**
+ * -X or --strategy-option of git-merge
+ * @var string
+ */
+ private $strategyOption;
+
+ /**
+ * --commit key of git-merge
+ * @var boolean
+ */
+ private $commit = false;
+
+ /**
+ * --no-commit key of git-merge
+ * @var boolean
+ */
+ private $noCommit = false;
+
+ /**
+ * --ff --no-ff keys to git-merge
+ * @var boolean
+ */
+ private $fastForwardCommit = false;
+
+ /**
+ * --quiet, -q key to git-merge
+ * @var boolean
+ */
+ private $quiet = false;
+
+ /**
+ * Valid merge strategies
+ * @var array
+ */
+ private $validStrategies = array(
+ 'octopus', 'ours', 'recursive', 'resolve', 'subtree');
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+ $remotes = trim($this->getRemote());
+ if (null === $remotes || '' === $remotes) {
+ throw new BuildException('"remote" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('merge');
+ $command
+ ->setOption('commit', $this->isCommit())
+ ->setOption('q', $this->isQuiet());
+
+ if ($this->getMessage()) {
+ $command->setOption('message', $this->getMessage());
+ }
+
+ if (!$this->isCommit()) {
+ $command->setOption('no-commit', $this->isNoCommit());
+ }
+
+ if ($this->isFastForwardCommit()) {
+ $command->setOption('no-ff', true);
+ }
+
+ $strategy = $this->getStrategy();
+ if ($strategy) {
+ // check if strategy is valid
+ if (false === in_array($strategy, $this->validStrategies)) {
+ throw new BuildException(
+ "Could not find merge strategy '" . $strategy . "'\n".
+ "Available strategies are: " . implode(', ', $this->validStrategies));
+ }
+ $command->setOption('strategy', $strategy);
+ if ($this->getStrategyOption()) {
+ $command->setOption(
+ 'strategy-option', $this->getStrategyOption());
+ }
+ }
+
+ $remotes = explode(' ', $this->getRemote());
+ foreach ($remotes as $remote) {
+ $command->addArgument($remote);
+ }
+
+ $this->log('git-merge command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log(
+ sprintf('git-merge: replaying "%s" commits', $this->getRemote()),
+ Project::MSG_INFO);
+ $this->log('git-merge output: ' . trim($output), Project::MSG_INFO);
+
+ }
+
+ public function setRemote($remote)
+ {
+ $this->remote = $remote;
+ }
+
+ public function getRemote()
+ {
+ return $this->remote;
+ }
+
+ public function setMessage($message)
+ {
+ $this->message = $message;
+ }
+
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ public function setStrategy($strategy)
+ {
+ $this->strategy = $strategy;
+ }
+
+ public function getStrategy()
+ {
+ return $this->strategy;
+ }
+
+ public function setStrategyOption($strategyOption)
+ {
+ $this->strategyOption = $strategyOption;
+ }
+
+ public function getStrategyOption()
+ {
+ return $this->strategyOption;
+ }
+
+ public function setQuiet($flag)
+ {
+ $this->quiet = $flag;
+ }
+
+ public function getQuiet()
+ {
+ return $this->quiet;
+ }
+
+ public function isQuiet()
+ {
+ return $this->getQuiet();
+ }
+
+ public function setCommit($flag)
+ {
+ $this->commit = (boolean)$flag;
+ }
+
+ public function getCommit()
+ {
+ return $this->commit;
+ }
+
+ public function isCommit()
+ {
+ return $this->getCommit();
+ }
+
+ public function setNoCommit($flag)
+ {
+ $this->noCommit = (boolean)$flag;
+ }
+
+ public function getNoCommit()
+ {
+ return $this->noCommit;
+ }
+
+ public function isNoCommit()
+ {
+ return $this->getNoCommit();
+ }
+
+ public function setFastForwardCommit($flag)
+ {
+ $this->fastForwardCommit = $flag;
+ }
+
+ public function getFastForwardCommit()
+ {
+ return $this->fastForwardCommit;
+ }
+
+ public function isFastForwardCommit()
+ {
+ return $this->getFastForwardCommit();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitPullTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitPullTask.php
new file mode 100644
index 00000000..1f7cfcc1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitPullTask.php
@@ -0,0 +1,373 @@
+<?php
+/*
+ * $Id: f96a4faad59ab1b29abccd59d04269fe0c409084 $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-pull
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: f96a4faad59ab1b29abccd59d04269fe0c409084 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ */
+class GitPullTask extends GitBaseTask
+{
+ /**
+ * <repository> argument to git-pull
+ * @var string
+ */
+ private $source = 'origin';
+
+ /**
+ * <refspec> argument to git-pull
+ * @var string
+ */
+ private $refspec;
+
+ /**
+ * --rebase key to git-pull
+ * @var boolean
+ */
+ private $rebase = false;
+
+ /**
+ * --no-rebase key to git-pull
+ * Allow to override --rebase (if set to default true in configuration)
+ * @var boolean
+ */
+ private $noRebase = false;
+
+ /**
+ * Merge strategy. See -s <strategy> of git-pull
+ * @var string
+ */
+ private $strategy;
+
+ /**
+ * -X or --strategy-option of git-pull
+ * @var string
+ */
+ private $strategyOption;
+
+ /**
+ * Fetch all remotes
+ * --all key to git-pull
+ * @var boolean
+ */
+ private $allRemotes = false;
+
+ /**
+ * --append key to git-pull
+ * @var boolean
+ */
+ private $append = false;
+
+ /**
+ * Keep downloaded pack
+ * --keep key to git-pull
+ * @var boolean
+ */
+ private $keepFiles = false;
+
+ /**
+ * Disable/enable automatic tag following
+ * --no-tags key to git-pull
+ * @var boolean
+ */
+ private $noTags = false;
+
+ /**
+ * Fetch all tags (even not reachable from branch heads)
+ * --tags key to git-pull
+ * @var boolean
+ */
+ private $tags = false;
+
+ /**
+ * --quiet, -q key to git-pull
+ * @var boolean
+ */
+ private $quiet = true;
+
+ /**
+ * --force, -f key to git-pull
+ * @var boolean
+ */
+ private $force = false;
+
+ /**
+ * Valid merge strategies
+ * @var array
+ */
+ private $validStrategies = array(
+ 'octopus', 'ours', 'recursive', 'resolve', 'subtree');
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('pull');
+ $command
+ ->setOption('rebase', $this->isRebase());
+
+ if (!$this->isRebase()) {
+ $command->setOption('no-rebase', $this->isNoRebase());
+ }
+
+ $strategy = $this->getStrategy();
+ if ($strategy) {
+ // check if strategy is valid
+ if (false === in_array($strategy, $this->validStrategies)) {
+ throw new BuildException(
+ "Could not find merge strategy '" . $strategy . "'\n".
+ "Available strategies are: " . implode(', ', $this->validStrategies));
+ }
+ $command->setOption('strategy', $strategy);
+ if ($this->getStrategyOption()) {
+ $command->setOption(
+ 'strategy-option', $this->getStrategyOption());
+ }
+ }
+
+ // order of arguments is important
+ $command
+ ->setOption('tags', $this->isTags())
+ ->setOption('no-tags', $this->isNoTags())
+ ->setOption('keep', $this->isKeepFiles())
+ ->setOption('append', $this->isAppend())
+ ->setOption('q', $this->isQuiet())
+ ->setOption('force', $this->isForce());
+
+ // set operation target
+ if ($this->isAllRemotes()) { // --all
+ $command->setOption('all', true);
+ $this->log('git-pull: fetching from all remotes', Project::MSG_INFO);
+ } elseif ($this->getSource()) { // <repository> [<refspec>]
+ $command->addArgument($this->getSource());
+ if ($this->getRefspec()) {
+ $command->addArgument($this->getRefspec());
+ }
+ $this->log(
+ sprintf('git-pull: pulling from %s %s',
+ $this->getSource(), $this->getRefspec()),
+ Project::MSG_INFO);
+ } else {
+ throw new BuildException('No source repository specified');
+ }
+
+ $this->log('git-pull command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log('git-pull: complete', Project::MSG_INFO);
+ $this->log('git-pull output: ' . trim($output), Project::MSG_INFO);
+
+ }
+
+ public function setStrategy($strategy)
+ {
+ $this->strategy = $strategy;
+ }
+
+ public function getStrategy()
+ {
+ return $this->strategy;
+ }
+
+ public function setStrategyOption($strategyOption)
+ {
+ $this->strategyOption = $strategyOption;
+ }
+
+ public function getStrategyOption()
+ {
+ return $this->strategyOption;
+ }
+
+ public function setSource($source)
+ {
+ $this->source = $source;
+ }
+
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ public function setRefspec($spec)
+ {
+ $this->refspec = $spec;
+ }
+
+ public function getRefspec()
+ {
+ return $this->refspec;
+ }
+
+ public function setAll($flag)
+ {
+ $this->allRemotes = $flag;
+ }
+
+ public function getAll()
+ {
+ return $this->allRemotes;
+ }
+
+ public function isAllRemotes()
+ {
+ return $this->getAll();
+ }
+
+ public function setAppend($flag)
+ {
+ $this->append = (boolean)$flag;
+ }
+
+ public function getAppend()
+ {
+ return $this->append;
+ }
+
+ public function isAppend()
+ {
+ return $this->getAppend();
+ }
+
+ public function setKeep($flag)
+ {
+ $this->keepFiles = $flag;
+ }
+
+ public function getKeep()
+ {
+ return $this->keepFiles;
+ }
+
+ public function isKeepFiles()
+ {
+ return $this->getKeep();
+ }
+
+ public function setNoTags($flag)
+ {
+ $this->noTags = $flag;
+ }
+
+ public function getNoTags()
+ {
+ return $this->noTags;
+ }
+
+ public function isNoTags()
+ {
+ return $this->getNoTags();
+ }
+
+ public function setTags($flag)
+ {
+ $this->tags = $flag;
+ }
+
+ public function getTags()
+ {
+ return $this->tags;
+ }
+
+ public function isTags()
+ {
+ return $this->getTags();
+ }
+
+ public function setQuiet($flag)
+ {
+ $this->quiet = $flag;
+ }
+
+ public function getQuiet()
+ {
+ return $this->quiet;
+ }
+
+ public function isQuiet()
+ {
+ return $this->getQuiet();
+ }
+
+ public function setRebase($flag)
+ {
+ $this->rebase = (boolean)$flag;
+ }
+
+ public function getRebase()
+ {
+ return $this->rebase;
+ }
+
+ public function isRebase()
+ {
+ return $this->getRebase();
+ }
+
+ public function setNoRebase($flag)
+ {
+ $this->noRebase = (boolean)$flag;
+ }
+
+ public function getNoRebase()
+ {
+ return $this->noRebase;
+ }
+
+ public function isNoRebase()
+ {
+ return $this->getNoRebase();
+ }
+
+ public function setForce($flag)
+ {
+ $this->force = $flag;
+ }
+
+ public function getForce()
+ {
+ return $this->force;
+ }
+
+ public function isForce()
+ {
+ return $this->getForce();
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitPushTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitPushTask.php
new file mode 100644
index 00000000..996fa57f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitPushTask.php
@@ -0,0 +1,255 @@
+<?php
+/*
+ * $Id: a01e7e9f6cc92e419e82b4e99e4a45de6a61eba8 $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper aroung git-push
+ *
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: a01e7e9f6cc92e419e82b4e99e4a45de6a61eba8 $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.3
+ * @link http://www.kernel.org/pub/software/scm/git/docs/git-push.html
+ */
+class GitPushTask extends GitBaseTask
+{
+ /**
+ * Instead of naming each ref to push, specifies that all refs
+ * --all key to git-push
+ * @var boolean
+ */
+ private $allRemotes = false;
+
+ /**
+ * Mirror to remote repository
+ * --mirror key to git-push
+ * @var boolean
+ */
+ private $mirror = false;
+
+ /**
+ * Same as prefixing repos with colon
+ * --delete argument to git-push
+ * @var string
+ */
+ private $delete = false;
+
+ /**
+ * Push all refs under refs/tags
+ * --tags key to git-fetch
+ * @var boolean
+ */
+ private $tags = false;
+
+ /**
+ * <repository> argument to git-push
+ * @var string
+ */
+ private $destination = 'origin';
+
+ /**
+ * <refspec> argument to git-push
+ * @var string
+ */
+ private $refspec;
+
+ /**
+ * --force, -f key to git-push
+ * @var boolean
+ */
+ private $force = false;
+
+ /**
+ * --quiet, -q key to git-push
+ * @var boolean
+ */
+ private $quiet = true;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('push');
+ $command
+ ->setOption('tags', $this->isTags())
+ ->setOption('mirror', $this->isMirror())
+ ->setOption('delete', $this->isDelete())
+ ->setOption('q', $this->isQuiet())
+ ->setOption('force', $this->isForce());
+
+ // set operation target
+ if ($this->isAllRemotes()) { // --all
+ $command->setOption('all', true);
+ $this->log('git-push: push to all refs', Project::MSG_INFO);
+ } elseif ($this->isMirror()) { // <repository> [<refspec>]
+ $command->setOption('mirror', true);
+ $this->log('git-push: mirror all refs', Project::MSG_INFO);
+ } elseif ($this->getDestination()) { // <repository> [<refspec>]
+ $command->addArgument($this->getDestination());
+ if ($this->getRefspec()) {
+ $command->addArgument($this->getRefspec());
+ }
+ $this->log(
+ sprintf('git-push: pushing to %s %s',
+ $this->getDestination(), $this->getRefspec()),
+ Project::MSG_INFO);
+ } else {
+ throw new BuildException('At least one destination must be provided');
+ }
+
+ $this->log('git-push command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ throw new BuildException('Task execution failed.');
+ }
+
+ $this->log('git-push: complete', Project::MSG_INFO);
+ if ($this->isDelete()) {
+ $this->log('git-push: branch delete requested', Project::MSG_INFO);
+ }
+ $this->log('git-push output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setAll($flag)
+ {
+ $this->allRemotes = $flag;
+ }
+
+ public function getAll()
+ {
+ return $this->allRemotes;
+ }
+
+ public function isAllRemotes()
+ {
+ return $this->getAll();
+ }
+
+ public function setMirror($flag)
+ {
+ $this->mirror = (boolean)$flag;
+ }
+
+ public function getMirror()
+ {
+ return $this->mirror;
+ }
+
+ public function isMirror()
+ {
+ return $this->getMirror();
+ }
+
+ public function setDelete($flag)
+ {
+ $this->delete = (boolean)$flag;
+ }
+
+ public function getDelete()
+ {
+ return $this->delete;
+ }
+
+ public function isDelete()
+ {
+ return $this->getDelete();
+ }
+
+ public function setTags($flag)
+ {
+ $this->tags = $flag;
+ }
+
+ public function getTags()
+ {
+ return $this->tags;
+ }
+
+ public function isTags()
+ {
+ return $this->getTags();
+ }
+
+ public function setDestination($destination)
+ {
+ $this->destination = $destination;
+ }
+
+ public function getDestination()
+ {
+ return $this->destination;
+ }
+
+ public function setRefspec($spec)
+ {
+ $this->refspec = $spec;
+ }
+
+ public function getRefspec()
+ {
+ return $this->refspec;
+ }
+
+ public function setForce($flag)
+ {
+ $this->force = $flag;
+ }
+
+ public function getForce()
+ {
+ return $this->force;
+ }
+
+ public function isForce()
+ {
+ return $this->getForce();
+ }
+
+ public function setQuiet($flag)
+ {
+ $this->quiet = $flag;
+ }
+
+ public function getQuiet()
+ {
+ return $this->quiet;
+ }
+
+ public function isQuiet()
+ {
+ return $this->getQuiet();
+ }
+
+
+
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/git/GitTagTask.php b/buildscripts/phing/classes/phing/tasks/ext/git/GitTagTask.php
new file mode 100644
index 00000000..864e71ba
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/git/GitTagTask.php
@@ -0,0 +1,406 @@
+<?php
+/*
+ * $Id: 127d4af12e159083935466773d1af788e46acd4e $
+ *
+ * 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/git/GitBaseTask.php';
+
+/**
+ * Wrapper around git-tag
+ *
+ * @author Evan Kaufman <evan@digitalflophouse.com>
+ * @author Victor Farazdagi <simple.square@gmail.com>
+ * @version $Id: 127d4af12e159083935466773d1af788e46acd4e $
+ * @package phing.tasks.ext.git
+ * @see VersionControl_Git
+ * @since 2.4.5
+ */
+class GitTagTask extends GitBaseTask
+{
+ /**
+ * Make unsigned, annotated tag object. See -a of git-tag
+ * @var boolean
+ */
+ private $annotate = false;
+
+ /**
+ * Make GPG-signed tag. See -s of git-tag
+ * @var boolean
+ */
+ private $sign = false;
+
+ /**
+ * Make GPG-signed tag, using given key. See -u of git-tag
+ * @var string
+ */
+ private $keySign;
+
+ /**
+ * Replace existing tag with given name. See -f of git-tag
+ * @var boolean
+ */
+ private $replace = false;
+
+ /**
+ * Delete existing tags with given names. See -d of git-tag
+ * @var boolean
+ */
+ private $delete = false;
+
+ /**
+ * Verify gpg signature of given tag names. See -v of git-tag
+ * @var boolean
+ */
+ private $verify = false;
+
+ /**
+ * List tags with names matching given pattern. See -l of git-tag
+ * @var boolean
+ */
+ private $list = false;
+
+ /**
+ * <num> specifies how many lines from the annotation, if any, are printed
+ * when using -l. See -n of git-tag
+ * @var int
+ */
+ private $num;
+
+ /**
+ * Only list tags containing specified commit. See --contains of git-tag
+ * @var string
+ */
+ private $contains;
+
+ /**
+ * Use given tag message. See -m of git-tag
+ * @var string
+ */
+ private $message;
+
+ /**
+ * Take tag message from given file. See -F of git-tag
+ * @var string
+ */
+ private $file;
+
+ /**
+ * <tagname> argument to git-tag
+ * @var string
+ */
+ private $name;
+
+ /**
+ * <commit> argument to git-tag
+ * @var string
+ */
+ private $commit;
+
+ /**
+ * <object> argument to git-tag
+ * @var string
+ */
+ private $object;
+
+ /**
+ * <pattern> argument to git-tag
+ * @var string
+ */
+ private $pattern;
+
+ /**
+ * Property name to set with output value from git-tag
+ * @var string
+ */
+ private $outputProperty;
+
+ /**
+ * The main entry point for the task
+ */
+ public function main()
+ {
+ if (null === $this->getRepository()) {
+ throw new BuildException('"repository" is required parameter');
+ }
+
+ $client = $this->getGitClient(false, $this->getRepository());
+ $command = $client->getCommand('tag');
+ $command
+ ->setOption('a', $this->isAnnotate())
+ ->setOption('s', $this->isSign())
+ ->setOption('f', $this->isReplace())
+ ->setOption('d', $this->isDelete())
+ ->setOption('v', $this->isVerify())
+ ->setOption('l', $this->isList());
+
+ if (null !== $this->getKeySign()) {
+ $command->setOption('u', $this->getKeySign());
+ }
+
+ if (null !== $this->getMessage()) {
+ $command->setOption('m', $this->getMessage());
+ }
+
+ if (null !== $this->getFile()) {
+ $command->setOption('F', $this->getFile());
+ }
+
+ // Use 'name' arg, if relevant
+ if (null != $this->getName() && false == $this->isList()) {
+ $command->addArgument($this->getName());
+ }
+
+ if (null !== $this->getKeySign() || $this->isAnnotate() || $this->isSign()) {
+ // Require a tag message or file
+ if (null === $this->getMessage() && null === $this->getFile()) {
+ throw new BuildException('"message" or "file" required to make a tag');
+ }
+ }
+
+ // Use 'commit' or 'object' args, if relevant
+ if (null !== $this->getCommit()) {
+ $command->addArgument($this->getCommit());
+ } else if (null !== $this->getObject()) {
+ $command->addArgument($this->getObject());
+ }
+
+ // Customize list (-l) options
+ if ($this->isList()) {
+ if (null !== $this->getContains()) {
+ $command->setOption('contains', $this->getContains());
+ }
+ if (null !== $this->getPattern()) {
+ $command->addArgument($this->getPattern());
+ }
+ if (null != $this->getNum()) {
+ $command->setOption('n', $this->getNum());
+ }
+ }
+
+ $this->log('git-tag command: ' . $command->createCommandString(), Project::MSG_INFO);
+
+ try {
+ $output = $command->execute();
+ } catch (Exception $e) {
+ $this->log($e->getMessage(), Project::MSG_ERR);
+ throw new BuildException('Task execution failed. ' . $e->getMessage());
+ }
+
+ if (null !== $this->outputProperty) {
+ $this->project->setProperty($this->outputProperty, $output);
+ }
+
+ $this->log(
+ sprintf('git-tag: tags for "%s" repository', $this->getRepository()),
+ Project::MSG_INFO);
+ $this->log('git-tag output: ' . trim($output), Project::MSG_INFO);
+ }
+
+ public function setAnnotate($flag)
+ {
+ $this->annotate = (bool)$flag;
+ }
+
+ public function getAnnotate()
+ {
+ return $this->annotate;
+ }
+
+ public function isAnnotate()
+ {
+ return $this->getAnnotate();
+ }
+
+ public function setSign($flag)
+ {
+ $this->sign = (bool)$flag;
+ }
+
+ public function getSign()
+ {
+ return $this->sign;
+ }
+
+ public function isSign()
+ {
+ return $this->getSign();
+ }
+
+ public function setKeySign($keyId)
+ {
+ $this->keySign = $keyId;
+ }
+
+ public function getKeySign()
+ {
+ return $this->keySign;
+ }
+
+ public function setReplace($flag)
+ {
+ $this->replace = (bool)$flag;
+ }
+
+ public function getReplace()
+ {
+ return $this->replace;
+ }
+
+ public function isReplace()
+ {
+ return $this->getReplace();
+ }
+
+ public function setForce($flag)
+ {
+ return $this->setReplace($flag);
+ }
+
+ public function setDelete($flag)
+ {
+ $this->delete = (bool)$flag;
+ }
+
+ public function getDelete()
+ {
+ return $this->delete;
+ }
+
+ public function isDelete()
+ {
+ return $this->getDelete();
+ }
+
+ public function setVerify($flag)
+ {
+ $this->verify = (bool)$flag;
+ }
+
+ public function getVerify()
+ {
+ return $this->verify;
+ }
+
+ public function isVerify()
+ {
+ return $this->getVerify();
+ }
+
+ public function setList($flag)
+ {
+ $this->list = (bool)$flag;
+ }
+
+ public function getList()
+ {
+ return $this->list;
+ }
+
+ public function isList()
+ {
+ return $this->getList();
+ }
+
+ public function setNum($num)
+ {
+ $this->num = (int)$num;
+ }
+
+ public function getNum()
+ {
+ return $this->num;
+ }
+
+ public function setContains($commit)
+ {
+ $this->contains = $commit;
+ }
+
+ public function getContains()
+ {
+ return $this->contains;
+ }
+
+ public function setMessage($msg)
+ {
+ $this->message = $msg;
+ }
+
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ public function getFile()
+ {
+ return $this->file;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setCommit($commit)
+ {
+ $this->commit = $commit;
+ }
+
+ public function getCommit()
+ {
+ return $this->commit;
+ }
+
+ public function setObject($object)
+ {
+ $this->object = $object;
+ }
+
+ public function getObject()
+ {
+ return $this->object;
+ }
+
+ public function setPattern($pattern)
+ {
+ $this->pattern = $pattern;
+ }
+
+ public function getPattern()
+ {
+ return $this->pattern;
+ }
+
+ public function setOutputProperty($prop)
+ {
+ $this->outputProperty = $prop;
+ }
+}
+
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 100755
index 00000000..38ec99d4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ * $Id: dbbc1b4830ba43116d5b5e5d20c749598eaf62b7 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: dbbc1b4830ba43116d5b5e5d20c749598eaf62b7 $
+ * @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);
+ }
+}
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 100755
index 00000000..5a31f355
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php
@@ -0,0 +1,642 @@
+<?php
+/**
+ * $Id: a6ce870b3d14be7f365468e3a272e5ac16128e93 $
+ *
+ * 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 <mrook@php.net>
+ * @author Andrew Eddie <andrew.eddie@jamboworks.com>
+ * @author Domenico Sgarbossa <sbraaaa@yahoo.it>
+ * @version $Id: a6ce870b3d14be7f365468e3a272e5ac16128e93 $
+ * @package phing.tasks.ext.ioncube
+ * @since 2.2.0
+ */
+class IoncubeEncoderTask extends Task
+{
+ private $ionSwitches = array();
+
+ private $ionOptions = array();
+
+ private $ionOptionsXS = array();
+
+ private $comments = array();
+
+ private $encoderName = 'ioncube_encoder';
+
+ private $fromDir = '';
+
+ private $ioncubePath = '/usr/local/ioncube';
+
+ private $phpVersion = '5';
+
+ private $targetOption = '';
+
+ private $toDir = '';
+
+ private $showCommandLine = false;
+
+ /**
+ * Sets whether to show command line before it is executed
+ */
+ function setShowCommandLine($value)
+ {
+ $this->showCommandLine = $value;
+ }
+
+ /**
+ * Adds a comment to be used in encoded files
+ */
+ function addComment(IoncubeComment $comment)
+ {
+ $this->comments[] = $comment;
+ }
+
+ /**
+ * Sets the allowed server
+ */
+ function setAllowedServer($value)
+ {
+ $this->ionOptionsXS['allowed-server'] = $value;
+ }
+
+ /**
+ * Returns the allowed server setting
+ */
+ function getAllowedServer()
+ {
+ return $this->ionOptionsXS['allowed-server'];
+ }
+
+ /**
+ * Sets the binary option
+ */
+ function setBinary($value)
+ {
+ $this->ionSwitches['binary'] = $value;
+ }
+
+ /**
+ * Returns the binary option
+ */
+ function getBinary()
+ {
+ return $this->ionSwitches['binary'];
+ }
+
+ /**
+ * Sets files or folders to copy (separated by space)
+ */
+ function setCopy($value)
+ {
+ $this->ionOptionsXS['copy'] = $value;
+ }
+
+ /**
+ * Returns the copy setting
+ */
+ function getCopy()
+ {
+ return $this->ionOptionsXS['copy'];
+ }
+
+ /**
+ * Sets additional file patterns, files or directories to encode,
+ * or to reverse the effect of copy (separated by space)
+ */
+ function setEncode($value)
+ {
+ $this->ionOptionsXS['encode'] = $value;
+ }
+
+ /**
+ * Returns the encode setting
+ */
+ function getEncode()
+ {
+ return $this->ionOptionsXS['encode'];
+ }
+
+ /**
+ * Sets regexps of additional files to encrypt (separated by space)
+ */
+ function setEncrypt($value)
+ {
+ $this->ionOptionsXS['encrypt'] = $value;
+ }
+
+ /**
+ * Returns regexps of additional files to encrypt (separated by space)
+ */
+ function getEncrypt()
+ {
+ return $this->ionOptionsXS['encrypt'];
+ }
+
+ /**
+ * Sets a period after which the files expire
+ */
+ function setExpirein($value)
+ {
+ $this->ionOptions['expire-in'] = $value;
+ }
+
+ /**
+ * Returns the expireIn setting
+ */
+ function getExpirein()
+ {
+ return $this->ionOptions['expire-in'];
+ }
+
+ /**
+ * Sets a YYYY-MM-DD date to expire the files
+ */
+ function setExpireon($value)
+ {
+ $this->ionOptions['expire-on'] = $value;
+ }
+
+ /**
+ * Returns the expireOn setting
+ */
+ function getExpireon()
+ {
+ return $this->ionOptions['expire-on'];
+ }
+
+ /**
+ * Sets the source directory
+ */
+ function setFromDir($value)
+ {
+ $this->fromDir = $value;
+ }
+
+ /**
+ * Returns the source directory
+ */
+ function getFromDir()
+ {
+ return $this->fromDir;
+ }
+
+ /**
+ * Set files and directories to ignore entirely and exclude from the target directory
+ * (separated by space).
+ */
+ function setIgnore($value)
+ {
+ $this->ionOptionsXS['ignore'] = $value;
+ }
+
+ /**
+ * Returns the ignore setting
+ */
+ function getIgnore()
+ {
+ return $this->ionOptionsXS['ignore'];
+ }
+
+ /**
+ * Sets the path to the ionCube encoder
+ */
+ function setIoncubePath($value)
+ {
+ $this->ioncubePath = $value;
+ }
+
+ /**
+ * Returns the path to the ionCube encoder
+ */
+ function getIoncubePath()
+ {
+ return $this->ioncubePath;
+ }
+
+ /**
+ * Set files and directories not to be ignored (separated by space).
+ */
+ function setKeep($value)
+ {
+ $this->ionOptionsXS['keep'] = $value;
+ }
+
+ /**
+ * Returns the ignore setting
+ */
+ function getKeep()
+ {
+ return $this->ionOptionsXS['keep'];
+ }
+
+ /**
+ * Sets the path to the license file to use
+ */
+ function setLicensePath($value)
+ {
+ $this->ionOptions['with-license'] = $value;
+ }
+
+ /**
+ * Returns the path to the license file to use
+ */
+ function getLicensePath()
+ {
+ return $this->ionOptions['with-license'];
+ }
+
+ /**
+ * Sets the no-doc-comments option
+ */
+ function setNoDocComments($value)
+ {
+ $this->ionSwitches['no-doc-comment'] = $value;
+ }
+
+ /**
+ * Returns the no-doc-comments option
+ */
+ function getNoDocComments()
+ {
+ return $this->ionSwitches['no-doc-comment'];
+ }
+
+ /**
+ * Sets the obfuscate option
+ */
+ function setObfuscate($value)
+ {
+ $this->ionOptionsXS['obfuscate'] = $value;
+ }
+
+ /**
+ * Returns the optimize option
+ */
+ function getObfuscate()
+ {
+ return $this->ionOptionsXS['obfuscate'];
+ }
+
+ /**
+ * Sets the obfuscation key (required if using the obfuscate option)
+ */
+ function setObfuscationKey($value)
+ {
+ $this->ionOptions['obfuscation-key'] = $value;
+ }
+
+ /**
+ * Returns the optimize option
+ */
+ function getObfuscationKey()
+ {
+ return $this->ionOptions['obfuscation-key'];
+ }
+
+ /**
+ * Sets the optimize option
+ */
+ function setOptimize($value)
+ {
+ $this->ionOptions['optimize'] = $value;
+ }
+
+ /**
+ * Returns the optimize option
+ */
+ function getOptimize()
+ {
+ return $this->ionOptions['optimize'];
+ }
+
+ /**
+ * Sets the passphrase to use when encoding files
+ */
+ function setPassPhrase($value)
+ {
+ $this->ionOptions['passphrase'] = $value;
+ }
+
+ /**
+ * Returns the passphrase to use when encoding files
+ */
+ function getPassPhrase()
+ {
+ return $this->ionOptions['passphrase'];
+ }
+
+ /**
+ * Sets the version of PHP to use (defaults to 5)
+ */
+ function setPhpVersion($value)
+ {
+ $this->phpVersion = $value;
+ }
+
+ /**
+ * Returns the version of PHP to use (defaults to 5)
+ */
+ function getPhpVersion()
+ {
+ return $this->phpVersion;
+ }
+
+ /**
+ * Sets the target directory
+ */
+ function setToDir($value)
+ {
+ $this->toDir = $value;
+ }
+
+ /**
+ * Returns the target directory
+ */
+ function getToDir()
+ {
+ return $this->toDir;
+ }
+
+ /**
+ * Sets the without-runtime-loader-support option
+ */
+ function setWithoutRuntimeLoaderSupport($value)
+ {
+ $this->ionSwitches['without-runtime-loader-support'] = $value;
+ }
+
+ /**
+ * Returns the without-runtime-loader-support option
+ */
+ function getWithoutRuntimeLoaderSupport()
+ {
+ return $this->ionSwitches['without-runtime-loader-support'];
+ }
+
+ /**
+ * Sets the no-short-open-tags option
+ */
+ function setNoShortOpenTags($value)
+ {
+ $this->ionSwitches['no-short-open-tags'] = $value;
+ }
+
+ /**
+ * Returns the no-short-open-tags option
+ */
+ function getNoShortOpenTags()
+ {
+ return $this->ionSwitches['no-short-open-tags'];
+ }
+
+ /**
+ * Sets the ignore-deprecated-warnings option
+ */
+ function setIgnoreDeprecatedWarnings($value)
+ {
+ $this->ionSwitches['ignore-deprecated-warnings'] = $value;
+ }
+
+ /**
+ * Returns the ignore-deprecated-warnings option
+ */
+ function getIgnoreDeprecatedWarnings()
+ {
+ return $this->ionSwitches['ignore-deprecated-warnings'];
+ }
+
+ /**
+ * Sets the ignore-strict-warnings option
+ */
+ function setIgnoreStrictWarnings($value)
+ {
+ $this->ionSwitches['ignore-strict-warnings'] = $value;
+ }
+
+ /**
+ * Returns the ignore-strict-warnings option
+ */
+ function getIgnoreStrictWarnings()
+ {
+ return $this->ionSwitches['ignore-strict-warnings'];
+ }
+
+ /**
+ * Sets the allow-encoding-into-source option
+ */
+ function setAllowEncodingIntoSource($value)
+ {
+ $this->ionSwitches['allow-encoding-into-source'] = $value;
+ }
+
+ /**
+ * Returns the allow-encoding-into-source option
+ */
+ function getAllowEncodingIntoSource()
+ {
+ return $this->ionSwitches['allow-encoding-into-source'];
+ }
+
+ /**
+ * Sets the message-if-no-loader option
+ */
+ function setMessageIfNoLoader($value)
+ {
+ $this->ionOptions['message-if-no-loader'] = $value;
+ }
+
+ /**
+ * Returns the message-if-no-loader option
+ */
+ function getMessageIfNoLoader()
+ {
+ return $this->ionOptions['message-if-no-loader'];
+ }
+
+ /**
+ * Sets the action-if-no-loader option
+ */
+ function setActionIfNoLoader($value)
+ {
+ $this->ionOptions['action-if-no-loader'] = $value;
+ }
+
+ /**
+ * Returns the action-if-no-loader option
+ */
+ function getActionIfNoLoader()
+ {
+ return $this->ionOptions['action-if-no-loader'];
+ }
+
+ /**
+ * 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 callback-file option
+ */
+ function setCallbackFile($value)
+ {
+ $this->ionOptions['callback-file'] = $value;
+ }
+
+ /**
+ * Returns the callback-file option
+ */
+ function getCallbackFile()
+ {
+ return $this->ionOptions['callback-file'];
+ }
+
+ /**
+ * Sets the obfuscation-exclusions-file option
+ */
+ function setObfuscationExclusionFile($value)
+ {
+ $this->ionOptions['obfuscation-exclusion-file'] = $value;
+ }
+
+ /**
+ * Returns the obfuscation-exclusions-file option
+ */
+ function getObfuscationExclusionFile()
+ {
+ return $this->ionOptions['obfuscation-exclusion-file'];
+ }
+
+ /**
+ * 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...");
+
+ if ($this->showCommandLine)
+ {
+ $this->log("Command line: ".$encoder->__toString() . ' ' . $arguments);
+ }
+
+ 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 = '';
+
+ foreach ($this->ionSwitches as $name => $value)
+ {
+ if ($value)
+ {
+ $arguments.= "--$name ";
+ }
+ }
+
+ foreach ($this->ionOptions as $name => $value)
+ {
+ /**
+ * action-if-no-loader value is a php source snippet so it is
+ * better to handle it this way to prevent quote problems!
+ */
+ if ($name == 'action-if-no-loader')
+ {
+ $arguments.= "--$name \"$value\" ";
+ }
+ else
+ {
+ $arguments.= "--$name '$value' ";
+ }
+ }
+
+ foreach ($this->ionOptionsXS as $name => $value)
+ {
+ foreach (explode(' ', $value) as $arg)
+ {
+ $arguments.= "--$name '$arg' ";
+ }
+ }
+
+ foreach ($this->comments as $comment)
+ {
+ $arguments.= "--add-comment '" . $comment->getValue() . "' ";
+ }
+
+ 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 ($this->fromDir != '')
+ {
+ $arguments .= $this->fromDir . ' ';
+ }
+
+ if ($this->toDir != '')
+ {
+ $arguments .= "-o " . $this->toDir . ' ';
+ }
+
+ return $arguments;
+ }
+}
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 100755
index 00000000..6e7ab68a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * $Id: 555e4853cd742e4ef733e3df4051c49cda527b73 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: 555e4853cd742e4ef733e3df4051c49cda527b73 $
+ * @package phing.tasks.ext.ioncube
+ * @since 2.2.0
+ */
+class IoncubeLicenseTask extends Task
+{
+ private $ioncubePath = "/usr/local/ioncube";
+
+ private $licensePath = "";
+ private $passPhrase = "";
+ private $allowedServer = "";
+ private $expireOn = "";
+ private $expireIn = "";
+ 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;
+ }
+
+ /**
+ * Sets the --allowed-server option to use when generating the license
+ */
+ function setAllowedServer($allowedServer)
+ {
+ $this->allowedServer = $allowedServer;
+ }
+
+ /**
+ * Returns the --allowed-server option
+ */
+ function getAllowedServer()
+ {
+ return $this->allowedServer;
+ }
+
+ /**
+ * Sets the --expire-on option to use when generating the license
+ */
+ function setExpireOn($expireOn)
+ {
+ $this->expireOn = $expireOn;
+ }
+
+ /**
+ * Returns the --expire-on option
+ */
+ function getExpireOn()
+ {
+ return $this->expireOn;
+ }
+
+ /**
+ * Sets the --expire-in option to use when generating the license
+ */
+ function setExpireIn($expireIn)
+ {
+ $this->expireIn = $expireIn;
+ }
+
+ /**
+ * Returns the --expire-in option
+ */
+ function getExpireIn()
+ {
+ return $this->expireIn;
+ }
+
+ /**
+ * 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 . "' ";
+ }
+
+ if (!empty($this->allowedServer))
+ {
+ $arguments.= "--allowed-server {" . $this->allowedServer . "} ";
+ }
+
+ if (!empty($this->expireOn))
+ {
+ $arguments.= "--expire-on " . $this->expireOn . " ";
+ }
+
+ if (!empty($this->expireIn))
+ {
+ $arguments.= "--expire-in " . $this->expireIn . " ";
+ }
+
+ return $arguments;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMin.php b/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMin.php
new file mode 100644
index 00000000..44766fc1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMin.php
@@ -0,0 +1,292 @@
+<?php
+/**
+ * jsmin.php - PHP implementation of Douglas Crockford's JSMin.
+ *
+ * This is pretty much a direct port of jsmin.c to PHP with just a few
+ * PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
+ * outputs to stdout, this library accepts a string as input and returns another
+ * string as output.
+ *
+ * PHP 5 or higher is required.
+ *
+ * Permission is hereby granted to use this version of the library under the
+ * same terms as jsmin.c, which has the following license:
+ *
+ * --
+ * Copyright (c) 2002 Douglas Crockford (www.crockford.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * The Software shall be used for Good, not Evil.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * --
+ *
+ * @package JSMin
+ * @author Ryan Grove <ryan@wonko.com>
+ * @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
+ * @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 1.1.1 (2008-03-02)
+ * @link http://code.google.com/p/jsmin-php/
+ */
+
+class JSMin {
+ const ORD_LF = 10;
+ const ORD_SPACE = 32;
+
+ protected $a = '';
+ protected $b = '';
+ protected $input = '';
+ protected $inputIndex = 0;
+ protected $inputLength = 0;
+ protected $lookAhead = null;
+ protected $output = '';
+
+ // -- Public Static Methods --------------------------------------------------
+
+ public static function minify($js) {
+ $jsmin = new JSMin($js);
+ return $jsmin->min();
+ }
+
+ // -- Public Instance Methods ------------------------------------------------
+
+ public function __construct($input) {
+ $this->input = str_replace("\r\n", "\n", $input);
+ $this->inputLength = strlen($this->input);
+ }
+
+ // -- Protected Instance Methods ---------------------------------------------
+
+ protected function action($d) {
+ switch($d) {
+ case 1:
+ $this->output .= $this->a;
+
+ case 2:
+ $this->a = $this->b;
+
+ if ($this->a === "'" || $this->a === '"') {
+ for (;;) {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+
+ if ($this->a === $this->b) {
+ break;
+ }
+
+ if (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated string literal.');
+ }
+
+ if ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ }
+ }
+ }
+
+ case 3:
+ $this->b = $this->next();
+
+ if ($this->b === '/' && (
+ $this->a === '(' || $this->a === ',' || $this->a === '=' ||
+ $this->a === ':' || $this->a === '[' || $this->a === '!' ||
+ $this->a === '&' || $this->a === '|' || $this->a === '?')) {
+
+ $this->output .= $this->a . $this->b;
+
+ for (;;) {
+ $this->a = $this->get();
+
+ if ($this->a === '/') {
+ break;
+ } elseif ($this->a === '\\') {
+ $this->output .= $this->a;
+ $this->a = $this->get();
+ } elseif (ord($this->a) <= self::ORD_LF) {
+ throw new JSMinException('Unterminated regular expression '.
+ 'literal.');
+ }
+
+ $this->output .= $this->a;
+ }
+
+ $this->b = $this->next();
+ }
+ }
+ }
+
+ protected function get() {
+ $c = $this->lookAhead;
+ $this->lookAhead = null;
+
+ if ($c === null) {
+ if ($this->inputIndex < $this->inputLength) {
+ $c = $this->input[$this->inputIndex];
+ $this->inputIndex += 1;
+ } else {
+ $c = null;
+ }
+ }
+
+ if ($c === "\r") {
+ return "\n";
+ }
+
+ if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
+ return $c;
+ }
+
+ return ' ';
+ }
+
+ protected function isAlphaNum($c) {
+ return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
+ }
+
+ protected function min() {
+ $this->a = "\n";
+ $this->action(3);
+
+ while ($this->a !== null) {
+ switch ($this->a) {
+ case ' ':
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ } else {
+ $this->action(2);
+ }
+ break;
+
+ case "\n":
+ switch ($this->b) {
+ case '{':
+ case '[':
+ case '(':
+ case '+':
+ case '-':
+ $this->action(1);
+ break;
+
+ case ' ':
+ $this->action(3);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->b)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(2);
+ }
+ }
+ break;
+
+ default:
+ switch ($this->b) {
+ case ' ':
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ break;
+ }
+
+ $this->action(3);
+ break;
+
+ case "\n":
+ switch ($this->a) {
+ case '}':
+ case ']':
+ case ')':
+ case '+':
+ case '-':
+ case '"':
+ case "'":
+ $this->action(1);
+ break;
+
+ default:
+ if ($this->isAlphaNum($this->a)) {
+ $this->action(1);
+ }
+ else {
+ $this->action(3);
+ }
+ }
+ break;
+
+ default:
+ $this->action(1);
+ break;
+ }
+ }
+ }
+
+ return $this->output;
+ }
+
+ protected function next() {
+ $c = $this->get();
+
+ if ($c === '/') {
+ switch($this->peek()) {
+ case '/':
+ for (;;) {
+ $c = $this->get();
+
+ if (ord($c) <= self::ORD_LF) {
+ return $c;
+ }
+ }
+
+ case '*':
+ $this->get();
+
+ for (;;) {
+ switch($this->get()) {
+ case '*':
+ if ($this->peek() === '/') {
+ $this->get();
+ return ' ';
+ }
+ break;
+
+ case null:
+ throw new JSMinException('Unterminated comment.');
+ }
+ }
+
+ default:
+ return $c;
+ }
+ }
+
+ return $c;
+ }
+
+ protected function peek() {
+ $this->lookAhead = $this->get();
+ return $this->lookAhead;
+ }
+}
+
+/**
+ * @package JSMin
+ */
+class JSMinException extends Exception {}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMinTask.php b/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMinTask.php
new file mode 100644
index 00000000..26202942
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMinTask.php
@@ -0,0 +1,145 @@
+<?php
+/*
+ * $Id: 4a9a75fcd969cfc4e26a7f2c78836389e8be7864 $
+ *
+ * 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/jsmin/JsMin.php';
+
+/**
+ * Task to minify javascript files.
+ *
+ * Requires JSMin which can be found at http://code.google.com/p/jsmin-php/ but
+ * is bundled with Phing so no additional install of JsMin is required.
+ *
+ * @author Frank Kleine <mikey@stubbles.net>
+ * @version $Id: 4a9a75fcd969cfc4e26a7f2c78836389e8be7864 $
+ * @package phing.tasks.ext
+ * @since 2.3.0
+ */
+class JsMinTask extends Task
+{
+ /**
+ * the source files
+ *
+ * @var FileSet
+ */
+ protected $filesets = array();
+ /**
+ * Whether the build should fail, if
+ * errors occured
+ *
+ * @var boolean
+ */
+ protected $failonerror = false;
+
+ /**
+ * Define if the target should use or not a suffix -min
+ *
+ * @var boolean
+ */
+ protected $suffix = '-min';
+
+ /**
+ * directory to put minified javascript files into
+ *
+ * @var string
+ */
+ protected $targetDir;
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num - 1];
+ }
+
+ /**
+ * Whether the build should fail, if an error occured.
+ *
+ * @param boolean $value
+ */
+ public function setFailonerror($value)
+ {
+ $this->failonerror = $value;
+ }
+
+ /**
+ * Define if the task should or not use a suffix (-min is the default)
+ *
+ * @param string $value
+ */
+ public function setSuffix($value)
+ {
+ $this->suffix = $value;
+ }
+
+ /**
+ * sets the directory where minified javascript files should be put inot
+ *
+ * @param string $targetDir
+ */
+ public function setTargetDir($targetDir)
+ {
+ $this->targetDir = $targetDir;
+ }
+
+ /**
+ * The init method: Do init steps.
+ */
+ public function init()
+ {
+ return true;
+ }
+
+ /**
+ * The main entry point method.
+ */
+ public function main()
+ {
+ foreach ($this->filesets as $fs) {
+ try {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ $fullPath = realpath($fs->getDir($this->project));
+ foreach ($files as $file) {
+ $this->log('Minifying file ' . $file);
+ try {
+ $target = $this->targetDir . '/' . str_replace($fullPath, '', str_replace('.js', $this->suffix . '.js', $file));
+ if (file_exists(dirname($target)) === false) {
+ mkdir(dirname($target), 0700, true);
+ }
+
+ file_put_contents($target, JSMin::minify(file_get_contents($fullPath . '/' . $file)));
+ } catch (JSMinException $jsme) {
+ $this->log("Could not minify file $file: " . $jsme->getMessage(), Project::MSG_ERR);
+ }
+ }
+ } 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);
+ }
+ }
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/AbstractLiquibaseTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/AbstractLiquibaseTask.php
new file mode 100755
index 00000000..fbda3ecc
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/AbstractLiquibaseTask.php
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/Task.php';
+require_once 'phing/tasks/system/ExecTask.php';
+
+/**
+ * Abstract Liquibase task. Base class for all Liquibase Phing tasks.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+abstract class AbstractLiquibaseTask extends Task
+{
+ protected $jar;
+ protected $changeLogFile;
+ protected $username;
+ protected $password;
+ protected $url;
+ protected $classpathref;
+
+
+ /**
+ * Sets the absolute path to liquibase jar.
+ *
+ * @param string the absolute path to the liquibase jar.
+ */
+ public function setJar($jar)
+ {
+ $this->jar = $jar;
+ }
+
+
+ /**
+ * Sets the absolute path to the changelog file to use.
+ *
+ * @param string the absolute path to the changelog file
+ */
+ public function setChangeLogFile($changelogFile)
+ {
+ $this->changeLogFile = $changelogFile;
+ }
+
+
+ /**
+ * Sets the username to connect to the database.
+ *
+ * @param string the username
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+
+ /**
+ * Sets the password to connect to the database.
+ *
+ * @param string the password
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+
+
+ /**
+ * Sets the url to connect to the database in jdbc style, e.g.
+ * <code>
+ * jdbc:postgresql://psqlhost/mydatabase
+ * </code>
+ *
+ * @param string jdbc connection string
+ */
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ }
+
+
+ /**
+ * Sets the Java classpathref.
+ *
+ * @param string A reference to the classpath that contains the database
+ * driver, liquibase.jar, and the changelog.xml file
+ */
+ public function setclasspathref($classpathref)
+ {
+ $this->classpathref = $classpathref;
+ }
+
+
+ /**
+ * Ensure that correct parameters were passed in.
+ *
+ * @return void
+ */
+ protected function checkParams()
+ {
+ if((null === $this->jar) or !file_exists($this->jar))
+ {
+ throw new BuildException(
+ sprintf(
+ 'Specify the name of the LiquiBase.jar. "%s" does not exist!',
+ $this->jar
+ )
+ );
+ }
+
+ if((null === $this->changeLogFile) or !file_exists($this->changeLogFile))
+ {
+ throw new BuildException(
+ sprintf(
+ 'Specify the name of the Changelog file. "%s" does not exist!',
+ $this->changeLogFile
+ )
+ );
+ }
+
+ if(null === $this->classpathref)
+ {
+ throw new BuildException('Please provide a classpath!');
+ }
+
+ if(null === $this->username)
+ {
+ throw new BuildException('Please provide a username for database acccess!');
+ }
+
+ if(null === $this->password)
+ {
+ throw new BuildException('Please provide a password for database acccess!');
+ }
+
+ if(null === $this->url)
+ {
+ throw new BuildException('Please provide a url for database acccess!');
+ }
+ }
+
+
+ /**
+ * Executes the given command and returns the output.
+ *
+ * @param string the command to execute
+ * @param string additional parameters
+ * @return string the output of the executed command
+ */
+ protected function execute($lbcommand, $lbparams = '')
+ {
+ $command = sprintf(
+ 'java -jar %s --changeLogFile=%s --url=%s --username=%s --password=%s --classpath=%s %s %s',
+ escapeshellarg($this->jar),
+ escapeshellarg($this->changeLogFile),
+ escapeshellarg($this->url),
+ escapeshellarg($this->username),
+ escapeshellarg($this->password),
+ escapeshellarg($this->classpathref),
+ escapeshellarg($lbcommand),
+ $lbparams
+ );
+
+ passthru($command);
+
+ return;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseChangeLogTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseChangeLogTask.php
new file mode 100755
index 00000000..77fb97d2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseChangeLogTask.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Task to create a changelog file.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseChangeLogTask extends AbstractLiquibaseTask
+{
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+ $this->execute('generateChangeLog');
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDbDocTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDbDocTask.php
new file mode 100755
index 00000000..e79fae92
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDbDocTask.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Task to create a javadoc-like documentation based on current database and
+ * changelog.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseDbDocTask extends AbstractLiquibaseTask
+{
+ protected $outputDir;
+
+
+ /**
+ * Sets the output directory where the documentation gets generated to.
+ *
+ * @param string the output directory
+ */
+ public function setOutputDir($outputDir)
+ {
+ $this->outputDir = $outputDir;
+ }
+
+
+ /**
+ * @see AbstractTask::checkParams()
+ */
+ protected function checkParams()
+ {
+ parent::checkParams();
+
+ if((null === $this->outputDir) or !is_dir($this->outputDir))
+ {
+ if(!mkdir($this->outputDir, 0777, true))
+ {
+ throw new BuildException(
+ sprintf(
+ 'The directory "%s" does not exist and could not be created!',
+ $this->outputDir
+ )
+ );
+ }
+ }
+
+ if(!is_writable($this->outputDir))
+ {
+ throw new BuildException(
+ sprintf(
+ 'The directory "%s" is not writable!',
+ $this->outputDir
+ )
+ );
+ }
+ }
+
+
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+ $this->execute('dbdoc', escapeshellarg($this->outputDir));
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDiffTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDiffTask.php
new file mode 100755
index 00000000..847f1401
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDiffTask.php
@@ -0,0 +1,137 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Task to create the diff between two databases. Will output the changes needed
+ * to convert the reference database to the database.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseDiffTask extends AbstractLiquibaseTask
+{
+ protected $referenceUsername;
+ protected $referencePassword;
+ protected $referenceUrl;
+
+
+ /**
+ * Sets the username to connect to the reference database.
+ *
+ * @param string the username
+ */
+ public function setReferenceUsername($username)
+ {
+ $this->referenceUsername = $username;
+ }
+
+
+ /**
+ * Sets the password to connect to the refernce database.
+ *
+ * @param string the password
+ */
+ public function setReferencePassword($password)
+ {
+ $this->referencePassword = $password;
+ }
+
+
+ /**
+ * Sets the url to connect to the reference database in jdbc style, e.g.
+ * <code>
+ * jdbc:postgresql://psqlhost/myrefdatabase
+ * </code>
+ *
+ * @param string jdbc connection string
+ */
+ public function setReferenceUrl($url)
+ {
+ $this->referenceUrl = $url;
+ }
+
+
+ /**
+ * @see AbstractTask::checkParams()
+ */
+ protected function checkParams()
+ {
+ parent::checkParams();
+
+ if(null === $this->referenceUsername)
+ {
+ throw new BuildException('Please provide a username for the reference database acccess!');
+ }
+
+ if(null === $this->referencePassword)
+ {
+ throw new BuildException('Please provide a password for the reference database acccess!');
+ }
+
+ if(null === $this->referenceUrl)
+ {
+ throw new BuildException('Please provide a url for the reference database acccess!');
+ }
+ }
+
+
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+
+ $refparams = sprintf(
+ '--referenceUsername=%s --referencePassword=%s --referenceUrl=%s',
+ escapeshellarg($this->referenceUsername),
+ escapeshellarg($this->referencePassword),
+ escapeshellarg($this->referenceUrl)
+ );
+
+ // save main changelog file
+ $changelogFile = $this->changeLogFile;
+
+ // set the name of the new generated changelog file
+ $this->setChangeLogFile(dirname($changelogFile).'/diffs/'.date('YmdHis').'.xml');
+ if(!is_dir(dirname($changelogFile).'/diffs/'))
+ {
+ mkdir(dirname($changelogFile).'/diffs/', 0777, true);
+ }
+ $this->execute('diffChangeLog', $refparams);
+
+ $xmlFile = new DOMDocument();
+ $xmlFile->load($changelogFile);
+
+ // create the new node
+ $rootNode = $xmlFile->getElementsByTagName('databaseChangeLog')->item(0);
+ $includeNode = $rootNode->appendChild($xmlFile->createElement('include'));
+
+ // set the attributes for the new node
+ $includeNode->setAttribute('file', str_replace(dirname($changelogFile).'/', '', $this->changeLogFile));
+ $includeNode->setAttribute('relativeToChangelogFile', 'true');
+ file_put_contents($changelogFile, $xmlFile->saveXML());
+
+ $this->setChangeLogFile($changelogFile);
+ $this->execute('markNextChangeSetRan');
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseRollbackTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseRollbackTask.php
new file mode 100755
index 00000000..ec5584e6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseRollbackTask.php
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Rollbacks the database changes.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseRollbackTask extends AbstractLiquibaseTask
+{
+ protected $rollbackTag;
+
+
+ /**
+ * Sets the name of the tag to roll back to.
+ *
+ * @param string the name to roll back to
+ */
+ public function setRollbackTag($rollbackTag)
+ {
+ $this->rollbackTag = $rollbackTag;
+ }
+
+
+ /**
+ * @see AbstractTask::checkParams()
+ */
+ protected function checkParams()
+ {
+ parent::checkParams();
+
+ if(null === $this->rollbackTag)
+ {
+ throw new BuildException(
+ sprintf(
+ 'Please specify the tag to rollback to!',
+ $this->rollbackTag
+ )
+ );
+ }
+ }
+
+
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+ $this->execute('rollback', escapeshellarg($this->rollbackTag));
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseTagTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseTagTask.php
new file mode 100755
index 00000000..07b0e72e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseTagTask.php
@@ -0,0 +1,75 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Task to tag the current database state. In case you tag the database multiple
+ * times without applying a new changelog before, the tags will overwrite each
+ * other!
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseTagTask extends AbstractLiquibaseTask
+{
+ protected $tag;
+
+
+ /**
+ * Sets the name of tag which is used to mark the database state for
+ * possible future rollback.
+ *
+ * @param string the name to tag the database with
+ */
+ public function setTag($tag)
+ {
+ $this->tag = $tag;
+ }
+
+
+ /**
+ * @see AbstractTask::checkParams()
+ */
+ protected function checkParams()
+ {
+ parent::checkParams();
+
+ if(null === $this->tag)
+ {
+ throw new BuildException(
+ sprintf(
+ 'Please specify the tag!',
+ $this->tag
+ )
+ );
+ }
+ }
+
+
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+ $this->execute('tag', escapeshellarg($this->tag));
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseUpdateTask.php b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseUpdateTask.php
new file mode 100755
index 00000000..35162e4d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseUpdateTask.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Copyright (c) 2007-2011 bitExpert AG
+ *
+ * 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.
+ */
+
+require_once 'phing/tasks/ext/liquibase/AbstractLiquibaseTask.php';
+
+/**
+ * Task to update the database to latest version of the changelog file.
+ *
+ * @author Stephan Hochdoerfer <S.Hochdoerfer@bitExpert.de>
+ * @version $Id$
+ * @since 2.4.10
+ * @package phing.tasks.ext.liquibase
+ */
+class LiquibaseUpdateTask extends AbstractLiquibaseTask
+{
+ /**
+ * @see Task::main()
+ */
+ public function main()
+ {
+ $this->checkParams();
+ $this->execute('update');
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php
new file mode 100644
index 00000000..53286f46
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * $Id: f3a492fa25b203d3263e3463c1ab522c61bd0a9c $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * Analyzer element for the PhpDependTask
+ *
+ * @package phing.tasks.ext.pdepend
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: f3a492fa25b203d3263e3463c1ab522c61bd0a9c $
+ * @since 2.4.1
+ */
+class PhpDependAnalyzerElement
+{
+ /**
+ * The type of the analyzer
+ *
+ * @var string
+ */
+ protected $_type = '';
+
+ /**
+ * The value(s) for the analyzer option
+ *
+ * @var array
+ */
+ protected $_value = array();
+
+ /**
+ * Sets the analyzer type
+ *
+ * @param string $type Type of the analyzer
+ *
+ * @return void
+ */
+ public function setType($type)
+ {
+ $this->_type = $type;
+
+ switch ($this->_type) {
+ case 'coderank-mode':
+ break;
+
+ default:
+ throw new BuildException(
+ "Analyzer '" . $this->_type . "' not implemented"
+ );
+ }
+ }
+
+ /**
+ * Get the analyzer type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Sets the value for the analyzer
+ *
+ * @param string $value Value for the analyzer
+ *
+ * @return void
+ */
+ public function setValue($value)
+ {
+ $this->_value = array();
+
+ $token = ' ,;';
+ $values = strtok($value, $token);
+
+ while ($values !== false) {
+ $this->_value[] = $values;
+ $values = strtok($token);
+ }
+ }
+
+ /**
+ * Get the analyzer value
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependLoggerElement.php b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependLoggerElement.php
new file mode 100644
index 00000000..619f7377
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependLoggerElement.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * $Id: 6aa728f12c6a9b89fb93cfd39908918937a6d5f9 $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * Logger element for the PhpDependTask.
+ *
+ * @package phing.tasks.ext.pdepend
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 6aa728f12c6a9b89fb93cfd39908918937a6d5f9 $
+ * @since 2.4.1
+ */
+class PhpDependLoggerElement
+{
+ /**
+ * The type of the logger.
+ *
+ * @var string
+ */
+ protected $_type = '';
+
+ /**
+ * Output file for logger.
+ *
+ * @var PhingFile
+ */
+ protected $_outfile = null;
+
+ /**
+ * Sets the logger type.
+ *
+ * @param string $type Type of the logger
+ *
+ * @return void
+ */
+ public function setType($type)
+ {
+ $this->_type = $type;
+
+ switch ($this->_type) {
+ case 'jdepend-chart':
+ case 'jdepend-xml':
+ case 'overview-pyramid':
+ case 'phpunit-xml':
+ case 'summary-xml':
+ break;
+
+ default:
+ throw new BuildException(
+ "Logger '" . $this->_type . "' not implemented"
+ );
+ }
+ }
+
+ /**
+ * Get the logger type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Sets the output file for the logger results.
+ *
+ * @param PhingFile $outfile The output file
+ *
+ * @return void
+ */
+ public function setOutfile(PhingFile $outfile)
+ {
+ $this->_outfile = $outfile;
+ }
+
+ /**
+ * Get the output file.
+ *
+ * @return PhingFile
+ */
+ public function getOutfile()
+ {
+ return $this->_outfile;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependTask.php b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependTask.php
new file mode 100644
index 00000000..c42575b7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependTask.php
@@ -0,0 +1,506 @@
+<?php
+/**
+ * $Id: 572bbfe2e542b864211a85de9990f5cbfe31a4cd $
+ *
+ * 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';
+
+/**
+ * Runs the PHP_Depend software analyzer and metric tool.
+ * Performs static code analysis on a given source base.
+ *
+ * @package phing.tasks.ext.pdepend
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 572bbfe2e542b864211a85de9990f5cbfe31a4cd $
+ * @since 2.4.1
+ */
+class PhpDependTask extends Task
+{
+ /**
+ * A php source code filename or directory
+ *
+ * @var PhingFile
+ */
+ protected $_file = null;
+
+ /**
+ * All fileset objects assigned to this task
+ *
+ * @var array<FileSet>
+ */
+ protected $_filesets = array();
+
+ /**
+ * List of allowed file extensions. Default file extensions are <b>php</b>
+ * and <p>php5</b>.
+ *
+ * @var array<string>
+ */
+ protected $_allowedFileExtensions = array('php', 'php5');
+
+ /**
+ * List of exclude directories. Default exclude dirs are <b>.git</b>,
+ * <b>.svn</b> and <b>CVS</b>.
+ *
+ * @var array<string>
+ */
+ protected $_excludeDirectories = array('.git', '.svn', 'CVS');
+
+ /**
+ * List of exclude packages
+ *
+ * @var array<string>
+ */
+ protected $_excludePackages = array();
+
+ /**
+ * Should the parse ignore doc comment annotations?
+ *
+ * @var boolean
+ */
+ protected $_withoutAnnotations = false;
+
+ /**
+ * Should PHP_Depend treat <b>+global</b> as a regular project package?
+ *
+ * @var boolean
+ */
+ protected $_supportBadDocumentation = false;
+
+ /**
+ * Flag for enable/disable debugging
+ *
+ * @var boolean
+ */
+ protected $_debug = false;
+
+ /**
+ * PHP_Depend configuration file
+ *
+ * @var PhingFile
+ */
+ protected $_configFile = null;
+
+ /**
+ * Logger elements
+ *
+ * @var array<PhpDependLoggerElement>
+ */
+ protected $_loggers = array();
+
+ /**
+ * Analyzer elements
+ *
+ * @var array<PhpDependAnalyzerElement>
+ */
+ protected $_analyzers = array();
+
+ /**
+ * Holds the PHP_Depend runner instance
+ *
+ * @var PHP_Depend_TextUI_Runner
+ */
+ protected $_runner = null;
+
+ /**
+ * Flag that determines whether to halt on error
+ *
+ * @var boolean
+ */
+ protected $_haltonerror = false;
+
+ /**
+ * Load the necessary environment for running PHP_Depend
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function init()
+ {
+ /**
+ * Determine PHP_Depend installation
+ */
+ @include_once 'PHP/Depend/TextUI/Runner.php';
+
+ if (! class_exists('PHP_Depend_TextUI_Runner')) {
+ throw new BuildException(
+ 'PhpDependTask depends on PHP_Depend being installed '
+ . 'and on include_path',
+ $this->getLocation()
+ );
+ }
+
+ /**
+ * Other dependencies that should only be loaded
+ * when class is actually used
+ */
+ require_once 'phing/tasks/ext/pdepend/PhpDependLoggerElement.php';
+ require_once 'phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php';
+ require_once 'PHP/Depend/Autoload.php';
+ }
+
+ /**
+ * Set the input source file or directory
+ *
+ * @param PhingFile $file The input source file or directory
+ *
+ * @return void
+ */
+ public function setFile(PhingFile $file)
+ {
+ $this->_file = $file;
+ }
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute)
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->_filesets, new FileSet());
+ return $this->_filesets[$num-1];
+ }
+
+ /**
+ * Sets a list of filename extensions for valid php source code files
+ *
+ * @param string $fileExtensions List of valid file extensions
+ *
+ * @return void
+ */
+ public function setAllowedFileExtensions($fileExtensions)
+ {
+ $this->_allowedFileExtensions = array();
+
+ $token = ' ,;';
+ $ext = strtok($fileExtensions, $token);
+
+ while ($ext !== false) {
+ $this->_allowedFileExtensions[] = $ext;
+ $ext = strtok($token);
+ }
+ }
+
+ /**
+ * Sets a list of exclude directories
+ *
+ * @param string $excludeDirectories List of exclude directories
+ *
+ * @return void
+ */
+ public function setExcludeDirectories($excludeDirectories)
+ {
+ $this->_excludeDirectories = array();
+
+ $token = ' ,;';
+ $pattern = strtok($excludeDirectories, $token);
+
+ while ($pattern !== false) {
+ $this->_excludeDirectories[] = $pattern;
+ $pattern = strtok($token);
+ }
+ }
+
+ /**
+ * Sets a list of exclude packages
+ *
+ * @param string $excludePackages Exclude packages
+ *
+ * @return void
+ */
+ public function setExcludePackages($excludePackages)
+ {
+ $this->_excludePackages = array();
+
+ $token = ' ,;';
+ $pattern = strtok($excludePackages, $token);
+
+ while ($pattern !== false) {
+ $this->_excludePackages[] = $pattern;
+ $pattern = strtok($token);
+ }
+ }
+
+ /**
+ * Should the parser ignore doc comment annotations?
+ *
+ * @param boolean $withoutAnnotations
+ *
+ * @return void
+ */
+ public function setWithoutAnnotations($withoutAnnotations)
+ {
+ $this->_withoutAnnotations = StringHelper::booleanValue(
+ $withoutAnnotations
+ );
+ }
+
+ /**
+ * Should PHP_Depend support projects with a bad documentation. If this
+ * option is set to <b>true</b>, PHP_Depend will treat the default package
+ * <b>+global</b> as a regular project package.
+ *
+ * @param boolean $supportBadDocumentation
+ *
+ * @return void
+ */
+ public function setSupportBadDocumentation($supportBadDocumentation)
+ {
+ $this->_supportBadDocumentation = StringHelper::booleanValue(
+ $supportBadDocumentation
+ );
+ }
+
+ /**
+ * Set debugging On/Off
+ *
+ * @param boolean $debug
+ *
+ * @return void
+ */
+ public function setDebug($debug)
+ {
+ $this->_debug = StringHelper::booleanValue($debug);
+ }
+
+ /**
+ * Set halt on error
+ *
+ * @param boolean $haltonerror
+ *
+ * @return void
+ */
+ public function setHaltonerror($haltonerror)
+ {
+ $this->_haltonerror = StringHelper::booleanValue($haltonerror);
+ }
+
+ /**
+ * Set the configuration file
+ *
+ * @param PhingFile $configFile The configuration file
+ *
+ * @return void
+ */
+ public function setConfigFile(PhingFile $configFile)
+ {
+ $this->_configFile = $configFile;
+ }
+
+ /**
+ * Create object for nested logger element
+ *
+ * @return PhpDependLoggerElement
+ */
+ public function createLogger()
+ {
+ $num = array_push($this->_loggers, new PhpDependLoggerElement());
+ return $this->_loggers[$num-1];
+ }
+
+ /**
+ * Create object for nested analyzer element
+ *
+ * @return PhpDependAnalyzerElement
+ */
+ public function createAnalyzer()
+ {
+ $num = array_push($this->_analyzers, new PhpDependAnalyzerElement());
+ return $this->_analyzers[$num-1];
+ }
+
+ /**
+ * Executes PHP_Depend_TextUI_Runner against PhingFile or a FileSet
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $autoload = new PHP_Depend_Autoload();
+ $autoload->register();
+
+ if (!isset($this->_file) and count($this->_filesets) == 0) {
+ throw new BuildException(
+ "Missing either a nested fileset or attribute 'file' set"
+ );
+ }
+
+ if (count($this->_loggers) == 0) {
+ throw new BuildException("Missing nested 'logger' element");
+ }
+
+ $this->validateLoggers();
+ $this->validateAnalyzers();
+
+ $filesToParse = array();
+
+ if ($this->_file instanceof PhingFile) {
+ $filesToParse[] = $this->_file->__toString();
+ } else {
+ // append any files in filesets
+ foreach ($this->_filesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)
+ ->getIncludedFiles();
+
+ foreach ($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $filesToParse[] = $f->getAbsolutePath();
+ }
+ }
+ }
+
+ $this->_runner = new PHP_Depend_TextUI_Runner();
+ $this->_runner->addProcessListener(new PHP_Depend_TextUI_ResultPrinter());
+
+ $configurationFactory = new PHP_Depend_Util_Configuration_Factory();
+ $configuration = $configurationFactory->createDefault();
+ $this->_runner->setConfiguration($configuration);
+
+ $this->_runner->setSourceArguments($filesToParse);
+
+ foreach ($this->_loggers as $logger) {
+ // Register logger
+ $this->_runner->addLogger(
+ $logger->getType(),
+ $logger->getOutfile()->__toString()
+ );
+ }
+
+ foreach ($this->_analyzers as $analyzer) {
+ // Register additional analyzer
+ $this->_runner->addOption(
+ $analyzer->getType(),
+ $analyzer->getValue()
+ );
+ }
+
+ // Disable annotation parsing
+ if ($this->_withoutAnnotations) {
+ $this->_runner->setWithoutAnnotations();
+ }
+
+ // Enable bad documentation support
+ if ($this->_supportBadDocumentation) {
+ $this->_runner->setSupportBadDocumentation();
+ }
+
+ // Check for suffix
+ if (count($this->_allowedFileExtensions) > 0) {
+ $this->_runner->setFileExtensions($this->_allowedFileExtensions);
+ }
+
+ // Check for ignore directories
+ if (count($this->_excludeDirectories) > 0) {
+ $this->_runner->setExcludeDirectories($this->_excludeDirectories);
+ }
+
+ // Check for exclude packages
+ if (count($this->_excludePackages) > 0) {
+ $this->_runner->setExcludePackages($this->_excludePackages);
+ }
+
+ // Check for configuration option
+ if ($this->_configFile instanceof PhingFile) {
+ if (file_exists($this->_configFile->__toString()) === false) {
+ throw new BuildException(
+ 'The configuration file "'
+ . $this->_configFile->__toString() . '" doesn\'t exist.'
+ );
+ }
+
+ // Load configuration file
+ $config = new PHP_Depend_Util_Configuration(
+ $this->_configFile->__toString(),
+ null,
+ true
+ );
+
+ // Store in config registry
+ PHP_Depend_Util_ConfigurationInstance::set($config);
+ }
+
+ if ($this->_debug) {
+ require_once 'PHP/Depend/Util/Log.php';
+ // Enable debug logging
+ PHP_Depend_Util_Log::setSeverity(PHP_Depend_Util_Log::DEBUG);
+ }
+
+ $this->_runner->run();
+
+ if ($this->_runner->hasParseErrors() === true) {
+ $this->log('Following errors occurred:');
+
+ foreach ($this->_runner->getParseErrors() as $error) {
+ $this->log($error);
+ }
+
+ if ($this->_haltonerror === true) {
+ throw new BuildException('Errors occurred during parse process');
+ }
+ }
+ }
+
+ /**
+ * Validates the available loggers
+ *
+ * @return void
+ * @throws BuildException
+ */
+ protected function validateLoggers()
+ {
+ foreach ($this->_loggers as $logger) {
+ if ($logger->getType() === '') {
+ throw new BuildException(
+ "Logger missing required 'type' attribute"
+ );
+ }
+
+ if ($logger->getOutfile() === null) {
+ throw new BuildException(
+ "Logger requires 'outfile' attribute"
+ );
+ }
+ }
+ }
+
+ /**
+ * Validates the available analyzers
+ *
+ * @return void
+ * @throws BuildException
+ */
+ protected function validateAnalyzers()
+ {
+ foreach ($this->_analyzers as $analyzer) {
+ if ($analyzer->getType() === '') {
+ throw new BuildException(
+ "Analyzer missing required 'type' attribute"
+ );
+ }
+
+ if (count($analyzer->getValue()) === 0) {
+ throw new BuildException(
+ "Analyzer missing required 'value' attribute"
+ );
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php
new file mode 100755
index 00000000..41f296f7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * 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>.
+ *
+ * @version SVN: $Id: dacfd46938db28930888f57a6924be642ec1b3d7 $
+ * @package phing.tasks.ext.pdo
+ */
+
+require_once 'phing/tasks/ext/pdo/PDOQuerySplitter.php';
+
+/**
+ * Splits SQL source into queries using simple regular expressions
+ *
+ * Extracted from PDOSQLExecTask::runStatements()
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @author Alexey Borzov <avb@php.net>
+ * @package phing.tasks.ext.pdo
+ * @version $Id$
+ */
+class DefaultPDOQuerySplitter extends PDOQuerySplitter
+{
+ /**
+ * Delimiter type, one of PDOSQLExecTask::DELIM_ROW or PDOSQLExecTask::DELIM_NORMAL
+ * @var string
+ */
+ private $delimiterType;
+
+ /**
+ * Leftover SQL from previous line
+ * @var string
+ */
+ private $sqlBacklog = '';
+
+ /**
+ * Constructor, sets the parent task, reader with SQL source and delimiter type
+ *
+ * @param PDOSQLExecTask $parent
+ * @param Reader $reader
+ * @param string $delimiterType
+ */
+ public function __construct(PDOSQLExecTask $parent, Reader $reader, $delimiterType = PDOSQLExecTask::DELIM_NORMAL)
+ {
+ parent::__construct($parent, $reader);
+ $this->delimiterType = $delimiterType;
+ }
+
+ /**
+ * Returns next query from SQL source, null if no more queries left
+ *
+ * In case of "row" delimiter type this searches for strings containing only
+ * delimiters. In case of "normal" delimiter type, this uses simple regular
+ * expression logic to search for delimiters.
+ *
+ * @return string|null
+ */
+ public function nextQuery()
+ {
+ $sql = "";
+ $hasQuery = false;
+
+ while (($line = $this->sqlReader->readLine()) !== null) {
+ $delimiter = $this->parent->getDelimiter();
+ $project = $this->parent->getOwningTarget()->getProject();
+ $line = ProjectConfigurator::replaceProperties(
+ $project, trim($line), $project->getProperties()
+ );
+
+ if (($line != $delimiter) && (
+ StringHelper::startsWith("//", $line) ||
+ StringHelper::startsWith("--", $line) ||
+ StringHelper::startsWith("#", $line))) {
+ continue;
+ }
+
+ if (strlen($line) > 4
+ && strtoupper(substr($line,0, 4)) == "REM ") {
+ continue;
+ }
+
+ // MySQL supports defining new delimiters
+ if (preg_match('/DELIMITER [\'"]?([^\'" $]+)[\'"]?/i', $line, $matches)) {
+ $this->parent->setDelimiter($matches[1]);
+ continue;
+ }
+
+ if ($this->sqlBacklog !== "") {
+ $sql = $this->sqlBacklog;
+ $this->sqlBacklog = "";
+ }
+
+ $sql .= " " . $line . "\n";
+
+ // 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";
+ }
+
+ // DELIM_ROW doesn't need this (as far as i can tell)
+ if ($this->delimiterType == PDOSQLExecTask::DELIM_NORMAL) {
+
+ $reg = "#((?:\"(?:\\\\.|[^\"])*\"?)+|'(?:\\\\.|[^'])*'?|" . preg_quote($delimiter) . ")#";
+
+ $sqlParts = preg_split($reg, $sql, 0, PREG_SPLIT_DELIM_CAPTURE);
+ $this->sqlBacklog = "";
+ foreach ($sqlParts as $sqlPart) {
+ // we always want to append, even if it's a delim (which will be stripped off later)
+ $this->sqlBacklog .= $sqlPart;
+
+ // we found a single (not enclosed by ' or ") delimiter, so we can use all stuff before the delim as the actual query
+ if ($sqlPart === $delimiter) {
+ $sql = $this->sqlBacklog;
+ $this->sqlBacklog = "";
+ $hasQuery = true;
+ }
+ }
+ }
+
+ if ($hasQuery || ($this->delimiterType == PDOSQLExecTask::DELIM_ROW && $line == $delimiter)) {
+ // this assumes there is always a delimter on the end of the SQL statement.
+ $sql = StringHelper::substring($sql, 0, strlen($sql) - strlen($delimiter)
+ - ($this->delimiterType == PDOSQLExecTask::DELIM_ROW ? 2 : 1));
+ return $sql;
+ }
+ }
+
+ // Catch any statements not followed by ;
+ if ($sql !== "") {
+ return $sql;
+ }
+
+ return null;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOQuerySplitter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOQuerySplitter.php
new file mode 100755
index 00000000..60a9d436
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOQuerySplitter.php
@@ -0,0 +1,63 @@
+<?php
+
+/**
+ * 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>.
+ *
+ * @version $Id: e84ada3cdb7a04da60158c7a352fbb06f17f2ca7 $
+ * @package phing.tasks.ext.pdo
+ */
+
+/**
+ * Base class for classes that split SQL source into separate queries
+ *
+ * @author Alexey Borzov <avb@php.net>
+ * @package phing.tasks.ext.pdo
+ * @version $Id$
+ */
+abstract class PDOQuerySplitter
+{
+ /**
+ * Task that uses the splitter
+ * @var PDOSQLExecTask
+ */
+ protected $parent;
+
+ /**
+ * Reader with SQL source
+ * @var BufferedReader
+ */
+ protected $sqlReader;
+
+ /**
+ * Constructor, sets the parent task and reader with SQL source
+ *
+ * @param PDOSQLExecTask $parent
+ * @param Reader $reader
+ */
+ public function __construct(PDOSQLExecTask $parent, Reader $reader)
+ {
+ $this->parent = $parent;
+ $this->sqlReader = new BufferedReader($reader);
+ }
+
+ /**
+ * Returns next query from SQL source, null if no more queries left
+ *
+ * @return string|null
+ */
+ abstract public function nextQuery();
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOResultFormatter.php
new file mode 100644
index 00000000..82a90ca4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOResultFormatter.php
@@ -0,0 +1,84 @@
+<?php
+/**
+ * $Id: a3237522d22494bbfaf0521ebb8f091d448f3614 $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * Abstract
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @package phing.tasks.ext.pdo
+ * @since 2.3.0
+ */
+abstract class PDOResultFormatter
+{
+ /**
+ * Output writer.
+ *
+ * @var Writer
+ */
+ protected $out;
+
+ /**
+ * Sets the output writer.
+ *
+ * @param Writer $out
+ */
+ public function setOutput(Writer $out) {
+ $this->out = $out;
+ }
+
+ /**
+ * Gets the output writer.
+ *
+ * @return Writer
+ */
+ public function getOutput() {
+ return $this->out;
+ }
+
+ /**
+ * Gets the preferred output filename for this formatter.
+ * @return string
+ */
+ abstract public function getPreferredOutfile();
+
+ /**
+ * Perform any initialization.
+ */
+ public function initialize() {
+
+ }
+
+ /**
+ * Processes a specific row from PDO result set.
+ *
+ * @param array $row Row of PDO result set.
+ */
+ abstract public function processRow($row);
+
+ /**
+ * Perform any final tasks and Close the writer.
+ */
+ public function close() {
+ $this->out->close();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php
new file mode 100644
index 00000000..bc657604
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php
@@ -0,0 +1,313 @@
+<?php
+/**
+ * $Id: a3ca52c2b277a8cbc0d2802b75f2bea18701b636 $
+ *
+ * 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/PhingFile.php';
+require_once 'phing/tasks/ext/pdo/PlainPDOResultFormatter.php';
+require_once 'phing/tasks/ext/pdo/XMLPDOResultFormatter.php';
+require_once 'phing/util/LogWriter.php';
+
+/**
+ * A class to represent the nested <formatter> element for PDO SQL results.
+ *
+ * This class is inspired by the similarly-named class in the PHPUnit tasks.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @package phing.tasks.ext.pdo
+ * @since 2.3.0
+ */
+class PDOSQLExecFormatterElement
+{
+ /**
+ * @var PDOResultFormatter
+ */
+ private $formatter;
+
+ /**
+ * The type of the formatter (used for built-in formatter classes).
+ * @var string
+ */
+ private $type = "";
+
+ /**
+ * Whether to use file (or write output to phing log).
+ * @var boolean
+ */
+ private $useFile = true;
+
+ /**
+ * Output file for formatter.
+ * @var PhingFile
+ */
+ private $outfile;
+
+ /**
+ * Print header columns.
+ * @var boolean
+ */
+ private $showheaders = true;
+
+ /**
+ * Whether to format XML output.
+ * @var boolean
+ */
+ private $formatoutput = true;
+
+ /**
+ * Encoding for XML output.
+ * @var string
+ */
+ private $encoding;
+
+ /**
+ * Column delimiter.
+ * Defaults to ','
+ * @var string
+ */
+ private $coldelimiter = ",";
+
+ /**
+ * Row delimiter.
+ * Defaults to PHP_EOL.
+ * @var string
+ */
+ private $rowdelimiter = PHP_EOL;
+
+ /**
+ * Append to an existing file or overwrite it?
+ * @var boolean
+ */
+ private $append = false;
+
+ /**
+ * Parameters for a custom formatter.
+ * @var array Parameter[]
+ */
+ private $formatterParams = array();
+
+ /**
+ * @var PDOSQLExecTask
+ */
+ private $parentTask;
+
+ /**
+ * Construct a new PDOSQLExecFormatterElement with parent task.
+ * @param PDOSQLExecTask $parentTask
+ */
+ public function __construct(PDOSQLExecTask $parentTask)
+ {
+ $this->parentTask = $parentTask;
+ }
+
+ /**
+ * Supports nested <param> element (for custom formatter classes).
+ * @return Parameter
+ */
+ public function createParam() {
+ $num = array_push($this->parameters, new Parameter());
+ return $this->parameters[$num-1];
+ }
+
+ /**
+ * Gets a configured output writer.
+ * @return Writer
+ */
+ private function getOutputWriter()
+ {
+ if ($this->useFile) {
+ $of = $this->getOutfile();
+ if (!$of) {
+ $of = new PhingFile($this->formatter->getPreferredOutfile());
+ }
+ return new FileWriter($of, $this->append);
+ } else {
+ return $this->getDefaultOutput();
+ }
+ }
+
+ /**
+ * Configures wrapped formatter class with any attributes on this element.
+ */
+ public function prepare() {
+
+ if (!$this->formatter) {
+ throw new BuildException("No formatter specified (use type or classname attribute)", $this->getLocation());
+ }
+
+ $out = $this->getOutputWriter();
+
+ $this->parentTask->log("Setting output writer to: " . get_class($out), Project::MSG_VERBOSE);
+ $this->formatter->setOutput($out);
+
+ if ($this->formatter instanceof PlainPDOResultFormatter) {
+ // set any options that apply to the plain formatter
+ $this->formatter->setShowheaders($this->showheaders);
+ $this->formatter->setRowdelim($this->rowdelimiter);
+ $this->formatter->setColdelim($this->coldelimiter);
+ } elseif ($this->formatter instanceof XMLPDOResultFormatter) {
+ // set any options that apply to the xml formatter
+ $this->formatter->setEncoding($this->encoding);
+ $this->formatter->setFormatOutput($this->formatoutput);
+ }
+
+ foreach($this->formatterParams as $param) {
+ $param = new Parameter();
+ $method = 'set' . $param->getName();
+ if (!method_exists($this->formatter, $param->getName())) {
+ throw new BuildException("Formatter " . get_class($this->formatter) . " does not have a $method method.", $this->getLocation());
+ }
+ call_user_func(array($this->formatter, $method), $param->getValue());
+ }
+ }
+
+ /**
+ * Sets the formatter type.
+ * @param string $type
+ */
+ function setType($type) {
+ $this->type = $type;
+ if ($this->type == "xml") {
+ $this->formatter = new XMLPDOResultFormatter();
+ } elseif ($this->type == "plain") {
+ $this->formatter = new PlainPDOResultFormatter();
+ } else {
+ throw new BuildException("Formatter '" . $this->type . "' not implemented");
+ }
+ }
+
+ /**
+ * Set classname for a custom formatter (must extend PDOResultFormatter).
+ * @param string $className
+ */
+ function setClassName($className) {
+ $classNameNoDot = Phing::import($className);
+ $this->formatter = new $classNameNoDot();
+ }
+
+ /**
+ * Set whether to write formatter results to file.
+ * @param boolean $useFile
+ */
+ function setUseFile($useFile) {
+ $this->useFile = (boolean) $useFile;
+ }
+
+ /**
+ * Return whether to write formatter results to file.
+ * @return boolean
+ */
+ function getUseFile() {
+ return $this->useFile;
+ }
+
+ /**
+ * Sets the output file for the formatter results.
+ * @param PhingFile $outFile
+ */
+ function setOutfile(PhingFile $outfile) {
+ $this->outfile = $outfile;
+ }
+
+ /**
+ * Get the output file.
+ * @return PhingFile
+ */
+ function getOutfile() {
+ return $this->outfile;
+ /*
+ } else {
+ return new PhingFile($this->formatter->getPreferredOutfile());
+ }*/
+ }
+
+ /**
+ * whether output should be appended to or overwrite
+ * an existing file. Defaults to false.
+ * @param boolean $append
+ */
+ public function setAppend($append) {
+ $this->append = (boolean) $append;
+ }
+
+ /**
+ * Whether output should be appended to file.
+ * @return boolean
+ */
+ public function getAppend() {
+ return $this->append;
+ }
+
+ /**
+ * Print headers for result sets from the
+ * statements; optional, default true.
+ * @param boolean $showheaders
+ */
+ public function setShowheaders($showheaders) {
+ $this->showheaders = (boolean) $showheaders;
+ }
+
+ /**
+ * Sets the column delimiter.
+ * @param string $v
+ */
+ public function setColdelim($v) {
+ $this->coldelimiter = $v;
+ }
+
+ /**
+ * Sets the row delimiter.
+ * @param string $v
+ */
+ public function setRowdelim($v) {
+ $this->rowdelimiter = $v;
+ }
+
+ /**
+ * Set the DOM document encoding.
+ * @param string $v
+ */
+ public function setEncoding($v) {
+ $this->encoding = $v;
+ }
+
+ /**
+ * @param boolean $v
+ */
+ public function setFormatOutput($v) {
+ $this->formatOutput = (boolean) $v;
+ }
+
+ /**
+ * Gets a default output writer for this task.
+ * @return Writer
+ */
+ private function getDefaultOutput()
+ {
+ return new LogWriter($this->parentTask);
+ }
+
+ /**
+ * Gets the formatter that has been configured based on this element.
+ * @return PDOResultFormatter
+ */
+ function getFormatter() {
+ return $this->formatter;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php
new file mode 100755
index 00000000..3837d7ff
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php
@@ -0,0 +1,606 @@
+<?php
+/*
+ * $Id: 8b5a8e4f80b46f8a797b058dbb9a240a1185c12b $
+ *
+ * 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/pdo/PDOTask.php';
+include_once 'phing/system/io/StringReader.php';
+include_once 'phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php';
+
+/**
+ * Executes a series of SQL statements on a database using PDO.
+ *
+ * <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.pdo
+ * @version $Id: 8b5a8e4f80b46f8a797b058dbb9a240a1185c12b $
+ */
+class PDOSQLExecTask extends PDOTask {
+
+ /**
+ * Count of how many statements were executed successfully.
+ * @var int
+ */
+ private $goodSql = 0;
+
+ /**
+ * Count of total number of SQL statements.
+ * @var int
+ */
+ private $totalSql = 0;
+
+ const DELIM_ROW = "row";
+ const DELIM_NORMAL = "normal";
+
+ /**
+ * Database connection
+ * @var PDO
+ */
+ private $conn = null;
+
+ /**
+ * Files to load
+ * @var array FileSet[]
+ */
+ private $filesets = array();
+
+ /**
+ * Files to load
+ * @var array FileList[]
+ */
+ private $filelists = array();
+
+ /**
+ * Formatter elements.
+ * @var array PDOSQLExecFormatterElement[]
+ */
+ private $formatters = array();
+
+ /**
+ * SQL statement
+ * @var PDOStatement
+ */
+ private $statement;
+
+ /**
+ * SQL input file
+ * @var PhingFile
+ */
+ private $srcFile;
+
+ /**
+ * SQL input command
+ * @var string
+ */
+ private $sqlCommand = "";
+
+ /**
+ * SQL transactions to perform
+ */
+ private $transactions = array();
+
+ /**
+ * SQL Statement delimiter (for parsing files)
+ * @var string
+ */
+ 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
+
+ /**
+ * Action to perform if an error is found
+ **/
+ private $onError = "abort";
+
+ /**
+ * Encoding to use when reading SQL statements from a file
+ */
+ private $encoding = null;
+
+ /**
+ * Fetch mode for PDO select queries.
+ * @var int
+ */
+ private $fetchMode;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Adds a set of files (nested filelist attribute).
+ */
+ public function addFilelist(FileList $list) {
+ $this->filelists[] = $list;
+ }
+
+ /**
+ * Creates a new PDOSQLExecFormatterElement for <formatter> element.
+ * @return PDOSQLExecFormatterElement
+ */
+ public function createFormatter()
+ {
+ $fe = new PDOSQLExecFormatterElement($this);
+ $this->formatters[] = $fe;
+ return $fe;
+ }
+
+ /**
+ * Add a SQL transaction to execute
+ */
+ public function createTransaction() {
+ $t = new PDOSQLExecTransaction($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;
+ }
+
+ /**
+ * Get the statement delimiter.
+ *
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->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;
+ }
+
+ /**
+ * Action to perform when statement fails: continue, stop, or abort
+ * optional; default &quot;abort&quot;
+ */
+ public function setOnerror($action) {
+ $this->onError = $action;
+ }
+
+ /**
+ * Sets the fetch mode to use for the PDO resultset.
+ * @param mixed $mode The PDO fetchmode integer or constant name.
+ */
+ public function setFetchmode($mode) {
+ if (is_numeric($mode)) {
+ $this->fetchMode = (int) $mode;
+ } else {
+ if (defined($mode)) {
+ $this->fetchMode = constant($mode);
+ } else {
+ throw new BuildException("Invalid PDO fetch mode specified: " . $mode, $this->getLocation());
+ }
+ }
+ }
+
+ /**
+ * Gets a default output writer for this task.
+ * @return Writer
+ */
+ private function getDefaultOutput()
+ {
+ return new LogWriter($this);
+ }
+
+ /**
+ * Load the sql file and then execute it
+ * @throws BuildException
+ */
+ public function main() {
+
+ // Set a default fetchmode if none was specified
+ // (We're doing that here to prevent errors loading the class is PDO is not available.)
+ if ($this->fetchMode === null) {
+ $this->fetchMode = PDO::FETCH_ASSOC;
+ }
+
+ // Initialize the formatters here. This ensures that any parameters passed to the formatter
+ // element get passed along to the actual formatter object
+ foreach($this->formatters as $fe) {
+ $fe->prepare();
+ }
+
+ $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) && empty($this->filelists)
+ && count($this->transactions) === 0) {
+ throw new BuildException("Source file or fileset/filelist, "
+ . "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
+ foreach($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $srcDir = $fs->getDir($this->project);
+ $srcFiles = $ds->getIncludedFiles();
+ // Make a transaction for each file
+ foreach($srcFiles as $srcFile) {
+ $t = $this->createTransaction();
+ $t->setSrc(new PhingFile($srcDir, $srcFile));
+ }
+ }
+
+ // process filelists
+ foreach($this->filelists as $fl) {
+ $srcDir = $fl->getDir($this->project);
+ $srcFiles = $fl->getFiles($this->project);
+ // Make a transaction for each file
+ foreach($srcFiles as $srcFile) {
+ $t = $this->createTransaction();
+ $t->setSrc(new PhingFile($srcDir, $srcFile));
+ }
+ }
+
+ // 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 = null;
+
+ // Initialize the formatters.
+ $this->initFormatters();
+
+ try {
+
+ // Process all transactions
+ for ($i=0,$size=count($this->transactions); $i < $size; $i++) {
+ if (!$this->isAutocommit()) {
+ $this->log("Beginning transaction", Project::MSG_VERBOSE);
+ $this->conn->beginTransaction();
+ }
+ $this->transactions[$i]->runTransaction();
+ if (!$this->isAutocommit()) {
+ $this->log("Commiting transaction", Project::MSG_VERBOSE);
+ $this->conn->commit();
+ }
+ }
+ } catch (Exception $e) {
+ $this->closeConnection();
+ throw $e;
+ }
+ } catch (IOException $e) {
+ if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") {
+ try {
+ $this->conn->rollback();
+ } catch (PDOException $ex) {}
+ }
+ $this->closeConnection();
+ throw new BuildException($e->getMessage(), $this->location);
+ } catch (PDOException $e){
+ if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") {
+ try {
+ $this->conn->rollback();
+ } catch (PDOException $ex) {}
+ }
+ $this->closeConnection();
+ throw new BuildException($e->getMessage(), $this->location);
+ }
+
+ // Close the formatters.
+ $this->closeFormatters();
+
+ $this->log($this->goodSql . " of " . $this->totalSql .
+ " SQL statements executed successfully");
+
+ } catch (Exception $e) {
+ $this->transactions = $savedTransaction;
+ $this->sqlCommand = $savedSqlCommand;
+ $this->closeConnection();
+ throw $e;
+ }
+ // finally {
+ $this->transactions = $savedTransaction;
+ $this->sqlCommand = $savedSqlCommand;
+ $this->closeConnection();
+ }
+
+
+ /**
+ * read in lines and execute them
+ * @throws PDOException, IOException
+ */
+ public function runStatements(Reader $reader) {
+
+ if (self::DELIM_NORMAL == $this->delimiterType && 0 === strpos($this->getUrl(), 'pgsql:')) {
+ require_once 'phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php';
+ $splitter = new PgsqlPDOQuerySplitter($this, $reader);
+ } else {
+ require_once 'phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php';
+ $splitter = new DefaultPDOQuerySplitter($this, $reader, $this->delimiterType);
+ }
+
+ try {
+ while (null !== ($query = $splitter->nextQuery())) {
+ $this->log("SQL: " . $query, Project::MSG_VERBOSE);
+ $this->execSQL($query);
+ }
+
+ } catch (PDOException $e) {
+ throw $e;
+ }
+ }
+
+ /**
+ * Whether the passed-in SQL statement is a SELECT statement.
+ * This does a pretty simple match, checking to see if statement starts with
+ * 'select' (but not 'select into').
+ *
+ * @param string $sql
+ * @return boolean Whether specified SQL looks like a SELECT query.
+ */
+ protected function isSelectSql($sql)
+ {
+ $sql = trim($sql);
+ return (stripos($sql, 'select') === 0 && stripos($sql, 'select into ') !== 0);
+ }
+
+ /**
+ * Exec the sql statement.
+ * @throws PDOException
+ */
+ protected function execSQL($sql) {
+
+ // Check and ignore empty statements
+ if (trim($sql) == "") {
+ return;
+ }
+
+ try {
+ $this->totalSql++;
+
+ $this->statement = $this->conn->prepare($sql);
+ $this->statement->execute();
+ $this->log($this->statement->rowCount() . " rows affected", Project::MSG_VERBOSE);
+
+ // only call processResults() for statements that return actual data (such as 'select')
+ if ($this->statement->columnCount() > 0)
+ {
+ $this->processResults();
+ }
+
+ $this->statement->closeCursor();
+ $this->statement = null;
+
+ $this->goodSql++;
+
+ } catch (PDOException $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);
+ }
+ }
+
+ /**
+ * Returns configured PDOResultFormatter objects (which were created from PDOSQLExecFormatterElement objects).
+ * @return array PDOResultFormatter[]
+ */
+ protected function getConfiguredFormatters()
+ {
+ $formatters = array();
+ foreach ($this->formatters as $fe) {
+ $formatters[] = $fe->getFormatter();
+ }
+ return $formatters;
+ }
+
+ /**
+ * Initialize the formatters.
+ */
+ protected function initFormatters() {
+ $formatters = $this->getConfiguredFormatters();
+ foreach ($formatters as $formatter) {
+ $formatter->initialize();
+ }
+
+ }
+
+ /**
+ * Run cleanup and close formatters.
+ */
+ protected function closeFormatters() {
+ $formatters = $this->getConfiguredFormatters();
+ foreach ($formatters as $formatter) {
+ $formatter->close();
+ }
+ }
+
+ /**
+ * Passes results from query to any formatters.
+ * @throws PDOException
+ */
+ protected function processResults() {
+
+ try {
+
+ $this->log("Processing new result set.", Project::MSG_VERBOSE);
+
+ $formatters = $this->getConfiguredFormatters();
+
+ while ($row = $this->statement->fetch($this->fetchMode)) {
+ foreach ($formatters as $formatter) {
+ $formatter->processRow($row);
+ }
+ }
+
+ } catch (Exception $x) {
+ $this->log("Error processing reults: " . $x->getMessage(), Project::MSG_ERR);
+ foreach ($formatters as $formatter) {
+ $formatter->close();
+ }
+ throw $x;
+ }
+
+ }
+
+ /**
+ * Closes current connection
+ */
+ protected function closeConnection()
+ {
+ if ($this->conn) {
+ unset($this->conn);
+ }
+ }
+}
+
+/**
+ * "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.
+ *
+ * @package phing.tasks.ext.pdo
+ */
+class PDOSQLExecTransaction {
+
+ 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, PDOException
+ */
+ public function runTransaction()
+ {
+ if (!empty($this->tSqlCommand)) {
+ $this->parent->log("Executing commands", Project::MSG_INFO);
+ $this->parent->runStatements(new StringReader($this->tSqlCommand));
+ }
+
+ if ($this->tSrcFile !== null) {
+ $this->parent->log("Executing file: " . $this->tSrcFile->getAbsolutePath(),
+ Project::MSG_INFO);
+ $reader = new FileReader($this->tSrcFile);
+ $this->parent->runStatements($reader);
+ $reader->close();
+ }
+ }
+}
+
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOTask.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOTask.php
new file mode 100755
index 00000000..93feaa6d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PDOTask.php
@@ -0,0 +1,215 @@
+<?php
+
+/*
+ * $Id: de478f3e51714db7d9163b6bbc3fa64de27549cb $
+ *
+ * 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 PDO 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 $Id$
+ * @package phing.tasks.system
+ */
+abstract class PDOTask extends Task {
+
+ private $caching = true;
+
+ /**
+ * Autocommit flag. Default value is false
+ */
+ private $autocommit = false;
+
+ /**
+ * 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() {
+ if (!class_exists('PDO')) {
+ throw new Exception("PDOTask depends on PDO feature being included in PHP.");
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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);
+
+ $user = null;
+ $pass = null;
+
+ if ($this->userId) {
+ $user = $this->getUserId();
+ }
+
+ if ($this->password) {
+ $pass = $this->getPassword();
+ }
+
+ $conn = new PDO($this->getUrl(), $user, $pass);
+ $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ try {
+ $conn->setAttribute(PDO::ATTR_AUTOCOMMIT, $this->autocommit);
+ } catch (PDOException $pe) {
+ $this->log("Unable to enable auto-commit for this database: " . $pe->getMessage(), Project::MSG_VERBOSE);
+ }
+
+ 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/pdo/PgsqlPDOQuerySplitter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php
new file mode 100755
index 00000000..b99ac624
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php
@@ -0,0 +1,291 @@
+<?php
+
+/**
+ * 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>.
+ *
+ * @version SVN: $Id: 0e3570c0e594f4396d833d77e841294855b297d9 $
+ * @package phing.tasks.ext.pdo
+ */
+
+require_once 'phing/tasks/ext/pdo/PDOQuerySplitter.php';
+
+/**
+ * Splits PostgreSQL's dialect of SQL into separate queries
+ *
+ * Unlike DefaultPDOQuerySplitter this uses a lexer instead of regular
+ * expressions. This allows handling complex constructs like C-style comments
+ * (including nested ones) and dollar-quoted strings.
+ *
+ * @author Alexey Borzov <avb@php.net>
+ * @package phing.tasks.ext.pdo
+ * @version $Id: 0e3570c0e594f4396d833d77e841294855b297d9 $
+ * @link http://www.phing.info/trac/ticket/499
+ * @link http://www.postgresql.org/docs/current/interactive/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING
+ */
+class PgsqlPDOQuerySplitter extends PDOQuerySplitter
+{
+ /**#@+
+ * Lexer states
+ */
+ const STATE_NORMAL = 0;
+ const STATE_SINGLE_QUOTED = 1;
+ const STATE_DOUBLE_QUOTED = 2;
+ const STATE_DOLLAR_QUOTED = 3;
+ const STATE_COMMENT_LINEEND = 4;
+ const STATE_COMMENT_MULTILINE = 5;
+ const STATE_BACKSLASH = 6;
+ /**#@-*/
+
+ /**
+ * Nesting depth of current multiline comment
+ * @var int
+ */
+ protected $commentDepth = 0;
+
+ /**
+ * Current dollar-quoting "tag"
+ * @var string
+ */
+ protected $quotingTag = '';
+
+ /**
+ * Current lexer state, one of STATE_* constants
+ * @var int
+ */
+ protected $state = self::STATE_NORMAL;
+
+ /**
+ * Whether a backslash was just encountered in quoted string
+ * @var bool
+ */
+ protected $escape = false;
+
+ /**
+ * Current source line being examined
+ * @var string
+ */
+ protected $line = '';
+
+ /**
+ * Position in current source line
+ * @var int
+ */
+ protected $inputIndex;
+
+ /**
+ * Gets next symbol from the input, false if at end
+ *
+ * @return string|bool
+ */
+ public function getc()
+ {
+ if (!strlen($this->line) || $this->inputIndex >= strlen($this->line)) {
+ if (null === ($line = $this->sqlReader->readLine())) {
+ return false;
+ }
+ $project = $this->parent->getOwningTarget()->getProject();
+ $this->line = ProjectConfigurator::replaceProperties(
+ $project, $line, $project->getProperties()
+ ) . "\n";
+ $this->inputIndex = 0;
+ }
+ return $this->line[$this->inputIndex++];
+ }
+
+ /**
+ * Bactracks one symbol on the input
+ *
+ * NB: we don't need ungetc() at the start of the line, so this case is
+ * not handled.
+ */
+ public function ungetc()
+ {
+ $this->inputIndex--;
+ }
+
+ /**
+ * Checks whether symbols after $ are a valid dollar-quoting tag
+ *
+ * @return string|bool Dollar-quoting "tag" if it is present, false otherwise
+ */
+ protected function checkDollarQuote()
+ {
+ $ch = $this->getc();
+ if ('$' == $ch) {
+ // empty tag
+ return '';
+
+ } elseif (!ctype_alpha($ch) && '_' != $ch) {
+ // not a delimiter
+ $this->ungetc();
+ return false;
+
+ } else {
+ $tag = $ch;
+ while (false !== ($ch = $this->getc())) {
+ if ('$' == $ch) {
+ return $tag;
+
+ } elseif (ctype_alnum($ch) || '_' == $ch) {
+ $tag .= $ch;
+
+ } else {
+ for ($i = 0; $i < strlen($tag); $i++) {
+ $this->ungetc();
+ }
+ return false;
+ }
+ }
+ }
+ }
+
+ public function nextQuery()
+ {
+ $sql = '';
+ $delimiter = $this->parent->getDelimiter();
+ $openParens = 0;
+
+ while (false !== ($ch = $this->getc())) {
+ switch ($this->state) {
+ case self::STATE_NORMAL:
+ switch ($ch) {
+ case '-':
+ if ('-' == $this->getc()) {
+ $this->state = self::STATE_COMMENT_LINEEND;
+ } else {
+ $this->ungetc();
+ }
+ break;
+ case '"':
+ $this->state = self::STATE_DOUBLE_QUOTED;
+ break;
+ case "'":
+ $this->state = self::STATE_SINGLE_QUOTED;
+ break;
+ case '/':
+ if ('*' == $this->getc()) {
+ $this->state = self::STATE_COMMENT_MULTILINE;
+ $this->commentDepth = 1;
+ } else {
+ $this->ungetc();
+ }
+ break;
+ case '$':
+ if (false !== ($tag = $this->checkDollarQuote())) {
+ $this->state = self::STATE_DOLLAR_QUOTED;
+ $this->quotingTag = $tag;
+ $sql .= '$' . $tag . '$';
+ continue 3;
+ }
+ break;
+ case '(':
+ $openParens++;
+ break;
+ case ')':
+ $openParens--;
+ break;
+ // technically we can use e.g. psql's \g command as delimiter
+ case $delimiter[0]:
+ // special case to allow "create rule" statements
+ // http://www.postgresql.org/docs/current/interactive/sql-createrule.html
+ if (';' == $delimiter && 0 < $openParens) {
+ break;
+ }
+ $hasQuery = true;
+ for ($i = 1; $i < strlen($delimiter); $i++) {
+ if ($delimiter[$i] != $this->getc()) {
+ $hasQuery = false;
+ }
+ }
+ if ($hasQuery) {
+ return $sql;
+ } else {
+ for ($j = 1; $j < $i; $j++) {
+ $this->ungetc();
+ }
+ }
+ }
+ break;
+
+ case self::STATE_COMMENT_LINEEND:
+ if ("\n" == $ch) {
+ $this->state = self::STATE_NORMAL;
+ }
+ break;
+
+ case self::STATE_COMMENT_MULTILINE:
+ switch ($ch) {
+ case '/':
+ if ('*' != $this->getc()) {
+ $this->ungetc();
+ } else {
+ $this->commentDepth++;
+ }
+ break;
+
+ case '*':
+ if ('/' != $this->getc()) {
+ $this->ungetc();
+ } else {
+ $this->commentDepth--;
+ if (0 == $this->commentDepth) {
+ $this->state = self::STATE_NORMAL;
+ continue 3;
+ }
+ }
+ }
+
+ case self::STATE_SINGLE_QUOTED:
+ case self::STATE_DOUBLE_QUOTED:
+ if ($this->escape) {
+ $this->escape = false;
+ break;
+ }
+ $quote = $this->state == self::STATE_SINGLE_QUOTED ? "'" : '"';
+ switch ($ch) {
+ case '\\':
+ $this->escape = true;
+ break;
+ case $quote:
+ if ($quote == $this->getc()) {
+ $sql .= $quote;
+ } else {
+ $this->ungetc();
+ $this->state = self::STATE_NORMAL;
+ }
+ }
+
+ case self::STATE_DOLLAR_QUOTED:
+ if ('$' == $ch && false !== ($tag = $this->checkDollarQuote())) {
+ if ($tag == $this->quotingTag) {
+ $this->state = self::STATE_NORMAL;
+ }
+ $sql .= '$' . $tag . '$';
+ continue 2;
+ }
+ }
+
+ if ($this->state != self::STATE_COMMENT_LINEEND && $this->state != self::STATE_COMMENT_MULTILINE) {
+ $sql .= $ch;
+ }
+ }
+ if ('' !== $sql) {
+ return $sql;
+ }
+ return null;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php
new file mode 100644
index 00000000..3aad8ec8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * $Id: 0b899576769e68651a8847db8db8941aa4d784a2 $
+ *
+ * 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/PhingFile.php';
+require_once 'phing/tasks/ext/pdo/PDOResultFormatter.php';
+
+/**
+ * Plain text formatter for PDO results.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @package phing.tasks.ext.pdo
+ * @since 2.3.0
+ */
+class PlainPDOResultFormatter extends PDOResultFormatter
+{
+ /**
+ * Have column headers been printed?
+ * @var boolean
+ */
+ private $colsprinted = false;
+
+ /**
+ * Whether to show headers.
+ * @var boolean
+ */
+ private $showheaders = true;
+
+ /**
+ * Column delimiter.
+ * Defaults to ','
+ * @var string
+ */
+ private $coldelimiter = ",";
+
+ /**
+ * Row delimiter.
+ * Defaults to PHP_EOL.
+ * @var string
+ */
+ private $rowdelimiter = PHP_EOL;
+
+ /**
+ * Set the showheaders attribute.
+ * @param boolean $v
+ */
+ public function setShowheaders($v) {
+ $this->showheaders = StringHelper::booleanValue($v);
+ }
+
+ /**
+ * Sets the column delimiter.
+ * @param string $v
+ */
+ public function setColdelim($v) {
+ $this->coldelimiter = $v;
+ }
+
+ /**
+ * Sets the row delimiter.
+ * @param string $v
+ */
+ public function setRowdelim($v) {
+ $this->rowdelimiter = $v;
+ }
+
+ /**
+ * Processes a specific row from PDO result set.
+ *
+ * @param array $row Row of PDO result set.
+ */
+ public function processRow($row) {
+
+ if (!$this->colsprinted && $this->showheaders) {
+ $first = true;
+ foreach($row as $fieldName => $ignore) {
+ if ($first) $first = false; else $line .= ",";
+ $line .= $fieldName;
+ }
+
+ $this->out->write($line);
+ $this->out->write(PHP_EOL);
+
+ $line = "";
+ $colsprinted = true;
+ } // if show headers
+
+ $first = true;
+ foreach($row as $columnValue) {
+
+ if ($columnValue != null) {
+ $columnValue = trim($columnValue);
+ }
+
+ if ($first) {
+ $first = false;
+ } else {
+ $line .= $this->coldelimiter;
+ }
+ $line .= $columnValue;
+ }
+
+ $this->out->write($line);
+ $this->out->write($this->rowdelimiter);
+
+ }
+
+ public function getPreferredOutfile()
+ {
+ return new PhingFile('results.txt');
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php
new file mode 100644
index 00000000..435ae6e7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * $Id: e5c24c7ac3cd665f7877d66f64218be584429581 $
+ *
+ * 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/PhingFile.php';
+require_once 'phing/tasks/ext/pdo/PDOResultFormatter.php';
+
+/**
+ * XML formatter for PDO results.
+ *
+ * This class reprsents the output of a query using a simple XML schema.
+ *
+ * <results>
+ * <row>
+ * <col name="id">value</col>
+ * <col name="name">value2</col>
+ * </row>
+ * <row>
+ * <col name="id">value</col>
+ * <col name="name">value2</col>
+ * </row>
+ * </results>
+ *
+ * The actual names of the colums will depend on the fetchmode that was used
+ * with PDO.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>
+ * @package phing.tasks.ext.pdo
+ * @since 2.3.0
+ */
+class XMLPDOResultFormatter extends PDOResultFormatter {
+
+ /**
+ * The XML document being created.
+ * @var DOMDocument
+ */
+ private $doc;
+
+ /**
+ * @var DOMElement
+ */
+ private $rootNode;
+
+ /**
+ * XML document encoding
+ *
+ * @var string
+ */
+ private $encoding;
+
+ /**
+ * @var boolean
+ */
+ private $formatOutput = true;
+
+ /**
+ * Set the DOM document encoding.
+ * @param string $v
+ */
+ public function setEncoding($v) {
+ $this->encoding = $v;
+ }
+
+ /**
+ * @param boolean $v
+ */
+ public function setFormatOutput($v) {
+ $this->formatOutput = (boolean) $v;
+ }
+
+ public function initialize() {
+ $this->doc = new DOMDocument("1.0", $this->encoding);
+ $this->rootNode = $this->doc->createElement('results');
+ $this->doc->appendChild($this->rootNode);
+ $this->doc->formatOutput = $this->formatOutput;
+ }
+
+ /**
+ * Processes a specific row from PDO result set.
+ *
+ * @param array $row Row of PDO result set.
+ */
+ public function processRow($row) {
+
+ $rowNode = $this->doc->createElement('row');
+ $this->rootNode->appendChild($rowNode);
+
+ foreach($row as $columnName => $columnValue) {
+
+ $colNode = $this->doc->createElement('column');
+ $colNode->setAttribute('name', $columnName);
+
+ if ($columnValue != null) {
+ $columnValue = trim($columnValue);
+ $colNode->nodeValue = $columnValue;
+ }
+ $rowNode->appendChild($colNode);
+ }
+
+ }
+
+ /**
+ * Gets a preferred filename for an output file.
+ *
+ * If no filename is specified, this is where the results will be placed
+ * (unless usefile=false).
+ *
+ * @return string
+ */
+ public function getPreferredOutfile()
+ {
+ return new PhingFile('results.xml');
+ }
+
+ /**
+ * Write XML to file and free the DOM objects.
+ */
+ public function close() {
+ $this->out->write($this->doc->saveXML());
+ $this->rootNode = null;
+ $this->doc = null;
+ parent::close();
+ }
+}
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 100755
index 00000000..23a0e4c6
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php
@@ -0,0 +1,228 @@
+<?php
+/*
+ * $Id: 7016dea93483cc99ad17a638e30f5ff57c37c78b $
+ *
+ * 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 $Id$
+ */
+class PEAR_PackageFileManager_Fileset {
+
+ /**
+ * 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($options)
+ {
+ if (!is_array($options)) {
+ $options = $options->getOptions();
+ }
+
+ $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/phar/PharMetadata.php b/buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadata.php
new file mode 100644
index 00000000..1f7a263c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadata.php
@@ -0,0 +1,55 @@
+<?php
+/*
+ * $Id: fae81ee47ae75fc98d7848a22da93bfd4afb7a1b $
+ *
+ * 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/phar/PharMetadataElement.php';
+
+/**
+ * @package phing.tasks.ext.phar
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @since 2.4.0
+ */
+class PharMetadata
+{
+ /**
+ * @var array
+ */
+ protected $elements = array();
+ /**
+ * @return PharMetadataElement
+ */
+ public function createElement()
+ {
+ return ($this->elements[] = new PharMetadataElement());
+ }
+ /**
+ * @return array
+ */
+ public function toArray()
+ {
+ $metadata = array();
+
+ foreach ($this->elements as $element) {
+ $metadata[$element->getName()] = $element->toArray();
+ }
+
+ return $metadata;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadataElement.php b/buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadataElement.php
new file mode 100644
index 00000000..c40f68f1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadataElement.php
@@ -0,0 +1,80 @@
+<?php
+/*
+ * $Id: 4c70deae6a6f273d55f504077a3941ad926ad325 $
+ *
+ * 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/phar/PharMetadata.php';
+
+/**
+ * @package phing.tasks.ext.phar
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @since 2.4.0
+ */
+class PharMetadataElement
+ extends PharMetadata
+{
+ /**
+ * @var string
+ */
+ private $name;
+ /**
+ * @var string
+ */
+ private $value;
+ /**
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->value = $value;
+ }
+ /**
+ * @param string $name
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+ /**
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+ /**
+ * Return array of
+ *
+ * @return string|array
+ */
+ public function getValue()
+ {
+ /*
+ * Elements first!
+ */
+ return (empty($this->elements) ? $this->value : $this->elements);
+ }
+ /**
+ * @return string|array
+ */
+ public function toArray()
+ {
+ return (empty($this->elements) ? $this->value : parent::toArray());
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phar/PharPackageTask.php b/buildscripts/phing/classes/phing/tasks/ext/phar/PharPackageTask.php
new file mode 100644
index 00000000..76a4215a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phar/PharPackageTask.php
@@ -0,0 +1,362 @@
+<?php
+/*
+ * $Id: 0396ab9c461e7d7655f12c9ed3a613fe6e69f973 $
+ *
+ * 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';
+require_once 'phing/types/IterableFileSet.php';
+require_once 'phing/tasks/ext/phar/PharMetadata.php';
+
+/**
+ * Package task for {@link http://ru.php.net/manual/en/book.phar.php Phar technology}.
+ *
+ * @package phing.tasks.ext
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @since 2.4.0
+ */
+class PharPackageTask
+ extends MatchingTask
+{
+ /**
+ * @var PhingFile
+ */
+ private $destinationFile;
+ /**
+ * @var int
+ */
+ private $compression = Phar::NONE;
+ /**
+ * Base directory, from where local package paths will be calculated.
+ *
+ * @var PhingFile
+ */
+ private $baseDirectory;
+ /**
+ * @var PhingFile
+ */
+ private $cliStubFile;
+ /**
+ * @var PhingFile
+ */
+ private $webStubFile;
+ /**
+ * @var string
+ */
+ private $stubPath;
+ /**
+ * Private key the Phar will be signed with.
+ *
+ * @var PhingFile
+ */
+ private $key;
+ /**
+ * Password for the private key.
+ *
+ * @var string
+ */
+ private $keyPassword = '';
+ /**
+ * @var int
+ */
+ private $signatureAlgorithm = Phar::SHA1;
+ /**
+ * @var array
+ */
+ private $filesets = array();
+ /**
+ * @var PharMetadata
+ */
+ private $metadata = null;
+ /**
+ * @var string
+ */
+ private $alias;
+ /**
+ * @return PharMetadata
+ */
+ public function createMetadata()
+ {
+ return ($this->metadata = new PharMetadata());
+ }
+ /**
+ * @return FileSet
+ */
+ public function createFileSet()
+ {
+ $this->fileset = new IterableFileSet();
+ $this->filesets[] = $this->fileset;
+ return $this->fileset;
+ }
+ /**
+ * @param string $algorithm
+ */
+ public function setSignature($algorithm)
+ {
+ /*
+ * If we don't support passed algprithm, leave old one.
+ */
+ switch ($algorithm) {
+ case 'md5':
+ $this->signatureAlgorithm = Phar::MD5;
+ break;
+ case 'sha1':
+ $this->signatureAlgorithm = Phar::SHA1;
+ break;
+ case 'sha256':
+ $this->signatureAlgorithm = Phar::SHA256;
+ break;
+ case 'sha512':
+ $this->signatureAlgorithm = Phar::SHA512;
+ break;
+ case 'openssl':
+ $this->signatureAlgorithm = Phar::OPENSSL;
+ break;
+ default:
+ break;
+ }
+ }
+ /**
+ * @param string $compression
+ */
+ public function setCompression($compression)
+ {
+ /*
+ * If we don't support passed compression, leave old one.
+ */
+ switch ($compression) {
+ case 'gzip':
+ $this->compression = Phar::GZ;
+ break;
+ case 'bzip2':
+ $this->compression = Phar::BZ2;
+ break;
+ default:
+ break;
+ }
+ }
+ /**
+ * @param PhingFile $destinationFile
+ */
+ public function setDestFile(PhingFile $destinationFile)
+ {
+ $this->destinationFile = $destinationFile;
+ }
+ /**
+ * @param PhingFile $baseDirectory
+ */
+ public function setBaseDir(PhingFile $baseDirectory)
+ {
+ $this->baseDirectory = $baseDirectory;
+ }
+ /**
+ * @param PhingFile $stubFile
+ */
+ public function setCliStub(PhingFile $stubFile)
+ {
+ $this->cliStubFile = $stubFile;
+ }
+ /**
+ * @param PhingFile $stubFile
+ */
+ public function setWebStub(PhingFile $stubFile)
+ {
+ $this->webStubFile = $stubFile;
+ }
+ /**
+ * @param string $stubPath
+ */
+ public function setStub($stubPath)
+ {
+ $this->stubPath = $stubPath;
+ }
+ /**
+ * @param $alias
+ */
+ public function setAlias($alias)
+ {
+ $this->alias = $alias;
+ }
+ /**
+ * Sets the private key to use to sign the Phar with.
+ *
+ * @param PhingFile $key Private key to sign the Phar with.
+ */
+ public function setKey(PhingFile $key)
+ {
+ $this->key = $key;
+ }
+ /**
+ * Password for the private key.
+ *
+ * @param string $keyPassword
+ */
+ public function setKeyPassword($keyPassword)
+ {
+ $this->keyPassword = $keyPassword;
+ }
+ /**
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $this->checkPreconditions();
+
+ try {
+ $this->log(
+ 'Building package: '.$this->destinationFile->__toString(),
+ Project::MSG_INFO
+ );
+
+ /*
+ * Delete old package, if exists.
+ */
+ if ($this->destinationFile->exists()) {
+ /*
+ * TODO Check operation for errors...
+ */
+ $this->destinationFile->delete();
+ }
+
+ $phar = $this->buildPhar();
+ $phar->startBuffering();
+
+ $baseDirectory = realpath($this->baseDirectory->getPath());
+
+ foreach ($this->filesets as $fileset) {
+ $this->log(
+ 'Adding specified files in ' . $fileset->getDir($this->project) . ' to package',
+ Project::MSG_VERBOSE
+ );
+
+ $phar->buildFromIterator($fileset, $baseDirectory);
+ }
+
+ $phar->stopBuffering();
+
+ /*
+ * File compression, if needed.
+ */
+ if (Phar::NONE != $this->compression) {
+ $phar->compressFiles($this->compression);
+ }
+ } catch (Exception $e) {
+ throw new BuildException(
+ 'Problem creating package: '.$e->getMessage(),
+ $e,
+ $this->getLocation()
+ );
+ }
+ }
+ /**
+ * @throws BuildException
+ */
+ private function checkPreconditions()
+ {
+ if (is_null($this->destinationFile)) {
+ throw new BuildException("destfile attribute must be set!", $this->getLocation());
+ }
+
+ if ($this->destinationFile->exists() && $this->destinationFile->isDirectory()) {
+ throw new BuildException("destfile is a directory!", $this->getLocation());
+ }
+
+ if (!$this->destinationFile->canWrite()) {
+ throw new BuildException("Can not write to the specified destfile!", $this->getLocation());
+ }
+ if (!is_null($this->baseDirectory)) {
+ if (!$this->baseDirectory->exists()) {
+ throw new BuildException("basedir '" . (string) $this->baseDirectory . "' does not exist!", $this->getLocation());
+ }
+ }
+ if ($this->signatureAlgorithm == Phar::OPENSSL) {
+
+ if (!extension_loaded('openssl')) {
+ throw new BuildException("PHP OpenSSL extension is required for OpenSSL signing of Phars!", $this->getLocation());
+ }
+
+ if (is_null($this->key)) {
+ throw new BuildException("key attribute must be set for OpenSSL signing!", $this->getLocation());
+ }
+
+ if (!$this->key->exists()) {
+ throw new BuildException("key '" . (string) $this->key . "' does not exist!", $this->getLocation());
+ }
+
+ if (!$this->key->canRead()) {
+ throw new BuildException("key '" . (string) $this->key . "' cannot be read!", $this->getLocation());
+ }
+ }
+ }
+ /**
+ * Build and configure Phar object.
+ *
+ * @return Phar
+ */
+ private function buildPhar()
+ {
+ $phar = new Phar($this->destinationFile);
+
+ if ($this->signatureAlgorithm == Phar::OPENSSL) {
+
+ // Load up the contents of the key
+ $keyContents = file_get_contents($this->key);
+
+ // Setup an OpenSSL resource using the private key and tell the Phar
+ // to sign it using that key.
+ $private = openssl_pkey_get_private($keyContents, $this->keyPassword);
+ $phar->setSignatureAlgorithm(Phar::OPENSSL, $private);
+
+ // Get the details so we can get the public key and write that out
+ // alongside the phar.
+ $details = openssl_pkey_get_details($private);
+ file_put_contents($this->destinationFile . '.pubkey', $details['key']);
+
+ } else {
+ $phar->setSignatureAlgorithm($this->signatureAlgorithm);
+ }
+
+ if (isset($this->stubPath)) {
+ $phar->setStub(file_get_contents($this->stubPath));
+ } else {
+ if (!empty($this->cliStubFile)) {
+ $cliStubFile = $this->cliStubFile->getPathWithoutBase($this->baseDirectory);
+ } else {
+ $cliStubFile = null;
+ }
+
+ if (!empty($this->webStubFile)) {
+ $webStubFile = $this->webStubFile->getPathWithoutBase($this->baseDirectory);
+ } else {
+ $webStubFile = null;
+ }
+
+ $phar->setDefaultStub($cliStubFile, $webStubFile);
+ }
+
+ if ($metadata = $this->metadata->toArray()) {
+ $phar->setMetadata($metadata);
+ }
+
+ if(!empty($this->alias)){
+ $phar->setAlias($this->alias);
+ }
+
+ return $phar;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageTask.php b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageTask.php
new file mode 100644
index 00000000..80da93fa
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageTask.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ * $Id: 5029881915d6a9e95320ba6e7f463f38af66cd93 $
+ *
+ * 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/phk/PhkPackageWebAccess.php';
+
+/**
+ * See {@link http://phk.tekwire.net/} for more information about PHK.
+ *
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @package phing.tasks.ext.phk
+ */
+class PhkPackageTask extends Task
+{
+ /**
+ * @var string
+ */
+ private $outputFile;
+ /**
+ * @var string
+ */
+ private $inputDirectory;
+ /**
+ * @var string
+ */
+ private $phkCreatorPath;
+ /**
+ * @var PhkPackageWebAccess
+ */
+ private $webAccess;
+ /**
+ * @var array
+ */
+ private $modifiers = array();
+ /**
+ * @var array
+ */
+ private $options = array();
+ /**
+ * @return PhkPackageWebAccess
+ */
+ public function createWebAccess()
+ {
+ return ($this->webAccess = new PhkPackageWebAccess());
+ }
+ /**
+ * @param string $crcCheck
+ */
+ public function setCrcCheck($crcCheck)
+ {
+ $this->options['crc_check'] = ('true' == $crcCheck ? true : false);
+ }
+ /**
+ * @param string $webRunScript
+ */
+ public function setWebRunScript($webRunScript)
+ {
+ $this->options['web_run_script'] = $webRunScript;
+ }
+ /**
+ * @param string $cliRunScript
+ */
+ public function setCliRunScript($cliRunScript)
+ {
+ $this->options['cli_run_script'] = $cliRunScript;
+ }
+ /**
+ * @param string $libRunScript
+ */
+ public function setLibRunScript($libRunScript)
+ {
+ $this->options['lib_run_script'] = $libRunScript;
+ }
+ /**
+ * @param string $name
+ */
+ public function setName($name)
+ {
+ $this->options['name'] = $name;
+ }
+ /**
+ * @param string $webMainRedirect
+ */
+ public function setWebMainRedirect($webMainRedirect)
+ {
+ $this->options['web_main_redirect'] = ('true' == $webMainRedirect ? true : false);
+ }
+ /**
+ * @param string $pluginClass
+ */
+ public function setPluginClass($pluginClass)
+ {
+ $this->options['plugin_class'] = $pluginClass;
+ }
+ /**
+ * @param string $version
+ */
+ public function setVersion($version)
+ {
+ $this->options['version'] = $version;
+ }
+ /**
+ * @param string $summary
+ */
+ public function setSummary($summary)
+ {
+ $this->options['summary'] = $summary;
+ }
+ /**
+ * @param string $inputDirectory
+ */
+ public function setInputDirectory($inputDirectory)
+ {
+ $this->inputDirectory = $inputDirectory;
+ }
+ /**
+ * @param string $outputFile
+ */
+ public function setOutputFile($outputFile)
+ {
+ $this->outputFile = $outputFile;
+ }
+ /**
+ * May be none, gzip or bzip2.
+ *
+ * @param string $compress
+ */
+ public function setCompress($compress)
+ {
+ $this->modifiers['compress'] = $compress;
+ }
+ /**
+ * True or false.
+ *
+ * @param srting $strip
+ */
+ public function setStrip($strip)
+ {
+ $this->modifiers['strip'] = $strip;
+ }
+ /**
+ * Path to PHK_Creator.phk file.
+ *
+ * @param srting $path
+ */
+ public function setPhkCreatorPath($path)
+ {
+ $this->phkCreatorPath = $path;
+ }
+ /**
+ *
+ */
+ public function init()
+ {
+
+ }
+ /**
+ * Main method...
+ */
+ public function main()
+ {
+ /*
+ * Check for empty first - speed ;)
+ */
+ if (!is_file($this->phkCreatorPath)) {
+ throw new BuildException('You must specify the "phkcreatorpath" attribute for PHK task.');
+ }
+ if (empty($this->inputDirectory)) {
+ throw new BuildException('You must specify the "inputdirectory" attribute for PHK task.');
+ }
+ if (empty($this->outputFile)) {
+ throw new BuildException('You must specify the "outputfile" attribute for PHK task.');
+ }
+
+ require_once $this->phkCreatorPath;
+
+ $mountPoint = PHK_Mgr::mount($this->outputFile, PHK::F_CREATOR);
+ $phkManager = PHK_Mgr::instance($mountPoint);
+
+ /*
+ * Add files.
+ */
+ $phkManager->ftree()->merge_file_tree('/', $this->inputDirectory, $this->modifiers);
+
+ /*
+ * Add web_access to options, if present.
+ */
+ if (!is_null($this->webAccess)) {
+ $webAccessPaths = $this->webAccess->getPaths();
+ if (!empty($webAccessPaths)) {
+ $this->options['web_access'] = $webAccessPaths;
+ }
+ }
+
+ $phkManager->set_options($this->options);
+
+ /*
+ * Intercept output (in PHP we can't intercept stream).
+ */
+ ob_start();
+ /*
+ * Create file...
+ */
+ $phkManager->dump();
+ /*
+ * Print with Phing log...
+ */
+ $output = trim(ob_get_clean());
+ $output = explode("\n", $output);
+ foreach ($output as $line) {
+ /*
+ * Delete all '--- *' lines. Bluh!
+ */
+ /*
+ * TODO Change preg_math to more faster alternative.
+ */
+ if (preg_match('/^---/', $line)) {
+ continue;
+ }
+
+ $this->log($line);
+ }
+
+ /*
+ * Set rights for generated file... Don't use umask() - see
+ * notes in official documentation for this function.
+ */
+ chmod($this->outputFile, 0644);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccess.php b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccess.php
new file mode 100644
index 00000000..9634d899
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccess.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * $Id: b6ea3e7df3c43498e8c6e105bedfd0b6e99e055a $
+ *
+ * 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/phk/PhkPackageWebAccessPath.php';
+
+/**
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @package phing.tasks.ext.phk
+ */
+class PhkPackageWebAccess
+{
+ /**
+ * @var array
+ */
+ private $paths = array();
+ /**
+ * @return PhkPackageWebAccessPath
+ */
+ public function createPath()
+ {
+ return ($this->paths[] = new PhkPackageWebAccessPath());
+ }
+ /**
+ * @return array
+ */
+ public function getPaths()
+ {
+ /*
+ * Get real paths...
+ */
+ $paths = array();
+
+ foreach ($this->paths as $path) {
+ $paths[] = $path->getPath();
+ }
+
+ return $paths;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccessPath.php b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccessPath.php
new file mode 100644
index 00000000..730a8929
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccessPath.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * $Id: 755aeaf34726af2eb30c989914faad8d7aebd126 $
+ *
+ * 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>.
+ */
+
+/**
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @package phing.tasks.ext.phk
+ */
+class PhkPackageWebAccessPath
+{
+ /**
+ * @var string
+ */
+ private $path;
+ /**
+ * @param string $path
+ */
+ public function addText($path)
+ {
+ $this->path = trim($path);
+ }
+ /**
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php
new file mode 100644
index 00000000..e650ca72
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php
@@ -0,0 +1,177 @@
+<?php
+/**
+ * $Id: dece05e79e883b4d5e95f2215e36ce4f2f72ed2e $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * A wrapper for the implementations of PHPCPDResultFormatter.
+ *
+ * @package phing.tasks.ext.phpcpd
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: dece05e79e883b4d5e95f2215e36ce4f2f72ed2e $
+ */
+class PHPCPDFormatterElement
+{
+ /**
+ * The report result formatter.
+ *
+ * @var PHPCPDResultFormatter
+ */
+ protected $_formatter = null;
+
+ /**
+ * The type of the formatter.
+ *
+ * @var string
+ */
+ protected $_type = '';
+
+ /**
+ * Whether to use file (or write output to phing log).
+ *
+ * @var boolean
+ */
+ protected $_useFile = true;
+
+ /**
+ * Output file for formatter.
+ *
+ * @var PhingFile
+ */
+ protected $_outfile = null;
+
+ /**
+ * The parent task
+ *
+ * @var PHPCPDTask
+ */
+ private $_parentTask;
+
+ /**
+ * Construct a new PHPCPDFormatterElement with parent task.
+ * @param PHPCPDTask $parentTask
+ */
+ public function __construct(PHPCPDTask $parentTask)
+ {
+ $this->_parentTask = $parentTask;
+ }
+
+ /**
+ * Sets the formatter type.
+ *
+ * @param string $type Type of the formatter
+ *
+ * @return void
+ */
+ public function setType($type)
+ {
+ $this->_type = $type;
+
+ switch ($this->_type) {
+ case 'pmd':
+ if ($this->_useFile === false) {
+ throw new BuildException(
+ "Formatter '" . $this->_type
+ . "' can only print the result to an file"
+ );
+ }
+
+ include_once 'phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php';
+ $this->_formatter = new PMDPHPCPDResultFormatter();
+ break;
+
+ case 'default':
+ include_once 'phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php';
+ $this->_formatter = new DefaultPHPCPDResultFormatter();
+ break;
+
+ default:
+ throw new BuildException(
+ "Formatter '" . $this->_type . "' not implemented"
+ );
+ }
+ }
+
+ /**
+ * Get the formatter type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->_type;
+ }
+
+ /**
+ * Set whether to write formatter results to file or not.
+ *
+ * @param boolean $useFile True or false.
+ *
+ * @return void
+ */
+ public function setUseFile($useFile)
+ {
+ $this->_useFile = StringHelper::booleanValue($useFile);
+ }
+
+ /**
+ * Return whether to write formatter results to file or not.
+ *
+ * @return boolean
+ */
+ public function getUseFile()
+ {
+ return $this->_useFile;
+ }
+
+ /**
+ * Sets the output file for the formatter results.
+ *
+ * @param PhingFile $outfile The output file
+ *
+ * @return void
+ */
+ public function setOutfile(PhingFile $outfile)
+ {
+ $this->_outfile = $outfile;
+ }
+
+ /**
+ * Get the output file.
+ *
+ * @return PhingFile
+ */
+ public function getOutfile()
+ {
+ return $this->_outfile;
+ }
+
+ /**
+ * Returns the report formatter.
+ *
+ * @throws BuildException When the specified renderer does not exist.
+ * @return PHPCPDResultFormatter
+ */
+ public function getFormatter()
+ {
+ return $this->_formatter;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDTask.php
new file mode 100644
index 00000000..31f76154
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDTask.php
@@ -0,0 +1,312 @@
+<?php
+/**
+ * $Id: 8fbff39b2ca68e97afd59d5dc6d5a37c3678624e $
+ *
+ * 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';
+
+/**
+ * Runs PHP Copy & Paste Detector. Checking PHP files for duplicated code.
+ * Refactored original PhpCpdTask provided by
+ * Timo Haberkern <timo.haberkern@fantastic-bits.de>
+ *
+ * @package phing.tasks.ext.phpcpd
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 8fbff39b2ca68e97afd59d5dc6d5a37c3678624e $
+ */
+class PHPCPDTask extends Task
+{
+ /**
+ * A php source code filename or directory
+ *
+ * @var PhingFile
+ */
+ protected $_file = null;
+
+ /**
+ * All fileset objects assigned to this task
+ *
+ * @var array<FileSet>
+ */
+ protected $_filesets = array();
+
+ /**
+ * Minimum number of identical lines.
+ *
+ * @var integer
+ */
+ protected $_minLines = 5;
+
+ /**
+ * Minimum number of identical tokens.
+ *
+ * @var integer
+ */
+ protected $_minTokens = 70;
+
+ /**
+ * List of valid file extensions for analyzed files.
+ *
+ * @var array
+ */
+ protected $_allowedFileExtensions = array('php');
+
+ /**
+ * List of exclude directory patterns.
+ *
+ * @var array
+ */
+ protected $_ignorePatterns = array('.git', '.svn', 'CVS', '.bzr', '.hg');
+
+ /**
+ * The format for the report
+ *
+ * @var string
+ */
+ protected $_format = 'default';
+
+ /**
+ * Formatter elements.
+ *
+ * @var array<PHPCPDFormatterElement>
+ */
+ protected $_formatters = array();
+
+ /**
+ * Load the necessary environment for running PHPCPD.
+ *
+ * @throws BuildException - if the phpcpd classes can't be loaded.
+ */
+ public function init()
+ {
+ /**
+ * Determine PHPCPD installation
+ */
+ @include_once 'PHPCPD/Autoload.php';
+
+ if (! class_exists('PHPCPD_TextUI_Command')) {
+ throw new BuildException(
+ 'PHPCPDTask depends on PHPCPD being installed '
+ . 'and on include_path.',
+ $this->getLocation()
+ );
+ }
+
+ // Other dependencies that should only be loaded
+ // when class is actually used
+ require_once 'phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php';
+ }
+
+ /**
+ * Set the input source file or directory.
+ *
+ * @param PhingFile $file The input source file or directory.
+ *
+ * @return void
+ */
+ public function setFile(PhingFile $file)
+ {
+ $this->_file = $file;
+ }
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ *
+ * @param FileSet $fs List of files to scan
+ *
+ * @return void
+ */
+ public function addFileSet(FileSet $fs)
+ {
+ $this->_filesets[] = $fs;
+ }
+
+ /**
+ * Sets the minimum number of identical lines (default: 5).
+ *
+ * @param integer $minLines Minimum number of identical lines
+ *
+ * @return void
+ */
+ public function setMinLines($minLines)
+ {
+ $this->_minLines = $minLines;
+ }
+
+ /**
+ * Sets the minimum number of identical tokens (default: 70).
+ *
+ * @param integer $minTokens Minimum number of identical tokens
+ */
+ public function setMinTokens($minTokens)
+ {
+ $this->_minTokens = $minTokens;
+ }
+
+ /**
+ * Sets a list of filename extensions for valid php source code files.
+ *
+ * @param string $fileExtensions List of valid file extensions.
+ *
+ * @return void
+ */
+ public function setAllowedFileExtensions($fileExtensions)
+ {
+ $this->_allowedFileExtensions = array();
+
+ $token = ' ,;';
+ $ext = strtok($fileExtensions, $token);
+
+ while ($ext !== false) {
+ $this->_allowedFileExtensions[] = $ext;
+ $ext = strtok($token);
+ }
+ }
+
+ /**
+ * Sets a list of ignore patterns that is used to exclude directories from
+ * the source analysis.
+ *
+ * @param string $ignorePatterns List of ignore patterns.
+ *
+ * @return void
+ */
+ public function setIgnorePatterns($ignorePatterns)
+ {
+ $this->_ignorePatterns = array();
+
+ $token = ' ,;';
+ $pattern = strtok($ignorePatterns, $token);
+
+ while ($pattern !== false) {
+ $this->_ignorePatterns[] = $pattern;
+ $pattern = strtok($token);
+ }
+ }
+
+ /**
+ * Sets the output format
+ *
+ * @param string $format Format of the report
+ */
+ public function setFormat($format)
+ {
+ $this->_format = $format;
+ }
+
+ /**
+ * Create object for nested formatter element.
+ *
+ * @return PHPCPDFormatterElement
+ */
+ public function createFormatter()
+ {
+ $num = array_push(
+ $this->_formatters,
+ new PHPCPDFormatterElement($this)
+ );
+ return $this->_formatters[$num-1];
+ }
+
+ /**
+ * Executes PHPCPD against PhingFile or a FileSet
+ *
+ * @return void
+ */
+ 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 (count($this->_formatters) == 0) {
+ // turn legacy format attribute into formatter
+ $fmt = new PHPCPDFormatterElement($this);
+ $fmt->setType($this->_format);
+ $fmt->setUseFile(false);
+ $this->_formatters[] = $fmt;
+ }
+
+ $this->validateFormatters();
+
+ $filesToParse = array();
+
+ if ($this->_file instanceof PhingFile) {
+ $filesToParse[] = $this->_file->getPath();
+ } else {
+ // append any files in filesets
+ foreach ($this->_filesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)
+ ->getIncludedFiles();
+
+ foreach ($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $filesToParse[] = $f->getAbsolutePath();
+ }
+ }
+ }
+
+ $this->log('Processing files...');
+
+ $detector = new PHPCPD_Detector(new PHPCPD_Detector_Strategy_Default());
+ $clones = $detector->copyPasteDetection(
+ $filesToParse,
+ $this->_minLines,
+ $this->_minTokens
+ );
+
+ $this->log('Finished copy/paste detection');
+
+ foreach ($this->_formatters as $fe) {
+ $formatter = $fe->getFormatter();
+ $formatter->processClones(
+ $clones,
+ $this->project,
+ $fe->getUseFile(),
+ $fe->getOutfile()
+ );
+ }
+ }
+
+ /**
+ * Validates the available formatters
+ *
+ * @throws BuildException
+ * @return void
+ */
+ protected function validateFormatters()
+ {
+ foreach ($this->_formatters as $fe) {
+ if ($fe->getType() == '') {
+ throw new BuildException(
+ "Formatter missing required 'type' attribute."
+ );
+ }
+
+ if ($fe->getUsefile() && $fe->getOutfile() === null) {
+ throw new BuildException(
+ "Formatter requires 'outfile' attribute "
+ . "when 'useFile' is true."
+ );
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php
new file mode 100644
index 00000000..b84da547
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * $Id: a4825de14746285d97af9d435215ec8400406fa7 $
+ *
+ * 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 'PHPCPD/TextUI/ResultPrinter.php';
+require_once 'phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php';
+
+/**
+ * Prints plain text output of phpcpd run
+ *
+ * @package phing.tasks.ext.phpcpd.formatter
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: a4825de14746285d97af9d435215ec8400406fa7 $
+ */
+class DefaultPHPCPDResultFormatter extends PHPCPDResultFormatter
+{
+
+ /**
+ * Processes a list of clones.
+ *
+ * @param PHPCPD_CloneMap $clones
+ * @param Project $project
+ * @param boolean $useFile
+ * @param PhingFile|null $outfile
+ */
+ public function processClones(PHPCPD_CloneMap $clones, Project $project, $useFile = false, $outFile = null)
+ {
+ $logger = new PHPCPD_TextUI_ResultPrinter();
+ // default format goes to logs, no buffering
+ ob_start();
+ $logger->printResult($clones, $project->getBaseDir(), true);
+ $output = ob_get_contents();
+ ob_end_clean();
+
+ if (!$useFile || empty($outFile)) {
+ echo $output;
+ } else {
+ file_put_contents($outFile->getPath(), $output);
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php
new file mode 100644
index 00000000..0cdab194
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * $Id: 478d7a823945aa4706befb0059b2fab28743fb07 $
+ *
+ * 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 abstract class describes classes that format the results of a PHPCPD run.
+ *
+ * @package phing.tasks.ext.phpcpd.formatter
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 478d7a823945aa4706befb0059b2fab28743fb07 $
+ */
+abstract class PHPCPDResultFormatter
+{
+ /**
+ * Processes a list of clones.
+ *
+ * @param PHPCPD_CloneMap $clones
+ * @param Project $project
+ * @param boolean $useFile
+ * @param PhingFile|null $outfile
+ */
+ abstract public function processClones(PHPCPD_CloneMap $clones, Project $project, $useFile = false, $outFile = null);
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php
new file mode 100644
index 00000000..33c24407
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * $Id: a336822b8c54702ba2b0590e5a812c779e5c221b $
+ *
+ * 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 'PHPCPD/Log/XML/PMD.php';
+require_once 'phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php';
+
+/**
+ * Prints PMD-XML output of phpcpd run
+ *
+ * @package phing.tasks.ext.phpcpd.formatter
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: a336822b8c54702ba2b0590e5a812c779e5c221b $
+ */
+class PMDPHPCPDResultFormatter extends PHPCPDResultFormatter
+{
+ /**
+ * Processes a list of clones.
+ *
+ * @param PHPCPD_CloneMap $clones
+ * @param Project $project
+ * @param boolean $useFile
+ * @param PhingFile|null $outfile
+ */
+ public function processClones(PHPCPD_CloneMap $clones, Project $project, $useFile = false, $outFile = null)
+ {
+ if (!$useFile || empty($outFile)) {
+ throw new BuildException("Output filename required for this formatter");
+ }
+
+ $logger = new PHPCPD_Log_XML_PMD($outFile);
+ $logger->processClones($clones);
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php
new file mode 100644
index 00000000..462b1d99
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * $Id: 73c919ab2044bf6582f52bd7ccb0184019d52f53 $
+ *
+ * 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 'PhpDocumentor/phpDocumentor/Errors.inc';
+
+/**
+ * Phing subclass of the ErrorTracker class provided with PhpDocumentor to work around limitations in PhpDocumentor API.
+ *
+ * This class is necessary because PhpDocumentor does directly output errors and
+ * warnings occured during testing for undocumented elements to stdout.
+ * This class is injected globally to force PhpDocumentor to use phing's logging
+ * mechanism.
+ *
+ * Obviously this is far from ideal, but there's also no solution given the inflexibility of the
+ * PhpDocumentor design.
+ *
+ * @author Timo A. Hummel <privat@timohummel.com> @author felicitus
+ * @version $Id: 73c919ab2044bf6582f52bd7ccb0184019d52f53 $
+ * @package phing.tasks.ext.phpdoc
+ */
+class PhingPhpDocumentorErrorTracker extends ErrorTracker {
+
+ /*
+ * @var object Reference to the task we're called with
+ */
+ private $task;
+
+ /**
+ * Outputs a warning. This is an almost 1:1 copy from PhpDocumentor,
+ * we're just processing the warning text and send it to phing's logger.
+ *
+ * @param $num integer Number of parameters
+ * @return nothing
+ */
+ function addWarning ($num) {
+ $a = array('', '', '', '');
+ if (func_num_args()>1) {
+ for ($i=1;$i<func_num_args();$i++) {
+ $a[$i - 1] = func_get_arg($i);
+ }
+ }
+
+ $message = sprintf($GLOBALS['phpDocumentor_warning_descrip'][$num], $a[0], $a[1], $a[2], $a[3]);
+ $this->task->log($message, Project::MSG_WARN);
+
+ }
+
+ /**
+ * Outputs an error. This is an almost 1:1 copy from PhpDocumentor,
+ * we're just processing the error text and send it to phing's logger.
+ *
+ * @param $num integer Number of parameters
+ * @return nothing
+ */
+
+ function addError ($num) {
+ $a = array('', '', '', '');
+ if (func_num_args()>1) {
+ for ($i=1;$i<func_num_args();$i++) {
+ $a[$i - 1] = func_get_arg($i);
+ }
+ }
+
+ $message = sprintf($GLOBALS['phpDocumentor_error_descrip'][$num], $a[0], $a[1], $a[2], $a[3]);
+ $this->task->log($message, Project::MSG_ERR);
+
+ }
+
+ /**
+ * Sets the task we're working with. This is necessary since we need to be
+ * able to call the method "log".
+ *
+ * @param object $task The task we're working with
+ * @return nothing
+ */
+ public function setTask ($task) {
+ $this->task = $task;
+ }
+
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php
new file mode 100644
index 00000000..62662b0b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * $Id: cde99d501839daf8c9dd9df61ee6cce7caad6b3e $
+ *
+ * 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 'PhpDocumentor/phpDocumentor/Setup.inc.php';
+
+/**
+ * Phing subclass of the phpDocumentor_setup class provided with PhpDocumentor to work around limitations in PhpDocumentor API.
+ *
+ * This class is necessary because phpDocumentor_setup does not expose a complete API for setting configuration options. Because
+ * this class must directly modify some "private" GLOBAL(!) configuration variables, it is liable to break if the PhpDocumentor
+ * internal implementation changes. Obviously this is far from ideal, but there's also no solution given the inflexibility of the
+ * PhpDocumentor design.
+ *
+ * @author Hans Lellelid <hans@xmpl.org>@author hans
+ * @version $Id: cde99d501839daf8c9dd9df61ee6cce7caad6b3e $
+ * @package phing.tasks.ext.phpdoc
+ */
+class PhingPhpDocumentorSetup extends phpDocumentor_setup {
+
+ /**
+ * Constructs a new PhingPhpDocumentorSetup.
+ *
+ * @param string $configDir Directory in which to look for configuration files.
+ * @param object $task The task we're working with, so we can pass it on to the ErrorTracker
+ */
+ public function __construct($configdir = null, $task) {
+ global $_phpDocumentor_cvsphpfile_exts, $_phpDocumentor_setting, $_phpDocumentor_phpfile_exts;
+
+ $this->setup = new Io();
+ $this->render = new phpDocumentor_IntermediateParser("Default Title");
+
+ $GLOBALS['_phpDocumentor_install_dir'] = $configdir;
+ $this->parseIni();
+
+ // These redundant-looking lines seem to actually make a difference.
+ // See: http://phing.info/trac/ticket/150
+ $_phpDocumentor_phpfile_exts = $GLOBALS['_phpDocumentor_phpfile_exts'];
+ $_phpDocumentor_cvsphpfile_exts = $GLOBALS['_phpDocumentor_cvsphpfile_exts'];
+
+ if (tokenizer_ext) {
+ $this->parse = new phpDocumentorTParser();
+ } else {
+ $this->parse = new Parser();
+ }
+
+ $this->setMemoryLimit();
+
+ include_once 'phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php';
+
+ // Inject our own error tracker to PhpDocumentor
+ $GLOBALS['phpDocumentor_errors'] = new PhingPhpDocumentorErrorTracker;
+ $GLOBALS['phpDocumentor_errors']->setTask($task);
+
+ }
+
+ /**
+ * Set whether to generate sourcecode for each file parsed.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param bool $b
+ */
+ public function setGenerateSourcecode($b) {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['sourcecode'] = (boolean) $b;
+ }
+
+ /**
+ * Set an array of README/INSTALL/CHANGELOG file paths.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param array $files Absolute paths to files.
+ */
+ public function setRicFiles($files) {
+ global $_phpDocumentor_RIC_files;
+ $_phpDocumentor_RIC_files = $files;
+ }
+
+ /**
+ * Set comma-separated list of tags to ignore.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param string $tags
+ */
+ public function setIgnoreTags($tags) {
+ global $_phpDocumentor_setting;
+ $ignoretags = explode(',', $tags);
+ $ignoretags = array_map('trim', $ignoretags);
+ $tags = array();
+ foreach($ignoretags as $tag) {
+ if (!in_array($tag,array('@global', '@access', '@package', '@ignore', '@name', '@param', '@return', '@staticvar', '@var')))
+ $tags[] = $tag;
+ }
+ $_phpDocumentor_setting['ignoretags'] = $tags;
+ }
+
+ /**
+ * Set whether to parse dirs as PEAR repos.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param bool $b
+ */
+ public function setPear($b) {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['pear'] = (boolean) $b;
+ }
+
+ /**
+ * Set fullpath to directory to look in for examples.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param string $dir
+ */
+ public function setExamplesDir($dir) {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['examplesdir'] = $dir;
+ }
+
+ /**
+ * Sets the default package name.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param string $name
+ */
+ public function setDefaultPackageName($name) {
+ $GLOBALS['phpDocumentor_DefaultPackageName'] = trim($name);
+ }
+
+ /**
+ * Sets the default category name.
+ *
+ * This method exists as a hack because there is no API exposed for this in PhpDocumentor.
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ * @param string $name
+ */
+ public function setDefaultCategoryName($name) {
+ $GLOBALS['phpDocumentor_DefaultCategoryName'] = trim($name);
+ }
+
+ /**
+ * Enables quiet mode.
+ *
+ * This method exists as a hack because the API exposed for this method in PhpDocumentor
+ * doesn't work correctly.
+ *
+ * Note that because we are setting a "private" GLOBAL(!!) config var with this value, this
+ * is subject to break if PhpDocumentor internals changes.
+ *
+ */
+ public function setQuietMode() {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['quiet'] = true;
+ parent::setQuietMode();
+ }
+
+ /**
+ * Control whether or not warnings will be shown for undocumented elements.
+ * Useful for identifying classes and methods that haven't yet been
+ * documented.
+ *
+ * @param bool $bEnable
+ */
+ public function setUndocumentedelements($bEnable) {
+ $this->render->setUndocumentedElementWarningsMode($bEnable);
+ }
+
+ /**
+ * custom tags, will be recognized and put in tags[] instead of
+ * unknowntags[]
+ *
+ * This method exists as a hack because the API exposed for this method in
+ * PhpDocumentor doesn't work correctly.
+ *
+ * Note that because we are setting a "private" GLOBAL(!!) config var with
+ * this value, this is subject to break if PhpDocumentor internals changes.
+ *
+ * @param string $sCustomtags
+ */
+ public function setCustomtags($sCustomtags) {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['customtags'] = $sCustomtags;
+ }
+
+ /**
+ * Files to ignore
+ *
+ * @param string $sIgnore
+ */
+ public function setIgnore($sIgnore) {
+ global $_phpDocumentor_setting;
+ $_phpDocumentor_setting['ignore'] = $sIgnore;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentor2Task.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentor2Task.php
new file mode 100755
index 00000000..70fcc9e2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentor2Task.php
@@ -0,0 +1,224 @@
+<?php
+/*
+ * $Id: eaa494390770adc752097a412d63fb863482fd5d $
+ *
+ * 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/FileOutputStream.php';
+
+/**
+ * PhpDocumentor2 Task (http://www.phpdoc.org)
+ * Based on the DocBlox Task
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: eaa494390770adc752097a412d63fb863482fd5d $
+ * @since 2.4.10
+ * @package phing.tasks.ext.phpdoc
+ */
+class PhpDocumentor2Task extends Task
+{
+ /**
+ * List of filesets
+ * @var FileSet[]
+ */
+ private $filesets = array();
+
+ /**
+ * Destination/target directory
+ * @var PhingFile
+ */
+ private $destDir = null;
+
+ /**
+ * name of the template to use
+ * @var string
+ */
+ private $template = "responsive";
+
+ /**
+ * Title of the project
+ * @var string
+ */
+ private $title = "";
+
+ /**
+ * Force phpDocumentor to be quiet
+ * @var boolean
+ */
+ private $quiet = true;
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ *
+ * @return FileSet
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Sets destination/target directory
+ * @param PhingFile $destDir
+ */
+ public function setDestDir(PhingFile $destDir)
+ {
+ $this->destDir = $destDir;
+ }
+
+ /**
+ * Convenience setter (@see setDestDir)
+ * @param PhingFile $output
+ */
+ public function setOutput(PhingFile $output)
+ {
+ $this->destDir = $output;
+ }
+
+ /**
+ * Sets the template to use
+ * @param strings $template
+ */
+ public function setTemplate($template)
+ {
+ $this->template = (string) $template;
+ }
+
+ /**
+ * Sets the title of the project
+ * @param strings $title
+ */
+ public function setTitle($title)
+ {
+ $this->title = (string) $title;
+ }
+
+ /**
+ * Forces phpDocumentor to be quiet
+ * @param boolean $quiet
+ */
+ public function setQuiet($quiet)
+ {
+ $this->quiet = (boolean) $quiet;
+ }
+
+ /**
+ * Finds and initializes the phpDocumentor installation
+ */
+ private function initializePhpDocumentor()
+ {
+ $phpDocumentorPath = null;
+
+ foreach (explode(PATH_SEPARATOR, get_include_path()) as $path) {
+ $testPhpDocumentorPath = $path . DIRECTORY_SEPARATOR . 'phpDocumentor' . DIRECTORY_SEPARATOR . 'src';
+
+ if (file_exists($testPhpDocumentorPath)) {
+ $phpDocumentorPath = $testPhpDocumentorPath;
+ }
+ }
+
+ if (empty($phpDocumentorPath)) {
+ throw new BuildException("Please make sure PhpDocumentor 2 is installed and on the include_path.", $this->getLocation());
+ }
+
+ set_include_path($phpDocumentorPath . PATH_SEPARATOR . get_include_path());
+
+ require_once $phpDocumentorPath . '/phpDocumentor/Bootstrap.php';
+
+ $bootstrap = phpDocumentor_Bootstrap::createInstance();
+
+ $autoloader = $bootstrap->registerAutoloader();
+
+ if ($this->quiet) {
+ phpDocumentor_Core_Abstract::config()->logging->level = 'quiet';
+ } else {
+ phpDocumentor_Core_Abstract::config()->logging->level = 'debug';
+ }
+
+ $bootstrap->registerPlugins($autoloader);
+ }
+
+ /**
+ * Build a list of files (from the fileset elements)
+ * and call the phpDocumentor parser
+ *
+ * @return string
+ */
+ private function parseFiles()
+ {
+ $parser = new phpDocumentor_Parser();
+
+ //Only initialize the dispatcher when not already done
+ if (is_null(phpDocumentor_Parser_Abstract::$event_dispatcher)) {
+ phpDocumentor_Parser_Abstract::$event_dispatcher = new sfEventDispatcher();
+ }
+ $parser->setTitle($this->title);
+
+ $paths = array();
+
+ // filesets
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $dir = $fs->getDir($this->project);
+ $srcFiles = $ds->getIncludedFiles();
+
+ foreach ($srcFiles as $file) {
+ $paths[] = $dir . FileSystem::getFileSystem()->getSeparator() . $file;
+ }
+ }
+
+ $this->log("Will parse " . count($paths) . " file(s)", Project::MSG_VERBOSE);
+
+ $files = new phpDocumentor_Parser_Files();
+ $files->addFiles($paths);
+
+ $parser->setPath($files->getProjectRoot());
+
+ return $parser->parseFiles($files);
+ }
+
+ /**
+ * Task entry point
+ * @see Task::main()
+ */
+ public function main()
+ {
+ if (empty($this->destDir)) {
+ throw new BuildException("You must supply the 'destdir' attribute", $this->getLocation());
+ }
+
+ if (empty($this->filesets)) {
+ throw new BuildException("You have not specified any files to include (<fileset>)", $this->getLocation());
+ }
+
+ $this->initializePhpDocumentor();
+
+ $xml = $this->parseFiles();
+
+ $this->log("Transforming...", Project::MSG_VERBOSE);
+
+ $transformer = new phpDocumentor_Transformer();
+ $transformer->setTemplatesPath(phpDocumentor_Core_Abstract::config()->paths->templates);
+ $transformer->setTemplates($this->template);
+ $transformer->setSource($xml);
+ $transformer->setTarget($this->destDir->getAbsolutePath());
+ $transformer->execute();
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorExternalTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorExternalTask.php
new file mode 100755
index 00000000..fb2a0b2b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorExternalTask.php
@@ -0,0 +1,265 @@
+<?php
+
+/**
+ * $Id: 6a6c740651bb91c9854fcdf0cb1d7e768b84f805 $
+ *
+ * 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/phpdoc/PhpDocumentorTask.php';
+
+/**
+ * Task to run phpDocumentor with an external process
+ *
+ * This classes uses the commandline phpdoc script to build documentation.
+ * Use this task instead of the PhpDocumentorTask when you've a clash with the
+ * Smarty libraries.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Markus Fischer <markus@fischer.name>
+ * @version $Id: 6a6c740651bb91c9854fcdf0cb1d7e768b84f805 $
+ * @package phing.tasks.ext.phpdoc
+ */
+class PhpDocumentorExternalTask extends PhpDocumentorTask
+{
+ /**
+ * The path to the executable for phpDocumentor
+ */
+ protected $programPath = 'phpdoc';
+
+ protected $sourcepath = NULL;
+
+ /**
+ * @var bool ignore symlinks to other files or directories
+ */
+ protected $ignoresymlinks = false;
+
+ /**
+ * Sets the path to the phpDocumentor executable
+ */
+ public function setProgramPath($programPath)
+ {
+ $this->programPath = $programPath;
+ }
+
+ /**
+ * Returns the path to the phpDocumentor executable
+ */
+ public function getProgramPath()
+ {
+ return $this->programPath;
+ }
+
+ /**
+ * Set the source path. A directory or a comma separate list of directories.
+ */
+ public function setSourcepath($sourcepath)
+ {
+ $this->sourcepath = $sourcepath;
+ }
+
+ /**
+ * Ignore symlinks to other files or directories.
+ *
+ * @param bool $bSet
+ */
+ public function setIgnoresymlinks($bSet) {
+ $this->ignoresymlinks = $bSet;
+ }
+
+ /**
+ * Main entrypoint of the task
+ */
+ public function main()
+ {
+ $this->validate();
+ $arguments = join(' ', $this->constructArguments());
+
+ $this->log("Running phpDocumentor...");
+
+ exec($this->programPath . " " . $arguments, $output, $return);
+
+ if ($return != 0)
+ {
+ throw new BuildException("Could not execute phpDocumentor: " . implode(' ', $output));
+ }
+
+ foreach($output as $line)
+ {
+ if(strpos($line, 'ERROR') !== false)
+ {
+ $this->log($line, Project::MSG_ERR);
+ continue;
+ }
+
+ $this->log($line, Project::MSG_VERBOSE);
+ }
+ }
+
+ /**
+ * Constructs an argument string for phpDocumentor
+ * @return array
+ */
+ protected function constructArguments()
+ {
+ $aArgs = array();
+ if ($this->title)
+ {
+ $aArgs[] = '--title "' . $this->title . '"';
+ }
+
+ if ($this->destdir)
+ {
+ $aArgs[] = '--target "' . $this->destdir->getAbsolutePath() . '"';
+ }
+
+ if ($this->sourcepath)
+ {
+ $aArgs[] = '--directory "' . $this->sourcepath . '"';
+ }
+
+ if ($this->output)
+ {
+ $aArgs[] = '--output ' . $this->output;
+ }
+
+ if ($this->linksource)
+ {
+ $aArgs[] = '--sourcecode on';
+ }
+
+ if ($this->parseprivate)
+ {
+ $aArgs[] = '--parseprivate on';
+ }
+
+ if ($this->ignore)
+ {
+ $aArgs[] = '--ignore ' . $this->ignore;
+ }
+
+ // append any files in filesets
+ $filesToParse = array();
+ foreach($this->filesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ foreach($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $filesToParse[] = $f->getAbsolutePath();
+ }
+ }
+ if (count($filesToParse) > 0) {
+ $aArgs[] = '--filename "' . join(',', $filesToParse) . '"';
+ }
+
+ // append any files in filesets
+ $ricFiles = array();
+ foreach($this->projDocFilesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ foreach($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $ricFiles[] = $f->getAbsolutePath();
+ }
+ }
+ if (count($ricFiles) > 0) {
+ $aArgs[] = '--readmeinstallchangelog "' .
+ join(',', $ricFiles) . '"';
+ }
+
+ if ($this->javadocDesc) {
+ $aArgs[] = '--javadocdesc on';
+ }
+
+ if ($this->quiet) {
+ $aArgs[] = '--quiet on';
+ }
+
+ if ($this->packages) {
+ $aArgs[] = '--packageoutput "' . $this->packages . '"';
+ }
+
+ if ($this->ignoreTags) {
+ $aArgs[] = '--ignore-tags "' . $this->ignoreTags . '"';
+ }
+
+ if ($this->defaultCategoryName) {
+ $aArgs[] = '--defaultcategoryname "' . $this->defaultCategoryName .
+ '"';
+ }
+
+ if ($this->examplesDir) {
+ $aArgs[] = '--examplesdir "' . $this->examplesDir->getAbsolutePath()
+ . '"';
+ }
+
+ if ($this->templateBase) {
+ $aArgs[] = '--templatebase "' . $this->templateBase->getAbsolutePath()
+ . '"';
+ }
+
+ if ($this->pear) {
+ $aArgs[] = '--pear on';
+ }
+
+ if ($this->undocumentedelements) {
+ $aArgs[] = '--undocumentedelements on';
+ }
+
+ if ($this->customtags) {
+ $aArgs[] = '--customtags "' . $this->customtags . '"';
+ }
+
+ if ($this->ignoresymlinks) {
+ $aArgs[] = '--ignoresymlinks on';
+ }
+
+ return $aArgs;
+ }
+
+ /**
+ * Override PhpDocumentorTask::init() because they're specific to the phpdoc
+ * API which we don't use.
+ */
+ public function init() {
+ }
+
+ /**
+ * Validates that necessary minimum options have been set. Based on
+ * PhpDocumentorTask::validate().
+ */
+ protected function validate() {
+ if (!$this->destdir) {
+ throw new BuildException("You must specify a destdir for phpdoc.",
+ $this->getLocation());
+ }
+ if (!$this->output) {
+ throw new BuildException("You must specify an output format for " .
+ "phpdoc (e.g. HTML:frames:default).", $this->getLocation());
+ }
+ if (empty($this->filesets) && !$this->sourcepath) {
+ throw new BuildException("You have not specified any files to " .
+ "include (<fileset> or sourcepath attribute) for phpdoc.",
+ $this->getLocation());
+ }
+ if ($this->configdir) {
+ $this->log('Ignoring unsupported configdir-Attribute',
+ Project::MSG_VERBOSE);
+ }
+ }
+};
+
+
+
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 100755
index 00000000..e4ae363a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorTask.php
@@ -0,0 +1,480 @@
+<?php
+
+/**
+ * $Id: 23a04ddae9cad46198e15081a0fb44354135b1c8 $
+ *
+ * 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 Hans Lellelid <hans@xmpl.org>
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 23a04ddae9cad46198e15081a0fb44354135b1c8 $
+ * @package phing.tasks.ext.phpdoc
+ */
+class PhpDocumentorTask extends Task
+{
+
+ /**
+ * @var string Title for browser window / package index.
+ */
+ protected $title;
+
+ /**
+ * @var PhingFile The target directory for output files.
+ */
+ protected $destdir;
+
+ /**
+ * @var array FileSet[] Filesets for files to parse.
+ */
+ protected $filesets = array();
+
+ /**
+ * @var array FileSet[] Project documentation (README/INSTALL/CHANGELOG) files.
+ */
+ protected $projDocFilesets = array();
+
+ /**
+ * @var string Package output format.
+ */
+ protected $output;
+
+ /**
+ * @var boolean Whether to generate sourcecode for each file parsed.
+ */
+ protected $linksource = false;
+
+ /**
+ * @var boolean Whether to parse private members.
+ */
+ protected $parsePrivate = false;
+
+ /**
+ * @var boolean Whether to use javadoc descriptions (more primitive).
+ */
+ protected $javadocDesc = false;
+
+ /**
+ * @var PhingFile Base directory for locating template files.
+ */
+ protected $templateBase;
+
+ /**
+ * @var boolean Wheter to suppress output.
+ */
+ protected $quiet = false;
+
+ /**
+ * @var string Comma-separated list of packages to output.
+ */
+ protected $packages;
+
+ /**
+ * @var string Comma-separated list of tags to ignore.
+ */
+ protected $ignoreTags;
+
+ /**
+ * @var string Default package name.
+ */
+ protected $defaultPackageName;
+
+ /**
+ * @var string Default category name.
+ */
+ protected $defaultCategoryName;
+
+ /**
+ * @var PhingFile Directory in which to look for examples.
+ */
+ protected $examplesDir;
+
+ /**
+ * @var PhingFile Directory in which to look for configuration files.
+ */
+ protected $configDir;
+
+ /**
+ * @var boolean Whether to parse as a PEAR repository.
+ */
+ protected $pear = false;
+
+ /**
+ * @var boolean Control whether or not warnings will be shown for
+ * undocumented elements. Useful for identifying classes and
+ * methods that haven't yet been documented.
+ */
+ protected $undocumentedelements = false;
+
+ /**
+ * @var string custom tags, will be recognized and put in tags[] instead of
+ * unknowntags[].
+ */
+ protected $customtags = '';
+
+ /**
+ * @var string files to ignore
+ */
+ protected $ignore = '';
+
+ /**
+ * Set the title for the generated documentation
+ */
+ public function setTitle($title) {
+ $this->title = $title;
+ }
+
+ /**
+ * Set the destination directory for the generated documentation
+ */
+ public function setDestdir(PhingFile $destdir) {
+ $this->destdir = $destdir;
+ }
+
+ /**
+ * Alias for {@link setDestdir()}.
+ * @see setDestdir()
+ */
+ public function setTarget(PhingFile $destdir) {
+ $this->setDestdir($destdir);
+ }
+
+ /**
+ * Set the output format (e.g. HTML:Smarty:PHP).
+ * @param string $output
+ */
+ public function setOutput($output) {
+ $this->output = $output;
+ }
+
+ /**
+ * Set whether to generate sourcecode for each file parsed
+ * @param boolean
+ */
+ public function setSourcecode($b) {
+ $this->setLinksource($b);
+ }
+
+ /**
+ * Set whether to generate sourcecode for each file parsed
+ * @param boolean
+ */
+ public function setLinksource($b) {
+ $this->linksource = $b;
+ }
+
+ /**
+ * Set whether to suppress output.
+ * @param boolean $b
+ */
+ public function setQuiet($b) {
+ $this->quiet = $b;
+ }
+
+ /**
+ * Should private members/classes be documented
+ * @param boolean
+ */
+ public function setParseprivate($parseprivate) {
+ $this->parsePrivate = $parseprivate;
+ }
+
+ /**
+ * Whether to use javadoc descriptions (more primitive).
+ * @param boolean
+ */
+ public function setJavadocdesc($javadoc) {
+ $this->javadocDesc = $javadoc;
+ }
+
+ /**
+ * Set (comma-separated) list of packages to output.
+ *
+ * @param string $packages
+ */
+ public function setPackageoutput($packages) {
+ $this->packages = $packages;
+ }
+
+ /**
+ * Set (comma-separated) list of tags to ignore.
+ *
+ * @param string $tags
+ */
+ public function setIgnoretags($tags) {
+ $this->ignoreTags = $tags;
+ }
+
+ /**
+ * Set a directory to search for examples in.
+ * @param PhingFile $d
+ */
+ public function setExamplesdir(PhingFile $d) {
+ $this->examplesDir = $d;
+ }
+
+ /**
+ * Set a directory to search for configuration files in.
+ * @param PhingFile $d
+ */
+ public function setConfigdir(PhingFile $d) {
+ $this->configDir = $d;
+ }
+
+ /**
+ * Sets the default package name.
+ * @param string $name
+ */
+ public function setDefaultpackagename($name) {
+ $this->defaultPackageName = $name;
+ }
+
+ /**
+ * Sets the default category name.
+ * @param string $name
+ */
+ public function setDefaultcategoryname($name) {
+ $this->defaultCategoryName = $name;
+ }
+
+ /**
+ * Set whether to parse as PEAR repository.
+ * @param boolean $b
+ */
+ public function setPear($b) {
+ $this->pear = $b;
+ }
+
+ /**
+ * Creates a FileSet.
+ * @return FileSet
+ */
+ public function createFileset() {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Creates a readme/install/changelog fileset.
+ * @return FileSet
+ */
+ public function createProjdocfileset() {
+ $num = array_push($this->projDocFilesets, new FileSet());
+ return $this->projDocFilesets[$num-1];
+ }
+
+ /**
+ * Control whether or not warnings will be shown for undocumented elements.
+ * Useful for identifying classes and methods that haven't yet been
+ * documented.
+ * @param boolean $b
+ */
+ public function setUndocumentedelements($b) {
+ $this->undocumentedelements = $b;
+ }
+
+ /**
+ * custom tags, will be recognized and put in tags[] instead of
+ * unknowntags[].
+ *
+ * @param string $sCustomtags
+ */
+ public function setCustomtags($sCustomtags) {
+ $this->customtags = $sCustomtags;
+ }
+
+ /**
+ * Set base location of all templates for this parse.
+ *
+ * @param PhingFile $destdir
+ */
+ public function setTemplateBase(PhingFile $oTemplateBase) {
+ $this->templateBase = $oTemplateBase;
+ }
+
+ /**
+ * Set files to ignore
+ * @param string $sIgnore
+ */
+ public function setIgnore($sIgnore) {
+ $this->ignore = $sIgnore;
+ }
+
+ /**
+ * Searches include_path for PhpDocumentor install and adjusts include_path appropriately.
+ * @throws BuildException - if unable to find PhpDocumentor on include_path
+ */
+ protected function findPhpDocumentorInstall()
+ {
+ $found = null;
+ foreach(explode(PATH_SEPARATOR, get_include_path()) as $path) {
+ $testpath = $path . DIRECTORY_SEPARATOR . 'PhpDocumentor';
+ if (file_exists($testpath)) {
+ $found = $testpath;
+ break;
+ }
+ }
+ if (!$found) {
+ throw new BuildException("PhpDocumentor task depends on PhpDocumentor being installed and on include_path.", $this->getLocation());
+ }
+ // otherwise, adjust the include_path to path to include the PhpDocumentor directory ...
+ set_include_path(get_include_path() . PATH_SEPARATOR . $found);
+ include_once ("phpDocumentor/Setup.inc.php");
+ if (!class_exists('phpDocumentor_setup')) {
+ throw new BuildException("Error including PhpDocumentor setup class file.");
+ }
+ }
+
+ /**
+ * Main entrypoint of the task
+ * Loads the necessary environment for running PhpDoc, then runs PhpDoc
+ *
+ * @throws BuildException - if the phpdoc classes can't be loaded.
+ */
+ function main()
+ {
+ $this->findPhpDocumentorInstall();
+ include_once 'phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php';
+
+ $this->validate();
+ $configdir = $this->configDir ? $this->configDir->getAbsolutePath() : null;
+ $phpdoc = new PhingPhpDocumentorSetup($configdir, $this);
+ $this->setPhpDocumentorOptions($phpdoc);
+ //$phpdoc->readCommandLineSettings();
+ $phpdoc->setupConverters($this->output);
+ $phpdoc->createDocs();
+ }
+
+ /**
+ * Validates that necessary minimum options have been set.
+ * @throws BuildException if validation doesn't pass
+ */
+ protected function validate()
+ {
+ if (!$this->destdir) {
+ throw new BuildException("You must specify a destdir for phpdoc.", $this->getLocation());
+ }
+ if (!$this->output) {
+ throw new BuildException("You must specify an output format for phpdoc (e.g. HTML:frames:default).", $this->getLocation());
+ }
+ if (empty($this->filesets)) {
+ throw new BuildException("You have not specified any files to include (<fileset>) for phpdoc.", $this->getLocation());
+ }
+ }
+
+ /**
+ * Sets the options on the passed-in phpdoc setup object.
+ * @param PhingPhpDocumentorSetup $phpdoc
+ */
+ protected function setPhpDocumentorOptions(PhingPhpDocumentorSetup $phpdoc)
+ {
+
+ // Title MUST be set first ... (because it re-initializes the internal state of the PhpDocu renderer)
+ if ($this->title) {
+ $phpdoc->setTitle($this->title);
+ }
+
+ if ($this->parsePrivate) {
+ $phpdoc->setParsePrivate();
+ }
+
+ if ($this->javadocDesc) {
+ $phpdoc->setJavadocDesc();
+ }
+
+ if ($this->quiet) {
+ $phpdoc->setQuietMode();
+ }
+
+ if ($this->destdir) {
+ $phpdoc->setTargetDir($this->destdir->getAbsolutePath());
+ }
+
+ if ($this->packages) {
+ $phpdoc->setPackageOutput($this->packages);
+ }
+
+ if ($this->templateBase) {
+ $phpdoc->setTemplateBase($this->templateBase->getAbsolutePath());
+ }
+
+ if ($this->linksource) {
+ $phpdoc->setGenerateSourcecode($this->linksource);
+ }
+
+ if ($this->examplesDir) {
+ $phpdoc->setExamplesDir($this->examplesDir->getAbsolutePath());
+ }
+
+ if ($this->ignoreTags) {
+ $phpdoc->setIgnoreTags($this->ignoreTags);
+ }
+
+ if ($this->defaultPackageName) {
+ $phpdoc->setDefaultPackageName($this->defaultPackageName);
+ }
+
+ if ($this->defaultCategoryName) {
+ $phpdoc->setDefaultCategoryName($this->defaultCategoryName);
+ }
+
+ if ($this->pear) {
+ $phpdoc->setPear($this->pear);
+ }
+
+ if ($this->ignore) {
+ $phpdoc->setIgnore($this->ignore);
+ }
+
+ // append any files in filesets
+ $filesToParse = array();
+ foreach($this->filesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ foreach($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $filesToParse[] = $f->getAbsolutePath();
+ }
+ }
+ //print_r(implode(",", $filesToParse));
+ $phpdoc->setFilesToParse(implode(",", $filesToParse));
+
+
+ // append any files in filesets
+ $ricFiles = array();
+ foreach($this->projDocFilesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ foreach($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $ricFiles[] = $f->getName();
+ }
+ }
+ $phpdoc->setRicFiles($ricFiles);
+
+ if ($this->undocumentedelements) {
+ $phpdoc->setUndocumentedelements($this->undocumentedelements);
+ }
+
+ if ($this->customtags) {
+ $phpdoc->setCustomtags($this->customtags);
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDFormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDFormatterElement.php
new file mode 100644
index 00000000..c327e331
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDFormatterElement.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * $Id: 69fc758899446b96312ac12f26b461969eb41b6e $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * A wrapper for the implementations of PHPMDResultFormatter.
+ *
+ * @package phing.tasks.ext.phpmd
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 69fc758899446b96312ac12f26b461969eb41b6e $
+ * @since 2.4.1
+ */
+class PHPMDFormatterElement
+{
+ /**
+ * @var PHPMDResultFormatter
+ */
+ protected $formatter = null;
+
+ /**
+ * The type of the formatter.
+ *
+ * @var string
+ */
+ protected $type = "";
+
+ /**
+ * Whether to use file (or write output to phing log).
+ *
+ * @var boolean
+ */
+ protected $useFile = true;
+
+ /**
+ * Output file for formatter.
+ *
+ * @var PhingFile
+ */
+ protected $outfile = null;
+
+ /**
+ * Sets the formatter type.
+ *
+ * @param string $type Type of the formatter
+ *
+ * @return void
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+
+ switch ($this->type) {
+ case 'xml':
+ include_once 'PHP/PMD/Renderer/XMLRenderer.php';
+ break;
+
+ case 'html':
+ include_once 'PHP/PMD/Renderer/HTMLRenderer.php';
+ break;
+
+ case 'text':
+ include_once 'PHP/PMD/Renderer/TextRenderer.php';
+ break;
+
+ default:
+ throw new BuildException("Formatter '" . $this->type . "' not implemented");
+ }
+ }
+
+ /**
+ * Get the formatter type
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set whether to write formatter results to file or not.
+ *
+ * @param boolean $useFile True or false.
+ *
+ * @return void
+ */
+ public function setUseFile($useFile)
+ {
+ $this->useFile = (boolean) $useFile;
+ }
+
+ /**
+ * Return whether to write formatter results to file or not.
+ *
+ * @return boolean
+ */
+ public function getUseFile()
+ {
+ return $this->useFile;
+ }
+
+ /**
+ * Sets the output file for the formatter results.
+ *
+ * @param PhingFile $outfile The output file
+ *
+ * @return void
+ */
+ public function setOutfile(PhingFile $outfile)
+ {
+ $this->outfile = $outfile;
+ }
+
+ /**
+ * Get the output file.
+ *
+ * @return PhingFile
+ */
+ public function getOutfile()
+ {
+ return $this->outfile;
+ }
+
+ /**
+ * Creates a report renderer instance based on the formatter type.
+ *
+ * @return PHP_PMD_AbstractRenderer
+ * @throws BuildException When the specified renderer does not exist.
+ */
+ public function getRenderer()
+ {
+ switch ($this->type) {
+ case 'xml':
+ $renderer = new PHP_PMD_Renderer_XMLRenderer();
+ break;
+
+ case 'html':
+ $renderer = new PHP_PMD_Renderer_HTMLRenderer();
+ break;
+
+ case 'text':
+ $renderer = new PHP_PMD_Renderer_TextRenderer();
+ break;
+
+ default:
+ throw new BuildException("PHP_MD renderer '" . $this->type . "' not implemented");
+ }
+
+ // Create a report stream
+ if ($this->getUseFile() === false || $this->getOutfile() === null) {
+ $stream = STDOUT;
+ } else {
+ $stream = fopen($this->getOutfile()->getAbsoluteFile(), 'wb');
+ }
+
+ require_once 'PHP/PMD/Writer/Stream.php';
+
+ $renderer->setWriter(new PHP_PMD_Writer_Stream($stream));
+
+ return $renderer;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDTask.php
new file mode 100644
index 00000000..1c4d34bf
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDTask.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * $Id: 35668c2c6fbf1ca87fab21c26fd55ef630458fc7 $
+ *
+ * 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/phpmd/PHPMDFormatterElement.php';
+
+/**
+ * Runs PHP Mess Detector. Checking PHP files for several potential problems
+ * based on rulesets.
+ *
+ * @package phing.tasks.ext.phpmd
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 35668c2c6fbf1ca87fab21c26fd55ef630458fc7 $
+ * @since 2.4.1
+ */
+class PHPMDTask extends Task
+{
+ /**
+ * A php source code filename or directory
+ *
+ * @var PhingFile
+ */
+ protected $file = null;
+
+ /**
+ * All fileset objects assigned to this task
+ *
+ * @var array<FileSet>
+ */
+ protected $filesets = array();
+
+ /**
+ * The rule-set filenames or identifier.
+ *
+ * @var string
+ */
+ protected $rulesets = 'codesize,unusedcode';
+
+ /**
+ * The minimum priority for rules to load.
+ *
+ * @var integer
+ */
+ protected $minimumPriority = 0;
+
+ /**
+ * List of valid file extensions for analyzed files.
+ *
+ * @var array
+ */
+ protected $allowedFileExtensions = array('php');
+
+ /**
+ * List of exclude directory patterns.
+ *
+ * @var array
+ */
+ protected $ignorePatterns = array('.git', '.svn', 'CVS', '.bzr', '.hg');
+
+ /**
+ * The format for the report
+ *
+ * @var string
+ */
+ protected $format = 'text';
+
+ /**
+ * Formatter elements.
+ *
+ * @var array<PHPMDFormatterElement>
+ */
+ protected $formatters = array();
+
+ /**
+ * Set the input source file or directory.
+ *
+ * @param PhingFile $file The input source file or directory.
+ *
+ * @return void
+ */
+ public function setFile(PhingFile $file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ *
+ * @return FileSet The created fileset object
+ */
+ public function createFileSet()
+ {
+ $num = array_push($this->filesets, new FileSet());
+ return $this->filesets[$num-1];
+ }
+
+ /**
+ * Sets the minimum rule priority.
+ *
+ * @param integer $minimumPriority Minimum rule priority.
+ *
+ * @return void
+ */
+ public function setMinimumPriority($minimumPriority)
+ {
+ $this->minimumPriority = $minimumPriority;
+ }
+
+ /**
+ * Sets the rule-sets.
+ *
+ * @param string $ruleSetFileNames Comma-separated string of rule-set filenames
+ * or identifier.
+ *
+ * @return void
+ */
+ public function setRulesets($ruleSetFileNames)
+ {
+ $this->rulesets = $ruleSetFileNames;
+ }
+
+ /**
+ * Sets a list of filename extensions for valid php source code files.
+ *
+ * @param string $fileExtensions List of valid file extensions without leading dot.
+ *
+ * @return void
+ */
+ public function setAllowedFileExtensions($fileExtensions)
+ {
+ $this->allowedFileExtensions = array();
+
+ $token = ' ,;';
+ $ext = strtok($fileExtensions, $token);
+
+ while ($ext !== false) {
+ $this->allowedFileExtensions[] = $ext;
+ $ext = strtok($token);
+ }
+ }
+
+ /**
+ * Sets a list of ignore patterns that is used to exclude directories from
+ * the source analysis.
+ *
+ * @param string $ignorePatterns List of ignore patterns.
+ *
+ * @return void
+ */
+ public function setIgnorePatterns($ignorePatterns)
+ {
+ $this->ignorePatterns = array();
+
+ $token = ' ,;';
+ $pattern = strtok($ignorePatterns, $token);
+
+ while ($pattern !== false) {
+ $this->ignorePatterns[] = $pattern;
+ $pattern = strtok($token);
+ }
+ }
+
+ /**
+ * Create object for nested formatter element.
+ *
+ * @return PHPMDFormatterElement
+ */
+ public function createFormatter()
+ {
+ $num = array_push($this->formatters, new PHPMDFormatterElement());
+ return $this->formatters[$num-1];
+ }
+
+ /**
+ * Executes PHPMD against PhingFile or a FileSet
+ *
+ * @throws BuildException - if the phpmd classes can't be loaded.
+ * @return void
+ */
+ public function main()
+ {
+ /**
+ * Find PHPMD
+ */
+ @include_once 'PHP/PMD.php';
+
+ if (! class_exists('PHP_PMD')) {
+ throw new BuildException(
+ 'PHPMDTask depends on PHPMD being installed and on include_path.',
+ $this->getLocation()
+ );
+ }
+
+ require_once 'PHP/PMD/AbstractRule.php';
+
+ if (!$this->minimumPriority) {
+ $this->minimumPriority = PHP_PMD_AbstractRule::LOWEST_PRIORITY;
+ }
+
+ if (!isset($this->file) and count($this->filesets) == 0) {
+ throw new BuildException("Missing either a nested fileset or attribute 'file' set");
+ }
+
+ if (count($this->formatters) == 0) {
+ // turn legacy format attribute into formatter
+ $fmt = new PHPMDFormatterElement();
+ $fmt->setType($this->format);
+ $fmt->setUseFile(false);
+ $this->formatters[] = $fmt;
+ }
+
+ $reportRenderers = array();
+
+ foreach ($this->formatters as $fe) {
+ if ($fe->getType() == '') {
+ throw new BuildException("Formatter missing required 'type' attribute.");
+ }
+ if ($fe->getUsefile() && $fe->getOutfile() === null) {
+ throw new BuildException("Formatter requires 'outfile' attribute when 'useFile' is true.");
+ }
+
+ $reportRenderers[] = $fe->getRenderer();
+ }
+
+ // Create a rule set factory
+ $ruleSetFactory = new PHP_PMD_RuleSetFactory();
+ $ruleSetFactory->setMinimumPriority($this->minimumPriority);
+
+ $phpmd = new PHP_PMD();
+
+ $phpmd->setFileExtensions($this->allowedFileExtensions);
+ $phpmd->setIgnorePattern($this->ignorePatterns);
+
+ $filesToParse = array();
+
+ if ($this->file instanceof PhingFile) {
+ $filesToParse[] = $this->file->getPath();
+ } else {
+ // append any files in filesets
+ foreach ($this->filesets as $fs) {
+ $files = $fs->getDirectoryScanner($this->project)->getIncludedFiles();
+ foreach ($files as $filename) {
+ $f = new PhingFile($fs->getDir($this->project), $filename);
+ $filesToParse[] = $f->getAbsolutePath();
+ }
+ }
+ }
+
+ if (count($filesToParse) > 0) {
+ $inputPath = implode(',', $filesToParse);
+
+ $this->log('Processing files...');
+
+ $phpmd->processFiles(
+ $inputPath,
+ $this->rulesets,
+ $reportRenderers,
+ $ruleSetFactory
+ );
+
+ $this->log('Finished processing files');
+ } else {
+ $this->log('No files to process');
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/BatchTest.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/BatchTest.php
new file mode 100755
index 00000000..6a6cec24
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/BatchTest.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * $Id: 4067d915614ff7a864c31f19549bcf6a96c0f92d $
+ *
+ * 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/phpunit/PHPUnitUtil.php';
+require_once 'phing/types/FileSet.php';
+
+/**
+ * Scans a list of files given by the fileset attribute, extracts valid test cases
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 4067d915614ff7a864c31f19549bcf6a96c0f92d $
+ * @package phing.tasks.ext.phpunit
+ * @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();
+
+ /** name of the batchtest/suite */
+ protected $name = "Phing Batchtest";
+
+ /**
+ * Create a new batchtest instance
+ *
+ * @param Project the project it depends on.
+ */
+ public function __construct(Project $project)
+ {
+ $this->project = $project;
+ }
+
+ /**
+ * Sets the name of the batchtest/suite
+ */
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Sets the classes to exclude
+ */
+ public function setExclude($exclude)
+ {
+ $this->excludeClasses = explode(" ", $exclude);
+ }
+
+ /**
+ * Sets the classpath
+ */
+ public function setClasspath(Path $classpath)
+ {
+ if ($this->classpath === null)
+ {
+ $this->classpath = $classpath;
+ }
+ else
+ {
+ $this->classpath->append($classpath);
+ }
+ }
+
+ /**
+ * Creates a new Path object
+ */
+ public function createClasspath()
+ {
+ $this->classpath = new Path();
+ return $this->classpath;
+ }
+
+ /**
+ * Returns the classpath
+ */
+ public function getClasspath()
+ {
+ return $this->classpath;
+ }
+
+ /**
+ * Add a new fileset containing the XML results to aggregate
+ *
+ * @param FileSet the new fileset containing XML results.
+ */
+ public function addFileSet(FileSet $fileset)
+ {
+ $this->filesets[] = $fileset;
+ }
+
+ /**
+ * Iterate over all filesets and return the filename of all files.
+ *
+ * @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)
+ {
+ $filenames[] = $ds->getBaseDir() . "/" . $file;
+ }
+ }
+
+ return $filenames;
+ }
+
+ /**
+ * Checks wheter $input is a PHPUnit Test
+ */
+ private function isTestCase($input)
+ {
+ return is_subclass_of($input, 'PHPUnit_Framework_TestCase') || is_subclass_of($input, 'PHPUnit_Framework_TestSuite');
+ }
+
+ /**
+ * Filters an array of classes, removes all classes that are not test cases or test suites,
+ * or classes that are declared abstract
+ */
+ private function filterTests($input)
+ {
+ $reflect = new ReflectionClass($input);
+
+ return $this->isTestCase($input) && (!$reflect->isAbstract());
+ }
+
+ /**
+ * Returns an array of test cases and test suites that are declared
+ * by the files included by the filesets
+ *
+ * @return array an array of tests.
+ */
+ protected function elements()
+ {
+ $filenames = $this->getFilenames();
+
+ $declaredClasses = array();
+
+ foreach ($filenames as $filename)
+ {
+ $definedClasses = PHPUnitUtil::getDefinedClasses($filename, $this->classpath);
+
+ foreach($definedClasses as $definedClass) {
+ $this->project->log("(PHPUnit) Adding $definedClass (from $filename) to tests.", Project::MSG_DEBUG);
+ }
+
+ $declaredClasses = array_merge($declaredClasses, $definedClasses);
+ }
+
+ $elements = array_filter($declaredClasses, array($this, "filterTests"));
+
+ return $elements;
+ }
+
+ /**
+ * Returns a testsuite containing all the tests in this batch
+ *
+ * @deprecated
+ * @return PHPUnit_Framework_TestSuite
+ */
+ public function getTestSuite()
+ {
+ $suite = new PHPUnit_Framework_TestSuite($this->name);
+
+ foreach ($this->elements() as $test)
+ {
+ $testClass = new $test();
+ if (!($testClass instanceof PHPUnit_Framework_TestSuite))
+ {
+ $testClass = new ReflectionClass($test);
+ }
+
+ $suite->addTestSuite($testClass);
+ }
+
+ return $suite;
+ }
+
+ /**
+ * Add the tests in this batchtest to a test suite
+ * @param PHPUnit_Framework_TestSuite $suite
+ */
+ public function addToTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ foreach ($this->elements() as $element) {
+ $testClass = new $element();
+ if (!($testClass instanceof PHPUnit_Framework_TestSuite))
+ {
+ $testClass = new ReflectionClass($element);
+ }
+ $suite->addTestSuite($testClass);
+ }
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/FormatterElement.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/FormatterElement.php
new file mode 100755
index 00000000..c220b79d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/FormatterElement.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * $Id: 296214ebac3a12e51bffed3dcc2c0bb93fb0754e $
+ *
+ * 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/PhingFile.php';
+
+/**
+ * A wrapper for the implementations of PHPUnit2ResultFormatter.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 296214ebac3a12e51bffed3dcc2c0bb93fb0754e $
+ * @package phing.tasks.ext.phpunit
+ * @since 2.1.0
+ */
+class FormatterElement
+{
+ protected $formatter = NULL;
+
+ protected $type = "";
+
+ protected $useFile = true;
+
+ protected $toDir = ".";
+
+ protected $outfile = "";
+
+ protected $parent = NULL;
+
+ /**
+ * Sets parent task
+ * @param Task $parent Calling Task
+ */
+ public function setParent($parent)
+ {
+ $this->parent = $parent;
+ }
+
+ /**
+ * Loads a specific formatter type
+ * @param string $type
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+
+ if ($this->type == "summary")
+ {
+ require_once 'phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php';
+ $this->formatter = new SummaryPHPUnitResultFormatter($this->parent);
+ }
+ else
+ if ($this->type == "clover")
+ {
+ require_once 'phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php';
+ $this->formatter = new CloverPHPUnitResultFormatter($this->parent);
+ }
+ else
+ if ($this->type == "xml")
+ {
+ require_once 'phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php';
+ $this->formatter = new XMLPHPUnitResultFormatter($this->parent);
+ }
+ else
+ if ($this->type == "plain")
+ {
+ require_once 'phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php';
+ $this->formatter = new PlainPHPUnitResultFormatter($this->parent);
+ }
+ else
+ {
+ throw new BuildException("Formatter '" . $this->type . "' not implemented");
+ }
+ }
+
+ /**
+ * Loads a specific formatter class
+ */
+ public function setClassName($className)
+ {
+ $classNameNoDot = Phing::import($className);
+
+ $this->formatter = new $classNameNoDot();
+ }
+
+ /**
+ * Sets whether to store formatting results in a file
+ */
+ public function setUseFile($useFile)
+ {
+ $this->useFile = $useFile;
+ }
+
+ /**
+ * Returns whether to store formatting results in a file
+ */
+ public function getUseFile()
+ {
+ return $this->useFile;
+ }
+
+ /**
+ * Sets output directory
+ * @param string $toDir
+ */
+ public function setToDir($toDir)
+ {
+ $this->toDir = $toDir;
+ }
+
+ /**
+ * Returns output directory
+ * @return string
+ */
+ public function getToDir()
+ {
+ return $this->toDir;
+ }
+
+ /**
+ * Sets output filename
+ * @param string $outfile
+ */
+ public function setOutfile($outfile)
+ {
+ $this->outfile = $outfile;
+ }
+
+ /**
+ * Returns output filename
+ * @return string
+ */
+ public function getOutfile()
+ {
+ if ($this->outfile)
+ {
+ return $this->outfile;
+ }
+ else
+ {
+ return $this->formatter->getPreferredOutfile() . $this->getExtension();
+ }
+ }
+
+ /**
+ * Returns extension
+ * @return string
+ */
+ public function getExtension()
+ {
+ return $this->formatter->getExtension();
+ }
+
+ /**
+ * Returns formatter object
+ * @return PHPUnitResultFormatter
+ */
+ public function getFormatter()
+ {
+ return $this->formatter;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitReportTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitReportTask.php
new file mode 100755
index 00000000..87338da7
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitReportTask.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ * $Id: b88d6fa4ca4717177b562a0475c81d92c161d9b4 $
+ *
+ * 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 PHPUnit 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 <mrook@php.net>
+ * @version $Id: b88d6fa4ca4717177b562a0475c81d92c161d9b4 $
+ * @package phing.tasks.ext.phpunit
+ * @since 2.1.0
+ */
+class PHPUnitReportTask extends Task
+{
+ private $format = "noframes";
+ private $styleDir = "";
+ private $toDir = "";
+
+ /**
+ * Whether to use the sorttable JavaScript library, defaults to false
+ * See {@link http://www.kryogenix.org/code/browser/sorttable/)}
+ *
+ * @var boolean
+ */
+ private $useSortTable = false;
+
+ /** the directory where the results XML can be found */
+ private $inFile = "testsuites.xml";
+
+ /**
+ * Set the filename of the XML results file to use.
+ */
+ public function setInFile(PhingFile $inFile)
+ {
+ $this->inFile = $inFile;
+ }
+
+ /**
+ * Set the format of the generated report. Must be noframes or frames.
+ */
+ public function setFormat($format)
+ {
+ $this->format = $format;
+ }
+
+ /**
+ * Set the directory where the stylesheets are located.
+ */
+ public function setStyleDir($styleDir)
+ {
+ $this->styleDir = $styleDir;
+ }
+
+ /**
+ * Set the directory where the files resulting from the
+ * transformation should be written to.
+ */
+ public function setToDir(PhingFile $toDir)
+ {
+ $this->toDir = $toDir;
+ }
+
+ /**
+ * Sets whether to use the sorttable JavaScript library, defaults to false
+ * See {@link http://www.kryogenix.org/code/browser/sorttable/)}
+ *
+ * @param boolean $useSortTable
+ */
+ public function setUseSortTable($useSortTable)
+ {
+ $this->useSortTable = (boolean) $useSortTable;
+ }
+
+ /**
+ * Returns the path to the XSL stylesheet
+ */
+ protected function getStyleSheet()
+ {
+ $xslname = "phpunit-" . $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;
+ }
+
+ /**
+ * Transforms the DOM document
+ */
+ protected function transform(DOMDocument $document)
+ {
+ if (!$this->toDir->exists())
+ {
+ throw new BuildException("Directory '" . $this->toDir . "' does not exist");
+ }
+
+ $xslfile = $this->getStyleSheet();
+
+ $xsl = new DOMDocument();
+ $xsl->load($xslfile->getAbsolutePath());
+
+ $proc = new XSLTProcessor();
+ if (defined('XSL_SECPREF_WRITE_FILE'))
+ {
+ if (version_compare(PHP_VERSION,'5.4',"<"))
+ {
+ ini_set("xsl.security_prefs", XSL_SECPREF_WRITE_FILE | XSL_SECPREF_CREATE_DIRECTORY);
+ }
+ else
+ {
+ $proc->setSecurityPrefs(XSL_SECPREF_WRITE_FILE | XSL_SECPREF_CREATE_DIRECTORY);
+ }
+ }
+
+ $proc->importStyleSheet($xsl);
+ $proc->setParameter('', 'output.sorttable', $this->useSortTable);
+
+ if ($this->format == "noframes")
+ {
+ $writer = new FileWriter(new PhingFile($this->toDir, "phpunit-noframes.html"));
+ $writer->write($proc->transformToXML($document));
+ $writer->close();
+ }
+ else
+ {
+ ExtendedFileStream::registerStream();
+
+ $toDir = (string) $this->toDir;
+
+ // urlencode() the path if we're on Windows
+ if (FileSystem::getFileSystem()->getSeparator() == '\\') {
+ $toDir = urlencode($toDir);
+ }
+
+ // no output for the framed report
+ // it's all done by extension...
+ $proc->setParameter('', 'output.dir', $toDir);
+ $proc->transformToXML($document);
+
+ ExtendedFileStream::unregisterStream();
+ }
+ }
+
+ /**
+ * Fixes DOM document tree:
+ * - adds package="default" to 'testsuite' elements without
+ * package attribute
+ * - removes outer 'testsuite' container(s)
+ */
+ protected function fixDocument(DOMDocument $document)
+ {
+ $rootElement = $document->firstChild;
+
+ $xp = new DOMXPath($document);
+
+ $nodes = $xp->query("/testsuites/testsuite");
+
+ foreach ($nodes as $node) {
+ $children = $xp->query("./testsuite", $node);
+
+ if ($children->length) {
+ foreach ($children as $child) {
+ if (!$child->hasAttribute('package'))
+ {
+ $child->setAttribute('package', 'default');
+ }
+ $rootElement->appendChild($child);
+ }
+
+ $rootElement->removeChild($node);
+ }
+ }
+ }
+
+ /**
+ * Initialize the task
+ */
+ public function init()
+ {
+ if (!class_exists('XSLTProcessor')) {
+ throw new BuildException("PHPUnitReportTask requires the XSL extension");
+ }
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $testSuitesDoc = new DOMDocument();
+ $testSuitesDoc->load((string) $this->inFile);
+
+ $this->fixDocument($testSuitesDoc);
+
+ $this->transform($testSuitesDoc);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTask.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTask.php
new file mode 100755
index 00000000..5b842b95
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTask.php
@@ -0,0 +1,378 @@
+<?php
+/**
+ * $Id: 4554fdd642b6ef7774cbb89c537ccba90f3ca972 $
+ *
+ * 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 PHPUnit tests.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 4554fdd642b6ef7774cbb89c537ccba90f3ca972 $
+ * @package phing.tasks.ext.phpunit
+ * @see BatchTest
+ * @since 2.1.0
+ */
+class PHPUnitTask extends Task
+{
+ private $batchtests = array();
+ private $formatters = array();
+ private $bootstrap = "";
+ private $haltonerror = false;
+ private $haltonfailure = false;
+ private $haltonincomplete = false;
+ private $haltonskipped = false;
+ private $errorproperty;
+ private $failureproperty;
+ private $incompleteproperty;
+ private $skippedproperty;
+ private $printsummary = false;
+ private $testfailed = false;
+ private $testfailuremessage = "";
+ private $codecoverage = null;
+ private $groups = array();
+ private $excludeGroups = array();
+ private $processIsolation = false;
+ private $usecustomerrorhandler = true;
+
+ /**
+ * Initialize Task.
+ * This method includes any necessary PHPUnit 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.
+ */
+ public function init() {
+ /**
+ * Determine PHPUnit version number
+ */
+ @include_once 'PHPUnit/Runner/Version.php';
+
+ if (!class_exists('PHPUnit_Runner_Version')) {
+ throw new BuildException("PHPUnitTask requires PHPUnit to be installed", $this->getLocation());
+ }
+
+ $version = PHPUnit_Runner_Version::id();
+
+ if (version_compare($version, '3.6.0') < 0)
+ {
+ throw new BuildException("PHPUnitTask requires PHPUnit version >= 3.6.0", $this->getLocation());
+ }
+
+ /**
+ * Other dependencies that should only be loaded when class is actually used.
+ */
+ require_once 'phing/tasks/ext/phpunit/PHPUnitTestRunner.php';
+ require_once 'phing/tasks/ext/phpunit/BatchTest.php';
+ require_once 'phing/tasks/ext/phpunit/FormatterElement.php';
+
+ /**
+ * point PHPUnit_MAIN_METHOD define to non-existing method
+ */
+ if (!defined('PHPUnit_MAIN_METHOD'))
+ {
+ define('PHPUnit_MAIN_METHOD', 'PHPUnitTask::undefined');
+ }
+ }
+
+ /**
+ * Sets the name of a bootstrap file that is run before
+ * executing the tests
+ *
+ * @param string $bootstrap the name of the bootstrap file
+ */
+ public function setBootstrap($bootstrap)
+ {
+ $this->bootstrap = $bootstrap;
+ }
+
+ public function setErrorproperty($value)
+ {
+ $this->errorproperty = $value;
+ }
+
+ public function setFailureproperty($value)
+ {
+ $this->failureproperty = $value;
+ }
+
+ public function setIncompleteproperty($value)
+ {
+ $this->incompleteproperty = $value;
+ }
+
+ public function setSkippedproperty($value)
+ {
+ $this->skippedproperty = $value;
+ }
+
+ public function setHaltonerror($value)
+ {
+ $this->haltonerror = $value;
+ }
+
+ public function setHaltonfailure($value)
+ {
+ $this->haltonfailure = $value;
+ }
+
+ public function getHaltonfailure()
+ {
+ return $this->haltonfailure;
+ }
+
+ public function setHaltonincomplete($value)
+ {
+ $this->haltonincomplete = $value;
+ }
+
+ public function getHaltonincomplete()
+ {
+ return $this->haltonincomplete;
+ }
+
+ public function setHaltonskipped($value)
+ {
+ $this->haltonskipped = $value;
+ }
+
+ public function getHaltonskipped()
+ {
+ return $this->haltonskipped;
+ }
+
+ public function setPrintsummary($printsummary)
+ {
+ $this->printsummary = $printsummary;
+ }
+
+ public function setCodecoverage($codecoverage)
+ {
+ $this->codecoverage = $codecoverage;
+ }
+
+ public function setProcessIsolation($processIsolation)
+ {
+ $this->processIsolation = $processIsolation;
+ }
+
+ public function setUseCustomErrorHandler($usecustomerrorhandler)
+ {
+ $this->usecustomerrorhandler = $usecustomerrorhandler;
+ }
+
+ public function setGroups($groups)
+ {
+ $token = ' ,;';
+ $this->groups = array();
+ $tok = strtok($groups, $token);
+ while ($tok !== false) {
+ $this->groups[] = $tok;
+ $tok = strtok($token);
+ }
+ }
+
+ public function setExcludeGroups($excludeGroups)
+ {
+ $token = ' ,;';
+ $this->excludeGroups = array();
+ $tok = strtok($excludeGroups, $token);
+ while ($tok !== false) {
+ $this->excludeGroups[] = $tok;
+ $tok = strtok($token);
+ }
+ }
+
+ /**
+ * Add a new formatter to all tests of this task.
+ *
+ * @param FormatterElement formatter element
+ */
+ public function addFormatter(FormatterElement $fe)
+ {
+ $fe->setParent($this);
+ $this->formatters[] = $fe;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ public function main()
+ {
+ if ($this->codecoverage && !extension_loaded('xdebug'))
+ {
+ throw new Exception("PHPUnitTask depends on Xdebug being installed to gather code coverage information.");
+ }
+
+ if ($this->printsummary)
+ {
+ $fe = new FormatterElement();
+ $fe->setParent($this);
+ $fe->setType("summary");
+ $fe->setUseFile(false);
+ $this->formatters[] = $fe;
+ }
+
+ $autoloadSave = spl_autoload_functions();
+
+ if ($this->bootstrap)
+ {
+ require_once $this->bootstrap;
+ }
+
+ $suite = new PHPUnit_Framework_TestSuite('AllTests');
+
+ foreach ($this->batchtests as $batchtest)
+ {
+ $batchtest->addToTestSuite($suite);
+ }
+
+ $this->execute($suite);
+
+ if ($this->testfailed)
+ {
+ throw new BuildException($this->testfailuremessage);
+ }
+
+ $autoloadNew = spl_autoload_functions();
+ foreach ($autoloadNew as $autoload) {
+ spl_autoload_unregister($autoload);
+ }
+
+ foreach ($autoloadSave as $autoload) {
+ spl_autoload_register($autoload);
+ }
+ }
+
+ /**
+ * @throws BuildException
+ */
+ protected function execute($suite)
+ {
+ $runner = new PHPUnitTestRunner($this->project, $this->groups, $this->excludeGroups, $this->processIsolation);
+
+ if ($this->codecoverage) {
+ /**
+ * Add some defaults to the PHPUnit filter
+ */
+ $pwd = dirname(__FILE__);
+ $path = realpath($pwd . '/../../../');
+
+ $filter = new PHP_CodeCoverage_Filter();
+ $filter->addDirectoryToBlacklist($path);
+ $runner->setCodecoverage(new PHP_CodeCoverage(null, $filter));
+ }
+
+ $runner->setUseCustomErrorHandler($this->usecustomerrorhandler);
+
+ foreach ($this->formatters as $fe)
+ {
+ $formatter = $fe->getFormatter();
+
+ if ($fe->getUseFile())
+ {
+ $destFile = new PhingFile($fe->getToDir(), $fe->getOutfile());
+
+ $writer = new FileWriter($destFile->getAbsolutePath());
+
+ $formatter->setOutput($writer);
+ }
+ else
+ {
+ $formatter->setOutput($this->getDefaultOutput());
+ }
+
+ $runner->addFormatter($formatter);
+
+ $formatter->startTestRun();
+ }
+
+ $runner->run($suite);
+
+ foreach ($this->formatters as $fe)
+ {
+ $formatter = $fe->getFormatter();
+ $formatter->endTestRun();
+ }
+
+ $retcode = $runner->getRetCode();
+
+ if ($retcode == PHPUnitTestRunner::ERRORS) {
+ if ($this->errorproperty) {
+ $this->project->setNewProperty($this->errorproperty, true);
+ }
+ if ($this->haltonerror) {
+ $this->testfailed = true;
+ $this->testfailuremessage = $runner->getLastErrorMessage();
+ }
+ } elseif ($retcode == PHPUnitTestRunner::FAILURES) {
+ if ($this->failureproperty) {
+ $this->project->setNewProperty($this->failureproperty, true);
+ }
+
+ if ($this->haltonfailure) {
+ $this->testfailed = true;
+ $this->testfailuremessage = $runner->getLastFailureMessage();
+ }
+ } elseif ($retcode == PHPUnitTestRunner::INCOMPLETES) {
+ if ($this->incompleteproperty) {
+ $this->project->setNewProperty($this->incompleteproperty, true);
+ }
+
+ if ($this->haltonincomplete) {
+ $this->testfailed = true;
+ $this->testfailuremessage = $runner->getLastIncompleteMessage();
+ }
+ } elseif ($retcode == PHPUnitTestRunner::SKIPPED) {
+ if ($this->skippedproperty) {
+ $this->project->setNewProperty($this->skippedproperty, true);
+ }
+
+ if ($this->haltonskipped) {
+ $this->testfailed = true;
+ $this->testfailuremessage = $runner->getLastSkippedMessage();
+ }
+ }
+ }
+
+ protected function getDefaultOutput()
+ {
+ return new LogWriter($this);
+ }
+
+ /**
+ * Adds a set of tests based on pattern matching.
+ *
+ * @return BatchTest a new instance of a batch test.
+ */
+ public function createBatchTest()
+ {
+ $batchtest = new BatchTest($this->getProject());
+
+ $this->batchtests[] = $batchtest;
+
+ return $batchtest;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTestRunner.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTestRunner.php
new file mode 100755
index 00000000..6c7e5e68
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTestRunner.php
@@ -0,0 +1,312 @@
+<?php
+/**
+ * $Id: 5926dfc1177ec0c52ec275a8e542979c8deb6e6f $
+ *
+ * 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 'PHPUnit/Autoload.php';
+require_once 'phing/tasks/ext/coverage/CoverageMerger.php';
+require_once 'phing/system/util/Timer.php';
+
+/**
+ * Simple Testrunner for PHPUnit that runs all tests of a testsuite.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 5926dfc1177ec0c52ec275a8e542979c8deb6e6f $
+ * @package phing.tasks.ext.phpunit
+ * @since 2.1.0
+ */
+class PHPUnitTestRunner extends PHPUnit_Runner_BaseTestRunner implements PHPUnit_Framework_TestListener
+{
+ const SUCCESS = 0;
+ const FAILURES = 1;
+ const ERRORS = 2;
+ const INCOMPLETES = 3;
+ const SKIPPED = 4;
+
+ private $retCode = 0;
+ private $lastErrorMessage = '';
+ private $lastFailureMessage = '';
+ private $lastIncompleteMessage = '';
+ private $lastSkippedMessage = '';
+ private $formatters = array();
+
+ private $codecoverage = null;
+
+ private $project = NULL;
+
+ private $groups = array();
+ private $excludeGroups = array();
+
+ private $processIsolation = false;
+
+ private $useCustomErrorHandler = true;
+
+ public function __construct(Project $project, $groups = array(), $excludeGroups = array(), $processIsolation = false)
+ {
+ $this->project = $project;
+ $this->groups = $groups;
+ $this->excludeGroups = $excludeGroups;
+ $this->processIsolation = $processIsolation;
+ $this->retCode = self::SUCCESS;
+ }
+
+ public function setCodecoverage($codecoverage)
+ {
+ $this->codecoverage = $codecoverage;
+ }
+
+ public function setUseCustomErrorHandler($useCustomErrorHandler)
+ {
+ $this->useCustomErrorHandler = $useCustomErrorHandler;
+ }
+
+ public function addFormatter($formatter)
+ {
+ $this->formatters[] = $formatter;
+ }
+
+ public function handleError($level, $message, $file, $line)
+ {
+ return PHPUnit_Util_ErrorHandler::handleError($level, $message, $file, $line);
+ }
+
+ /**
+ * Run a test
+ */
+ public function run(PHPUnit_Framework_TestSuite $suite)
+ {
+ $res = new PHPUnit_Framework_TestResult();
+
+ if ($this->codecoverage)
+ {
+ $whitelist = CoverageMerger::getWhiteList($this->project);
+
+ $this->codecoverage->filter()->addFilesToWhiteList($whitelist);
+
+ $res->setCodeCoverage($this->codecoverage);
+ }
+
+ $res->addListener($this);
+
+ foreach ($this->formatters as $formatter)
+ {
+ $res->addListener($formatter);
+ }
+
+ /* Set PHPUnit error handler */
+ if ($this->useCustomErrorHandler)
+ {
+ $oldErrorHandler = set_error_handler(array($this, 'handleError'), E_ALL | E_STRICT);
+ }
+
+ $suite->run($res, false, $this->groups, $this->excludeGroups, $this->processIsolation);
+
+ foreach ($this->formatters as $formatter)
+ {
+ $formatter->processResult($res);
+ }
+
+ /* Restore Phing error handler */
+ if ($this->useCustomErrorHandler)
+ {
+ restore_error_handler();
+ }
+
+ if ($this->codecoverage)
+ {
+ CoverageMerger::merge($this->project, $this->codecoverage->getData());
+ }
+
+ if ($res->errorCount() != 0)
+ {
+ $this->retCode = self::ERRORS;
+ }
+ else if ($res->failureCount() != 0)
+ {
+ $this->retCode = self::FAILURES;
+ }
+ else if ($res->notImplementedCount() != 0)
+ {
+ $this->retCode = self::INCOMPLETES;
+ }
+ else if ($res->skippedCount() != 0)
+ {
+ $this->retCode = self::SKIPPED;
+ }
+ }
+
+ public function getRetCode()
+ {
+ return $this->retCode;
+ }
+
+ public function getLastErrorMessage()
+ {
+ return $this->lastErrorMessage;
+ }
+
+ public function getLastFailureMessage()
+ {
+ return $this->lastFailureMessage;
+ }
+
+ public function getLastIncompleteMessage()
+ {
+ return $this->lastIncompleteMessage;
+ }
+
+ public function getLastSkippedMessage()
+ {
+ return $this->lastSkippedMessage;
+ }
+
+ protected function composeMessage($message, PHPUnit_Framework_Test $test, Exception $e)
+ {
+ return "Test $message (" . $test->getName() . " in class " . get_class($test) . "): " . $e->getMessage();
+ }
+
+ /**
+ * An error occurred.
+ *
+ * @param PHPUnit_Framework_Test $test
+ * @param Exception $e
+ * @param float $time
+ */
+ public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->lastErrorMessage = $this->composeMessage("ERROR", $test, $e);
+ }
+
+ /**
+ * A failure occurred.
+ *
+ * @param PHPUnit_Framework_Test $test
+ * @param PHPUnit_Framework_AssertionFailedError $e
+ * @param float $time
+ */
+ public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
+ {
+ $this->lastFailureMessage = $this->composeMessage("FAILURE", $test, $e);
+ }
+
+ /**
+ * Incomplete test.
+ *
+ * @param PHPUnit_Framework_Test $test
+ * @param Exception $e
+ * @param float $time
+ */
+ public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->lastIncompleteMessage = $this->composeMessage("INCOMPLETE", $test, $e);
+ }
+
+ /**
+ * Skipped test.
+ *
+ * @param PHPUnit_Framework_Test $test
+ * @param Exception $e
+ * @param float $time
+ * @since Method available since Release 3.0.0
+ */
+ public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->lastSkippedMessage = $this->composeMessage("SKIPPED", $test, $e);
+ }
+
+ /**
+ * A test started.
+ *
+ * @param string $testName
+ */
+ public function testStarted($testName)
+ {
+ }
+
+ /**
+ * A test ended.
+ *
+ * @param string $testName
+ */
+ public function testEnded($testName)
+ {
+ }
+
+ /**
+ * A test failed.
+ *
+ * @param integer $status
+ * @param PHPUnit_Framework_Test $test
+ * @param PHPUnit_Framework_AssertionFailedError $e
+ */
+ public function testFailed($status, PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e)
+ {
+ }
+
+ /**
+ * Override to define how to handle a failed loading of
+ * a test suite.
+ *
+ * @param string $message
+ */
+ protected function runFailed($message)
+ {
+ throw new BuildException($message);
+ }
+
+ /**
+ * A test suite started.
+ *
+ * @param PHPUnit_Framework_TestSuite $suite
+ * @since Method available since Release 2.2.0
+ */
+ public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ }
+
+ /**
+ * A test suite ended.
+ *
+ * @param PHPUnit_Framework_TestSuite $suite
+ * @since Method available since Release 2.2.0
+ */
+ public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ }
+
+ /**
+ * A test started.
+ *
+ * @param PHPUnit_Framework_Test $test
+ */
+ public function startTest(PHPUnit_Framework_Test $test)
+ {
+ }
+
+ /**
+ * A test ended.
+ *
+ * @param PHPUnit_Framework_Test $test
+ * @param float $time
+ */
+ public function endTest(PHPUnit_Framework_Test $test, $time)
+ {
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitUtil.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitUtil.php
new file mode 100755
index 00000000..25a85f4c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitUtil.php
@@ -0,0 +1,141 @@
+<?php
+/**
+ * $Id: c569f96e625ed8f9c6ae5add2b2f4a0a6c3e5a54 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: c569f96e625ed8f9c6ae5add2b2f4a0a6c3e5a54 $
+ * @package phing.tasks.ext.phpunit
+ * @since 2.1.0
+ */
+class PHPUnitUtil
+{
+ 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";
+ }
+ }
+
+ /**
+ * Returns the subpackage of a class as defined in the docblock of the class
+ * using @subpackage
+ *
+ * @param string $classname the name of the class
+ *
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @return string|null the name of the subpackage
+ */
+ public static function getSubpackageName($classname)
+ {
+ $reflect = new ReflectionClass($classname);
+
+ if (preg_match('/@subpackage[\s]+([\.\w]+)/', $reflect->getDocComment(), $matches)) {
+ return $matches[1];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * 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
+ */
+ public 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
+ */
+ public 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()]);
+ }
+ }
+
+ if (isset(self::$definedClasses[$filename]))
+ {
+ return self::$definedClasses[$filename];
+ }
+ else
+ {
+ return array();
+ }
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php
new file mode 100755
index 00000000..4d03078d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php
@@ -0,0 +1,87 @@
+<?php
+/**
+ * $Id: 97f504caad678a6c7d231fe298c27d1281008e48 $
+ *
+ * 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/phpunit/formatter/PHPUnitResultFormatter.php';
+
+/**
+ * Prints Clover XML output of the test
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 97f504caad678a6c7d231fe298c27d1281008e48 $
+ * @package phing.tasks.ext.formatter
+ * @since 2.4.0
+ */
+class CloverPHPUnitResultFormatter extends PHPUnitResultFormatter
+{
+ /**
+ * @var PHPUnit_Framework_TestResult
+ */
+ private $result = NULL;
+
+ /**
+ * PHPUnit version
+ * @var string
+ */
+ private $version = NULL;
+
+ public function __construct(PHPUnitTask $parentTask)
+ {
+ parent::__construct($parentTask);
+
+ $this->version = PHPUnit_Runner_Version::id();
+ }
+
+ public function getExtension()
+ {
+ return ".xml";
+ }
+
+ public function getPreferredOutfile()
+ {
+ return "clover-coverage";
+ }
+
+ public function processResult(PHPUnit_Framework_TestResult $result)
+ {
+ $this->result = $result;
+ }
+
+ public function endTestRun()
+ {
+ require_once 'PHP/CodeCoverage/Report/Clover.php';
+
+ $coverage = $this->result->getCodeCoverage();
+
+ if (!empty($coverage)) {
+ $clover = new PHP_CodeCoverage_Report_Clover();
+
+ $contents = $clover->process($coverage);
+
+ if ($this->out)
+ {
+ $this->out->write($contents);
+ $this->out->close();
+ }
+ }
+
+ parent::endTestRun();
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php
new file mode 100755
index 00000000..1b09dbc1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * $Id: cbf356a8395e116cd6ecddb7f5a822d4b6edf01c $
+ *
+ * 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 'PHPUnit/Framework/TestListener.php';
+
+require_once 'phing/system/io/Writer.php';
+
+/**
+ * This abstract class describes classes that format the results of a PHPUnit testrun.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: cbf356a8395e116cd6ecddb7f5a822d4b6edf01c $
+ * @package phing.tasks.ext.phpunit.formatter
+ * @since 2.1.0
+ */
+abstract class PHPUnitResultFormatter implements PHPUnit_Framework_TestListener
+{
+ protected $out = NULL;
+
+ protected $project = NULL;
+
+ private $timers = false;
+
+ private $runCounts = false;
+
+ private $failureCounts = false;
+
+ private $errorCounts = false;
+
+ private $incompleteCounts = false;
+
+ private $skipCounts = false;
+
+ /**
+ * Constructor
+ * @param PHPUnitTask $parentTask Calling Task
+ */
+ public function __construct(PHPUnitTask $parentTask)
+ {
+ $this->project = $parentTask->getProject();
+ }
+
+ /**
+ * Sets the writer the formatter is supposed to write its results to.
+ */
+ public function setOutput(Writer $out)
+ {
+ $this->out = $out;
+ }
+
+ /**
+ * Returns the extension used for this formatter
+ *
+ * @return string the extension
+ */
+ public function getExtension()
+ {
+ return "";
+ }
+
+ public function getPreferredOutfile()
+ {
+ return "";
+ }
+
+ public function processResult(PHPUnit_Framework_TestResult $result)
+ {
+ }
+
+ public function startTestRun()
+ {
+ $this->timers = array($this->getMicrotime());
+ $this->runCounts = array(0);
+ $this->failureCounts = array(0);
+ $this->errorCounts = array(0);
+ $this->incompleteCounts = array(0);
+ $this->skipCounts = array(0);
+ }
+
+ public function endTestRun()
+ {
+ }
+
+ public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ $this->timers[] = $this->getMicrotime();
+ $this->runCounts[] = 0;
+ $this->failureCounts[] = 0;
+ $this->errorCounts[] = 0;
+ $this->incompleteCounts[] = 0;
+ $this->skipCounts[] = 0;
+ }
+
+ public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ $lastRunCount = array_pop($this->runCounts);
+ $this->runCounts[count($this->runCounts) - 1] += $lastRunCount;
+
+ $lastFailureCount = array_pop($this->failureCounts);
+ $this->failureCounts[count($this->failureCounts) - 1] += $lastFailureCount;
+
+ $lastErrorCount = array_pop($this->errorCounts);
+ $this->errorCounts[count($this->errorCounts) - 1] += $lastErrorCount;
+
+ $lastIncompleteCount = array_pop($this->incompleteCounts);
+ $this->incompleteCounts[count($this->incompleteCounts) - 1] += $lastIncompleteCount;
+
+ $lastSkipCount = array_pop($this->skipCounts);
+ $this->skipCounts[count($this->skipCounts) - 1] += $lastSkipCount;
+
+ array_pop($this->timers);
+ }
+
+ public function startTest(PHPUnit_Framework_Test $test)
+ {
+ $this->runCounts[count($this->runCounts) - 1]++;
+ }
+
+ public function endTest(PHPUnit_Framework_Test $test, $time)
+ {
+ }
+
+ public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->errorCounts[count($this->errorCounts) - 1]++;
+ }
+
+ public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
+ {
+ $this->failureCounts[count($this->failureCounts) - 1]++;
+ }
+
+ public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->incompleteCounts[count($this->incompleteCounts) - 1]++;
+ }
+
+ public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ $this->skipCounts[count($this->skipCounts) - 1]++;
+ }
+
+ public function getRunCount()
+ {
+ return end($this->runCounts);
+ }
+
+ public function getFailureCount()
+ {
+ return end($this->failureCounts);
+ }
+
+ public function getErrorCount()
+ {
+ return end($this->errorCounts);
+ }
+
+ public function getIncompleteCount()
+ {
+ return end($this->incompleteCounts);
+ }
+
+ public function getSkippedCount()
+ {
+ return end($this->skipCounts);
+ }
+
+ public function getElapsedTime()
+ {
+ if (end($this->timers))
+ {
+ return $this->getMicrotime() - end($this->timers);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ private function getMicrotime() {
+ list($usec, $sec) = explode(' ', microtime());
+ return (float)$usec + (float)$sec;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php
new file mode 100755
index 00000000..e67cfd2b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * $Id: 529f9b6ab9ced7b78871e3612cd8afce58261a6f $
+ *
+ * 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/phpunit/formatter/PHPUnitResultFormatter.php';
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 529f9b6ab9ced7b78871e3612cd8afce58261a6f $
+ * @package phing.tasks.ext.phpunit.formatter
+ * @since 2.1.0
+ */
+class PlainPHPUnitResultFormatter extends PHPUnitResultFormatter
+{
+ private $inner = "";
+
+ public function getExtension()
+ {
+ return ".txt";
+ }
+
+ public function getPreferredOutfile()
+ {
+ return "testresults";
+ }
+
+ public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ parent::startTestSuite($suite);
+
+ $this->inner = "";
+ }
+
+ public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ if ($suite->getName() == 'AllTests')
+ {
+ return false;
+ }
+
+ $sb = "Testsuite: " . $suite->getName() . "\n";
+ $sb.= "Tests run: " . $this->getRunCount();
+ $sb.= ", Failures: " . $this->getFailureCount();
+ $sb.= ", Errors: " . $this->getErrorCount();
+ $sb.= ", Incomplete: " . $this->getIncompleteCount();
+ $sb.= ", Skipped: " . $this->getSkippedCount();
+ $sb.= ", Time elapsed: " . sprintf('%0.5f', $this->getElapsedTime()) . " s\n";
+
+ if ($this->out != NULL)
+ {
+ $this->out->write($sb);
+ $this->out->write($this->inner);
+ }
+
+ parent::endTestSuite($suite);
+ }
+
+ public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ parent::addError($test, $e, $time);
+
+ $this->formatError("ERROR", $test, $e);
+ }
+
+ public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
+ {
+ parent::addFailure($test, $e, $time);
+ $this->formatError("FAILED", $test, $e);
+ }
+
+ public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ parent::addIncompleteTest($test, $e, $time);
+
+ $this->formatError("INCOMPLETE", $test);
+ }
+
+ public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ parent::addSkippedTest($test, $e, $time);
+ $this->formatError("SKIPPED", $test);
+ }
+
+ private function formatError($type, PHPUnit_Framework_Test $test, Exception $e = null)
+ {
+ if ($test != null)
+ {
+ $this->endTest($test, time());
+ }
+
+ $this->inner.= $test->getName() . " " . $type . "\n";
+
+ if ($e !== null) {
+ $this->inner.= $e->getMessage() . "\n";
+ // $this->inner.= PHPUnit_Util_Filter::getFilteredStackTrace($e, true) . "\n";
+ }
+ }
+
+ public function endTestRun()
+ {
+ parent::endTestRun();
+
+ if ($this->out != NULL)
+ {
+ $this->out->close();
+ }
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php
new file mode 100755
index 00000000..0007c235
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * $Id: bd9c51fa75c9b856105fc810200028d855a3782d $
+ *
+ * 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/phpunit/formatter/PHPUnitResultFormatter.php';
+
+/**
+ * Prints short summary output of the test to Phing's logging system.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: bd9c51fa75c9b856105fc810200028d855a3782d $
+ * @package phing.tasks.ext.formatter
+ * @since 2.1.0
+ */
+class SummaryPHPUnitResultFormatter extends PHPUnitResultFormatter
+{
+ public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ parent::endTestSuite($suite);
+ }
+
+ public function endTestRun()
+ {
+ parent::endTestRun();
+
+ $sb = "Total tests run: " . $this->getRunCount();
+ $sb.= ", Failures: " . $this->getFailureCount();
+ $sb.= ", Errors: " . $this->getErrorCount();
+ $sb.= ", Incomplete: " . $this->getIncompleteCount();
+ $sb.= ", Skipped: " . $this->getSkippedCount();
+ $sb.= ", Time elapsed: " . sprintf('%0.5f', $this->getElapsedTime()) . " s\n";
+
+ if ($this->out != NULL)
+ {
+ $this->out->write($sb);
+ $this->out->close();
+ }
+ }
+
+ public function getExtension()
+ {
+ return NULL;
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php
new file mode 100755
index 00000000..7fef7454
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * $Id: 3d9c47a29ded9b67b3a3e10c55602b0ab2a9ea38 $
+ *
+ * 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 'PHPUnit/Util/Log/JUnit.php';
+
+require_once 'phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php';
+
+/**
+ * Prints XML output of the test to a specified Writer
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 3d9c47a29ded9b67b3a3e10c55602b0ab2a9ea38 $
+ * @package phing.tasks.ext.formatter
+ * @since 2.1.0
+ */
+class XMLPHPUnitResultFormatter extends PHPUnitResultFormatter
+{
+ /**
+ * @var PHPUnit_Util_Log_JUnit
+ */
+ private $logger = NULL;
+
+ public function __construct(PHPUnitTask $parentTask)
+ {
+ parent::__construct($parentTask);
+
+ $logIncompleteSkipped = $parentTask->getHaltonincomplete() || $parentTask->getHaltonskipped();
+
+ $this->logger = new PHPUnit_Util_Log_JUnit(null, $logIncompleteSkipped);
+ $this->logger->setWriteDocument(false);
+ }
+
+ public function getExtension()
+ {
+ return ".xml";
+ }
+
+ public function getPreferredOutfile()
+ {
+ return "testsuites";
+ }
+
+ public function startTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ parent::startTestSuite($suite);
+
+ $this->logger->startTestSuite($suite);
+ }
+
+ public function endTestSuite(PHPUnit_Framework_TestSuite $suite)
+ {
+ parent::endTestSuite($suite);
+
+ $this->logger->endTestSuite($suite);
+ }
+
+ public function startTest(PHPUnit_Framework_Test $test)
+ {
+ parent::startTest($test);
+
+ $this->logger->startTest($test);
+ }
+
+ public function endTest(PHPUnit_Framework_Test $test, $time)
+ {
+ parent::endTest($test, $time);
+
+ $this->logger->endTest($test, $time);
+ }
+
+ public function addError(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ parent::addError($test, $e, $time);
+
+ $this->logger->addError($test, $e, $time);
+ }
+
+ public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time)
+ {
+ parent::addFailure($test, $e, $time);
+
+ $this->logger->addFailure($test, $e, $time);
+ }
+
+ public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time)
+ {
+ parent::addIncompleteTest($test, $e, $time);
+
+ $this->logger->addIncompleteTest($test, $e, $time);
+ }
+
+ public function endTestRun()
+ {
+ parent::endTestRun();
+
+ if ($this->out)
+ {
+ $this->out->write($this->logger->getXML());
+ $this->out->close();
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/rSTTask.php b/buildscripts/phing/classes/phing/tasks/ext/rSTTask.php
new file mode 100644
index 00000000..77170f18
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/rSTTask.php
@@ -0,0 +1,476 @@
+<?php
+
+/**
+ * reStructuredText rendering task for Phing, the PHP build tool.
+ *
+ * PHP version 5
+ *
+ * @category Tasks
+ * @package phing.tasks.ext
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @link http://www.phing.info/
+ * @version SVN: $Id: ad2ac21008b4635c4f557e3a65c9306a350ca1f2 $
+ */
+
+require_once 'phing/Task.php';
+require_once 'phing/util/FileUtils.php';
+
+/**
+ * reStructuredText rendering task for Phing, the PHP build tool.
+ *
+ * PHP version 5
+ *
+ * @category Tasks
+ * @package phing.tasks.ext
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @link http://www.phing.info/
+ */
+class rSTTask extends Task
+{
+ /**
+ * @var string Taskname for logger
+ */
+ protected $taskName = 'rST';
+
+ /**
+ * Result format, defaults to "html".
+ * @see $supportedFormats for all possible options
+ *
+ * @var string
+ */
+ protected $format = 'html';
+
+ /**
+ * Array of supported output formats
+ *
+ * @var array
+ * @see $format
+ * @see $targetExt
+ */
+ protected static $supportedFormats = array(
+ 'html', 'latex', 'man', 'odt', 's5', 'xml'
+ );
+
+ /**
+ * Maps formats to file extensions
+ *
+ * @var array
+ */
+ protected static $targetExt = array(
+ 'html' => 'html',
+ 'latex' => 'tex',
+ 'man' => '3',
+ 'odt' => 'odt',
+ 's5' => 'html',
+ 'xml' => 'xml',
+ );
+
+ /**
+ * Input file in rST format.
+ * Required
+ *
+ * @var string
+ */
+ protected $file = null;
+
+ /**
+ * Additional rst2* tool parameters.
+ *
+ * @var string
+ */
+ protected $toolParam = null;
+
+ /**
+ * Full path to the tool, i.e. /usr/local/bin/rst2html
+ *
+ * @var string
+ */
+ protected $toolPath = null;
+
+ /**
+ * Output file or directory. May be omitted.
+ * When it ends with a slash, it is considered to be a directory
+ *
+ * @var string
+ */
+ protected $destination = null;
+
+ protected $filesets = array(); // all fileset objects assigned to this task
+ protected $mapperElement = null;
+
+ /**
+ * all filterchains objects assigned to this task
+ *
+ * @var array
+ */
+ protected $filterChains = array();
+
+ /**
+ * mode to create directories with
+ *
+ * @var integer
+ */
+ protected $mode = 0755;
+
+ /**
+ * Only render files whole source files are newer than the
+ * target files
+ *
+ * @var boolean
+ */
+ protected $uptodate = false;
+
+
+ /**
+ * Init method: requires the PEAR System class
+ */
+ public function init()
+ {
+ require_once 'System.php';
+ }
+
+ /**
+ * The main entry point method.
+ *
+ * @return void
+ */
+ public function main()
+ {
+ $tool = $this->getToolPath($this->format);
+ if (count($this->filterChains)) {
+ $this->fileUtils = new FileUtils();
+ }
+
+ if ($this->file != '') {
+ $file = $this->file;
+ $targetFile = $this->getTargetFile($file, $this->destination);
+ $this->render($tool, $file, $targetFile);
+ return;
+ }
+
+ if (!count($this->filesets)) {
+ throw new BuildException(
+ '"file" attribute or "fileset" subtag required'
+ );
+ }
+
+ // process filesets
+ $mapper = null;
+ if ($this->mapperElement !== null) {
+ $mapper = $this->mapperElement->getImplementation();
+ }
+
+ $project = $this->getProject();
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($project);
+ $fromDir = $fs->getDir($project);
+ $srcFiles = $ds->getIncludedFiles();
+
+ foreach ($srcFiles as $src) {
+ $file = new PhingFile($fromDir, $src);
+ if ($mapper !== null) {
+ $results = $mapper->main($file);
+ if ($results === null) {
+ throw new BuildException(
+ sprintf(
+ 'No filename mapper found for "%s"',
+ $file
+ )
+ );
+ }
+ $targetFile = reset($results);
+ } else {
+ $targetFile = $this->getTargetFile($file, $this->destination);
+ }
+ $this->render($tool, $file, $targetFile);
+ }
+ }
+ }
+
+
+
+ /**
+ * Renders a single file and applies filters on it
+ *
+ * @param string $tool conversion tool to use
+ * @param string $source rST source file
+ * @param string $targetFile target file name
+ *
+ * @return void
+ */
+ protected function render($tool, $source, $targetFile)
+ {
+ if (count($this->filterChains) == 0) {
+ return $this->renderFile($tool, $source, $targetFile);
+ }
+
+ $tmpTarget = tempnam(sys_get_temp_dir(), 'rST-');
+ $this->renderFile($tool, $source, $tmpTarget);
+
+ $this->fileUtils->copyFile(
+ new PhingFile($tmpTarget),
+ new PhingFile($targetFile),
+ true, false, $this->filterChains,
+ $this->getProject(), $this->mode
+ );
+ unlink($tmpTarget);
+ }
+
+
+
+ /**
+ * Renders a single file with the rST tool.
+ *
+ * @param string $tool conversion tool to use
+ * @param string $source rST source file
+ * @param string $targetFile target file name
+ *
+ * @return void
+ *
+ * @throws BuildException When the conversion fails
+ */
+ protected function renderFile($tool, $source, $targetFile)
+ {
+ if ($this->uptodate && file_exists($targetFile)
+ && filemtime($source) <= filemtime($targetFile)
+ ) {
+ //target is up to date
+ return;
+ }
+ //work around a bug in php by replacing /./ with /
+ $targetDir = str_replace('/./', '/', dirname($targetFile));
+ if (!is_dir($targetDir)) {
+ $this->log("Creating directory '$targetDir'", Project::MSG_VERBOSE);
+ mkdir($targetDir, $this->mode, true);
+ }
+
+ $cmd = $tool
+ . ' --exit-status=2'
+ . ' ' . $this->toolParam
+ . ' ' . escapeshellarg($source)
+ . ' ' . escapeshellarg($targetFile)
+ . ' 2>&1';
+
+ $this->log('command: ' . $cmd, Project::MSG_VERBOSE);
+ exec($cmd, $arOutput, $retval);
+ if ($retval != 0) {
+ $this->log(implode("\n", $arOutput), Project::MSG_INFO);
+ throw new BuildException('Rendering rST failed');
+ }
+ $this->log(implode("\n", $arOutput), Project::MSG_DEBUG);
+ }
+
+
+
+ /**
+ * Finds the rst2* binary path
+ *
+ * @param string $format Output format
+ *
+ * @return string Full path to rst2$format
+ *
+ * @throws BuildException When the tool cannot be found
+ */
+ protected function getToolPath($format)
+ {
+ if ($this->toolPath !== null) {
+ return $this->toolPath;
+ }
+
+ $tool = 'rst2' . $format;
+ $path = System::which($tool);
+ if (!$path) {
+ throw new BuildException(
+ sprintf('"%s" not found. Install python-docutils.', $tool)
+ );
+ }
+
+ return $path;
+ }
+
+
+
+ /**
+ * Determines and returns the target file name from the
+ * input file and the configured destination name.
+ *
+ * @param string $file Input file
+ * @param string $destination Destination file or directory name,
+ * may be null
+ *
+ * @return string Target file name
+ *
+ * @uses $format
+ * @uses $targetExt
+ */
+ public function getTargetFile($file, $destination = null)
+ {
+ if ($destination != ''
+ && substr($destination, -1) !== '/'
+ && substr($destination, -1) !== '\\'
+ ) {
+ return $destination;
+ }
+
+ if (strtolower(substr($file, -4)) == '.rst') {
+ $file = substr($file, 0, -4);
+ }
+
+ return $destination . $file . '.' . self::$targetExt[$this->format];
+ }
+
+
+
+ /**
+ * The setter for the attribute "file"
+ *
+ * @param string $file Path of file to render
+ *
+ * @return void
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+
+
+ /**
+ * The setter for the attribute "format"
+ *
+ * @param string $format Output format
+ *
+ * @return void
+ *
+ * @throws BuildException When the format is not supported
+ */
+ public function setFormat($format)
+ {
+ if (!in_array($format, self::$supportedFormats)) {
+ throw new BuildException(
+ sprintf(
+ 'Invalid output format "%s", allowed are: %s',
+ $format,
+ implode(', ', self::$supportedFormats)
+ )
+ );
+ }
+ $this->format = $format;
+ }
+
+
+
+ /**
+ * The setter for the attribute "destination"
+ *
+ * @param string $destination Output file or directory. When it ends
+ * with a slash, it is taken as directory.
+ *
+ * @return void
+ */
+ public function setDestination($destination)
+ {
+ $this->destination = $destination;
+ }
+
+ /**
+ * The setter for the attribute "toolparam"
+ *
+ * @param string $param Additional rst2* tool parameters
+ *
+ * @return void
+ */
+ public function setToolparam($param)
+ {
+ $this->toolParam = $param;
+ }
+
+ /**
+ * The setter for the attribute "toolpath"
+ *
+ * @param string $param Full path to tool path, i.e. /usr/local/bin/rst2html
+ *
+ * @return void
+ *
+ * @throws BuildException When the tool does not exist or is not executable
+ */
+ public function setToolpath($path)
+ {
+ if (!file_exists($path)) {
+ $fullpath = System::which($path);
+ if ($fullpath === false) {
+ throw new BuildException(
+ 'Tool does not exist. Path: ' . $path
+ );
+ }
+ $path = $fullpath;
+ }
+ if (!is_executable($path)) {
+ throw new BuildException(
+ 'Tool not executable. Path: ' . $path
+ );
+ }
+ $this->toolPath = $path;
+ }
+
+ /**
+ * The setter for the attribute "uptodate"
+ *
+ * @param string $uptodate True/false
+ *
+ * @return void
+ */
+ public function setUptodate($uptodate)
+ {
+ $this->uptodate = (boolean)$uptodate;
+ }
+
+
+
+ /**
+ * Add a set of files to be rendered.
+ *
+ * @param FileSet $fileset Set of rst files to render
+ *
+ * @return void
+ */
+ public function addFileset(FileSet $fileset)
+ {
+ $this->filesets[] = $fileset;
+ }
+
+
+
+ /**
+ * Nested creator, creates one Mapper for this task
+ *
+ * @return Mapper The created Mapper type object
+ *
+ * @throws BuildException
+ */
+ public 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;
+ }
+
+
+
+ /**
+ * Creates a filterchain, stores and returns it
+ *
+ * @return FilterChain The created filterchain object
+ */
+ public function createFilterChain()
+ {
+ $num = array_push($this->filterChains, new FilterChain($this->project));
+ return $this->filterChains[$num-1];
+ }
+}
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 100755
index 00000000..32fbc212
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * $Id: ae09aa1a433f4de854fa7c27903e7eb0957bc90b $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: ae09aa1a433f4de854fa7c27903e7eb0957bc90b $
+ * @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;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php
new file mode 100755
index 00000000..de78ab24
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * $Id: d7e7e397e81588c3eafcb9e758666fec0fa166f5 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: d7e7e397e81588c3eafcb9e758666fec0fa166f5 $
+ * @package phing.tasks.ext.simpletest
+ * @since 2.2.0
+ */
+class SimpleTestDebugResultFormatter extends SimpleTestResultFormatter
+{
+ protected $current_case = "";
+ protected $current_test = "";
+ private $failingTests = array();
+
+ function printFailingTests() {
+ foreach ($this->failingTests as $test) {
+ $this->out->write($test . "\n");
+ }
+ }
+
+ function paintCaseStart($test_name)
+ {
+ parent::paintCaseStart($test_name);
+ $this->paint( "Testsuite: $test_name\n");
+ $this->current_case = $test_name;
+ }
+
+ function paintMethodStart($test_name)
+ {
+ parent::paintMethodStart($test_name);
+ $this->current_test = $test_name;
+ //$msg = "{$this->current_case} :: $test_name\n";
+ $msg = " TestCase: $test_name";
+ $this->paint($msg);
+ }
+
+ function paint($msg) {
+ if ($this->out == null ) {
+ print $msg;
+ } else {
+ $this->out->write($msg);
+ }
+ }
+
+ function paintMethodEnd($test_name) {
+ parent::paintMethodEnd($test_name);
+ $this->paint("\n");
+ }
+
+ function paintCaseEnd($test_name)
+ {
+ parent::paintCaseEnd($test_name);
+ $this->current_case = "";
+ /* Only count suites where more than one test was run */
+
+ if ($this->getRunCount() && false)
+ {
+ $sb = "";
+ $sb.= "Tests run: " . $this->getRunCount();
+ $sb.= ", Failures: " . $this->getFailureCount();
+ $sb.= ", Errors: " . $this->getErrorCount();
+ $sb.= ", Time elapsed: " . $this->getElapsedTime();
+ $sb.= " sec\n";
+ $this->paint($sb);
+ }
+
+ }
+
+ function paintError($message)
+ {
+ parent::paintError($message);
+ $this->formatError("ERROR", $message);
+ $this->failingTests[] = $this->current_case . "->" . $this->current_test;
+ }
+
+ function paintFail($message)
+ {
+ parent::paintFail($message);
+ $this->formatError("FAILED", $message);
+ $this->failingTests[] = $this->current_case . "->" . $this->current_test;
+ }
+ function paintException($message)
+ {
+ parent::paintException($message);
+ $this->failingTests[] = $this->current_case . "->" . $this->current_test;
+ $this->formatError("Exception", $message);
+ }
+
+
+
+ private function formatError($type, $message)
+ {
+ $this->paint("ERROR: $type: $message");
+ }
+
+}
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 100755
index 00000000..5ae9ba23
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * $Id: 2441f1b83b9f9d1aeb2a4afd7e049c840d70bbd9 $
+ *
+ * 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/phpunit/FormatterElement.php';
+
+/**
+ * Child class of "FormatterElement", overrides setType to provide other
+ * formatter classes for SimpleTest
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 2441f1b83b9f9d1aeb2a4afd7e049c840d70bbd9 $
+ * @package phing.tasks.ext.simpletest
+ * @since 2.2.0
+ */
+class SimpleTestFormatterElement extends FormatterElement
+{
+ function setType($type)
+ {
+ $this->type = $type;
+
+ if ($this->type == "xml")
+ {
+ require_once 'phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php';
+ $destFile = new PhingFile($this->toDir, 'testsuites.xml');
+ $this->formatter = new SimpleTestXmlResultFormatter();
+ }
+ else
+ if ($this->type == "plain")
+ {
+ require_once 'phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php';
+ $this->formatter = new SimpleTestPlainResultFormatter();
+ }
+ else
+ if ($this->type == "summary")
+ {
+ require_once 'phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php';
+ $this->formatter = new SimpleTestSummaryResultFormatter();
+ }
+ else
+ if ($this->type == "debug")
+ {
+ require_once 'phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php';
+ $this->formatter = new SimpleTestDebugResultFormatter();
+ }
+ else
+ {
+ throw new BuildException("Formatter '" . $this->type . "' not implemented");
+ }
+ }
+}
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 100755
index 00000000..cfba9533
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * $Id: c0fa060b8f439f7d0013a0ec016ede4c5a76b42d $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: c0fa060b8f439f7d0013a0ec016ede4c5a76b42d $
+ * @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);
+
+ $sb = "";
+ /* 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";
+ }
+}
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 100755
index 00000000..8efcbb63
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * $Id: b9fbde1e1a21cccbcf6c3bdc29765cf0cf681e31 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: b9fbde1e1a21cccbcf6c3bdc29765cf0cf681e31 $
+ * @package phing.tasks.ext.simpletest
+ * @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;
+ }
+ }
+}
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 100755
index 00000000..e0a78f11
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * $Id: cd15496bfbce39bfd20fe17d52f9348848df0706 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: cd15496bfbce39bfd20fe17d52f9348848df0706 $
+ * @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);
+ }
+ }
+ }
+}
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 100755
index 00000000..8082e1ee
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php
@@ -0,0 +1,264 @@
+<?php
+/**
+ * $Id: d53b946f773798618069fe162d47ac5f6643662a $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: d53b946f773798618069fe162d47ac5f6643662a $
+ * @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;
+ private $debug = 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/SimpleTestDebugResultFormatter.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;
+ }
+
+ public function setDebug($debug)
+ {
+ $this->debug = $debug;
+ }
+
+ public function getDebug()
+ {
+ return $this->debug;
+ }
+
+ /**
+ * 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()
+ {
+ $suite= new TestSuite();
+
+ $filenames = $this->getFilenames();
+
+ foreach ($filenames as $testfile)
+ {
+ $suite->addFile($testfile);
+ }
+
+ if ($this->debug)
+ {
+ $fe = new SimpleTestFormatterElement();
+ $fe->setType('debug');
+ $fe->setUseFile(false);
+ $this->formatters[] = $fe;
+ }
+
+ 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($suite);
+
+ if ($this->testfailed && $this->formatters[0]->getFormatter() instanceof SimpleTestDebugResultFormatter )
+ {
+ $this->getDefaultOutput()->write("Failed tests: ");
+ $this->formatters[0]->getFormatter()->printFailingTests();
+ }
+
+ 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)
+ {
+ // SimpleTest 1.0.1 workaround
+ $formatterList[] = $fe->getFormatter();
+
+ $reporter->attachReporter(end($formatterList));
+ }
+
+ $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);
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php
new file mode 100755
index 00000000..5ffa668b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * $Id: 03b9f976a961a2688d51c9429087a98c31326f42 $
+ *
+ * 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';
+require_once 'simpletest/xml.php';
+
+/**
+ * Prints plain text output of the test to a specified Writer.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 03b9f976a961a2688d51c9429087a98c31326f42 $
+ * @package phing.tasks.ext.simpletest
+ * @since 2.2.0
+ */
+class SimpleTestXmlResultFormatter extends SimpleTestResultFormatter
+{
+ /**
+ * @var XmlReporter
+ */
+ private $logger = NULL;
+
+ private $xmlData = "";
+
+ function __construct()
+ {
+ $this->logger = new XmlReporter();
+ }
+
+ function getExtension()
+ {
+ return ".xml";
+ }
+
+ function getPreferredOutfile()
+ {
+ return "testsuites";
+ }
+
+ private function captureStart()
+ {
+ ob_start();
+ }
+
+ private function captureStop()
+ {
+ $this->xmlData .= ob_get_contents();
+ ob_end_clean();
+ }
+
+ function paintGroupStart($test_name, $size)
+ {
+ parent::paintGroupStart($test_name, $size);
+
+ $this->captureStart();
+ $this->logger->paintGroupStart($test_name, $size);
+ $this->captureStop();
+ }
+
+ function paintGroupEnd($test_name)
+ {
+ parent::paintGroupEnd($test_name);
+
+ $this->captureStart();
+ $this->logger->paintGroupEnd($test_name);
+ $this->captureStop();
+
+ if (count($this->_test_stack) == 0)
+ {
+ if ($this->out)
+ {
+ $this->out->write($this->xmlData);
+ $this->out->close();
+ }
+ }
+ }
+
+ function paintCaseStart($test_name)
+ {
+ $this->captureStart();
+ $this->logger->paintCaseStart($test_name);
+ $this->captureStop();
+ }
+
+ function paintCaseEnd($test_name)
+ {
+ $this->captureStart();
+ $this->logger->paintCaseEnd($test_name);
+ $this->captureStop();
+ }
+
+ function paintMethodStart($test_name)
+ {
+ $this->captureStart();
+ $this->logger->paintMethodStart($test_name);
+ $this->captureStop();
+ }
+
+ function paintMethodEnd($test_name)
+ {
+ $this->captureStart();
+ $this->logger->paintMethodEnd($test_name);
+ $this->captureStop();
+ }
+
+ function paintPass($message)
+ {
+ $this->captureStart();
+ $this->logger->paintPass($message);
+ $this->captureStop();
+ }
+
+ function paintError($message)
+ {
+ $this->captureStart();
+ $this->logger->paintError($message);
+ $this->captureStop();
+ }
+
+ function paintFail($message)
+ {
+ $this->captureStart();
+ $this->logger->paintFail($message);
+ $this->captureStop();
+ }
+
+ function paintException($exception)
+ {
+ $this->captureStart();
+ $this->logger->paintException($exception);
+ $this->captureStop();
+ }
+
+ function paintSkip($message)
+ {
+ $this->captureStart();
+ $this->logger->paintSkip($message);
+ $this->captureStop();
+ }
+
+ function paintMessage($message)
+ {
+ $this->captureStart();
+ $this->logger->paintMessage($message);
+ $this->captureStop();
+ }
+
+ function paintFormattedMessage($message)
+ {
+ $this->captureStart();
+ $this->logger->paintFormattedMessage($message);
+ $this->captureStop();
+ }
+
+ function paintSignal($type, $payload)
+ {
+ $this->captureStart();
+ $this->logger->paintSignal($type, $payload);
+ $this->captureStop();
+ }
+}
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 100755
index 00000000..ed9cb276
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php
@@ -0,0 +1,347 @@
+<?php
+/*
+ * $Id: b6c644f650a69cad32ced1d030685a7a7a46251c $
+ *
+ * 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';
+
+/**
+ * Base class for Subversion tasks
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Andrew Eddie <andrew.eddie@jamboworks.com>
+ * @version $Id: b6c644f650a69cad32ced1d030685a7a7a46251c $
+ * @package phing.tasks.ext.svn
+ * @see VersionControl_SVN
+ * @since 2.2.0
+ */
+abstract class SvnBaseTask extends Task
+{
+ private $workingCopy = "";
+
+ private $repositoryUrl = "";
+
+ private $svnPath = "/usr/bin/svn";
+
+ private $svn = NULL;
+
+ private $mode = "";
+
+ private $svnArgs = array();
+
+ private $svnSwitches = array();
+
+ private $toDir = "";
+
+ protected $fetchMode = VERSIONCONTROL_SVN_FETCHMODE_ASSOC;
+
+ /**
+ * 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("The SVN tasks depend 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;
+ }
+
+ //
+ // Args
+ //
+
+ /**
+ * 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;
+ }
+
+ //
+ // Switches
+ //
+
+ /**
+ * Sets the force switch
+ */
+ function setForce($value)
+ {
+ $this->svnSwitches['force'] = $value;
+ }
+
+ /**
+ * Returns the force switch
+ */
+ function getForce()
+ {
+ return isset( $this->svnSwitches['force'] ) ? $this->svnSwitches['force'] : '';
+ }
+
+ /**
+ * Sets the username of the user to export
+ */
+ function setUsername($value)
+ {
+ $this->svnSwitches['username'] = $value;
+ }
+
+ /**
+ * Returns the username
+ */
+ function getUsername()
+ {
+ return isset( $this->svnSwitches['username'] ) ? $this->svnSwitches['username'] : '';
+ }
+
+ /**
+ * Sets the password of the user to export
+ */
+ function setPassword($value)
+ {
+ $this->svnSwitches['password'] = $value;
+ }
+
+ /**
+ * Returns the password
+ */
+ function getPassword()
+ {
+ return isset( $this->svnSwitches['password'] ) ? $this->svnSwitches['password'] : '';
+ }
+
+ /**
+ * Sets the no-auth-cache switch
+ */
+ function setNoCache($value)
+ {
+ $this->svnSwitches['no-auth-cache'] = $value;
+ }
+
+ /**
+ * Returns the no-auth-cache switch
+ */
+ function getNoCache()
+ {
+ return isset( $this->svnSwitches['no-auth-cache'] ) ? $this->svnSwitches['no-auth-cache'] : '';
+ }
+
+ /**
+ * Sets the non-recursive switch
+ */
+ function setRecursive($value)
+ {
+ $this->svnSwitches['non-recursive'] = is_bool($value) ? !$value : true;
+ }
+
+ /**
+ * Returns the non-recursive switch
+ */
+ function getRecursive()
+ {
+ return isset( $this->svnSwitches['non-recursive'] ) ? !$this->svnSwitches['non-recursive'] : true;
+ }
+
+ /**
+ * Sets the ignore-externals switch
+ */
+ function setIgnoreExternals($value)
+ {
+ $this->svnSwitches['ignore-externals'] = $value;
+ }
+
+ /**
+ * Returns the ignore-externals switch
+ */
+ function getIgnoreExternals()
+ {
+ return isset( $this->svnSwitches['ignore-externals'] ) ? $this->svnSwitches['ignore-externals'] : '';
+ }
+
+ /**
+ * Sets the trust-server-cert switch
+ */
+ public function setTrustServerCert($value)
+ {
+ $this->svnSwitches['trust-server-cert'] = $value;
+ }
+
+ /**
+ * Returns the trust-server-cert switch
+ */
+ public function getTrustServerCert()
+ {
+ return isset($this->svnSwitches['trust-server-cert']) ? $this->svnSwitches['trust-server-cert'] : '';
+ }
+
+ /**
+ * 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' => $this->fetchMode, 'svn_path' => $this->getSvnPath());
+
+ // Pass array of subcommands we need to factory
+ $this->svn = VersionControl_SVN::factory($mode, $options);
+
+ $this->svn->use_escapeshellcmd = false;
+
+ 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
+ if ($mode=='info' )
+ {
+ if (is_file($this->workingCopy))
+ {
+ $this->svnArgs = array($this->workingCopy);
+ }
+ else
+ {
+ throw new BuildException("'".$this->workingCopy."' is not a directory nor a file");
+ }
+ }
+ 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);
+
+ $tempSwitches = $this->svnSwitches;
+
+ $tempSwitches = array_merge($tempSwitches, $switches);
+
+ if ($output = $this->svn->run($tempArgs, $tempSwitches))
+ {
+ return $output;
+ }
+ else
+ {
+ if (count($errs = $svnstack->getErrors()))
+ {
+ $err = current($errs);
+
+ $errorMessage = $err['message'];
+
+ if (isset($err['params']['errstr'])) {
+ $errorMessage = $err['params']['errstr'];
+ }
+
+ throw new BuildException("Failed to run the 'svn " . $this->mode . "' command: " . $errorMessage);
+ }
+ }
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCheckoutTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCheckoutTask.php
new file mode 100644
index 00000000..76dc976a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCheckoutTask.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * $Id: f8844430c9e30d1c603452d8763fbd1114d80051 $
+ *
+ * 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';
+
+/**
+ * Checks out a repository to a local directory
+ *
+ * @author Andrew Eddie <andrew.eddie@jamboworks.com>
+ * @version $Id: f8844430c9e30d1c603452d8763fbd1114d80051 $
+ * @package phing.tasks.ext.svn
+ * @since 2.3.0
+ */
+class SvnCheckoutTask extends SvnBaseTask
+{
+ /**
+ * Which Revision to Export
+ *
+ * @todo check if version_control_svn supports constants
+ *
+ * @var string
+ */
+ private $revision = 'HEAD';
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('checkout');
+
+ $this->log("Checking out SVN repository to '" . $this->getToDir() . "'". ($this->revision=='HEAD'?'':" (revision: {$this->revision})"));
+
+ // revision
+ $switches = array(
+ 'r' => $this->revision,
+ );
+
+ $this->run(array($this->getToDir()), $switches);
+ }
+
+ public function setRevision($revision)
+ {
+ $this->revision = $revision;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCommitTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCommitTask.php
new file mode 100644
index 00000000..7eb1ce7a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCommitTask.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * $Id: 6fdb36b57778f5c0cd46110fd36c8c261ced0e86 $
+ *
+ * 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';
+
+/**
+ * Commits changes in a local working copy to the repository
+ *
+ * @author Johan Persson <johanp@aditus.nu>
+ * @version $Id: 6fdb36b57778f5c0cd46110fd36c8c261ced0e86 $
+ * @package phing.tasks.ext.svn
+ * @since 2.4.0
+ */
+class SvnCommitTask extends SvnBaseTask
+{
+ /**
+ * Commit message
+ */
+ private $message = '';
+
+ /**
+ * Property name where we store the revision number of the just
+ * commited version.
+ */
+ private $propertyName = "svn.committedrevision";
+
+ /**
+ * Sets the commit message
+ */
+ function setMessage($message)
+ {
+ $this->message = $message;
+ }
+
+ /**
+ * Gets the commit message
+ */
+ function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Sets the name of the property to use for returned revision
+ */
+ function setPropertyName($propertyName)
+ {
+ $this->propertyName = $propertyName;
+ }
+
+ /**
+ * Returns the name of the property to use for returned revision
+ */
+ function getPropertyName()
+ {
+ return $this->propertyName;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ if( trim($this->message) === '' )
+ {
+ throw new BuildException('SVN Commit message can not be empty.');
+ }
+
+ $this->setup('commit');
+
+ $this->log("Commiting SVN working copy at '" . $this->getWorkingCopy() . "' with message '".$this->GetMessage()."'");
+
+ $output = $this->run(array(), array('message' => $this->GetMessage() ) );
+
+ if( preg_match('/[\s]*Committed revision[\s]+([\d]+)/', $output, $matches) )
+ {
+ $this->project->setProperty($this->getPropertyName(), $matches[1]);
+ }
+ else
+ {
+ /**
+ * If no new revision was committed set revision to "empty". Remember that
+ * this is not necessarily an error. It could be that the specified working
+ * copy is identical to to the copy in the repository and in that case
+ * there will be no update and no new revision number.
+ */
+ $this->project->setProperty($this->getPropertyName(), '' );
+ }
+
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCopyTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCopyTask.php
new file mode 100644
index 00000000..c1eb7089
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnCopyTask.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * 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';
+
+/**
+ * Copies a repository from the repository url to another
+ *
+ * @version $Id: 6f39598901c83ecaf8e7fcb9d4065f70b38324cb $
+ * @package phing.tasks.ext.svn
+ * @since 2.3.0
+ */
+class SvnCopyTask extends SvnBaseTask
+{
+ private $message = "";
+
+ /**
+ * Sets the message
+ */
+ function setMessage($message)
+ {
+ $this->message = $message;
+ }
+
+ /**
+ * Gets the message
+ */
+ function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('copy');
+
+ $this->log("Copying SVN repository from '" . $this->getRepositoryUrl() . "' to '" . $this->getToDir() . "'");
+
+ $options = array();
+
+ if (strlen($this->getMessage()) > 0) {
+ $options['message'] = $this->getMessage();
+ }
+
+ $this->run(array($this->getToDir()), $options);
+ }
+}
+
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 100755
index 00000000..e0b2e78b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * $Id: ca2d150a53b870fe410f5434f4d500decc7cda73 $
+ *
+ * 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
+ * with authentication
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @author Andrew Eddie <andrew.eddie@jamboworks.com>
+ * @version $Id: ca2d150a53b870fe410f5434f4d500decc7cda73 $
+ * @package phing.tasks.ext.svn
+ * @since 2.2.0
+ */
+class SvnExportTask extends SvnBaseTask
+{
+ /**
+ * Which Revision to Export
+ *
+ * @todo check if version_control_svn supports constants
+ *
+ * @var string
+ */
+ private $revision = 'HEAD';
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('export');
+
+ $this->log("Exporting SVN repository to '" . $this->getToDir() . "'");
+
+ $switches = array();
+
+ if (!empty($this->revision)) {
+ $switches['r'] = $this->revision;
+ }
+
+ $this->run(array($this->getToDir()), $switches);
+ }
+
+ public function setRevision($revision)
+ {
+ $this->revision = $revision;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnInfoTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnInfoTask.php
new file mode 100644
index 00000000..68111d74
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnInfoTask.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * $Id: 36ffb2ececed4c83c9ca7ad3674b3fa11074f2a5 $
+ *
+ * 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';
+
+/**
+ * Parses the output of 'svn info --xml' and
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: 36ffb2ececed4c83c9ca7ad3674b3fa11074f2a5 $
+ * @package phing.tasks.ext.svn
+ * @see VersionControl_SVN
+ * @since 2.4.9
+ */
+class SvnInfoTask extends SvnBaseTask
+{
+ private $propertyName = "svn.info";
+
+ private $element = 'url';
+ private $subElement = null;
+
+ /**
+ * Sets the name of the property to use
+ */
+ public function setPropertyName($propertyName)
+ {
+ $this->propertyName = $propertyName;
+ }
+
+ /**
+ * Returns the name of the property to use
+ */
+ public function getPropertyName()
+ {
+ return $this->propertyName;
+ }
+
+ /**
+ * Sets the name of the xml element to use
+ */
+ public function setElement($element)
+ {
+ $this->element = $element;
+ }
+
+ /**
+ * Returns the name of the xml element to use
+ */
+ public function getElement()
+ {
+ return $this->element;
+ }
+
+ /**
+ * Sets the name of the xml sub element to use
+ */
+ public function setSubElement($subElement)
+ {
+ $this->subElement = $subElement;
+ }
+
+ /**
+ * Returns the name of the xml sub element to use
+ */
+ public function getSubElement()
+ {
+ return $this->subElement;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('info');
+
+ $output = $this->run(array('--xml', '--incremental'));
+
+ if ($xmlObj = @simplexml_load_string($output)) {
+ $object = $xmlObj->{$this->element};
+
+ if (!empty($this->subElement)) {
+ $object = $object->{$this->subElement};
+ }
+
+ $this->project->setProperty($this->getPropertyName(), (string) $object);
+ } else {
+ throw new BuildException("Failed to parse the output of 'svn info --xml'.");
+ }
+ }
+}
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 100755
index 00000000..7305c27b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php
@@ -0,0 +1,120 @@
+<?php
+/**
+ * $Id: 74d61db8c11978a2383f071b7ab7ed0afae6953c $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: 74d61db8c11978a2383f071b7ab7ed0afae6953c $
+ * @package phing.tasks.ext.svn
+ * @see VersionControl_SVN
+ * @since 2.1.0
+ */
+class SvnLastRevisionTask extends SvnBaseTask
+{
+ private $propertyName = "svn.lastrevision";
+ private $forceCompatible = false;
+ private $lastChanged = false;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets whether to force compatibility with older SVN versions (< 1.2)
+ */
+ public function setForceCompatible($force)
+ {
+ $this->forceCompatible = (bool) $force;
+ }
+
+ /**
+ * Sets whether to retrieve the last changed revision
+ */
+ public function setLastChanged($lastChanged)
+ {
+ $this->lastChanged = (bool) $lastChanged;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('info');
+
+ if ($this->forceCompatible)
+ {
+ $output = $this->run();
+
+ if ($this->lastChanged) {
+ $found = preg_match('/Rev:[\s]+([\d]+)/', $output, $matches);
+ } else {
+ $found = preg_match('/Last Changed Rev:[\s]+([\d]+)/', $output, $matches);
+ }
+
+ if ($found)
+ {
+ $this->project->setProperty($this->getPropertyName(), $matches[1]);
+ }
+ else
+ {
+ throw new BuildException("Failed to parse the output of 'svn info'.");
+ }
+ }
+ else
+ {
+ $output = $this->run(array('--xml'));
+
+ if ($xmlObj = @simplexml_load_string($output))
+ {
+ if ($this->lastChanged) {
+ $lastRevision = (int)$xmlObj->entry->commit['revision'];
+ } else {
+ $lastRevision = (int)$xmlObj->entry['revision'];
+ }
+
+ $this->project->setProperty($this->getPropertyName(), $lastRevision);
+ }
+ else
+ {
+ throw new BuildException("Failed to parse the output of 'svn info --xml'.");
+ }
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnListTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnListTask.php
new file mode 100755
index 00000000..63d8445c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnListTask.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * $Id: 5dfcc23bc58efaad0eb11ef4964bcd7be0fb99e9 $
+ *
+ * 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 output of a list command on a workingcopy or repositoryurl in a property.
+ * This stems from the SvnLastRevisionTask.
+ *
+ * @author Anton Stöckl <anton@stoeckl.de>
+ * @author Michiel Rook <mrook@php.net> (SvnLastRevisionTask)
+ * @version $Id: 5dfcc23bc58efaad0eb11ef4964bcd7be0fb99e9 $
+ * @package phing.tasks.ext.svn
+ * @see VersionControl_SVN
+ * @since 2.1.0
+ */
+class SvnListTask extends SvnBaseTask
+{
+ private $propertyName = "svn.list";
+ private $forceCompatible = true;
+ private $limit = null;
+ private $orderDescending = false;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets whether to force compatibility with older SVN versions (< 1.2)
+ */
+ public function setForceCompatible($force)
+ {
+ //$this->forceCompatible = (bool) $force;
+ // see below, we need this to be true as xml mode does not work
+ }
+
+ /**
+ * Sets the max num of tags to display
+ */
+ function setLimit($limit)
+ {
+ $this->limit = (int) $limit;
+ }
+
+ /**
+ * Sets whether to sort tags in descending order
+ */
+ function setOrderDescending($orderDescending)
+ {
+ $this->orderDescending = (bool) $orderDescending;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('list');
+
+ if ($this->forceCompatible) {
+ $output = $this->run(array('--verbose'));
+ $result = null;
+
+ $lines = $output['.']['name'];
+
+ if ($this->orderDescending) {
+ $lines = array_reverse($lines);
+ }
+
+ $count = 0;
+ foreach ($lines as $line) {
+ if ($this->limit > 0 && $count >= $this->limit) {
+ break;
+ }
+ if (preg_match('@\s+(\d+)\s+(\S+)\s+(\S+ \S+ \S+)\s+(\S+)@', $line, $matches)) {
+ if ($matches[4] == '.') {
+ continue;
+ }
+ $result .= (!empty($result)) ? "\n" : '';
+ $result .= $matches[1] . ' | ' . $matches[2] . ' | ' . $matches[3] . ' | ' . $matches[4];
+ $count++;
+ }
+ }
+
+ if (!empty($result)) {
+ $this->project->setProperty($this->getPropertyName(), $result);
+ } else {
+ throw new BuildException("Failed to parse the output of 'svn list --verbose'.");
+ }
+ } else {
+ // this is not possible at the moment as SvnBaseTask always uses fetchmode ASSOC
+ // which transfers everything into nasty assoc array instead of xml
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLogTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLogTask.php
new file mode 100755
index 00000000..7f5c4025
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnLogTask.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * $Id: fc8bc4cf4caa997c13dd66095997fa5478c47959 $
+ *
+ * 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 output of a log command on a workingcopy or repositoryurl in a property.
+ * This stems from the SvnLastRevisionTask.
+ *
+ * @author Anton Stöckl <anton@stoeckl.de>
+ * @author Michiel Rook <mrook@php.net> (SvnLastRevisionTask)
+ * @version $Id: fc8bc4cf4caa997c13dd66095997fa5478c47959 $
+ * @package phing.tasks.ext.svn
+ * @see VersionControl_SVN
+ * @since 2.1.0
+ */
+class SvnLogTask extends SvnBaseTask
+{
+ private $propertyName = "svn.log";
+ private $forceCompatible = true;
+ private $limit = null;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets whether to force compatibility with older SVN versions (< 1.2)
+ */
+ public function setForceCompatible($force)
+ {
+ //$this->forceCompatible = (bool) $force;
+ // see below, we need this to be true as xml mode does not work
+ }
+
+ /**
+ * Sets the max num of log entries to get from svn
+ */
+ function setLimit($limit)
+ {
+ $this->limit = (int) $limit;
+ }
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('log');
+
+ $switches= array();
+ if ($this->limit > 0) {
+ $switches['limit'] = $this->limit;
+ }
+
+ if ($this->forceCompatible) {
+ $output = $this->run(array(), $switches);
+ $result = null;
+
+ foreach ($output as $line) {
+ $result .= (!empty($result)) ? "\n" : '';
+ $result .= "{$line['REVISION']} | {$line['AUTHOR']} | {$line['DATE']} | {$line['MSG']}";
+ }
+
+ if (!empty($result)) {
+ $this->project->setProperty($this->getPropertyName(), $result);
+ } else {
+ throw new BuildException("Failed to parse the output of 'svn log'.");
+ }
+ } else {
+ // this is not possible at the moment as SvnBaseTask always uses fetchmode ASSOC
+ // which transfers everything into nasty assoc array instead of xml
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnSwitchTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnSwitchTask.php
new file mode 100644
index 00000000..cb6c5ca4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnSwitchTask.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * $Id: 2beb14d928ee47f36cceb9467b4a2ac9d2c81ef4 $
+ *
+ * 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';
+
+/**
+ * Switches a repository at a given local directory to a different location
+ *
+ * @author Dom Udall <dom.udall@clock.co.uk>
+ * @version $Id: 2beb14d928ee47f36cceb9467b4a2ac9d2c81ef4 $
+ * @package phing.tasks.ext.svn
+ * @since 2.4.3
+ */
+class SvnSwitchTask extends SvnBaseTask
+{
+ /**
+ * Which Revision to Export
+ *
+ * @todo check if version_control_svn supports constants
+ *
+ * @var string
+ */
+ private $revision = 'HEAD';
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('switch');
+
+ $this->log("Switching SVN repository at '" . $this->getToDir() . "' to '" . $this->getRepositoryUrl() . "' "
+ . ($this->getRevision()=='HEAD'?'':" (revision: {$this->getRevision()})"));
+
+ // revision
+ $switches = array(
+ 'r' => $this->getRevision(),
+ );
+
+ $this->run(array($this->getToDir()), $switches);
+ }
+
+ public function setRevision($revision)
+ {
+ $this->revision = $revision;
+ }
+
+ public function getRevision()
+ {
+ return $this->revision;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/svn/SvnUpdateTask.php b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnUpdateTask.php
new file mode 100644
index 00000000..c70039fc
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/svn/SvnUpdateTask.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * $Id: 9f5e4de2948b03eb6c9e459b1065bcedd851c025 $
+ *
+ * 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';
+
+/**
+ * Updates a repository in local directory
+ *
+ * @author Andrew Eddie <andrew.eddie@jamboworks.com>
+ * @version $Id: 9f5e4de2948b03eb6c9e459b1065bcedd851c025 $
+ * @package phing.tasks.ext.svn
+ * @since 2.3.0
+ */
+class SvnUpdateTask extends SvnBaseTask
+{
+ /**
+ * Which Revision to Export
+ *
+ * @todo check if version_control_svn supports constants
+ *
+ * @var string
+ */
+ private $revision = 'HEAD';
+
+ /**
+ * The main entry point
+ *
+ * @throws BuildException
+ */
+ function main()
+ {
+ $this->setup('update');
+
+ $this->log("Updating SVN repository at '" . $this->getToDir() . "'". ($this->revision=='HEAD'?'':" (revision: {$this->revision})"));
+
+ // revision
+ $switches = array(
+ 'r' => $this->revision,
+ );
+
+ $this->run(array($this->getToDir()), $switches);
+ }
+
+ public function setRevision($revision)
+ {
+ $this->revision = $revision;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardEncodeTask.php b/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardEncodeTask.php
new file mode 100644
index 00000000..33d2e4e3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardEncodeTask.php
@@ -0,0 +1,510 @@
+<?php
+
+/*
+ * $Id: cdbb2883ab70c650896a465a872b3da30f13eb00 $
+ *
+ * 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';
+
+/**
+ * Encodes files using Zeng Guard Encoder
+ *
+ * @author Petr Rybak <petr@rynawe.net>
+ * @version $Id: cdbb2883ab70c650896a465a872b3da30f13eb00 $
+ * @package phing.tasks.ext.zendguard
+ * @since 2.4.3
+ */
+class ZendGuardEncodeTask extends MatchingTask
+{
+ protected $filesets = array();
+ protected $encodeCommand;
+
+
+ /**
+ * TASK PROPERTIES
+ *
+ * See http://static.zend.com/topics/Zend-Guard-User-Guidev5x.pdf
+ * for more information on how to use ZendGuard
+ *
+ */
+ /**
+ * Permanently deletes (see warning below) the original source files specified in the
+ * SourceInputPath and saves the encoded files in its place.
+ * This option has no option parameter.
+ * When this option is use, do not use the output_file parameter.
+ *
+ * Warning:
+ * To avoid permanent loss of non-encoded scripts, make a backup. Deleted files
+ * cannot be restored or recovered and will be permanently deleted with this option.
+ * If you are unsure about deleting the source files, use the ––rename-source option
+ * instead
+ *
+ * @var bool
+ */
+ protected $deleteSource = true;
+ /**
+ * Move the original source file to <input_file>.<renameSourceExt> and save the encoded file in its
+ * place.
+ *
+ * If specified deleteSource will be automatically disabled.
+ *
+ * @var string
+ */
+ protected $renameSourceExt = null;
+ /**
+ * Turns short PHP tag (“<?” ) recognition either on or off.
+ * On or off must be specified as an argument when using this option.
+ * The default, when option is not used in the command-line, is - on
+ *
+ * @var bool
+ */
+ protected $shortTags = true;
+ /**
+ * Turn ASP tag (“<%” ) recognition on/off. (default: off). On or off must be specified
+ * as an argument when using this option.
+ * The default, when this option is not used in the command-line, is - off
+ *
+ * @var bool
+ */
+ protected $aspTags = false;
+ /**
+ *
+ * Disables the PHP-compatible header that is added to the top of every encoded file
+ * by default. Encoded files generated with this option will not display a meaningful
+ * error when loaded by PHP that doesn't have the Zend Optimizer properly installed.
+ * Using this option saves approximately 1.5KB for every encoded file. Do not use it
+ * unless disk space constraints are critica
+ *
+ * @var bool
+ */
+ protected $noHeader = false;
+ /**
+ * If cryptography should be used to encode the source code
+ *
+ * @var bool
+ */
+ protected $useCrypto = false;
+ /**
+ * Force cooperation with other encoded files only. This option generates files that
+ * work exclusively with associated encoded files. Associated encoded files are
+ * those generated by the same company. Files that do not share the same encoded
+ * company association cannot call these files
+ *
+ * @var bool
+ */
+ protected $encodedOnly = false;
+ /**
+ * Allow encoding previously encoded files. (NOT recommended!)
+ *
+ * @var bool
+ */
+ protected $forceEncode = false;
+ /**
+ * Make an encoded file to expire on the given date. Date is in yyyy-mm-dd format.
+ *
+ * @var string
+ */
+ protected $expires = null;
+ /**
+ * Level of obfuscation. Defaults to 0 (no obfuscation).
+ *
+ * @var int
+ */
+ protected $obfuscationLevel = 0;
+ /**
+ * Optimization mask. (default value: [+++++++])
+ * opt_mask is an integer representing a bit-mask.
+ * The default value enables all of the optimization passes.
+ * Each optimization pass of the Zend Optimizer can be turned on or off based on
+ * the mask entered
+ *
+ * @var int
+ */
+ protected $optMask = null;
+ /**
+ * Path to the zend encoder binary
+ *
+ * @var string
+ */
+ protected $zendEncoderPath = null;
+ /**
+ * Path to private key for licensing
+ *
+ * @var string
+ */
+ protected $privateKeyPath = null;
+ /**
+ * Enable licensing.
+ * If enabled, productName must be defined.
+ *
+ * @var bool
+ */
+ protected $licenseProduct = false;
+ /**
+ * If true the ownership, permissions and timestamps
+ * of the encoded files won't be preserved.
+ *
+ * @var bool
+ */
+ protected $ignoreFileModes = false;
+ /**
+ * Enable signing
+ * If enabled, productName must be defined.
+ *
+ * @var bool
+ */
+ protected $signProduct = false;
+ /**
+ * Product name. Must be defined if licenseProduct
+ * or signProduct is set to 1
+ *
+ * @var string
+ */
+ protected $productName = null;
+ /**
+ * Embed the information in the specified file into the header of the encoded file
+ * (overrides noHeader)
+ *
+ * @var string
+ */
+ protected $prologFile = null;
+
+ /**
+ * TASK PROPERTIES SETTERS
+ */
+ public function setZendEncoderPath($value)
+ {
+ $this->zendEncoderPath = $value;
+ }
+
+ public function setPrivateKeyPath($value)
+ {
+ $this->privateKeyPath = $value;
+ }
+
+ public function setShortTags($value)
+ {
+ $this->shortTags = (bool) $value;
+ }
+
+ public function setAspTags($value)
+ {
+ $this->aspTags = (bool) $value;
+ }
+
+ public function setDeleteSource($value)
+ {
+ $this->shortTags = (bool) $value;
+ }
+
+ public function setUseCrypto($value)
+ {
+ $this->useCrypto = (bool) $value;
+ }
+
+ public function setObfuscationLevel($value)
+ {
+ $this->obfuscationLevel = (int) $value;
+ }
+
+ public function setLicenseProduct($value)
+ {
+ $this->licenseProduct = (bool) $value;
+ }
+
+ public function setPrologFile($value)
+ {
+ $this->prologFile = $value;
+ }
+
+ public function setSignProduct($value)
+ {
+ $this->signProduct = (bool) $value;
+ }
+
+ public function setForceEncode($value)
+ {
+ $this->forceEncode = (bool) $value;
+ }
+
+ public function setEncodedOnly($value)
+ {
+ $this->encodedOnly = (bool) $value;
+ }
+
+ public function setIgnoreFileModes($value)
+ {
+ $this->ignoreFileModes = (bool) $value;
+ }
+
+ public function setExpires($value)
+ {
+ $this->expires = $value;
+ }
+
+ public function setProductName($value)
+ {
+ $this->productName = $value;
+ }
+
+ public function setOptMask($value)
+ {
+ $this->optMask = (int) $value;
+ }
+
+ public function setRenameSourceExt($value)
+ {
+ $this->renameSourceExt = $value;
+ }
+
+ public function setNoHeader($value)
+ {
+ $this->noHeader = (bool) $value;
+ }
+
+ /**
+ * Add a new fileset.
+ *
+ * @return FileSet
+ */
+ public function createFileSet()
+ {
+ $this->fileset = new ZendGuardFileSet();
+ $this->filesets[] = $this->fileset;
+ return $this->fileset;
+ }
+
+ /**
+ * Verifies that the configuration is correct
+ *
+ * @throws BuildException
+ */
+ protected function verifyConfiguration()
+ {
+ // Check that the zend encoder path is specified
+ if (empty($this->zendEncoderPath)) {
+ throw new BuildException("Zend Encoder path must be specified");
+ }
+
+ // verify that the zend encoder binary exists
+ if (!file_exists($this->zendEncoderPath)) {
+ throw new BuildException("Zend Encoder not found on path " . $this->zendEncoderPath);
+ }
+
+ // if either sign or license is required the private key path needs to be defined
+ // and the file has to exist and product name has to be specified
+ if ($this->signProduct || $this->licenseProduct) {
+ if (empty($this->privateKeyPath)) {
+ throw new BuildException("Licensing or signing requested but privateKeyPath not provided.");
+ }
+ if (!is_readable($this->privateKeyPath)) {
+ throw new BuildException("Licensing or signing requested but private key path doesn't exist or is unreadable.");
+ }
+ if (empty($this->productName)) {
+ throw new BuildException("Licensing or signing requested but product name not provided.");
+ }
+ }
+
+ // verify prolog file exists
+ if (!empty($this->prologFile)) {
+ if (!file_exists($this->prologFile)) {
+ throw new BuildException("The prolog file doesn't exist: " . $this->prologFile);
+ }
+ }
+ }
+
+ /**
+ * Do the work
+ *
+ * @throws BuildException
+ */
+ public function main()
+ {
+ $this->verifyConfiguration();
+ $this->prepareEncoderCommand();
+
+ try {
+ if (empty($this->filesets)) {
+ throw new BuildException("You must supply nested fileset.",
+ $this->getLocation());
+ }
+
+ $encodedFilesCounter = 0;
+
+ foreach ($this->filesets as $fs) {
+ /* @var $fs FileSet */
+
+ /* @var $fsBasedir PhingFile */
+ $fsBasedir = $fs->getDir($this->project)->getAbsolutePath();
+
+ $files = $fs->getFiles($this->project, false);
+
+ foreach ($files as $file) {
+ $f = new PhingFile($fsBasedir, $file);
+
+ if ($f->isFile()) {
+ $path = $f->getAbsolutePath();
+
+ $this->log("Encoding " . $path, Project::MSG_VERBOSE);
+ $this->encodeFile($path);
+
+ $encodedFilesCounter++;
+ }
+ }
+ }
+
+ $this->log("Encoded files: " . $encodedFilesCounter);
+ } catch (IOException $ioe) {
+ $msg = "Problem encoding files: " . $ioe->getMessage();
+ throw new BuildException($msg, $ioe, $this->getLocation());
+ }
+ }
+
+ /**
+ * Prepares the main part of the command that will be
+ * used to encode the given file(s).
+ */
+ protected function prepareEncoderCommand()
+ {
+ $command = $this->zendEncoderPath . " \\\n";
+
+ if (!empty($this->renameSourceExt)) {
+ $command .= " --rename-source " . $this->renameSourceExt . " \\\n";
+ } elseif ($this->deleteSource) {
+ // delete source
+ $command .= " --delete-source \\\n";
+ }
+
+ // short tags
+ $command .= " --short-tags " . (($this->shortTags) ? 'on' : 'off') . " \\\n";
+
+ // asp tags
+ $command .= " --asp-tags " . (($this->aspTags) ? 'on' : 'off') . " \\\n";
+
+ // use crypto
+ if ($this->useCrypto) {
+ $command .= " --use-crypto \\\n";
+ }
+
+ // ignore file modes
+ if ($this->ignoreFileModes) {
+ $command .= " --ignore-file-modes \\\n";
+ }
+
+ // force encode
+ if ($this->forceEncode) {
+ $command .= " --force-encode \\\n";
+ }
+
+ // expires
+ if (!empty($this->expires)) {
+ $command .= " --expires " . $this->expires . " \\\n";
+ }
+
+ // insert prolog file name or no-header
+ if (!empty($this->prologFile)) {
+ $command .= " --prolog-filename " . $this->prologFile . " \\\n";
+ } elseif ($this->noHeader) {
+ // no-header
+ $command .= " --no-header \\\n";
+ }
+
+ // obfuscation level
+ if ($this->obfuscationLevel > 0) {
+ $command .= " --obfuscation-level " . $this->obfuscationLevel . " \\\n";
+ }
+
+ // encoded only
+ if ($this->encodedOnly) {
+ $command .= " --encoded-only \\\n";
+ }
+
+ // opt mask
+ if (null !== $this->optMask) {
+ $command .= " --optimizations " . $this->optMask . " \\\n";
+ }
+
+ // Signing or licensing
+ if ($this->signProduct) {
+ $command .= " --sign-product " . $this->productName . " --private-key " . $this->privateKeyPath . " \\\n";
+ } elseif ($this->licenseProduct) {
+ $command .= " --license-product " . $this->productName . " --private-key " . $this->privateKeyPath . " \\\n";
+ }
+
+ // add a blank space
+ $command .= " ";
+
+ $this->encodeCommand = $command;
+
+ }
+
+ /**
+ * Encodes a file using currently defined Zend Guard settings
+ *
+ * @param string $filePath Path to the encoded file
+ */
+ protected function encodeFile($filePath)
+ {
+ $command = $this->encodeCommand . $filePath . ' 2>&1';
+
+ $this->log('Running: ' . $command, Project::MSG_VERBOSE);
+
+ $tmp = exec($command, $output, $return_var);
+ if ($return_var !== 0) {
+ throw new BuildException("Encoding failed. \n Msg: " . $tmp . " \n Encode command: " . $command);
+ }
+
+ return true;
+ }
+
+}
+
+/**
+ * This is a FileSet with the to specify permissions.
+ *
+ * Permissions are currently not implemented by PEAR Archive_Tar,
+ * but hopefully they will be in the future.
+ *
+ * @package phing.tasks.ext.zendguard
+ */
+class ZendGuardFileSet extends FileSet
+{
+ private $files = null;
+
+ /**
+ * 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, $includeEmpty = true)
+ {
+
+ if ($this->files === null) {
+
+ $ds = $this->getDirectoryScanner($p);
+ $this->files = $ds->getIncludedFiles();
+ } // if ($this->files===null)
+
+ return $this->files;
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardLicenseTask.php b/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardLicenseTask.php
new file mode 100644
index 00000000..2a3f71ca
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardLicenseTask.php
@@ -0,0 +1,524 @@
+<?php
+
+/*
+ * $Id: 96af59b9cbecaf7f146dffab1d0b5a806a56b47f $
+ *
+ * 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>.
+ */
+
+/**
+ * Produce license files using Zeng Guard.
+ * The task can produce a license file from the given
+ * license properties or it can use a template.
+ *
+ * @author Petr Rybak <petr@rynawe.net>
+ * @version $Id: 96af59b9cbecaf7f146dffab1d0b5a806a56b47f $
+ * @package phing.tasks.ext.zendguard
+ * @since 2.4.3
+ */
+class ZendGuardLicenseTask extends Task
+{
+ protected $zendsignCommand;
+ private $tmpLicensePath;
+
+ /**
+ * TASK PROPERTIES
+ *
+ * See http://static.zend.com/topics/Zend-Guard-User-Guidev5x.pdf
+ * for more information on how to use ZendGuard
+ *
+ */
+ /**
+ * Path to Zend Guard zendenc_sign executable
+ *
+ * @var string
+ */
+ protected $zendsignPath;
+ /**
+ * Path to private key that will be used to sign the license
+ *
+ * @var string
+ */
+ protected $privateKeyPath;
+ /**
+ * Where to store the signed license file
+ *
+ * @var string
+ */
+ protected $outputFile;
+ /**
+ * Path to license template. If specified all
+ * license properties will be ignored and the
+ * template will be used to generate the file.
+ *
+ * @var string
+ */
+ protected $licenseTemplate;
+ /**
+ * The name assigned to Product. This must be the same name used when encoding
+ * the PHP files.
+ *
+ * REQUIRED
+ *
+ * @var string
+ */
+ protected $productName;
+ /**
+ * The Name of the Registered owner of the license.
+ *
+ * REQUIRED
+ *
+ * @var string
+ */
+ protected $registeredTo;
+ /**
+ * Expiration date of the license. Used if the license is issued with a date restriction.
+ * Possible values:
+ * - 'Never', '0' or false: the license won't expire
+ * - A Date in format DD-MM-YYYY to set expiration for that date
+ * - Relative date supported by the PHP strtotime function (e.g. +1 month)
+ *
+ * REQUIRED
+ *
+ * @var string
+ */
+ protected $expires;
+ /**
+ * Limits the use of the license to IP addresses that fall within specification. Supports
+ * wildcards for any of the IP place holders, as well as the two types of net masks
+ * (filters).
+ * Netmask pair An IP a.b.c.d, and a netmask w.x.y.z. (That is., 10.1.0.0/255.255.0.0),
+ * where the binary of mask is applied to filter IP addresses.
+ * ip/nnn (similar to a CIDR specification) This mask consists of nnn high-order 1 bits.
+ * (That is, 10.1.0.0/16 is the same as 10.1.0.0/255.255.0.0). Instead of spelling out
+ * the bits of the subnet mask, this mask notation is simply listed as the number of 1s
+ * bits that start the mask. Rather than writing the address and subnet mask as
+ * 192.60.128.0/255.255.252.0 the network address would be written simply as:
+ * 192.60.128.0/22 which indicates starting address of the network and number of 1s
+ * bits (22) in the network portion of the address. The mask in binary is
+ * (11111111.11111111.11111100.00000000).
+ *
+ * OPTIONAL
+ *
+ * Example (Wildcard):
+ * IP-Range = 10.1.*.*
+ * Example (Net Mask):
+ * IP-Range = 10.1.0.0/255.255.0.0
+ * Example (Net Mask):
+ * IP-Range = 10.1.0.0/16
+ *
+ * @var string
+ */
+ protected $ipRange;
+ /**
+ * Coded string (Zend Host ID) used to lock the license to a specific hardware. The
+ * Zend Host ID obtained from the machine where the encoded files and license are
+ * to be installed. The Zend Host ID code can be obtained by using the zendid utility.
+ * For more details, see Getting the Zend Host ID.
+ *
+ * REQUIRED if Hardware-Locked is set equal to YES.
+ * Meaningless if Hardware-Locked is set equal to NO.
+ *
+ * User semicolon to enter more than one Host-ID
+ *
+ * Example:
+ * Host-ID = H:MFM43-Q9CXC-B9EDX-GWYSU;H:MFM43-Q9CXC-B9EDX-GWYTY
+ *
+ * @var string
+ */
+ protected $hostID;
+ /**
+ * Option that indicates if the license will be locked to a specific machine
+ * using the Zend Host ID code(s). If set to YES, the Host-ID is required.
+ *
+ * OPTIONAL
+ *
+ * @var bool
+ */
+ protected $hardwareLocked;
+ /**
+ * Semi-colon separated user defined values that will be part of the license. These values
+ * CANNOT be modified after the license is produced. Modification
+ * would invalidate the license.
+ *
+ * OPTIONAL
+ * Example:
+ * Tea=Mint Flavor;Coffee=Arabica
+ *
+ * @var string
+ */
+ protected $userDefinedValues;
+ /**
+ * Semi-colon separated user defined x-values that will be part of the license. These values
+ * CAN be modified after the license is produced. Modification
+ * won't invalidate the license.
+ *
+ * OPTIONAL
+ * Example:
+ * Tea=Mint Flavor;Coffee=Arabica
+ *
+ * @var string
+ */
+ protected $xUserDefinedValues;
+
+
+ public function setLicenseTemplate($value)
+ {
+ $this->licenseTemplate = $value;
+ }
+
+ public function setProductName($productName)
+ {
+ $this->productName = $productName;
+ }
+
+ public function setRegisteredTo($registeredTo)
+ {
+ $this->registeredTo = $registeredTo;
+ }
+
+ /**
+ * Process the expires property. If the value is
+ * empty (false, '', ...) it will set the value to 'Never'
+ * Otherwise it will run the value through strtotime so relative
+ * date and time notation can be used (e.g. +1 month)
+ *
+ * @param mixed $expires
+ *
+ * @return string
+ */
+ public function setExpires($expires)
+ {
+ // process the expires value
+ if (false === $expires || '0' === $expires || strtolower($expires) == 'never' || '' === $expires) {
+ $this->expires = 'Never';
+ } else {
+ $time = strtotime($expires);
+ if (!$time) {
+ throw new BuildException("Unsupported expires format: " . $expires);
+ }
+ $this->expires = date('d-M-Y', $time);
+ }
+ }
+
+ public function setIpRange($iprange)
+ {
+ $this->ipRange = $iprange;
+ }
+
+ public function setHostID($hostID)
+ {
+ $this->hostID = $hostID;
+ }
+
+ public function setHardwareLocked($hardwareLocked)
+ {
+ $this->hardwareLocked = (bool) $hardwareLocked;
+ }
+
+ public function setUserDefinedValues($userDefinedValues)
+ {
+ $this->userDefinedValues = $userDefinedValues;
+ }
+
+ public function setXUserDefinedValues($xUserDefinedValues)
+ {
+ $this->xUserDefinedValues = $xUserDefinedValues;
+ }
+
+ public function setZendsignPath($zendsignPath)
+ {
+ $this->zendsignPath = $zendsignPath;
+ }
+
+ public function setPrivateKeyPath($privateKeyPath)
+ {
+ $this->privateKeyPath = $privateKeyPath;
+ }
+
+ public function setOutputFile($outputFile)
+ {
+ $this->outputFile = $outputFile;
+ }
+
+ /**
+ * Verifies that the configuration is correct
+ *
+ * @throws BuildException
+ */
+ protected function verifyConfiguration()
+ {
+ // Check that the zend encoder path is specified
+ if (empty($this->zendsignPath)) {
+ throw new BuildException("Zendenc_sign path must be specified");
+ }
+ // verify that the zend encoder binary exists
+ if (!file_exists($this->zendsignPath)) {
+ throw new BuildException("Zendenc_sign not found on path " . $this->zendsignPath);
+ }
+
+ // verify that the private key path is defined
+ if (empty($this->privateKeyPath)) {
+ throw new BuildException("You must define privateKeyPath.");
+ }
+ // verify that the private key file is readable
+ if (!is_readable($this->privateKeyPath)) {
+ throw new BuildException("Private key file is not readable: " . $this->privateKeyPath);
+ }
+
+ // if template is passed, verify that it is readable
+ if (!empty($this->licenseTemplate)) {
+ if (!is_readable($this->licenseTemplate)) {
+ throw new BuildException("License template file is not readable " . $this->licenseTemplate);
+ }
+ }
+
+ // check that output file path is defined
+ if (empty($this->outputFile)) {
+ throw new BuildException("Path where to store the result file needs to be defined in outputFile property");
+ }
+
+ // if license template is NOT provided check that all required parameters are defined
+ if (empty($this->licenseTemplate)) {
+
+ // check productName
+ if (empty($this->productName)) {
+ throw new BuildException("Property must be defined: productName");
+ }
+
+ // check expires
+ if (null === $this->expires) {
+ throw new BuildException("Property must be defined: expires");
+ }
+
+ // check registeredTo
+ if (empty($this->registeredTo)) {
+ throw new BuildException("Property must be defined: registeredTo");
+ }
+
+ // check hardwareLocked
+ if (null === $this->hardwareLocked) {
+ throw new BuildException("Property must be defined: hardwareLocked");
+ }
+
+ // if hardwareLocked is set to true, check that Host-ID is set
+ if ($this->hardwareLocked) {
+ if (empty($this->hostID)) {
+ throw new BuildException("If you set hardwareLocked to true hostID must be provided");
+ }
+ }
+ }
+ }
+
+ /**
+ * Do the work
+ *
+ * @throws BuildException
+ */
+ public function main()
+ {
+ try {
+ $this->verifyConfiguration();
+
+ $this->generateLicense();
+ } catch (Exception $e) {
+ // remove the license temp file if it was created
+ $this->cleanupTmpFiles();
+
+ throw $e;
+ }
+ $this->cleanupTmpFiles();
+ }
+
+ /**
+ * If temporary license file was created during the process
+ * this will remove it
+ *
+ * @return void
+ */
+ private function cleanupTmpFiles()
+ {
+ if (!empty($this->tmpLicensePath) && file_exists($this->tmpLicensePath)) {
+ $this->log("Deleting temporary license template " . $this->tmpLicensePath, Project::MSG_VERBOSE);
+
+ unlink($this->tmpLicensePath);
+ }
+ }
+
+ /**
+ * Prepares and returns the command that will be
+ * used to create the license.
+ *
+ * @return string
+ */
+ protected function prepareSignCommand()
+ {
+ $command = $this->zendsignPath;
+
+ // add license path
+ $command .= ' ' . $this->getLicenseTemplatePath();
+
+ // add result file path
+ $command .= ' ' . $this->outputFile;
+
+ // add key path
+ $command .= ' ' . $this->privateKeyPath;
+
+
+ $this->zendsignCommand = $command;
+
+ return $command;
+ }
+
+ /**
+ * Checks if the license template path is defined
+ * and returns it.
+ * If it the license template path is not defined
+ * it will generate a temporary template file and
+ * provide it as a template.
+ *
+ * @return string
+ */
+ protected function getLicenseTemplatePath()
+ {
+ if (!empty($this->licenseTemplate)) {
+ return $this->licenseTemplate;
+ } else {
+ return $this->generateLicenseTemplate();
+ }
+ }
+
+ /**
+ * Creates the signed license at the defined output path
+ *
+ * @return void
+ */
+ protected function generateLicense()
+ {
+ $command = $this->prepareSignCommand() . ' 2>&1';
+
+ $this->log('Creating license at ' . $this->outputFile);
+
+ $this->log('Running: ' . $command, Project::MSG_VERBOSE);
+ $tmp = exec($command, $output, $return_var);
+
+ // Check for exit value 1. Zendenc_sign command for some reason
+ // returns 0 in case of failure and 1 in case of success...
+ if ($return_var !== 1) {
+ throw new BuildException("Creating license failed. \n\nZendenc_sign msg:\n" . join("\n", $output) . "\n\n");
+ }
+ }
+
+ /**
+ * It will generate a temporary license template
+ * based on the properties defined.
+ *
+ * @return string Path of the temporary license template file
+ */
+ protected function generateLicenseTemplate()
+ {
+ $this->tmpLicensePath = tempnam(sys_get_temp_dir(), 'zendlicense');
+
+ $this->log("Creating temporary license template " . $this->tmpLicensePath, Project::MSG_VERBOSE);
+ if (file_put_contents($this->tmpLicensePath, $this->generateLicenseTemplateContent()) === false) {
+ throw new BuildException("Unable to create temporary template license file: " . $this->tmpLicensePath);
+ }
+
+ return $this->tmpLicensePath;
+ }
+
+ /**
+ * Generates license template content based
+ * on the defined parameters
+ *
+ * @return string
+ */
+ protected function generateLicenseTemplateContent()
+ {
+ $contentArr = array();
+
+ // Product Name
+ $contentArr[] = array('Product-Name', $this->productName);
+ // Registered to
+ $contentArr[] = array('Registered-To', $this->registeredTo);
+ // Hardware locked
+ $contentArr[] = array('Hardware-Locked', ($this->hardwareLocked ? 'Yes' : 'No'));
+
+ // Expires
+ $contentArr[] = array('Expires', $this->expires);
+
+ // IP-Range
+ if (!empty($this->ipRange)) {
+ $contentArr[] = array('IP-Range', $this->ipRange);
+ }
+ // Host-ID
+ if (!empty($this->hostID)) {
+ foreach (explode(';', $this->hostID) as $hostID) {
+ $contentArr[] = array('Host-ID', $hostID);
+ }
+ } else {
+ $contentArr[] = array('Host-ID', 'Not-Locked');
+ }
+
+ // parse user defined fields
+ if (!empty($this->userDefinedValues)) {
+ $this->parseAndAddUserDefinedValues($this->userDefinedValues, $contentArr);
+ }
+ // parse user defined x-fields
+ if (!empty($this->xUserDefinedValues)) {
+ $this->parseAndAddUserDefinedValues($this->xUserDefinedValues, $contentArr, 'X-');
+ }
+
+ // merge all the values
+ $content = '';
+ foreach ($contentArr as $valuePair) {
+
+ list($key, $value) = $valuePair;
+
+ $content .= $key . " = " . $value . "\n";
+ }
+
+ return $content;
+ }
+
+ /**
+ * Parse the given string in format like key1=value1;key2=value2;... and
+ * converts it to array
+ * (key1=>value1, key2=value2, ...)
+ *
+ * @param stirng $valueString Semi-colon separated value pairs
+ * @param array $valueArray Array to which the values will be added
+ * @param string $keyPrefix Prefix to use when adding the key
+ *
+ * @return void
+ */
+ protected function parseAndAddUserDefinedValues($valueString, array &$valueArray, $keyPrefix = '',
+ $pairSeparator = ';')
+ {
+ // explode the valueString (semicolon)
+ $valuePairs = explode($pairSeparator, $valueString);
+ if (!empty($valuePairs)) {
+ foreach ($valuePairs as $valuePair) {
+ list($key, $value) = explode('=', $valuePair, 2);
+
+ // add pair into the valueArray
+ $valueArray[] = array($keyPrefix . $key, $value);
+ }
+ }
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php
new file mode 100755
index 00000000..ce0ca210
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTask.php
@@ -0,0 +1,88 @@
+<?php
+/*
+ * $Id: 03a742eb03e5e1515c297d941970a86b00e1f69e $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..03f80b27
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * $Id: da14cd0fdc73a0eb13ecc8c0b5ae693550a052b1 $
+ *
+ * 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 $Id$
+ * @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);
+ }
+
+ $taskdefs = $this->getProject()->getTaskDefinitions();
+
+ if (!isset($taskdefs[$this->name]))
+ {
+ $this->execute();
+
+ $classes = $this->getNewClasses();
+
+ if (count($classes) < 1)
+ {
+ throw new BuildException("You must define at least one class for AdhocTaskdefTask.");
+ }
+
+ $classname = array_pop($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 100755
index 00000000..80be2fc9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * $Id: 679ed701a01fef022a2da8ff5db16cff658b77e6 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..a7c4dcda
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/AppendTask.php
@@ -0,0 +1,240 @@
+<?php
+/*
+ * $Id: 056086ae305f5447baee1a4c7b1ad59ceb8cf50b $
+ *
+ * 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 $Id$
+ */
+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 100755
index 00000000..bd5701e4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/AvailableTask.php
@@ -0,0 +1,172 @@
+<?php
+/*
+ * $Id: 7388bc66c9574987edd02ad3b2d6f14462f6b157 $
+ *
+ * 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 $Id$
+ * @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;
+
+ private $followSymlinks = false;
+
+ 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);
+ }
+
+ public function setFollowSymlinks($followSymlinks)
+ {
+ $this->followSymlinks = (bool) $followSymlinks;
+ }
+
+ /**
+ * Set the path to use when looking for a file.
+ *
+ * @param Path $filepath a Path instance containing the search path for files.
+ */
+ public function setFilepath(Path $filepath) {
+ if ($this->filepath === null) {
+ $this->filepath = $filepath;
+ } else {
+ $this->filepath->append($filepath);
+ }
+ }
+
+ /**
+ * Creates a path to be configured
+ *
+ * @return Path
+ */
+ public function createFilepath() {
+ if ($this->filepath === null) {
+ $this->filepath = new Path($this->project);
+ }
+ return $this->filepath->createPath();
+ }
+
+ 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
+ private function _checkFile() {
+ if ($this->filepath === null) {
+ return $this->_checkFile1($this->file);
+ } else {
+ $paths = $this->filepath->listPaths();
+ 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;
+ }
+
+ private function _checkFile1(PhingFile $file) {
+ // Resolve symbolic links
+ if ($this->followSymlinks && $file->isLink()) {
+ $file = new PhingFile($file->getLinkTarget());
+ }
+
+ if ($this->type !== null) {
+ if ($this->type === "dir") {
+ return $file->isDirectory();
+ } else if ($this->type === "file") {
+ return $file->isFile();
+ }
+ }
+ return $file->exists();
+ }
+
+ private function _checkResource($resource) {
+ if (null != ($resourcePath = Phing::getResourcePath($resource))) {
+ return $this->_checkFile1(new PhingFile($resourcePath));
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php
new file mode 100755
index 00000000..b2300459
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ChmodTask.php
@@ -0,0 +1,203 @@
+<?php
+/*
+ * $Id: fad30caf32ff1ee9ff98f63849d61053ab88f645 $
+ *
+ * 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 $Id: fad30caf32ff1ee9ff98f63849d61053ab88f645 $
+ * @package phing.tasks.system
+ */
+class ChmodTask extends Task {
+
+ private $file;
+
+ private $mode;
+
+ private $filesets = array();
+
+ private $filesystem;
+
+ private $quiet = false;
+ private $failonerror = true;
+ private $verbose = 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;
+ }
+ }
+
+ /**
+ * Set verbosity, which if set to false surpresses all but an overview
+ * of what happened.
+ */
+ function setVerbose($bool) {
+ $this->verbose = (bool)$bool;
+ }
+
+ /**
+ * 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);
+ }
+
+ // counters for non-verbose output
+ $total_files = 0;
+ $total_dirs = 0;
+
+ // one file
+ if ($this->file !== null) {
+ $total_files = 1;
+ $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();
+
+ $filecount = count($srcFiles);
+ $total_files = $total_files + $filecount;
+ for ($j = 0; $j < $filecount; $j++) {
+ $this->chmodFile(new PhingFile($fromDir, $srcFiles[$j]), $mode);
+ }
+
+ $dircount = count($srcDirs);
+ $total_dirs = $total_dirs + $dircount;
+ for ($j = 0; $j < $dircount; $j++) {
+ $this->chmodFile(new PhingFile($fromDir, $srcDirs[$j]), $mode);
+ }
+ }
+
+ if (!$this->verbose) {
+ $this->log('Total files changed to ' . vsprintf('%o', $mode) . ': ' . $total_files);
+ $this->log('Total directories changed to ' . vsprintf('%o', $mode) . ': ' . $total_dirs);
+ }
+
+ }
+
+ /**
+ * 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);
+ if ($this->verbose) {
+ $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/ChownTask.php b/buildscripts/phing/classes/phing/tasks/system/ChownTask.php
new file mode 100755
index 00000000..60b8105c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ChownTask.php
@@ -0,0 +1,216 @@
+<?php
+/*
+ * $Id: f7234abd52e7f80177f4b121436ae7276370993c $
+ *
+ * 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 Mehmet Emre Yilmaz <mehmety@gmail.com>
+ * @version $Id: f7234abd52e7f80177f4b121436ae7276370993c $
+ * @package phing.tasks.system
+ */
+class ChownTask extends Task {
+
+ private $file;
+
+ private $user;
+ private $group;
+
+ private $filesets = array();
+
+ private $filesystem;
+
+ private $quiet = false;
+ private $failonerror = true;
+ private $verbose = 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 chown() fails.
+ * @see setFailonerror()
+ */
+ function setQuiet($bool) {
+ $this->quiet = $bool;
+ if ($this->quiet) {
+ $this->failonerror = false;
+ }
+ }
+
+ /**
+ * Set verbosity, which if set to false surpresses all but an overview
+ * of what happened.
+ */
+ function setVerbose($bool) {
+ $this->verbose = (bool)$bool;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets the user
+ */
+ function setUser($user) {
+ $this->user = $user;
+ }
+
+ /**
+ * Sets the group
+ */
+ function setGroup($group) {
+ $this->group = $group;
+ }
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ */
+ function addFileSet(FileSet $fs) {
+ $this->filesets[] = $fs;
+ }
+
+ /**
+ * Execute the touch operation.
+ * @return void
+ */
+ function main() {
+ // Check Parameters
+ $this->checkParams();
+ $this->chown();
+ }
+
+ /**
+ * 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->user === null && $this->group === null) {
+ throw new BuildException("You have to specify either an owner or a group for chown.");
+ }
+ }
+
+ /**
+ * Does the actual work.
+ * @return void
+ */
+ private function chown() {
+ $userElements = explode('.', $this->user);
+
+ $user = $userElements[0];
+
+ if (count($userElements) > 1) {
+ $group = $userElements[1];
+ } else {
+ $group = $this->group;
+ }
+
+ // counters for non-verbose output
+ $total_files = 0;
+ $total_dirs = 0;
+
+ // one file
+ if ($this->file !== null) {
+ $total_files = 1;
+ $this->chownFile($this->file, $user, $group);
+ }
+
+ // filesets
+ foreach($this->filesets as $fs) {
+
+ $ds = $fs->getDirectoryScanner($this->project);
+ $fromDir = $fs->getDir($this->project);
+
+ $srcFiles = $ds->getIncludedFiles();
+ $srcDirs = $ds->getIncludedDirectories();
+
+ $filecount = count($srcFiles);
+ $total_files = $total_files + $filecount;
+ for ($j = 0; $j < $filecount; $j++) {
+ $this->chownFile(new PhingFile($fromDir, $srcFiles[$j]), $user, $group);
+ }
+
+ $dircount = count($srcDirs);
+ $total_dirs = $total_dirs + $dircount;
+ for ($j = 0; $j < $dircount; $j++) {
+ $this->chownFile(new PhingFile($fromDir, $srcDirs[$j]), $user, $group);
+ }
+ }
+
+ if (!$this->verbose) {
+ $this->log('Total files changed to ' . $user . ($group ? "." . $group : "") . ': ' . $total_files);
+ $this->log('Total directories changed to ' . $user . ($group ? "." . $group : "") . ': ' . $total_dirs);
+ }
+
+ }
+
+ /**
+ * Actually change the mode for the file.
+ * @param PhingFile $file
+ * @param string $user
+ * @param string $group
+ */
+ private function chownFile(PhingFile $file, $user, $group = "") {
+ if ( !$file->exists() ) {
+ throw new BuildException("The file " . $file->__toString() . " does not exist");
+ }
+
+ try {
+ if (!empty($user)) {
+ $file->setUser($user);
+ }
+
+ if (!empty($group)) {
+ $file->setGroup($group);
+ }
+
+ if ($this->verbose) {
+ $this->log("Changed file owner on '" . $file->__toString() ."' to " . $user . ($group ? "." . $group : ""));
+ }
+ } 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 100755
index 00000000..040fff8a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ConditionTask.php
@@ -0,0 +1,74 @@
+<?php
+/*
+ * $Id: 31dfd9d24212a4cf5afcce43a9ae337669bafc35 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..2533bb95
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/CopyTask.php
@@ -0,0 +1,480 @@
+<?php
+/*
+ * $Id: 86322e73609da671413e4c959082958c16a510cc $
+ *
+ * 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 $Id: 86322e73609da671413e4c959082958c16a510cc $
+ * @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 = false; // 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 $completeDirMap= array(); // asoc array containing complete dir names
+ protected $fileUtils = null; // a instance of fileutils
+ protected $filesets = array(); // all fileset objects assigned to this task
+ protected $filelists = array(); // all filelist objects assigned to this task
+ protected $filterChains = array(); // all filterchains objects assigned to this task
+
+ protected $verbosity = Project::MSG_VERBOSE;
+
+ protected $mode = 0755; // mode to create directories with
+
+ protected $haltonerror = true; // stop build on errors
+
+ /**
+ * 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;
+ }
+ }
+
+ /**
+ * @see CopyTask::setPreserveLastModified
+ */
+ function setTstamp($bool) {
+ $this->setPreserveLastModified($bool);
+ }
+
+ /**
+ * Set the preserve timestamp 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 setPreserveLastModified($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;
+ }
+
+ /**
+ * Sets the mode to create destination directories with (ignored on Windows).
+ * Default mode is 0755.
+ *
+ * @param integer Octal mode
+ * @return void
+ * @access public
+ */
+ function setMode($mode) {
+ $this->mode = (int) base_convert($mode, 8, 10);
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Set the haltonerror attribute - when true, will
+ * make the build fail when errors are detected.
+ *
+ * @param boolean Flag if the build should be stopped on errors
+ * @return void
+ * @access public
+ */
+ function setHaltonerror($haltonerror) {
+ $this->haltonerror = (boolean) $haltonerror;
+ }
+
+ /**
+ * Nested creator, creates a FileSet for this task
+ *
+ * @param FileSet $fileset Set of files to copy
+ *
+ * @return void
+ */
+ public function addFileSet(FileSet $fs) {
+ $this->filesets[] = $fs;
+ }
+
+ /**
+ * Nested creator, adds a set of files (nested fileset attribute).
+ *
+ * @access public
+ * @return object The created filelist object
+ */
+ function createFileList() {
+ $num = array_push($this->filelists, new FileList());
+ return $this->filelists[$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
+ $this->logError("Could not find file " . $this->file->__toString() . " to copy.");
+ }
+ }
+
+ $project = $this->getProject();
+
+ // process filelists
+ foreach($this->filelists as $fl) {
+ $fromDir = $fl->getDir($project);
+ $srcFiles = $fl->getFiles($project);
+ $srcDirs = array($fl->getDir($project));
+
+ if (!$this->flatten && $this->mapperElement === null)
+ {
+ $this->completeDirMap[$fromDir->getAbsolutePath()] = $this->destDir->getAbsolutePath();
+ }
+
+ $this->_scan($fromDir, $this->destDir, $srcFiles, $srcDirs);
+ }
+
+ // process filesets
+ foreach($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($project);
+ $fromDir = $fs->getDir($project);
+ $srcFiles = $ds->getIncludedFiles();
+ $srcDirs = $ds->getIncludedDirectories();
+
+ if (!$this->flatten && $this->mapperElement === null)
+ {
+ $this->completeDirMap[$fromDir->getAbsolutePath()] = $this->destDir->getAbsolutePath();
+ }
+
+ $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
+ */
+ protected function validateAttributes() {
+
+ if ($this->file === null && count($this->filesets) === 0 && count($this->filelists) === 0) {
+ throw new BuildException("CopyTask. Specify at least one source - a file, fileset or filelist.");
+ }
+
+ 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
+ */
+ protected 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;
+
+ // handle empty dirs if appropriate
+ if ($this->includeEmpty) {
+ $count = 0;
+ foreach ($this->dirCopyMap as $srcdir => $destdir) {
+ $s = new PhingFile((string) $srcdir);
+ $d = new PhingFile((string) $destdir);
+ if (!$d->exists()) {
+ if (!$d->mkdirs()) {
+ $this->logError("Unable to create directory " . $d->__toString());
+ } else {
+ if ($this->preserveLMT) {
+ $d->setLastModified($s->lastModified());
+ }
+
+ $count++;
+ }
+ }
+ }
+ if ($count > 0) {
+ $this->log("Created ".$count." empty director" . ($count == 1 ? "y" : "ies") . " in " . $this->destDir->getAbsolutePath());
+ }
+ }
+
+ 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(), $this->mode);
+
+ $count++;
+ } catch (IOException $ioe) {
+ $this->logError("Failed to copy " . $from . " to " . $to . ": " . $ioe->getMessage());
+ }
+ }
+ }
+ }
+
+ protected function logError($message, $location = NULL)
+ {
+ if ($this->haltonerror) {
+ throw new BuildException($message, $location);
+ } else {
+ $this->log($message, Project::MSG_ERR);
+ }
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php
new file mode 100755
index 00000000..87a9b63c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php
@@ -0,0 +1,173 @@
+<?php
+/*
+ * $Id: c1e02a8d43f62c584ba2f1cd5a6f0cc690bceb94 $
+ *
+ * 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 $Id$
+ * @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 . PHP_EOL;
+ }
+ }
+ }
+
+ $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 100755
index 00000000..3c12a597
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/CvsTask.php
@@ -0,0 +1,540 @@
+<?php
+/*
+ * $Id: 642c6947fa58e02a8c7893c8c4dfab2debfdd51d $
+ *
+ * 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 $Id: 642c6947fa58e02a8c7893c8c4dfab2debfdd51d $
+ * @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->main();
+ $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
+ . PHP_EOL
+ . "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 100755
index 00000000..8af8a632
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/DeleteTask.php
@@ -0,0 +1,276 @@
+<?php
+/*
+ * $Id: f25fc4c605ead65db9235c9fe328b2d47b7c8299 $
+ *
+ * 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 $Id: f25fc4c605ead65db9235c9fe328b2d47b7c8299 $
+ * @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 addFileSet(FileSet $fs) {
+ $this->filesets[] = $fs;
+ }
+
+ /** 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->__toString();
+ 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 100755
index 00000000..edc098c4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/EchoTask.php
@@ -0,0 +1,152 @@
+<?php
+/*
+ * $Id: c5ebadd12256533d9ca4d6fb6cabd50415bdddbf $
+ *
+ * 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 <mrook@php.net>
+ * @author Andreas Aderhold, andi@binarycloud.com
+ * @version $Id$
+ * @package phing.tasks.system
+ */
+
+class EchoTask extends Task {
+
+ protected $msg = "";
+
+ protected $file = "";
+
+ protected $append = false;
+
+ protected $level = "info";
+
+ protected $filesets = array();
+
+ 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 (count($this->filesets)) {
+ if (trim(substr($this->msg, -1)) != '') {
+ $this->msg .= "\n";
+ }
+ $this->msg .= $this->getFilesetsMsg();
+ }
+
+ 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);
+ }
+ }
+
+ /**
+ * Merges all filesets into a string to be echoed out
+ *
+ * @return string String to echo
+ */
+ protected function getFilesetsMsg()
+ {
+ $project = $this->getProject();
+ $msg = '';
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($project);
+ $fromDir = $fs->getDir($project);
+ $srcFiles = $ds->getIncludedFiles();
+ $msg .= 'Directory: ' . $fromDir . ' => '
+ . realpath($fromDir) . "\n";
+ foreach ($srcFiles as $file) {
+ $relPath = $fromDir . DIRECTORY_SEPARATOR . $file;
+ $msg .= $relPath . "\n";
+ }
+ }
+
+ return $msg;
+ }
+
+ /** 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;
+ }
+
+ /**
+ * Adds a fileset to echo the files of
+ *
+ * @param FileSet $fs Set of files to echo
+ *
+ * @return void
+ */
+ public function addFileSet(FileSet $fs)
+ {
+ $this->filesets[] = $fs;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/ExecTask.php b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php
new file mode 100755
index 00000000..f5a57948
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ExecTask.php
@@ -0,0 +1,516 @@
+<?php
+
+/**
+ * $Id: 3101d1403eeb4fe4fe8bae729b7d918b303de1cf $
+ *
+ * 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>
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @version $Id: 3101d1403eeb4fe4fe8bae729b7d918b303de1cf $
+ * @package phing.tasks.system
+ */
+class ExecTask extends Task
+{
+
+ /**
+ * Command to execute.
+ * @var string
+ */
+ protected $command;
+
+ /**
+ * Commandline managing object
+ *
+ * @var Commandline
+ */
+ protected $commandline;
+
+ /**
+ * Working directory.
+ * @var PhingFile
+ */
+ 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 use PHP's passthru() function instead of exec()
+ * @var boolean
+ */
+ protected $passthru = false;
+
+ /**
+ * Whether to log returned output as MSG_INFO instead of MSG_VERBOSE
+ * @var boolean
+ */
+ protected $logOutput = false;
+
+ /**
+ * Logging level for status messages
+ * @var integer
+ */
+ protected $logLevel = Project::MSG_VERBOSE;
+
+ /**
+ * 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;
+
+ /**
+ * Property name to set with return value from exec call.
+ *
+ * @var string
+ */
+ protected $returnProperty;
+
+ /**
+ * Property name to set with output value from exec call.
+ *
+ * @var string
+ */
+ protected $outputProperty;
+
+ /**
+ * Whether to check the return code.
+ * @var boolean
+ */
+ protected $checkreturn = false;
+
+
+
+ public function __construct()
+ {
+ $this->commandline = new Commandline();
+ }
+
+ /**
+ * Main method: wraps execute() command.
+ *
+ * @return void
+ */
+ public function main()
+ {
+ if (!$this->isApplicable()) {
+ return;
+ }
+
+ $this->prepare();
+ $this->buildCommand();
+ list($return, $output) = $this->executeCommand();
+ $this->cleanup($return, $output);
+ }
+
+ /**
+ * Checks whether the command shall be executed
+ *
+ * @return boolean False if the exec command shall not be run
+ */
+ protected function isApplicable()
+ {
+ if ($this->os === null) {
+ return true;
+ }
+
+ $myos = Phing::getProperty('os.name');
+ $this->log('Myos = ' . $myos, Project::MSG_VERBOSE);
+
+ if (strpos($this->os, $myos) !== false) {
+ // this command will be executed only on the specified OS
+ // OS matches
+ return true;
+ }
+
+ $this->log(
+ sprintf(
+ 'Operating system %s not found in %s',
+ $myos, $this->os
+ ),
+ Project::MSG_VERBOSE
+ );
+ return false;
+ }
+
+ /**
+ * Prepares the command building and execution, i.e.
+ * changes to the specified directory.
+ *
+ * @return void
+ */
+ protected function prepare()
+ {
+ if ($this->dir === null) {
+ return;
+ }
+
+ // expand any symbolic links first
+ if (!$this->dir->getCanonicalFile()->isDirectory()) {
+ throw new BuildException(
+ "'" . (string) $this->dir . "' is not a valid directory"
+ );
+ }
+ $this->currdir = getcwd();
+ @chdir($this->dir->getPath());
+ }
+
+ /**
+ * Builds the full command to execute and stores it in $command.
+ *
+ * @return void
+ * @uses $command
+ */
+ protected function buildCommand()
+ {
+ if ($this->command === null && $this->commandline->getExecutable() === null) {
+ throw new BuildException(
+ 'ExecTask: Please provide "command" OR "executable"'
+ );
+ } else if ($this->command === null) {
+ $this->command = Commandline::toString($this->commandline->getCommandline(), $this->escape);
+ } else if ($this->commandline->getExecutable() === null) {
+ //we need to escape the command only if it's specified directly
+ // commandline takes care of "executable" already
+ if ($this->escape == true) {
+ $this->command = escapeshellcmd($this->command);
+ }
+ } else {
+ throw new BuildException(
+ 'ExecTask: Either use "command" OR "executable"'
+ );
+ }
+
+ if ($this->error !== null) {
+ $this->command .= ' 2> ' . $this->error->getPath();
+ $this->log(
+ "Writing error output to: " . $this->error->getPath(),
+ $this->logLevel
+ );
+ }
+
+ if ($this->output !== null) {
+ $this->command .= ' 1> ' . $this->output->getPath();
+ $this->log(
+ "Writing standard output to: " . $this->output->getPath(),
+ $this->logLevel
+ );
+ } elseif ($this->spawn) {
+ $this->command .= ' 1>/dev/null';
+ $this->log("Sending output to /dev/null", $this->logLevel);
+ }
+
+ // 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 .= ' &';
+ }
+ }
+
+ /**
+ * Executes the command and returns return code and output.
+ *
+ * @return array array(return code, array with output)
+ */
+ protected function executeCommand()
+ {
+ $this->log("Executing command: " . $this->command, $this->logLevel);
+
+ $output = array();
+ $return = null;
+
+ if ($this->passthru) {
+ passthru($this->command, $return);
+ } else {
+ exec($this->command, $output, $return);
+ }
+
+ return array($return, $output);
+ }
+
+ /**
+ * Runs all tasks after command execution:
+ * - change working directory back
+ * - log output
+ * - verify return value
+ *
+ * @param integer $return Return code
+ * @param array $output Array with command output
+ *
+ * @return void
+ */
+ protected function cleanup($return, $output)
+ {
+ if ($this->dir !== null) {
+ @chdir($this->currdir);
+ }
+
+ $outloglevel = $this->logOutput ? Project::MSG_INFO : Project::MSG_VERBOSE;
+ foreach ($output as $line) {
+ $this->log($line, $outloglevel);
+ }
+
+ if ($this->returnProperty) {
+ $this->project->setProperty($this->returnProperty, $return);
+ }
+
+ if ($this->outputProperty) {
+ $this->project->setProperty(
+ $this->outputProperty, implode("\n", $output)
+ );
+ }
+
+ if ($return != 0 && $this->checkreturn) {
+ throw new BuildException("Task exited with code $return");
+ }
+ }
+
+
+ /**
+ * The command to use.
+ *
+ * @param mixed $command String or string-compatible (e.g. w/ __toString()).
+ *
+ * @return void
+ */
+ public function setCommand($command)
+ {
+ $this->command = "" . $command;
+ }
+
+ /**
+ * The executable to use.
+ *
+ * @param mixed $executable String or string-compatible (e.g. w/ __toString()).
+ *
+ * @return void
+ */
+ public function setExecutable($executable)
+ {
+ $this->commandline->setExecutable((string)$executable);
+ }
+
+ /**
+ * Whether to use escapeshellcmd() to escape command.
+ *
+ * @param boolean $escape If the command shall be escaped or not
+ *
+ * @return void
+ */
+ public function setEscape($escape)
+ {
+ $this->escape = (bool) $escape;
+ }
+
+ /**
+ * Specify the working directory for executing this command.
+ *
+ * @param PhingFile $dir Working directory
+ *
+ * @return void
+ */
+ public function setDir(PhingFile $dir)
+ {
+ $this->dir = $dir;
+ }
+
+ /**
+ * Specify OS (or muliple OS) that must match in order to execute this command.
+ *
+ * @param string $os Operating system string (e.g. "Linux")
+ *
+ * @return void
+ */
+ public function setOs($os)
+ {
+ $this->os = (string) $os;
+ }
+
+ /**
+ * File to which output should be written.
+ *
+ * @param PhingFile $f Output log file
+ *
+ * @return void
+ */
+ public function setOutput(PhingFile $f)
+ {
+ $this->output = $f;
+ }
+
+ /**
+ * File to which error output should be written.
+ *
+ * @param PhingFile $f Error log file
+ *
+ * @return void
+ */
+ public function setError(PhingFile $f)
+ {
+ $this->error = $f;
+ }
+
+ /**
+ * Whether to use PHP's passthru() function instead of exec()
+ *
+ * @param boolean $passthru If passthru shall be used
+ *
+ * @return void
+ */
+ public function setPassthru($passthru)
+ {
+ $this->passthru = (bool) $passthru;
+ }
+
+ /**
+ * Whether to log returned output as MSG_INFO instead of MSG_VERBOSE
+ *
+ * @param boolean $logOutput If output shall be logged visibly
+ *
+ * @return void
+ */
+ public function setLogoutput($logOutput)
+ {
+ $this->logOutput = (bool) $logOutput;
+ }
+
+ /**
+ * Whether to suppress all output and run in the background.
+ *
+ * @param boolean $spawn If the command is to be run in the background
+ *
+ * @return void
+ */
+ public function setSpawn($spawn)
+ {
+ $this->spawn = (bool) $spawn;
+ }
+
+ /**
+ * Whether to check the return code.
+ *
+ * @param boolean $checkreturn If the return code shall be checked
+ *
+ * @return void
+ */
+ public function setCheckreturn($checkreturn)
+ {
+ $this->checkreturn = (bool) $checkreturn;
+ }
+
+ /**
+ * The name of property to set to return value from exec() call.
+ *
+ * @param string $prop Property name
+ *
+ * @return void
+ */
+ public function setReturnProperty($prop)
+ {
+ $this->returnProperty = $prop;
+ }
+
+ /**
+ * The name of property to set to output value from exec() call.
+ *
+ * @param string $prop Property name
+ *
+ * @return void
+ */
+ public function setOutputProperty($prop)
+ {
+ $this->outputProperty = $prop;
+ }
+
+ /**
+ * Set level of log messages generated (default = verbose)
+ *
+ * @param string $level Log level
+ *
+ * @return void
+ */
+ public function setLevel($level)
+ {
+ switch ($level) {
+ case 'error':
+ $this->logLevel = Project::MSG_ERR;
+ break;
+ case 'warning':
+ $this->logLevel = Project::MSG_WARN;
+ break;
+ case 'info':
+ $this->logLevel = Project::MSG_INFO;
+ break;
+ case 'verbose':
+ $this->logLevel = Project::MSG_VERBOSE;
+ break;
+ case 'debug':
+ $this->logLevel = Project::MSG_DEBUG;
+ break;
+ default:
+ throw new BuildException(
+ sprintf('Unknown log level "%s"', $level)
+ );
+ }
+ }
+
+ /**
+ * Creates a nested <arg> tag.
+ *
+ * @return CommandlineArgument Argument object
+ */
+ public function createArg()
+ {
+ return $this->commandline->createArgument();
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/tasks/system/FailTask.php b/buildscripts/phing/classes/phing/tasks/system/FailTask.php
new file mode 100755
index 00000000..92306842
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/FailTask.php
@@ -0,0 +1,118 @@
+<?php
+/*
+ * $Id: 260a7f3caa499a33f0d3982f9a5cc9db222475a6 $
+ *
+ * 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 $Id$
+ * @package phing.tasks.system
+ */
+class FailTask 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 100755
index 00000000..e9b556d3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ForeachTask.php
@@ -0,0 +1,320 @@
+<?php
+/*
+ * $Id: 7acb78ab792426fa7d4edec53496cff8da5923eb $
+ *
+ * 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/FileSystem.php';
+include_once 'phing/mappers/FileNameMapper.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 $Id$
+ * @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;
+
+ /** Name of absolute path parameter to pass to callee */
+ private $absparam;
+
+ /** Delimiter that separates items in $list */
+ private $delimiter = ',';
+
+ /**
+ * PhingCallTask that will be invoked w/ calleeTarget.
+ * @var PhingCallTask
+ */
+ private $callee;
+
+ /** Array of filesets */
+ private $filesets = array();
+
+ /** Instance of mapper **/
+ private $mapperElement;
+
+ /**
+ * Array of filelists
+ * @var array
+ */
+ private $filelists = array();
+
+ /**
+ * Target to execute.
+ * @var string
+ */
+ private $calleeTarget;
+
+ /**
+ * Total number of files processed
+ * @var integer
+ */
+ private $total_files = 0;
+
+ /**
+ * Total number of directories processed
+ * @var integer
+ */
+ private $total_dirs = 0;
+
+
+ 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 && count($this->filesets) == 0 && count($this->filelists) == 0) {
+ throw new BuildException("Need either list, nested fileset or nested filelist to iterate through");
+ }
+ 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);
+ $mapper = null;
+
+ if ($this->mapperElement !== null) {
+ $mapper = $this->mapperElement->getImplementation();
+ }
+
+ if (trim($this->list)) {
+ $arr = explode($this->delimiter, $this->list);
+
+ foreach ($arr as $value) {
+ $value = trim($value);
+ $premapped = '';
+ if ($mapper !== null) {
+ $premapped = $value;
+ $value = $mapper->main($value);
+ if ($value === null) {
+ continue;
+ }
+ $value = array_shift($value);
+ }
+ $this->log("Setting param '$this->param' to value '$value'" . ($premapped ? " (mapped from '$premapped')" : ''), Project::MSG_VERBOSE);
+ $prop = $callee->createProperty();
+ $prop->setOverride(true);
+ $prop->setName($this->param);
+ $prop->setValue($value);
+ $callee->main();
+ }
+ }
+
+ // filelists
+ foreach ($this->filelists as $fl) {
+ $srcFiles = $fl->getFiles($this->project);
+
+ $this->process($callee, $fl->getDir($this->project), $srcFiles, array());
+ }
+
+ // filesets
+ foreach ($this->filesets as $fs) {
+ $ds = $fs->getDirectoryScanner($this->project);
+ $srcFiles = $ds->getIncludedFiles();
+ $srcDirs = $ds->getIncludedDirectories();
+
+ $this->process($callee, $fs->getDir($this->project), $srcFiles, $srcDirs);
+ }
+
+ $this->log("Processed {$this->total_dirs} directories and {$this->total_files} files", Project::MSG_VERBOSE);
+ }
+
+ /**
+ * Processes a list of files & directories
+ *
+ * @param Task $callee
+ * @param PhingFile $fromDir
+ * @param array $srcFiles
+ * @param array $srcDirs
+ */
+ protected function process(Task $callee, PhingFile $fromDir, $srcFiles, $srcDirs)
+ {
+ $mapper = null;
+
+ if ($this->mapperElement !== null) {
+ $mapper = $this->mapperElement->getImplementation();
+ }
+
+ $filecount = count($srcFiles);
+ $this->total_files += $filecount;
+
+ for ($j = 0; $j < $filecount; $j++) {
+ $value = $srcFiles[$j];
+ $premapped = "";
+
+ if ($this->absparam) {
+ $prop = $callee->createProperty();
+ $prop->setOverride(true);
+ $prop->setName($this->absparam);
+ $prop->setValue($fromDir . FileSystem::getFileSystem()->getSeparator() . $value);
+ }
+
+ if ($mapper !== null) {
+ $premapped = $value;
+ $value = $mapper->main($value);
+ if ($value === null) {
+ continue;
+ }
+ $value = array_shift($value);
+ }
+
+ if ($this->param) {
+ $this->log("Setting param '$this->param' to value '$value'" . ($premapped ? " (mapped from '$premapped')" : ''), Project::MSG_VERBOSE);
+ $prop = $callee->createProperty();
+ $prop->setOverride(true);
+ $prop->setName($this->param);
+ $prop->setValue($value);
+ }
+
+ $callee->main();
+ }
+
+ $dircount = count($srcDirs);
+ $this->total_dirs += $dircount;
+
+ for ($j = 0; $j < $dircount; $j++) {
+ $value = $srcDirs[$j];
+ $premapped = "";
+
+ if ($this->absparam) {
+ $prop = $callee->createProperty();
+ $prop->setOverride(true);
+ $prop->setName($this->absparam);
+ $prop->setValue($fromDir . FileSystem::getFileSystem()->getSeparator() . $value);
+ }
+
+ if ($mapper !== null) {
+ $premapped = $value;
+ $value = $mapper->main($value);
+ if ($value === null) {
+ continue;
+ }
+ $value = array_shift($value);
+ }
+
+ if ($this->param) {
+ $this->log("Setting param '$this->param' to value '$value'" . ($premapped ? " (mapped from '$premapped')" : ''), 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 setAbsparam($absparam) {
+ $this->absparam = (string) $absparam;
+ }
+
+ function setDelimiter($delimiter) {
+ $this->delimiter = (string) $delimiter;
+ }
+
+ /**
+ * 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, 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;
+ }
+
+ /**
+ * @return Property
+ */
+ function createProperty() {
+ return $this->callee->createProperty();
+ }
+
+ /**
+ * Supports embedded <filelist> element.
+ * @return FileList
+ */
+ public function createFileList() {
+ $num = array_push($this->filelists, new FileList());
+ return $this->filelists[$num-1];
+ }
+}
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..cff06ce1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/IfTask.php
@@ -0,0 +1,227 @@
+<?php
+
+/*
+ * $Id: 4452f066ac71d51d3e2521d39cdee2caf4f7e9cc $
+ *
+ * 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&gt;</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&gt;</code> task, only a single
+ * condition can be specified - you combine them using
+ * <code><and&gt;</code> or <code><or&gt;</code> conditions.</p>
+ *
+ * <p>In addition to the condition, you can specify three different
+ * child elements, <code><elseif&gt;</code>, <code><then&gt;</code> and
+ * <code><else&gt;</code>. All three subelements are optional.
+ *
+ * Both <code><then&gt;</code> and <code><else&gt;</code> must not be
+ * used more than once inside the if task. Both are
+ * containers for Ant tasks, just like Ant's
+ * <code><parallel&gt;</code> and <code><sequential&gt;</code>
+ * tasks - in fact they are implemented using the same class as Ant's
+ * <code><sequential&gt;</code> task.</p>
+ *
+ * The <code><elseif&gt;</code> behaves exactly like an <code><if&gt;</code>
+ * except that it cannot contain the <code><else&gt;</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&gt;</code> is false, then the first
+ * <code><elseif&gt;</code> who's conditional evaluates to true
+ * will be executed. The <code><else&gt;</code> will be executed
+ * only if the <code><if&gt;</code> and all <code><elseif&gt;</code>
+ * conditions are false.
+ *
+ * <p>Use the following task to define the <code><if&gt;</code>
+ * task before you use it the first time:</p>
+ *
+ * <pre><code>
+ * &lt;taskdef name=&quot;if&quot; classname=&quot;net.sf.antcontrib.logic.IfTask&quot; /&gt;
+ * </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" /&gt;
+ * <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>
+ * @package phing.tasks.system
+ */
+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.
+ *
+ * @package phing.tasks.system
+ */
+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();
+ }
+ }
+ }
diff --git a/buildscripts/phing/classes/phing/tasks/system/ImportTask.php b/buildscripts/phing/classes/phing/tasks/system/ImportTask.php
new file mode 100755
index 00000000..760380eb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ImportTask.php
@@ -0,0 +1,136 @@
+<?php
+/*
+ * $Id: 88eafadfcd59c0ce28f122926b7d5706b807a8e3 $
+ *
+ * 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/FileSystem.php';
+require_once 'phing/system/io/PhingFile.php';
+require_once 'phing/parser/ProjectConfigurator.php';
+
+/**
+ * Imports another build file into the current project.
+ *
+ * Targets and properties of the imported file can be overrridden
+ * by targets and properties of the same name declared in the importing file.
+ *
+ * The imported file will have a new synthetic property of
+ * "phing.file.<projectname>" declared which gives the full path to the
+ * imported file. Additionally each target in the imported file will be
+ * declared twice: once with the normal name and once with "<projectname>."
+ * prepended. The "<projectname>.<targetname>" synthetic targets allow the
+ * importing file a mechanism to call the imported files targets as
+ * dependencies or via the <phing> or <phingcall> task mechanisms.
+ *
+ * @author Bryan Davis <bpd@keynetics.com>
+ * @version $Id: 88eafadfcd59c0ce28f122926b7d5706b807a8e3 $
+ * @package phing.tasks.system
+ */
+class ImportTask extends Task {
+
+ /**
+ * @var FileSystem
+ */
+ protected $fs;
+
+ /**
+ * @var PhingFile
+ */
+ protected $file = null;
+
+ /**
+ * @var bool
+ */
+ protected $optional = false;
+
+ /**
+ * Initialize task.
+ * @return void
+ */
+ public function init () {
+ $this->fs = FileSystem::getFileSystem();
+ } //end init
+
+
+ /**
+ * Set the file to import.
+ * @param string $f Path to file
+ * @return void
+ */
+ public function setFile ($f) {
+ $this->file = $f;
+ }
+
+ /**
+ * Is this include optional?
+ * @param bool $opt If true, do not stop the build if the file does not
+ * exist
+ * @return void
+ */
+ public function setOptional ($opt) {
+ $this->optional = $opt;
+ }
+
+ /**
+ * Parse a Phing build file and copy the properties, tasks, data types and
+ * targets it defines into the current project.
+ *
+ * @return void
+ */
+ public function main () {
+ if (!isset($this->file)) {
+ throw new BuildException("Missing attribute 'file'");
+ }
+
+ $file = new PhingFile($this->file);
+ if (!$file->isAbsolute()) {
+ $file = new PhingFile($this->project->getBasedir(), $this->file);
+ }
+ if (!$file->exists()) {
+ $msg = "Unable to find build file: {$file->getPath()}";
+ if ($this->optional) {
+ $this->log($msg . '... skipped');
+ return;
+ } else {
+ throw new BuildException($msg);
+ }
+ }
+
+ $ctx = $this->project->getReference("phing.parsing.context");
+ $cfg = $ctx->getConfigurator();
+ if (null !== $cfg && $cfg->isParsing()) {
+ // because there isn't a top level implicit target in phing like there is
+ // in Ant 1.6, we will be called as soon as our xml is parsed. This isn't
+ // really what we want to have happen. Instead we will register ourself
+ // with the parse context to be called at the end of the current file's
+ // parse phase.
+ $cfg->delayTaskUntilParseEnd($this);
+
+ } else {
+ // Import xml file into current project scope
+ // Since this is delayed until after the importing file has been
+ // processed, the properties and targets of this new file may not take
+ // effect if they have alreday been defined in the outer scope.
+ $this->log("Importing configuration from {$file->getName()}", Project::MSG_VERBOSE);
+ ProjectConfigurator::configureProject($this->project, $file);
+ $this->log("Configuration imported.", Project::MSG_VERBOSE);
+ }
+ } //end main
+
+} //end ImportTask
diff --git a/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php
new file mode 100755
index 00000000..807a3cad
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php
@@ -0,0 +1,115 @@
+<?php
+
+/*
+ * $Id: eaa0d6c5c7fb908d419cd6e22c7eccbf01506da7 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..3c7168fd
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/InputTask.php
@@ -0,0 +1,150 @@
+<?php
+/*
+ * $Id: ae986f84ca9d952b0e14f2df9f21657213ef5e47 $
+ *
+ * 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 $Id: ae986f84ca9d952b0e14f2df9f21657213ef5e47 $
+ * @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->message === "") {
+ throw new BuildException("You must specify a message for input task.");
+ }
+
+ 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/LoadFileTask.php b/buildscripts/phing/classes/phing/tasks/system/LoadFileTask.php
new file mode 100644
index 00000000..ff7b7d3b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/LoadFileTask.php
@@ -0,0 +1,119 @@
+<?php
+/*
+ * $Id: d4796a6eb57300eca59f8b6f79e3dbcb08d1e346 $
+ *
+ * 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';
+
+/**
+ * LoadFileTask
+ *
+ * Loads a (text) file and stores the contents in a property.
+ * Supports filterchains.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: d4796a6eb57300eca59f8b6f79e3dbcb08d1e346 $
+ * @package phing.tasks.ext
+ */
+class LoadFileTask extends Task
+{
+ /**
+ * File to read
+ * @var PhingFile file
+ */
+ private $file;
+
+ /**
+ * Property to be set
+ * @var string $property
+ */
+ private $property;
+
+ /**
+ * Array of FilterChain objects
+ * @var FilterChain[]
+ */
+ private $filterChains = array();
+
+ /**
+ * Set file to read
+ * @param PhingFile $file
+ */
+ public function setFile($file)
+ {
+ $this->file = $file;
+ }
+
+ /**
+ * Convenience setter to maintain Ant compatibility (@see setFile())
+ * @param PhingFile $file
+ */
+ public function setSrcFile($srcFile)
+ {
+ $this->file = $srcFile;
+ }
+
+ /**
+ * Set name of property to be set
+ * @param $property
+ * @return void
+ */
+ public function setProperty($property)
+ {
+ $this->property = $property;
+ }
+
+ /**
+ * 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];
+ }
+
+ /**
+ * Main method
+ *
+ * @return void
+ * @throws BuildException
+ */
+ public function main()
+ {
+ if (empty($this->file)) {
+ throw new BuildException("Attribute 'file' required", $this->getLocation());
+ }
+
+ if (empty($this->property)) {
+ throw new BuildException("Attribute 'property' required", $this->getLocation());
+ }
+
+ // read file (through filterchains)
+ $contents = "";
+
+ $reader = FileUtils::getChainedReader(new FileReader($this->file), $this->filterChains, $this->project);
+ while(-1 !== ($buffer = $reader->read())) {
+ $contents .= $buffer;
+ }
+ $reader->close();
+
+ // publish as property
+ $this->project->setProperty($this->property, $contents);
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php
new file mode 100755
index 00000000..b04be2e1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/MatchingTask.php
@@ -0,0 +1,361 @@
+<?php
+/*
+ * $Id: 1e1f6274f400b90c2344c8cdb5d3711030b8f44a $
+ *
+ * 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 $Id: 1e1f6274f400b90c2344c8cdb5d3711030b8f44a $
+ * @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) {
+ 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 100755
index 00000000..934b991f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/MkdirTask.php
@@ -0,0 +1,79 @@
+<?php
+/*
+ * $Id: e7e3dbd896d8d46cd8694fca10d1d9a7b3ce54fc $
+ *
+ * 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 $Id$
+ * @package phing.tasks.system
+ */
+class MkdirTask extends Task {
+
+ /** directory to create*/
+ private $dir;
+
+ /**
+ * Mode to create directory with
+ * @var integer
+ */
+ private $mode = 0755;
+
+ /**
+ * 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($this->mode);
+ 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;
+ }
+
+ /**
+ * Sets mode to create directory with
+ * @param mixed $mode
+ */
+ function setMode($mode)
+ {
+ $this->mode = base_convert((int) $mode, 8, 10);
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/MoveTask.php b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php
new file mode 100755
index 00000000..e7041464
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/MoveTask.php
@@ -0,0 +1,202 @@
+<?php
+/*
+ * $Id: 01e6d627d455729bfed47d603188d8c56f54d9e5 $
+ *
+ * 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 $Id$
+ * @package phing.tasks.system
+ */
+class MoveTask extends CopyTask {
+
+ function __construct() {
+ parent::__construct();
+ $this->forceOverwrite = true;
+ }
+
+ /**
+ * Validates attributes coming in from XML
+ *
+ * @access private
+ * @return void
+ * @throws BuildException
+ */
+ protected function validateAttributes() {
+ if ($this->file !== null && $this->file->isDirectory()) {
+ if (($this->destFile !== null && $this->destDir !== null)
+ || ($this->destFile === null && $this->destDir === null)) {
+ throw new BuildException("One and only one of tofile and todir must be set.");
+ }
+
+ if ($this->destFile === null)
+ {
+ $this->destFile = new PhingFile($this->destDir, $this->file->getName());
+ }
+
+ if ($this->destDir === null)
+ {
+ $this->destDir = $this->destFile->getParentFile();
+ }
+
+ $this->completeDirMap[$this->file->getAbsolutePath()] = $this->destFile->getAbsolutePath();
+
+ $this->file = null;
+ } else {
+ parent::validateAttributes();
+ }
+ }
+
+ protected function doWork() {
+ if (count($this->completeDirMap) > 0)
+ {
+ foreach ($this->completeDirMap as $from => $to)
+ {
+ $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->fileUtils->copyFile($f, $d, $this->forceOverwrite, $this->preserveLMT, $this->filterChains, $this->getProject(), $this->mode);
+ $f->delete(true);
+ $moved = true;
+ } catch (IOException $ioe) {
+ $moved = false;
+ $this->logError("Failed to rename $from to $to: " . $ioe->getMessage());
+ }
+ }
+ }
+
+ $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;
+ }
+
+ $f = new PhingFile($from);
+ $d = new PhingFile($to);
+
+ 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(), $this->mode);
+
+ $f->delete();
+ } catch (IOException $ioe) {
+ $this->logError("Failed to move $from to $to: " . $ioe->getMessage(), $this->location);
+ }
+ } // 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->logError("Unable to create directory " . $d->getAbsolutePath());
+ } 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) {
+ $this->logError("Unable to delete directory " . $d->__toString() . ": " . $e->getMessage());
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php
new file mode 100755
index 00000000..2aec4db5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php
@@ -0,0 +1,161 @@
+<?php
+/*
+ * $Id: 5d02fa25dc18b56093884ae756b1720aafb42937 $
+ *
+ * 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.
+ *
+ * <samp>
+ * <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>
+ * </samp>
+ *
+ * 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 $Id: 5d02fa25dc18b56093884ae756b1720aafb42937 $
+ * @access public
+ * @package phing.tasks.system
+ */
+class PhingCallTask extends Task {
+
+ /**
+ * The called Phing task.
+ *
+ * @var PhingTask
+ */
+ private $callee;
+
+ /**
+ * The target to call.
+ *
+ * @var string
+ */
+ private $subTarget;
+
+ /**
+ * Whether to inherit all properties from current project.
+ *
+ * @var boolean
+ */
+ private $inheritAll = true;
+
+ /**
+ * Whether to inherit refs from current project.
+ *
+ * @var boolean
+ */
+ 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;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * 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->setHaltOnFailure(true);
+ $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->getLocation());
+ }
+
+ $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();
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/PhingTask.php b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php
new file mode 100755
index 00000000..6ac0b5ac
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PhingTask.php
@@ -0,0 +1,627 @@
+<?php
+
+/*
+ * $Id: 2eec26f6ebaaeceb4eca76644de88bde7515f5dc $
+ *
+ * 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 $Id: 2eec26f6ebaaeceb4eca76644de88bde7515f5dc $
+ * @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)) {
+ // preserve old settings
+ $savedDir = $this->dir;
+ $savedPhingFile = $this->phingFile;
+ $savedTarget = $this->newTarget;
+
+ // 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());
+ }
+ }
+
+ // Remove any dangling references to help the GC
+ foreach ($this->properties as $property) {
+ $property->setFallback(null);
+ }
+ }
+
+ /**
+ * Execute phing file.
+ *
+ * @return void
+ */
+ private function processFile() {
+
+ $buildFailed = false;
+ $savedDir = $this->dir;
+ $savedPhingFile = $this->phingFile;
+ $savedTarget = $this->newTarget;
+
+ $savedBasedirAbsPath = null; // this is used to save the basedir *if* we change it
+
+ try {
+
+ if ($this->newProject === null) {
+ $this->reinit();
+ }
+
+ $this->initializeProject();
+
+ if ($this->dir !== null) {
+
+ $dirAbsPath = $this->dir->getAbsolutePath();
+
+ // BE CAREFUL! -- when the basedir is changed for a project,
+ // all calls to getAbsolutePath() on a relative-path dir will
+ // be made relative to the project's basedir! This means
+ // that subsequent calls to $this->dir->getAbsolutePath() will be WRONG!
+
+ // We need to save the current project's basedir first.
+ $savedBasedirAbsPath = $this->getProject()->getBasedir()->getAbsolutePath();
+
+ $this->newProject->setBasedir($this->dir);
+
+ // Now we must reset $this->dir so that it continues to resolve to the same
+ // path.
+ $this->dir = new PhingFile($dirAbsPath);
+
+ if ($savedDir !== null) { // has been set explicitly
+ $this->newProject->setInheritedProperty("project.basedir", $this->dir->getAbsolutePath());
+ }
+
+ } else {
+
+ // Since we're not changing the basedir here (for file resolution),
+ // we don't need to worry about any side-effects in this scanrio.
+ $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);
+ if (Phing::getMsgOutputLevel() <= Project::MSG_DEBUG) {
+ $lines = explode("\n", $e->getTraceAsString());
+ foreach($lines as $line) {
+ $this->log($line, Project::MSG_DEBUG);
+ }
+ }
+ // important!!! continue on to perform cleanup tasks.
+ }
+
+
+ // reset environment values to prevent side-effects.
+
+ $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;
+
+ // If the basedir for any project was changed, we need to set that back here.
+ if ($savedBasedirAbsPath !== null) {
+ chdir($savedBasedirAbsPath);
+ }
+
+ if ($this->haltOnFailure && $buildFailed) {
+ 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>.
+ *
+ * @package phing.tasks.system
+ */
+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 100755
index 00000000..99316f7b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php
@@ -0,0 +1,192 @@
+<?php
+/*
+ * $Id: 8c46403ac685f362e310ffcceff5d4193bf09ef0 $
+ *
+ * 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 $Id$
+ * @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 = null; // name of property to set to return value
+ protected $params = array(); // parameters for function calls
+
+ protected $logLevel = Project::MSG_INFO;
+
+ /**
+ * Set level of log messages generated (default = info)
+ * @param string $level
+ */
+ public function setLevel($level)
+ {
+ switch ($level)
+ {
+ case "error": $this->logLevel = Project::MSG_ERR; break;
+ case "warning": $this->logLevel = Project::MSG_WARN; break;
+ case "info": $this->logLevel = Project::MSG_INFO; break;
+ case "verbose": $this->logLevel = Project::MSG_VERBOSE; break;
+ case "debug": $this->logLevel = Project::MSG_DEBUG; break;
+ }
+ }
+
+ /** 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);
+ }
+
+ if ($this->function !== null) {
+ $this->callFunction();
+ } elseif ($this->expression !== null) {
+ $this->evalExpression();
+ }
+ }
+
+ /**
+ * 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 . "()", $this->logLevel);
+ foreach($params as $p) {
+ $this->log(" param: " . $p, Project::MSG_VERBOSE);
+ }
+
+ $return = call_user_func_array($user_func, $params);
+
+ if ($this->returnProperty !== null) {
+ $this->project->setProperty($this->returnProperty, $return);
+ }
+ }
+
+ /**
+ * Evaluates expression and returns resulting value.
+ * @return mixed
+ */
+ protected function evalExpression() {
+ $this->log("Evaluating PHP expression: " . $this->expression, $this->logLevel);
+ if (!StringHelper::endsWith(';', trim($this->expression))) {
+ $this->expression .= ';';
+ }
+
+ if ($this->returnProperty !== null) {
+ $retval = null;
+ eval('$retval = ' . $this->expression);
+ $this->project->setProperty($this->returnProperty, $retval);
+ } else {
+ eval($this->expression);
+ }
+ }
+
+ /** 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.
+ *
+ * @package phing.tasks.system
+ */
+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 100755
index 00000000..7a337764
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php
@@ -0,0 +1,234 @@
+<?php
+/*
+ * $Id: d2de9371732599b179facb97ef937b2cfbfbead2 $
+ *
+ * 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 $Id$
+ * @package phing.tasks.system
+ * @deprecated - in favor of the more capable InputTask
+ */
+class PropertyPromptTask extends Task {
+
+ /**
+ * The property name to set with the output.
+ * @var string
+ */
+ private $propertyName; // required
+
+ /**
+ * The default value to use if no input is entered.
+ * @var string
+ */
+ private $defaultValue;
+
+ /**
+ * The entered value.
+ * @var string
+ */
+ private $proposedValue;
+
+ /**
+ * The text to use for the prompt.
+ * @var string
+ */
+ private $promptText;
+
+ /**
+ * The character to put after the text.
+ * @var string
+ */
+ private $promptCharacter;
+
+ /**
+ *
+ */
+ private $useExistingValue;
+
+ /**
+ * 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 ($this->proposedValue === "") {
+ $this->log("No value specified, using default.", Project::MSG_VERBOSE);
+ $this->proposedValue = $this->defaultValue;
+ }
+
+ if (isset($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 string $newPromptcharacter
+ */
+ public function setPromptCharacter($newPromptcharacter) {
+ $this->promptCharacter = $newPromptcharacter;
+ }
+
+ /**
+ * Sets text of the prompt.
+ * @param string $newPrompttext
+ */
+ 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;
+ }
+
+ /**
+ * Sets the prompt text that will be presented to the user.
+ * @param string $prompt
+ * @return void
+ */
+ public function addText($prompt) {
+ $this->setPromptText($prompt);
+ }
+
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php
new file mode 100755
index 00000000..0d8854c8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/PropertyTask.php
@@ -0,0 +1,438 @@
+<?php
+
+/*
+ * $Id: e6d7123b6331d5032ad1e67967cf54ef2aae3f7f $
+ *
+ * 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 $Id: e6d7123b6331d5032ad1e67967cf54ef2aae3f7f $
+ * @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 100755
index 00000000..d49c47f2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php
@@ -0,0 +1,155 @@
+<?php
+/*
+ * $Id: 3dcb1ad6e9fd3b2801c1fe3bcbaf2fcab8ea6018 $
+ *
+ * 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 $Id$
+ * @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);
+ }
+
+ }
+
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php
new file mode 100755
index 00000000..bdd707a2
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php
@@ -0,0 +1,159 @@
+<?php
+/*
+ * $Id: 9635ed3f6605f5ed64b74e85731dbcd3ad43ce0f $
+ *
+ * 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 $Id$
+ * @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;
+
+ /**
+ * Log level
+ */
+ private $logLevel = Project::MSG_VERBOSE;
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Set level of log messages generated (default = verbose)
+ *
+ * @param string $level Log level
+ *
+ * @return void
+ */
+ public function setLevel($level)
+ {
+ switch ($level) {
+ case 'error':
+ $this->logLevel = Project::MSG_ERR;
+ break;
+ case 'warning':
+ $this->logLevel = Project::MSG_WARN;
+ break;
+ case 'info':
+ $this->logLevel = Project::MSG_INFO;
+ break;
+ case 'verbose':
+ $this->logLevel = Project::MSG_VERBOSE;
+ break;
+ case 'debug':
+ $this->logLevel = Project::MSG_DEBUG;
+ break;
+ default:
+ throw new BuildException(
+ sprintf('Unknown log level "%s"', $level)
+ );
+ }
+ }
+
+ /**
+ * 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(), $this->logLevel);
+ $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..d080deda
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/SequentialTask.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * $Id: e6be0ff54ade0fb900d101759d8788590e769831 $
+ *
+ * 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
+ * @package phing.tasks.system
+ */
+class SequentialTask extends Task implements TaskContainer {
+
+ /** Optional Vector holding the nested tasks */
+ protected $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 100755
index 00000000..84552d69
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php
@@ -0,0 +1,165 @@
+<?php
+
+/*
+ * $Id: df52def0bb44ce1b0909f5e8858e79b2ef88ca0f $
+ *
+ * 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';
+
+/**
+ * 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 $Id: df52def0bb44ce1b0909f5e8858e79b2ef88ca0f $
+ * @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;
+
+ /**
+ * Name of file to load multiple definitions from.
+ * @var string
+ */
+ private $typeFile;
+
+ /**
+ * Set the classpath to be used when searching for component being defined
+ *
+ * @param Path $classpath A 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
+ *
+ * @return Path
+ */
+ 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;
+ }
+
+ /**
+ * Sets the file of definitionas to use to use.
+ * @param string $file
+ */
+ public function setFile($file) {
+ $this->typeFile = $file;
+ }
+
+ /** Main entry point */
+ public function main() {
+ if ($this->typeFile === null &&
+ ($this->name === null || $this->classname === null)) {
+ throw new BuildException("You must specify name and class attributes for <taskdef>.");
+ }
+ if ($this->typeFile == null) {
+ $this->log("Task " . $this->name . " will be handled by class " . $this->classname, Project::MSG_VERBOSE);
+ $this->project->addTaskDefinition($this->name, $this->classname, $this->classpath);
+ } else {
+ try { // try to load taskdefs given in file
+ $props = new Properties();
+ $in = new PhingFile((string) $this->typeFile);
+
+ if ($in === null) {
+ throw new BuildException("Can't load task list {$this->typeFile}");
+ }
+ $props->load($in);
+
+ $enum = $props->propertyNames();
+ foreach($enum as $key) {
+ $value = $props->getProperty($key);
+ $this->project->addTaskDefinition($key, $value, $this->classpath);
+ }
+ } catch (IOException $ioe) {
+ throw new BuildException("Can't load task list {$this->typeFile}");
+ }
+ }
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/TouchTask.php b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php
new file mode 100755
index 00000000..3c45d0d3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/TouchTask.php
@@ -0,0 +1,170 @@
+<?php
+/*
+ * $Id: e581b40ff4e3eac5f62a32b48b4a22285cbc51c1 $
+ *
+ * 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 $Id$
+ * @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/TryCatchTask.php b/buildscripts/phing/classes/phing/tasks/system/TryCatchTask.php
new file mode 100644
index 00000000..b27d829b
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/TryCatchTask.php
@@ -0,0 +1,123 @@
+<?php
+/*
+ * $Id: acc9e5d431141ae13ea43c1ed1d3177a4fb60bf9 $
+ *
+ * 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';
+
+/**
+ * A wrapper task that lets you run tasks(s) when another set
+ * of tasks fails.
+ *
+ * Inspired by {@link http://ant-contrib.sourceforge.net/tasks/tasks/trycatch.html}
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id: acc9e5d431141ae13ea43c1ed1d3177a4fb60bf9 $
+ * @package phing.tasks.system
+ */
+class TryCatchTask extends Task
+{
+ protected $propertyName = "";
+
+ protected $tryContainer = null;
+ protected $catchContainer = null;
+ protected $finallyContainer = null;
+
+ /**
+ * Main method
+ *
+ * @throws BuildException
+ * @return void
+ */
+ public function main()
+ {
+ $exc = null;
+
+ if (empty($this->tryContainer)) {
+ throw new BuildException('A nested <try> element is required');
+ }
+
+ try {
+ $this->tryContainer->perform();
+ } catch (BuildException $e) {
+ if (!empty($this->propertyName)) {
+ $this->project->setProperty($this->propertyName, $e->getMessage());
+ }
+
+ if (!empty($this->referenceName)) {
+ $this->project->addReference($this->referenceName, $e);
+ }
+
+ if (!empty($this->catchContainer)) {
+ $this->catchContainer->perform();
+ } else {
+ $exc = $e;
+ }
+ }
+
+ if (!empty($this->finallyContainer)) {
+ $this->finallyContainer->perform();
+ }
+
+ if (!empty($exc)) {
+ throw $exc;
+ }
+ }
+
+ /**
+ * Sets the name of the property that will
+ * contain the exception message.
+ *
+ * @param string $property
+ */
+ public function setProperty($property)
+ {
+ $this->propertyName = (string) $property;
+ }
+
+ /**
+ * Add nested <try> element
+ *
+ * @param SequentialTask $container
+ */
+ public function addTry(SequentialTask $container)
+ {
+ $this->tryContainer = $container;
+ }
+
+ /**
+ * Add nested <catch> element
+ *
+ * @param SequentialTask $container
+ */
+ public function addCatch(SequentialTask $container)
+ {
+ $this->catchContainer = $container;
+ }
+
+ /**
+ * Add nested <finally> element
+ *
+ * @param SequentialTask $container
+ */
+ public function addFinally(SequentialTask $container)
+ {
+ $this->finallyContainer = $container;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/tasks/system/TstampTask.php b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php
new file mode 100755
index 00000000..44f2c3f0
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/TstampTask.php
@@ -0,0 +1,171 @@
+<?php
+/*
+ * $Id: c0693134153e6095ab198edb5cf204f53bb7ba69 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id$
+ * @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);
+ }
+}
+
+/**
+ * @package phing.tasks.system
+ */
+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 100755
index 00000000..c03e716d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/TypedefTask.php
@@ -0,0 +1,127 @@
+<?php
+/*
+ * $Id: 6122dcb36b79ffe3c3fb430a0b4586d9d145410b $
+ *
+ * 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 $Id$
+ * @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 A 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
+ *
+ * @return Path
+ */
+ 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 100755
index 00000000..1954fe88
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php
@@ -0,0 +1,257 @@
+<?php
+/*
+ * $Id: 5b0af63dfa9acb85374dcdd2d7fd866ce81391d0 $
+ *
+ * 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/tasks/system/PropertyTask.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 $Id$
+ * @package phing.tasks.system
+ */
+class UpToDateTask extends Task implements Condition {
+
+ private $_property;
+ private $_value;
+ private $_sourceFile;
+ private $_targetFile;
+ private $sourceFileSets = array();
+ private $_filelists = 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;
+ }
+
+ /**
+ * Get property name
+ * @param property the name of the property to set if Target is up-to-date.
+ */
+ public function getProperty() {
+ return $this->_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.
+ *
+ * @deprecated Deprecated since Phing 2.4.0
+ */
+ public function createSrcfiles() {
+ $fs = new FileSet();
+ $this->sourceFileSets[] = $fs;
+ return $fs;
+ }
+
+ /**
+ * Nested <fileset> element.
+ */
+ public function addFileset(FileSet $fs) {
+ $this->sourceFileSets[] = $fs;
+ }
+
+ /**
+ * Supports embedded <filelist> element.
+ * @return FileList
+ */
+ public function createFileList() {
+ $num = array_push($this->_filelists, new FileList());
+ return $this->_filelists[$num-1];
+ }
+
+ /**
+ * 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 && count($this->_filelists) == 0 && $this->_sourceFile === null) {
+ throw new BuildException("At least one srcfile or a nested "
+ . "<fileset> or <filelist> element must be set.");
+ }
+
+ if ((count($this->sourceFileSets) > 0 || count($this->_filelists) > 0) && $this->_sourceFile !== null) {
+ throw new BuildException("Cannot specify both the srcfile "
+ . "attribute and a nested <fileset> "
+ . "or <filelist> 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());
+ }
+
+ for($i=0,$size=count($this->_filelists); $i < $size && $upToDate; $i++) {
+ $fl = $this->_filelists[$i];
+ $srcFiles = $fl->getFiles($this->project);
+ $upToDate = $upToDate && $this->scanDir($fs->getDir($this->project),
+ $srcFiles);
+ }
+
+ 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) {
+ $property = $this->project->createTask('property');
+ $property->setName($this->getProperty());
+ $property->setValue($this->getValue());
+ $property->setOverride(true);
+ $property->main(); // execute
+
+ 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/WaitForTask.php b/buildscripts/phing/classes/phing/tasks/system/WaitForTask.php
new file mode 100755
index 00000000..00bcff1e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/WaitForTask.php
@@ -0,0 +1,188 @@
+<?php
+/*
+ * $Id: dae67bf2b9c154d4614f30e9ba85c16782550bb3 $
+ *
+ * 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';
+
+/**
+ * Based on Apache Ant Wait For:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ *
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id$
+ * @package phing.tasks.system
+ */
+class WaitForTask extends ConditionBase
+{
+ const ONE_MILLISECOND = 1;
+ const ONE_SECOND = 1000;
+ const ONE_MINUTE = 60000;
+ const ONE_HOUR = 3600000;
+ const ONE_DAY = 86400000;
+ const ONE_WEEK = 604800000;
+
+ const DEFAULT_MAX_WAIT_MILLIS = 180000;
+ const DEFAULT_CHECK_MILLIS = 500;
+
+ protected $maxWait = self::DEFAULT_MAX_WAIT_MILLIS;
+ protected $maxWaitMultiplier = self::ONE_MILLISECOND;
+
+ protected $checkEvery = self::DEFAULT_CHECK_MILLIS;
+ protected $checkEveryMultiplier = self::ONE_MILLISECOND;
+
+ protected $timeoutProperty = null;
+
+ /**
+ * Set the maximum length of time to wait.
+ * @param int $maxWait
+ */
+ public function setMaxWait($maxWait)
+ {
+ $this->maxWait = (int) $maxWait;
+ }
+
+ /**
+ * Set the max wait time unit
+ * @param string $maxWaitUnit
+ */
+ public function setMaxWaitUnit($maxWaitUnit)
+ {
+ $this->maxWaitMultiplier = $this->_convertUnit($maxWaitUnit);
+ }
+
+ /**
+ * Set the time between each check
+ * @param int $checkEvery
+ */
+ public function setCheckEvery($checkEvery)
+ {
+ $this->checkEvery = (int) $checkEvery;
+ }
+
+ /**
+ * Set the check every time unit
+ * @param string $checkEveryUnit
+ */
+ public function setCheckEveryUnit($checkEveryUnit)
+ {
+ $this->checkEveryMultiplier = $this->_convertUnit($checkEveryUnit);
+ }
+
+ /**
+ * Name of the property to set after a timeout.
+ * @param string $timeoutProperty
+ */
+ public function setTimeoutProperty($timeoutProperty)
+ {
+ $this->timeoutProperty = $timeoutProperty;
+ }
+
+ /**
+ * Convert the unit to a multipler.
+ * @param string $unit
+ */
+ protected function _convertUnit($unit)
+ {
+ switch ($unit) {
+ case "week": {
+ return self::ONE_WEEK;
+ }
+
+ case "day": {
+ return self::ONE_DAY;
+ }
+
+ case "hour": {
+ return self::ONE_HOUR;
+ }
+
+ case "minute": {
+ return self::ONE_MINUTE;
+ }
+
+ case "second": {
+ return self::ONE_SECOND;
+ }
+
+ case "millisecond": {
+ return self::ONE_MILLISECOND;
+ }
+
+ default: {
+ throw new BuildException("Illegal unit '$unit'");
+ }
+ }
+ }
+
+ /**
+ * Check repeatedly for the specified conditions until they become
+ * true or the timeout expires.
+ * @throws BuildException
+ */
+ public function main()
+ {
+ if ($this->countConditions() > 1) {
+ throw new BuildException("You must not nest more than one condition into <waitfor>");
+ }
+
+ if ($this->countConditions() < 1) {
+ throw new BuildException("You must nest a condition into <waitfor>");
+ }
+
+ $cs = $this->getIterator();
+ $condition = $cs->current();
+
+ $maxWaitMillis = $this->maxWait * $this->maxWaitMultiplier;
+ $checkEveryMillis = $this->checkEvery * $this->checkEveryMultiplier;
+
+ $start = microtime(true) * 1000;
+ $end = $start + $maxWaitMillis;
+
+ while (microtime(true) * 1000 < $end) {
+ if ($condition->evaluate()) {
+ $this->log("waitfor: condition was met", Project::MSG_VERBOSE);
+
+ return;
+ }
+
+ usleep($checkEveryMillis * 1000);
+ }
+
+ $this->log("waitfor: timeout", Project::MSG_VERBOSE);
+
+ if ($this->timeoutProperty != null) {
+ $this->project->setNewProperty($this->timeoutProperty, "true");
+ }
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/tasks/system/WarnTask.php b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php
new file mode 100755
index 00000000..28f0ad92
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/WarnTask.php
@@ -0,0 +1,35 @@
+<?php
+/*
+ * $Id: a2192433abbea9c5fe4b4ddb518cde8c09a643da $
+ *
+ * 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 $Id$
+ * @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..7155caf8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/XsltTask.php
@@ -0,0 +1,103 @@
+<?php
+/*
+ * $Id: 8f87e1c7908c06223382baf628d018c3a0f10824 $
+ *
+ * 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 $Id: 8f87e1c7908c06223382baf628d018c3a0f10824 $
+ * @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);
+ }
+
+ /**
+ * Whether to resolve entities in the XML document.
+ *
+ * @param bool $resolveExternals
+ *
+ * @since 2.4
+ */
+ function setResolveDocumentExternals($resolveExternals) {
+ $this->xsltFilter->setResolveDocumentExternals((bool)$resolveExternals);
+ }
+
+ /**
+ * Whether to resolve entities in the stylesheet.
+ *
+ * @param bool $resolveExternals
+ *
+ * @since 2.4
+ */
+ function setResolveStylesheetExternals($resolveExternals) {
+ $this->xsltFilter->setResolveStylesheetExternals((bool)$resolveExternals);
+ }
+
+ /**
+ * 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 100755
index 00000000..41b57a8e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php
@@ -0,0 +1,46 @@
+<?php
+/*
+ * $Id: 69074307e3d1aae5fbfaa03842f5a8fc14b49625 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..9c9d90e5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/Condition.php
@@ -0,0 +1,38 @@
+<?php
+
+/*
+ * $Id: c971532805c4ac4c3d3cbf05a5c53abe7279b336 $
+ *
+ * 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 $Id$
+ * @package phing.tasks.system.condition
+ */
+interface Condition {
+ /**
+ * @return boolean
+ * @throws BuildException
+ */
+ public function evaluate();
+}
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 100755
index 00000000..e21ce4e4
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php
@@ -0,0 +1,197 @@
+<?php
+/*
+ * $Id: 8721880badf6aee475a8cb87c88ca3dc4299efb8 $
+ *
+ * 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 $Id$
+ * @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.
+ *
+ * @package phing.tasks.system.condition
+ */
+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 100755
index 00000000..d7fb80ac
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php
@@ -0,0 +1,76 @@
+<?php
+
+/*
+ * $Id: 6cdecc53a715fce4601b1ceb64c8ec95d29c1468 $
+ *
+ * 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 $Id: 6cdecc53a715fce4601b1ceb64c8ec95d29c1468 $
+ * @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
+ : strpos(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 100755
index 00000000..4be4e8fe
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php
@@ -0,0 +1,78 @@
+<?php
+/*
+ * $Id: faec716501a00cdeb84b8c893b5bbe5c76064dec $
+ *
+ * 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 $Id: faec716501a00cdeb84b8c893b5bbe5c76064dec $
+ * @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 100755
index 00000000..8a1b3dcf
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php
@@ -0,0 +1,60 @@
+<?php
+/*
+ * $Id: f7d355bdf8f7aa539afb572e2fe033ffd3bcd89b $
+ *
+ * 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 $Id: f7d355bdf8f7aa539afb572e2fe033ffd3bcd89b $
+ * @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 100755
index 00000000..24f3f609
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php
@@ -0,0 +1,53 @@
+<?php
+/*
+ * $Id: 5c5924da5cff2626af09b4908703a21eec79c777 $
+ *
+ * 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 $Id$
+ * @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..8c6d19fc
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/IsTrueCondition.php
@@ -0,0 +1,59 @@
+<?php
+/*
+ * $Id: d567f7c477e075a5c06d3f8e07ff8a7412cf31cd $
+ *
+ * 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 100755
index 00000000..081876af
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php
@@ -0,0 +1,48 @@
+<?php
+/*
+ * $Id: d8c985da7c759357135cf717b1f4b52a1bd50cb6 $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..d88df271
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php
@@ -0,0 +1,46 @@
+<?php
+/*
+ * $Id: adcd6785a85304a0860cc3dd9a0146d965c1cb0c $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..50a7174f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php
@@ -0,0 +1,63 @@
+<?php
+/*
+ * $Id: d63246e2d25230f5ba6e45a651497e3ba01abe2c $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..08e291e3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php
@@ -0,0 +1,52 @@
+<?php
+/*
+ * $Id: e62ed1e00cc6ed859746760c89bc0f873db4620a $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..60ca4d04
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/AbstractFileSet.php
@@ -0,0 +1,587 @@
+<?php
+/*
+ * $Id: b7d8ccab6ed556e74626d880dcc09be20ea8bd58 $
+ *
+ * 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 $Id$
+ * @see ProjectComponent
+ * @package phing.types
+ */
+class AbstractFileSet extends DataType implements SelectorContainer {
+
+ // These vars are public for cloning purposes
+
+ /**
+ * @var boolean
+ */
+ public $useDefaultExcludes = true;
+
+ /**
+ * Whether to expand/dereference symbolic links, default is false
+ * @var boolean
+ */
+ protected $expandSymbolicLinks = false;
+
+ /**
+ * @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();
+ }
+
+ /**
+ * Sets whether to expand/dereference symbolic links, default is false
+ * @var boolean
+ */
+ function setExpandSymbolicLinks($expandSymbolicLinks)
+ {
+ $this->expandSymbolicLinks = $expandSymbolicLinks;
+ }
+
+ /**
+ * 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->isLink() || !$this->expandSymbolicLinks) {
+ if (!$this->dir->isDirectory()) {
+ throw new BuildException($this->dir->getAbsolutePath()." is not a directory.");
+ }
+ }
+ $ds = new DirectoryScanner();
+ $ds->setExpandSymbolicLinks($this->expandSymbolicLinks);
+ $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 100755
index 00000000..d6b36e14
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Commandline.php
@@ -0,0 +1,475 @@
+<?php
+/*
+ * $Id: 891b349dcd88b825ae99edf53ed4c7ac2c1c2467 $
+ *
+ * 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>
+ * &lt;someelement&gt;<br>
+ * &nbsp;&nbsp;&lt;acommandline executable="/executable/to/run"&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 1" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument line="argument_1 argument_2 argument_3" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;argument value="argument 4" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/acommandline&gt;<br>
+ * &lt;/someelement&gt;<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>
+ * @package phing.types
+ */
+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, $escape = false) {
+ if ($escape) {
+ return escapeshellarg($argument);
+ } elseif (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, $escape = false) {
+ // 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], $escape);
+ }
+ 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 .= ":" . PHP_EOL;
+ for ($i = $offset, $alen=count($args); $i < $alen; $i++) {
+ $buf .= "'" . $args[$i] . "'" . PHP_EOL;
+ }
+ $buf .= self::DISCLAIMER;
+ return $buf;
+ }
+}
+
+
+/**
+ * "Inner" class used for nested xml command line definitions.
+ *
+ * @package phing.types
+ */
+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 &lt;execon&gt; and &lt;transform&gt; - don't know
+ * whether there might be additional use cases.</p> --SB
+ *
+ * @package phing.types
+ */
+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..8aa3b487
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/DataType.php
@@ -0,0 +1,182 @@
+<?php
+/*
+ * $Id: 3b15630144c62dda1f447d8eed1e5eda7ac8a466 $
+ *
+ * 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..85b2c529
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Description.php
@@ -0,0 +1,53 @@
+<?php
+
+/*
+ * $Id: bb303eb742207be6958c8107e21ec7c964c09dee $
+ *
+ * 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 &lt;description&gt; 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..527127bb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/DirSet.php
@@ -0,0 +1,49 @@
+<?php
+
+/*
+ * $Id: 1ab2ec4f1b43daee6cf4c247b4b18b78d87052bc $
+ *
+ * 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/Excludes.php b/buildscripts/phing/classes/phing/types/Excludes.php
new file mode 100644
index 00000000..2d45b593
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Excludes.php
@@ -0,0 +1,208 @@
+<?php
+/*
+ * $Id: 0c22f261d1984da235c6cf4993d1275c225a33ba $
+ *
+ * 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/FileSet.php';
+require_once 'phing/types/ExcludesNameEntry.php';
+
+/**
+ * Datatype which handles excluded files, classes and methods.
+ *
+ * @package phing.types
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: 0c22f261d1984da235c6cf4993d1275c225a33ba $
+ * @since 2.4.6
+ */
+class Excludes extends DataType
+{
+ /**
+ * The directory scanner for getting the excluded files
+ *
+ * @var DirectoryScanner
+ */
+ private $_directoryScanner = null;
+
+ /**
+ * Holds the excluded file patterns
+ *
+ * @var array
+ */
+ private $_files = array();
+
+ /**
+ * Holds the excluded classes
+ *
+ * @var array
+ */
+ private $_classes = array();
+
+ /**
+ * Holds the excluded methods
+ *
+ * @var array
+ */
+ private $_methods = array();
+
+ /**
+ * ctor
+ *
+ * @param Project $project
+ */
+ public function __construct(Project $project)
+ {
+ $this->_directoryScanner = new DirectoryScanner();
+ $this->_directoryScanner->setBasedir($project->getBasedir());
+ }
+
+ /**
+ * Add a name entry on the exclude file list
+ *
+ * @return ExcludesNameEntry Reference to object
+ */
+ public function createFile()
+ {
+ return $this->_addFile($this->_files);
+ }
+
+ /**
+ * Add a name entry on the exclude class list
+ *
+ * @return ExcludesNameEntry Reference to object
+ */
+ public function createClass()
+ {
+ return $this->_addClass($this->_classes);
+ }
+
+ /**
+ * Add a name entry on the exclude method list
+ *
+ * @return ExcludesNameEntry Reference to object
+ */
+ public function createMethod()
+ {
+ return $this->_addMethod($this->_methods);
+ }
+
+ /**
+ * Adds a file to the exclusion list
+ *
+ * @param FileSet $fileSet The FileSet into which the nameentry should be added
+ *
+ * @return ExcludesNameEntry Reference to the created ExcludesNameEntry instance
+ */
+ private function _addFile(&$fileList)
+ {
+ $file = new ExcludesNameEntry();
+ $fileList[] = $file;
+
+ return $file;
+ }
+
+ /**
+ * Adds a class to the exclusion list
+ *
+ * @return ExcludesNameEntry Reference to the created ExcludesNameEntry instance
+ */
+ private function _addClass(&$classList)
+ {
+ $excludedClass = new ExcludesNameEntry();
+ $classList[] = $excludedClass;
+
+ return $excludedClass;
+ }
+
+ /**
+ * Adds a method to the exclusion list
+ *
+ * @return ExcludesNameEntry Reference to the created ExcludesNameEntry instance
+ */
+ private function _addMethod(&$methodList)
+ {
+ $excludedMethod = new ExcludesNameEntry();
+ $methodList[] = $excludedMethod;
+
+ return $excludedMethod;
+ }
+
+ /**
+ * Returns the excluded files
+ *
+ * @return array
+ */
+ public function getExcludedFiles()
+ {
+ $includes = array();
+
+ foreach ($this->_files as $file) {
+ $includes[] = $file->getName();
+ }
+
+ $this->_directoryScanner->setIncludes($includes);
+ $this->_directoryScanner->scan();
+
+ $files = $this->_directoryScanner->getIncludedFiles();
+ $dir = $this->_directoryScanner->getBasedir();
+ $fileList = array();
+
+ foreach ($files as $file) {
+ $fileList[] = $dir . DIRECTORY_SEPARATOR . $file;
+ }
+
+ return $fileList;
+ }
+
+ /**
+ * Returns the excluded class names
+ *
+ * @return array
+ */
+ public function getExcludedClasses()
+ {
+ $excludedClasses = array();
+
+ foreach ($this->_classes as $excludedClass) {
+ $excludedClasses[] = $excludedClass->getName();
+ }
+
+ return $excludedClasses;
+ }
+
+ /**
+ * Returns the excluded method names
+ *
+ * @return array
+ */
+ public function getExcludedMethods()
+ {
+ $excludedMethods = array();
+
+ foreach ($this->_methods as $excludedMethod) {
+ $classAndMethod = explode('::', $excludedMethod->getName());
+ $className = $classAndMethod[0];
+ $methodName = $classAndMethod[1];
+
+ $excludedMethods[$className][] = $methodName;
+ }
+
+ return $excludedMethods;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/types/ExcludesNameEntry.php b/buildscripts/phing/classes/phing/types/ExcludesNameEntry.php
new file mode 100644
index 00000000..1aa6aae5
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/ExcludesNameEntry.php
@@ -0,0 +1,81 @@
+<?php
+/*
+ * $Id: a1098700b4f205baacfd5adf5434e5a4803a6a3f $
+ *
+ * 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 for holding nested excludes elements (file, class, method).
+ *
+ * @package phing.types
+ * @author Benjamin Schultz <bschultz@proqrent.de>
+ * @version $Id: a1098700b4f205baacfd5adf5434e5a4803a6a3f $
+ * @since 2.4.6
+ */
+class ExcludesNameEntry
+{
+ /**
+ * Holds the name of a file, class or method or a file pattern
+ *
+ * @var string
+ */
+ private $_name;
+
+ /**
+ * An alias for the setName() method.
+ * Set the name of a file pattern.
+ *
+ * @see setName()
+ *
+ * @param string $pattern The file pattern
+ */
+ public function addText($pattern)
+ {
+ $this->setName($pattern);
+ }
+
+ /**
+ * Set the name of a file, class or method
+ *
+ * @param string $name
+ */
+ public function setName($name)
+ {
+ $this->_name = (string) $name;
+ }
+
+ /**
+ * Get the name of a file, class or method or the file pattern
+ *
+ * @return string The name of a file, class or method or the file pattern
+ */
+ public function getName()
+ {
+ return $this->_name;
+ }
+
+ /**
+ * Gets a string representation of this name or pattern.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return $this->_name;
+ }
+} \ No newline at end of file
diff --git a/buildscripts/phing/classes/phing/types/FileList.php b/buildscripts/phing/classes/phing/types/FileList.php
new file mode 100755
index 00000000..bc7c6b18
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/FileList.php
@@ -0,0 +1,224 @@
+<?php
+/*
+ * $Id: aab0ffb8e2266923f6cdaf165741dc38931a2aed $
+ *
+ * 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 $Id$
+ * @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.
+ * @param Project $p
+ * @return PhingFile
+ */
+ function getListFile(Project $p) {
+ 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..229e4419
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/FileSet.php
@@ -0,0 +1,56 @@
+<?php
+
+/*
+ * $Id: 1fbeb217059bb26788059dd46affde1428d5a52e $
+ *
+ * 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 100755
index 00000000..e6575c33
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/FilterChain.php
@@ -0,0 +1,191 @@
+<?php
+/*
+ * $Id: ec2362b430c0a863a77968e9003b09c4b9a78d7e $
+ *
+ * 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/IconvFilter.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/ReplaceTokensWithFile.php';
+include_once 'phing/filters/StripPhpComments.php';
+include_once 'phing/filters/StripLineBreaks.php';
+include_once 'phing/filters/StripLineComments.php';
+include_once 'phing/filters/StripWhitespace.php';
+include_once 'phing/filters/TabToSpaces.php';
+include_once 'phing/filters/TidyFilter.php';
+include_once 'phing/filters/TranslateGettext.php';
+include_once 'phing/filters/XincludeFilter.php';
+include_once 'phing/filters/XsltFilter.php';
+
+/**
+ * FilterChain may contain a chained set of filter readers.
+ *
+ * @author Yannick Lecaillez <yl@seasonfive.com>
+ * @version $Id$
+ * @package phing.types
+ */
+class FilterChain extends DataType {
+
+ private $filterReaders = array();
+
+ function __construct($project = null) {
+ if ($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 addIconvFilter(IconvFilter $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 addReplaceTokensWithFile(ReplaceTokensWithFile $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 addStripWhitespace(StripWhitespace $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 addXincludeFilter(XincludeFilter $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
+ * @throws 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/IterableFileSet.php b/buildscripts/phing/classes/phing/types/IterableFileSet.php
new file mode 100644
index 00000000..bc800bbe
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/IterableFileSet.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * $Id: a607a54aa4e434c01a1f36600274fb31041549e2 $
+ *
+ * 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>.
+ */
+
+/**
+ * FileSet adapter to SPL's Iterator.
+ *
+ * @package phing.types
+ * @author Alexey Shockov <alexey@shockov.com>
+ * @since 2.4.0
+ * @internal
+ */
+class IterableFileSet
+ extends FileSet
+ implements IteratorAggregate
+{
+ /**
+ * @return Iterator
+ */
+ public function getIterator()
+ {
+ return new ArrayIterator($this->getFiles());
+ }
+ /**
+ * @return array
+ */
+ private function getFiles()
+ {
+ $directoryScanner = $this->getDirectoryScanner($this->getProject());
+ $files = $directoryScanner->getIncludedFiles();
+
+ $baseDirectory = $directoryScanner->getBasedir();
+ foreach ($files as $index => $file) {
+ $files[$index] = realpath($baseDirectory.'/'.$file);
+ }
+
+ return $files;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/types/Mapper.php b/buildscripts/phing/classes/phing/types/Mapper.php
new file mode 100644
index 00000000..03042c64
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Mapper.php
@@ -0,0 +1,207 @@
+<?php
+/*
+ * $Id: bab760877500c0bb1ed4d6879c7e31c60c3fd307 $
+ *
+ * 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(Reference $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..cbba153c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Parameter.php
@@ -0,0 +1,99 @@
+<?php
+/*
+ * $Id: 725ec7b7d585219471bb8793da0210c7ab1452c0 $
+ *
+ * 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..7efe790a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Parameterizable.php
@@ -0,0 +1,32 @@
+<?php
+
+/*
+ * $Id: e0d41388dad173e2dd61527524d6c3958683171b $
+ *
+ * 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..b8525628
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Path.php
@@ -0,0 +1,452 @@
+<?php
+/*
+ * $Id: 762715ec83a12704f4ab528e507c28396c159083 $
+ *
+ * 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>
+ * &lt;sometask&gt;<br>
+ * &nbsp;&nbsp;&lt;somepath&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/path/to/file" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement path="/path/to/class2;/path/to/class3" /&gt;<br>
+ * &nbsp;&nbsp;&nbsp;&nbsp;&lt;pathelement location="/path/to/file3" /&gt;<br>
+ * &nbsp;&nbsp;&lt;/somepath&gt;<br>
+ * &lt;/sometask&gt;<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>&lt;pathelement&gt;</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>&lt;fileset&gt;</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>&lt;dirset&gt;</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>&lt;path&gt;</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);
+ 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);
+ while ($tok->hasMoreTokens()) {
+ $pathElement = $tok->nextToken();
+ try {
+ $element = self::resolveFile($project, $pathElement);
+ for ($i = 0, $_i=strlen($element); $i < $_i; $i++) {
+ self::translateFileSep($element, $i);
+ }
+ $result[] = $element;
+ } catch (BuildException $e) {
+ $this->project->log("Dropping path element " . $pathElement
+ . " as it is not valid relative to the project",
+ Project::MSG_VERBOSE);
+ }
+ }
+
+ 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>&lt;pathelement&gt;</code> values.
+ *
+ * @package phing.types
+ */
+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;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/types/PatternSet.php b/buildscripts/phing/classes/phing/types/PatternSet.php
new file mode 100755
index 00000000..32967d62
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/PatternSet.php
@@ -0,0 +1,493 @@
+<?php
+/*
+ * $Id: af3bd3709d79ad0299bf6ec0130a8a244ee325ab $
+ *
+ * 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 $Id: af3bd3709d79ad0299bf6ec0130a8a244ee325ab $
+ * @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
+ *
+ * @return 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
+ *
+ * @return 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
+ *
+ * @return 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
+ *
+ * @return 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
+ * @return 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
+ * @return 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
+ * @return 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 }";
+ }
+}
+
+
+/**
+ * "Internal" class for holding an include/exclude pattern.
+ *
+ * @package phing.types
+ */
+class PatternSetNameEntry {
+
+ /**
+ * The pattern.
+ * @var string
+ */
+ private $name;
+
+ /**
+ * The if-condition property for this pattern to be applied.
+ * @var string
+ */
+ private $ifCond;
+
+ /**
+ * The unless-condition property for this pattern to be applied.
+ * @var string
+ */
+ private $unlessCond;
+
+ /**
+ * An alias for the setName() method.
+ * @see setName()
+ * @param string $pattern
+ */
+ public function setPattern($pattern) {
+ $this->setName($pattern);
+ }
+
+ /**
+ * Set the pattern text.
+ * @param string $name The pattern
+ */
+ public function setName($name) {
+ $this->name = (string) $name;
+ }
+
+ /**
+ * Sets an if-condition property for this pattern to match.
+ * @param string $cond
+ */
+ public function setIf($cond) {
+ $this->ifCond = (string) $cond;
+ }
+
+
+ /**
+ * Sets an unless-condition property for this pattern to match.
+ * @param string $cond
+ */
+ public function setUnless($cond) {
+ $this->unlessCond = (string) $cond;
+ }
+
+ /**
+ * Get the pattern text.
+ * @return string The pattern.
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Evaluates the pattern.
+ * @return string The pattern or null if it is ruled out by a condition.
+ */
+ public function evalName(Project $project) {
+ return $this->valid($project) ? $this->name : null;
+ }
+
+
+ /**
+ * Checks whether pattern should be applied based on whether the if and unless
+ * properties are set in project.
+ * @param Project $project
+ * @return boolean
+ */
+ public function valid(Project $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;
+ }
+
+ /**
+ * Gets a string representation of this pattern.
+ * @return string
+ */
+ public 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/PearPackageFileSet.php b/buildscripts/phing/classes/phing/types/PearPackageFileSet.php
new file mode 100644
index 00000000..8cf99b28
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/PearPackageFileSet.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * Part of phing, the PHP build tool
+ *
+ * PHP version 5
+ *
+ * @category Types
+ * @package phing.types
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @version SVN: $Id: 5ba010b83645d0ea709761a3d8260fc013239458 $
+ * @link http://www.phing.info/
+ */
+require_once 'phing/types/FileSet.php';
+require_once 'PEAR/Config.php';
+require_once 'phing/util/PearPackageScanner.php';
+
+/**
+ * Fileset that contains files of an installed PEAR package.
+ * It can be used to package up PEAR package dependencies in own
+ * release files (zip, tgz, phar).
+ *
+ * @internal
+ * A normal fileset is used that way in CopyTask, rSTTask:
+ * <code>
+ * $ds = $fs->getDirectoryScanner($project);
+ * $fromDir = $fs->getDir($project);
+ * $srcFiles = $ds->getIncludedFiles();
+ * $srcDirs = $ds->getIncludedDirectories();
+ * </code>
+ * The scanner is used as follows:
+ * <code>
+ * $ds->getBaseDir()
+ * $ds->scan()
+ * </code>
+ *
+ * @category Types
+ * @package phing.types
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @link http://www.phing.info/
+ */
+class PearPackageFileSet extends FileSet
+{
+ /**
+ * Name of channel the package is from, e.g. "pear.php.net".
+ *
+ * @var string
+ */
+ protected $channel;
+
+ /**
+ * Package name to get files from, e.g. "Console_CommandLine"
+ *
+ * @var string
+ */
+ protected $package;
+
+ /**
+ * Use files of that role only.
+ * Multiple roles are not supported, and you always have to specify one.
+ *
+ * @var string
+ */
+ protected $role = 'php';
+
+ /**
+ * Prefix to prepend to the file paths in the zip
+ */
+ protected $prefix;
+
+ /**
+ * Full path to a PEAR config file.
+ * If none provided, default one is used.
+ */
+ protected $config;
+
+ /**
+ * @var PearPackageScanner instance
+ */
+ protected $pps;
+
+
+ /**
+ * Creates and returns the pear package scanner.
+ * Scanner already has scan() called.
+ *
+ * @param Project $project Current phing project
+ *
+ * @return PearPackageScanner
+ */
+ public function getDirectoryScanner(Project $project)
+ {
+ if ($this->isReference()) {
+ $obj = $this->getRef($project);
+ return $obj->getDirectoryScanner($project);
+ }
+
+ $this->loadPearPackageScanner();
+ return $this->pps;
+ }
+
+ /**
+ * Returns the base directory all package files are relative to
+ *
+ * @return PhingFile Base directory
+ */
+ public function getDir()
+ {
+ if ($this->pps === null) {
+ $this->loadPearPackageScanner();
+ }
+ return new PhingFile((string) $this->pps->getBaseDir());
+ }
+
+ /**
+ * Loads the package scanner instance into $this->pps
+ *
+ * @return void
+ */
+ protected function loadPearPackageScanner()
+ {
+ $this->pps = new PearPackageScanner();
+ $this->pps->setPackage($this->package);
+ $this->pps->setChannel($this->channel);
+ $this->pps->setRole($this->role);
+ $this->pps->setConfig($this->config);
+ $this->pps->scan();
+ }
+
+ /**
+ * Sets the package name.
+ * If no channel is given, "pear.php.net" is used.
+ *
+ * @param string $package Single package name, or "channel/name" combination
+ *
+ * @return void
+ */
+ public function setPackage($package)
+ {
+ $parts = explode('/', $package);
+ if (count($parts) > 2) {
+ throw new BuildException('Invalid package name: ' . $package);
+ }
+
+ if (count($parts) == 1) {
+ $this->channel = 'pear.php.net';
+ $this->package = $parts[0];
+ } else {
+ $this->channel = $parts[0];
+ $this->package = $parts[1];
+ }
+ }
+
+ /**
+ * Sets the role of files that should be included.
+ * Examples are php,doc,script
+ *
+ * @param string $role PEAR file role
+ *
+ * @return void
+ */
+ public function setRole($role)
+ {
+ $this->role = $role;
+ }
+
+ /**
+ * Sets the full path to the PEAR configuration file
+ *
+ * @param string $config Configuration file
+ *
+ * @return void
+ */
+ public function setConfig($config)
+ {
+ $this->config = $config;
+ }
+}
diff --git a/buildscripts/phing/classes/phing/types/PhingFilterReader.php b/buildscripts/phing/classes/phing/types/PhingFilterReader.php
new file mode 100755
index 00000000..2337977a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/PhingFilterReader.php
@@ -0,0 +1,136 @@
+<?php
+/*
+ * $Id: fee06c9abce6700d773004bd83a5312d94c5aa29 $
+ *
+ * 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 $Id$
+ * @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..5f490b3f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/Reference.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * $Id: 48c142f41717a31654d5cbfdb37f339e84adf391 $
+ *
+ * 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 100755
index 00000000..84a25591
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/RegularExpression.php
@@ -0,0 +1,128 @@
+<?php
+/*
+ * $Id: 257bd788b6185a3561f10a8de40502473076b6dd $
+ *
+ * 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 $Id$
+ * @access public
+ * @see phing.util.regex.RegexMatcher
+ * @package phing.types
+*/
+class RegularExpression extends DataType {
+
+ private $regexp = null;
+ /**
+ * @todo Probably both $ignoreCase and $multiline should be removed
+ * from attribute list of RegularExpression class:
+ * actual values are preserved on regexp *engine* level, not expression
+ * object itself.
+ */
+ private $ignoreCase = false;
+ private $multiline = 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 setModifiers($modifiers) {
+ $this->regexp->setModifiers($modifiers);
+ }
+
+ function getModifiers() {
+ return $this->regexp->getModifiers();
+ }
+
+ function setIgnoreCase($bit) {
+ $this->regexp->setIgnoreCase($bit);
+ }
+
+ function getIgnoreCase() {
+ return $this->regexp->getIgnoreCase();
+ }
+
+ function setMultiline($multiline) {
+ $this->regexp->setMultiline($multiline);
+ }
+
+ function getMultiline() {
+ return $this->regexp->getMultiline();
+ }
+
+ 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 100755
index 00000000..98ed3083
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/TokenReader.php
@@ -0,0 +1,66 @@
+<?php
+/*
+ * $Id: c267e1935c57a372e5b8fc07eef73bd084195e82 $
+ *
+ * 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 $Id$
+ * @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..0ca0367a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/TokenSource.php
@@ -0,0 +1,157 @@
+<?php
+/*
+ * $Id: 1bc91e925ce194c2e7a615e8f8c950d2057a9cb5 $
+ *
+ * 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..1a27829d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/AndSelector.php
@@ -0,0 +1,67 @@
+<?php
+/*
+ * $Id: f36556afb9487cce2e56d5c174e3ce4c43ef968f $
+ *
+ * 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..d8ae0444
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/BaseExtendSelector.php
@@ -0,0 +1,62 @@
+<?php
+
+/*
+ * $Id: 0c36c2b00f8ab8d20025b9ad38043c762b6fc7f9 $
+ *
+ * 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
+ * &lt;custom&gt; 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..c463fa33
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelector.php
@@ -0,0 +1,84 @@
+<?php
+/*
+ * $Id: e1f8e20eb87ea465d29ba3add6fada790642bcf8 $
+ *
+ * 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..3b2a10b1
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/BaseSelectorContainer.php
@@ -0,0 +1,270 @@
+<?php
+
+/*
+ * $Id: 9dd90d3e78d751562859bbe5179db148ee5b025c $
+ *
+ * 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 100755
index 00000000..5b45bac8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php
@@ -0,0 +1,164 @@
+<?php
+
+/*
+ * $Id: 2a891d7cc3fb1b710b72d51e6a8cf2d0b553f91a $
+ *
+ * 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 $Id$
+ * @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..5e270583
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/ContainsSelector.php
@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * $Id: ab2c641c048573b0a9976b7cb92138b8ceda511f $
+ *
+ * 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 100755
index 00000000..0f8c28a8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/DateSelector.php
@@ -0,0 +1,214 @@
+<?php
+
+/*
+ * $Id: f05cee91082616c66b2e109157b1d2f2298a66f8 $
+ *
+ * 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 $Id: f05cee91082616c66b2e109157b1d2f2298a66f8 $
+ * @package phing.types.selectors
+ */
+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 100755
index 00000000..3b869199
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/DependSelector.php
@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * $Id: eac9e808c89c2a8f414f86afc589eda4f218dd6e $
+ *
+ * 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 $Id$
+ * @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 100755
index 00000000..0ad6c8eb
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/DepthSelector.php
@@ -0,0 +1,158 @@
+<?php
+/*
+ * $Id: 9c244177a7f95995cd30c67c9fee47c1e977e4e2 $
+ *
+ * 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 $Id$
+ * @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..8394387c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/ExtendFileSelector.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * $Id: dc3c5cb2a3043b7a3f7600591ce825b6563ec0ce $
+ *
+ * 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 &lt;custom&gt; 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..1204ef12
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/ExtendSelector.php
@@ -0,0 +1,124 @@
+<?php
+
+/*
+ * $Id: 1683a0a93b4bb5486f3cffbe40e8260f886c6258 $
+ *
+ * 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 (phing.types.Path) support to this class
+ * and to the Mappers class. See Ant versions for implimentation details.
+ *
+ * @author Hans Lellelid <hans@xmpl.org> (Phing)
+ * @author Bruce Atherton <bruce@callenish.com> (Ant)
+ * @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.
+ *
+ * @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..3c014d61
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/FileSelector.php
@@ -0,0 +1,47 @@
+<?php
+
+/*
+ * $Id: 26b8712469a798faf79d1c877aad89d64880f061 $
+ *
+ * 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..04abbe2e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/FilenameSelector.php
@@ -0,0 +1,157 @@
+<?php
+
+/*
+ * $Id: d0a6af11eeda50b911bad3717528a9ea72291185 $
+ *
+ * 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 &lt;exclude&gt; tag, by setting the attribute
+ * negate to true. This is identical to surrounding the selector
+ * with &lt;not&gt;&lt;/not&gt;.
+ *
+ * @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..5ad2629e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/MajoritySelector.php
@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * $Id: 9071d88eb880abe5a299f7c5db707d4439ccaa6c $
+ *
+ * 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..f8941208
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/NoneSelector.php
@@ -0,0 +1,71 @@
+<?php
+/*
+ * $Id: a085187a008c4d8e8ba25fd6f1315b3dee92ec27 $
+ *
+ * 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..08e70a5a
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/NotSelector.php
@@ -0,0 +1,59 @@
+<?php
+
+/*
+ * $Id: 8dcce9d2d304b7a8d4be0ef5b5111b582846840d $
+ *
+ * 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..56e6df1e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/OrSelector.php
@@ -0,0 +1,72 @@
+<?php
+/*
+ * $Id: bfed3cc534a3e1ab8789f0ed4a6e64419979e21a $
+ *
+ * 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..462d3927
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/PresentSelector.php
@@ -0,0 +1,154 @@
+<?php
+
+/*
+ * $Id: db4c8bc8217483d4150b2d9e62d2ef5129038b4e $
+ *
+ * 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 100755
index 00000000..0db73e5d
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/SelectSelector.php
@@ -0,0 +1,124 @@
+<?php
+
+/*
+ * $Id: aa3a5cceea362713959333bda113e0ca5428a530 $
+ *
+ * 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 $Id$
+ * @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..0ee42237
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/SelectorContainer.php
@@ -0,0 +1,141 @@
+<?php
+
+/*
+ * $Id: 6fedde4695e4838f435f336b7936190b16429706 $
+ *
+ * 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..91fc3f4c
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/SelectorScanner.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * $Id: 3c28c4c2e4c41cf4507870e472ed9f278e2d9c9f $
+ *
+ * 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..2d7e5068
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/SelectorUtils.php
@@ -0,0 +1,200 @@
+<?php
+
+/*
+ * $Id: 4a682bbe8751f6e09a725af7cfdf2bd17ab00645 $
+ *
+ * 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 static 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 static 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 static function matchPath($pattern, $str, $isCaseSensitive = true) {
+
+ $rePattern = preg_quote($pattern, '/');
+ $dirSep = preg_quote(DIRECTORY_SEPARATOR, '/');
+ $trailingDirSep = '(('.$dirSep.')?|('.$dirSep.').+)';
+ $patternReplacements = array(
+ $dirSep.'\*\*'.$dirSep => $dirSep.'.*'.$trailingDirSep,
+ $dirSep.'\*\*' => $trailingDirSep,
+ '\*\*'.$dirSep => '.*'.$trailingDirSep,
+ '\*\*' => '.*',
+ '\*' => '[^'.$dirSep.']*',
+ '\?' => '[^'.$dirSep.']'
+ );
+ $rePattern = str_replace(array_keys($patternReplacements), array_values($patternReplacements), $rePattern);
+ $rePattern = '/^'.$rePattern.'$/'.($isCaseSensitive ? '' : 'i');
+ return (bool) preg_match($rePattern, $str);
+ }
+
+ /**
+ * 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 static function match($pattern, $str, $isCaseSensitive = true) {
+
+ $rePattern = preg_quote($pattern, '/');
+ $rePattern = str_replace(array("\*", "\?"), array('.*', '.'), $rePattern);
+ $rePattern = '/^'.$rePattern.'$/'.($isCaseSensitive ? '' : 'i');
+ return (bool) preg_match($rePattern, $str);
+ }
+
+ /**
+ * 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 static 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..3aaf8a92
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/SizeSelector.php
@@ -0,0 +1,228 @@
+<?php
+
+/*
+ * $Id: 4969c98a4e03305a23770e2afd5da641999f6174 $
+ *
+ * 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 100755
index 00000000..6ff024e8
--- /dev/null
+++ b/buildscripts/phing/classes/phing/types/selectors/TypeSelector.php
@@ -0,0 +1,120 @@
+<?php
+
+/*
+ * $Id: 95c34bb6a364dc0131e9e9c5c124d5074b4a2a21 $
+ *
+ * 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 $Id: 95c34bb6a364dc0131e9e9c5c124d5074b4a2a21 $
+ * @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', 'link');
+
+ /**
+ * @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->isLink()) {
+ if ($this->type == 'link')
+ return true;
+
+ $this->log($file->getAbsolutePath() . " is a link, proceeding with " . $file->getCanonicalPath() . " instead.", Project::MSG_DEBUG);
+ $file = new PhingFile($file->getCanonicalPath());
+ }
+
+ if ($file->isDirectory()) {
+ return $this->type === 'dir';
+ } else {
+ return $this->type === 'file';
+ }
+ }
+
+}
diff --git a/buildscripts/phing/classes/phing/util/DataStore.php b/buildscripts/phing/classes/phing/util/DataStore.php
new file mode 100755
index 00000000..af696697
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/DataStore.php
@@ -0,0 +1,151 @@
+<?php
+
+/*
+ * $Id: 77f24d8b9d8082b4c23cb4cd5d23a06a3be88e2d $
+ *
+ * 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/PhingFile.php';
+require_once 'phing/system/io/FileWriter.php';
+
+/**
+ * An abstract representation of file and directory pathnames.
+ *
+ * @package phing.util
+ * @author Michiel Rook <mrook@php.net>
+ * @version $Id$
+ */
+class DataStore
+{
+ private $data = array();
+ private $file = null;
+
+ /**
+ * Constructs a new data store
+ *
+ * @param PhingFile $file object pointing to the data store on disk
+ */
+ function __construct(PhingFile $file)
+ {
+ $this->file = $file;
+
+ if ($this->file->exists())
+ {
+ $this->read();
+ }
+ }
+
+ /**
+ * Destructor
+ */
+ function __destruct()
+ {
+ $this->commit();
+ }
+
+ /**
+ * Retrieves a value from the data store
+ *
+ * @param string $key the key
+ *
+ * @return mixed the value
+ */
+ public function get($key)
+ {
+ if (!isset($this->data[$key]))
+ {
+ return null;
+ }
+ else
+ {
+ return $this->data[$key];
+ }
+ }
+
+ /**
+ * Adds a value to the data store
+ *
+ * @param string $key the key
+ * @param mixed $value the value
+ * @param boolean $autocommit whether to auto-commit (write)
+ * the data store to disk
+ *
+ * @return none
+ */
+ public function put($key, $value, $autocommit = false)
+ {
+ $this->data[$key] = $value;
+
+ if ($autocommit)
+ {
+ $this->commit();
+ }
+ }
+
+ /**
+ * Commits data store to disk
+ *
+ * @return none
+ */
+ public function commit()
+ {
+ $this->write();
+ }
+
+ /**
+ * Internal function to read data store from file
+ *
+ * @return none
+ */
+ private function read()
+ {
+ if (!$this->file->canRead())
+ {
+ throw new BuildException("Can't read data store from '" .
+ $file->getPath() . "'");
+ }
+ else
+ {
+ $serializedData = $this->file->contents();
+
+ $this->data = unserialize($serializedData);
+ }
+ }
+
+ /**
+ * Internal function to write data store to file
+ *
+ * @return none
+ */
+ private function write()
+ {
+ if (!$this->file->canWrite())
+ {
+ throw new BuildException("Can't write data store to '" .
+ $file->getPath() . "'");
+ }
+ else
+ {
+ $serializedData = serialize($this->data);
+
+ $writer = new FileWriter($this->file);
+ $writer->write($serializedData);
+ $writer->close();
+ }
+ }
+};
diff --git a/buildscripts/phing/classes/phing/util/DirectoryScanner.php b/buildscripts/phing/classes/phing/util/DirectoryScanner.php
new file mode 100755
index 00000000..02d5be88
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/DirectoryScanner.php
@@ -0,0 +1,755 @@
+<?php
+/*
+ * $Id: 7aef4b4e372e89055248ab063660dbee92a98cc3 $
+ *
+ * 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 $Id: 7aef4b4e372e89055248ab063660dbee92a98cc3 $
+ * @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",
+ "**/.darcs",
+ "**/.darcs/**",
+ "**/.git",
+ "**/.git/**",
+ "**/.gitattributes",
+ "**/.gitignore",
+ "**/.gitmodules",
+ );
+
+ /** 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;
+
+ /** Whether to expand/dereference symbolic links, default is false */
+ protected $expandSymbolicLinks = false;
+
+ /**
+ * 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;
+ }
+ }
+ }
+
+ /**
+ * Sets whether to expand/dereference symbolic links
+ *
+ * @param expandSymbolicLinks boolean value
+ */
+ function setExpandSymbolicLinks($expandSymbolicLinks)
+ {
+ $this->expandSymbolicLinks = $expandSymbolicLinks;
+ }
+
+ /**
+ * 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()) !== false) {
+ 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_link($file) && !$this->expandSymbolicLinks)
+ {
+ 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;
+ }
+ }
+ else
+ 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) {
+ $basedir = new PhingFile($this->basedir);
+ $file = new PhingFile($file);
+ if (!$file->canRead())
+ return false;
+
+ foreach($this->selectors as $selector) {
+ if (!$selector->isSelected($basedir, $name, $file)) {
+ 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 100755
index 00000000..9c09b56f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/ExtendedFileStream.php
@@ -0,0 +1,129 @@
+<?php
+
+ include_once 'phing/system/io/PhingFile.php';
+
+ /**
+ * $Id: f7e4641c758d5e781ad209d3eaf653a20404bf56 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: f7e4641c758d5e781ad209d3eaf653a20404bf56 $
+ * @package phing.util
+ */
+ class ExtendedFileStream
+ {
+ private $fp = NULL;
+
+ static function registerStream()
+ {
+ if (!in_array("efile", stream_get_wrappers()))
+ {
+ stream_wrapper_register("efile", "ExtendedFileStream");
+ }
+ }
+
+ static function unregisterStream()
+ {
+ stream_wrapper_unregister("efile");
+ }
+
+ private function createDirectories($path)
+ {
+ $f = new PhingFile($path);
+ if (!$f->exists()) {
+ $f->mkdirs();
+ }
+ }
+
+ function stream_open($path, $mode, $options, &$opened_path)
+ {
+ $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;
+ }
+ };
+
diff --git a/buildscripts/phing/classes/phing/util/FileUtils.php b/buildscripts/phing/classes/phing/util/FileUtils.php
new file mode 100755
index 00000000..c98bbdd3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/FileUtils.php
@@ -0,0 +1,298 @@
+<?php
+/*
+ * $Id: fe077b4174763861e773f5e5e55bbfc5030cac4d $
+ *
+ * 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 $Id$
+ */
+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).
+ */
+ public static 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
+ * @param integer $mode
+ * @return void
+ */
+ function copyFile(PhingFile $sourceFile, PhingFile $destFile, $overwrite = false, $preserveLastModified = true, &$filterChains = null, Project $project, $mode = 0755) {
+
+ 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($mode);
+ }
+
+ 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();
+
+ $destFile->setMode($sourceFile->getMode());
+
+ } 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 100755
index 00000000..ae97705e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/LogWriter.php
@@ -0,0 +1,95 @@
+<?php
+
+ /**
+ * $Id: ccb6c8b930bb3f293074969323467edeaf40bd02 $
+ *
+ * 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 <mrook@php.net>
+ * @version $Id: ccb6c8b930bb3f293074969323467edeaf40bd02 $
+ * @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;
+ }
+ }
+
diff --git a/buildscripts/phing/classes/phing/util/PathTokenizer.php b/buildscripts/phing/classes/phing/util/PathTokenizer.php
new file mode 100644
index 00000000..0a469acf
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/PathTokenizer.php
@@ -0,0 +1,245 @@
+<?php
+/*
+ * $Id: 0ca7f2a419b5cc4285a8f84695c4b680b0aa190b $
+ *
+ * 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)
+
+ * @package 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/PearPackageScanner.php b/buildscripts/phing/classes/phing/util/PearPackageScanner.php
new file mode 100644
index 00000000..9071ed37
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/PearPackageScanner.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * Part of phing, the PHP build tool
+ *
+ * PHP version 5
+ *
+ * @category Util
+ * @package phing.util
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @version SVN: $Id: e549026313edf53c67f495489f671cf0b71df80d $
+ * @link http://www.phing.info/
+ */
+require_once 'phing/util/DirectoryScanner.php';
+require_once 'PEAR/Config.php';
+
+/**
+ * Scans for files in a PEAR package.
+ *
+ * @category Util
+ * @package phing.util
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license LGPL v3 or later http://www.gnu.org/licenses/lgpl.html
+ * @link http://www.phing.info/
+ */
+class PearPackageScanner extends DirectoryScanner
+{
+ protected $packageInfo;
+ protected $role = 'php';
+ protected $config;
+ protected $package;
+ protected $channel = 'pear.php.net';
+
+ /**
+ * Sets the name of the PEAR package to get the files from
+ *
+ * @param string $package Package name without channel
+ *
+ * @return void
+ */
+ public function setPackage($package)
+ {
+ $this->package = $package;
+ }
+
+ /**
+ * Sets the name of the package channel name
+ *
+ * @param string $channel package channel name or alias
+ *
+ * @return void
+ */
+ public function setChannel($channel)
+ {
+ $this->channel = $channel;
+ }
+
+ /**
+ * Sets the full path to the PEAR configuration file
+ *
+ * @param string $config Configuration file
+ *
+ * @return void
+ */
+ public function setConfig($config)
+ {
+ if ($config != '' && !file_exists($config)) {
+ throw new BuildException(
+ 'PEAR configuration file "' . $config . '" does not exist'
+ );
+ }
+
+ $this->config = $config;
+ }
+
+ /**
+ * Sets the role of files that should be included.
+ * Examples are php,doc,script
+ *
+ * @param string $role PEAR file role
+ *
+ * @return void
+ *
+ * @internal
+ * We do not verify the role against a hardcoded list since that
+ * would break packages with additional roles.
+ */
+ public function setRole($role)
+ {
+ if ($role == '') {
+ throw new BuildException('A non-empty role is required');
+ }
+
+ $this->role = $role;
+ }
+
+ /**
+ * Loads the package information.
+ *
+ * @return void
+ *
+ * @uses $packageInfo
+ */
+ protected function init()
+ {
+ if (!$this->packageInfo) {
+ $this->packageInfo = $this->loadPackageInfo();
+ }
+ }
+
+ /**
+ * Loads and returns the PEAR package information.
+ *
+ * @return PEAR_PackageFile_v2 Package information object
+ *
+ * @throws BuildException When the package does not exist
+ */
+ protected function loadPackageInfo()
+ {
+ $cfg = PEAR_Config::singleton($this->config);
+ $reg = $cfg->getRegistry();
+ if (!$reg->packageExists($this->package, $this->channel)) {
+ throw new BuildException(
+ sprintf(
+ 'PEAR package %s/%s does not exist',
+ $this->channel, $this->package
+ )
+ );
+ }
+
+ $packageInfo = $reg->getPackage($this->package, $this->channel);
+ return $packageInfo;
+ }
+
+ /**
+ * Generates the list of included files and directories
+ *
+ * @return boolean True if all went well, false if something was wrong
+ *
+ * @uses $filesIncluded
+ * @uses $filesDeselected
+ * @uses $filesNotIncluded
+ * @uses $filesExcluded
+ * @uses $everythingIncluded
+ * @uses $dirsIncluded
+ * @uses $dirsDeselected
+ * @uses $dirsNotIncluded
+ * @uses $dirsExcluded
+ */
+ public function scan()
+ {
+ $this->init();
+ $list = $this->packageInfo->getFilelist();
+ $found = null;
+ foreach ($list as $file => $att) {
+ if ($att['role'] != $this->role) {
+ continue;
+ }
+ $this->filesIncluded[] = $file;
+ $found = array($file, $att);
+ }
+ if ($found !== null) {
+ list($file, $att) = $found;
+ $this->setBaseDir(substr($att['installed_as'], 0, -strlen($file)));
+ }
+
+ return 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..d958a15f
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/SourceFileScanner.php
@@ -0,0 +1,159 @@
+<?php
+/*
+ * $Id: 0555ae8b4e7418c211bd69a066877ab8cf95fbb8 $
+ *
+ * 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..31d0b0e9
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/StringHelper.php
@@ -0,0 +1,208 @@
+<?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.
+ *
+ * @param array $strings Array of strings to multiply. (If string is passed, will convert to array)
+ * @param array $tokens The tokens to search for.
+ * @param 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, '%{} ');
+ }
+
+}
+
+
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..76cf56b3
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/regexp/PregEngine.php
@@ -0,0 +1,167 @@
+<?php
+/*
+ * $Id: 94607411e16d4c9091369ff4a65ea8f44bde8781 $
+ *
+ * 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.regexp
+ */
+class PregEngine implements RegexpEngine {
+
+ /**
+ * Set to null by default to distinguish between false and not set
+ * @var boolean
+ */
+ private $ignoreCase = null;
+
+ /**
+ * Set to null by default to distinguish between false and not set
+ * @var boolean
+ */
+ private $multiline = null;
+
+ /**
+ * Pattern modifiers
+ * @link http://php.net/manual/en/reference.pcre.pattern.modifiers.php
+ * @var string
+ */
+ private $modifiers = null;
+
+ /**
+ * Sets pattern modifiers for regex engine
+ *
+ * @param string $mods Modifiers to be applied to a given regex
+ * @return void
+ */
+ public function setModifiers($mods) {
+ $this->modifiers = (string)$mods;
+ }
+
+ /**
+ * Gets pattern modifiers.
+ * @return string
+ */
+ public function getModifiers() {
+ $mods = $this->modifiers;
+ if($this->getIgnoreCase()) {
+ $mods .= 'i';
+ } elseif($this->getIgnoreCase() === false) {
+ $mods = str_replace('i', '', $mods);
+ }
+ if($this->getMultiline()) {
+ $mods .= 's';
+ } elseif($this->getMultiline() === false) {
+ $mods = str_replace('s', '', $mods);
+ }
+ // filter out duplicates
+ $mods = preg_split('//', $mods, -1, PREG_SPLIT_NO_EMPTY);
+ $mods = implode('', array_unique($mods));
+ return $mods;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Sets whether regexp should be applied in multiline mode.
+ * @param boolean $bit
+ */
+ function setMultiline($bit) {
+ $this->multiline = $bit;
+ }
+
+ /**
+ * Gets whether regexp is to be applied in multiline mode.
+ * @return boolean
+ */
+ function getMultiline() {
+ return $this->multiline;
+ }
+
+ /**
+ * 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)
+ {
+ // Use backquotes since hardly ever found in a regexp pattern, avoids using preg_quote
+ return '`'.$pattern.'`' . $this->getModifiers();
+ }
+
+ /**
+ * 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);
+ }
+
+}
+
diff --git a/buildscripts/phing/classes/phing/util/regexp/Regexp.php b/buildscripts/phing/classes/phing/util/regexp/Regexp.php
new file mode 100755
index 00000000..7188997e
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/regexp/Regexp.php
@@ -0,0 +1,203 @@
+<?php
+/*
+ * $Id: b669eb9f2dd8533cba67b2058b7cbc2f558bdeae $
+ *
+ * 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 $Id$
+ */
+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.
+ */
+ 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 pattern modifiers for regex engine
+ *
+ * @param string $mods Modifiers to be applied to a given regex
+ * @return void
+ */
+ public function setModifiers($mods) {
+ $this->engine->setModifiers($mods);
+ }
+
+ /**
+ * Gets pattern modifiers.
+ * Subsequent call to engines getModifiers() filters out duplicates
+ * i.e. if i is provided in $mods, and setIgnoreCase(true), "i"
+ * modifier would be included only once
+ * @return string
+ */
+ public function getModifiers() {
+ return $this->engine->getModifiers();
+ }
+
+ /**
+ * 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();
+ }
+
+ /**
+ * Sets whether regexp should be applied in multiline mode.
+ * @param boolean $bit
+ */
+ function setMultiline($bit) {
+ $this->engine->setMultiline($bit);
+ }
+
+ /**
+ * Gets whether regexp is to be applied in multiline mode.
+ * @return boolean
+ */
+ function getMultiline() {
+ return $this->engine->getMultiline();
+ }
+}
+
diff --git a/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php
new file mode 100755
index 00000000..3eb8c408
--- /dev/null
+++ b/buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php
@@ -0,0 +1,73 @@
+<?php
+/*
+ * $Id: 5e2886f3fae60fff1fd142e79717a3a7a4555772 $
+ *
+ * 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.regexp
+ * @version $Id$
+ */
+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);
+
+}
+
diff --git a/buildscripts/phing/composer.json b/buildscripts/phing/composer.json
new file mode 100644
index 00000000..e9b10fef
--- /dev/null
+++ b/buildscripts/phing/composer.json
@@ -0,0 +1,23 @@
+{
+ "name": "phing/phing",
+ "description": "PHing Is Not GNU make; it's a PHP project build system or build tool based on Apache Ant.",
+ "keywords": ["build", "tool", "task"],
+ "homepage": "http://www.phing.info/",
+ "license": "LGPL3",
+ "authors": [
+ {
+ "name": "Michiel Rook",
+ "email": "mrook@php.net"
+ },
+ {
+ "name": "Phing Community",
+ "homepage": "http://www.phing.info/trac/wiki/Development/Contributors"
+ }
+ ],
+ "require": {
+ "php": ">=5.2.0"
+ },
+ "autoload": {
+ "classmap": ["classes/phing/"]
+ }
+}
diff --git a/buildscripts/phing/etc/VERSION.TXT b/buildscripts/phing/etc/VERSION.TXT
new file mode 100644
index 00000000..321d7fe1
--- /dev/null
+++ b/buildscripts/phing/etc/VERSION.TXT
@@ -0,0 +1 @@
+Phing 2.4.12 \ 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 100755
index 00000000..251faff6
--- /dev/null
+++ b/buildscripts/phing/etc/coverage-frames.xsl
@@ -0,0 +1,1067 @@
+<?xml version="1.0"?>
+<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.rook@gmail.com"/>
+ @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+
+-->
+
+<!-- default output directory is current directory -->
+<xsl:param name="output.dir" select="'.'"/>
+<xsl:param name="output.sorttable" select="'.'"/>
+<xsl:param name="document.title" 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 omit-xml-declaration="yes" 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"/>
+
+ <!-- process all subpackages -->
+ <xsl:apply-templates select="./package/subpackage" mode="write"/>
+</xsl:template>
+
+<!-- =======================================================================
+ Frameset definition. Entry point for the report.
+ 3 frames: packageListFrame, classListFrame, classFrame
+ ======================================================================= -->
+<xsl:template name="index.html">
+<html>
+ <head><title><xsl:value-of select="$document.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">
+ <xsl:if test="$output.sorttable = 1">
+ .sortable th {
+ cursor: pointer;
+ }
+ </xsl:if>
+ .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.legendItem {
+ font-weight: bold;
+ padding-bottom: 2px;
+ padding-right: 6px;
+ padding-top: 6px;
+ text-align: right;
+ }
+ td.legendValue {
+ color: #2E3436;
+ font-weight: bold;
+ padding-bottom: 2px;
+ padding-top: 6px;
+ text-align: left;
+ }
+ span.LegendCovered {
+ background-color: #8AE234;
+ margin-right: 2px;
+ padding-left: 10px;
+ padding-right: 10px;
+ text-align: center;
+ }
+ span.LegendUncovered {
+ background-color: #F0C8C8;
+ margin-right: 2px;
+ padding-left: 10px;
+ padding-right: 10px;
+ text-align: center;
+ }
+ span.LegendDeadCode {
+ background-color: #D3D7CF;
+ margin-right: 2px;
+ padding-left: 10px;
+ padding-right: 10px;
+ text-align: center;
+ }
+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;
+}
+ PRE.srcLineUncovered {
+ BACKGROUND: #F0C8C8; MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px;
+}
+ PRE.srcLineCovered {
+ BACKGROUND: #8AE234; MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px;
+ }
+ PRE.srcLineDeadCode {
+ BACKGROUND: #D3D7CF; MARGIN-TOP: 0px; MARGIN-BOTTOM: 0px;
+ }
+td.lineCount, td.coverageCount {
+ BACKGROUND: #F0F0F0; PADDING-RIGHT: 3px;
+ text-align: right;
+}
+ td.lineCountCovered, td.coverageCountCovered {
+ background: #8AE234; PADDING-RIGHT: 3px;
+ text-align: right;
+}
+ td.srcLineCovered {
+ background: #8AE234;
+ }
+ td.lineCountUncovered, td.coverageCountUncovered {
+ background: #F0C8C8; PADDING-RIGHT: 3px;
+ text-align: right;
+}
+ td.srcLineUncovered {
+ background: #F0C8C8;
+}
+ td.lineCountDeadCode, td.coverageCountDeadCode {
+ background: #D3D7CF; PADDING-RIGHT: 3px;
+ text-align: right;
+ }
+ td.srcLineDeadCode {
+ background: #D3D7CF;
+ }
+td.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>
+ <xsl:for-each select="package/subpackage/class">
+ <xsl:sort select="@name"/>
+ <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/>
+ <xsl:variable name="subpackage.name" select="(ancestor::subpackage)[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:if test="not($subpackage.name='')">
+ <xsl:value-of select="translate($subpackage.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>
+ <title>Coverage Results Overview</title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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">Subpackages: <xsl:value-of select="count(package/subpackage)"/></td>
+ <td class="small">Classes: <xsl:value-of select="count(package/class) + count(package/subpackage/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) + count(package/subpackage/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 <xsl:value-of select="$document.title"/></b></td>
+ <xsl:call-template name="stats.formatted"/>
+ </tr>
+ <tr><td colspan="4"><br/></td></tr>
+ </table>
+
+ <table class="log sortable" cellpadding="5" cellspacing="0" width="100%">
+ <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 in package, 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>
+
+ <!-- for each class in subpackage, creates a @name.html -->
+ <xsl:for-each select="subpackage">
+ <xsl:variable name="subpackage.dir">
+ <xsl:if test="not(@name = '')"><xsl:value-of select="translate(@name,'._','//')"/></xsl:if>
+ <xsl:if test="@name = ''">.</xsl:if>
+ </xsl:variable>
+ <xsl:for-each select="./class">
+ <exsl:document href="efile://{$output.dir}/{$package.dir}/{$subpackage.dir}/{@name}.html">
+ <xsl:apply-templates select="." mode="class.details"/>
+ </exsl:document>
+ </xsl:for-each>
+ </xsl:for-each>
+</xsl:template>
+
+<!--
+ detailed info for a subpackage. It will output the list of classes and the summary page
+-->
+<xsl:template match="subpackage" mode="write">
+ <xsl:variable name="package.name" select="(ancestor::package)[last()]/@name"/>
+
+ <xsl:variable name="package.dir">
+ <xsl:if test="not($package.name = '')"><xsl:value-of select="translate($package.name,'._','//')"/></xsl:if>
+ <xsl:if test="$package.name = ''">.</xsl:if>
+ </xsl:variable>
+
+ <xsl:variable name="subpackage.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 subpackage directory -->
+ <exsl:document href="efile://{$output.dir}/{$package.dir}/{$subpackage.dir}/subpackage-frame.html">
+ <xsl:apply-templates select="." mode="classes.list"/>
+ </exsl:document>
+
+ <!-- create a subpackage-summary.html in the subpackage directory -->
+ <exsl:document href="efile://{$output.dir}/{$package.dir}/{$subpackage.dir}/subpackage-summary.html">
+ <xsl:apply-templates select="." mode="subpackage.summary"/>
+ </exsl:document>
+</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>Subpackages</h2>
+ <table width="100%">
+ <xsl:for-each select="subpackage">
+ <xsl:sort select="@name"/>
+ <tr>
+ <td nowrap="nowrap">
+ <a href="{translate(@name,'._','//')}/subpackage-summary.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>
+
+ <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>
+
+<!-- list of classes in a subpackage -->
+<xsl:template match="subpackage" mode="classes.list">
+ <xsl:variable name="fullpackage.name">
+ <xsl:value-of select="(ancestor::package)[last()]/@name"/>
+ <!-- append subpackage name if exists -->
+ <xsl:if test="not(@name='')">
+ <xsl:choose>
+ <!-- determine path separator -->
+ <xsl:when test="contains((ancestor::package)[last()]/@name, '_') or contains(@name, '_')">
+ <xsl:text>_</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>.</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="@name"/>
+ </xsl:if>
+ </xsl:variable>
+
+ <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="$fullpackage.name"/>
+ </xsl:call-template>
+ </head>
+ <body>
+ <table width="100%">
+ <tr>
+ <td nowrap="nowrap">
+ <H2>
+ <xsl:call-template name="create.package-summary.link">
+ <xsl:with-param name="package.name" select="$package.name"/>
+ <xsl:with-param name="fullpackage.name" select="$fullpackage.name"/>
+ </xsl:call-template>::<a href="subpackage-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>
+ <title>Coverage Results for <xsl:value-of select="@name"/></title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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">Subpackages: <xsl:value-of select="count(subpackage)"/></td>
+ <td class="small">Classes: <xsl:value-of select="count(class) + count(subpackage/class)"/></td>
+ <td class="small">Methods: <xsl:value-of select="@methodcount"/></td>
+ <td class="small">LOC: <xsl:value-of select="count(class/sourcefile/sourceline) + count(subpackage/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"/>
+ <tr>
+ <td colspan="5"><br/></td>
+ </tr>
+ </table>
+
+ <xsl:if test="count(subpackage) &gt; 0">
+ <table class="log sortable" cellpadding="5" cellspacing="0" width="100%">
+ <tr>
+ <th width="100%">Subpackages</th>
+ <th>Statements</th>
+ <th>Methods</th>
+ <th width="350" colspan="2" nowrap="nowrap">Total coverage</th>
+ </tr>
+ <xsl:apply-templates select="subpackage" mode="stats">
+ <xsl:sort data-type="number" select="@totalcovered div @totalcount"/>
+ </xsl:apply-templates>
+ <tr>
+ <td colspan="5"><br/></td>
+ </tr>
+ </table>
+ </xsl:if>
+
+ <xsl:if test="count(class) &gt; 0">
+ <table class="log sortable" cellpadding="5" cellspacing="0" width="100%">
+ <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>
+ </table>
+ </xsl:if>
+ <xsl:call-template name="pageFooter"/>
+ </body>
+ </html>
+</xsl:template>
+
+<!-- summary of a subpackage -->
+<xsl:template match="subpackage" mode="subpackage.summary">
+ <xsl:variable name="fullpackage.name">
+ <xsl:value-of select="(ancestor::package)[last()]/@name"/>
+ <!-- append subpackage name if exists -->
+ <xsl:if test="not(@name='')">
+ <xsl:choose>
+ <!-- determine path separator -->
+ <xsl:when test="contains((ancestor::package)[last()]/@name, '_') or contains(@name, '_')">
+ <xsl:text>_</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>.</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="@name"/>
+ </xsl:if>
+ </xsl:variable>
+
+ <html>
+ <head>
+ <xsl:call-template name="create.stylesheet.link">
+ <xsl:with-param name="package.name" select="$fullpackage.name"/>
+ </xsl:call-template>
+ </head>
+ <!-- when loading this subpackage, it will open the classes into the frame -->
+ <body onload="open('subpackage-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%">Subpackage</th>
+ <th>Statements</th>
+ <th>Methods</th>
+ <th width="350" colspan="2" nowrap="nowrap">Total coverage</th>
+ </tr>
+ <xsl:apply-templates select="." mode="stats.summary"/>
+
+ <xsl:if test="count(class) &gt; 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="subpackage.name" select="(ancestor::subpackage)[last()]/@name"/>
+
+ <xsl:variable name="fullpackage.name">
+ <xsl:value-of select="(ancestor::package)[last()]/@name"/>
+ <!-- append subpackage name if exists -->
+ <xsl:if test="not($subpackage.name='')">
+ <xsl:choose>
+ <!-- determine path/package separator -->
+ <xsl:when test="contains((ancestor::package)[last()]/@name, '_') or contains($subpackage.name, '_')">
+ <xsl:text>_</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>.</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:value-of select="$subpackage.name"/>
+ </xsl:if>
+ </xsl:variable>
+
+ <html>
+ <head>
+ <xsl:call-template name="create.stylesheet.link">
+ <xsl:with-param name="package.name" select="$fullpackage.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>
+
+ <!-- legend -->
+ <table class="log" cellpadding="5" cellspacing="0" width="100%">
+ <tbody>
+ <tr>
+ <td class="legendItem" width="0%">Legend:</td>
+ <td class="legendValue" width="100%">
+ <span class="legendCovered">executed</span>
+ <span class="legendUncovered">not executed</span>
+ <span class="legendDeadCode">dead code</span>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <!-- 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://www.phing.info/">
+ <img src="http://www.phing.info/images/phing.gif" alt="http://www.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://www.phpunit.de'>PHPUnit</a>, <a href='http://www.xdebug.org/'>Xdebug</a> and <a href='http://www.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="subpackage" mode="stats">
+ <tr>
+ <xsl:call-template name="alternate-row"/>
+ <td><a href="{translate(@name,'._','//')}/subpackage-summary.html" target="classFrame"><xsl:value-of select="@name"/></a></td>
+ <xsl:call-template name="stats.formatted"/>
+ </tr>
+</xsl:template>
+
+<xsl:template match="subpackage" mode="stats.summary">
+ <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">&#160;</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">&#160;</td>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:if test="not($leftwidth=0)">
+ <td class="covered" width="{$leftwidth}" height="12">&#160;</td>
+ </xsl:if>
+ <xsl:if test="not($rightwidth=0)">
+ <td class="uncovered" width="{$rightwidth}" height="12">&#160;</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="lineCountCovered"><xsl:value-of select="position()"/></td>
+ <td class="lineCountCovered"><xsl:value-of select="@coveredcount"/></td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=-1">
+ <td class="lineCountUncovered"><xsl:value-of select="position()"/></td>
+ <td class="coverageCountUncovered"></td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=-2">
+ <td class="lineCountDeadCode"><xsl:value-of select="position()"/></td>
+ <td class="coverageCountDeadCode"></td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=0">
+ <td class="lineCount"><xsl:value-of select="position()"/></td>
+ <td class="coverageCount"></td>
+ </xsl:if>
+
+ <xsl:if test="@coveredcount>0">
+ <td class="srcLineCovered">
+ <xsl:if test="@startclass=1">
+ <xsl:attribute name="class">srcLineClassStart</xsl:attribute>
+ </xsl:if>
+ <pre class="srcLineCovered"><xsl:value-of select="."/></pre>
+ </td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=-1">
+ <td class="srcLineUncovered">
+ <xsl:if test="@startclass=1">
+ <xsl:attribute name="class">srcLineClassStart</xsl:attribute>
+ </xsl:if>
+ <pre class="srcLineUncovered"><xsl:value-of select="."/></pre>
+ </td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=-2">
+ <td class="srcLineDeadCode">
+ <xsl:if test="@startclass=1">
+ <xsl:attribute name="class">srcLineClassStart</xsl:attribute>
+ </xsl:if>
+ <pre class="srcLineDeadCode"><xsl:value-of select="."/></pre>
+ </td>
+ </xsl:if>
+ <xsl:if test="@coveredcount=0">
+ <td>
+ <xsl:if test="@startclass=1">
+ <xsl:attribute name="class">srcLineClassStart</xsl:attribute>
+ </xsl:if>
+ <pre class="srcLine"><xsl:value-of select="."/></pre>
+ </td>
+ </xsl:if>
+ </tr>
+</xsl:template>
+
+<!--
+ transform string like a.b.c to ../../../
+ 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="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(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>
+
+<!-- create the link to the package summary -->
+<xsl:template name="create.package-summary.link">
+ <xsl:param name="package.name"/>
+ <xsl:param name="fullpackage.name"/>
+ <a target="classFrame">
+ <xsl:attribute name="href">
+ <xsl:if test="not($fullpackage.name = 'unnamed package')">
+ <xsl:call-template name="path">
+ <xsl:with-param name="path" select="$fullpackage.name"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:value-of select="translate($package.name,'._','//')"/>/package-summary.html</xsl:attribute>
+ <xsl:value-of select="$package.name"/>
+ </a>
+</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 100755
index 00000000..f0ef4695
--- /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.rook@gmail.com>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/phing-grammar.rng b/buildscripts/phing/etc/phing-grammar.rng
new file mode 100644
index 00000000..7f0351ce
--- /dev/null
+++ b/buildscripts/phing/etc/phing-grammar.rng
@@ -0,0 +1,5015 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ -File $Id: cf64bd85a79d1a3be75c42eab1ac6100a05f3a30 $
+ -License GNU LGPL (http://www.gnu.org/copyleft/lgpl.html)
+ -Author Johan Persson, johanp@aditus.nu
+-->
+<!--
+ ==================================================================================
+
+ Relax-NG XML Schema For Phing build XML scripts. (See http://www.relaxng.org)
+
+ The purpose of this schema is to facilitate the writing of correct Phing build
+ scripts in a XML and schema aware editor. The schema will help the editor verify
+ the input as well as providing tag completion making it easier and faster to
+ write correct Phing build scripts.
+
+ It can also be used together with one of the many existing R-NG validators to
+ validate a Phing script for adherence to the Phing syntax, like a "lint"
+ for Phing scripts.
+
+ Note however that it is actually impossible to write a generic schema for
+ Phing since it is possible to define new elements dynamically which means
+ that the grammar can never be complete.
+
+ However, in a particular setup only a few custom tasks is usually
+ used. This is easy to add att the end of this schema so it can be extended to
+ include those additional elements as well.
+
+ ==================================================================================
+-->
+<grammar xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"
+ xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
+
+ <start>
+ <ref name="project"/>
+ </start>
+
+ <!--
+ ===========================================================================================================
+ Entry point "project" element
+ ===========================================================================================================
+ -->
+ <define name="project">
+ <element name="project">
+ <interleave>
+ <attribute name="name"/>
+ <optional>
+ <attribute name="basedir"/>
+ </optional>
+ <attribute name="default"/>
+ <optional>
+ <attribute name="description"/>
+ </optional>
+ <optional>
+ <attribute name="phingVersion"/>
+ </optional>
+ </interleave>
+
+ <interleave>
+ <zeroOrMore>
+ <ref name="target"/>
+ </zeroOrMore>
+ <ref name="coretasks"/>
+ <ref name="optionaltasks"/>
+ <ref name="customtasks"/>
+ <ref name="coretypes"/>
+ </interleave>
+
+ </element>
+ </define>
+
+ <!--
+ ===========================================================================================================
+ Macros for all built in tasks (both core and optional) as well as for core complex types
+ ===========================================================================================================
+ -->
+
+ <define name="coretypes">
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filelist"/>
+ <ref name="path"/>
+ <ref name="classpath"/>
+ <ref name="excludes"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+
+ <define name="optionaltasks">
+ <zeroOrMore>
+ <choice>
+ <ref name="apigen"/>
+ <ref name="coverage-merger"/>
+ <ref name="coverage-report"/>
+ <ref name="coverage-setup"/>
+ <ref name="dbdeploy"/>
+ <ref name="exportproperties"/>
+ <ref name="filterchain"/>
+ <ref name="ftpdeploy"/>
+ <ref name="gitinit"/>
+ <ref name="gitclone"/>
+ <ref name="gitgc"/>
+ <ref name="gitbranch"/>
+ <ref name="gitfetch"/>
+ <ref name="gitcheckout"/>
+ <ref name="gitmerge"/>
+ <ref name="gitpull"/>
+ <ref name="gitpush"/>
+ <ref name="gittag"/>
+ <ref name="gitlog"/>
+ <ref name="httpget"/>
+ <ref name="httprequest"/>
+ <ref name="headfilter"/>
+ <ref name="iconvfilter"/>
+ <ref name="ioncubeencoder"/>
+ <ref name="ioncubelicense"/>
+ <ref name="jsllint"/>
+ <ref name="jsmin"/>
+ <ref name="mail"/>
+ <ref name="linecontains"/>
+ <ref name="pdosqlexec"/>
+ <ref name="pearpkg"/>
+ <ref name="pearpkg2"/>
+ <ref name="phpcodesniffer"/>
+ <ref name="phpdepend"/>
+ <ref name="phpdoc"/>
+ <ref name="phpdocumentor"/>
+ <ref name="phpdocumentorexternal"/>
+ <ref name="phplint"/>
+ <ref name="linecontainsregexp"/>
+ <ref name="phpunit"/>
+ <ref name="phkpackage"/>
+ <ref name="phpmd"/>
+ <ref name="prefixlines"/>
+ <ref name="phpunitreport"/>
+ <ref name="rst"/>
+ <ref name="s3put"/>
+ <ref name="s3get"/>
+ <ref name="scp"/>
+ <ref name="ssh"/>
+ <ref name="simpletest"/>
+ <ref name="striplinecomments"/>
+ <ref name="stripphpcomments"/>
+ <ref name="symlink"/>
+ <ref name="svncheckout"/>
+ <ref name="svnexport"/>
+ <ref name="svncommit"/>
+ <ref name="svncopy"/>
+ <ref name="svninfo"/>
+ <ref name="svnlastrevision"/>
+ <ref name="svnlog"/>
+ <ref name="svnlist"/>
+ <ref name="svnupdate"/>
+ <ref name="svnswitch"/>
+ <ref name="tabtospace"/>
+ <ref name="tabtospaces"/>
+ <ref name="tailfilter"/>
+ <ref name="tar"/>
+ <ref name="tidyfilter"/>
+ <ref name="untar"/>
+ <ref name="unzip"/>
+ <ref name="version"/>
+ <ref name="xincludefilter"/>
+ <ref name="xsltfilter"/>
+ <ref name="xmllint"/>
+ <ref name="xmlproperty"/>
+ <ref name="zendcodeanalyzer"/>
+ <ref name="zendguardencode"/>
+ <ref name="zendguardlicense"/>
+ <ref name="zip"/>
+ <ref name="contains"/>
+ <ref name="pharpackage"/>
+ <ref name="filehash"/>
+ <ref name="filesize"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+
+ <define name="customtasks">
+ <zeroOrMore>
+ <choice>
+ <ref name="highlightsrc"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+
+ <define name="coretasks">
+ <zeroOrMore>
+ <choice>
+ <ref name="adhoc"/>
+ <ref name="adhoc-task"/>
+ <ref name="adhoc-type"/>
+ <ref name="append"/>
+ <ref name="available"/>
+ <ref name="phingcall"/>
+ <ref name="phpeval"/>
+ <ref name="condition"/>
+ <ref name="copy"/>
+ <ref name="cvs"/>
+ <ref name="cvspass"/>
+ <ref name="chmod"/>
+ <ref name="chown"/>
+ <ref name="delete"/>
+ <ref name="echo"/>
+ <ref name="warn"/>
+ <ref name="exec"/>
+ <ref name="exit"/>
+ <ref name="foreach"/>
+ <ref name="if"/>
+ <ref name="includepath"/>
+ <ref name="input"/>
+ <ref name="mkdir"/>
+ <ref name="move"/>
+ <ref name="phing"/>
+ <ref name="php"/>
+ <ref name="property"/>
+ <ref name="propertyprompt"/>
+ <ref name="reflexive"/>
+ <ref name="resolvepath"/>
+ <ref name="taskdef"/>
+ <ref name="touch"/>
+ <ref name="tstamp"/>
+ <ref name="typedef"/>
+ <ref name="uptodate"/>
+ <ref name="xslt"/>
+ <ref name="loadfile"/>
+ <ref name="import"/>
+ </choice>
+ </zeroOrMore>
+ </define>
+
+ <!--
+ ===========================================================================================================
+ Target element.
+ ===========================================================================================================
+ -->
+ <define name="target">
+ <element name="target">
+
+ <!-- Attributes for target element -->
+ <interleave>
+ <attribute name="name"/>
+ <optional>
+ <attribute name="depends"/>
+ </optional>
+ <optional>
+ <attribute name="if"/>
+ </optional>
+ <optional>
+ <attribute name="unless"/>
+ </optional>
+ <optional>
+ <attribute name="description"/>
+ </optional>
+ </interleave>
+ <interleave>
+ <ref name="coretasks"/>
+ <ref name="coretypes"/>
+ <ref name="optionaltasks"/>
+ <ref name="customtasks"/>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ ===========================================================================================================
+ Core types
+ ===========================================================================================================
+ -->
+
+ <define name="filelist">
+ <element name="filelist">
+ <interleave>
+ <attribute name="dir"/>
+ <choice>
+ <attribute name="files"/>
+ <attribute name="listfile"/>
+ </choice>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="class">
+ <element name="class">
+ <attribute name="name"/>
+ </element>
+ </define>
+ <define name="method">
+ <element name="method">
+ <attribute name="name"/>
+ </element>
+ </define>
+ <define name="file">
+ <element name="file">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+
+ <define name="excludes">
+ <element name="excludes">
+ <oneOrMore>
+ <choice>
+ <ref name="class"/>
+ <ref name="method"/>
+ <ref name="file"/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="fileset">
+ <element name="fileset">
+ <interleave>
+ <choice>
+ <attribute name="refid">
+ <data type="IDREF"/>
+ </attribute>
+ <group>
+ <attribute name="dir"/>
+ <optional>
+ <choice>
+ <attribute name="id">
+ <data type="ID"/>
+ </attribute>
+ <attribute name="refid">
+ <data type="IDREF"/>
+ </attribute>
+ </choice>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <ref name="include"/>
+ <ref name="exclude"/>
+ </choice>
+ </zeroOrMore>
+ </group>
+ </choice>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="path">
+ <element name="path">
+ <optional>
+ <attribute name="id">
+ <data type="ID"/>
+ </attribute>
+ <optional>
+ <attribute name="dir"/>
+ <attribute name="path"/>
+ </optional>
+ </optional>
+ <choice>
+ <text/>
+ <zeroOrMore>
+ <choice>
+ <ref name="pathelement"/>
+ <ref name="fileset"/>
+ <ref name="dirset"/>
+ </choice>
+ </zeroOrMore>
+ </choice>
+ </element>
+ </define>
+
+ <define name="classpath">
+ <element name="classpath">
+ <attribute name="refid">
+ <data type="IDREF"/>
+ </attribute>
+ </element>
+ </define>
+
+ <define name="projdocfileset">
+ <element name="projdocfileset">
+ <attribute name="dir"/>
+ <oneOrMore>
+ <choice>
+ <ref name="include"/>
+ <ref name="exclude"/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="dirset">
+ <element name="dirset">
+ <interleave>
+ <optional>
+ <attribute name="includes"/>
+ </optional>
+ <optional>
+ <attribute name="includesfile"/>
+ </optional>
+ <optional>
+ <attribute name="excludes"/>
+ </optional>
+ <optional>
+ <attribute name="excludesfile"/>
+ </optional>
+ <optional>
+ <attribute name="casesensitive" a:defaultValue="yes">
+ <choice>
+ <value>yes</value>
+ <value>no</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="followsymlinks" a:defaultValue="yes">
+ <choice>
+ <value>yes</value>
+ <value>no</value>
+ </choice>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="include"/>
+ <ref name="exclude"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="include">
+ <element name="include">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <define name="exclude">
+ <element name="exclude">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <define name="pathelement">
+ <element name="pathelement">
+ <attribute name="dir"/>
+ </element>
+ </define>
+
+ <define name="arg">
+ <element name="arg">
+ <choice>
+ <attribute name="value"/>
+ <attribute name="file"/>
+ <attribute name="path"/>
+ <attribute name="line"/>
+ </choice>
+ </element>
+ </define>
+
+
+ <!--
+ ===========================================================================================================
+ Core Tasks
+ ===========================================================================================================
+ -->
+
+ <define name="adhoc">
+ <element name="adhoc">
+ <text/>
+ </element>
+ </define>
+
+ <define name="adhoc-task">
+ <element name="adhoc-task">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <define name="adhoc-type">
+ <element name="adhoc-type">
+ <attribute name="name"/>
+ </element>
+ </define>
+
+ <define name="append">
+ <element name="append">
+ <attribute name="destFile"/>
+ <optional>
+ <attribute name="text"/>
+ </optional>
+ <interleave>
+ <optional>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <interleave>
+ <optional>
+ <ref name="fileset"/>
+ </optional>
+ <optional>
+ <ref name="filelist"/>
+ </optional>
+ </interleave>
+ </oneOrMore>
+ </choice>
+ </optional>
+ <optional>
+ <ref name="filterchain"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="available">
+ <element name="available">
+ <interleave>
+ <attribute name="property"/>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ <choice>
+ <attribute name="file"/>
+ <attribute name="resource"/>
+ </choice>
+ <optional>
+ <attribute name="type"/>
+ </optional>
+ <optional>
+ <attribute name="filepath"/>
+ </optional>
+ <optional>
+ <attribute name="followSymlinks">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="condition">
+ <element name="condition">
+ <attribute name="property"/>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ <optional>
+ <choice>
+ <ref name="or"/>
+ <ref name="and"/>
+ </choice>
+ </optional>
+ </element>
+ </define>
+
+ <define name="delete">
+ <element name="delete">
+ <interleave>
+ <optional>
+ <choice>
+ <attribute name="file"/>
+ <attribute name="dir"/>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="verbose">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="failonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <define name="warn">
+ <element name="warn">
+ <interleave>
+ <choice>
+ <attribute name="msg"/>
+ <attribute name="message"/>
+ </choice>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="append">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="level"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <define name="echo">
+ <element name="echo">
+ <interleave>
+ <choice>
+ <attribute name="msg"/>
+ <attribute name="message"/>
+ <text/>
+ <ref name="fileset"/>
+ </choice>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="append">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="level"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="exec">
+ <element name="exec">
+ <interleave>
+ <oneOrMore>
+ <choice>
+ <attribute name="command"/>
+ <attribute name="executable"/>
+ </choice>
+ </oneOrMore>
+ <optional>
+ <attribute name="passthru">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="checkreturn">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="dir"/>
+ </optional>
+ <optional>
+ <attribute name="os"/>
+ </optional>
+ <optional>
+ <attribute name="escape">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="spawn">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="returnProperty"/>
+ </optional>
+ <optional>
+ <attribute name="outputProperty"/>
+ </optional>
+ <optional>
+ <attribute name="logoutput"/>
+ </optional>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="error"/>
+ </optional>
+ <optional>
+ <attribute name="level">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ <value>info</value>
+ <value>verbose</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="arg"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="copy">
+ <element name="copy">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filelist"/>
+ </choice>
+ </oneOrMore>
+ </choice>
+ <choice>
+ <attribute name="tofile"/>
+ <attribute name="todir"/>
+ </choice>
+ <optional>
+ <attribute name="overwrite">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <choice>
+ <attribute name="tstamp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="preservelastmodified">
+ <data type="boolean"/>
+ </attribute>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="mode">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="mapper"/>
+ <ref name="filterchain"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="argument">
+ <element name="argument">
+ <choice>
+ <attribute name="value"/>
+ <attribute name="line"/>
+ </choice>
+ </element>
+ </define>
+
+ <define name="commandline">
+ <element name="commandline">
+ <attribute name="executable"/>
+ <oneOrMore>
+ <ref name="argument"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="cvs">
+ <element name="cvs">
+ <interleave>
+ <attribute name="dest"/>
+ <attribute name="modules"/>
+ <optional>
+ <attribute name="cvsRoot"/>
+ </optional>
+ <optional>
+ <attribute name="cvsRsh"/>
+ </optional>
+ <optional>
+ <attribute name="port">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="passfile"/>
+ </optional>
+ <optional>
+ <attribute name="tag"/>
+ </optional>
+ <optional>
+ <attribute name="date"/>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="noexec">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="setfailonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="compression">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="compressionlevel">
+ <data type="unsignedByte"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="error"/>
+ </optional>
+ <optional>
+ <attribute name="command"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="cvspass">
+ <element name="cvspass">
+ <interleave>
+ <attribute name="password"/>
+ <attribute name="cvsRoot"/>
+ <optional>
+ <attribute name="passFile"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="exit">
+ <element name="exit">
+ <interleave>
+ <optional>
+ <choice>
+ <attribute name="message"/>
+ <attribute name="msg"/>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="if"/>
+ </optional>
+ <optional>
+ <attribute name="unless"/>
+ </optional>
+ <text/>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="foreach">
+ <element name="foreach">
+ <interleave>
+ <attribute name="target"/>
+ <attribute name="param"/>
+ <optional>
+ <attribute name="list"/>
+ </optional>
+ <optional>
+ <attribute name="delimiter"/>
+ </optional>
+ </interleave>
+ <interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="mapper"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="if">
+ <element name="if">
+ <choice>
+ <ref name="not"/>
+ <ref name="equals"/>
+ <ref name="or"/>
+ <ref name="and"/>
+ <ref name="isfalse"/>
+ <ref name="istrue"/>
+ <ref name="isset"/>
+ <ref name="contains_cond"/>
+ <ref name="referenceexists"/>
+ </choice>
+ <ref name="then"/>
+ <zeroOrMore>
+ <ref name="elseif"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="else"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="not">
+ <element name="not">
+ <choice>
+ <ref name="equals"/>
+ <ref name="or"/>
+ <ref name="and"/>
+ <ref name="isfalse"/>
+ <ref name="istrue"/>
+ <ref name="isset"/>
+ <ref name="contains_cond"/>
+ <ref name="referenceexists"/>
+ </choice>
+ </element>
+ </define>
+
+ <define name="istrue">
+ <element name="istrue">
+ <attribute name="value"/>
+ </element>
+ </define>
+
+ <define name="isset">
+ <element name="isset">
+ <attribute name="property"/>
+ </element>
+ </define>
+
+ <define name="isfalse">
+ <element name="isfalse">
+ <attribute name="value"/>
+ </element>
+ </define>
+
+ <define name="referenceexists">
+ <element name="referenceexists">
+ <attribute name="ref"/>
+ </element>
+ </define>
+
+ <define name="contains_cond">
+ <element name="contains">
+ <interleave>
+ <attribute name="string"/>
+ <attribute name="substring"/>
+ <optional>
+ <attribute name="casesensitive"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="equals">
+ <element name="equals">
+ <interleave>
+ <attribute name="arg1"/>
+ <attribute name="arg2"/>
+ <optional>
+ <attribute name="casesensitive"/>
+ </optional>
+ <optional>
+ <attribute name="trim"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="then">
+ <element name="then">
+ <interleave>
+ <ref name="coretasks"/>
+ <ref name="optionaltasks"/>
+ <ref name="customtasks"/>
+ <ref name="coretypes"/>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="elseif">
+ <choice>
+ <ref name="equals"/>
+ <ref name="or"/>
+ <ref name="and"/>
+ <ref name="isfalse"/>
+ <ref name="istrue"/>
+ <ref name="isset"/>
+ <ref name="contains_cond"/>
+ <ref name="referenceexists"/>
+ </choice>
+ <interleave>
+ <ref name="coretasks"/>
+ <ref name="optionaltasks"/>
+ <ref name="customtasks"/>
+ <ref name="coretypes"/>
+ </interleave>
+ </define>
+
+ <define name="else">
+ <element name="else">
+ <interleave>
+ <ref name="coretasks"/>
+ <ref name="optionaltasks"/>
+ <ref name="customtasks"/>
+ <ref name="coretypes"/>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="includepath">
+ <element name="includepath">
+ <choice>
+ <attribute name="classpath"/>
+ <attribute name="classpathref"/>
+ </choice>
+ </element>
+ </define>
+
+ <define name="or">
+ <element name="or">
+ <oneOrMore>
+ <interleave>
+ <ref name="property"/>
+ <ref name="and"/>
+ <ref name="isfalse"/>
+ <ref name="istrue"/>
+ <ref name="isset"/>
+ <ref name="contains_cond"/>
+ <ref name="referenceexists"/>
+ </interleave>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="and">
+ <element name="and">
+ <oneOrMore>
+ <interleave>
+ <ref name="property"/>
+ <ref name="or"/>
+ <ref name="isfalse"/>
+ <ref name="istrue"/>
+ <ref name="isset"/>
+ <ref name="contains_cond"/>
+ <ref name="referenceexists"/>
+ </interleave>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="input">
+ <element name="input">
+ <interleave>
+ <attribute name="propertyName"/>
+ <attribute name="message"/>
+ <optional>
+ <attribute name="defaultValue"/>
+ </optional>
+ <optional>
+ <attribute name="promptChar"/>
+ </optional>
+ <optional>
+ <attribute name="validArgs"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="mkdir">
+ <element name="mkdir">
+ <attribute name="dir"/>
+ <optional>
+ <attribute name="mode">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
+
+ <define name="move">
+ <element name="move">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filelist"/>
+ </choice>
+ </oneOrMore>
+ </choice>
+ <choice>
+ <attribute name="tofile"/>
+ <attribute name="todir"/>
+ </choice>
+ <optional>
+ <attribute name="overwrite">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <choice>
+ <attribute name="tstamp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="preservelastmodified">
+ <data type="boolean"/>
+ </attribute>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="mode">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="mapper"/>
+ <ref name="filterchain"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="phing">
+ <element name="phing">
+ <interleave>
+ <attribute name="phingfile"/>
+ <optional>
+ <attribute name="inheritAll">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="inheritRefs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="dir"/>
+ </optional>
+ <optional>
+ <ref name="property"/>
+ </optional>
+ <optional>
+ <attribute name="target"/>
+ </optional>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="phingcall">
+ <element name="phingcall">
+ <attribute name="target"/>
+ <zeroOrMore>
+ <choice>
+ <ref name="property"/>
+ <ref name="param"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="phpeval">
+ <element name="phpeval">
+ <interleave>
+ <choice>
+ <attribute name="function"/>
+ <attribute name="expression"/>
+ </choice>
+ <optional>
+ <attribute name="class"/>
+ </optional>
+ <optional>
+ <attribute name="returnProperty"/>
+ </optional>
+ <optional>
+ <attribute name="level">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ <value>info</value>
+ <value>verbose</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="php">
+ <element name="php">
+ <interleave>
+ <choice>
+ <attribute name="function"/>
+ <attribute name="expression"/>
+ </choice>
+ <optional>
+ <attribute name="class"/>
+ </optional>
+ <optional>
+ <attribute name="returnProperty"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="param"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="property">
+ <element name="property">
+ <interleave>
+ <choice>
+ <group>
+ <attribute name="name"/>
+ <attribute name="value"/>
+ </group>
+ <attribute name="file"/>
+ <optional>
+ <attribute name="environment"/>
+ </optional>
+ </choice>
+ <optional>
+ <attribute name="override">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="prefix"/>
+ </optional>
+ <optional>
+ <attribute name="refid"/>
+ </optional>
+ <optional>
+ <attribute name="fallback"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="propertyprompt">
+ <element name="propertyprompt">
+ <interleave>
+ <attribute name="propertyName"/>
+ <attribute name="promptText"/>
+ <optional>
+ <attribute name="promptCharacter"/>
+ </optional>
+ <optional>
+ <attribute name="defaultValue"/>
+ </optional>
+ <optional>
+ <attribute name="useExistingValue"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="reflexive">
+ <element name="reflexive">
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <zeroOrMore>
+ <ref name="filterchain"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="resolvepath">
+ <element name="resolvepath">
+ <interleave>
+ <attribute name="file"/>
+ <attribute name="propertyName"/>
+ <optional>
+ <attribute name="dir"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="symlink">
+ <element name="symlink">
+ <choice>
+ <attribute name="target"/>
+ <ref name="fileset"/>
+ </choice>
+ <attribute name="link"/>
+ <optional>
+ <attribute name="overwrite">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
+
+ <define name="taskdef">
+ <element name="taskdef">
+ <interleave>
+ <choice>
+ <group>
+ <attribute name="classname"/>
+ <attribute name="name"/>
+ </group>
+ <attribute name="file"/>
+ </choice>
+ <optional>
+ <attribute name="classpath"/>
+ </optional>
+ <optional>
+ <attribute name="classpathref"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="touch">
+ <element name="touch">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <ref name="fileset"/>
+ </choice>
+ <optional>
+ <attribute name="datetime"/>
+ </optional>
+ <optional>
+ <attribute name="millis">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="tstamp">
+ <element name="tstamp">
+ <interleave>
+ <optional>
+ <attribute name="prefix"/>
+ </optional>
+ <optional>
+ <element name="format">
+ <interleave>
+ <attribute name="property"/>
+ <attribute name="pattern"/>
+ <optional>
+ <attribute name="locale"/>
+ </optional>
+ </interleave>
+ </element>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="typedef">
+ <element name="typedef">
+ <interleave>
+ <attribute name="classname"/>
+ <attribute name="name"/>
+ <optional>
+ <attribute name="classpath"/>
+ </optional>
+ <optional>
+ <attribute name="classpathref"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="classpath"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="uptodate">
+ <element name="uptodate">
+ <interleave>
+ <attribute name="property"/>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ <choice>
+ <attribute name="srcfile"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <choice>
+ <attribute name="targetfile"/>
+ <oneOrMore>
+ <ref name="mapper"/>
+ </oneOrMore>
+ </choice>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="xslt">
+ <element name="xslt">
+ <interleave>
+ <attribute name="style"/>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filelist"/>
+ </choice>
+ </oneOrMore>
+ </choice>
+ <choice>
+ <attribute name="tofile"/>
+ <attribute name="todir"/>
+ </choice>
+ <optional>
+ <attribute name="overwrite">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <choice>
+ <attribute name="tstamp">
+ <data type="boolean"/>
+ </attribute>
+ <attribute name="preservelastmodified">
+ <data type="boolean"/>
+ </attribute>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="mode">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="mapper"/>
+ <ref name="filterchain"/>
+ <ref name="param"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="chmod">
+ <element name="chmod">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <attribute name="mode"/>
+ <optional>
+ <attribute name="failonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="verbose">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="chown">
+ <element name="chown">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <attribute name="user"/>
+ <optional>
+ <attribute name="failonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="verbose">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="loadfile">
+ <element name="loadfile">
+ <interleave>
+ <attribute name="property"/>
+ <attribute name="file"/>
+ </interleave>
+ <zeroOrMore>
+ <ref name="filterchain"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="import">
+ <element name="import">
+ <attribute name="file"/>
+ <optional>
+ <attribute name="optional">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
+
+
+ <!--
+ ===========================================================================================================
+ Optional Tasks
+ ===========================================================================================================
+ -->
+
+ <!--
+ =========================================
+ ApiGenTask
+ =========================================
+ -->
+
+ <define name="apigen">
+ <element name="apigen">
+ <interleave>
+ <optional>
+ <attribute name="executable"/>
+ </optional>
+ <optional>
+ <attribute name="config"/>
+ </optional>
+ <optional>
+ <attribute name="source"/>
+ </optional>
+ <optional>
+ <attribute name="destination"/>
+ </optional>
+ <optional>
+ <attribute name="extensions"/>
+ </optional>
+ <optional>
+ <attribute name="exclude"/>
+ </optional>
+ <optional>
+ <attribute name="skipdocpath"/>
+ </optional>
+ <optional>
+ <attribute name="skipdocprefix"/>
+ </optional>
+ <optional>
+ <attribute name="charset"/>
+ </optional>
+ <optional>
+ <attribute name="main"/>
+ </optional>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <optional>
+ <attribute name="baseurl"/>
+ </optional>
+ <optional>
+ <attribute name="googlecseid"/>
+ </optional>
+ <optional>
+ <attribute name="googlecselabel"/>
+ </optional>
+ <optional>
+ <attribute name="googleanalytics"/>
+ </optional>
+ <optional>
+ <attribute name="templateconfig"/>
+ </optional>
+ <optional>
+ <attribute name="allowedhtml"/>
+ </optional>
+ <optional>
+ <attribute name="groups"/>
+ </optional>
+ <optional>
+ <attribute name="autocomplete"/>
+ </optional>
+ <optional>
+ <attribute name="accesslevels"/>
+ </optional>
+ <optional>
+ <attribute name="internal">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="php">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tree">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="deprecated">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="todo">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="sourcecode">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="download">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="report"/>
+ </optional>
+ <optional>
+ <attribute name="wipeout">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="updatecheck">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="debug">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ CoverageMergerTask
+ =========================================
+ -->
+
+ <define name="coverage-merger">
+ <element name="coverage-merger">
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ CoverageReportTask
+ =========================================
+ -->
+ <define name="coverage-report">
+ <element name="coverage-report">
+ <attribute name="outfile"/>
+ <optional>
+ <attribute name="classpath"/>
+ </optional>
+ <optional>
+ <attribute name="geshipath"/>
+ </optional>
+ <optional>
+ <attribute name="geshilanguagespath"/>
+ </optional>
+ <ref name="report"/>
+ </element>
+ </define>
+
+ <define name="report">
+ <element name="report">
+ <attribute name="todir"/>
+ <attribute name="styledir"/>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <optional>
+ <attribute name="usesorttable"/>
+ </optional>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ CoverageSetupTask
+ =========================================
+ -->
+ <define name="coverage-setup">
+ <element name="coverage-setup">
+ <interleave>
+ <attribute name="database"/>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filelist"/>
+ <ref name="classpath"/>
+ </choice>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ CoverageThresholdTask
+ =========================================
+ -->
+ <define name="coverage-threshold">
+ <element name="coverage-threshold">
+ <interleave>
+ <optional>
+ <attribute name="database">
+ <data type="string"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="perProject">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="perClass">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="perMethod">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="verbose">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="classpath"/>
+ <ref name="excludes"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ DbDeployTask
+ =========================================
+ -->
+
+ <define name="dbdeploy">
+ <element name="dbdeploy">
+ <interleave>
+ <attribute name="url"/>
+ <attribute name="dir"/>
+ <optional>
+ <attribute name="userid"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+
+ <optional>
+ <attribute name="outputfile"/>
+ </optional>
+
+ <optional>
+ <attribute name="undooutputfile"/>
+ </optional>
+
+ <optional>
+ <attribute name="deltaset"/>
+ </optional>
+
+ <optional>
+ <attribute name="lastchangetoapply">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ ExportPropertiesTask
+ =========================================
+ -->
+
+ <define name="exportproperties">
+ <element name="exportproperties">
+ <interleave>
+ <attribute name="targetfile"/>
+ <optional>
+ <attribute name="disallowedpropertyprefixes"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ FileHashTask
+ =========================================
+ -->
+ <define name="filehash">
+ <element name="filehash">
+ <interleave>
+ <attribute name="file"/>
+ <optional>
+ <attribute name="hashtype">
+ <choice>
+ <value>0</value>
+ <value>1</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ FileSizeTask
+ =========================================
+ -->
+ <define name="filesize">
+ <element name="filesize">
+ <interleave>
+ <attribute name="file"/>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ git Manipulation tasks
+ =========================================
+ -->
+
+ <define name="gitinit">
+ <element name="gitinit">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="bare">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="gitclone">
+ <element name="gitclone">
+ <interleave>
+ <attribute name="repository"/>
+ <attribute name="targetpath"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="bare">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="gitgc">
+ <element name="gitgc">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="aggresive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="auto">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="noprune">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="prune"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="gitbranch">
+ <element name="gitbranch">
+ <interleave>
+ <attribute name="repository"/>
+ <attribute name="branchname"/>
+ <optional>
+ <attribute name="newbranch"/>
+ </optional>
+ <optional>
+ <attribute name="startpoint"/>
+ </optional>
+ <optional>
+ <attribute name="setupstream"/>
+ </optional>
+ <optional>
+ <attribute name="track">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="notrack">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="move">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="forcemove">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="delete">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="forcedelete">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="gitfetch">
+ <element name="gitfetch">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="source"/>
+ </optional>
+ <optional>
+ <attribute name="refspec"/>
+ </optional>
+ <optional>
+ <attribute name="group"/>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="all">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="keep">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="prune">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="notags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+
+ </element>
+ </define>
+
+ <define name="gitcheckout">
+ <element name="gitcheckout">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="forcecreate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="create">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="merge">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="track">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="notrack">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+
+ </element>
+ </define>
+
+ <define name="gitmerge">
+ <element name="gitmerge">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="remote"/>
+ </optional>
+ <optional>
+ <attribute name="message"/>
+ </optional>
+ <optional>
+ <attribute name="strategy"/>
+ </optional>
+ <optional>
+ <attribute name="strategyoption"/>
+ </optional>
+ <optional>
+ <attribute name="commit">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="nocommit">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="fastforwardcommit">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="gitpull">
+ <element name="gitpull">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="all"/>
+ </optional>
+ <optional>
+ <attribute name="source"/>
+ </optional>
+ <optional>
+ <attribute name="refspec"/>
+ </optional>
+ <optional>
+ <attribute name="strategy"/>
+ </optional>
+ <optional>
+ <attribute name="strategyoption"/>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="append">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="keepfiles">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="notags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="norebase">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="rebase">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+
+ </interleave>
+
+ </element>
+ </define>
+
+ <define name="gitpush">
+ <element name="gitpush">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="all"/>
+ </optional>
+ <optional>
+ <attribute name="destination"/>
+ </optional>
+ <optional>
+ <attribute name="refspec"/>
+ </optional>
+ <optional>
+ <attribute name="mirror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="delete">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+
+ </element>
+ </define>
+
+ <define name="gittag">
+ <element name="gittag">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="message"/>
+ </optional>
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <optional>
+ <attribute name="commit"/>
+ </optional>
+ <optional>
+ <attribute name="object"/>
+ </optional>
+ <optional>
+ <attribute name="pattern"/>
+ </optional>
+ <optional>
+ <attribute name="outputproperty"/>
+ </optional>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="num">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="contains"/>
+ </optional>
+ <optional>
+ <attribute name="keysign"/>
+ </optional>
+ <optional>
+ <attribute name="verify">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="sign">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="list">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="delete">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="annotate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+
+ </element>
+ </define>
+
+ <define name="gitlog">
+ <element name="gitlog">
+ <interleave>
+ <attribute name="repository"/>
+ <optional>
+ <attribute name="gitpath"/>
+ </optional>
+ <optional>
+ <attribute name="outputproperty"/>
+ </optional>
+ <optional>
+ <attribute name="paths"/>
+ </optional>
+ <optional>
+ <attribute name="format"/>
+ </optional>
+ <optional>
+ <attribute name="date"/>
+ </optional>
+ <optional>
+ <attribute name="since"/>
+ </optional>
+ <optional>
+ <attribute name="until"/>
+ </optional>
+ <optional>
+ <attribute name="stat"/>
+ </optional>
+ <optional>
+ <attribute name="namestatus">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="maxcount">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="nomerges">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ Http manipulation
+ =========================================
+ -->
+ <define name="httpget">
+ <element name="httpget">
+ <interleave>
+ <attribute name="url"/>
+ <attribute name="dir"/>
+ <optional>
+ <attribute name="filename"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="header">
+ <element name="header">
+ <attribute name="name"/>
+ <attribute name="val"/>
+ </element>
+ </define>
+
+ <define name="httprequest">
+ <element name="httprequest">
+ <interleave>
+ <attribute name="url"/>
+ <optional>
+ <attribute name="responseregex"/>
+ </optional>
+ <optional>
+ <attribute name="authuser"/>
+ </optional>
+ <optional>
+ <attribute name="authpassword"/>
+ </optional>
+ <optional>
+ <attribute name="authschema"/>
+ </optional>
+ <optional>
+ <attribute name="verbose">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="observerevents"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="config"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="header"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ IoncubeEncoderTask
+ =========================================
+ -->
+ <define name="ioncubeencoder">
+ <element name="ioncubeencoder">
+ <interleave>
+ <attribute name="ignore"/>
+ <attribute name="fromdir"/>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="allowedserver"/>
+ </optional>
+ <optional>
+ <attribute name="binary">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="copy"/>
+ </optional>
+ <optional>
+ <attribute name="encode"/>
+ </optional>
+ <optional>
+ <attribute name="encrypt"/>
+ </optional>
+ <optional>
+ <attribute name="expirein"/>
+ </optional>
+ <optional>
+ <attribute name="expireon"/>
+ </optional>
+ <optional>
+ <attribute name="ioncubepath"/>
+ </optional>
+ <optional>
+ <attribute name="keep"/>
+ </optional>
+ <optional>
+ <attribute name="licensepath"/>
+ </optional>
+ <optional>
+ <attribute name="nodocomments"/>
+ </optional>
+ <optional>
+ <attribute name="obfuscation-key"/>
+ </optional>
+ <optional>
+ <attribute name="obfuscate"/>
+ </optional>
+ <optional>
+ <attribute name="optimize"/>
+ </optional>
+ <optional>
+ <attribute name="passphrase"/>
+ </optional>
+ <optional>
+ <attribute name="phpversion">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="targetoption"/>
+ </optional>
+ <optional>
+ <attribute name="withoutruntimeloadersupport">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="noshortopentags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="callbackfile"/>
+ </optional>
+ <optional>
+ <attribute name="obfuscationexclusionfile"/>
+ </optional>
+ <optional>
+ <attribute name="ignoredeprecatedwarnings">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignorestrictwarnings">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="allowencodingintosource">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="messageifnoloader"/>
+ </optional>
+ <optional>
+ <attribute name="actionifnoloader"/>
+ </optional>
+ <optional>
+ <attribute name="showcommandline">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <optional>
+ <ref name="comment"/>
+ </optional>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ IoncubeLicenseTask
+ =========================================
+ -->
+ <define name="ioncubelicense">
+ <element name="ioncubelicense">
+ <interleave>
+ <optional>
+ <attribute name="licensepath"/>
+ </optional>
+ <optional>
+ <attribute name="ioncubepath"/>
+ </optional>
+ <optional>
+ <attribute name="passphrase"/>
+ </optional>
+ <optional>
+ <attribute name="allowedserver"/>
+ </optional>
+ <optional>
+ <attribute name="expirein"/>
+ </optional>
+ <optional>
+ <attribute name="expireon"/>
+ </optional>
+ </interleave>
+ <optional>
+ <ref name="comment"/>
+ </optional>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ JslLintTask
+ =========================================
+ -->
+ <define name="jsllint">
+ <element name="jsllint">
+ <interleave>
+ <choice>
+ <attribute name="executable"/>
+ </choice>
+ <choice>
+ <attribute name="file"/>
+ <ref name="fileset"/>
+ </choice>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="showwarnings">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="cachefile"/>
+ </optional>
+ <optional>
+ <attribute name="conffile"/>
+ </optional>
+ <optional>
+ <attribute name="tofile"/>
+ </optional>
+ </interleave>
+ <ref name="fileset"/>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ JsMinTask
+ =========================================
+ -->
+ <define name="jsmin">
+ <element name="jsmin">
+ <interleave>
+ <attribute name="targetdir"/>
+ <optional>
+ <attribute name="suffix"/>
+ </optional>
+ <optional>
+ <attribute name="failonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ MailTask
+ =========================================
+ -->
+
+ <define name="mail">
+ <element name="mail">
+ <interleave>
+ <attribute name="from"/>
+ <attribute name="tolist"/>
+ <optional>
+ <attribute name="message"/>
+ </optional>
+ <optional>
+ <attribute name="subject"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PatchTask
+ =========================================
+ -->
+
+ <define name="patch">
+ <element name="patch">
+ <interleave>
+ <attribute name="patchfile"/>
+ <optional>
+ <attribute name="originalfile"/>
+ </optional>
+ <optional>
+ <attribute name="destfile"/>
+ </optional>
+ <optional>
+ <attribute name="backups">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="reverse">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignorewhitespace">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="strip">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="dir"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+
+ <!--
+ =========================================
+ PDOSQLExecTask
+ =========================================
+ -->
+ <define name="pdosqlexec">
+ <element name="pdosqlexec">
+ <interleave>
+ <attribute name="url"/>
+ <optional>
+ <attribute name="userid"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="encoding"/>
+ </optional>
+ <optional>
+ <attribute name="src"/>
+ </optional>
+ <optional>
+ <attribute name="onerror"/>
+ </optional>
+ <optional>
+ <attribute name="delimiter"/>
+ </optional>
+ <optional>
+ <attribute name="delimitertype"/>
+ </optional>
+ <optional>
+ <attribute name="autocommit">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="transaction"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="formatter"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="transaction">
+ <element name="transaction">
+ <optional>
+ <attribute name="tsrcfile"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="formatter">
+ <element name="formatter">
+ <interleave>
+ <choice>
+ <attribute name="type"/>
+ <attribute name="classname"/>
+ </choice>
+ <optional>
+ <attribute name="usefile">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="outfile"/>
+ </optional>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="showheaders">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="coldelim"/>
+ </optional>
+ <optional>
+ <attribute name="rowdelim"/>
+ </optional>
+ <optional>
+ <attribute name="encoding"/>
+ </optional>
+ <optional>
+ <attribute name="formatoutput">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="todir"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="param"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ PearPackageTask
+ =========================================
+ -->
+ <define name="pearpkg">
+ <element name="pearpkg">
+ <interleave>
+ <attribute name="name"/>
+ <attribute name="dir"/>
+ <optional>
+ <attribute name="destFile"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="mapping"/>
+ <ref name="option"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PearPackage2Task
+ =========================================
+ -->
+ <define name="pearpkg2">
+ <element name="pearpkg2">
+ <interleave>
+ <attribute name="name"/>
+ <attribute name="dir"/>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="mapping"/>
+ <ref name="option"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="option">
+ <element name="option">
+ <interleave>
+ <attribute name="name"/>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ </interleave>
+ <text/>
+ </element>
+ </define>
+
+ <define name="mapping">
+ <element name="mapping">
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <oneOrMore>
+ <ref name="element"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="element">
+ <element name="element">
+ <interleave>
+ <optional>
+ <choice>
+ <attribute name="key"/>
+ <attribute name="name"/>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="element"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PharPackageTask
+ =========================================
+ -->
+ <define name="pharpackage">
+ <element name="pharpackage">
+ <interleave>
+ <attribute name="basedir"/>
+ <attribute name="destfile"/>
+ <optional>
+ <attribute name="compression"/>
+ </optional>
+ <optional>
+ <attribute name="webstub"/>
+ </optional>
+ <optional>
+ <attribute name="clistub"/>
+ </optional>
+ <optional>
+ <attribute name="stub"/>
+ </optional>
+ <optional>
+ <attribute name="alias"/>
+ </optional>
+ <optional>
+ <attribute name="signature"/>
+ </optional>
+ </interleave>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ <optional>
+ <ref name="metadata"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="metadata">
+ <element name="metadata">
+ <oneOrMore>
+ <ref name="element"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PhkPackageTask
+ =========================================
+ -->
+ <define name="phkpackage">
+ <element name="phkpackage">
+ <interleave>
+ <attribute name="phkcreatorpath"/>
+ <attribute name="inputdirectory"/>
+ <attribute name="outputfile"/>
+ <optional>
+ <attribute name="compress"/>
+ </optional>
+ <optional>
+ <attribute name="strip">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <optional>
+ <attribute name="webrunscript"/>
+ </optional>
+ <optional>
+ <attribute name="crccheck"/>
+ </optional>
+ <optional>
+ <ref name="webaccess"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="webaccess">
+ <element name="webaccess">
+ <oneOrMore>
+ <ref name="path"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PhpCodeSnifferTask
+ =========================================
+ -->
+ <define name="phpcodesniffer">
+ <element name="phpcodesniffer">
+ <interleave>
+ <optional>
+ <attribute name="standard"/>
+ </optional>
+ <optional>
+ <attribute name="format"/>
+ </optional>
+ <optional>
+ <attribute name="showSniffs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="showWarnings">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="showSources">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <optional>
+ <attribute name="sniffs"/>
+ </optional>
+ <optional>
+ <attribute name="verbosity"/>
+ </optional>
+ <optional>
+ <attribute name="tabwidth">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="reportwidth">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="docgenerator"/>
+ </optional>
+ <optional>
+ <attribute name="docfile"/>
+ </optional>
+ <optional>
+ <attribute name="allowedFileExtensions"/>
+ </optional>
+ <optional>
+ <attribute name="ignorePatterns"/>
+ </optional>
+ <optional>
+ <attribute name="nosubdirectories">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonwarning">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="skipversioncheck">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <ref name="config"/>
+ <ref name="formatter"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="config">
+ <element name="config">
+ <attribute name="name"/>
+ <attribute name="value"/>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ PhpDocumentorTask
+ =========================================
+ -->
+ <define name="phpdocumentor">
+ <element name="phpdocumentor">
+ <interleave>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <choice>
+ <attribute name="destdir"/>
+ <attribute name="target"/>
+ </choice>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="sourcecode">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="examplesdir"/>
+ </optional>
+ <optional>
+ <attribute name="parseprivate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="javadocdesc">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="packageoutput"/>
+ </optional>
+ <optional>
+ <attribute name="ignoretags"/>
+ </optional>
+ <optional>
+ <attribute name="defaultpackagename"/>
+ </optional>
+ <optional>
+ <attribute name="defaultcategoryname"/>
+ </optional>
+ <optional>
+ <attribute name="pear"/>
+ </optional>
+ <optional>
+ <attribute name="templatebase"/>
+ </optional>
+ <optional>
+ <attribute name="undocumentedelements"/>
+ </optional>
+ <optional>
+ <attribute name="customtags"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="projdocfileset"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PHPMDTask
+ =========================================
+ -->
+ <define name="phpmd">
+ <element name="phpmd">
+ <interleave>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="ruleset"/>
+ </optional>
+ <optional>
+ <attribute name="minimumpriority">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="allowedfileextensions"/>
+ </optional>
+ <optional>
+ <attribute name="ignorepatterns"/>
+ </optional>
+ <optional>
+ <attribute name="format"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PhpDependTask
+ =========================================
+ -->
+ <define name="phpdepend">
+ <element name="phpdepend">
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="configfile"/>
+ </optional>
+ <optional>
+ <attribute name="allowedfileextensions"/>
+ </optional>
+ <optional>
+ <attribute name="excludedirectories"/>
+ </optional>
+ <optional>
+ <attribute name="excludepackages"/>
+ </optional>
+ <optional>
+ <attribute name="withoutannotations">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="superbaddocumentation">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="debug">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PhpDocumentorTask
+ =========================================
+ -->
+ <define name="phpdoc">
+ <element name="phpdoc">
+ <interleave>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <choice>
+ <attribute name="destdir"/>
+ <attribute name="target"/>
+ </choice>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="sourcecode">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="examplesdir"/>
+ </optional>
+ <optional>
+ <attribute name="parseprivate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="javadocdesc">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="packageoutput"/>
+ </optional>
+ <optional>
+ <attribute name="ignoretags"/>
+ </optional>
+ <optional>
+ <attribute name="defaultpackagename"/>
+ </optional>
+ <optional>
+ <attribute name="defaultcategoryname"/>
+ </optional>
+ <optional>
+ <attribute name="pear">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="templatebase"/>
+ </optional>
+ <optional>
+ <attribute name="undocumentedelements">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="customtags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignore"/>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="projdocfileset"/>
+ </choice>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ PhpDocumentorExternalTask
+ =========================================
+ -->
+ <define name="phpdocumentorexternal">
+ <element name="phpdocumentorexternal">
+ <interleave>
+ <optional>
+ <attribute name="title"/>
+ </optional>
+ <choice>
+ <attribute name="destdir"/>
+ <attribute name="target"/>
+ </choice>
+ <optional>
+ <attribute name="output"/>
+ </optional>
+ <optional>
+ <attribute name="sourcecode">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="examplesdir"/>
+ </optional>
+ <optional>
+ <attribute name="parseprivate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="javadocdesc">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="quiet">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="packageoutput"/>
+ </optional>
+ <optional>
+ <attribute name="ignoretags"/>
+ </optional>
+ <optional>
+ <attribute name="defaultpackagename"/>
+ </optional>
+ <optional>
+ <attribute name="defaultcategoryname"/>
+ </optional>
+ <optional>
+ <attribute name="pear"/>
+ </optional>
+ <optional>
+ <attribute name="templatebase"/>
+ </optional>
+ <optional>
+ <attribute name="undocumentedelements"/>
+ </optional>
+ <optional>
+ <attribute name="customtags"/>
+ </optional>
+ <optional>
+ <attribute name="programpath"/>
+ </optional>
+ <optional>
+ <attribute name="ignore"/>
+ </optional>
+ <choice>
+ <attribute name="sourcepath"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PhpLintTask
+ =========================================
+ -->
+ <define name="phplint">
+ <element name="phplint">
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="errorproperty"/>
+ </optional>
+ <optional>
+ <attribute name="interpretator"/>
+ </optional>
+ <optional>
+ <attribute name="cachefile"/>
+ </optional>
+ <optional>
+ <attribute name="level">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ <value>info</value>
+ <value>verbose</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="tofile"/>
+ </optional>
+ <optional>
+ <attribute name="deprecatedaserror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PHPUnitTask
+ =========================================
+ -->
+ <define name="phpunit">
+ <element name="phpunit">
+ <interleave>
+ <optional>
+ <attribute name="printsummary">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="bootstrap"/>
+ </optional>
+ <optional>
+ <attribute name="codecoverage">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonincomplete">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonskipped">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="failureproperty"/>
+ </optional>
+ <optional>
+ <attribute name="errorproperty"/>
+ </optional>
+ <optional>
+ <attribute name="incompleteproperty"/>
+ </optional>
+ <optional>
+ <attribute name="skippedproperty"/>
+ </optional>
+ <optional>
+ <attribute name="usecustomerrorhandler">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="processisolation">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="formatter"/>
+ </zeroOrMore>
+ <optional>
+ <ref name="batchtest"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="batchtest">
+ <element name="batchtest">
+ <interleave>
+ <optional>
+ <attribute name="exclude"/>
+ </optional>
+ <optional>
+ <attribute name="classpath"/>
+ </optional>
+ </interleave>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ PHPUnitReporttask
+ =========================================
+ -->
+ <define name="phpunitreport">
+ <element name="phpunitreport">
+ <interleave>
+ <optional>
+ <attribute name="infile"/>
+ </optional>
+ <optional>
+ <attribute name="format"/>
+ </optional>
+ <optional>
+ <attribute name="styledir"/>
+ </optional>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="usesorttable">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ rSTTask
+ =========================================
+ -->
+ <define name="rst">
+ <element name="rst">
+ <interleave>
+ <choice>
+ <attribute name="file"/>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </choice>
+ <optional>
+ <attribute name="format">
+ <choice>
+ <value>html</value>
+ <value>latex</value>
+ <value>man</value>
+ <value>odt</value>
+ <value>s5</value>
+ <value>xml</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="destination"/>
+ </optional>
+ <optional>
+ <attribute name="uptodate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="toolpath"/>
+ </optional>
+ <optional>
+ <attribute name="toolparam"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="mapper"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="filterchain"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ S3PutTask
+ =========================================
+ -->
+ <define name="s3put">
+ <element name="s3put">
+ <interleave>
+ <choice>
+ <attribute name="source"/>
+ <attribute name="content"/>
+ </choice>
+ <attribute name="key"/>
+ <attribute name="secret"/>
+ <attribute name="bucket"/>
+ <optional>
+ <attribute name="object"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ S3GetTask
+ =========================================
+ -->
+ <define name="s3get">
+ <element name="s3get">
+ <interleave>
+ <attribute name="key"/>
+ <attribute name="secret"/>
+ <attribute name="bucket"/>
+ <attribute name="object"/>
+ <attribute name="target"/>
+ </interleave>
+ </element>
+ </define>
+
+
+ <define name="scp">
+ <element name="scp">
+ <interleave>
+ <attribute name="host"/>
+ <optional>
+ <attribute name="port">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <attribute name="username"/>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="pubkeyfile"/>
+ </optional>
+ <optional>
+ <attribute name="privkeyfile"/>
+ </optional>
+ <optional>
+ <attribute name="privkeyfilepassphrase"/>
+ </optional>
+ <optional>
+ <attribute name="autocreate">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="todir"/>
+ </optional>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="fetch">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="level">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ <value>info</value>
+ <value>verbose</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+ </optional>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SshTask
+ =========================================
+ -->
+ <define name="ssh">
+ <element name="ssh">
+ <interleave>
+ <attribute name="host"/>
+ <optional>
+ <attribute name="port">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <attribute name="username"/>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="pubkeyfile"/>
+ </optional>
+ <optional>
+ <attribute name="privkeyfile"/>
+ </optional>
+ <optional>
+ <attribute name="privkeyfilepassphrase"/>
+ </optional>
+ <attribute name="command"/>
+ <optional>
+ <attribute name="property"/>
+ </optional>
+ <optional>
+ <attribute name="display">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SimpleTestTask
+ =========================================
+ -->
+ <define name="simpletest">
+ <element name="simpletest">
+ <interleave>
+ <optional>
+ <attribute name="printsummary">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonerror">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="failureproperty"/>
+ </optional>
+ <optional>
+ <attribute name="errorproperty"/>
+ </optional>
+ <optional>
+ <attribute name="debug">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <optional>
+ <ref name="formatter"/>
+ </optional>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SvnCheckoutTask
+ =========================================
+ -->
+ <define name="svncheckout">
+ <element name="svncheckout">
+ <interleave>
+ <attribute name="repositoryurl"/>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <empty/>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SvnCommitTask
+ =========================================
+ -->
+ <define name="svncommit">
+ <element name="svncommit">
+ <interleave>
+ <attribute name="message"/>
+ <attribute name="workingcopy"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SvnCopyTask
+ =========================================
+ -->
+ <define name="svncopy">
+ <element name="svncopy">
+ <interleave>
+ <attribute name="repositoryurl"/>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="message"/>
+ </optional>
+ <attribute name="workingcopy"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SvnExportTask
+ =========================================
+ -->
+ <define name="svnexport">
+ <element name="svnexport">
+ <interleave>
+ <attribute name="repositoryurl"/>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals"/>
+ </optional>
+ <optional>
+ <attribute name="force">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SvnInfoTask
+ =========================================
+ -->
+ <define name="svninfo">
+ <element name="svninfo">
+ <interleave>
+ <choice>
+ <attribute name="workingcopy"/>
+ <attribute name="repositoryurl"/>
+ </choice>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ <optional>
+ <attribute name="element"/>
+ </optional>
+ <optional>
+ <attribute name="subelement"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SvnLastRevisionTask
+ =========================================
+ -->
+ <define name="svnlastrevision">
+ <element name="svnlastrevision">
+ <interleave>
+ <attribute name="workingcopy"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ <optional>
+ <attribute name="lastChanged">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="forcecompatible">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SvnListTask
+ =========================================
+ -->
+ <define name="svnlist">
+ <element name="svnlist">
+ <interleave>
+ <choice>
+ <attribute name="workingcopy"/>
+ <attribute name="repositourl"/>
+ </choice>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ <optional>
+ <attribute name="forcecompatible">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="limit">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="orderdescending">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ SvnLogTask
+ =========================================
+ -->
+ <define name="svnlog">
+ <element name="svnlog">
+ <interleave>
+ <choice>
+ <attribute name="workingcopy"/>
+ <attribute name="repositourl"/>
+ </choice>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="propertyname"/>
+ </optional>
+ <optional>
+ <attribute name="forcecompatible">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="limit">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SvnUpdateTask
+ =========================================
+ -->
+ <define name="svnupdate">
+ <element name="svnupdate">
+ <interleave>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="revision">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ SvnSwitchTask
+ =========================================
+ -->
+ <define name="svnswitch">
+ <element name="svnswitch">
+ <interleave>
+ <attribute name="todir"/>
+ <attribute name="repositoryurl"/>
+ <optional>
+ <attribute name="svnpath"/>
+ </optional>
+ <optional>
+ <attribute name="username"/>
+ </optional>
+ <optional>
+ <attribute name="password"/>
+ </optional>
+ <optional>
+ <attribute name="nocache">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="recursive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="ignoreexternals">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="trustservercert">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+
+ <!--
+ =========================================
+ TarTask
+ =========================================
+ -->
+ <define name="tar">
+ <element name="tar">
+ <interleave>
+ <attribute name="destfile"/>
+ <optional>
+ <attribute name="basedir"/>
+ </optional>
+ <optional>
+ <attribute name="compression">
+ <choice>
+ <value>gzip</value>
+ <value>bzip2</value>
+ <value>none</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="longfile">
+ <choice>
+ <value>truncate</value>
+ <value>fail</value>
+ <value>warn</value>
+ <value>gnu</value>
+ <value>omit</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="prefix"/>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ UntarTask
+ =========================================
+ -->
+ <define name="untar">
+ <element name="untar">
+ <interleave>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="removepath"/>
+ </optional>
+ <optional>
+ <attribute name="forceextract">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ UnzipTask
+ =========================================
+ -->
+ <define name="unzip">
+ <element name="unzip">
+ <interleave>
+ <attribute name="todir"/>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="forceextract">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ VersionTask
+ =========================================
+ -->
+ <define name="version">
+ <element name="version">
+ <interleave>
+ <attribute name="releasetype">
+ <choice>
+ <value>Major</value>
+ <value>Minor</value>
+ <value>Bugfix</value>
+ </choice>
+ </attribute>
+ <attribute name="file"/>
+ <attribute name="property"/>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ XmlLintTask
+ =========================================
+ -->
+ <define name="xmllint">
+ <element name="xmllint">
+ <interleave>
+ <attribute name="schema"/>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="useRNG">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="haltonfailure">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ XmlPropertyTask
+ =========================================
+ -->
+ <define name="xmlproperty">
+ <element name="xmlproperty">
+ <interleave>
+ <attribute name="file"/>
+ <optional>
+ <attribute name="prefix"/>
+ </optional>
+ <optional>
+ <attribute name="keeproot">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="collapseattributes">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="delimiter"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ ZendCodeAnalyzerTask
+ =========================================
+ -->
+ <define name="zendcodeanalyzer">
+ <element name="zendcodeanalyzer">
+ <interleave>
+ <attribute name="analyzerPath"/>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ <optional>
+ <attribute name="disable"/>
+ </optional>
+ <optional>
+ <attribute name="enable"/>
+ </optional>
+ <optional>
+ <attribute name="haltonwarning">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ ZendGuardEncodeTask
+ =========================================
+ -->
+ <define name="zendguardencode">
+ <element name="zendguardencode">
+ <interleave>
+ <attribute name="zendencoderpath"/>
+ <optional>
+ <attribute name="deletesource">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="renamesourceext"/>
+ </optional>
+ <optional>
+ <attribute name="expires"/>
+ </optional>
+ <optional>
+ <attribute name="obfuscationlevel">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="optmask">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="privatekeypath"/>
+ </optional>
+ <optional>
+ <attribute name="productname"/>
+ </optional>
+ <optional>
+ <attribute name="prologfile"/>
+ </optional>
+ <optional>
+ <attribute name="shorttags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="asptags">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="noheader">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="usecrypto">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="encodedonly">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="forceencode">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="licenseproduct">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="signproduct">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <!--
+ =========================================
+ ZendGuardLicenseTask
+ =========================================
+ -->
+ <define name="zendguardlicense">
+ <element name="zendguardlicense">
+ <interleave>
+ <attribute name="zendsignpath"/>
+ <attribute name="privatekeypath"/>
+ <attribute name="outputfile"/>
+ <attribute name="productname"/>
+ <attribute name="registeredto"/>
+ <attribute name="expires"/>
+ <optional>
+ <attribute name="licensetemplate"/>
+ </optional>
+ <optional>
+ <attribute name="iprange"/>
+ </optional>
+ <optional>
+ <attribute name="hardwarelocked">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="hostid"/>
+ </optional>
+ <optional>
+ <attribute name="userdefinedvalues"/>
+ </optional>
+ <optional>
+ <attribute name="xuserdefinedvalues"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+
+
+ <!--
+ =========================================
+ ZipTask
+ =========================================
+ -->
+ <define name="zip">
+ <element name="zip">
+ <interleave>
+ <attribute name="destfile"/>
+ <optional>
+ <attribute name="basedir"/>
+ </optional>
+ <optional>
+ <attribute name="prefix"/>
+ </optional>
+ <optional>
+ <attribute name="includeemptydirs">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ </interleave>
+ <zeroOrMore>
+ <ref name="fileset"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <!--
+ =========================================
+ FtpDeployTask
+ =========================================
+ -->
+ <define name="ftpdeploy">
+ <element name="ftpdeploy">
+ <interleave>
+ <attribute name="host"/>
+ <attribute name="username"/>
+ <attribute name="password"/>
+ <optional>
+ <attribute name="port">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="dir"/>
+ </optional>
+ <optional>
+ <attribute name="mode">
+ <choice>
+ <value>ascii</value>
+ <value>binary</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="clearfirst">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="passive">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="level">
+ <choice>
+ <value>error</value>
+ <value>warning</value>
+ <value>info</value>
+ <value>verbose</value>
+ <value>debug</value>
+ </choice>
+ </attribute>
+ </optional>
+ <oneOrMore>
+ <ref name="fileset"/>
+ </oneOrMore>
+ </interleave>
+ </element>
+ </define>
+
+ <!--
+ ======================================================================
+ Filters
+ ======================================================================
+ -->
+
+ <define name="mapper">
+ <element name="mapper">
+ <interleave>
+ <choice>
+ <attribute name="classname"/>
+ <attribute name="type">
+ <choice>
+ <value type="string">flatten</value>
+ <value type="string">glob</value>
+ <value type="string">merge</value>
+ <value type="string">identity</value>
+ <value type="string">regexp</value>
+ </choice>
+ </attribute>
+ </choice>
+ <optional>
+ <attribute name="from"/>
+ </optional>
+ <optional>
+ <attribute name="to"/>
+ </optional>
+ </interleave>
+ </element>
+ </define>
+
+ <define name="param">
+ <element name="param">
+ <optional>
+ <attribute name="type"/>
+ </optional>
+ <optional>
+ <attribute name="key"/>
+ </optional>
+ <optional>
+ <attribute name="value"/>
+ </optional>
+ <optional>
+ <attribute name="name"/>
+ </optional>
+ <optional>
+ <attribute name="expression"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="filterreader">
+ <element name="filterreader">
+ <attribute name="classname"/>
+ <optional>
+ <attribute name="classpath"/>
+ </optional>
+ <optional>
+ <attribute name="classpathref"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="param"/>
+ </zeroOrMore>
+ </element>
+ </define>
+
+ <define name="expandproperties">
+ <element name="expandproperties">
+ <empty/>
+ </element>
+ </define>
+
+ <define name="filterchain">
+ <element name="filterchain">
+ <oneOrMore>
+ <choice>
+ <ref name="expandproperties"/>
+ <ref name="filterreader"/>
+ <ref name="expandproperties"/>
+ <ref name="headfilter"/>
+ <ref name="iconvfilter"/>
+ <ref name="linecontains"/>
+ <ref name="linecontainsregexp"/>
+ <ref name="prefixlines"/>
+ <ref name="replacetokens"/>
+ <ref name="replaceregexp"/>
+ <ref name="striplinecomments"/>
+ <ref name="stripphpcomments"/>
+ <ref name="stripwhitespace"/>
+ <ref name="tabtospaces"/>
+ <ref name="tailfilter"/>
+ <ref name="tidyfilter"/>
+ <ref name="xincludefilter"/>
+ <ref name="xsltfilter"/>
+ </choice>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="linecontains">
+ <element name="linecontains">
+ <oneOrMore>
+ <ref name="contains"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="contains">
+ <element name="contains">
+ <attribute name="value"/>
+ </element>
+ </define>
+
+ <define name="linecontainsregexp">
+ <element name="linecontainsregexp">
+ <ref name="regexp"/>
+ </element>
+ </define>
+
+ <define name="regexp">
+ <element name="regexp">
+ <attribute name="pattern"/>
+ <optional>
+ <attribute name="replace"/>
+ </optional>
+ <optional>
+ <attribute name="ignoreCase"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="prefixlines">
+ <element name="prefixlines">
+ <attribute name="prefix"/>
+ </element>
+ </define>
+
+ <define name="replacetokens">
+ <element name="replacetokens">
+ <interleave>
+ <optional>
+ <attribute name="begintoken"/>
+ </optional>
+ <optional>
+ <attribute name="endtoken"/>
+ </optional>
+ </interleave>
+ <oneOrMore>
+ <ref name="token"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="token">
+ <element name="token">
+ <attribute name="key"/>
+ <attribute name="value"/>
+ </element>
+ </define>
+
+ <define name="replaceregexp">
+ <element name="replaceregexp">
+ <oneOrMore>
+ <ref name="regexp"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="stripwhitespace">
+ <element name="stripwhitespace">
+ <optional>
+ <attribute name="tablength">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </element>
+ </define>
+
+ <define name="striplinecomments">
+ <element name="striplinecomments">
+ <oneOrMore>
+ <ref name="comment"/>
+ </oneOrMore>
+ </element>
+ </define>
+
+ <define name="comment">
+ <element name="comment">
+ <choice>
+ <attribute name="value"/>
+ <text/>
+ </choice>
+ </element>
+ </define>
+
+ <define name="stripphpcomments">
+ <element name="stripphpcomments">
+ <empty/>
+ </element>
+ </define>
+
+ <define name="tabtospaces">
+ <element name="tabtospaces">
+ <empty/>
+ </element>
+ </define>
+
+ <define name="tabtospace">
+ <element name="tabtospaces">
+ <optional>
+ <attribute name="tablength">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </element>
+ <empty/>
+ </define>
+
+ <define name="tailfilter">
+ <element name="tailfilter">
+ <optional>
+ <attribute name="lines">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ </element>
+ <empty/>
+ </define>
+
+ <define name="headfilter">
+ <element name="headfilter">
+ <optional>
+ <attribute name="lines">
+ <data type="int"/>
+ </attribute>
+ </optional>
+ <empty/>
+ </element>
+ </define>
+
+ <define name="iconvfilter">
+ <element name="iconvfilter">
+ <attribute name="inputencoding"/>
+ <attribute name="outputencoding"/>
+ <empty/>
+ </element>
+ </define>
+
+ <define name="tidyfilter">
+ <element name="tidyfilter">
+ <optional>
+ <attribute name="encoding"/>
+ </optional>
+ <empty/>
+ </element>
+ </define>
+
+ <define name="xincludefilter">
+ <element name="xincludefilter">
+ <optional>
+ <attribute name="basedir"/>
+ </optional>
+ </element>
+ </define>
+
+ <define name="xsltfilter">
+ <element name="xsltfilter">
+ <interleave>
+ <attribute name="style"/>
+ <optional>
+ <attribute name="html"/>
+ </optional>
+ <zeroOrMore>
+ <ref name="param"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+
+ <!--
+ ================================================================
+ Custom tasks/filters
+ ================================================================
+ -->
+
+ <define name="highlightsrc">
+ <element name="highlightsrc">
+ <interleave>
+ <optional>
+ <attribute name="linenumber">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="file"/>
+ </optional>
+ </interleave>
+ <interleave>
+ <zeroOrMore>
+ <choice>
+ <ref name="fileset"/>
+ <ref name="filterchain"/>
+ </choice>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+
+</grammar>
diff --git a/buildscripts/phing/etc/phpunit-frames.xsl b/buildscripts/phing/etc/phpunit-frames.xsl
new file mode 100755
index 00000000..a3147eb9
--- /dev/null
+++ b/buildscripts/phing/etc/phpunit-frames.xsl
@@ -0,0 +1,694 @@
+<?xml version="1.0"?>
+<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/PHPUnit 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.rook@gmail.com"/>
+ @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:param name="output.sorttable" 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 omit-xml-declaration="yes" 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:if test="$output.sorttable = 1">
+.sortable th {
+ cursor: pointer;
+}
+</xsl:if>
+</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: Class <xsl:value-of select="$class.name"/></title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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 sortable" 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 | ./testsuite/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 = ''">&lt;none&gt;</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 = ''">&lt;none&gt;</xsl:if>
+ </a>
+ </td>
+ </tr>
+</xsl:template>
+
+
+<xsl:template match="testsuites" mode="overview.packages">
+ <html>
+ <head>
+ <title>Unit Test Results: Summary</title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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 &gt; 0">Error</xsl:when>
+ <xsl:when test="$failureCount &gt; 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 sortable" 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) &gt; 0">Error</xsl:when>
+ <xsl:when test="sum($insamepackage/@failures) &gt; 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 = ''">&lt;none&gt;</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>
+ <title>Unit Test Results: Package <xsl:value-of select="$name"/></title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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) &gt; 0">
+ <h2>Classes</h2>
+ <p>
+ <table class="details sortable" 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://www.phpunit.de'>PHPUnit</a> and <a href='http://www.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[.&gt; 0]">Error</xsl:when>
+ <xsl:when test="@failures[.&gt; 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:param name="word"/>
+ <xsl:choose>
+ <xsl:when test="contains($word,'&#x0A;')">
+ <xsl:value-of select="substring-before($word,'&#x0A;')"/>
+ <br />
+ <xsl:call-template name="br-replace">
+ <xsl:with-param name="word" select="substring-after($word,'&#x0A;')"/>
+ </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/phpunit-noframes.xsl b/buildscripts/phing/etc/phpunit-noframes.xsl
new file mode 100755
index 00000000..d71e58d9
--- /dev/null
+++ b/buildscripts/phing/etc/phpunit-noframes.xsl
@@ -0,0 +1,448 @@
+<?xml version="1.0"?>
+<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/PHPUnit 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.rook@gmail.com"/>
+ @author Stephane Bailliez <a href="mailto:sbailliez@apache.org"/>
+ @author Erik Hatcher <a href="mailto:ehatcher@apache.org"/>
+
+-->
+<xsl:param name="output.sorttable" select="'.'"/>
+
+<xsl:template match="testsuites">
+ <html>
+ <head>
+ <title>Unit Test Results</title>
+ <xsl:if test="$output.sorttable = 1">
+ <script language="JavaScript" src="http://www.phing.info/support/sorttable.js"/>
+ </xsl:if>
+ <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;
+ }
+ <xsl:if test="$output.sorttable = 1">
+ .sortable th {
+ cursor: pointer;
+ }
+ </xsl:if>
+ </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 sortable" 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 &gt; 0">Failure</xsl:when>
+ <xsl:when test="$errorCount &gt; 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 sortable" 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 sortable" 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 | ./testsuite/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 &gt; 0">Failure</xsl:when>
+ <xsl:when test="$errorCount &gt; 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://www.phpunit.de'>PHPUnit</a> and <a href='http://www.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[.&gt; 0]">Failure</xsl:when>
+ <xsl:when test="@errors[.&gt; 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:param name="word"/>
+ <xsl:choose>
+ <xsl:when test="contains($word,'&#x0A;')">
+ <xsl:value-of select="substring-before($word,'&#x0A;')"/>
+ <br />
+ <xsl:call-template name="br-replace">
+ <xsl:with-param name="word" select="substring-after($word,'&#x0A;')"/>
+ </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 100755
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