From edf2251aca60a970e822079d23933e5b70b26571 Mon Sep 17 00:00:00 2001 From: ctrlaltca <> Date: Wed, 2 Jan 2013 14:42:24 +0000 Subject: backported all related changes up to 3229 to branch/3.2 --- buildscripts/phing/classes/phing/BuildEvent.php | 117 +- .../phing/classes/phing/BuildException.php | 42 +- buildscripts/phing/classes/phing/BuildListener.php | 40 +- buildscripts/phing/classes/phing/BuildLogger.php | 70 + .../phing/classes/phing/ConfigurationException.php | 85 + .../phing/classes/phing/IntrospectionHelper.php | 95 +- buildscripts/phing/classes/phing/Phing.php | 1155 ++++--- buildscripts/phing/classes/phing/Project.php | 310 +- .../phing/classes/phing/ProjectComponent.php | 32 +- .../phing/classes/phing/RuntimeConfigurable.php | 6 +- buildscripts/phing/classes/phing/Target.php | 208 +- buildscripts/phing/classes/phing/Task.php | 160 +- buildscripts/phing/classes/phing/TaskAdapter.php | 11 +- buildscripts/phing/classes/phing/TaskContainer.php | 10 +- .../phing/classes/phing/UnknownElement.php | 14 +- .../phing/contrib/DocBlox/Parallel/Manager.php | 304 ++ .../phing/contrib/DocBlox/Parallel/README.md | 106 + .../phing/contrib/DocBlox/Parallel/Worker.php | 203 ++ .../phing/contrib/DocBlox/Parallel/WorkerPipe.php | 127 + .../phing/contrib/DocBlox/Parallel/example.php | 57 + .../classes/phing/filters/BaseFilterReader.php | 8 +- .../phing/filters/BaseParamFilterReader.php | 8 +- .../classes/phing/filters/ChainableReader.php | 5 +- .../classes/phing/filters/ExpandProperties.php | 25 +- .../phing/classes/phing/filters/HeadFilter.php | 6 +- .../phing/classes/phing/filters/IconvFilter.php | 155 + .../phing/classes/phing/filters/LineContains.php | 12 +- .../classes/phing/filters/LineContainsRegexp.php | 6 +- .../phing/classes/phing/filters/PrefixLines.php | 6 +- .../phing/classes/phing/filters/ReplaceRegexp.php | 10 +- .../phing/classes/phing/filters/ReplaceTokens.php | 34 +- .../phing/filters/ReplaceTokensWithFile.php | 361 ++ .../classes/phing/filters/StripLineBreaks.php | 6 +- .../classes/phing/filters/StripLineComments.php | 14 +- .../classes/phing/filters/StripPhpComments.php | 8 +- .../classes/phing/filters/StripWhitespace.php | 95 + .../phing/classes/phing/filters/TabToSpaces.php | 6 +- .../phing/classes/phing/filters/TailFilter.php | 8 +- .../phing/classes/phing/filters/TidyFilter.php | 154 +- .../classes/phing/filters/TranslateGettext.php | 14 +- .../phing/classes/phing/filters/XincludeFilter.php | 176 + .../phing/classes/phing/filters/XsltFilter.php | 111 +- .../phing/filters/util/ChainReaderHelper.php | 5 +- .../phing/filters/util/IniFileTokenReader.php | 7 +- .../classes/phing/input/DefaultInputHandler.php | 15 +- .../phing/classes/phing/input/InputHandler.php | 4 +- .../phing/classes/phing/input/InputRequest.php | 4 +- .../phing/input/MultipleChoiceInputRequest.php | 4 +- .../phing/input/PropertyFileInputHandler.php | 129 - .../classes/phing/input/YesNoInputRequest.php | 4 +- buildscripts/phing/classes/phing/lib/Capsule.php | 3 +- buildscripts/phing/classes/phing/lib/Zip.php | 3588 -------------------- .../classes/phing/listener/AnsiColorLogger.php | 49 +- .../phing/classes/phing/listener/BuildLogger.php | 42 - .../phing/classes/phing/listener/DefaultLogger.php | 150 +- .../classes/phing/listener/HtmlColorLogger.php | 175 + .../phing/classes/phing/listener/MailLogger.php | 105 + .../classes/phing/listener/NoBannerLogger.php | 22 +- .../classes/phing/listener/PearLogListener.php | 197 ++ .../phing/classes/phing/listener/PearLogger.php | 246 -- .../phing/listener/StreamRequiredBuildLogger.php | 39 + .../phing/classes/phing/listener/XmlLogger.php | 617 ++-- .../classes/phing/listener/defaults.properties | 10 +- .../phing/classes/phing/mappers/FileNameMapper.php | 4 +- .../phing/classes/phing/mappers/FlattenMapper.php | 4 +- .../phing/classes/phing/mappers/GlobMapper.php | 4 +- .../phing/classes/phing/mappers/IdentityMapper.php | 4 +- .../phing/classes/phing/mappers/MergeMapper.php | 20 +- .../phing/classes/phing/mappers/RegexpMapper.php | 4 +- .../phing/classes/phing/parser/AbstractHandler.php | 6 +- .../classes/phing/parser/AbstractSAXParser.php | 44 +- .../phing/classes/phing/parser/DataTypeHandler.php | 8 +- .../classes/phing/parser/ExpatParseException.php | 4 +- .../phing/classes/phing/parser/ExpatParser.php | 8 +- .../phing/classes/phing/parser/Location.php | 12 +- .../classes/phing/parser/NestedElementHandler.php | 22 +- .../phing/classes/phing/parser/PhingXMLContext.php | 81 + .../classes/phing/parser/ProjectConfigurator.php | 207 +- .../phing/classes/phing/parser/ProjectHandler.php | 84 +- .../phing/classes/phing/parser/RootHandler.php | 6 +- .../phing/classes/phing/parser/TargetHandler.php | 63 +- .../phing/classes/phing/parser/TaskHandler.php | 81 +- .../classes/phing/system/io/BufferedReader.php | 62 +- .../classes/phing/system/io/BufferedWriter.php | 31 +- .../classes/phing/system/io/ConsoleReader.php | 10 +- .../classes/phing/system/io/FileInputStream.php | 79 + .../classes/phing/system/io/FileOutputStream.php | 71 + .../phing/classes/phing/system/io/FileReader.php | 164 +- .../phing/classes/phing/system/io/FileSystem.php | 283 +- .../phing/classes/phing/system/io/FileWriter.php | 117 +- .../phing/classes/phing/system/io/FilterReader.php | 20 +- .../phing/classes/phing/system/io/IOException.php | 3 +- .../phing/classes/phing/system/io/InputStream.php | 178 + .../classes/phing/system/io/InputStreamReader.php | 127 + .../phing/classes/phing/system/io/OutputStream.php | 108 + .../classes/phing/system/io/OutputStreamWriter.php | 84 + .../phing/classes/phing/system/io/PhingFile.php | 350 +- .../phing/classes/phing/system/io/Reader.php | 23 +- .../phing/classes/phing/system/io/StringReader.php | 19 +- .../phing/classes/phing/system/io/TokenReader.php | 51 - .../classes/phing/system/io/UnixFileSystem.php | 62 +- .../classes/phing/system/io/Win32FileSystem.php | 10 +- .../classes/phing/system/io/WinNTFileSystem.php | 7 +- .../phing/classes/phing/system/io/Writer.php | 35 +- .../phing/classes/phing/system/lang/Character.php | 6 +- .../classes/phing/system/lang/EventObject.php | 4 +- .../phing/system/lang/FileNotFoundException.php | 3 +- .../phing/system/lang/NullPointerException.php | 3 +- .../phing/system/lang/SecurityException.php | 3 +- .../phing/classes/phing/system/util/Message.php | 9 - .../phing/classes/phing/system/util/Properties.php | 84 +- .../phing/classes/phing/system/util/Register.php | 38 +- .../phing/classes/phing/system/util/Timer.php | 4 +- .../phing/classes/phing/tasks/defaults.properties | 92 +- .../phing/classes/phing/tasks/ext/CapsuleTask.php | 18 +- .../classes/phing/tasks/ext/CreoleSQLExecTask.php | 556 --- .../phing/classes/phing/tasks/ext/CreoleTask.php | 242 -- .../phing/tasks/ext/ExportPropertiesTask.php | 141 + .../classes/phing/tasks/ext/ExtractBaseTask.php | 199 ++ .../phing/classes/phing/tasks/ext/FileHashTask.php | 147 + .../phing/classes/phing/tasks/ext/FileSizeTask.php | 120 + .../classes/phing/tasks/ext/FtpDeployTask.php | 233 ++ .../phing/classes/phing/tasks/ext/HttpGetTask.php | 170 + .../classes/phing/tasks/ext/HttpRequestTask.php | 286 ++ .../phing/classes/phing/tasks/ext/JslLintTask.php | 284 ++ .../phing/classes/phing/tasks/ext/MailTask.php | 144 +- .../phing/classes/phing/tasks/ext/ManifestTask.php | 343 ++ .../classes/phing/tasks/ext/PackageAsPathTask.php | 4 +- .../phing/classes/phing/tasks/ext/ParallelTask.php | 83 + .../phing/classes/phing/tasks/ext/PatchTask.php | 301 ++ .../classes/phing/tasks/ext/PearPackage2Task.php | 279 ++ .../classes/phing/tasks/ext/PearPackageTask.php | 115 +- .../classes/phing/tasks/ext/PhpCodeSnifferTask.php | 648 ++++ .../phing/classes/phing/tasks/ext/PhpLintTask.php | 326 +- .../classes/phing/tasks/ext/ReplaceRegexpTask.php | 204 ++ .../phing/classes/phing/tasks/ext/ScpTask.php | 380 +++ .../classes/phing/tasks/ext/Service/Amazon.php | 120 + .../classes/phing/tasks/ext/Service/Amazon/S3.php | 188 + .../tasks/ext/Service/Amazon/S3/S3GetTask.php | 108 + .../tasks/ext/Service/Amazon/S3/S3PutTask.php | 243 ++ .../phing/classes/phing/tasks/ext/SmartyTask.php | 10 +- .../phing/classes/phing/tasks/ext/SshTask.php | 224 ++ .../classes/phing/tasks/ext/SymfonyConsole/Arg.php | 96 + .../ext/SymfonyConsole/SymfonyConsoleTask.php | 113 + .../phing/classes/phing/tasks/ext/SymlinkTask.php | 309 ++ .../phing/classes/phing/tasks/ext/TarTask.php | 139 +- .../phing/classes/phing/tasks/ext/UntarTask.php | 89 + .../phing/classes/phing/tasks/ext/UnzipTask.php | 77 + .../phing/classes/phing/tasks/ext/VersionTask.php | 217 ++ .../phing/classes/phing/tasks/ext/XmlLintTask.php | 113 +- .../classes/phing/tasks/ext/XmlPropertyTask.php | 273 ++ .../phing/tasks/ext/ZendCodeAnalyzerTask.php | 272 +- .../phing/classes/phing/tasks/ext/ZipTask.php | 193 +- .../classes/phing/tasks/ext/apigen/ApiGenTask.php | 439 +++ .../phing/tasks/ext/coverage/CoverageMerger.php | 221 +- .../tasks/ext/coverage/CoverageMergerTask.php | 102 +- .../tasks/ext/coverage/CoverageReportTask.php | 894 +++-- .../ext/coverage/CoverageReportTransformer.php | 219 +- .../phing/tasks/ext/coverage/CoverageSetupTask.php | 257 +- .../tasks/ext/coverage/CoverageThresholdTask.php | 458 +++ .../phing/tasks/ext/creole/CreoleSQLExecTask.php | 592 ++++ .../classes/phing/tasks/ext/creole/CreoleTask.php | 242 ++ .../phing/tasks/ext/dbdeploy/DbDeployTask.php | 436 +++ .../phing/tasks/ext/dbdeploy/DbmsSyntax.php | 34 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php | 67 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php | 37 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php | 37 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php | 37 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php | 36 + .../phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php | 37 + .../phing/tasks/ext/docblox/DocBloxTask.php | 221 ++ .../classes/phing/tasks/ext/git/GitBaseTask.php | 134 + .../classes/phing/tasks/ext/git/GitBranchTask.php | 296 ++ .../phing/tasks/ext/git/GitCheckoutTask.php | 256 ++ .../classes/phing/tasks/ext/git/GitCloneTask.php | 128 + .../classes/phing/tasks/ext/git/GitCommitTask.php | 179 + .../classes/phing/tasks/ext/git/GitFetchTask.php | 284 ++ .../classes/phing/tasks/ext/git/GitGcTask.php | 158 + .../classes/phing/tasks/ext/git/GitInitTask.php | 81 + .../classes/phing/tasks/ext/git/GitLogTask.php | 270 ++ .../classes/phing/tasks/ext/git/GitMergeTask.php | 258 ++ .../classes/phing/tasks/ext/git/GitPullTask.php | 373 ++ .../classes/phing/tasks/ext/git/GitPushTask.php | 255 ++ .../classes/phing/tasks/ext/git/GitTagTask.php | 406 +++ .../phing/tasks/ext/ioncube/IoncubeComment.php | 29 +- .../phing/tasks/ext/ioncube/IoncubeEncoderTask.php | 908 +++-- .../phing/tasks/ext/ioncube/IoncubeLicenseTask.php | 262 +- .../phing/classes/phing/tasks/ext/jsmin/JsMin.php | 292 ++ .../classes/phing/tasks/ext/jsmin/JsMinTask.php | 145 + .../tasks/ext/liquibase/AbstractLiquibaseTask.php | 184 + .../tasks/ext/liquibase/LiquibaseChangeLogTask.php | 39 + .../tasks/ext/liquibase/LiquibaseDbDocTask.php | 86 + .../tasks/ext/liquibase/LiquibaseDiffTask.php | 137 + .../tasks/ext/liquibase/LiquibaseRollbackTask.php | 72 + .../phing/tasks/ext/liquibase/LiquibaseTagTask.php | 75 + .../tasks/ext/liquibase/LiquibaseUpdateTask.php | 39 + .../tasks/ext/pdepend/PhpDependAnalyzerElement.php | 109 + .../tasks/ext/pdepend/PhpDependLoggerElement.php | 105 + .../phing/tasks/ext/pdepend/PhpDependTask.php | 506 +++ .../tasks/ext/pdo/DefaultPDOQuerySplitter.php | 151 + .../phing/tasks/ext/pdo/PDOQuerySplitter.php | 63 + .../phing/tasks/ext/pdo/PDOResultFormatter.php | 84 + .../tasks/ext/pdo/PDOSQLExecFormatterElement.php | 313 ++ .../classes/phing/tasks/ext/pdo/PDOSQLExecTask.php | 606 ++++ .../phing/classes/phing/tasks/ext/pdo/PDOTask.php | 215 ++ .../phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php | 291 ++ .../tasks/ext/pdo/PlainPDOResultFormatter.php | 130 + .../phing/tasks/ext/pdo/XMLPDOResultFormatter.php | 141 + .../phing/tasks/ext/pearpackage/Fileset.php | 21 +- .../classes/phing/tasks/ext/phar/PharMetadata.php | 55 + .../phing/tasks/ext/phar/PharMetadataElement.php | 80 + .../phing/tasks/ext/phar/PharPackageTask.php | 362 ++ .../classes/phing/tasks/ext/phk/PhkPackageTask.php | 248 ++ .../phing/tasks/ext/phk/PhkPackageWebAccess.php | 57 + .../tasks/ext/phk/PhkPackageWebAccessPath.php | 46 + .../tasks/ext/phpcpd/PHPCPDFormatterElement.php | 177 + .../classes/phing/tasks/ext/phpcpd/PHPCPDTask.php | 312 ++ .../formatter/DefaultPHPCPDResultFormatter.php | 58 + .../ext/phpcpd/formatter/PHPCPDResultFormatter.php | 40 + .../phpcpd/formatter/PMDPHPCPDResultFormatter.php | 51 + .../phing/tasks/ext/phpdoc/PHPDocumentorTask.php | 157 - .../ext/phpdoc/PhingPhpDocumentorErrorTracker.php | 98 + .../tasks/ext/phpdoc/PhingPhpDocumentorSetup.php | 230 ++ .../phing/tasks/ext/phpdoc/PhpDocumentor2Task.php | 224 ++ .../tasks/ext/phpdoc/PhpDocumentorExternalTask.php | 265 ++ .../phing/tasks/ext/phpdoc/PhpDocumentorTask.php | 480 +++ .../tasks/ext/phpmd/PHPMDFormatterElement.php | 181 + .../classes/phing/tasks/ext/phpmd/PHPMDTask.php | 284 ++ .../classes/phing/tasks/ext/phpunit/BatchTest.php | 230 ++ .../phing/tasks/ext/phpunit/FormatterElement.php | 178 + .../phing/tasks/ext/phpunit/PHPUnitReportTask.php | 248 ++ .../phing/tasks/ext/phpunit/PHPUnitTask.php | 378 +++ .../phing/tasks/ext/phpunit/PHPUnitTestRunner.php | 312 ++ .../phing/tasks/ext/phpunit/PHPUnitUtil.php | 141 + .../formatter/CloverPHPUnitResultFormatter.php | 87 + .../phpunit/formatter/PHPUnitResultFormatter.php | 203 ++ .../formatter/PlainPHPUnitResultFormatter.php | 128 + .../formatter/SummaryPHPUnitResultFormatter.php | 62 + .../formatter/XMLPHPUnitResultFormatter.php | 120 + .../classes/phing/tasks/ext/phpunit2/BatchTest.php | 171 - .../phing/tasks/ext/phpunit2/FormatterElement.php | 120 - .../tasks/ext/phpunit2/PHPUnit2ReportTask.php | 162 - .../tasks/ext/phpunit2/PHPUnit2ResultFormatter.php | 154 - .../phing/tasks/ext/phpunit2/PHPUnit2Task.php | 239 -- .../tasks/ext/phpunit2/PHPUnit2TestRunner.php | 107 - .../phing/tasks/ext/phpunit2/PHPUnit2Util.php | 114 - .../ext/phpunit2/PlainPHPUnit2ResultFormatter.php | 117 - .../phpunit2/SummaryPHPUnit2ResultFormatter.php | 58 - .../ext/phpunit2/XMLPHPUnit2ResultFormatter.php | 117 - .../phing/classes/phing/tasks/ext/rSTTask.php | 476 +++ .../simpletest/SimpleTestCountResultFormatter.php | 41 +- .../simpletest/SimpleTestDebugResultFormatter.php | 119 + .../ext/simpletest/SimpleTestFormatterElement.php | 134 +- .../simpletest/SimpleTestPlainResultFormatter.php | 118 +- .../ext/simpletest/SimpleTestResultFormatter.php | 261 +- .../SimpleTestSummaryResultFormatter.php | 43 +- .../phing/tasks/ext/simpletest/SimpleTestTask.php | 430 +-- .../simpletest/SimpleTestXmlResultFormatter.php | 244 +- .../classes/phing/tasks/ext/svn/SvnBaseTask.php | 455 ++- .../phing/tasks/ext/svn/SvnCheckoutTask.php | 67 + .../classes/phing/tasks/ext/svn/SvnCommitTask.php | 113 + .../classes/phing/tasks/ext/svn/SvnCopyTask.php | 70 + .../classes/phing/tasks/ext/svn/SvnExportTask.php | 70 +- .../classes/phing/tasks/ext/svn/SvnInfoTask.php | 112 + .../phing/tasks/ext/svn/SvnLastRevisionTask.php | 123 +- .../classes/phing/tasks/ext/svn/SvnListTask.php | 128 + .../classes/phing/tasks/ext/svn/SvnLogTask.php | 108 + .../classes/phing/tasks/ext/svn/SvnSwitchTask.php | 73 + .../classes/phing/tasks/ext/svn/SvnUpdateTask.php | 67 + .../tasks/ext/zendguard/ZendGuardEncodeTask.php | 510 +++ .../tasks/ext/zendguard/ZendGuardLicenseTask.php | 524 +++ .../phing/classes/phing/tasks/system/AdhocTask.php | 8 +- .../phing/tasks/system/AdhocTaskdefTask.php | 53 +- .../phing/tasks/system/AdhocTypedefTask.php | 6 +- .../classes/phing/tasks/system/AppendTask.php | 16 +- .../classes/phing/tasks/system/AvailableTask.php | 76 +- .../phing/classes/phing/tasks/system/ChmodTask.php | 104 +- .../phing/classes/phing/tasks/system/ChownTask.php | 216 ++ .../classes/phing/tasks/system/ConditionTask.php | 6 +- .../phing/classes/phing/tasks/system/CopyTask.php | 207 +- .../classes/phing/tasks/system/CvsPassTask.php | 14 +- .../phing/classes/phing/tasks/system/CvsTask.php | 24 +- .../classes/phing/tasks/system/DeleteTask.php | 75 +- .../phing/classes/phing/tasks/system/EchoTask.php | 123 +- .../phing/classes/phing/tasks/system/ExecTask.php | 476 ++- .../phing/classes/phing/tasks/system/ExitTask.php | 118 - .../phing/classes/phing/tasks/system/FailTask.php | 118 + .../classes/phing/tasks/system/ForeachTask.php | 212 +- .../phing/classes/phing/tasks/system/IfTask.php | 45 +- .../classes/phing/tasks/system/ImportTask.php | 136 + .../classes/phing/tasks/system/IncludePathTask.php | 6 +- .../phing/classes/phing/tasks/system/InputTask.php | 8 +- .../classes/phing/tasks/system/LoadFileTask.php | 119 + .../classes/phing/tasks/system/MatchingTask.php | 6 +- .../phing/classes/phing/tasks/system/MkdirTask.php | 21 +- .../phing/classes/phing/tasks/system/MoveTask.php | 119 +- .../classes/phing/tasks/system/PhingCallTask.php | 106 +- .../phing/classes/phing/tasks/system/PhingTask.php | 155 +- .../classes/phing/tasks/system/PhpEvalTask.php | 57 +- .../phing/tasks/system/PropertyPromptTask.php | 79 +- .../classes/phing/tasks/system/PropertyTask.php | 40 +- .../classes/phing/tasks/system/ReflexiveTask.php | 30 +- .../classes/phing/tasks/system/ResolvePathTask.php | 49 +- .../classes/phing/tasks/system/SequentialTask.php | 11 +- .../classes/phing/tasks/system/TaskdefTask.php | 50 +- .../phing/classes/phing/tasks/system/TouchTask.php | 6 +- .../classes/phing/tasks/system/TryCatchTask.php | 123 + .../classes/phing/tasks/system/TstampTask.php | 217 +- .../classes/phing/tasks/system/TypedefTask.php | 8 +- .../classes/phing/tasks/system/UpToDateTask.php | 60 +- .../classes/phing/tasks/system/WaitForTask.php | 188 + .../phing/classes/phing/tasks/system/WarnTask.php | 8 +- .../phing/classes/phing/tasks/system/XsltTask.php | 28 +- .../phing/tasks/system/condition/AndCondition.php | 6 +- .../phing/tasks/system/condition/Condition.php | 5 +- .../phing/tasks/system/condition/ConditionBase.php | 10 +- .../tasks/system/condition/ContainsCondition.php | 6 +- .../tasks/system/condition/EqualsCondition.php | 6 +- .../tasks/system/condition/IsFalseCondition.php | 4 +- .../tasks/system/condition/IsSetCondition.php | 4 +- .../tasks/system/condition/IsTrueCondition.php | 2 +- .../phing/tasks/system/condition/NotCondition.php | 6 +- .../phing/tasks/system/condition/OrCondition.php | 4 +- .../phing/tasks/system/condition/OsCondition.php | 22 +- .../system/condition/ReferenceExistsCondition.php | 4 +- .../phing/classes/phing/types/AbstractFileSet.php | 29 +- .../phing/classes/phing/types/Commandline.php | 32 +- .../phing/classes/phing/types/DataType.php | 8 +- .../phing/classes/phing/types/Description.php | 2 +- buildscripts/phing/classes/phing/types/DirSet.php | 2 +- .../phing/classes/phing/types/Excludes.php | 208 ++ .../classes/phing/types/ExcludesNameEntry.php | 81 + .../phing/classes/phing/types/FileList.php | 7 +- buildscripts/phing/classes/phing/types/FileSet.php | 2 +- .../phing/classes/phing/types/FilterChain.php | 79 +- .../phing/classes/phing/types/IterableFileSet.php | 56 + buildscripts/phing/classes/phing/types/Mapper.php | 6 +- .../phing/classes/phing/types/Parameter.php | 14 +- .../phing/classes/phing/types/Parameterizable.php | 2 +- buildscripts/phing/classes/phing/types/Path.php | 84 +- .../phing/classes/phing/types/PatternSet.php | 162 +- .../classes/phing/types/PearPackageFileSet.php | 179 + .../classes/phing/types/PhingFilterReader.php | 20 +- .../phing/classes/phing/types/Reference.php | 4 +- .../classes/phing/types/RegularExpression.php | 33 +- .../phing/classes/phing/types/TokenReader.php | 6 +- .../phing/classes/phing/types/TokenSource.php | 8 +- .../classes/phing/types/selectors/AndSelector.php | 2 +- .../phing/types/selectors/BaseExtendSelector.php | 2 +- .../classes/phing/types/selectors/BaseSelector.php | 2 +- .../types/selectors/BaseSelectorContainer.php | 2 +- .../types/selectors/ContainsRegexpSelector.php | 4 +- .../phing/types/selectors/ContainsSelector.php | 2 +- .../classes/phing/types/selectors/DateSelector.php | 8 +- .../phing/types/selectors/DependSelector.php | 4 +- .../phing/types/selectors/DepthSelector.php | 4 +- .../phing/types/selectors/ExtendFileSelector.php | 2 +- .../phing/types/selectors/ExtendSelector.php | 15 +- .../classes/phing/types/selectors/FileSelector.php | 2 +- .../phing/types/selectors/FilenameSelector.php | 2 +- .../phing/types/selectors/MajoritySelector.php | 2 +- .../classes/phing/types/selectors/NoneSelector.php | 2 +- .../classes/phing/types/selectors/NotSelector.php | 2 +- .../classes/phing/types/selectors/OrSelector.php | 2 +- .../phing/types/selectors/PresentSelector.php | 6 +- .../phing/types/selectors/SelectSelector.php | 4 +- .../phing/types/selectors/SelectorContainer.php | 2 +- .../phing/types/selectors/SelectorScanner.php | 2 +- .../phing/types/selectors/SelectorUtils.php | 288 +- .../classes/phing/types/selectors/SizeSelector.php | 2 +- .../classes/phing/types/selectors/TypeSelector.php | 25 +- .../phing/classes/phing/util/DataStore.php | 151 + .../phing/classes/phing/util/DirectoryScanner.php | 63 +- .../classes/phing/util/ExtendedFileStream.php | 252 +- .../phing/classes/phing/util/FileUtils.php | 16 +- .../phing/classes/phing/util/LogWriter.php | 181 +- .../phing/classes/phing/util/PathTokenizer.php | 4 +- .../classes/phing/util/PearPackageScanner.php | 170 + .../phing/classes/phing/util/SourceFileScanner.php | 16 +- .../phing/classes/phing/util/StringHelper.php | 7 +- .../phing/classes/phing/util/regexp/PregEngine.php | 74 +- .../phing/classes/phing/util/regexp/Regexp.php | 45 +- .../classes/phing/util/regexp/RegexpEngine.php | 7 +- 383 files changed, 37583 insertions(+), 12613 deletions(-) mode change 100644 => 100755 buildscripts/phing/classes/phing/BuildEvent.php mode change 100644 => 100755 buildscripts/phing/classes/phing/BuildException.php mode change 100644 => 100755 buildscripts/phing/classes/phing/BuildListener.php create mode 100755 buildscripts/phing/classes/phing/BuildLogger.php create mode 100755 buildscripts/phing/classes/phing/ConfigurationException.php mode change 100644 => 100755 buildscripts/phing/classes/phing/IntrospectionHelper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/Phing.php mode change 100644 => 100755 buildscripts/phing/classes/phing/Project.php mode change 100644 => 100755 buildscripts/phing/classes/phing/ProjectComponent.php mode change 100644 => 100755 buildscripts/phing/classes/phing/RuntimeConfigurable.php mode change 100644 => 100755 buildscripts/phing/classes/phing/Target.php mode change 100644 => 100755 buildscripts/phing/classes/phing/Task.php mode change 100644 => 100755 buildscripts/phing/classes/phing/TaskAdapter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/TaskContainer.php mode change 100644 => 100755 buildscripts/phing/classes/phing/UnknownElement.php create mode 100644 buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Manager.php create mode 100644 buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/README.md create mode 100644 buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/Worker.php create mode 100644 buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/WorkerPipe.php create mode 100644 buildscripts/phing/classes/phing/contrib/DocBlox/Parallel/example.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/BaseFilterReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/ExpandProperties.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/HeadFilter.php create mode 100755 buildscripts/phing/classes/phing/filters/IconvFilter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/LineContains.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/LineContainsRegexp.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/PrefixLines.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/ReplaceRegexp.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/ReplaceTokens.php create mode 100644 buildscripts/phing/classes/phing/filters/ReplaceTokensWithFile.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/StripLineBreaks.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/StripLineComments.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/StripPhpComments.php create mode 100755 buildscripts/phing/classes/phing/filters/StripWhitespace.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/TabToSpaces.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/TailFilter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/TidyFilter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/TranslateGettext.php create mode 100644 buildscripts/phing/classes/phing/filters/XincludeFilter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/input/DefaultInputHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/input/InputHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/input/InputRequest.php mode change 100644 => 100755 buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php delete mode 100644 buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/input/YesNoInputRequest.php mode change 100644 => 100755 buildscripts/phing/classes/phing/lib/Capsule.php delete mode 100644 buildscripts/phing/classes/phing/lib/Zip.php mode change 100644 => 100755 buildscripts/phing/classes/phing/listener/AnsiColorLogger.php delete mode 100644 buildscripts/phing/classes/phing/listener/BuildLogger.php mode change 100644 => 100755 buildscripts/phing/classes/phing/listener/DefaultLogger.php create mode 100755 buildscripts/phing/classes/phing/listener/HtmlColorLogger.php create mode 100755 buildscripts/phing/classes/phing/listener/MailLogger.php mode change 100644 => 100755 buildscripts/phing/classes/phing/listener/NoBannerLogger.php create mode 100755 buildscripts/phing/classes/phing/listener/PearLogListener.php delete mode 100644 buildscripts/phing/classes/phing/listener/PearLogger.php create mode 100755 buildscripts/phing/classes/phing/listener/StreamRequiredBuildLogger.php mode change 100644 => 100755 buildscripts/phing/classes/phing/listener/XmlLogger.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/FileNameMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/FlattenMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/GlobMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/IdentityMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/MergeMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/mappers/RegexpMapper.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/AbstractHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/AbstractSAXParser.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/DataTypeHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/ExpatParseException.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/ExpatParser.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/Location.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/NestedElementHandler.php create mode 100755 buildscripts/phing/classes/phing/parser/PhingXMLContext.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/ProjectConfigurator.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/ProjectHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/RootHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/TargetHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/parser/TaskHandler.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/BufferedReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/BufferedWriter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/ConsoleReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/FileInputStream.php create mode 100644 buildscripts/phing/classes/phing/system/io/FileOutputStream.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/FileSystem.php create mode 100644 buildscripts/phing/classes/phing/system/io/InputStream.php create mode 100644 buildscripts/phing/classes/phing/system/io/InputStreamReader.php create mode 100644 buildscripts/phing/classes/phing/system/io/OutputStream.php create mode 100644 buildscripts/phing/classes/phing/system/io/OutputStreamWriter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/PhingFile.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/Reader.php delete mode 100644 buildscripts/phing/classes/phing/system/io/TokenReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/io/UnixFileSystem.php delete mode 100644 buildscripts/phing/classes/phing/system/util/Message.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/util/Properties.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/util/Register.php mode change 100644 => 100755 buildscripts/phing/classes/phing/system/util/Timer.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/defaults.properties delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ExportPropertiesTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ExtractBaseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/FileHashTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/FileSizeTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/FtpDeployTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/HttpGetTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/HttpRequestTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/JslLintTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/MailTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ManifestTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/ParallelTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/PatchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/PearPackage2Task.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/PhpCodeSnifferTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ReplaceRegexpTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/ScpTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/Service/Amazon.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3GetTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/Service/Amazon/S3/S3PutTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/SshTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/Arg.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/SymfonyConsole/SymfonyConsoleTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/SymlinkTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/UntarTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/UnzipTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/VersionTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/XmlPropertyTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/ZipTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/apigen/ApiGenTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMerger.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageMergerTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageReportTransformer.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageSetupTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/coverage/CoverageThresholdTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/creole/CreoleSQLExecTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/creole/CreoleTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbDeployTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntax.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxFactory.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMsSql.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxMysql.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxOracle.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxPgSQL.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/dbdeploy/DbmsSyntaxSQLite.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/docblox/DocBloxTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitBaseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitBranchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitCheckoutTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitCloneTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitCommitTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitFetchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitGcTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitInitTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitLogTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitMergeTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitPullTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitPushTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/git/GitTagTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeComment.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeEncoderTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/ioncube/IoncubeLicenseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMin.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/jsmin/JsMinTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/AbstractLiquibaseTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseChangeLogTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDbDocTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseDiffTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseRollbackTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseTagTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/liquibase/LiquibaseUpdateTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependAnalyzerElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependLoggerElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdepend/PhpDependTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/pdo/DefaultPDOQuerySplitter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/pdo/PDOQuerySplitter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdo/PDOResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecFormatterElement.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/pdo/PDOSQLExecTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/pdo/PDOTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/pdo/PgsqlPDOQuerySplitter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdo/PlainPDOResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/pdo/XMLPDOResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/pearpackage/Fileset.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadata.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phar/PharMetadataElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phar/PharPackageTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccess.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phk/PhkPackageWebAccessPath.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDFormatterElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpcpd/PHPCPDTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/DefaultPHPCPDResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PHPCPDResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpcpd/formatter/PMDPHPCPDResultFormatter.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PHPDocumentorTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorErrorTracker.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhingPhpDocumentorSetup.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentor2Task.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorExternalTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpdoc/PhpDocumentorTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDFormatterElement.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpmd/PHPMDTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/BatchTest.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/FormatterElement.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitReportTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitTestRunner.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/PHPUnitUtil.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/CloverPHPUnitResultFormatter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PHPUnitResultFormatter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/PlainPHPUnitResultFormatter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/SummaryPHPUnitResultFormatter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/phpunit/formatter/XMLPHPUnitResultFormatter.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/BatchTest.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/FormatterElement.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ReportTask.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2ResultFormatter.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Task.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2TestRunner.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PHPUnit2Util.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/PlainPHPUnit2ResultFormatter.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/SummaryPHPUnit2ResultFormatter.php delete mode 100644 buildscripts/phing/classes/phing/tasks/ext/phpunit2/XMLPHPUnit2ResultFormatter.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/rSTTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestCountResultFormatter.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestDebugResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestFormatterElement.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestPlainResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestSummaryResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/simpletest/SimpleTestXmlResultFormatter.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/svn/SvnBaseTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnCheckoutTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnCommitTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnCopyTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/svn/SvnExportTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnInfoTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/ext/svn/SvnLastRevisionTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/svn/SvnListTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/ext/svn/SvnLogTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnSwitchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/svn/SvnUpdateTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardEncodeTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/ext/zendguard/ZendGuardLicenseTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/AdhocTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/AdhocTaskdefTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/AdhocTypedefTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/AppendTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/AvailableTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ChmodTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/system/ChownTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ConditionTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/CopyTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/CvsPassTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/CvsTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/DeleteTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/EchoTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ExecTask.php delete mode 100644 buildscripts/phing/classes/phing/tasks/system/ExitTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/system/FailTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ForeachTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/system/ImportTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/IncludePathTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/InputTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/LoadFileTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/MatchingTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/MkdirTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/MoveTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/PhingCallTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/PhingTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/PhpEvalTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/PropertyPromptTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/PropertyTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ReflexiveTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/ResolvePathTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/TaskdefTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/TouchTask.php create mode 100644 buildscripts/phing/classes/phing/tasks/system/TryCatchTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/TstampTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/TypedefTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/UpToDateTask.php create mode 100755 buildscripts/phing/classes/phing/tasks/system/WaitForTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/WarnTask.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/AndCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/Condition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/ConditionBase.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/ContainsCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/EqualsCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/IsFalseCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/IsSetCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/NotCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/OrCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/OsCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/tasks/system/condition/ReferenceExistsCondition.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/AbstractFileSet.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/Commandline.php create mode 100644 buildscripts/phing/classes/phing/types/Excludes.php create mode 100644 buildscripts/phing/classes/phing/types/ExcludesNameEntry.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/FileList.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/FilterChain.php create mode 100644 buildscripts/phing/classes/phing/types/IterableFileSet.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/PatternSet.php create mode 100644 buildscripts/phing/classes/phing/types/PearPackageFileSet.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/PhingFilterReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/RegularExpression.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/TokenReader.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/ContainsRegexpSelector.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/DateSelector.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/DependSelector.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/DepthSelector.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/SelectSelector.php mode change 100644 => 100755 buildscripts/phing/classes/phing/types/selectors/TypeSelector.php create mode 100755 buildscripts/phing/classes/phing/util/DataStore.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/DirectoryScanner.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/ExtendedFileStream.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/FileUtils.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/LogWriter.php create mode 100644 buildscripts/phing/classes/phing/util/PearPackageScanner.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/regexp/Regexp.php mode change 100644 => 100755 buildscripts/phing/classes/phing/util/regexp/RegexpEngine.php (limited to 'buildscripts/phing/classes') diff --git a/buildscripts/phing/classes/phing/BuildEvent.php b/buildscripts/phing/classes/phing/BuildEvent.php old mode 100644 new mode 100755 index d4e1ea79..581f7cf4 --- a/buildscripts/phing/classes/phing/BuildEvent.php +++ b/buildscripts/phing/classes/phing/BuildEvent.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.10 $ + * @version $Id$ * @package phing */ class BuildEvent extends EventObject { /** - * A reference to the project - * @var Project + * A reference to the project + * @var Project */ protected $project; /** - * A reference to the target - * @var Target + * A reference to the target + * @var Target */ protected $target; /** - * A reference to the task + * A reference to the task * - * @var Task + * @var Task */ protected $task; /** - * The message of this event, if the event is a message - * @var string - * @access private + * The message of this event, if the event is a message + * @var string */ protected $message = null; /** - * The priority of the message + * The priority of the message * - * @var string - * @see $message - * @access private + * @var string + * @see $message */ - protected $priority = PROJECT_MSG_VERBOSE; + protected $priority = Project::MSG_VERBOSE; /** - * The execption that caused the event, if any + * The execption that caused the event, if any * - * @var object - * @access private + * @var object */ protected $exception = null; /** - * Construct a BuildEvent for a project, task or target source event + * Construct a BuildEvent for a project, task or target source event * - * @param object project the project that emitted the event. - * @access public + * @param object project the project that emitted the event. */ - function __construct($source) { + public function __construct($source) { parent::__construct($source); if ($source instanceof Project) { $this->project = $source; @@ -111,95 +107,92 @@ class BuildEvent extends EventObject { } /** - * Sets the message with details and the message priority for this event. + * 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 + * @param string The string message of the event + * @param integer The priority this message should have */ - function setMessage($message, $priority) { + public function setMessage($message, $priority) { $this->message = (string) $message; $this->priority = (int) $priority; } /** - * Set the exception that was the cause of this event. + * Set the exception that was the cause of this event. * - * @param Exception The exception that caused the event + * @param Exception The exception that caused the event */ - function setException($exception) { + public function setException($exception) { $this->exception = $exception; } /** - * Returns the project instance that fired this event. + * 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. + * 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 + * @return Project The project instance that fired this event */ - function getProject() { + public function getProject() { return $this->project; } /** - * Returns the target instance that fired this event. + * 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. + * The reference to the target instance is set by the constructor if this + * event was fired from the target class. * - * @return object The target that fired this event - * @access public + * @return Target The target that fired this event */ - function getTarget() { + public function getTarget() { return $this->target; } /** - * Returns the target instance that fired this event. + * 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. + * The reference to the task instance is set by the constructor if this + * event was fired within a task. * - * @return object The task that fired this event - * @access public + * @return Task The task that fired this event */ - function getTask() { + public function getTask() { return $this->task; } /** - * Returns the logging message. This field will only be set for - * "messageLogged" events. + * Returns the logging message. This field will only be set for + * "messageLogged" events. * - * @return string The log message - * @access public + * @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. + * Returns the priority of the logging message. This field will only + * be set for "messageLogged" events. * - * @return integer The message priority - * @access public + * @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. + * 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() + * @see BuildListener::taskFinished() + * @see BuildListener::targetFinished() + * @see BuildListener::buildFinished() + * @return Exception */ - function getException() { + public function getException() { return $this->exception; } } diff --git a/buildscripts/phing/classes/phing/BuildException.php b/buildscripts/phing/classes/phing/BuildException.php old mode 100644 new mode 100755 index 8c108130..dda1a05a --- a/buildscripts/phing/classes/phing/BuildException.php +++ b/buildscripts/phing/classes/phing/BuildException.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.12 $ + * @version $Id$ * @package phing */ class BuildException extends Exception { - /** location in the xml file */ - protected $location = null; + /** + * Location in the xml file. + * @var Location + */ + protected $location; - /** The nested "cause" exception. */ + /** + * The nested "cause" exception. + * @var Exception + */ protected $cause; /** @@ -43,8 +49,11 @@ class BuildException extends Exception { * 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 */ - function __construct($p1, $p2 = null, $p3 = null) { + public function __construct($p1, $p2 = null, $p3 = null) { $cause = null; $loc = null; @@ -84,15 +93,30 @@ class BuildException extends Exception { } } - function getCause() { + /** + * Gets the cause exception. + * + * @return Exception + */ + public function getCause() { return $this->cause; } - function getLocation() { + /** + * Gets the location of error in XML file. + * + * @return Location + */ + public function getLocation() { return $this->location; } - function setLocation($loc) { + /** + * 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 old mode 100644 new mode 100755 index 12a96c7b..a4086aa3 --- a/buildscripts/phing/classes/phing/BuildListener.php +++ b/buildscripts/phing/classes/phing/BuildListener.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.6 $ + * @version $Id$ * @see BuildEvent * @see Project::addBuildListener() * @package phing @@ -37,55 +37,55 @@ interface BuildListener { /** * Fired before any targets are started. * - * @param BuildEvent The BuildEvent + * @param BuildEvent $event The BuildEvent */ - function buildStarted(BuildEvent $event); + public function buildStarted(BuildEvent $event); /** * Fired after the last target has finished. * - * @param BuildEvent The BuildEvent + * @param BuildEvent $event The BuildEvent * @see BuildEvent::getException() */ - function buildFinished(BuildEvent $event); + public function buildFinished(BuildEvent $event); /** * Fired when a target is started. * - * @param BuildEvent The BuildEvent + * @param BuildEvent $event The BuildEvent * @see BuildEvent::getTarget() */ - function targetStarted(BuildEvent $event); + public function targetStarted(BuildEvent $event); /** * Fired when a target has finished. * - * @param BuildEvent The BuildEvent + * @param BuildEvent $event The BuildEvent * @see BuildEvent#getException() */ - function targetFinished(BuildEvent $event); + public function targetFinished(BuildEvent $event); /** * Fired when a task is started. * - * @param BuildEvent The BuildEvent + * @param BuildEvent $event The BuildEvent * @see BuildEvent::getTask() */ - function taskStarted(BuildEvent $event); + public function taskStarted(BuildEvent $event); /** - * Fired when a task has finished. + * Fired when a task has finished. * - * @param BuildEvent The BuildEvent - * @see BuildEvent::getException() + * @param BuildEvent $event The BuildEvent + * @see BuildEvent::getException() */ - function taskFinished(BuildEvent $event); + public function taskFinished(BuildEvent $event); /** - * Fired whenever a message is logged. + * Fired whenever a message is logged. * - * @param BuildEvent The BuildEvent - * @see BuildEvent::getMessage() + * @param BuildEvent $event The BuildEvent + * @see BuildEvent::getMessage() */ - function messageLogged(BuildEvent $event); + 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 @@ +. + */ + +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 + * @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 @@ +. + */ + +/** + * ConfigurationException is thrown by Phing during the configuration and setup phase of the project. + * + * @author Hans Lellelid + * @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 old mode 100644 new mode 100755 index b4300950..8bcf2456 --- a/buildscripts/phing/classes/phing/IntrospectionHelper.php +++ b/buildscripts/phing/classes/phing/IntrospectionHelper.php @@ -1,7 +1,7 @@ * @author Hans Lellelid - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.19 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id: a5f2dbd71bafd2c363026d911132c3b47bf44239 $ * @package phing */ class IntrospectionHelper { @@ -123,9 +123,9 @@ class IntrospectionHelper { * need to perform any introspection -- either the requested attribute setter/creator * exists or it does not & a BuildException is thrown. * - * @param string $bean The classname for this IH. + * @param string $class The classname for this IH. */ - function __construct($class) { + public function __construct($class) { $this->bean = new ReflectionClass($class); @@ -178,7 +178,7 @@ class IntrospectionHelper { } elseif (strpos($name, "create") === 0) { - if (count($method->getParameters()) > 0) { + if ($method->getNumberOfRequiredParameters() > 0) { throw new BuildException($method->getDeclaringClass()->getName()."::".$method->getName()."() may not take any parameters."); } @@ -266,8 +266,14 @@ class IntrospectionHelper { } - /** Sets the named attribute. */ - function setAttribute(Project $project, $element, $attributeName, &$value) { + /** + * 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} @@ -309,10 +315,6 @@ class IntrospectionHelper { if ($as == "setrefid") { $value = new Reference($value); } else { - - // decode any html entities in string - $value = html_entity_decode($value); - // value is a string representation of a boolean type, // convert it to primitive if (StringHelper::isBoolean($value)) { @@ -352,7 +354,7 @@ class IntrospectionHelper { } // if is slot-listener try { - $project->log(" -calling setter ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $project->log(" -calling setter ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", Project::MSG_DEBUG); $method->invoke($element, $value); } catch(Exception $exc) { throw new BuildException($exc); @@ -360,8 +362,14 @@ class IntrospectionHelper { } - /** Adds PCDATA areas.*/ - function addText(Project $project, $element, $text) { + /** + * 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); @@ -378,10 +386,14 @@ class IntrospectionHelper { * 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 */ - function createElement(Project $project, $element, $elementName) { + public function createElement(Project $project, $element, $elementName) { $addMethod = "add".strtolower($elementName); $createMethod = "create".strtolower($elementName); @@ -391,7 +403,7 @@ class IntrospectionHelper { $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); + $project->log(" -calling creator ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", Project::MSG_DEBUG); $nestedElement = $method->invoke($element); } catch (Exception $exc) { throw new BuildException($exc); @@ -405,7 +417,7 @@ class IntrospectionHelper { try { // try to invoke the adder method on object - $project->log(" -calling adder ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $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(); @@ -438,10 +450,15 @@ class IntrospectionHelper { /** * Creates a named nested element. + * + * @param Project $project + * @param string $element + * @param string $child + * @param string|null $elementName * @return void * @throws BuildException */ - function storeElement($project, $element, $child, $elementName = null) { + public function storeElement($project, $element, $child, $elementName = null) { if ($elementName === null) { return; @@ -454,7 +471,7 @@ class IntrospectionHelper { $method = $this->nestedStorers[$storer]; try { - $project->log(" -calling storer ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", PROJECT_MSG_DEBUG); + $project->log(" -calling storer ".$method->getDeclaringClass()->getName()."::".$method->getName()."()", Project::MSG_DEBUG); $method->invoke($element, $child); } catch (Exception $exc) { throw new BuildException($exc); @@ -463,13 +480,19 @@ class IntrospectionHelper { } - /** Does the introspected class support PCDATA? */ - function supportsCharacters() { + /** + * Does the introspected class support PCDATA? + * @return boolean + */ + public function supportsCharacters() { return ($this->methodAddText !== null); } - /** Return all attribues supported by the introspected class. */ - function getAttributes() { + /** + * 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"); @@ -477,8 +500,11 @@ class IntrospectionHelper { return $attribs; } - /** Return all nested elements supported by the introspected class. */ - function getNestedElements() { + /** + * Return all nested elements supported by the introspected class. + * @return string[] + */ + public function getNestedElements() { return $this->nestedTypes; } @@ -492,7 +518,7 @@ class IntrospectionHelper { * @param object $element The Task or type element. * @return string Fully qualified class name of element when possible. */ - function getElementName(Project $project, $element) { + public function getElementName(Project $project, $element) { $taskdefs = $project->getTaskDefinitions(); $typedefs = $project->getDataTypeDefinitions(); @@ -524,17 +550,24 @@ class IntrospectionHelper { } } - /** extract the name of a property from a method name - subtracting a given prefix. */ - function getPropertyName($methodName, $prefix) { + /** + * 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 */ - function warn($msg) { - if (Phing::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { + 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 old mode 100644 new mode 100755 index bb8d67f6..d663ee42 --- a/buildscripts/phing/classes/phing/Phing.php +++ b/buildscripts/phing/classes/phing/Phing.php @@ -1,6 +1,6 @@ . */ - + 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'; @@ -41,11 +42,13 @@ 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 + * 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. * @@ -55,7 +58,7 @@ include_once 'phing/system/util/Register.php'; * * @author Andreas Aderhold * @author Hans Lellelid - * @version $Revision: 1.51 $ + * @version $Id: 1ad418f51ac07c9afaadf1c1f4befd5535f5b390 $ * @package phing */ class Phing { @@ -63,8 +66,8 @@ 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; + /** 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; @@ -85,90 +88,166 @@ class Phing { /** 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(); - + + /** The current Project */ + private static $currentProject; + + /** Whether to capture PHP errors to buffer. */ + private static $phpErrorCapture = false; + + /** Array of captured PHP errors */ + private static $capturedPhpErrors = array(); + /** - * Prints the message of the Exception if it's not null. + * @var OUtputStream Stream for standard output. */ - function printMessage(Exception $t) { - print($t->getMessage() . "\n"); - if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { - print($t->getTraceAsString()."\n"); - if ($t instanceof Exception) { - $c = $t->getCause(); - if ($c !== null) { - print("Wrapped exception trace:\n"); - print($c->getTraceAsString() . "\n"); - } - } - } // if output level is DEBUG - } + 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 $args The commandline args passed to phing shell script. * @param array $additionalUserProperties Any additional properties to be passed to Phing (alternative front-end might implement this). * These additional properties will be available using the getDefinedProperty() method and will - * be added to the project's "user" properties. - * @return void + * 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, $additionalUserProperties = null) { + public static function start($args, array $additionalUserProperties = null) { try { $m = new Phing(); $m->execute($args); } catch (Exception $exc) { - $m->printMessage($exc); - self::halt(-1); // Parameter error + self::handleLogfile(); + throw $exc; } if ($additionalUserProperties !== null) { - $keys = $m->additionalUserProperties->keys(); - while(count($keys)) { - $key = array_shift($keys); - $property = $m->additionalUserProperties->getProperty($key); - $m->setDefinedProperty($key, $property); + foreach($additionalUserProperties as $key => $value) { + $m->setDefinedProperty($key, $value); } } try { $m->runBuild(); } catch(Exception $exc) { - self::halt(1); // Errors occured + self::handleLogfile(); + throw $exc; } - + // everything fine, shutdown - self::halt(0); // no errors, everything is cake + 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 @@ -177,8 +256,8 @@ class Phing { */ 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 @@ -190,65 +269,92 @@ class Phing { public static function fire($args) { self::start($args, null); } - + /** * Setup/initialize Phing environment from commandline args. * @param array $args commandline args passed to phing shell. * @return void */ public function execute($args) { - + self::$definedProps = new Properties(); $this->searchForThis = null; - // cycle through given args - for ($i = 0, $argcount = count($args); $i < $argcount; ++$i) { - // ++$i intentional here, as first param is script name + // 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 == "-help" || $arg == "-h") { - $this->printUsage(); - return; - } elseif ($arg == "-version" || $arg == "-v") { - $this->printVersion(); - return; - } elseif ($arg == "-quiet" || $arg == "-q") { - self::$msgOutputLevel = PROJECT_MSG_WARN; - } elseif ($arg == "-verbose") { - $this->printVersion(); - self::$msgOutputLevel = PROJECT_MSG_VERBOSE; - } elseif ($arg == "-debug") { - $this->printVersion(); - self::$msgOutputLevel = PROJECT_MSG_DEBUG; - } elseif ($arg == "-logfile") { - try { // try to set logfile + if ($arg == "-logfile") { + try { + // see: http://phing.info/trac/ticket/65 if (!isset($args[$i+1])) { - print("You must specify a log file when using the -logfile argument\n"); - return; + $msg = "You must specify a log file when using the -logfile argument\n"; + throw new ConfigurationException($msg); } else { $logFile = new PhingFile($args[++$i]); - $this->loggerClassname = 'phing.listener.PearLogger'; - $this->setDefinedProperty('pear.log.name', $logFile->getAbsolutePath()); + $out = new FileOutputStream($logFile); // overwrite + self::setOutputStream($out); + self::setErrorStream($out); + self::$isLogFileUsed = true; } } catch (IOException $ioe) { - print("Cannot write on the specified log file. Make sure the path exists and you have write permissions.\n"); - throw $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])) { - print("You must specify a buildfile when using the -buildfile argument\n"); - return; + $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])) { - print("You must specify a listener class when using the -listener argument\n"); - return; + $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; @@ -256,28 +362,41 @@ class Phing { if ($posEq !== false) { $value = substr($name, $posEq+1); $name = substr($name, 0, $posEq); - } elseif ($i < count($args)-1) { + } 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])) { - print("You must specify a classname when using the -logger argument\n"); - return; + $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 BuildException("Only one input handler class may be specified."); + throw new ConfigurationException("Only one input handler class may be specified."); } if (!isset($args[$i+1])) { - print("You must specify a classname when using the -inputhandler argument\n"); - return; + $msg = "You must specify a classname when using the -inputhandler argument"; + throw new ConfigurationException($msg); } else { $this->inputHandlerClassname = $args[++$i]; } - } elseif ($arg == "-projecthelp" || $arg == "-targets" || $arg == "-list" || $arg == "-l") { + } 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") { @@ -289,8 +408,8 @@ class Phing { } } elseif (substr($arg,0,1) == "-") { // we don't have any more args - print("Unknown argument: $arg\n"); - $this->printUsage(); + self::$err->write("Unknown argument: $arg" . PHP_EOL); + self::printUsage(); return; } else { // if it's no other arg, it may be the target @@ -309,12 +428,12 @@ class Phing { } // make sure buildfile exists if (!$this->buildFile->exists()) { - throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " does not exist!"); + throw new ConfigurationException("Buildfile: " . $this->buildFile->__toString() . " does not exist!"); } // make sure it's not a directory - if ($this->buildFile->isDirectory()) { - throw new BuildException("Buildfile: " . $this->buildFile->__toString() . " is a dir!"); + if ($this->buildFile->isDirectory()) { + throw new ConfigurationException("Buildfile: " . $this->buildFile->__toString() . " is a dir!"); } $this->readyToRun = true; @@ -326,15 +445,10 @@ class Phing { * @param PhingFile $file * @return PhingFile Parent file or null if none */ - function _getParentFile(PhingFile $file) { + private function _getParentFile(PhingFile $file) { $filename = $file->getAbsolutePath(); $file = new PhingFile($filename); $filename = $file->getParent(); - - if ($filename !== null && self::$msgOutputLevel >= PROJECT_MSG_VERBOSE) { - print("Searching in $filename\n"); - } - return ($filename === null) ? null : new PhingFile($filename); } @@ -345,17 +459,14 @@ class Phing { * parent directory in search of a build file. Once the * root of the file-system has been reached an exception * is thrown. - * + * * @param string $start Start file path. * @param string $suffix Suffix filename to look for in parents. * @return PhingFile A handle to the build file * * @throws BuildException Failed to locate a build file */ - function _findBuildFile($start, $suffix) { - if (self::$msgOutputLevel >= PROJECT_MSG_INFO) { - print("Searching for $suffix ...\n"); - } + private function _findBuildFile($start, $suffix) { $startf = new PhingFile($start); $parent = new PhingFile($startf->getAbsolutePath()); $file = new PhingFile($parent, $suffix); @@ -368,7 +479,7 @@ class Phing { // if parent is null, then we are at the root of the fs, // complain that we can't find the build file. if ($parent === null) { - throw new BuildException("Could not locate a build file!"); + throw new ConfigurationException("Could not locate a build file!"); } // refresh our file handle $file = new PhingFile($parent, $suffix); @@ -385,17 +496,17 @@ class Phing { if (!$this->readyToRun) { return; } - + $project = new Project(); - - self::setCurrentProject($project); - set_error_handler(array('Phing', 'handlePhpError')); - + + 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()); @@ -404,7 +515,7 @@ class Phing { $project->init(); } catch (Exception $exc) { $project->fireBuildFinished($exc); - throw $exc; + throw $exc; } $project->setUserProperty("phing.version", $this->getPhingVersion()); @@ -421,30 +532,40 @@ class Phing { // 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(); + 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 { + + try { $project->executeTargets($this->targets); } catch (Exception $exc) { $project->fireBuildFinished($exc); - restore_error_handler(); - self::unsetCurrentProject(); + restore_error_handler(); + self::unsetCurrentProject(); throw $exc; } } @@ -455,32 +576,68 @@ class Phing { $this->printTargets($project); } catch (Exception $exc) { $project->fireBuildFinished($exc); - restore_error_handler(); - self::unsetCurrentProject(); + restore_error_handler(); + self::unsetCurrentProject(); throw $exc; } } - + // finally { if (!$this->projectHelp) { $project->fireBuildFinished(null); } - - restore_error_handler(); - self::unsetCurrentProject(); + + 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 default build listeners to this project. - * Currently this means adding the logger. + * 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. * @@ -498,12 +655,12 @@ class Phing { $handler = new $clz(); if ($project !== null && method_exists($handler, 'setProject')) { $handler->setProject($project); - } + } } catch (Exception $e) { $msg = "Unable to instantiate specified input handler " - . "class " . $this->inputHandlerClassname . " : " - . $e->getMessage(); - throw new BuildException($msg); + . "class " . $this->inputHandlerClassname . " : " + . $e->getMessage(); + throw new ConfigurationException($msg); } } $project->setInputHandler($handler); @@ -511,165 +668,185 @@ class Phing { /** * Creates the default build logger for sending build events to the log. - * @return BuildListener The created Logger + * @return BuildLogger The created Logger */ private function createLogger() { if ($this->loggerClassname !== null) { self::import($this->loggerClassname); - // get class name part + // 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) { - + + /** + * Sets the current Project + * @param Project $p + */ + public static function setCurrentProject($p) { + self::$currentProject = $p; + } + + /** + * Unsets the current Project + */ + public static function unsetCurrentProject() { + self::$currentProject = null; + } + + /** + * Gets the current Project. + * @return Project Current Project or NULL if none is set yet/still. + */ + public static function getCurrentProject() { + return self::$currentProject; + } + + /** + * A static convenience method to send a log to the current (last-setup) Project. + * If there is no currently-configured Project, then this will do nothing. + * @param string $message + * @param int $priority Project::MSG_INFO, etc. + */ + public static function log($message, $priority = Project::MSG_INFO) { + $p = self::getCurrentProject(); + if ($p) { + $p->log($message, $priority); + } + } + + /** + * Error handler for PHP errors encountered during the build. + * This uses the logging for the currently configured project. + */ + public static function handlePhpError($level, $message, $file, $line) { + // don't want to print supressed errors if (error_reporting() > 0) { - - if (self::$phpErrorCapture) { - - self::$capturedPhpErrors[] = array('message' => $message, 'level' => $level, 'line' => $line, 'file' => $file); - - } else { - - $message = '[PHP Error] ' . $message; - $message .= ' [line ' . $line . ' of ' . $file . ']'; - - switch ($level) { - - case E_STRICT: - case E_NOTICE: - case E_USER_NOTICE: - self::log($message, PROJECT_MSG_VERBOSE); - break; - case E_WARNING: - case E_USER_WARNING: - self::log($message, PROJECT_MSG_WARN); - break; - case E_ERROR: - case E_USER_ERROR: - default: - self::log($message, PROJECT_MSG_ERR); - - } // switch - - } // if phpErrorCapture - + + if (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; - } - + + } + + /** + * Begins capturing PHP errors to a buffer. + * While errors are being captured, they are not logged. + */ + public static function startPhpErrorCapture() { + self::$phpErrorCapture = true; + self::$capturedPhpErrors = array(); + } + + /** + * Stops capturing PHP errors to a buffer. + * The errors will once again be logged after calling this method. + */ + public static function stopPhpErrorCapture() { + self::$phpErrorCapture = false; + } + + /** + * Clears the captured errors without affecting the starting/stopping of the capture. + */ + public static function clearCapturedPhpErrors() { + self::$capturedPhpErrors = array(); + } + + /** + * Gets any PHP errors that were captured to buffer. + * @return array array('message' => message, 'line' => line number, 'file' => file name, 'level' => error level) + */ + public static function getCapturedPhpErrors() { + return self::$capturedPhpErrors; + } + /** Prints the usage of how to use this class */ - function printUsage() { - $lSep = self::getProperty("line.separator"); + public static function printUsage() { + $msg = ""; - $msg .= "phing [options] [target [target2 [target3] ...]]" . $lSep; - $msg .= "Options: " . $lSep; - $msg .= " -h -help print this message" . $lSep; - $msg .= " -l -list list available targets in this project" . $lSep; - $msg .= " -v -version print the version information and exit" . $lSep; - $msg .= " -q -quiet be extra quiet" . $lSep; - $msg .= " -verbose be extra verbose" . $lSep; - $msg .= " -debug print debugging information" . $lSep; - $msg .= " -logfile use given file for log" . $lSep; - $msg .= " -logger the class which is to perform logging" . $lSep; - $msg .= " -f -buildfile use given buildfile" . $lSep; - $msg .= " -D= use value for given property" . $lSep; - $msg .= " -find search for buildfile towards the root of the" . $lSep; - $msg .= " filesystem and use it" . $lSep; - //$msg .= " -recursive search for buildfile downwards and use it" . $lSep; - $msg .= $lSep; - $msg .= "Report bugs to ".$lSep; - print($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 use given file for log" . PHP_EOL; + $msg .= " -logger the class which is to perform logging" . PHP_EOL; + $msg .= " -f -buildfile use given buildfile" . PHP_EOL; + $msg .= " -D= use value for given property" . PHP_EOL; + $msg .= " -propertyfile load all properties from file" . PHP_EOL; + $msg .= " -find search for buildfile towards the root of the" . PHP_EOL; + $msg .= " filesystem and use it" . PHP_EOL; + $msg .= " -inputhandler the class to use to handle user input" . PHP_EOL; + //$msg .= " -recursive search for buildfile downwards and use it" . PHP_EOL; + $msg .= PHP_EOL; + $msg .= "Report bugs to ".PHP_EOL; + self::$err->write($msg); } - function printVersion() { - print(self::getPhingVersion()."\n"); + /** + * Prints the current Phing version. + */ + public static function printVersion() { + self::$out->write(self::getPhingVersion().PHP_EOL); } - function getPhingVersion() { + /** + * 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) { + $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); @@ -679,16 +856,17 @@ class Phing { //$buffer = "PHING version 1.0, Released 2002-??-??"; $phingVersion = $buffer; } catch (IOException $iox) { - print("Can't read version information file\n"); - throw new BuildException("Build failed"); - } + throw new ConfigurationException("Can't read version information file"); + } return $phingVersion; } - /** Print the project description, if any */ - function printDescription(Project $project) { + /** + * Print the project description, if any + */ + public static function printDescription(Project $project) { if ($project->getDescription() !== null) { - print($project->getDescription()."\n"); + self::$out->write($project->getDescription() . PHP_EOL); } } @@ -704,31 +882,34 @@ class Phing { // split the targets in top-level and sub-targets depending // on the presence of a description - + $subNames = array(); $topNameDescMap = array(); - - foreach($targets as $currentTarget) { + + foreach($targets as $currentTarget) { $targetName = $currentTarget->getName(); - $targetDescription = $currentTarget->getDescription(); - + $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; + $topNameDescMap[$targetName] = $targetDescription; if (strlen($targetName) > $maxLength) { $maxLength = strlen($targetName); } } } - + // Sort the arrays - sort($subNames); // sort array values, resetting keys (which are numeric) + 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); @@ -750,7 +931,7 @@ class Phing { } $this->_printTargets($topNames, $topDescriptions, "Main targets:", $maxLength); $this->_printTargets($subNames, null, "Subtargets:", 0); - } + } /** * Writes a formatted list of target names with an optional description. @@ -770,14 +951,14 @@ class Phing { * are shorter than this). */ private function _printTargets($names, $descriptions, $heading, $maxlen) { - $lSep = self::getProperty("line.separator"); + $spaces = ' '; while (strlen($spaces) < $maxlen) { $spaces .= $spaces; } $msg = ""; - $msg .= $heading . $lSep; - $msg .= str_repeat("-",79) . $lSep; + $msg .= $heading . PHP_EOL; + $msg .= str_repeat("-",79) . PHP_EOL; $total = count($names); for($i=0; $i < $total; $i++) { @@ -787,58 +968,74 @@ class Phing { $msg .= substr($spaces, 0, $maxlen - strlen($names[$i]) + 2); $msg .= $descriptions[$i]; } - $msg .= $lSep; + $msg .= PHP_EOL; } if ($total > 0) { - print $msg . $lSep; - } - } - - /** - * Import a dot-path notation class path. - * @param string $dotPath - * @param mixed $classpath String or object supporting __toString() - * @return string The unqualified classname (which can be instantiated). - * @throws BuildException - if cannot find the specified file - */ - public static function import($dotPath, $classpath = null) { + 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) - $classname = StringHelper::unqualify($dotPath); - if (class_exists($classname, false)) { + if (class_exists($classname)) { return $classname; } - + $dotClassname = basename($dotPath); $dotClassnamePos = strlen($dotPath) - strlen($dotClassname); - $classFile = strtr($dotClassname, '.', DIRECTORY_SEPARATOR) . ".php"; + + // 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) { - + } + + /** + * 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. + // 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 @@ -848,88 +1045,89 @@ class Phing { // be more expensive than switching & switching back (not sure, but maybe), it makes it // possible to write far less expensive run-time applications (e.g. using Propel), which is // really where speed matters more. - - $curr_parts = explode(PATH_SEPARATOR, ini_get('include_path')); + + $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) { - if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { - print("Phing::import() prepending new include_path components: " . implode(PATH_SEPARATOR, $new_parts) . "\n"); - } - ini_set('include_path', implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); + set_include_path(implode(PATH_SEPARATOR, array_merge($new_parts, $curr_parts))); } } - $ret = include_once($path); - + $ret = include_once($path); + if ($ret === false) { - $e = new BuildException("Error importing $path"); - if (self::getMsgOutputLevel() === PROJECT_MSG_DEBUG) { - // We can't log this because listeners belong - // to projects. We'll just print it -- of course - // that isn't very compatible w/ other frontends (but - // there aren't any right now, so I'm not stressing) - print("Error importing $path\n"); - print($e->getTraceAsString()."\n"); - } - throw $e; + $msg = "Error importing $path"; + if (self::getMsgOutputLevel() >= Project::MSG_DEBUG) { + $x = new Exception("for-path-trace-only"); + $msg .= $x->getTraceAsString(); + } + throw new ConfigurationException($msg); } - - return; - } - - /** - * Looks on include path for specified file. - * @return string File found (null if no file found). - */ - public static function getResourcePath($path) { - + } + + /** + * Looks on include path for specified file. + * @return string File found (null if no file found). + */ + public static function getResourcePath($path) { + if (self::$importPaths === null) { - $paths = ini_get("include_path"); + $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) { - $foo_path = $prefix . DIRECTORY_SEPARATOR . $path; - if (file_exists($foo_path)) { - return $foo_path; + $testPath = $prefix . DIRECTORY_SEPARATOR . $path; + if (file_exists($testPath)) { + return $testPath; } } - + // Check for the property phing.home - $home_dir = self::getProperty('phing.home'); - - if ($home_dir) - { - $home_path = $home_dir . DIRECTORY_SEPARATOR . $path; - - if (file_exists($home_path)) - { - return $home_path; - } - } - + $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. - $data_dir = '@DATA-DIR@'; - if ($data_dir{0} != '@') { // if we're using PEAR then the @ DATA-DIR @ token will have been substituted. - $data_path = $data_dir . DIRECTORY_SEPARATOR . $path; - if (file_exists($data_path)) { - return $data_path; - } + $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) - // ------------------------------------------------------------------------------------------- - + } + + // ------------------------------------------------------------------------------------------- + // 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 @@ -944,20 +1142,20 @@ class Phing { * Windows 98SE => WIN32 * FreeBSD 4.5p7 => FreeBSD * Redhat Linux => Linux - * Mac OS X => Darwin + * Mac OS X => Darwin */ self::setProperty('host.os', PHP_OS); - - // this is used by some tasks too + + // 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 @@ -976,24 +1174,26 @@ class Phing { 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('line.separator', "\n"); + 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(); + $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'); - } - + $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"); @@ -1002,55 +1202,55 @@ class Phing { 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 + * provide a public means of accessing commandline properties for (e.g.) logger or listener * scripts. E.g. to specify which logfile to use, PearLogger needs to be able to access * the pear.log.name property. - * + * * @param string $name * @return string value of found property (or null, if none found). */ public static function getDefinedProperty($name) { return self::$definedProps->getProperty($name); } - + /** * This sets a property that was set via command line or otherwise passed into Phing. - * + * * @param string $name * @return string value of found property (or null, if none found). */ public static function setDefinedProperty($name, $value) { return self::$definedProps->setProperty($name, $value); } - + /** * Returns property value for a System property. - * System properties are "global" properties like line.separator, + * 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 + + // special exceptions switch($propName) { case 'user.dir': $val = getcwd(); - break; + break; } - + return $val; } @@ -1059,56 +1259,106 @@ class Phing { return self::$properties; } - public static function setProperty($propName, $propValue) { + public static function setProperty($propName, $propValue) { $propName = (string) $propName; $oldValue = self::getProperty($propName); self::$properties[$propName] = $propValue; return $oldValue; } - + public static function currentTimeMillis() { list($usec, $sec) = explode(" ",microtime()); return ((float)$usec + (float)$sec); } - + /** - * Sets the include path based on PHP_CLASSPATH constant (set in phing.php). + * 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() { - $success = false; - if (defined('PHP_CLASSPATH')) { - $success = ini_set('include_path', PHP_CLASSPATH); - } else { - // don't do anything, just assume that include_path has been properly set. - $success = true; + $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]); - if ($success === false) { - print("SYSTEM FAILURE: Could not set PHP include path\n"); - self::halt(-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() { - error_reporting(E_ALL); + + 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); - ini_set('magic_quotes_gpc', 'off'); - ini_set('short_open_tag', 'off'); - ini_set('default_charset', 'iso-8859-1'); - ini_set('register_globals', 'off'); - ini_set('allow_call_time_pass_reference', 'on'); - - // should return memory limit in MB - $mem_limit = (int) ini_get('memory_limit'); - if ($mem_limit < 32) { + + 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); + } + } } /** @@ -1122,15 +1372,17 @@ class Phing { } return self::$timer; } - - /** + + /** * Start up Phing. - * Sets up the Phing environment -- does NOT initiate the build process. + * 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() { - - register_shutdown_function(array('Phing', 'shutdown')); + + // setup STDOUT and STDERR defaults + self::initializeOutputStreams(); // some init stuff self::getTimer()->start(); @@ -1139,23 +1391,24 @@ class Phing { 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($code=0) { - self::shutdown($code); + public static function halt() { + self::shutdown(); } /** - * Stops timers & exits. + * Performs any shutdown routines, such as stopping timers. * @return void */ - public static function shutdown($exitcode = 0) { - //print("[AUTOMATIC SYSTEM SHUTDOWN]\n"); + public static function shutdown() { + self::restoreIni(); self::getTimer()->stop(); - exit($exitcode); // final point where everything stops } - + } diff --git a/buildscripts/phing/classes/phing/Project.php b/buildscripts/phing/classes/phing/Project.php old mode 100644 new mode 100755 index 8123d91e..8e662543 --- a/buildscripts/phing/classes/phing/Project.php +++ b/buildscripts/phing/classes/phing/Project.php @@ -1,6 +1,6 @@ . */ -define('PROJECT_MSG_DEBUG', 4); -define('PROJECT_MSG_VERBOSE', 3); -define('PROJECT_MSG_INFO', 2); -define('PROJECT_MSG_WARN', 1); -define('PROJECT_MSG_ERR', 0); - include_once 'phing/system/io/PhingFile.php'; include_once 'phing/util/FileUtils.php'; include_once 'phing/TaskAdapter.php'; @@ -40,11 +34,18 @@ include_once 'phing/input/DefaultInputHandler.php'; * * @author Andreas Aderhold * @author Hans Lellelid - * @version $Revision: 1.29 $ + * @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) */ @@ -97,6 +98,9 @@ class Project { /** project description */ private $description; + /** require phing version */ + private $phingVersion; + /** a FileUtils object */ private $fileUtils; @@ -106,13 +110,14 @@ class Project { /** * Constructor, sets any default vars. */ - function __construct() { + 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; @@ -120,13 +125,14 @@ class Project { /** * Retrieves the current input handler. + * @return InputHandler */ public function getInputHandler() { return $this->inputHandler; } /** inits the project, called from main app */ - function init() { + public function init() { // set builtin properties $this->setSystemProperties(); @@ -173,7 +179,7 @@ class Project { } /** returns the global filterset (future use) */ - function getGlobalFilterSet() { + public function getGlobalFilterSet() { return $this->globalFilterSet; } @@ -191,18 +197,18 @@ class Project { * @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); + $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("Overriding previous definition of property " . $name, Project::MSG_VERBOSE); } - $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->log("Setting project property: " . $name . " -> " . $value, Project::MSG_DEBUG); $this->properties[$name] = $value; } @@ -219,10 +225,10 @@ class Project { */ public function setNewProperty($name, $value) { if (isset($this->properties[$name])) { - $this->log("Override ignored for property " . $name, PROJECT_MSG_DEBUG); + $this->log("Override ignored for property " . $name, Project::MSG_DEBUG); return; } - $this->log("Setting project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->log("Setting project property: " . $name . " -> " . $value, Project::MSG_DEBUG); $this->properties[$name] = $value; } @@ -236,7 +242,7 @@ class Project { * @see #setProperty() */ public function setUserProperty($name, $value) { - $this->log("Setting ro project property: " . $name . " -> " . $value, PROJECT_MSG_DEBUG); + $this->log("Setting ro project property: " . $name . " -> " . $value, Project::MSG_DEBUG); $this->userProperties[$name] = $value; $this->properties[$name] = $value; } @@ -268,7 +274,7 @@ class Project { */ private function setPropertyInternal($name, $value) { if (isset($this->userProperties[$name])) { - $this->log("Override ignored for user property " . $name, PROJECT_MSG_VERBOSE); + $this->log("Override ignored for user property " . $name, Project::MSG_VERBOSE); return; } $this->properties[$name] = $value; @@ -287,7 +293,15 @@ class Project { if (!isset($this->properties[$name])) { return null; } - return $this->properties[$name]; + $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; } /** @@ -370,7 +384,7 @@ class Project { *

To copy all "user" properties, you will also have to call * {@link #copyUserProperties copyUserProperties}.

* - * @param other the project to copy the properties to. Must not be null. + * @param Project $other the project to copy the properties to. Must not be null. * * @since phing 2.0 */ @@ -388,24 +402,31 @@ class Project { // --------------------------------------------------------- - function setDefaultTarget($targetName) { + /** + * Sets default target + * @param string $targetName + */ + public function setDefaultTarget($targetName) { $this->defaultTarget = (string) trim($targetName); } - function getDefaultTarget() { + /** + * Returns default target + * @return string + */ + public function getDefaultTarget() { return (string) $this->defaultTarget; } /** * Sets the name of the current project * - * @param string name of project + * @param string $name name of project * @return void * @access public * @author Andreas Aderhold, andi@binarycloud.com */ - - function setName($name) { + public function setName($name) { $this->name = (string) trim($name); $this->setProperty("phing.project.name", $this->name); } @@ -413,26 +434,55 @@ class Project { /** * Returns the name of this project * - * @returns string projectname - * @access public - * @author Andreas Aderhold, andi@binarycloud.com + * @return string projectname + * @access public + * @author Andreas Aderhold, andi@binarycloud.com */ - function getName() { + public function getName() { return (string) $this->name; } - /** Set the projects description */ - function setDescription($description) { + /** + * Set the projects description + * @param string $description + */ + public function setDescription($description) { $this->description = (string) trim($description); } - /** return the description, null otherwise */ - function getDescription() { + /** + * return the description, null otherwise + * @return string|null + */ + public function getDescription() { return $this->description; } - /** Set basedir object from xml*/ - function setBasedir($dir) { + /** + * 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(); } @@ -448,7 +498,7 @@ class Project { } $this->basedir = $dir; $this->setPropertyInternal("project.basedir", $this->basedir->getAbsolutePath()); - $this->log("Project base dir set to: " . $this->basedir->getPath(), PROJECT_MSG_VERBOSE); + $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()); @@ -457,12 +507,12 @@ class Project { /** * Returns the basedir of this project * - * @returns PhingFile Basedir PhingFile object - * @access public - * @throws BuildException - * @author Andreas Aderhold, andi@binarycloud.com + * @return PhingFile Basedir PhingFile object + * @access public + * @throws BuildException + * @author Andreas Aderhold, andi@binarycloud.com */ - function getBasedir() { + public function getBasedir() { if ($this->basedir === null) { try { // try to set it $this->setBasedir("."); @@ -478,7 +528,7 @@ class Project { * * @return void */ - function setSystemProperties() { + public function setSystemProperties() { // first get system properties $systemP = array_merge( self::getProperties(), Phing::getProperties() ); @@ -504,59 +554,84 @@ class Project { * @param string $class The class path to use. * @param string $classpath The classpat to use. */ - function addTaskDefinition($name, $class, $classpath = null) { + public function addTaskDefinition($name, $class, $classpath = null) { $name = $name; $class = $class; if ($class === "") { - $this->log("Task $name has no class defined.", PROJECT_MSG_ERR); + $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); + $this->log(" +Task definiton: $name ($class)", Project::MSG_DEBUG); } else { - $this->log("Task $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); + $this->log("Task $name ($class) already registerd, skipping", Project::MSG_VERBOSE); } } - function &getTaskDefinitions() { + /** + * Returns the task definitions + * @return array + */ + public function getTaskDefinitions() { return $this->taskdefs; } /** * Adds a data type definition. - * @param string $name Name of tag. - * @param string $class The class path to use. - * @param string $classpath The classpat to use. + * @param string $typeName Name of the type. + * @param string $typeClass The class to use. + * @param string $classpath The classpath to use. */ - function addDataTypeDefinition($typeName, $typeClass, $classpath = null) { + 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); + $this->log(" +User datatype: $typeName ($typeClass)", Project::MSG_DEBUG); } else { - $this->log("Type $name ($class) already registerd, skipping", PROJECT_MSG_VERBOSE); + $this->log("Type $typeName ($typeClass) already registerd, skipping", Project::MSG_VERBOSE); } } - function getDataTypeDefinitions() { + /** + * Returns the data type definitions + * @return array + */ + public function getDataTypeDefinitions() { return $this->typedefs; } - /** add a new target to the project */ - function addTarget($targetName, &$target) { + /** + * 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); } - function addOrReplaceTarget($targetName, &$target) { - $this->log(" +Target: $targetName", PROJECT_MSG_DEBUG); + /** + * 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; } - function getTargets() { + /** + * Returns the available targets + * @return array + */ + public function getTargets() { return $this->targets; } @@ -573,35 +648,37 @@ class Project { * unless there's any good reason not to. * * @param string $taskType Task name - * @returns Task A task object + * @return Task A task object * @throws BuildException * Exception */ - function createTask($taskType) { + public function createTask($taskType) { try { - $cls = ""; + $classname = ""; $tasklwr = strtolower($taskType); foreach ($this->taskdefs as $name => $class) { if (strtolower($name) === $tasklwr) { - $cls = StringHelper::unqualify($class); + $classname = $class; break; } } - if ($cls === "") { + 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(); + $o = new $cls(); if ($o instanceof Task) { $task = $o; } else { - $this->log (" (Using TaskAdapter for: $taskType)", PROJECT_MSG_DEBUG); + $this->log (" (Using TaskAdapter for: $taskType)", Project::MSG_DEBUG); // not a real task, try adapter $taskA = new TaskAdapter(); $taskA->setProxy($o); @@ -611,7 +688,7 @@ class Project { $task->setTaskType($taskType); // set default value, can be changed by the user $task->setTaskName($taskType); - $this->log (" +Task: " . $taskType, PROJECT_MSG_DEBUG); + $this->log (" +Task: " . $taskType, Project::MSG_DEBUG); } catch (Exception $t) { throw new BuildException("Could not create task of type: " . $taskType, $t); } @@ -620,15 +697,15 @@ class Project { } /** - * Create a task instance and return reference to it + * Create a datatype instance and return reference to it * See createTask() for explanation how this works * - * @param string Type name - * @returns object A datatype object - * @throws BuildException - * Exception + * @param string $typeName Type name + * @return object A datatype object + * @throws BuildException + * Exception */ - function createDataType($typeName) { + public function createDataType($typeName) { try { $cls = ""; $typelwr = strtolower($typeName); @@ -648,7 +725,7 @@ class Project { } $type = new $cls(); - $this->log(" +Type: $typeName", PROJECT_MSG_DEBUG); + $this->log(" +Type: $typeName", Project::MSG_DEBUG); if (!($type instanceof DataType)) { throw new Exception("$class is not an instance of phing.types.DataType"); } @@ -665,11 +742,11 @@ class Project { /** * Executes a list of targets * - * @param array List of target names to execute - * @returns void - * @throws BuildException + * @param array $targetNames List of target names to execute + * @return void + * @throws BuildException */ - function executeTargets($targetNames) { + public function executeTargets($targetNames) { foreach($targetNames as $tname) { $this->executeTarget($tname); } @@ -678,11 +755,11 @@ class Project { /** * Executes a target * - * @param string Name of Target to execute - * @returns void - * @throws BuildException + * @param string $targetName Name of Target to execute + * @return void + * @throws BuildException */ - function executeTarget($targetName) { + public function executeTarget($targetName) { // complain about executing void if ($targetName === null) { @@ -700,14 +777,16 @@ class Project { $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); + $this->log("Execution of target \"".$curTarget->getName()."\" failed for the following reason: ".$exc->getMessage(), Project::MSG_ERR); throw $exc; } } while ($curTarget->getName() !== $targetName); } - - function resolveFile($fileName, $rootDir = null) { + /** + * Helper function + */ + public function resolveFile($fileName, $rootDir = null) { if ($rootDir === null) { return $this->fileUtils->resolveFile($this->basedir, $fileName); } else { @@ -717,14 +796,14 @@ class Project { /** * Topologically sort a set of Targets. - * @param $root is the (String) name of the root Target. The sort is + * @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 $targets is a array representing a "name to Target" mapping + * @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. */ - function _topoSort($root, &$targets) { + public function _topoSort($root, &$targets) { $root = (string) $root; $ret = array(); @@ -745,7 +824,7 @@ class Project { 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); + $this->log("Build sequence for target '$root' is: $retHuman", Project::MSG_VERBOSE); $keys = array_keys($targets); while($keys) { @@ -767,7 +846,7 @@ class Project { for ($i=0,$_i=count($ret); $i < $_i; $i++) { $retHuman .= $ret[$i]->toString()." "; } - $this->log("Complete build sequence is: $retHuman", PROJECT_MSG_VERBOSE); + $this->log("Complete build sequence is: $retHuman", Project::MSG_VERBOSE); return $ret; } @@ -789,7 +868,7 @@ class Project { // "ret" now contains the sorted sequence of Targets upto the current // Target. - function _tsort($root, &$targets, &$state, &$visiting, &$ret) { + public function _tsort($root, &$targets, &$state, &$visiting, &$ret) { $state[$root] = "VISITING"; $visiting[] = $root; @@ -805,7 +884,7 @@ class Project { array_pop($visiting); if (!empty($visiting)) { $parent = (string) $visiting[count($visiting)-1]; - $sb .= "It is used from target '$parent'."; + $sb .= " It is a dependency of target '$parent'."; } throw new BuildException($sb); } @@ -837,10 +916,11 @@ class Project { $ret[] = $target; } - function _makeCircularException($end, $stk) { + public function _makeCircularException($end, $stk) { $sb = "Circular dependency: $end"; do { - $sb .= " <- ".(string) array_pop($stk); + $c = (string) array_pop($stk); + $sb .= " <- ".$c; } while($c != $end); return new BuildException($sb); } @@ -849,12 +929,14 @@ class Project { * 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 */ - function addReference($name, $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("Overriding previous definition of reference to $name", Project::MSG_WARN); } - $this->log("Adding reference: $name -> ".get_class($object), PROJECT_MSG_DEBUG); + $this->log("Adding reference: $name -> ".get_class($object), Project::MSG_DEBUG); $this->references[$name] = $object; } @@ -862,27 +944,29 @@ class Project { * Returns the references array. * @return array */ - function getReferences() { + public function getReferences() { return $this->references; } - - /** - * Returns a specific reference. - * @param string $key The reference id/key. - * @return object or null if not defined - */ - function getReference($key) - { - if (isset($this->references[$key])) { - return $this->references[$key]; - } - return null; // just to be explicit - } + + /** + * 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 */ - function log($msg, $level = PROJECT_MSG_INFO) { + public function log($msg, $level = Project::MSG_INFO) { $this->logObject($this, $msg, $level); } diff --git a/buildscripts/phing/classes/phing/ProjectComponent.php b/buildscripts/phing/classes/phing/ProjectComponent.php old mode 100644 new mode 100755 index 97ef329f..343e3a6c --- a/buildscripts/phing/classes/phing/ProjectComponent.php +++ b/buildscripts/phing/classes/phing/ProjectComponent.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.5 $ + * @version $Id$ * @package phing */ abstract class ProjectComponent { /** - * Holds a reference to the project that a project component - * (a task, a target, etc.) belongs to + * Holds a reference to the project that a project component + * (a task, a target, etc.) belongs to * - * @var object A reference to the current project instance + * @var Project A reference to the current project instance */ protected $project = null; /** - * References the project to the current component. + * References the project to the current component. * - * @param object The reference to the current project - * @access public + * @param Project $project The reference to the current project */ - function setProject($project) { + public function setProject($project) { $this->project = $project; } /** - * Returns a reference to current project + * Returns a reference to current project * - * @return object Reference to current porject object - * @access public + * @return Project Reference to current porject object */ - function getProject() { + public function getProject() { return $this->project; } /** - * Logs a message with the given priority. + * Logs a message with the given priority. * - * @param string The message to be logged. - * @param integer The message's priority at this message should have + * @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) { + 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 old mode 100644 new mode 100755 index a23437fa..305a35f3 --- a/buildscripts/phing/classes/phing/RuntimeConfigurable.php +++ b/buildscripts/phing/classes/phing/RuntimeConfigurable.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.6 $ + * @version $Id$ * @package phing */ class RuntimeConfigurable { @@ -95,8 +95,6 @@ class RuntimeConfigurable { $id = $this->attributes["id"]; } - $this->attributes = null; - if ($this->characters) { ProjectConfigurator::addText($project, $this->wrappedObject, (string) $this->characters); $this->characters=""; diff --git a/buildscripts/phing/classes/phing/Target.php b/buildscripts/phing/classes/phing/Target.php old mode 100644 new mode 100755 index 9aeb9440..342d11cb --- a/buildscripts/phing/classes/phing/Target.php +++ b/buildscripts/phing/classes/phing/Target.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id: b6779ff7860ec7a7a84d74a40ffcc9efa75255f7 $ * @access public * @see TaskContainer * @package phing @@ -35,51 +35,78 @@ include_once 'phing/TaskContainer.php'; class Target implements TaskContainer { - /** name of target */ + /** + * Name of target + * @var string + */ private $name; - /** dependencies */ + /** + * Dependencies + * @var array + */ private $dependencies = array(); - /** holds objects of children of this target */ + /** + * Holds objects of children of this target + * @var array + */ private $children = array(); - /** the if cond. from xml */ + /** + * The if condition from xml + * @var string + */ private $ifCondition = ""; - /** the unless cond. from xml */ + /** + * The unless condition from xml + * @var string + */ private $unlessCondition = ""; - /** description of this target */ + /** + * Description of this target + * @var string + */ private $description; + + /** + * Whether to hide target in targets list (-list -p switches) + * @var boolean + */ + private $hidden = false; - /** reference to project */ + /** + * Rreference to project + * @var Project + */ private $project; /** - * References the project to the current component. + * References the project to the current component. * - * @param Project The reference to the current project + * @param Project $project The reference to the current project */ public function setProject(Project $project) { $this->project = $project; } /** - * Returns reference to current project + * Returns reference to current project * - * @return Project Reference to current porject object + * @return Project Reference to current porject object */ public function getProject() { return $this->project; } /** - * Sets the target dependencies from xml + * Sets the target dependencies from xml * - * @param string $depends Comma separated list of targetnames that depend on + * @param string $depends Comma separated list of targetnames that depend on * this target - * @throws BuildException + * @throws BuildException */ public function setDepends($depends) { // explode should be faster than strtok @@ -94,71 +121,103 @@ class Target implements TaskContainer { } /** - * Adds a singular dependent target name to the list + * Adds a singular dependent target name to the list * - * @param string The dependency target to add - * @access public + * @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. + * Returns reference to indexed array of the dependencies this target has. * - * @return array Referece to target dependencoes + * @return array Referece to target dependencoes */ public function getDependencies() { return $this->dependencies; } /** - * Sets the name of the target + * Sets the name of the target * - * @param string Name of this target + * @param string $name Name of this target */ public function setName($name) { $this->name = (string) $name; } /** - * Returns name of this target. + * Returns name of this target. * - * @return string The name of the target - * @access public + * @return string The name of the target + * @access public */ - function getName() { + public function getName() { return (string) $this->name; } /** - * Adds a task element to the list of this targets child elements + * Set target status. If true, target does not come in phing -list * - * @param object The task object to add - * @access public + * @param boolean $flag + * @return Target */ - function addTask(Task $task) { + 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. + * Adds a runtime configurable element to the list of this targets child + * elements. * - * @param object The RuntimeConfigurabel object - * @access public + * @param RuntimeConfigurable $rtc The RuntimeConfigurable object + * @access public */ - function addDataType($rtc) { + public function addDataType($rtc) { $this->children[] = $rtc; } /** - * Returns an array of all tasks this target has as childrens. + * 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. + * The task objects are copied here. Don't use this method to modify + * task objects. * - * @return array Task[] + * @return array Task[] */ public function getTasks() { $tasks = array(); @@ -173,32 +232,32 @@ class Target implements TaskContainer { } /** - * 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 + * Set the if-condition from the XML tag, if any. The property name given + * as parameter must be present so the if condition evaluates to true * - * @param string The property name that has to be present - * @access public + * @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 + * Set the unless-condition from the XML tag, if any. The property name + * given as parameter must be present so the unless condition evaluates + * to true * - * @param string The property name that has to be present - * @access public + * @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. + * Sets a textual description of this target. * - * @param string The description text + * @param string $description The description text */ public function setDescription($description) { if ($description !== null && strcmp($description, "") !== 0) { @@ -209,28 +268,27 @@ class Target implements TaskContainer { } /** - * Returns the description of this target. + * Returns the description of this target. * - * @return string The description text 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 + * 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 + * @return string The string representation of this target */ - function toString() { + 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. - * + * 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()) { @@ -244,25 +302,25 @@ class Target implements TaskContainer { } } } elseif (!$this->testIfCondition()) { - $this->project->log("Skipped target '".$this->name."' because property '".$this->ifCondition."' not set.", PROJECT_MSG_VERBOSE); + $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); + $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. + * 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. + * This method is for ZE2 and used for proper exception handling of + * task exceptions. */ public function performTasks() { try {// try to execute this target $this->project->fireTargetStarted($this); $this->main(); $this->project->fireTargetFinished($this, $null=null); - } catch (Exception $exc) { + } catch (BuildException $exc) { // log here and rethrow $this->project->fireTargetFinished($this, $exc); throw $exc; @@ -270,11 +328,11 @@ class Target implements TaskContainer { } /** - * Tests if the property set in ifConfiditon exists. + * Tests if the property set in ifConfiditon exists. * - * @return boolean true if the property specified - * in $this->ifCondition exists; - * false otherwise + * @return boolean true if the property specified + * in $this->ifCondition exists; + * false otherwise */ private function testIfCondition() { if ($this->ifCondition === "") { @@ -293,10 +351,10 @@ class Target implements TaskContainer { } /** - * Tests if the property set in unlessCondition exists. + * Tests if the property set in unlessCondition exists. * - * @return boolean true if the property specified - * in $this->unlessCondition exists; + * @return boolean true if the property specified + * in $this->unlessCondition exists; * false otherwise */ private function testUnlessCondition() { diff --git a/buildscripts/phing/classes/phing/Task.php b/buildscripts/phing/classes/phing/Task.php old mode 100644 new mode 100755 index 893a82e9..d2490a90 --- a/buildscripts/phing/classes/phing/Task.php +++ b/buildscripts/phing/classes/phing/Task.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.11 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @see Project#createTask() * @package phing */ abstract class Task extends ProjectComponent { - /** owning Target object */ + /** + * Owning Target object + * @var Target + */ protected $target; - /** description of the task */ + /** + * Description of the task + * @var string + */ protected $description; - /** internal taskname (req) */ + /** + * Internal taskname (req) + * @var string + */ protected $taskType; - /** taskname for logger */ + /** + * Taskname for logger + * @var string + */ protected $taskName; - /** stored buildfile location */ + /** + * Stored buildfile location + * @var Location + */ protected $location; - /** wrapper of the task */ + /** + * Wrapper of the task + * @var RuntimeConfigurable + */ protected $wrapper; /** * Sets the owning target this task belongs to. * - * @param object Reference to owning target - * @access public + * @param Target Reference to owning target */ - function setOwningTarget(Target $target) { + public function setOwningTarget(Target $target) { $this->target = $target; } /** - * Returns the owning target of this task. + * Returns the owning target of this task. * - * @return object The target object that owns this task - * @access public + * @return Target The target object that owns this task */ - function getOwningTarget() { + public function getOwningTarget() { return $this->target; } /** - * Returns the name of task, used only for log messages + * Returns the name of task, used only for log messages * - * @return string Name of this task - * @access public + * @return string Name of this task */ - function getTaskName() { + 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 @@ -92,77 +107,77 @@ abstract class Task extends ProjectComponent { } /** - * Sets the name of this task for log messages + * Sets the name of this task for log messages * - * @return string A string representing the name of this task for log - * @access public + * @param string $name + * @return string A string representing the name of this task for log */ - function setTaskName($name) { + public function setTaskName($name) { $this->taskName = (string) $name; } /** - * Returns the name of the task under which it was invoked, - * usually the XML tagname + * Returns the name of the task under which it was invoked, + * usually the XML tagname * - * @return string The type of this task (XML Tag) + * @return string The type of this task (XML Tag) */ - function getTaskType() { + public function getTaskType() { return $this->taskType; } /** - * Sets the type of the task. Usually this is the name of the XML tag + * Sets the type of the task. Usually this is the name of the XML tag * - * @param string The type of this task (XML Tag) + * @param string The type of this task (XML Tag) */ - function setTaskType($name) { + public function setTaskType($name) { $this->taskType = (string) $name; } - - /** - * Returns a name - * - */ - protected function getRegisterSlot($slotName) { - return Register::getSlot('task.' . $this->getTaskName() . '.' . $slotName); - } - + + /** + * 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. + * 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 + * @param string The message to log + * @param integer The priority of the message + * @see BuildEvent + * @see BuildListener */ - function log($msg, $level = PROJECT_MSG_INFO) { + function log($msg, $level = Project::MSG_INFO) { $this->project->logObject($this, $msg, $level); } /** - * Sets a textual description of the task + * Sets a textual description of the task * - * @param string The text describing the task + * @param string $desc The text describing the task */ public function setDescription($desc) { $this->description = $desc; } /** - * Returns the textual description of the task + * Returns the textual description of the task * - * @return string The text 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 + * 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. + * This is abstract here, but may not be overloaded by subclasses. * * @throws BuildException */ @@ -178,39 +193,35 @@ abstract class Task extends ProjectComponent { * Should throw a BuildException if someting goes wrong with the build * * This is abstract here. Must be overloaded by real tasks. - * - * @access public */ - abstract function main(); + abstract public function main(); /** - * Returns the location within the buildfile this task occurs. Used - * by {@link BuildException} to give detailed error messages. + * 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. + * @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. + * Sets the location within the buildfile this task occurs. Called by + * the parser to set location information. * - * @return object The location object describing the position of this - * task within the buildfile. - * @access public + * @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 + * Returns the wrapper object for runtime configuration * - * @return object The wrapper object used by this task - * @access public + * @return RuntimeConfigurable The wrapper object used by this task */ function getRuntimeConfigurableWrapper() { if ($this->wrapper === null) { @@ -223,8 +234,7 @@ abstract class Task extends ProjectComponent { * Sets the wrapper object this task should use for runtime * configurable elements. * - * @param object The wrapper object this task should use - * @access public + * @param RuntimeConfigurable $wrapper The wrapper object this task should use */ function setRuntimeConfigurableWrapper(RuntimeConfigurable $wrapper) { $this->wrapper = $wrapper; @@ -232,21 +242,17 @@ abstract class Task extends ProjectComponent { /** * Configure this task if it hasn't been done already. - * - * @access public */ - function maybeConfigure() { + public function maybeConfigure() { if ($this->wrapper !== null) { $this->wrapper->maybeConfigure($this->project); } } /** - * Perfrom this task - * - * @access public + * Perfrom this task */ - function perform() { + public function perform() { try { // try executing task $this->project->fireTaskStarted($this); diff --git a/buildscripts/phing/classes/phing/TaskAdapter.php b/buildscripts/phing/classes/phing/TaskAdapter.php old mode 100644 new mode 100755 index 8b84b768..ba323c56 --- a/buildscripts/phing/classes/phing/TaskAdapter.php +++ b/buildscripts/phing/classes/phing/TaskAdapter.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.7 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @package phing */ class TaskAdapter extends Task { @@ -45,7 +45,7 @@ class TaskAdapter extends Task { 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); + $this->log("Error setting project in " . get_class($this->proxy) . Project::MSG_ERR); throw new BuildException($ex); } } else { @@ -56,7 +56,8 @@ class TaskAdapter extends Task { 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("Error in " . get_class($this->proxy), Project::MSG_ERR); + $this->log($ex->getTraceAsString(), Project::MSG_DEBUG); throw new BuildException($ex->getMessage()); } } else { diff --git a/buildscripts/phing/classes/phing/TaskContainer.php b/buildscripts/phing/classes/phing/TaskContainer.php old mode 100644 new mode 100755 index 2e9eb67a..4be2ef41 --- a/buildscripts/phing/classes/phing/TaskContainer.php +++ b/buildscripts/phing/classes/phing/TaskContainer.php @@ -1,6 +1,6 @@ . + * + * @package phing */ /** @@ -24,8 +26,8 @@ * Used to check if a class can contain tasks (via instanceof) * * @author Andreas Aderhold - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.5 $ $Date: 2005/10/04 19:13:44 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @access public * @package phing */ diff --git a/buildscripts/phing/classes/phing/UnknownElement.php b/buildscripts/phing/classes/phing/UnknownElement.php old mode 100644 new mode 100755 index 745130dc..b04365e7 --- a/buildscripts/phing/classes/phing/UnknownElement.php +++ b/buildscripts/phing/classes/phing/UnknownElement.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.9 $ + * @version $Id$ * @package phing */ class UnknownElement extends Task { @@ -130,15 +130,19 @@ class UnknownElement extends Task { $realChild = $this->makeTask($child, $childWrapper, false); $parent->addTask($realChild); } else { - $realChild = $ih->createElement($this->project, $parent, $child->getTag()); + $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); } - - $child->handleChildren($realChild, $childWrapper); + + if ($realChild instanceof ProjectComponent) { + $child->handleChildren($realChild, $childWrapper); + } + if ($realChild instanceof Task) { $realChild->maybeConfigure(); } 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 @@ + + * @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 + * @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 @@ + + * @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 + * @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 @@ + + * @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 + * @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 @@ + + * @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 old mode 100644 new mode 100755 index c9f8c619..4489b16e --- a/buildscripts/phing/classes/phing/filters/BaseFilterReader.php +++ b/buildscripts/phing/classes/phing/filters/BaseFilterReader.php @@ -1,7 +1,7 @@ Yannick Lecaillez - * @version $Revision: 1.8 $ $Date: 2004/05/20 02:24:10 $ + * @version $Id$ * @access public * @see FilterReader * @package phing.filters @@ -147,11 +147,11 @@ class BaseFilterReader extends FilterReader { * @param string $msg Message to log. * @param int $level Priority level. */ - function log($msg, $level = PROJECT_MSG_INFO) { + 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 old mode 100644 new mode 100755 index 3d767b40..8d3b0810 --- a/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php +++ b/buildscripts/phing/classes/phing/filters/BaseParamFilterReader.php @@ -1,7 +1,7 @@ Yannick Lecaillez - * @copyright © 2003 seasonfive. All rights reserved - * @version $Revision: 1.5 $ $Date: 2005/02/27 20:52:08 $ + * @copyright � 2003 seasonfive. All rights reserved + * @version $Id$ * @access public * @see FilterReader * @package phing.filters @@ -66,4 +66,4 @@ class BaseParamFilterReader extends BaseFilterReader implements Parameterizable } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/ChainableReader.php b/buildscripts/phing/classes/phing/filters/ChainableReader.php index c7de07c4..2b773dbe 100644 --- a/buildscripts/phing/classes/phing/filters/ChainableReader.php +++ b/buildscripts/phing/classes/phing/filters/ChainableReader.php @@ -1,7 +1,7 @@ + diff --git a/buildscripts/phing/classes/phing/filters/ExpandProperties.php b/buildscripts/phing/classes/phing/filters/ExpandProperties.php old mode 100644 new mode 100755 index dfd98cc8..2517783f --- a/buildscripts/phing/classes/phing/filters/ExpandProperties.php +++ b/buildscripts/phing/classes/phing/filters/ExpandProperties.php @@ -1,7 +1,7 @@ * @author Hans Lellelid - * @version $Revision: 1.6 $ + * @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. @@ -57,7 +74,7 @@ class ExpandProperties extends BaseFilterReader implements ChainableReader { } $project = $this->getProject(); - $buffer = ProjectConfigurator::replaceProperties($project, $buffer, $project->getProperties()); + $buffer = ProjectConfigurator::replaceProperties($project, $buffer, $project->getProperties(), $this->logLevel); return $buffer; } @@ -79,4 +96,4 @@ class ExpandProperties extends BaseFilterReader implements ChainableReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/HeadFilter.php b/buildscripts/phing/classes/phing/filters/HeadFilter.php old mode 100644 new mode 100755 index 84673b4a..3cbcb51b --- a/buildscripts/phing/classes/phing/filters/HeadFilter.php +++ b/buildscripts/phing/classes/phing/filters/HeadFilter.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @version $Id$ * @access public * @see FilterReader * @package phing.filters @@ -158,4 +158,4 @@ class HeadFilter extends BaseParamFilterReader implements ChainableReader { } } -?> + 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 @@ +. +*/ + +include_once 'phing/filters/BaseParamFilterReader.php'; +include_once 'phing/filters/ChainableReader.php'; + +/** + * Encode data from in encoding to out encoding. + * + * Example: + *
+ * 
+ * 
+ * Or: + *
+ * 
+ *    
+ *    
+ * 
+ * 
+ * + * @author Alexey Shockov, + * @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 null. + * + * @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 old mode 100644 new mode 100755 index 8f3136b7..b84b62c1 --- a/buildscripts/phing/classes/phing/filters/LineContains.php +++ b/buildscripts/phing/classes/phing/filters/LineContains.php @@ -1,7 +1,7 @@ * @author Hans Lellelid - * @version $Revision: 1.11 $ + * @version $Id$ * @see PhingFilterReader * @package phing.filters */ @@ -153,7 +153,7 @@ class LineContains extends BaseParamFilterReader implements ChainableReader { } /** - * Adds a nested element. + * Adds a contains nested element. * * @return Contains The contains element added. * Must not be null. @@ -169,7 +169,7 @@ class LineContains extends BaseParamFilterReader implements ChainableReader { * * @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 null. + * Must not be null. */ function setContains($contains) { // type check, error must never occur, bad code of it does @@ -231,6 +231,8 @@ class LineContains extends BaseParamFilterReader implements ChainableReader { /** * Holds a contains element. + * + * @package phing.filters */ class Contains { @@ -255,4 +257,4 @@ class Contains { return $this->_value; } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php old mode 100644 new mode 100755 index dcbb532c..c603978f --- a/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php +++ b/buildscripts/phing/classes/phing/filters/LineContainsRegexp.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.8 $ + * @version $Id$ * @see FilterReader * @package phing.filters */ @@ -176,4 +176,4 @@ class LineContainsRegexp extends BaseParamFilterReader implements ChainableReade } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/PrefixLines.php b/buildscripts/phing/classes/phing/filters/PrefixLines.php old mode 100644 new mode 100755 index a5580f87..9edcc02a --- a/buildscripts/phing/classes/phing/filters/PrefixLines.php +++ b/buildscripts/phing/classes/phing/filters/PrefixLines.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.6 $ $Date: 2004/03/15 14:45:06 $ + * @version $Id$ * @access public * @see FilterReader * @package phing.filters @@ -139,4 +139,4 @@ class PrefixLines extends BaseParamFilterReader implements ChainableReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php old mode 100644 new mode 100755 index 3c5592e8..70e8940f --- a/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php +++ b/buildscripts/phing/classes/phing/filters/ReplaceRegexp.php @@ -1,7 +1,7 @@ * * @author Hans Lellelid - * @version $Revision: 1.5 $ + * @version $Id$ * @package phing.filters */ class ReplaceRegexp extends BaseFilterReader implements ChainableReader { @@ -97,10 +97,10 @@ class ReplaceRegexp extends BaseFilterReader implements ChainableReader { $regexp = $exptype->getRegexp($this->project); try { $buffer = $regexp->replace($buffer); - $this->log("Performing regexp replace: /".$regexp->getPattern()."/".$regexp->getReplace()."/g".($regexp->getIgnoreCase() ? 'i' : ''), PROJECT_MSG_VERBOSE); + $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); + $this->log("Error performing regexp replace: " . $e->getMessage(), Project::MSG_WARN); } } @@ -126,4 +126,4 @@ class ReplaceRegexp extends BaseFilterReader implements ChainableReader { } -?> + diff --git a/buildscripts/phing/classes/phing/filters/ReplaceTokens.php b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php old mode 100644 new mode 100755 index 999f734f..a5cd7521 --- a/buildscripts/phing/classes/phing/filters/ReplaceTokens.php +++ b/buildscripts/phing/classes/phing/filters/ReplaceTokens.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.14 $ $Date: 2005/06/16 15:09:10 $ + * @version $Id: 6c5d97f2254de3c08ac34baaabf6119c54a49a7d $ * @access public * @see BaseParamFilterReader * @package phing.filters @@ -142,7 +142,7 @@ class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { $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."\""); + $this->log("Replaced \"".$this->_beginToken . $key . $this->_endToken ."\" with \"".$replaceWith."\"", Project::MSG_VERBOSE); } return $replaceWith; @@ -169,7 +169,7 @@ class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { // filter buffer $buffer = preg_replace_callback( - "/".preg_quote($this->_beginToken)."([\w\.\-:]+?)".preg_quote($this->_endToken)."/", + "/".preg_quote($this->_beginToken, '/')."([\w\.\-:]+?)".preg_quote($this->_endToken, '/')."/", array($this, 'replaceTokenCallback'), $buffer); return $buffer; @@ -360,6 +360,8 @@ class ReplaceTokens extends BaseParamFilterReader implements ChainableReader { /** * Holds a token. + * + * @package phing.filters */ class Token { @@ -390,7 +392,16 @@ class Token { * @param string $value The value for this token. Must not be null. */ function setValue($value) { - $this->_value = (string) $value; + // special case for boolean values + if (is_bool($value)) { + if ($value) { + $this->_value = "true"; + } else { + $this->_value = "false"; + } + } else { + $this->_value = (string) $value; + } } /** @@ -410,6 +421,15 @@ class Token { function getValue() { return $this->_value; } + + /** + * Sets the token value from text. + * + * @param string $value The value for this token. Must not be null. + */ + 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 @@ +. +*/ + +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: + *
+ *  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.
+ * 
+ * Example: + * + *

+ *   
+ *   
+ * 
+ * + * @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 < 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 null. + * + * @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 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 old mode 100644 new mode 100755 index c5a06129..08d1aa6b --- a/buildscripts/phing/classes/phing/filters/StripLineBreaks.php +++ b/buildscripts/phing/classes/phing/filters/StripLineBreaks.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.8 $ $Date: 2004/03/15 14:45:06 $ + * @version $Id$ * @access public * @see BaseParamFilterReader * @package phing.filters @@ -145,4 +145,4 @@ class StripLineBreaks extends BaseParamFilterReader implements ChainableReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/StripLineComments.php b/buildscripts/phing/classes/phing/filters/StripLineComments.php old mode 100644 new mode 100755 index 5d97979a..2a19ca25 --- a/buildscripts/phing/classes/phing/filters/StripLineComments.php +++ b/buildscripts/phing/classes/phing/filters/StripLineComments.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.8 $ $Date: 2005/02/27 20:52:08 $ + * @version $Id$ * @access public * @see BaseParamFilterReader * @package phing.filters @@ -175,9 +175,11 @@ class StripLineComments extends BaseParamFilterReader implements ChainableReader } } -/* +/** * The class that holds a comment representation. -*/ + * + * @package phing.filters + */ class Comment { /** The prefix for a line comment. */ @@ -202,4 +204,4 @@ class Comment { return $this->_value; } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/StripPhpComments.php b/buildscripts/phing/classes/phing/filters/StripPhpComments.php old mode 100644 new mode 100755 index 9e21eed3..0abb8a67 --- a/buildscripts/phing/classes/phing/filters/StripPhpComments.php +++ b/buildscripts/phing/classes/phing/filters/StripPhpComments.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @version $Revision: 1.6 $ $Date: 2004/07/16 01:36:35 $ + * @version $Id$ * @access public * @see FilterReader * @package phing.filters - * @todo -c use new PHP functions to perform this instead of regex. */ class StripPhpComments extends BaseFilterReader implements ChainableReader { /** @@ -171,7 +170,7 @@ class StripPhpComments extends BaseFilterReader implements ChainableReader { } /** - * Creates a new StripJavaComments using the passed in + * Creates a new StripPhpComments using the passed in * Reader for instantiation. * * @param reader A Reader object providing the underlying stream. @@ -187,4 +186,3 @@ class StripPhpComments extends BaseFilterReader implements ChainableReader { } } -?> \ No newline at end of file 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 @@ +. +*/ + +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 null. + * + * @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 old mode 100644 new mode 100755 index 7293d3b5..80d3c215 --- a/buildscripts/phing/classes/phing/filters/TabToSpaces.php +++ b/buildscripts/phing/classes/phing/filters/TabToSpaces.php @@ -1,7 +1,7 @@ * @author Hans Lellelid - * @version $Revision: 1.9 $ + * @version $Id$ * @see BaseParamFilterReader * @package phing.filters */ @@ -141,4 +141,4 @@ class TabToSpaces extends BaseParamFilterReader implements ChainableReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/TailFilter.php b/buildscripts/phing/classes/phing/filters/TailFilter.php old mode 100644 new mode 100755 index a6af6e4b..95a9c6f5 --- a/buildscripts/phing/classes/phing/filters/TailFilter.php +++ b/buildscripts/phing/classes/phing/filters/TailFilter.php @@ -1,7 +1,7 @@ Yannick Lecaillez * @author hans lellelid, hans@velum.net - * @copyright © 2003 seasonfive. All rights reserved - * @version $Revision: 1.7 $ + * @copyright � 2003 seasonfive. All rights reserved + * @version $Id$ * @see BaseParamFilterReader * @package phing.filters */ @@ -154,4 +154,4 @@ class TailFilter extends BaseParamFilterReader implements ChainableReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/filters/TidyFilter.php b/buildscripts/phing/classes/phing/filters/TidyFilter.php old mode 100644 new mode 100755 index 10d75fc4..22abcee5 --- a/buildscripts/phing/classes/phing/filters/TidyFilter.php +++ b/buildscripts/phing/classes/phing/filters/TidyFilter.php @@ -1,6 +1,6 @@ * * @author Hans Lellelid - * @version $Revision: 1.2 $ $Date: 2005/12/08 19:15:20 $ + * @version $Id$ * @package phing.filters */ class TidyFilter extends BaseParamFilterReader implements ChainableReader { - - /** @var string Encoding of resulting document. */ - private $encoding = 'utf8'; + + /** @var string Encoding of resulting document. */ + private $encoding = 'utf8'; /** @var array Parameter[] */ - private $configParameters = array(); + 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 element (which is a Parameter). - * @return Parameter - */ - public function createConfig() { - $num = array_push($this->configParameters, new Parameter()); + /** + * 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 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; - } - + } + + /** + * 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. * @@ -94,29 +94,29 @@ class TidyFilter extends BaseParamFilterReader implements ChainableReader { * 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() ) { + + 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(); + + $config = $this->getDistilledConfig(); + + $tidy = new Tidy(); + $tidy->parseString($buffer, $config, $this->encoding); + $tidy->cleanRepair(); - return tidy_get_output($tidy); - + return tidy_get_output($tidy); + } @@ -131,32 +131,32 @@ class TidyFilter extends BaseParamFilterReader implements ChainableReader { */ public function chain(Reader $reader) { $newFilter = new TidyFilter($reader); - $newFilter->setConfigParameters($this->configParameters); - $newFilter->setEncoding($this->encoding); + $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 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()); - } - - } - - } - } + 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 old mode 100644 new mode 100755 index f71823e3..b2a4264c --- a/buildscripts/phing/classes/phing/filters/TranslateGettext.php +++ b/buildscripts/phing/classes/phing/filters/TranslateGettext.php @@ -1,7 +1,7 @@ * * @author Hans Lellelid - * @version $Revision: 1.11 $ $Date: 2005/12/08 15:59:56 $ + * @version $Id$ * @access public * @see BaseFilterReader * @package phing.filters @@ -140,7 +140,7 @@ class TranslateGettext extends BaseParamFilterReader implements ChainableReader protected function initEnvironment() { $this->storedLocale = getenv("LANG"); - $this->log("Setting locale to " . $this->locale, PROJECT_MSG_DEBUG); + $this->log("Setting locale to " . $this->locale, Project::MSG_DEBUG); putenv("LANG=".$this->locale); $ret = setlocale(LC_ALL, $this->locale); if ($ret === false) { @@ -150,7 +150,7 @@ class TranslateGettext extends BaseParamFilterReader implements ChainableReader throw new BuildException($msg); } - $this->log("Binding domain '".$this->domain."' to " . $this->dir, PROJECT_MSG_DEBUG); + $this->log("Binding domain '".$this->domain."' to " . $this->dir, Project::MSG_DEBUG); bindtextdomain($this->domain, $this->dir->getAbsolutePath()); textdomain($this->domain); } @@ -181,7 +181,7 @@ class TranslateGettext extends BaseParamFilterReader implements ChainableReader $charbefore = $matches[1]; $msgid = $matches[2]; $translated = gettext($msgid); - $this->log("Translating \"$msgid\" => \"$translated\"", PROJECT_MSG_DEBUG); + $this->log("Translating \"$msgid\" => \"$translated\"", Project::MSG_DEBUG); return $charbefore . '"' . $translated . '"'; } @@ -231,7 +231,7 @@ class TranslateGettext extends BaseParamFilterReader implements ChainableReader $matches = array(); if (preg_match('/([^\w]|^)(gettext\([^\)]+\))/', $buffer, $matches)) { - $this->log("Unable to perform translation on: " . $matches[2], PROJECT_MSG_WARN); + $this->log("Unable to perform translation on: " . $matches[2], Project::MSG_WARN); } $this->restoreEnvironment(); @@ -282,4 +282,4 @@ class TranslateGettext extends BaseParamFilterReader implements ChainableReader } } -?> + 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 @@ +. + */ + +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 + * @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 null. + * + * @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 index 0b8c4e6f..8866bff7 100644 --- a/buildscripts/phing/classes/phing/filters/XsltFilter.php +++ b/buildscripts/phing/classes/phing/filters/XsltFilter.php @@ -1,7 +1,7 @@ * @author Yannick Lecaillez * @author Andreas Aderhold - * @version $Revision: 1.16 $ + * @version $Id: 057af49d450e4c137127acc0f5331368e7a76183 $ * @see FilterReader * @package phing.filters */ @@ -60,6 +60,26 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { */ 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 nested element. * @return XSLTParam @@ -120,6 +140,46 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { 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. @@ -150,7 +210,7 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { } if(empty($_xml)) { - $this->log("XML file is empty!", PROJECT_MSG_WARN); + $this->log("XML file is empty!", Project::MSG_WARN); return ''; // return empty string, don't attempt to apply XSLT } @@ -159,7 +219,7 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { $xslFr = new FileReader($this->xslFile); $xslFr->readInto($_xsl); - $this->log("Tranforming XML " . $this->in->getResource() . " using style " . $this->xslFile->getPath(), PROJECT_MSG_VERBOSE); + $this->log("Tranforming XML " . $this->in->getResource() . " using style " . $this->xslFile->getPath(), Project::MSG_VERBOSE); $out = ''; try { @@ -185,8 +245,13 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { $processor = new XSLTProcessor(); - $xmlDom = new DOMDocument(); - $xslDom = new DOMDocument(); + // 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); @@ -201,13 +266,16 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { // 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); + $this->log("Setting XSLT param: " . $param->getName() . "=>" . $param->getExpression(), Project::MSG_DEBUG); $processor->setParameter(null, $param->getName(), $param->getExpression()); } - $result = $processor->transformToXML($xmlDom); + $errorlevel = error_reporting(); + error_reporting($errorlevel & ~E_WARNING); + @$result = $processor->transformToXML($xmlDom); + error_reporting($errorlevel); - if ( !$result ) { + if (false === $result) { //$errno = xslt_errno($processor); //$err = xslt_error($processor); throw new BuildException("XSLT Error"); @@ -262,6 +330,8 @@ class XsltFilter extends BaseParamFilterReader implements ChainableReader { /** * Class that holds an XSLT parameter. + * + * @package phing.filters */ class XSLTParam { @@ -285,6 +355,28 @@ class XSLTParam { 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 @@ -314,4 +406,3 @@ class XSLTParam { } } -?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php old mode 100644 new mode 100755 index 80508a82..c465d0a1 --- a/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php +++ b/buildscripts/phing/classes/phing/filters/util/ChainReaderHelper.php @@ -1,6 +1,6 @@ Yannick Lecaillez - * @version $Revision: 1.8 $ $Date: 2005/02/27 20:52:09 $ + * @version $Id$ * @access public * @package phing.filters.util */ @@ -181,4 +181,3 @@ class ChainReaderHelper { } -?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php old mode 100644 new mode 100755 index 34bc5943..f47e155c --- a/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php +++ b/buildscripts/phing/classes/phing/filters/util/IniFileTokenReader.php @@ -1,6 +1,6 @@ file === null) { @@ -93,4 +94,4 @@ class IniFileTokenReader extends TokenReader { } } -?> + diff --git a/buildscripts/phing/classes/phing/input/DefaultInputHandler.php b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php old mode 100644 new mode 100755 index 8ce76cdd..5e53c878 --- a/buildscripts/phing/classes/phing/input/DefaultInputHandler.php +++ b/buildscripts/phing/classes/phing/input/DefaultInputHandler.php @@ -1,7 +1,7 @@ (Phing) * @author Stefan Bodewig (Ant) - * @version $Revision: 1.6 $ + * @version $Id$ * @package phing.input */ class DefaultInputHandler implements InputHandler { @@ -66,15 +66,18 @@ class DefaultInputHandler implements InputHandler { */ protected function getPrompt(InputRequest $request) { $prompt = $request->getPrompt(); + $defaultValue = $request->getDefaultValue(); - // use is_a() to avoid needing the class to be loaded - if (is_a($request, 'YesNoInputRequest')) { // (yes/no) + if ($request instanceof YesNoInputRequest) { + $choices = $request->getChoices(); + $defaultValue = $choices[(int) !$request->getDefaultValue()]; $prompt .= '(' . implode('/', $request->getChoices()) .')'; - } elseif (is_a($request, 'MultipleChoiceInputRequest')) { // (a,b,c,d) + } elseif ($request instanceof MultipleChoiceInputRequest) { // (a,b,c,d) $prompt .= '(' . implode(',', $request->getChoices()) . ')'; } + if ($request->getDefaultValue() !== null) { - $prompt .= ' ['.$request->getDefaultValue().']'; + $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 old mode 100644 new mode 100755 index 68fad7b5..9a414fd4 --- a/buildscripts/phing/classes/phing/input/InputHandler.php +++ b/buildscripts/phing/classes/phing/input/InputHandler.php @@ -1,7 +1,7 @@ - * @version $Revision: 1.3 $ + * @version $Id$ * @package phing.input */ interface InputHandler { diff --git a/buildscripts/phing/classes/phing/input/InputRequest.php b/buildscripts/phing/classes/phing/input/InputRequest.php old mode 100644 new mode 100755 index 7bfe8def..1d9e156d --- a/buildscripts/phing/classes/phing/input/InputRequest.php +++ b/buildscripts/phing/classes/phing/input/InputRequest.php @@ -1,7 +1,7 @@ (Phing) * @author Stefan Bodewig (Ant) - * @version $Revision: 1.4 $ + * @version $Id$ * @package phing.input */ class InputRequest { diff --git a/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php old mode 100644 new mode 100755 index d4ea1212..24e93b58 --- a/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php +++ b/buildscripts/phing/classes/phing/input/MultipleChoiceInputRequest.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.5 $ + * @version $Id$ * @package phing.input */ class MultipleChoiceInputRequest extends InputRequest { diff --git a/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php b/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php deleted file mode 100644 index e588cead..00000000 --- a/buildscripts/phing/classes/phing/input/PropertyFileInputHandler.php +++ /dev/null @@ -1,129 +0,0 @@ -/* - * The Apache Software License, Version 1.1 - * - * Copyright (c) 2002 The Apache Software Foundation. All rights - * reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. The end-user documentation included with the redistribution, if - * any, must include the following acknowlegement: - * "This product includes software developed by the - * Apache Software Foundation (http://www.apache.org/)." - * Alternately, this acknowlegement may appear in the software itself, - * if and wherever such third-party acknowlegements normally appear. - * - * 4. The names "Ant" and "Apache Software - * Foundation" must not be used to endorse or promote products derived - * from this software without prior written permission. For written - * permission, please contact apache@apache.org. - * - * 5. Products derived from this software may not be called "Apache" - * nor may "Apache" appear in their names without prior written - * permission of the Apache Group. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.tools.ant.input; - -import org.apache.tools.ant.BuildException; - -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -/** - * Reads input from a property file, the file name is read from the - * system property ant.input.properties, the prompt is the key for input. - * - * @author Stefan Bodewig - * @version $Revision: 1.1 $ - * @since Ant 1.5 - */ -public class PropertyFileInputHandler implements InputHandler { - private Properties props = null; - - /** - * Name of the system property we expect to hold the file name. - */ - public static final String FILE_NAME_KEY = "ant.input.properties"; - - /** - * Empty no-arg constructor. - */ - public PropertyFileInputHandler() { - } - - /** - * Picks up the input from a property, using the prompt as the - * name of the property. - * - * @exception BuildException if no property of that name can be found. - */ - public void handleInput(InputRequest request) throws BuildException { - readProps(); - - Object o = props.get(request.getPrompt()); - if (o == null) { - throw new BuildException("Unable to find input for \'" - + request.getPrompt()+"\'"); - } - request.setInput(o.toString()); - if (!request.isInputValid()) { - throw new BuildException("Found invalid input " + o - + " for \'" + request.getPrompt() + "\'"); - } - } - - /** - * Reads the properties file if it hasn't already been read. - */ - private synchronized void readProps() throws BuildException { - if (props == null) { - String propsFile = System.getProperty(FILE_NAME_KEY); - if (propsFile == null) { - throw new BuildException("System property " - + FILE_NAME_KEY - + " for PropertyFileInputHandler not" - + " set"); - } - - props = new Properties(); - - try { - props.load(new FileInputStream(propsFile)); - } catch (IOException e) { - throw new BuildException("Couldn't load " + propsFile, e); - } - } - } - -} diff --git a/buildscripts/phing/classes/phing/input/YesNoInputRequest.php b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php old mode 100644 new mode 100755 index e34863d5..1a712327 --- a/buildscripts/phing/classes/phing/input/YesNoInputRequest.php +++ b/buildscripts/phing/classes/phing/input/YesNoInputRequest.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.4 $ + * @version $Id: 659526fec1ed2e66d5b9308fba48924ea3dda494 $ * @package phing.input */ class YesNoInputRequest extends MultipleChoiceInputRequest { diff --git a/buildscripts/phing/classes/phing/lib/Capsule.php b/buildscripts/phing/classes/phing/lib/Capsule.php old mode 100644 new mode 100755 index bab05486..e6885a6a --- a/buildscripts/phing/classes/phing/lib/Capsule.php +++ b/buildscripts/phing/classes/phing/lib/Capsule.php @@ -9,7 +9,8 @@ * the business logic from display / output logic. * * @author Hans Lellelid - * @version $Revision: 1.9 $ $Date: 2004/08/31 20:12:02 $ + * @version $Id$ + * @package phing.lib */ class Capsule { diff --git a/buildscripts/phing/classes/phing/lib/Zip.php b/buildscripts/phing/classes/phing/lib/Zip.php deleted file mode 100644 index 70d31595..00000000 --- a/buildscripts/phing/classes/phing/lib/Zip.php +++ /dev/null @@ -1,3588 +0,0 @@ - | -// +----------------------------------------------------------------------+ -// -// $Id: Zip.php,v 1.3 2005/12/27 16:05:57 hlellelid Exp $ - - // ----- Constants - define( 'ARCHIVE_ZIP_READ_BLOCK_SIZE', 2048 ); - - // ----- File list separator - define( 'ARCHIVE_ZIP_SEPARATOR', ',' ); - - // ----- Optional static temporary directory - // By default temporary files are generated in the script current - // path. - // If defined : - // - MUST BE terminated by a '/'. - // - MUST be a valid, already created directory - // Samples : - // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '/temp/' ); - // define( 'ARCHIVE_ZIP_TEMPORARY_DIR', 'C:/Temp/' ); - define( 'ARCHIVE_ZIP_TEMPORARY_DIR', '' ); - - // ----- Error codes - define( 'ARCHIVE_ZIP_ERR_NO_ERROR', 0 ); - define( 'ARCHIVE_ZIP_ERR_WRITE_OPEN_FAIL', -1 ); - define( 'ARCHIVE_ZIP_ERR_READ_OPEN_FAIL', -2 ); - define( 'ARCHIVE_ZIP_ERR_INVALID_PARAMETER', -3 ); - define( 'ARCHIVE_ZIP_ERR_MISSING_FILE', -4 ); - define( 'ARCHIVE_ZIP_ERR_FILENAME_TOO_LONG', -5 ); - define( 'ARCHIVE_ZIP_ERR_INVALID_ZIP', -6 ); - define( 'ARCHIVE_ZIP_ERR_BAD_EXTRACTED_FILE', -7 ); - define( 'ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL', -8 ); - define( 'ARCHIVE_ZIP_ERR_BAD_EXTENSION', -9 ); - define( 'ARCHIVE_ZIP_ERR_BAD_FORMAT', -10 ); - define( 'ARCHIVE_ZIP_ERR_DELETE_FILE_FAIL', -11 ); - define( 'ARCHIVE_ZIP_ERR_RENAME_FILE_FAIL', -12 ); - define( 'ARCHIVE_ZIP_ERR_BAD_CHECKSUM', -13 ); - define( 'ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP', -14 ); - define( 'ARCHIVE_ZIP_ERR_MISSING_OPTION_VALUE', -15 ); - define( 'ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE', -16 ); - - // ----- Warning codes - define( 'ARCHIVE_ZIP_WARN_NO_WARNING', 0 ); - define( 'ARCHIVE_ZIP_WARN_FILE_EXIST', 1 ); - - // ----- Methods parameters - define( 'ARCHIVE_ZIP_PARAM_PATH', 'path' ); - define( 'ARCHIVE_ZIP_PARAM_ADD_PATH', 'add_path' ); - define( 'ARCHIVE_ZIP_PARAM_REMOVE_PATH', 'remove_path' ); - define( 'ARCHIVE_ZIP_PARAM_REMOVE_ALL_PATH', 'remove_all_path' ); - define( 'ARCHIVE_ZIP_PARAM_SET_CHMOD', 'set_chmod' ); - define( 'ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING', 'extract_as_string' ); - define( 'ARCHIVE_ZIP_PARAM_NO_COMPRESSION', 'no_compression' ); - define( 'ARCHIVE_ZIP_PARAM_BY_NAME', 'by_name' ); - define( 'ARCHIVE_ZIP_PARAM_BY_INDEX', 'by_index' ); - define( 'ARCHIVE_ZIP_PARAM_BY_EREG', 'by_ereg' ); - define( 'ARCHIVE_ZIP_PARAM_BY_PREG', 'by_preg' ); - - define( 'ARCHIVE_ZIP_PARAM_PRE_EXTRACT', 'callback_pre_extract' ); - define( 'ARCHIVE_ZIP_PARAM_POST_EXTRACT', 'callback_post_extract' ); - define( 'ARCHIVE_ZIP_PARAM_PRE_ADD', 'callback_pre_add' ); - define( 'ARCHIVE_ZIP_PARAM_POST_ADD', 'callback_post_add' ); - - - -/** -* Class for manipulating zip archive files -* -* A class which provided common methods to manipulate ZIP formatted -* archive files. -* It provides creation, extraction, deletion and add features. -* -* @author Vincent Blavet -* @version $Revision: 1.3 $ -* @package phing.lib -*/ -class Archive_Zip -{ - /** - * The filename of the zip archive. - * - * @var string Name of the Zip file - */ - var $_zipname=''; - - /** - * File descriptor of the opened Zip file. - * - * @var int Internal zip file descriptor - */ - var $_zip_fd=0; - - /** - * @var int last error code - */ - var $_error_code=1; - - /** - * @var string Last error description - */ - var $_error_string=''; - - // {{{ constructor - /** - * Archive_Zip Class constructor. This flavour of the constructor only - * declare a new Archive_Zip object, identifying it by the name of the - * zip file. - * - * @param string $p_zipname The name of the zip archive to create - * @access public - */ - function __construct($p_zipname) - { - if (!extension_loaded('zlib')) { - throw new Exception("The extension 'zlib' couldn't be found.\n". - "Please make sure your version of PHP was built ". - "with 'zlib' support."); - } - - // ----- Set the attributes - $this->_zipname = $p_zipname; - $this->_zip_fd = 0; - } - // }}} - - // {{{ create() - /** - * This method creates a Zip Archive with the filename set with - * the constructor. - * The files and directories indicated in $p_filelist - * are added in the archive. - * When a directory is in the list, the directory and its content is added - * in the archive. - * The methods takes a variable list of parameters in $p_params. - * The supported parameters for this method are : - * 'add_path' : Add a path to the archived files. - * 'remove_path' : Remove the specified 'root' path of the archived files. - * 'remove_all_path' : Remove all the path of the archived files. - * 'no_compression' : The archived files will not be compressed. - * - * @access public - * @param mixed $p_filelist The list of the files or folders to add. - * It can be a string with filenames separated - * by a comma, or an array of filenames. - * @param mixed $p_params An array of variable parameters and values. - * @return mixed An array of file description on success, - * an error code on error - */ - function create($p_filelist, $p_params=0) - { - $this->_errorReset(); - - // ----- Set default values - if ($p_params === 0) { - $p_params = array(); - } - if ($this->_check_parameters($p_params, - array('no_compression' => false, - 'add_path' => "", - 'remove_path' => "", - 'remove_all_path' => false)) != 1) { - return 0; - } - - // ----- Look if the $p_filelist is really an array - $p_result_list = array(); - if (is_array($p_filelist)) { - $v_result = $this->_create($p_filelist, $p_result_list, $p_params); - } - - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list with the elements from the string - $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); - - $v_result = $this->_create($v_list, $p_result_list, $p_params); - } - - // ----- Invalid variable - else { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - 'Invalid variable type p_filelist'); - $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; - } - - if ($v_result != 1) { - return 0; - } - - return $p_result_list; - } - // }}} - - // {{{ add() - /** - * This method add files or directory in an existing Zip Archive. - * If the Zip Archive does not exist it is created. - * The files and directories to add are indicated in $p_filelist. - * When a directory is in the list, the directory and its content is added - * in the archive. - * The methods takes a variable list of parameters in $p_params. - * The supported parameters for this method are : - * 'add_path' : Add a path to the archived files. - * 'remove_path' : Remove the specified 'root' path of the archived files. - * 'remove_all_path' : Remove all the path of the archived files. - * 'no_compression' : The archived files will not be compressed. - * 'callback_pre_add' : A callback function that will be called before - * each entry archiving. - * 'callback_post_add' : A callback function that will be called after - * each entry archiving. - * - * @access public - * @param mixed $p_filelist The list of the files or folders to add. - * It can be a string with filenames separated - * by a comma, or an array of filenames. - * @param mixed $p_params An array of variable parameters and values. - * @return mixed An array of file description on success, - * 0 on an unrecoverable failure, an error code is logged. - */ - function add($p_filelist, $p_params=0) - { - $this->_errorReset(); - - // ----- Set default values - if ($p_params === 0) { - $p_params = array(); - } - if ($this->_check_parameters($p_params, - array ('no_compression' => false, - 'add_path' => '', - 'remove_path' => '', - 'remove_all_path' => false, - 'callback_pre_add' => '', - 'callback_post_add' => '')) != 1) { - return 0; - } - - // ----- Look if the $p_filelist is really an array - $p_result_list = array(); - if (is_array($p_filelist)) { - // ----- Call the create fct - $v_result = $this->_add($p_filelist, $p_result_list, $p_params); - } - - // ----- Look if the $p_filelist is a string - else if (is_string($p_filelist)) { - // ----- Create a list with the elements from the string - $v_list = explode(ARCHIVE_ZIP_SEPARATOR, $p_filelist); - - // ----- Call the create fct - $v_result = $this->_add($v_list, $p_result_list, $p_params); - } - - // ----- Invalid variable - else { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - "add() : Invalid variable type p_filelist"); - $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; - } - - if ($v_result != 1) { - return 0; - } - - // ----- Return the result list - return $p_result_list; - } - // }}} - - // {{{ listContent() - /** - * This method gives the names and properties of the files and directories - * which are present in the zip archive. - * The properties of each entries in the list are : - * filename : Name of the file. - * For create() or add() it's the filename given by the user. - * For an extract() it's the filename of the extracted file. - * stored_filename : Name of the file / directory stored in the archive. - * size : Size of the stored file. - * compressed_size : Size of the file's data compressed in the archive - * (without the zip headers overhead) - * mtime : Last known modification date of the file (UNIX timestamp) - * comment : Comment associated with the file - * folder : true | false (indicates if the entry is a folder) - * index : index of the file in the archive (-1 when not available) - * status : status of the action on the entry (depending of the action) : - * Values are : - * ok : OK ! - * filtered : the file/dir was not extracted (filtered by user) - * already_a_directory : the file can't be extracted because a - * directory with the same name already - * exists - * write_protected : the file can't be extracted because a file - * with the same name already exists and is - * write protected - * newer_exist : the file was not extracted because a newer - * file already exists - * path_creation_fail : the file is not extracted because the - * folder does not exists and can't be - * created - * write_error : the file was not extracted because there was a - * error while writing the file - * read_error : the file was not extracted because there was a - * error while reading the file - * invalid_header : the file was not extracted because of an - * archive format error (bad file header) - * Note that each time a method can continue operating when there - * is an error on a single file, the error is only logged in the file status. - * - * @access public - * @return mixed An array of file description on success, - * 0 on an unrecoverable failure, an error code is logged. - */ - function listContent() - { - $this->_errorReset(); - - // ----- Check archive - if (!$this->_checkFormat()) { - return(0); - } - - $v_list = array(); - if ($this->_list($v_list) != 1) { - unset($v_list); - return(0); - } - - return $v_list; - } - // }}} - - // {{{ extract() - /** - * This method extract the files and folders which are in the zip archive. - * It can extract all the archive or a part of the archive by using filter - * feature (extract by name, by index, by ereg, by preg). The extraction - * can occur in the current path or an other path. - * All the advanced features are activated by the use of variable - * parameters. - * The return value is an array of entry descriptions which gives - * information on extracted files (See listContent()). - * The method may return a success value (an array) even if some files - * are not correctly extracted (see the file status in listContent()). - * The supported variable parameters for this method are : - * 'add_path' : Path where the files and directories are to be extracted - * 'remove_path' : First part ('root' part) of the memorized path - * (if similar) to remove while extracting. - * 'remove_all_path' : Remove all the memorized path while extracting. - * 'extract_as_string' : - * 'set_chmod' : After the extraction of the file the indicated mode - * will be set. - * 'by_name' : It can be a string with file/dir names separated by ',', - * or an array of file/dir names to extract from the archive. - * 'by_index' : A string with range of indexes separated by ',', - * (sample "1,3-5,12"). - * 'by_ereg' : A regular expression (ereg) that must match the extracted - * filename. - * 'by_preg' : A regular expression (preg) that must match the extracted - * filename. - * 'callback_pre_extract' : A callback function that will be called before - * each entry extraction. - * 'callback_post_extract' : A callback function that will be called after - * each entry extraction. - * - * @access public - * @param mixed $p_params An array of variable parameters and values. - * @return mixed An array of file description on success, - * 0 on an unrecoverable failure, an error code is logged. - */ - function extract($p_params=0) - { - - $this->_errorReset(); - - // ----- Check archive - if (!$this->_checkFormat()) { - return(0); - } - - // ----- Set default values - if ($p_params === 0) { - $p_params = array(); - } - if ($this->_check_parameters($p_params, - array ('extract_as_string' => false, - 'add_path' => '', - 'remove_path' => '', - 'remove_all_path' => false, - 'callback_pre_extract' => '', - 'callback_post_extract' => '', - 'set_chmod' => 0, - 'by_name' => '', - 'by_index' => '', - 'by_ereg' => '', - 'by_preg' => '') ) != 1) { - return 0; - } - - // ----- Call the extracting fct - $v_list = array(); - if ($this->_extractByRule($v_list, $p_params) != 1) { - unset($v_list); - return(0); - } - - return $v_list; - } - // }}} - - - // {{{ delete() - /** - * This methods delete archive entries in the zip archive. - * Notice that at least one filtering rule (set by the variable parameter - * list) must be set. - * Also notice that if you delete a folder entry, only the folder entry - * is deleted, not all the files bellonging to this folder. - * The supported variable parameters for this method are : - * 'by_name' : It can be a string with file/dir names separated by ',', - * or an array of file/dir names to delete from the archive. - * 'by_index' : A string with range of indexes separated by ',', - * (sample "1,3-5,12"). - * 'by_ereg' : A regular expression (ereg) that must match the extracted - * filename. - * 'by_preg' : A regular expression (preg) that must match the extracted - * filename. - * - * @access public - * @param mixed $p_params An array of variable parameters and values. - * @return mixed An array of file description on success, - * 0 on an unrecoverable failure, an error code is logged. - */ - function delete($p_params) - { - $this->_errorReset(); - - // ----- Check archive - if (!$this->_checkFormat()) { - return(0); - } - - // ----- Set default values - if ($this->_check_parameters($p_params, - array ('by_name' => '', - 'by_index' => '', - 'by_ereg' => '', - 'by_preg' => '') ) != 1) { - return 0; - } - - // ----- Check that at least one rule is set - if ( ($p_params['by_name'] == '') - && ($p_params['by_index'] == '') - && ($p_params['by_ereg'] == '') - && ($p_params['by_preg'] == '')) { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - 'At least one filtering rule must' - .' be set as parameter'); - return 0; - } - - // ----- Call the delete fct - $v_list = array(); - if ($this->_deleteByRule($v_list, $p_params) != 1) { - unset($v_list); - return(0); - } - - return $v_list; - } - // }}} - - // {{{ properties() - /** - * This method gives the global properties of the archive. - * The properties are : - * nb : Number of files in the archive - * comment : Comment associated with the archive file - * status : not_exist, ok - * - * @access public - * @param mixed $p_params {Description} - * @return mixed An array with the global properties or 0 on error. - */ - function properties() - { - $this->_errorReset(); - - // ----- Check archive - if (!$this->_checkFormat()) { - return(0); - } - - // ----- Default properties - $v_prop = array(); - $v_prop['comment'] = ''; - $v_prop['nb'] = 0; - $v_prop['status'] = 'not_exist'; - - // ----- Look if file exists - if (@is_file($this->_zipname)) { - // ----- Open the zip file - if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) { - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Unable to open archive \''.$this->_zipname - .'\' in binary read mode'); - return 0; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { - return 0; - } - - $this->_closeFd(); - - // ----- Set the user attributes - $v_prop['comment'] = $v_central_dir['comment']; - $v_prop['nb'] = $v_central_dir['entries']; - $v_prop['status'] = 'ok'; - } - - return $v_prop; - } - // }}} - - - // {{{ duplicate() - /** - * This method creates an archive by copying the content of an other one. - * If the archive already exist, it is replaced by the new one without - * any warning. - * - * @access public - * @param mixed $p_archive It can be a valid Archive_Zip object or - * the filename of a valid zip archive. - * @return integer 1 on success, 0 on failure. - */ - function duplicate($p_archive) - { - $this->_errorReset(); - - // ----- Look if the $p_archive is a Archive_Zip object - if ( (is_object($p_archive)) - && (strtolower(get_class($p_archive)) == 'archive_zip')) { - $v_result = $this->_duplicate($p_archive->_zipname); - } - - // ----- Look if the $p_archive is a string (so a filename) - else if (is_string($p_archive)) { - // ----- Check that $p_archive is a valid zip file - // TBC : Should also check the archive format - if (!is_file($p_archive)) { - $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, - "No file with filename '".$p_archive."'"); - $v_result = ARCHIVE_ZIP_ERR_MISSING_FILE; - } - else { - $v_result = $this->_duplicate($p_archive); - } - } - - // ----- Invalid variable - else { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - "Invalid variable type p_archive_to_add"); - $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; - } - - return $v_result; - } - // }}} - - // {{{ merge() - /** - * This method merge a valid zip archive at the end of the - * archive identified by the Archive_Zip object. - * If the archive ($this) does not exist, the merge becomes a duplicate. - * If the archive to add does not exist, the merge is a success. - * - * @access public - * @param mixed $p_archive_to_add It can be a valid Archive_Zip object or - * the filename of a valid zip archive. - * @return integer 1 on success, 0 on failure. - */ - function merge($p_archive_to_add) - { - $v_result = 1; - $this->_errorReset(); - - // ----- Check archive - if (!$this->_checkFormat()) { - return(0); - } - - // ----- Look if the $p_archive_to_add is a Archive_Zip object - if ( (is_object($p_archive_to_add)) - && (strtolower(get_class($p_archive_to_add)) == 'archive_zip')) { - $v_result = $this->_merge($p_archive_to_add); - } - - // ----- Look if the $p_archive_to_add is a string (so a filename) - else if (is_string($p_archive_to_add)) { - // ----- Create a temporary archive - $v_object_archive = new Archive_Zip($p_archive_to_add); - - // ----- Merge the archive - $v_result = $this->_merge($v_object_archive); - } - - // ----- Invalid variable - else { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - "Invalid variable type p_archive_to_add"); - $v_result = ARCHIVE_ZIP_ERR_INVALID_PARAMETER; - } - - return $v_result; - } - // }}} - - // {{{ errorCode() - /** - * Method that gives the lastest error code. - * - * @access public - * @return integer The error code value. - */ - function errorCode() - { - return($this->_error_code); - } - // }}} - - // {{{ errorName() - /** - * This method gives the latest error code name. - * - * @access public - * @param boolean $p_with_code If true, gives the name and the int value. - * @return string The error name. - */ - function errorName($p_with_code=false) - { - $v_const_list = get_defined_constants(); - - // ----- Extract error constants from all const. - for (reset($v_const_list); - list($v_key, $v_value) = each($v_const_list);) { - if (substr($v_key, 0, strlen('ARCHIVE_ZIP_ERR_')) - =='ARCHIVE_ZIP_ERR_') { - $v_error_list[$v_key] = $v_value; - } - } - - // ----- Search the name form the code value - $v_key=array_search($this->_error_code, $v_error_list, true); - if ($v_key!=false) { - $v_value = $v_key; - } - else { - $v_value = 'NoName'; - } - - if ($p_with_code) { - return($v_value.' ('.$this->_error_code.')'); - } - else { - return($v_value); - } - } - // }}} - - // {{{ errorInfo() - /** - * This method returns the description associated with the latest error. - * - * @access public - * @param boolean $p_full If set to true gives the description with the - * error code, the name and the description. - * If set to false gives only the description - * and the error code. - * @return string The error description. - */ - function errorInfo($p_full=false) - { - if ($p_full) { - return($this->errorName(true)." : ".$this->_error_string); - } - else { - return($this->_error_string." [code ".$this->_error_code."]"); - } - } - // }}} - - -// ----------------------------------------------------------------------------- -// ***** UNDER THIS LINE ARE DEFINED PRIVATE INTERNAL FUNCTIONS ***** -// ***** ***** -// ***** THESES FUNCTIONS MUST NOT BE USED DIRECTLY ***** -// ----------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _checkFormat() - // Description : - // This method check that the archive exists and is a valid zip archive. - // Several level of check exists. (futur) - // Parameters : - // $p_level : Level of check. Default 0. - // 0 : Check the first bytes (magic codes) (default value)) - // 1 : 0 + Check the central directory (futur) - // 2 : 1 + Check each file header (futur) - // Return Values : - // true on success, - // false on error, the error code is set. - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_checkFormat() - * - * { Description } - * - * @param integer $p_level - */ - function _checkFormat($p_level=0) - { - $v_result = true; - - // ----- Reset the error handler - $this->_errorReset(); - - // ----- Look if the file exits - if (!is_file($this->_zipname)) { - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, - "Missing archive file '".$this->_zipname."'"); - return(false); - } - - // ----- Check that the file is readeable - if (!is_readable($this->_zipname)) { - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - "Unable to read archive '".$this->_zipname."'"); - return(false); - } - - // ----- Check the magic code - // TBC - - // ----- Check the central header - // TBC - - // ----- Check each file header - // TBC - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _create() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_create() - * - * { Description } - * - */ - function _create($p_list, &$p_result_list, &$p_params) - { - $v_result=1; - $v_list_detail = array(); - - $p_add_dir = $p_params['add_path']; - $p_remove_dir = $p_params['remove_path']; - $p_remove_all_dir = $p_params['remove_all_path']; - - // ----- Open the file in write mode - if (($v_result = $this->_openFd('wb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Add the list of files - $v_result = $this->_addList($p_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); - - // ----- Close - $this->_closeFd(); - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _add() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_add() - * - * { Description } - * - */ - function _add($p_list, &$p_result_list, &$p_params) - { - $v_result=1; - $v_list_detail = array(); - - $p_add_dir = $p_params['add_path']; - $p_remove_dir = $p_params['remove_path']; - $p_remove_all_dir = $p_params['remove_all_path']; - - // ----- Look if the archive exists or is empty and need to be created - if ((!is_file($this->_zipname)) || (filesize($this->_zipname) == 0)) { - $v_result = $this->_create($p_list, $p_result_list, $p_params); - return $v_result; - } - - // ----- Open the zip file - if (($v_result=$this->_openFd('rb')) != 1) { - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) - { - $this->_closeFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->_zip_fd); - - // ----- Creates a temporay file - $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) - { - $this->_closeFd(); - - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Unable to open temporary file \'' - .$v_zip_temp_name.'\' in binary write mode'); - return Archive_Zip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the - // central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) - { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->_zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to - // use the following methods on the temporary fil and not the real archive - $v_swap = $this->_zip_fd; - $this->_zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->_addFileList($p_list, $v_header_list, - $p_add_dir, $p_remove_dir, - $p_remove_all_dir, $p_params)) != 1) - { - fclose($v_zip_temp_fd); - $this->_closeFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($this->_zip_fd); - - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->_zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Create the Central Dir files header - for ($i=0, $v_count=0; $i_writeCentralFileHeader($v_header_list[$i]))!=1) { - fclose($v_zip_temp_fd); - $this->_closeFd(); - @unlink($v_zip_temp_name); - - // ----- Return - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } - - // ----- Zip file comment - $v_comment = ''; - - // ----- Calculate the size of the central header - $v_size = @ftell($this->_zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $this->_writeCentralHeader($v_count - +$v_central_dir['entries'], - $v_size, $v_offset, - $v_comment)) != 1) { - // ----- Reset the file list - unset($v_header_list); - - // ----- Return - return $v_result; - } - - // ----- Swap back the file descriptor - $v_swap = $this->_zip_fd; - $this->_zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Close - $this->_closeFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->_zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->_zipname); - $this->_tool_Rename($v_zip_temp_name, $this->_zipname); - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _openFd() - // Description : - // Parameters : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_openFd() - * - * { Description } - * - */ - function _openFd($p_mode) - { - $v_result=1; - - // ----- Look if already open - if ($this->_zip_fd != 0) - { - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Zip file \''.$this->_zipname.'\' already open'); - return Archive_Zip::errorCode(); - } - - // ----- Open the zip file - if (($this->_zip_fd = @fopen($this->_zipname, $p_mode)) == 0) - { - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Unable to open archive \''.$this->_zipname - .'\' in '.$p_mode.' mode'); - return Archive_Zip::errorCode(); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _closeFd() - // Description : - // Parameters : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_closeFd() - * - * { Description } - * - */ - function _closeFd() - { - $v_result=1; - - if ($this->_zip_fd != 0) - @fclose($this->_zip_fd); - $this->_zip_fd = 0; - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _addList() - // Description : - // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is - // different from the real path of the file. This is usefull if you want to have PclTar - // running in any directory, and memorize relative path from an other directory. - // Parameters : - // $p_list : An array containing the file or directory names to add in the tar - // $p_result_list : list of added files with their properties (specially the status field) - // $p_add_dir : Path to add in the filename path archived - // $p_remove_dir : Path to remove in the filename path archived - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_addList() - * - * { Description } - * - */ - function _addList($p_list, &$p_result_list, - $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) - { - $v_result=1; - - // ----- Add the files - $v_header_list = array(); - if (($v_result = $this->_addFileList($p_list, $v_header_list, - $p_add_dir, $p_remove_dir, - $p_remove_all_dir, $p_params)) != 1) { - return $v_result; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($this->_zip_fd); - - // ----- Create the Central Dir files header - for ($i=0,$v_count=0; $i_writeCentralFileHeader($v_header_list[$i])) != 1) { - return $v_result; - } - $v_count++; - } - - // ----- Transform the header to a 'usable' info - $this->_convertHeader2FileInfo($v_header_list[$i], $p_result_list[$i]); - } - - // ----- Zip file comment - $v_comment = ''; - - // ----- Calculate the size of the central header - $v_size = @ftell($this->_zip_fd)-$v_offset; - - // ----- Create the central dir footer - if (($v_result = $this->_writeCentralHeader($v_count, $v_size, $v_offset, - $v_comment)) != 1) - { - // ----- Reset the file list - unset($v_header_list); - - // ----- Return - return $v_result; - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _addFileList() - // Description : - // $p_add_dir and $p_remove_dir will give the ability to memorize a path which is - // different from the real path of the file. This is usefull if you want to - // run the lib in any directory, and memorize relative path from an other directory. - // Parameters : - // $p_list : An array containing the file or directory names to add in the tar - // $p_result_list : list of added files with their properties (specially the status field) - // $p_add_dir : Path to add in the filename path archived - // $p_remove_dir : Path to remove in the filename path archived - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_addFileList() - * - * { Description } - * - */ - function _addFileList($p_list, &$p_result_list, - $p_add_dir, $p_remove_dir, $p_remove_all_dir, - &$p_params) - { - $v_result=1; - $v_header = array(); - - // ----- Recuperate the current number of elt in list - $v_nb = sizeof($p_result_list); - - // ----- Loop on the files - for ($j=0; ($j_tool_TranslateWinPath($p_list[$j], false); - - // ----- Skip empty file names - if ($p_filename == "") - { - continue; - } - - // ----- Check the filename - if (!file_exists($p_filename)) - { - $this->_errorLog(ARCHIVE_ZIP_ERR_MISSING_FILE, - "File '$p_filename' does not exists"); - return Archive_Zip::errorCode(); - } - - // ----- Look if it is a file or a dir with no all pathnre move - if ((is_file($p_filename)) || ((is_dir($p_filename)) && !$p_remove_all_dir)) { - // ----- Add the file - if (($v_result = $this->_addFile($p_filename, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) - { - // ----- Return status - return $v_result; - } - - // ----- Store the file infos - $p_result_list[$v_nb++] = $v_header; - } - - // ----- Look for directory - if (is_dir($p_filename)) - { - - // ----- Look for path - if ($p_filename != ".") - $v_path = $p_filename."/"; - else - $v_path = ""; - - // ----- Read the directory for files and sub-directories - $p_hdir = opendir($p_filename); - $p_hitem = readdir($p_hdir); // '.' directory - $p_hitem = readdir($p_hdir); // '..' directory - while ($p_hitem = readdir($p_hdir)) - { - - // ----- Look for a file - if (is_file($v_path.$p_hitem)) - { - - // ----- Add the file - if (($v_result = $this->_addFile($v_path.$p_hitem, $v_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params)) != 1) - { - // ----- Return status - return $v_result; - } - - // ----- Store the file infos - $p_result_list[$v_nb++] = $v_header; - } - - // ----- Recursive call to _addFileList() - else - { - - // ----- Need an array as parameter - $p_temp_list[0] = $v_path.$p_hitem; - $v_result = $this->_addFileList($p_temp_list, $p_result_list, $p_add_dir, $p_remove_dir, $p_remove_all_dir, $p_params); - - // ----- Update the number of elements of the list - $v_nb = sizeof($p_result_list); - } - } - - // ----- Free memory for the recursive loop - unset($p_temp_list); - unset($p_hdir); - unset($p_hitem); - } - } - - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _addFile() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_addFile() - * - * { Description } - * - */ - function _addFile($p_filename, &$p_header, $p_add_dir, $p_remove_dir, $p_remove_all_dir, &$p_params) - { - $v_result=1; - - if ($p_filename == "") - { - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, "Invalid file list parameter (invalid or empty list)"); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Calculate the stored filename - $v_stored_filename = $p_filename; - - // ----- Look for all path to remove - if ($p_remove_all_dir) { - $v_stored_filename = basename($p_filename); - } - // ----- Look for partial path remove - else if ($p_remove_dir != "") - { - if (substr($p_remove_dir, -1) != '/') - $p_remove_dir .= "/"; - - if ((substr($p_filename, 0, 2) == "./") || (substr($p_remove_dir, 0, 2) == "./")) - { - if ((substr($p_filename, 0, 2) == "./") && (substr($p_remove_dir, 0, 2) != "./")) - $p_remove_dir = "./".$p_remove_dir; - if ((substr($p_filename, 0, 2) != "./") && (substr($p_remove_dir, 0, 2) == "./")) - $p_remove_dir = substr($p_remove_dir, 2); - } - - $v_compare = $this->_tool_PathInclusion($p_remove_dir, $p_filename); - if ($v_compare > 0) -// if (substr($p_filename, 0, strlen($p_remove_dir)) == $p_remove_dir) - { - - if ($v_compare == 2) { - $v_stored_filename = ""; - } - else { - $v_stored_filename = substr($p_filename, strlen($p_remove_dir)); - } - } - } - // ----- Look for path to add - if ($p_add_dir != "") - { - if (substr($p_add_dir, -1) == "/") - $v_stored_filename = $p_add_dir.$v_stored_filename; - else - $v_stored_filename = $p_add_dir."/".$v_stored_filename; - } - - // ----- Filename (reduce the path of stored name) - $v_stored_filename = $this->_tool_PathReduction($v_stored_filename); - - - /* filename length moved after call-back in release 1.3 - // ----- Check the path length - if (strlen($v_stored_filename) > 0xFF) - { - // ----- Error log - $this->_errorLog(-5, "Stored file name is too long (max. 255) : '$v_stored_filename'"); - - // ----- Return - return Archive_Zip::errorCode(); - } - */ - - // ----- Set the file properties - clearstatcache(); - $p_header['version'] = 20; - $p_header['version_extracted'] = 10; - $p_header['flag'] = 0; - $p_header['compression'] = 0; - $p_header['mtime'] = filemtime($p_filename); - $p_header['crc'] = 0; - $p_header['compressed_size'] = 0; - $p_header['size'] = filesize($p_filename); - $p_header['filename_len'] = strlen($p_filename); - $p_header['extra_len'] = 0; - $p_header['comment_len'] = 0; - $p_header['disk'] = 0; - $p_header['internal'] = 0; - $p_header['external'] = (is_file($p_filename)?0xFE49FFE0:0x41FF0010); - $p_header['offset'] = 0; - $p_header['filename'] = $p_filename; - $p_header['stored_filename'] = $v_stored_filename; - $p_header['extra'] = ''; - $p_header['comment'] = ''; - $p_header['status'] = 'ok'; - $p_header['index'] = -1; - - // ----- Look for pre-add callback - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD])) - && ($p_params[ARCHIVE_ZIP_PARAM_PRE_ADD] != '')) { - - // ----- Generate a local information - $v_local_header = array(); - $this->_convertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. - eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_ADD].'(ARCHIVE_ZIP_PARAM_PRE_ADD, $v_local_header);'); - if ($v_result == 0) { - // ----- Change the file status - $p_header['status'] = "skipped"; - $v_result = 1; - } - - // ----- Update the informations - // Only some fields can be modified - if ($p_header['stored_filename'] != $v_local_header['stored_filename']) { - $p_header['stored_filename'] = $this->_tool_PathReduction($v_local_header['stored_filename']); - } - } - - // ----- Look for empty stored filename - if ($p_header['stored_filename'] == "") { - $p_header['status'] = "filtered"; - } - - // ----- Check the path length - if (strlen($p_header['stored_filename']) > 0xFF) { - $p_header['status'] = 'filename_too_long'; - } - - // ----- Look if no error, or file not skipped - if ($p_header['status'] == 'ok') { - - // ----- Look for a file - if (is_file($p_filename)) - { - // ----- Open the source file - if (($v_file = @fopen($p_filename, "rb")) == 0) { - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, "Unable to open file '$p_filename' in binary read mode"); - return Archive_Zip::errorCode(); - } - - if ($p_params['no_compression']) { - // ----- Read the file content - $v_content_compressed = @fread($v_file, $p_header['size']); - - // ----- Calculate the CRC - $p_header['crc'] = crc32($v_content_compressed); - } - else { - // ----- Read the file content - $v_content = @fread($v_file, $p_header['size']); - - // ----- Calculate the CRC - $p_header['crc'] = crc32($v_content); - - // ----- Compress the file - $v_content_compressed = gzdeflate($v_content); - } - - // ----- Set header parameters - $p_header['compressed_size'] = strlen($v_content_compressed); - $p_header['compression'] = 8; - - // ----- Call the header generation - if (($v_result = $this->_writeFileHeader($p_header)) != 1) { - @fclose($v_file); - return $v_result; - } - - // ----- Write the compressed content - $v_binary_data = pack('a'.$p_header['compressed_size'], $v_content_compressed); - @fwrite($this->_zip_fd, $v_binary_data, $p_header['compressed_size']); - - // ----- Close the file - @fclose($v_file); - } - - // ----- Look for a directory - else - { - // ----- Set the file properties - $p_header['filename'] .= '/'; - $p_header['filename_len']++; - $p_header['size'] = 0; - $p_header['external'] = 0x41FF0010; // Value for a folder : to be checked - - // ----- Call the header generation - if (($v_result = $this->_writeFileHeader($p_header)) != 1) - { - return $v_result; - } - } - } - - // ----- Look for pre-add callback - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_POST_ADD])) - && ($p_params[ARCHIVE_ZIP_PARAM_POST_ADD] != '')) { - - // ----- Generate a local information - $v_local_header = array(); - $this->_convertHeader2FileInfo($p_header, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. - eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_ADD].'(ARCHIVE_ZIP_PARAM_POST_ADD, $v_local_header);'); - if ($v_result == 0) { - // ----- Ignored - $v_result = 1; - } - - // ----- Update the informations - // Nothing can be modified - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _writeFileHeader() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_writeFileHeader() - * - * { Description } - * - */ - function _writeFileHeader(&$p_header) - { - $v_result=1; - - // TBC - //for(reset($p_header); $key = key($p_header); next($p_header)) { - //} - - // ----- Store the offset position of the file - $p_header['offset'] = ftell($this->_zip_fd); - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - // ----- Packed data - $v_binary_data = pack("VvvvvvVVVvv", 0x04034b50, $p_header['version'], $p_header['flag'], - $p_header['compression'], $v_mtime, $v_mdate, - $p_header['crc'], $p_header['compressed_size'], $p_header['size'], - strlen($p_header['stored_filename']), $p_header['extra_len']); - - // ----- Write the first 148 bytes of the header in the archive - fputs($this->_zip_fd, $v_binary_data, 30); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _writeCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_writeCentralFileHeader() - * - * { Description } - * - */ - function _writeCentralFileHeader(&$p_header) - { - $v_result=1; - - // TBC - //for(reset($p_header); $key = key($p_header); next($p_header)) { - //} - - // ----- Transform UNIX mtime to DOS format mdate/mtime - $v_date = getdate($p_header['mtime']); - $v_mtime = ($v_date['hours']<<11) + ($v_date['minutes']<<5) + $v_date['seconds']/2; - $v_mdate = (($v_date['year']-1980)<<9) + ($v_date['mon']<<5) + $v_date['mday']; - - // ----- Packed data - $v_binary_data = pack("VvvvvvvVVVvvvvvVV", 0x02014b50, $p_header['version'], $p_header['version_extracted'], - $p_header['flag'], $p_header['compression'], $v_mtime, $v_mdate, $p_header['crc'], - $p_header['compressed_size'], $p_header['size'], - strlen($p_header['stored_filename']), $p_header['extra_len'], $p_header['comment_len'], - $p_header['disk'], $p_header['internal'], $p_header['external'], $p_header['offset']); - - // ----- Write the 42 bytes of the header in the zip file - fputs($this->_zip_fd, $v_binary_data, 46); - - // ----- Write the variable fields - if (strlen($p_header['stored_filename']) != 0) - { - fputs($this->_zip_fd, $p_header['stored_filename'], strlen($p_header['stored_filename'])); - } - if ($p_header['extra_len'] != 0) - { - fputs($this->_zip_fd, $p_header['extra'], $p_header['extra_len']); - } - if ($p_header['comment_len'] != 0) - { - fputs($this->_zip_fd, $p_header['comment'], $p_header['comment_len']); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _writeCentralHeader() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_writeCentralHeader() - * - * { Description } - * - */ - function _writeCentralHeader($p_nb_entries, $p_size, $p_offset, $p_comment) - { - $v_result=1; - - // ----- Packed data - $v_binary_data = pack("VvvvvVVv", 0x06054b50, 0, 0, $p_nb_entries, $p_nb_entries, $p_size, $p_offset, strlen($p_comment)); - - // ----- Write the 22 bytes of the header in the zip file - fputs($this->_zip_fd, $v_binary_data, 22); - - // ----- Write the variable fields - if (strlen($p_comment) != 0) - { - fputs($this->_zip_fd, $p_comment, strlen($p_comment)); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _list() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_list() - * - * { Description } - * - */ - function _list(&$p_list) - { - $v_result=1; - - // ----- Open the zip file - if (($this->_zip_fd = @fopen($this->_zipname, 'rb')) == 0) - { - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive \''.$this->_zipname.'\' in binary read mode'); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) - { - return $v_result; - } - - // ----- Go to beginning of Central Dir - @rewind($this->_zip_fd); - if (@fseek($this->_zip_fd, $v_central_dir['offset'])) - { - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Read each entry - for ($i=0; $i<$v_central_dir['entries']; $i++) - { - // ----- Read the file header - if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) - { - return $v_result; - } - $v_header['index'] = $i; - - // ----- Get the only interesting attributes - $this->_convertHeader2FileInfo($v_header, $p_list[$i]); - unset($v_header); - } - - // ----- Close the zip file - $this->_closeFd(); - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _convertHeader2FileInfo() - // Description : - // This function takes the file informations from the central directory - // entries and extract the interesting parameters that will be given back. - // The resulting file infos are set in the array $p_info - // $p_info['filename'] : Filename with full path. Given by user (add), - // extracted in the filesystem (extract). - // $p_info['stored_filename'] : Stored filename in the archive. - // $p_info['size'] = Size of the file. - // $p_info['compressed_size'] = Compressed size of the file. - // $p_info['mtime'] = Last modification date of the file. - // $p_info['comment'] = Comment associated with the file. - // $p_info['folder'] = true/false : indicates if the entry is a folder or not. - // $p_info['status'] = status of the action on the file. - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_convertHeader2FileInfo() - * - * { Description } - * - */ - function _convertHeader2FileInfo($p_header, &$p_info) - { - $v_result=1; - - // ----- Get the interesting attributes - $p_info['filename'] = $p_header['filename']; - $p_info['stored_filename'] = $p_header['stored_filename']; - $p_info['size'] = $p_header['size']; - $p_info['compressed_size'] = $p_header['compressed_size']; - $p_info['mtime'] = $p_header['mtime']; - $p_info['comment'] = $p_header['comment']; - $p_info['folder'] = (($p_header['external']&0x00000010)==0x00000010); - $p_info['index'] = $p_header['index']; - $p_info['status'] = $p_header['status']; - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _extractByRule() - // Description : - // Extract a file or directory depending of rules (by index, by name, ...) - // Parameters : - // $p_file_list : An array where will be placed the properties of each - // extracted file - // $p_path : Path to add while writing the extracted files - // $p_remove_path : Path to remove (from the file memorized path) while writing the - // extracted files. If the path does not match the file path, - // the file is extracted with its memorized path. - // $p_remove_path does not apply to 'list' mode. - // $p_path and $p_remove_path are commulative. - // Return Values : - // 1 on success,0 or less on error (see error code list) - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_extractByRule() - * - * { Description } - * - */ - function _extractByRule(&$p_file_list, &$p_params) - { - $v_result=1; - - $p_path = $p_params['add_path']; - $p_remove_path = $p_params['remove_path']; - $p_remove_all_path = $p_params['remove_all_path']; - - // ----- Check the path - if (($p_path == "") - || ((substr($p_path, 0, 1) != "/") - && (substr($p_path, 0, 3) != "../") && (substr($p_path,1,2)!=":/"))) - $p_path = "./".$p_path; - - // ----- Reduce the path last (and duplicated) '/' - if (($p_path != "./") && ($p_path != "/")) { - // ----- Look for the path end '/' - while (substr($p_path, -1) == "/") { - $p_path = substr($p_path, 0, strlen($p_path)-1); - } - } - - // ----- Look for path to remove format (should end by /) - if (($p_remove_path != "") && (substr($p_remove_path, -1) != '/')) { - $p_remove_path .= '/'; - } - $p_remove_path_size = strlen($p_remove_path); - - // ----- Open the zip file - if (($v_result = $this->_openFd('rb')) != 1) - { - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) - { - // ----- Close the zip file - $this->_closeFd(); - - return $v_result; - } - - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - - // ----- Read each entry - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { - // ----- Read next Central dir entry - @rewind($this->_zip_fd); - if (@fseek($this->_zip_fd, $v_pos_entry)) { - $this->_closeFd(); - - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, - 'Invalid archive size'); - - return Archive_Zip::errorCode(); - } - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->_readCentralFileHeader($v_header)) != 1) { - $this->_closeFd(); - - return $v_result; - } - - // ----- Store the index - $v_header['index'] = $i; - - // ----- Store the file position - $v_pos_entry = ftell($this->_zip_fd); - - // ----- Look for the specific extract rules - $v_extract = false; - - // ----- Look for extract by name rule - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; - ($j strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) - && (substr($v_header['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { - $v_extract = true; - } - } - // ----- Look for a filename - elseif ($v_header['stored_filename'] == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { - $v_extract = true; - } - } - } - - // ----- Look for extract by ereg rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { - - if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - - // ----- Look for extract by preg rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { - - if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], $v_header['stored_filename'])) { - $v_extract = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; ($j=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { - $v_extract = true; - } - if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - - // ----- Look for no rule, which means extract all the archive - else { - $v_extract = true; - } - - - // ----- Look for real extraction - if ($v_extract) - { - - // ----- Go to the file position - @rewind($this->_zip_fd); - if (@fseek($this->_zip_fd, $v_header['offset'])) - { - // ----- Close the zip file - $this->_closeFd(); - - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size'); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Look for extraction as string - if ($p_params[ARCHIVE_ZIP_PARAM_EXTRACT_AS_STRING]) { - - // ----- Extracting the file - if (($v_result = $this->_extractFileAsString($v_header, $v_string)) != 1) - { - // ----- Close the zip file - $this->_closeFd(); - - return $v_result; - } - - // ----- Get the only interesting attributes - if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1) - { - // ----- Close the zip file - $this->_closeFd(); - - return $v_result; - } - - // ----- Set the file content - $p_file_list[$v_nb_extracted]['content'] = $v_string; - - // ----- Next extracted file - $v_nb_extracted++; - } - else { - // ----- Extracting the file - if (($v_result = $this->_extractFile($v_header, $p_path, $p_remove_path, $p_remove_all_path, $p_params)) != 1) - { - // ----- Close the zip file - $this->_closeFd(); - - return $v_result; - } - - // ----- Get the only interesting attributes - if (($v_result = $this->_convertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) - { - // ----- Close the zip file - $this->_closeFd(); - - return $v_result; - } - } - } - } - - // ----- Close the zip file - $this->_closeFd(); - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _extractFile() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_extractFile() - * - * { Description } - * - */ - function _extractFile(&$p_entry, $p_path, $p_remove_path, $p_remove_all_path, &$p_params) - { - $v_result=1; - - // ----- Read the file header - if (($v_result = $this->_readFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } - - - // ----- Check that the file header is coherent with $p_entry info - // TBC - - // ----- Look for all path to remove - if ($p_remove_all_path == true) { - // ----- Get the basename of the path - $p_entry['filename'] = basename($p_entry['filename']); - } - - // ----- Look for path to remove - else if ($p_remove_path != "") - { - //if (strcmp($p_remove_path, $p_entry['filename'])==0) - if ($this->_tool_PathInclusion($p_remove_path, $p_entry['filename']) == 2) - { - - // ----- Change the file status - $p_entry['status'] = "filtered"; - - // ----- Return - return $v_result; - } - - $p_remove_path_size = strlen($p_remove_path); - if (substr($p_entry['filename'], 0, $p_remove_path_size) == $p_remove_path) - { - - // ----- Remove the path - $p_entry['filename'] = substr($p_entry['filename'], $p_remove_path_size); - - } - } - - // ----- Add the path - if ($p_path != '') - { - $p_entry['filename'] = $p_path."/".$p_entry['filename']; - } - - // ----- Look for pre-extract callback - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT])) - && ($p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT] != '')) { - - // ----- Generate a local information - $v_local_header = array(); - $this->_convertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. - eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_PRE_EXTRACT].'(ARCHIVE_ZIP_PARAM_PRE_EXTRACT, $v_local_header);'); - if ($v_result == 0) { - // ----- Change the file status - $p_entry['status'] = "skipped"; - $v_result = 1; - } - - // ----- Update the informations - // Only some fields can be modified - $p_entry['filename'] = $v_local_header['filename']; - } - - // ----- Trace - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Look for specific actions while the file exist - if (file_exists($p_entry['filename'])) - { - - // ----- Look if file is a directory - if (is_dir($p_entry['filename'])) - { - - // ----- Change the file status - $p_entry['status'] = "already_a_directory"; - - // ----- Return - //return $v_result; - } - // ----- Look if file is write protected - else if (!is_writeable($p_entry['filename'])) - { - - // ----- Change the file status - $p_entry['status'] = "write_protected"; - - // ----- Return - //return $v_result; - } - - // ----- Look if the extracted file is older - else if (filemtime($p_entry['filename']) > $p_entry['mtime']) - { - - // ----- Change the file status - $p_entry['status'] = "newer_exist"; - - // ----- Return - //return $v_result; - } - } - - // ----- Check the directory availability and create it if necessary - else { - if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/')) - $v_dir_to_check = $p_entry['filename']; - else if (!strstr($p_entry['filename'], "/")) - $v_dir_to_check = ""; - else - $v_dir_to_check = dirname($p_entry['filename']); - - if (($v_result = $this->_dirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) { - - // ----- Change the file status - $p_entry['status'] = "path_creation_fail"; - - // ----- Return - //return $v_result; - $v_result = 1; - } - } - } - - // ----- Look if extraction should be done - if ($p_entry['status'] == 'ok') { - - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) - { - - // ----- Look for not compressed file - if ($p_entry['compressed_size'] == $p_entry['size']) - { - - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) - { - - // ----- Change the file status - $p_entry['status'] = "write_error"; - - // ----- Return - return $v_result; - } - - - // ----- Read the file by ARCHIVE_ZIP_READ_BLOCK_SIZE octets blocks - $v_size = $p_entry['compressed_size']; - while ($v_size != 0) - { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->_zip_fd, $v_read_size); - $v_binary_data = pack('a'.$v_read_size, $v_buffer); - @fwrite($v_dest_file, $v_binary_data, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Closing the destination file - fclose($v_dest_file); - - // ----- Change the file mtime - touch($p_entry['filename'], $p_entry['mtime']); - } - else - { - // ----- Trace - - // ----- Opening destination file - if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) { - - // ----- Change the file status - $p_entry['status'] = "write_error"; - - return $v_result; - } - - - // ----- Read the compressed file in a buffer (one shot) - $v_buffer = @fread($this->_zip_fd, $p_entry['compressed_size']); - - // ----- Decompress the file - $v_file_content = gzinflate($v_buffer); - unset($v_buffer); - - // ----- Write the uncompressed data - @fwrite($v_dest_file, $v_file_content, $p_entry['size']); - unset($v_file_content); - - // ----- Closing the destination file - @fclose($v_dest_file); - - // ----- Change the file mtime - touch($p_entry['filename'], $p_entry['mtime']); - } - - // ----- Look for chmod option - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD])) - && ($p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD] != 0)) { - - // ----- Change the mode of the file - chmod($p_entry['filename'], $p_params[ARCHIVE_ZIP_PARAM_SET_CHMOD]); - } - - } - } - - // ----- Look for post-extract callback - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT])) - && ($p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT] != '')) { - - // ----- Generate a local information - $v_local_header = array(); - $this->_convertHeader2FileInfo($p_entry, $v_local_header); - - // ----- Call the callback - // Here I do not use call_user_func() because I need to send a reference to the - // header. - eval('$v_result = '.$p_params[ARCHIVE_ZIP_PARAM_POST_EXTRACT].'(ARCHIVE_ZIP_PARAM_POST_EXTRACT, $v_local_header);'); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _extractFileAsString() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_extractFileAsString() - * - * { Description } - * - */ - function _extractFileAsString(&$p_entry, &$p_string) - { - $v_result=1; - - // ----- Read the file header - $v_header = array(); - if (($v_result = $this->_readFileHeader($v_header)) != 1) - { - // ----- Return - return $v_result; - } - - - // ----- Check that the file header is coherent with $p_entry info - // TBC - - // ----- Trace - - // ----- Do the extraction (if not a folder) - if (!(($p_entry['external']&0x00000010)==0x00000010)) - { - // ----- Look for not compressed file - if ($p_entry['compressed_size'] == $p_entry['size']) - { - // ----- Trace - - // ----- Reading the file - $p_string = fread($this->_zip_fd, $p_entry['compressed_size']); - } - else - { - // ----- Trace - - // ----- Reading the file - $v_data = fread($this->_zip_fd, $p_entry['compressed_size']); - - // ----- Decompress the file - $p_string = gzinflate($v_data); - } - - // ----- Trace - } - else { - // TBC : error : can not extract a folder in a string - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _readFileHeader() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_readFileHeader() - * - * { Description } - * - */ - function _readFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->_zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x04034b50) - { - - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->_zip_fd, 26); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 26) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; - - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Extract the values - $v_data = unpack('vversion/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len', $v_binary_data); - - // ----- Get filename - $p_header['filename'] = fread($this->_zip_fd, $v_data['filename_len']); - - // ----- Get extra_fields - if ($v_data['extra_len'] != 0) { - $p_header['extra'] = fread($this->_zip_fd, $v_data['extra_len']); - } - else { - $p_header['extra'] = ''; - } - - // ----- Extract properties - $p_header['compression'] = $v_data['compression']; - $p_header['size'] = $v_data['size']; - $p_header['compressed_size'] = $v_data['compressed_size']; - $p_header['crc'] = $v_data['crc']; - $p_header['flag'] = $v_data['flag']; - - // ----- Recuperate date in UNIX format - $p_header['mdate'] = $v_data['mdate']; - $p_header['mtime'] = $v_data['mtime']; - if ($p_header['mdate'] && $p_header['mtime']) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - - } - else - { - $p_header['mtime'] = time(); - } - - // ----- Other informations - - // TBC - //for(reset($v_data); $key = key($v_data); next($v_data)) { - //} - - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; - - // ----- Set the status field - $p_header['status'] = "ok"; - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _readCentralFileHeader() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_readCentralFileHeader() - * - * { Description } - * - */ - function _readCentralFileHeader(&$p_header) - { - $v_result=1; - - // ----- Read the 4 bytes signature - $v_binary_data = @fread($this->_zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] != 0x02014b50) - { - - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, 'Invalid archive structure'); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Read the first 42 bytes of the header - $v_binary_data = fread($this->_zip_fd, 42); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 42) - { - $p_header['filename'] = ""; - $p_header['status'] = "invalid_header"; - - // ----- Error log - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, "Invalid block size : ".strlen($v_binary_data)); - - // ----- Return - return Archive_Zip::errorCode(); - } - - // ----- Extract the values - $p_header = unpack('vversion/vversion_extracted/vflag/vcompression/vmtime/vmdate/Vcrc/Vcompressed_size/Vsize/vfilename_len/vextra_len/vcomment_len/vdisk/vinternal/Vexternal/Voffset', $v_binary_data); - - // ----- Get filename - if ($p_header['filename_len'] != 0) - $p_header['filename'] = fread($this->_zip_fd, $p_header['filename_len']); - else - $p_header['filename'] = ''; - - // ----- Get extra - if ($p_header['extra_len'] != 0) - $p_header['extra'] = fread($this->_zip_fd, $p_header['extra_len']); - else - $p_header['extra'] = ''; - - // ----- Get comment - if ($p_header['comment_len'] != 0) - $p_header['comment'] = fread($this->_zip_fd, $p_header['comment_len']); - else - $p_header['comment'] = ''; - - // ----- Extract properties - - // ----- Recuperate date in UNIX format - if ($p_header['mdate'] && $p_header['mtime']) - { - // ----- Extract time - $v_hour = ($p_header['mtime'] & 0xF800) >> 11; - $v_minute = ($p_header['mtime'] & 0x07E0) >> 5; - $v_seconde = ($p_header['mtime'] & 0x001F)*2; - - // ----- Extract date - $v_year = (($p_header['mdate'] & 0xFE00) >> 9) + 1980; - $v_month = ($p_header['mdate'] & 0x01E0) >> 5; - $v_day = $p_header['mdate'] & 0x001F; - - // ----- Get UNIX date format - $p_header['mtime'] = mktime($v_hour, $v_minute, $v_seconde, $v_month, $v_day, $v_year); - - } - else - { - $p_header['mtime'] = time(); - } - - // ----- Set the stored filename - $p_header['stored_filename'] = $p_header['filename']; - - // ----- Set default status to ok - $p_header['status'] = 'ok'; - - // ----- Look if it is a directory - if (substr($p_header['filename'], -1) == '/') - { - $p_header['external'] = 0x41FF0010; - } - - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _readEndCentralDir() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_readEndCentralDir() - * - * { Description } - * - */ - function _readEndCentralDir(&$p_central_dir) - { - $v_result=1; - - // ----- Go to the end of the zip file - $v_size = filesize($this->_zipname); - @fseek($this->_zip_fd, $v_size); - if (@ftell($this->_zip_fd) != $v_size) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - 'Unable to go to the end of the archive \'' - .$this->_zipname.'\''); - return Archive_Zip::errorCode(); - } - - // ----- First try : look if this is an archive with no commentaries - // (most of the time) - // in this case the end of central dir is at 22 bytes of the file end - $v_found = 0; - if ($v_size > 26) { - @fseek($this->_zip_fd, $v_size-22); - if (($v_pos = @ftell($this->_zip_fd)) != ($v_size-22)) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - 'Unable to seek back to the middle of the archive \'' - .$this->_zipname.'\''); - return Archive_Zip::errorCode(); - } - - // ----- Read for bytes - $v_binary_data = @fread($this->_zip_fd, 4); - $v_data = unpack('Vid', $v_binary_data); - - // ----- Check signature - if ($v_data['id'] == 0x06054b50) { - $v_found = 1; - } - - $v_pos = ftell($this->_zip_fd); - } - - // ----- Go back to the maximum possible size of the Central Dir End Record - if (!$v_found) { - $v_maximum_size = 65557; // 0xFFFF + 22; - if ($v_maximum_size > $v_size) - $v_maximum_size = $v_size; - @fseek($this->_zip_fd, $v_size-$v_maximum_size); - if (@ftell($this->_zip_fd) != ($v_size-$v_maximum_size)) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - 'Unable to seek back to the middle of the archive \'' - .$this->_zipname.'\''); - return Archive_Zip::errorCode(); - } - - // ----- Read byte per byte in order to find the signature - $v_pos = ftell($this->_zip_fd); - $v_bytes = 0x00000000; - while ($v_pos < $v_size) { - // ----- Read a byte - $v_byte = @fread($this->_zip_fd, 1); - - // ----- Add the byte - $v_bytes = ($v_bytes << 8) | Ord($v_byte); - - // ----- Compare the bytes - if ($v_bytes == 0x504b0506) { - $v_pos++; - break; - } - - $v_pos++; - } - - // ----- Look if not found end of central dir - if ($v_pos == $v_size) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - "Unable to find End of Central Dir Record signature"); - return Archive_Zip::errorCode(); - } - } - - // ----- Read the first 18 bytes of the header - $v_binary_data = fread($this->_zip_fd, 18); - - // ----- Look for invalid block size - if (strlen($v_binary_data) != 18) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - "Invalid End of Central Dir Record size : " - .strlen($v_binary_data)); - return Archive_Zip::errorCode(); - } - - // ----- Extract the values - $v_data = unpack('vdisk/vdisk_start/vdisk_entries/ventries/Vsize/Voffset/vcomment_size', $v_binary_data); - - // ----- Check the global size - if (($v_pos + $v_data['comment_size'] + 18) != $v_size) { - $this->_errorLog(ARCHIVE_ZIP_ERR_BAD_FORMAT, - "Fail to find the right signature"); - return Archive_Zip::errorCode(); - } - - // ----- Get comment - if ($v_data['comment_size'] != 0) - $p_central_dir['comment'] = fread($this->_zip_fd, $v_data['comment_size']); - else - $p_central_dir['comment'] = ''; - - $p_central_dir['entries'] = $v_data['entries']; - $p_central_dir['disk_entries'] = $v_data['disk_entries']; - $p_central_dir['offset'] = $v_data['offset']; - $p_central_dir['size'] = $v_data['size']; - $p_central_dir['disk'] = $v_data['disk']; - $p_central_dir['disk_start'] = $v_data['disk_start']; - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _deleteByRule() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_deleteByRule() - * - * { Description } - * - */ - function _deleteByRule(&$p_result_list, &$p_params) - { - $v_result=1; - $v_list_detail = array(); - - // ----- Open the zip file - if (($v_result=$this->_openFd('rb')) != 1) - { - // ----- Return - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) - { - $this->_closeFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->_zip_fd); - - // ----- Scan all the files - // ----- Start at beginning of Central Dir - $v_pos_entry = $v_central_dir['offset']; - @rewind($this->_zip_fd); - if (@fseek($this->_zip_fd, $v_pos_entry)) { - // ----- Clean - $this->_closeFd(); - - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, - 'Invalid archive size'); - return Archive_Zip::errorCode(); - } - - // ----- Read each entry - $v_header_list = array(); - $j_start = 0; - for ($i=0, $v_nb_extracted=0; $i<$v_central_dir['entries']; $i++) { - - // ----- Read the file header - $v_header_list[$v_nb_extracted] = array(); - $v_result - = $this->_readCentralFileHeader($v_header_list[$v_nb_extracted]); - if ($v_result != 1) { - // ----- Clean - $this->_closeFd(); - - return $v_result; - } - - // ----- Store the index - $v_header_list[$v_nb_extracted]['index'] = $i; - - // ----- Look for the specific extract rules - $v_found = false; - - // ----- Look for extract by name rule - if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_NAME])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_NAME] != 0)) { - - // ----- Look if the filename is in the list - for ($j=0; - ($j strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) - && (substr($v_header_list[$v_nb_extracted]['stored_filename'], 0, strlen($p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { - $v_found = true; - } - elseif ( (($v_header_list[$v_nb_extracted]['external']&0x00000010)==0x00000010) /* Indicates a folder */ - && ($v_header_list[$v_nb_extracted]['stored_filename'].'/' == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j])) { - $v_found = true; - } - } - // ----- Look for a filename - elseif ($v_header_list[$v_nb_extracted]['stored_filename'] - == $p_params[ARCHIVE_ZIP_PARAM_BY_NAME][$j]) { - $v_found = true; - } - } - } - - // ----- Look for extract by ereg rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_EREG])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_EREG] != "")) { - - if (ereg($p_params[ARCHIVE_ZIP_PARAM_BY_EREG], - $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - - // ----- Look for extract by preg rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_PREG])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_PREG] != "")) { - - if (preg_match($p_params[ARCHIVE_ZIP_PARAM_BY_PREG], - $v_header_list[$v_nb_extracted]['stored_filename'])) { - $v_found = true; - } - } - - // ----- Look for extract by index rule - else if ( (isset($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX])) - && ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX] != 0)) { - - // ----- Look if the index is in the list - for ($j=$j_start; - ($j=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']) - && ($i<=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end'])) { - $v_found = true; - } - if ($i>=$p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['end']) { - $j_start = $j+1; - } - - if ($p_params[ARCHIVE_ZIP_PARAM_BY_INDEX][$j]['start']>$i) { - break; - } - } - } - - // ----- Look for deletion - if ($v_found) { - unset($v_header_list[$v_nb_extracted]); - } - else { - $v_nb_extracted++; - } - } - - // ----- Look if something need to be deleted - if ($v_nb_extracted > 0) { - - // ----- Creates a temporay file - $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-') - .'.tmp'; - - // ----- Creates a temporary zip archive - $v_temp_zip = new Archive_Zip($v_zip_temp_name); - - // ----- Open the temporary zip file in write mode - if (($v_result = $v_temp_zip->_openFd('wb')) != 1) { - $this->_closeFd(); - - // ----- Return - return $v_result; - } - - // ----- Look which file need to be kept - for ($i=0; $i_zip_fd); - if (@fseek($this->_zip_fd, $v_header_list[$i]['offset'])) { - // ----- Clean - $this->_closeFd(); - $v_temp_zip->_closeFd(); - @unlink($v_zip_temp_name); - - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_ARCHIVE_ZIP, - 'Invalid archive size'); - return Archive_Zip::errorCode(); - } - - // ----- Read the file header - if (($v_result = $this->_readFileHeader($v_header_list[$i])) != 1) { - // ----- Clean - $this->_closeFd(); - $v_temp_zip->_closeFd(); - @unlink($v_zip_temp_name); - - return $v_result; - } - - // ----- Write the file header - $v_result = $v_temp_zip->_writeFileHeader($v_header_list[$i]); - if ($v_result != 1) { - // ----- Clean - $this->_closeFd(); - $v_temp_zip->_closeFd(); - @unlink($v_zip_temp_name); - - return $v_result; - } - - // ----- Read/write the data block - $v_result = $this->_tool_CopyBlock($this->_zip_fd, - $v_temp_zip->_zip_fd, - $v_header_list[$i]['compressed_size']); - if ($v_result != 1) { - // ----- Clean - $this->_closeFd(); - $v_temp_zip->_closeFd(); - @unlink($v_zip_temp_name); - - return $v_result; - } - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($v_temp_zip->_zip_fd); - - // ----- Re-Create the Central Dir files header - for ($i=0; $i_writeCentralFileHeader($v_header_list[$i]); - if ($v_result != 1) { - // ----- Clean - $v_temp_zip->_closeFd(); - $this->_closeFd(); - @unlink($v_zip_temp_name); - - return $v_result; - } - - // ----- Transform the header to a 'usable' info - $v_temp_zip->_convertHeader2FileInfo($v_header_list[$i], - $p_result_list[$i]); - } - - - // ----- Zip file comment - $v_comment = ''; - - // ----- Calculate the size of the central header - $v_size = @ftell($v_temp_zip->_zip_fd)-$v_offset; - - // ----- Create the central dir footer - $v_result = $v_temp_zip->_writeCentralHeader(sizeof($v_header_list), - $v_size, $v_offset, - $v_comment); - if ($v_result != 1) { - // ----- Clean - unset($v_header_list); - $v_temp_zip->_closeFd(); - $this->_closeFd(); - @unlink($v_zip_temp_name); - - return $v_result; - } - - // ----- Close - $v_temp_zip->_closeFd(); - $this->_closeFd(); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->_zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->_zipname); - $this->_tool_Rename($v_zip_temp_name, $this->_zipname); - - // ----- Destroy the temporary archive - unset($v_temp_zip); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _dirCheck() - // Description : - // Check if a directory exists, if not it creates it and all the parents directory - // which may be useful. - // Parameters : - // $p_dir : Directory path to check. - // Return Values : - // 1 : OK - // -1 : Unable to create directory - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_dirCheck() - * - * { Description } - * - * @param [type] $p_is_dir - */ - function _dirCheck($p_dir, $p_is_dir=false) - { - $v_result = 1; - - // ----- Remove the final '/' - if (($p_is_dir) && (substr($p_dir, -1)=='/')) { - $p_dir = substr($p_dir, 0, strlen($p_dir)-1); - } - - // ----- Check the directory availability - if ((is_dir($p_dir)) || ($p_dir == "")) { - return 1; - } - - // ----- Extract parent directory - $p_parent_dir = dirname($p_dir); - - // ----- Just a check - if ($p_parent_dir != $p_dir) { - // ----- Look for parent directory - if ($p_parent_dir != "") { - if (($v_result = $this->_dirCheck($p_parent_dir)) != 1) { - return $v_result; - } - } - } - - // ----- Create the directory - if (!@mkdir($p_dir, 0777)) { - $this->_errorLog(ARCHIVE_ZIP_ERR_DIR_CREATE_FAIL, - "Unable to create directory '$p_dir'"); - return Archive_Zip::errorCode(); - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _merge() - // Description : - // If $p_archive_to_add does not exist, the function exit with a success result. - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_merge() - * - * { Description } - * - */ - function _merge(&$p_archive_to_add) - { - $v_result=1; - - // ----- Look if the archive_to_add exists - if (!is_file($p_archive_to_add->_zipname)) { - // ----- Nothing to merge, so merge is a success - return 1; - } - - // ----- Look if the archive exists - if (!is_file($this->_zipname)) { - // ----- Do a duplicate - $v_result = $this->_duplicate($p_archive_to_add->_zipname); - - return $v_result; - } - - // ----- Open the zip file - if (($v_result=$this->_openFd('rb')) != 1) { - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir = array(); - if (($v_result = $this->_readEndCentralDir($v_central_dir)) != 1) { - $this->_closeFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($this->_zip_fd); - - // ----- Open the archive_to_add file - if (($v_result=$p_archive_to_add->_openFd('rb')) != 1) { - $this->_closeFd(); - return $v_result; - } - - // ----- Read the central directory informations - $v_central_dir_to_add = array(); - $v_result = $p_archive_to_add->_readEndCentralDir($v_central_dir_to_add); - if ($v_result != 1) { - $this->_closeFd(); - $p_archive_to_add->_closeFd(); - return $v_result; - } - - // ----- Go to beginning of File - @rewind($p_archive_to_add->_zip_fd); - - // ----- Creates a temporay file - $v_zip_temp_name = ARCHIVE_ZIP_TEMPORARY_DIR.uniqid('archive_zip-').'.tmp'; - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0) { - $this->_closeFd(); - $p_archive_to_add->_closeFd(); - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Unable to open temporary file \'' - .$v_zip_temp_name.'\' in binary write mode'); - return Archive_Zip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the - // central dir - $v_size = $v_central_dir['offset']; - while ($v_size != 0) { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = fread($this->_zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Copy the files from the archive_to_add into the temporary file - $v_size = $v_central_dir_to_add['offset']; - while ($v_size != 0) { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = fread($p_archive_to_add->_zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Store the offset of the central dir - $v_offset = @ftell($v_zip_temp_fd); - - // ----- Copy the block of file headers from the old archive - $v_size = $v_central_dir['size']; - while ($v_size != 0) { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($this->_zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Copy the block of file headers from the archive_to_add - $v_size = $v_central_dir_to_add['size']; - while ($v_size != 0) { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_archive_to_add->_zip_fd, $v_read_size); - @fwrite($v_zip_temp_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Zip file comment - // TBC : I should merge the two comments - $v_comment = ''; - - // ----- Calculate the size of the (new) central header - $v_size = @ftell($v_zip_temp_fd)-$v_offset; - - // ----- Swap the file descriptor - // Here is a trick : I swap the temporary fd with the zip fd, in order to use - // the following methods on the temporary fil and not the real archive fd - $v_swap = $this->_zip_fd; - $this->_zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Create the central dir footer - if (($v_result = $this->_writeCentralHeader($v_central_dir['entries'] - +$v_central_dir_to_add['entries'], - $v_size, $v_offset, - $v_comment)) != 1) { - $this->_closeFd(); - $p_archive_to_add->_closeFd(); - @fclose($v_zip_temp_fd); - $this->_zip_fd = null; - - // ----- Reset the file list - unset($v_header_list); - - // ----- Return - return $v_result; - } - - // ----- Swap back the file descriptor - $v_swap = $this->_zip_fd; - $this->_zip_fd = $v_zip_temp_fd; - $v_zip_temp_fd = $v_swap; - - // ----- Close - $this->_closeFd(); - $p_archive_to_add->_closeFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - // ----- Delete the zip file - // TBC : I should test the result ... - @unlink($this->_zipname); - - // ----- Rename the temporary file - // TBC : I should test the result ... - //@rename($v_zip_temp_name, $this->_zipname); - $this->_tool_Rename($v_zip_temp_name, $this->_zipname); - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _duplicate() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_duplicate() - * - * { Description } - * - */ - function _duplicate($p_archive_filename) - { - $v_result=1; - - // ----- Look if the $p_archive_filename exists - if (!is_file($p_archive_filename)) { - - // ----- Nothing to duplicate, so duplicate is a success. - $v_result = 1; - - // ----- Return - return $v_result; - } - - // ----- Open the zip file - if (($v_result=$this->_openFd('wb')) != 1) { - // ----- Return - return $v_result; - } - - // ----- Open the temporary file in write mode - if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0) { - $this->_closeFd(); - $this->_errorLog(ARCHIVE_ZIP_ERR_READ_OPEN_FAIL, - 'Unable to open archive file \'' - .$p_archive_filename.'\' in binary write mode'); - return Archive_Zip::errorCode(); - } - - // ----- Copy the files from the archive to the temporary file - // TBC : Here I should better append the file and go back to erase the - // central dir - $v_size = filesize($p_archive_filename); - while ($v_size != 0) { - $v_read_size = ($v_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $v_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = fread($v_zip_temp_fd, $v_read_size); - @fwrite($this->_zip_fd, $v_buffer, $v_read_size); - $v_size -= $v_read_size; - } - - // ----- Close - $this->_closeFd(); - - // ----- Close the temporary file - @fclose($v_zip_temp_fd); - - return $v_result; - } - // --------------------------------------------------------------------------- - - /** - * Archive_Zip::_check_parameters() - * - * { Description } - * - * @param integer $p_error_code - * @param string $p_error_string - */ - function _check_parameters(&$p_params, $p_default) - { - - // ----- Check that param is an array - if (!is_array($p_params)) { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - 'Unsupported parameter, waiting for an array'); - return Archive_Zip::errorCode(); - } - - // ----- Check that all the params are valid - for (reset($p_params); list($v_key, $v_value) = each($p_params); ) { - if (!isset($p_default[$v_key])) { - $this->_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAMETER, - 'Unsupported parameter with key \''.$v_key.'\''); - - return Archive_Zip::errorCode(); - } - } - - // ----- Set the default values - for (reset($p_default); list($v_key, $v_value) = each($p_default); ) { - if (!isset($p_params[$v_key])) { - $p_params[$v_key] = $p_default[$v_key]; - } - } - - // ----- Check specific parameters - $v_callback_list = array ('callback_pre_add','callback_post_add', - 'callback_pre_extract','callback_post_extract'); - for ($i=0; $i_errorLog(ARCHIVE_ZIP_ERR_INVALID_PARAM_VALUE, - "Callback '".$p_params[$v_key] - ."()' is not an existing function for " - ."parameter '".$v_key."'"); - return Archive_Zip::errorCode(); - } - } - } - - return(1); - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _errorLog() - // Description : - // Parameters : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_errorLog() - * - * { Description } - * - * @param integer $p_error_code - * @param string $p_error_string - */ - function _errorLog($p_error_code=0, $p_error_string='') - { - $this->_error_code = $p_error_code; - $this->_error_string = $p_error_string; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : _errorReset() - // Description : - // Parameters : - // --------------------------------------------------------------------------- - /** - * Archive_Zip::_errorReset() - * - * { Description } - * - */ - function _errorReset() - { - $this->_error_code = 1; - $this->_error_string = ''; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : $this->_tool_PathReduction() - // Description : - // Parameters : - // Return Values : - // --------------------------------------------------------------------------- - /** - * _tool_PathReduction() - * - * { Description } - * - */ - function _tool_PathReduction($p_dir) - { - $v_result = ""; - - // ----- Look for not empty path - if ($p_dir != "") - { - // ----- Explode path by directory names - $v_list = explode("/", $p_dir); - - // ----- Study directories from last to first - for ($i=sizeof($v_list)-1; $i>=0; $i--) - { - // ----- Look for current path - if ($v_list[$i] == ".") - { - // ----- Ignore this directory - // Should be the first $i=0, but no check is done - } - else if ($v_list[$i] == "..") - { - // ----- Ignore it and ignore the $i-1 - $i--; - } - else if (($v_list[$i] == "") && ($i!=(sizeof($v_list)-1)) && ($i!=0)) - { - // ----- Ignore only the double '//' in path, - // but not the first and last '/' - } - else - { - $v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:""); - } - } - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : $this->_tool_PathInclusion() - // Description : - // This function indicates if the path $p_path is under the $p_dir tree. Or, - // said in an other way, if the file or sub-dir $p_path is inside the dir - // $p_dir. - // The function indicates also if the path is exactly the same as the dir. - // This function supports path with duplicated '/' like '//', but does not - // support '.' or '..' statements. - // Parameters : - // Return Values : - // 0 if $p_path is not inside directory $p_dir - // 1 if $p_path is inside directory $p_dir - // 2 if $p_path is exactly the same as $p_dir - // --------------------------------------------------------------------------- - /** - * _tool_PathInclusion() - * - * { Description } - * - */ - function _tool_PathInclusion($p_dir, $p_path) - { - $v_result = 1; - - // ----- Explode dir and path by directory separator - $v_list_dir = explode("/", $p_dir); - $v_list_dir_size = sizeof($v_list_dir); - $v_list_path = explode("/", $p_path); - $v_list_path_size = sizeof($v_list_path); - - // ----- Study directories paths - $i = 0; - $j = 0; - while (($i < $v_list_dir_size) && ($j < $v_list_path_size) && ($v_result)) { - - // ----- Look for empty dir (path reduction) - if ($v_list_dir[$i] == '') { - $i++; - continue; - } - if ($v_list_path[$j] == '') { - $j++; - continue; - } - - // ----- Compare the items - if ( ($v_list_dir[$i] != $v_list_path[$j]) - && ($v_list_dir[$i] != '') - && ( $v_list_path[$j] != '')) { - $v_result = 0; - } - - // ----- Next items - $i++; - $j++; - } - - // ----- Look if everything seems to be the same - if ($v_result) { - // ----- Skip all the empty items - while (($j < $v_list_path_size) && ($v_list_path[$j] == '')) $j++; - while (($i < $v_list_dir_size) && ($v_list_dir[$i] == '')) $i++; - - if (($i >= $v_list_dir_size) && ($j >= $v_list_path_size)) { - // ----- There are exactly the same - $v_result = 2; - } - else if ($i < $v_list_dir_size) { - // ----- The path is shorter than the dir - $v_result = 0; - } - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : $this->_tool_CopyBlock() - // Description : - // Parameters : - // $p_mode : read/write compression mode - // 0 : src & dest normal - // 1 : src gzip, dest normal - // 2 : src normal, dest gzip - // 3 : src & dest gzip - // Return Values : - // --------------------------------------------------------------------------- - /** - * _tool_CopyBlock() - * - * { Description } - * - * @param integer $p_mode - */ - function _tool_CopyBlock($p_src, $p_dest, $p_size, $p_mode=0) - { - $v_result = 1; - - if ($p_mode==0) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==1) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @fwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==2) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @fread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - else if ($p_mode==3) - { - while ($p_size != 0) - { - $v_read_size = ($p_size < ARCHIVE_ZIP_READ_BLOCK_SIZE - ? $p_size : ARCHIVE_ZIP_READ_BLOCK_SIZE); - $v_buffer = @gzread($p_src, $v_read_size); - @gzwrite($p_dest, $v_buffer, $v_read_size); - $p_size -= $v_read_size; - } - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : $this->_tool_Rename() - // Description : - // This function tries to do a simple rename() function. If it fails, it - // tries to copy the $p_src file in a new $p_dest file and then unlink the - // first one. - // Parameters : - // $p_src : Old filename - // $p_dest : New filename - // Return Values : - // 1 on success, 0 on failure. - // --------------------------------------------------------------------------- - /** - * _tool_Rename() - * - * { Description } - * - */ - function _tool_Rename($p_src, $p_dest) - { - $v_result = 1; - - // ----- Try to rename the files - if (!@rename($p_src, $p_dest)) { - - // ----- Try to copy & unlink the src - if (!@copy($p_src, $p_dest)) { - $v_result = 0; - } - else if (!@unlink($p_src)) { - $v_result = 0; - } - } - - // ----- Return - return $v_result; - } - // --------------------------------------------------------------------------- - - // --------------------------------------------------------------------------- - // Function : $this->_tool_TranslateWinPath() - // Description : - // Translate windows path by replacing '\' by '/' and optionally removing - // drive letter. - // Parameters : - // $p_path : path to translate. - // $p_remove_disk_letter : true | false - // Return Values : - // The path translated. - // --------------------------------------------------------------------------- - /** - * _tool_TranslateWinPath() - * - * { Description } - * - * @param [type] $p_remove_disk_letter - */ - function _tool_TranslateWinPath($p_path, $p_remove_disk_letter=true) - { - if (stristr(php_uname(), 'windows')) { - // ----- Look for potential disk letter - if ( ($p_remove_disk_letter) - && (($v_position = strpos($p_path, ':')) != false)) { - $p_path = substr($p_path, $v_position+1); - } - // ----- Change potential windows directory separator - if ((strpos($p_path, '\\') > 0) || (substr($p_path, 0,1) == '\\')) { - $p_path = strtr($p_path, '\\', '/'); - } - } - return $p_path; - } - // --------------------------------------------------------------------------- - - } - // End of class - -?> diff --git a/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php old mode 100644 new mode 100755 index 00b0a7a9..fc12c9d2 --- a/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php +++ b/buildscripts/phing/classes/phing/listener/AnsiColorLogger.php @@ -1,6 +1,6 @@ (Phing) * @author Magesh Umasankar (Ant) * @package phing.listener - * @version $Revision: 1.13 $ + * @version $Id$ */ -final class AnsiColorLogger extends DefaultLogger { +class AnsiColorLogger extends DefaultLogger { const ATTR_NORMAL = 0; const ATTR_BRIGHT = 1; @@ -144,11 +144,11 @@ final class AnsiColorLogger extends DefaultLogger { */ public function __construct() { parent::__construct(); - $this->errColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_RED . self::SUFFIX; - $this->warnColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_MAGENTA . self::SUFFIX; - $this->infoColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_CYAN . self::SUFFIX; - $this->verboseColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_GREEN . self::SUFFIX; - $this->debugColor = self::PREFIX . self::ATTR_DIM . self::SEPARATOR . self::FG_BLUE . self::SUFFIX; + $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; } /** @@ -177,19 +177,19 @@ final class AnsiColorLogger extends DefaultLogger { $verbose = $prop->getProperty("AnsiColorLogger.VERBOSE_COLOR"); $debug = $prop->getProperty("AnsiColorLogger.DEBUG_COLOR"); if ($err !== null) { - $errColor = self::PREFIX . $err . self::SUFFIX; + $this->errColor = self::PREFIX . $err . self::SUFFIX; } if ($warn !== null) { - $warnColor = self::PREFIX . $warn . self::SUFFIX; + $this->warnColor = self::PREFIX . $warn . self::SUFFIX; } if ($info !== null) { - $infoColor = self::PREFIX . $info . self::SUFFIX; + $this->infoColor = self::PREFIX . $info . self::SUFFIX; } if ($verbose !== null) { - $verboseColor = self::PREFIX . $verbose . self::SUFFIX; + $this->verboseColor = self::PREFIX . $verbose . self::SUFFIX; } if ($debug !== null) { - $debugColor = self::PREFIX . $debug . self::SUFFIX; + $this->debugColor = self::PREFIX . $debug . self::SUFFIX; } } catch (IOException $ioe) { //Ignore exception - we will use the defaults. @@ -198,9 +198,11 @@ final class AnsiColorLogger extends DefaultLogger { /** * @see DefaultLogger#printMessage + * @param string $message + * @param OutputStream $stream + * @param int $priority */ - protected final function printMessage($message, $priority) { - + protected final function printMessage($message, OutputStream $stream, $priority) { if ($message !== null) { if (!$this->colorsSet) { @@ -209,23 +211,24 @@ final class AnsiColorLogger extends DefaultLogger { } switch ($priority) { - case PROJECT_MSG_ERR: + case Project::MSG_ERR: $message = $this->errColor . $message . self::END_COLOR; break; - case PROJECT_MSG_WARN: + case Project::MSG_WARN: $message = $this->warnColor . $message . self::END_COLOR; break; - case PROJECT_MSG_INFO: + case Project::MSG_INFO: $message = $this->infoColor . $message . self::END_COLOR; break; - case PROJECT_MSG_VERBOSE: + case Project::MSG_VERBOSE: $message = $this->verboseColor . $message . self::END_COLOR; break; - case PROJECT_MSG_DEBUG: + case Project::MSG_DEBUG: $message = $this->debugColor . $message . self::END_COLOR; break; } - print($message."\n"); + + $stream->write($message . PHP_EOL); } } } diff --git a/buildscripts/phing/classes/phing/listener/BuildLogger.php b/buildscripts/phing/classes/phing/listener/BuildLogger.php deleted file mode 100644 index d1c5fcb6..00000000 --- a/buildscripts/phing/classes/phing/listener/BuildLogger.php +++ /dev/null @@ -1,42 +0,0 @@ -. - */ - - require_once 'phing/BuildListener.php'; - /** - * Interface used by Phing Ant to log the build output. - * - * @author Michiel Rook - * @version $Id: BuildLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ - * @package phing.listener - */ - interface BuildLogger extends BuildListener - { - /** - * Sets the highest level of message this logger should respond to. - * - * Only messages with a message level lower than or equal to the - * given level should be written to the log. - * - * @param int the logging level for the logger. - */ - function setMessageOutputLevel($level); - }; -?> \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/listener/DefaultLogger.php b/buildscripts/phing/classes/phing/listener/DefaultLogger.php old mode 100644 new mode 100755 index c7387592..31051a75 --- a/buildscripts/phing/classes/phing/listener/DefaultLogger.php +++ b/buildscripts/phing/classes/phing/listener/DefaultLogger.php @@ -1,6 +1,6 @@ . */ -require_once 'phing/BuildListener.php'; +require_once 'phing/listener/StreamRequiredBuildLogger.php'; include_once 'phing/BuildEvent.php'; /** @@ -29,12 +29,12 @@ include_once 'phing/BuildEvent.php'; * any messages that get logged. * * @author Andreas Aderhold - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.11 $ $Date: 2005/08/25 19:33:43 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @see BuildEvent * @package phing.listener */ -class DefaultLogger implements BuildListener { +class DefaultLogger implements StreamRequiredBuildLogger { /** * Size of the left column in output. The default char width is 12. @@ -44,29 +44,32 @@ class DefaultLogger implements BuildListener { /** * The message output level that should be used. The default is - * PROJECT_MSG_VERBOSE. + * Project::MSG_VERBOSE. * @var int */ - protected $msgOutputLevel = PROJECT_MSG_ERR; + protected $msgOutputLevel = Project::MSG_ERR; /** * Time that the build started * @var int */ protected $startTime; - + + /** + * @var OutputStream Stream to use for standard output. + */ + protected $out; + /** - * Char that should be used to seperate lines. Default is the system - * property line.seperator. - * @var string + * @var OutputStream Stream to use for error output. */ - protected $lSep; + protected $err; /** * Construct a new default logger. */ public function __construct() { - $this->lSep = Phing::getProperty("line.separator"); + } /** @@ -79,22 +82,40 @@ class DefaultLogger implements BuildListener { * the levels, from least to most verbose, is: * *
    - *
  • PROJECT_MSG_ERR
  • - *
  • PROJECT_MSG_WARN
  • - *
  • PROJECT_MSG_INFO
  • - *
  • PROJECT_MSG_VERBOSE
  • - *
  • PROJECT_MSG_DEBUG
  • + *
  • Project::MSG_ERR
  • + *
  • Project::MSG_WARN
  • + *
  • Project::MSG_INFO
  • + *
  • Project::MSG_VERBOSE
  • + *
  • Project::MSG_DEBUG
  • *
* - * The default message level for DefaultLogger is PROJECT_MSG_ERR. + * The default message level for DefaultLogger is Project::MSG_ERR. * - * @param integer the logging level for the logger. - * @access public + * @param int $level The logging level for the logger. + * @see BuildLogger#setMessageOutputLevel() */ - function setMessageOutputLevel($level) { + 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. @@ -102,11 +123,10 @@ class DefaultLogger implements BuildListener { * @param object The BuildEvent * @access public */ - - function buildStarted(BuildEvent $event) { + public function buildStarted(BuildEvent $event) { $this->startTime = Phing::currentTimeMillis(); - if ($this->msgOutputLevel >= PROJECT_MSG_INFO) { - $this->printMessage("Buildfile: ".$event->getProject()->getProperty("phing.file"), PROJECT_MSG_INFO); + if ($this->msgOutputLevel >= Project::MSG_INFO) { + $this->printMessage("Buildfile: ".$event->getProject()->getProperty("phing.file"), $this->out, Project::MSG_INFO); } } @@ -115,24 +135,45 @@ class DefaultLogger implements BuildListener { * occured during the build. Also outputs the total build-time. * * @param object The BuildEvent - * @access public * @see BuildEvent::getException() */ - function buildFinished(BuildEvent $event) { + public function buildFinished(BuildEvent $event) { $error = $event->getException(); if ($error === null) { - print($this->lSep . "BUILD FINISHED" . $this->lSep); + $msg = PHP_EOL . $this->getBuildSuccessfulMessage() . PHP_EOL; } else { - print($this->lSep . "BUILD FAILED" . $this->lSep); - if (PROJECT_MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) { - print($error->__toString().$this->lSep); + $msg = PHP_EOL . $this->getBuildFailedMessage() . PHP_EOL; + if (Project::MSG_VERBOSE <= $this->msgOutputLevel || !($error instanceof BuildException)) { + $msg .= $error->__toString().PHP_EOL; } else { - print($error->getMessage()); + $msg .= $error->getMessage(); } } - print($this->lSep . "Total time: " .$this->_formatTime(Phing::currentTimeMillis() - $this->startTime) . $this->lSep); + $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 * @@ -140,9 +181,11 @@ class DefaultLogger implements BuildListener { * @access public * @see BuildEvent::getTarget() */ - function targetStarted(BuildEvent $event) { - if (PROJECT_MSG_INFO <= $this->msgOutputLevel) { - print($this->lSep . $event->getProject()->getName() . ' > ' . $event->getTarget()->getName() . ':' . $this->lSep); + 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()); } } @@ -151,10 +194,9 @@ class DefaultLogger implements BuildListener { * event. So the methods are empty. * * @param object The BuildEvent - * @access public * @see BuildEvent::getException() */ - function targetFinished(BuildEvent $event) {} + public function targetFinished(BuildEvent $event) {} /** * Fired when a task is started. We don't need specific action on this @@ -164,7 +206,7 @@ class DefaultLogger implements BuildListener { * @access public * @see BuildEvent::getTask() */ - function taskStarted(BuildEvent $event) {} + public function taskStarted(BuildEvent $event) {} /** * Fired when a task has finished. We don't need specific action on this @@ -174,7 +216,7 @@ class DefaultLogger implements BuildListener { * @access public * @see BuildEvent::getException() */ - function taskFinished(BuildEvent $event) {} + public function taskFinished(BuildEvent $event) {} /** * Print a message to the stdout. @@ -183,20 +225,23 @@ class DefaultLogger implements BuildListener { * @access public * @see BuildEvent::getMessage() */ - function messageLogged(BuildEvent $event) { - if ($event->getPriority() <= $this->msgOutputLevel) { + 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); - #for ($i=0; $i < ($this->LEFT_COLUMN_SIZE - strlen($msg)); ++$i) { - # print(" "); - #} - #print($msg); } + $msg .= $event->getMessage(); - $this->printMessage($msg, $event->getPriority()); + + if ($priority != Project::MSG_ERR) { + $this->printMessage($msg, $this->out, $priority); + } else { + $this->printMessage($msg, $this->err, $priority); + } } } @@ -206,7 +251,7 @@ class DefaultLogger implements BuildListener { * @param integer The time stamp * @access private */ - function _formatTime($micros) { + public static function formatTime($micros) { $seconds = $micros; $minutes = $seconds / 60; if ($minutes > 1) { @@ -223,11 +268,12 @@ class DefaultLogger implements BuildListener { * * @param string $message The message to print. * Should not be null. + * @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, $priority) { - print($message . $this->lSep); + 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 @@ +. + */ + +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 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 (Phing HTML Color Logger) + * @author Hans Lellelid (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 = ''; + const END_COLOR = ''; + + 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('<', '>'); + $message = str_replace($search, $replace, $message); + + $search = array("\t", "\n", "\r"); + $replace = array('   ', '
', ''); + $message = str_replace($search, $replace, $message); + + if (preg_match('@^( +)([^ ].+)@', $message, $matches)) { + $len = strlen($matches[1]); + $space = ' '; + for ($i = 1; $i < $len; $i++) { + $space .= ' '; + } + $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 . '
'); + } + } +} 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 @@ +. + */ + +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 + * @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 old mode 100644 new mode 100755 index e222e10c..887f6678 --- a/buildscripts/phing/classes/phing/listener/NoBannerLogger.php +++ b/buildscripts/phing/classes/phing/listener/NoBannerLogger.php @@ -1,6 +1,6 @@ . */ -include_once 'phing/listener/DefaultLogger.php'; +require_once 'phing/listener/DefaultLogger.php'; /** - * Extends DefaultLogger to strip out empty targets. This logger is most - * commonly used and also enforced by the default phing invokation scripts - * in bin/. + * Extends DefaultLogger to strip out empty targets. * * @author Andreas Aderhold - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.4 $ $Date: 2003/12/24 13:02:08 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @package phing.listener */ class NoBannerLogger extends DefaultLogger { @@ -45,14 +43,14 @@ class NoBannerLogger extends DefaultLogger { } function messageLogged(BuildEvent $event) { - if ($event->getPriority() > $this->msgOutputLevel || - null === $event->getMessage() || - trim($event->getMessage() === "")) { + + if ($event->getPriority() > $this->msgOutputLevel || null === $event->getMessage() || trim($event->getMessage() === "")) { return; } - + if ($this->targetName !== null) { - print($this->lSep . "Target: ".$this->targetName . $this->lSep); + $msg = PHP_EOL . $event->getProject()->getName() . ' > ' . $this->targetName . ':' . PHP_EOL; + $this->printMessage($msg, $this->out, $event->getPriority()); $this->targetName = null; } 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 @@ +. + */ + +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) + * + * + * phing -f build.xml -logger phing.listener.PearLogger -Dpear.log.type=file -Dpear.log.name=/path/to/log.log + * + * + * @author Hans Lellelid + * @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/PearLogger.php b/buildscripts/phing/classes/phing/listener/PearLogger.php deleted file mode 100644 index 2bea6655..00000000 --- a/buildscripts/phing/classes/phing/listener/PearLogger.php +++ /dev/null @@ -1,246 +0,0 @@ -. - */ - -require_once 'phing/BuildListener.php'; -include_once 'phing/BuildEvent.php'; -require_once 'Log.php'; - -/** - * Writes log messages to PEAR Log. - * - * By default it will log to file in current directory w/ name 'phing.log'. You can customize - * this behavior by setting properties: - * - pear.log.type - * - pear.log.name - * - pear.log.ident (note that this class changes ident to project name) - * - pear.log.conf (note that array values are currently unsupported in Phing property files) - * - * - * phing -f build.xml -logger phing.listener.PearLogger -Dpear.log.type=file -Dpear.log.name=/path/to/log.log - * - * - * @author Hans Lellelid - * @version $Revision: 1.3 $ $Date: 2004/03/15 14:45:06 $ - * @see BuildEvent - * @package phing.listener - */ -class PearLogger implements BuildListener { - - /** - * Size of the left column in output. The default char width is 12. - * @var int - */ - const LEFT_COLUMN_SIZE = 12; - - /** - * The message output level that should be used. The default is - * PROJECT_MSG_VERBOSE. - * @var int - */ - protected $msgOutputLevel = PROJECT_MSG_ERR; - - /** - * Time that the build started - * @var int - */ - protected $startTime; - - /** - * Maps Phing PROJECT_MSG_* constants to PEAR_LOG_* constants. - * @var array - */ - protected static $levelMap = array( PROJECT_MSG_DEBUG => PEAR_LOG_DEBUG, - PROJECT_MSG_INFO => PEAR_LOG_INFO, - PROJECT_MSG_VERBOSE => PEAR_LOG_NOTICE, - PROJECT_MSG_WARN => PEAR_LOG_WARNING, - PROJECT_MSG_ERR => PEAR_LOG_ERR - ); - /** - * Whether logging has been configured. - * @var boolean - */ - protected $logConfigured = false; - - /** - * Configure the logger. - */ - protected function configureLogging() { - - $type = Phing::getDefinedProperty('pear.log.type'); - $name = Phing::getDefinedProperty('pear.log.name'); - $ident = Phing::getDefinedProperty('pear.log.ident'); - $conf = Phing::getDefinedProperty('pear.log.conf'); - - if ($type === null) $type = 'file'; - if ($name === null) $name = 'phing.log'; - if ($ident === null) $ident = 'phing'; - if ($conf === null) $conf = array(); - - $this->logger = Log::singleton($type, $name, $ident, $conf, self::$levelMap[$this->msgOutputLevel]); - } - - /** - * Get the configured PEAR logger to use. - * This method just ensures that logging has been configured and returns the configured logger. - * @return Log - */ - protected function logger() { - if (!$this->logConfigured) { - $this->configureLogging(); - } - return $this->logger; - } - - /** - * Set the msgOutputLevel this logger is to respond to. - * - * Only messages with a message level lower than or equal to the given - * level are output to the log. - * - *

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
  • - *
- * - * The default message level for DefaultLogger is PROJECT_MSG_ERR. - * - * @param integer the logging level for the logger. - * @access public - */ - function setMessageOutputLevel($level) { - $this->msgOutputLevel = (int) $level; - } - - /** - * Sets the start-time when the build started. Used for calculating - * the build-time. - * - * @param object The BuildEvent - * @access public - */ - - function buildStarted(BuildEvent $event) { - $this->startTime = Phing::currentTimeMillis(); - $this->logger()->setIdent($event->getProject()->getName()); - $this->logger()->info("Starting build with buildfile: ". $event->getProject()->getProperty("phing.file")); - } - - /** - * Prints whether the build succeeded or failed, and any errors that - * occured during the build. Also outputs the total build-time. - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getException() - */ - function buildFinished(BuildEvent $event) { - $error = $event->getException(); - if ($error === null) { - $msg = "Finished successful build."; - } else { - $msg = "Build failed. [reason: " . $error->getMessage() ."]"; - } - $this->logger()->log($msg . " Total time: " . $this->_formatTime(Phing::currentTimeMillis() - $this->startTime)); - } - - /** - * Prints the current target name - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getTarget() - */ - function targetStarted(BuildEvent $event) {} - - /** - * Fired when a target has finished. We don't need specific action on this - * event. So the methods are empty. - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getException() - */ - function targetFinished(BuildEvent $event) {} - - /** - * Fired when a task is started. We don't need specific action on this - * event. So the methods are empty. - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getTask() - */ - function taskStarted(BuildEvent $event) {} - - /** - * Fired when a task has finished. We don't need specific action on this - * event. So the methods are empty. - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getException() - */ - function taskFinished(BuildEvent $event) {} - - /** - * Print a message to the stdout. - * - * @param object The BuildEvent - * @access public - * @see BuildEvent::getMessage() - */ - function messageLogged(BuildEvent $event) { - if ($event->getPriority() <= $this->msgOutputLevel) { - $msg = ""; - if ($event->getTask() !== null) { - $name = $event->getTask(); - $name = $name->getTaskName(); - $msg = str_pad("[$name] ", self::LEFT_COLUMN_SIZE, " ", STR_PAD_LEFT); - } - $msg .= $event->getMessage(); - $this->logger()->log($msg, self::$levelMap[$event->getPriority()]); - } - } - - /** - * Formats a time micro integer to human readable format. - * - * @param integer The time stamp - * @access private - */ - function _formatTime($micros) { - $seconds = $micros; - $minutes = $seconds / 60; - if ($minutes > 1) { - return sprintf("%1.0f minute%s %0.2f second%s", - $minutes, ($minutes === 1 ? " " : "s "), - $seconds - floor($seconds/60) * 60, ($seconds%60 === 1 ? "" : "s")); - } else { - return sprintf("%0.4f second%s", $seconds, ($seconds%60 === 1 ? "" : "s")); - } - } -} diff --git a/buildscripts/phing/classes/phing/listener/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 @@ +. + */ + +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 + * @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 old mode 100644 new mode 100755 index 07ff031e..25ff0ba2 --- a/buildscripts/phing/classes/phing/listener/XmlLogger.php +++ b/buildscripts/phing/classes/phing/listener/XmlLogger.php @@ -1,265 +1,354 @@ . - */ - - require_once 'phing/listener/BuildLogger.php'; - require_once 'phing/listener/DefaultLogger.php'; - require_once 'phing/system/util/Timer.php'; - /** - * Generates a file in the current directory with - * an XML description of what happened during a build. - * The default filename is "log.xml", but this can be overridden - * with the property XmlLogger.file. - * - * @author Michiel Rook - * @version $Id: XmlLogger.php,v 1.3 2005/02/11 10:51:21 mrook Exp $ - * @package phing.listener - */ - class XmlLogger implements BuildLogger - { - /** XML element name for a build. */ - const BUILD_TAG = "build"; - /** XML element name for a target. */ - const TARGET_TAG = "target"; - /** XML element name for a task. */ - const TASK_TAG = "task"; - /** XML element name for a message. */ - const MESSAGE_TAG = "message"; - /** XML attribute name for a name. */ - const NAME_ATTR = "name"; - /** XML attribute name for a time. */ - const TIME_ATTR = "time"; - /** XML attribute name for a message priority. */ - const PRIORITY_ATTR = "priority"; - /** XML attribute name for a file location. */ - const LOCATION_ATTR = "location"; - /** XML attribute name for an error description. */ - const ERROR_ATTR = "error"; - /** XML element name for a stack trace. */ - const STACKTRACE_TAG = "stacktrace"; - - private $doc = NULL; - - private $buildStartTime = 0; - private $targetStartTime = 0; - private $taskStartTime = 0; - - private $buildElement = NULL; - - private $msgOutputLevel = PROJECT_MSG_DEBUG; - - /** - * Constructs a new BuildListener that logs build events to an XML file. - */ - function __construct() - { - $this->doc = new DOMDocument(); - $this->doc->formatOutput = true; - - $this->buildTimer = new Timer(); - $this->targetTimer = new Timer(); - $this->taskTimer = new Timer(); - } - - /** - * Fired when the build starts, this builds the top-level element for the - * document and remembers the time of the start of the build. - * - * @param BuildEvent Ignored. - */ - function buildStarted(BuildEvent $event) - { - $this->buildTimerStart = Phing::currentTimeMillis(); - $this->buildElement = $this->doc->createElement(XmlLogger::BUILD_TAG); - } - - /** - * Fired when the build finishes, this adds the time taken and any - * error stacktrace to the build element and writes the document to disk. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function buildFinished(BuildEvent $event) - { - $this->buildTimer->stop(); - - $elapsedTime = Phing::currentTimeMillis() - $this->buildTimerStart; - - $this->buildElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); - - if ($event->getException() != null) - { - $this->buildElement->setAttribute(XmlLogger::ERROR_ATTR, $event->getException()->toString()); - - $errText = $this->doc->createCDATASection($event->getException()->getTraceAsString()); - $stacktrace = $this->doc->createElement(XmlLogger::STACKTRACE_TAG); - $stacktrace->appendChild($errText); - $this->buildElement->appendChild($stacktrace); - } - - $outFilename = $event->getProject()->getProperty("XmlLogger.file"); - - if ($outFilename == "") - { - $outFilename = "log.xml"; - } - $writer = new FileWriter($outFilename); - - $writer->write("\n"); - $writer->write($this->doc->saveXML($this->buildElement)); - $writer->close(); - } - /** - * Fired when a target starts building, remembers the current time and the name of the target. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function targetStarted(BuildEvent $event) - { - $target = $event->getTarget(); - - $this->targetTimerStart = Phing::currentTimeMillis(); - - $this->targetElement = $this->doc->createElement(XmlLogger::TARGET_TAG); - $this->targetElement->setAttribute(XmlLogger::NAME_ATTR, $target->getName()); - } - - /** - * Fired when a target finishes building, this adds the time taken - * to the appropriate target element in the log. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function targetFinished(BuildEvent $event) - { - $target = $event->getTarget(); - - $elapsedTime = Phing::currentTimeMillis() - $this->targetTimerStart; - - $this->targetElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); - - $this->buildElement->appendChild($this->targetElement); - } - - /** - * Fired when a task starts building, remembers the current time and the name of the task. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function taskStarted(BuildEvent $event) - { - $task = $event->getTask(); - - $this->taskTimerStart = Phing::currentTimeMillis(); - - $this->taskElement = $this->doc->createElement(XmlLogger::TASK_TAG); - $this->taskElement->setAttribute(XmlLogger::NAME_ATTR, $task->getTaskName()); - $this->taskElement->setAttribute(XmlLogger::LOCATION_ATTR, $task->getLocation()->toString()); - } - /** - * Fired when a task finishes building, this adds the time taken - * to the appropriate task element in the log. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function taskFinished(BuildEvent $event) - { - $task = $event->getTask(); - - $elapsedTime = Phing::currentTimeMillis() - $this->taskTimerStart; - $this->taskElement->setAttribute(XmlLogger::TIME_ATTR, DefaultLogger::_formatTime($elapsedTime)); - - $this->targetElement->appendChild($this->taskElement); - } - - /** - * Fired when a message is logged, this adds a message element to the - * most appropriate parent element (task, target or build) and records - * the priority and text of the message. - * - * @param BuildEvent An event with any relevant extra information. - * Will not be null. - */ - function messageLogged(BuildEvent $event) - { - $priority = $event->getPriority(); - - if ($priority > $this->msgOutputLevel) - { - return; - } - - $messageElement = $this->doc->createElement(XmlLogger::MESSAGE_TAG); - - switch ($priority) - { - case PROJECT_MSG_ERR: - $name = "error"; - break; - - case PROJECT_MSG_WARN: - $name = "warn"; - break; - - case PROJECT_MSG_INFO: - $name = "info"; - break; - - default: - $name = "debug"; - break; - } - - $messageElement->setAttribute(XmlLogger::PRIORITY_ATTR, $name); - - $messageText = $this->doc->createCDATASection($event->getMessage()); - - $messageElement->appendChild($messageText); - - if ($event->getTask() != null) - { - $this->taskElement->appendChild($messageElement); - } - else - if ($event->getTarget() != null) - { - $this->targetElement->appendChild($messageElement); - } - else - if ($this->buildElement != null) - { - $this->buildElement->appendChild($messageElement); - } - } - - /** - * Set the logging level when using this as a Logger - */ - function setMessageOutputLevel($level) - { - $this->msgOutputLevel = $level; - } - }; -?> \ No newline at end of file +/** + * $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 + * . + */ + +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 XmlLogger.file. + * + * @author Michiel Rook + * @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 null. + */ + 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 null. + */ + 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 null. + */ + 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 null. + */ + 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 null. + */ + 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 null. + */ + 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. + * + *

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
  • + *
+ * + * 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 index f60a3fd5..4a4dec68 100644 --- a/buildscripts/phing/classes/phing/listener/defaults.properties +++ b/buildscripts/phing/classes/phing/listener/defaults.properties @@ -36,8 +36,8 @@ # #################################################### -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 +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 old mode 100644 new mode 100755 index c8f1f8a9..f4306b4c --- a/buildscripts/phing/classes/phing/mappers/FileNameMapper.php +++ b/buildscripts/phing/classes/phing/mappers/FileNameMapper.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.7 $ + * @version $Id$ * @package phing.mappers */ interface FileNameMapper { diff --git a/buildscripts/phing/classes/phing/mappers/FlattenMapper.php b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php old mode 100644 new mode 100755 index fea5c1e4..55ed4113 --- a/buildscripts/phing/classes/phing/mappers/FlattenMapper.php +++ b/buildscripts/phing/classes/phing/mappers/FlattenMapper.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.9 $ + * @version $Id$ * @package phing.mappers */ class FlattenMapper implements FileNameMapper { diff --git a/buildscripts/phing/classes/phing/mappers/GlobMapper.php b/buildscripts/phing/classes/phing/mappers/GlobMapper.php old mode 100644 new mode 100755 index 3c178620..79df94d6 --- a/buildscripts/phing/classes/phing/mappers/GlobMapper.php +++ b/buildscripts/phing/classes/phing/mappers/GlobMapper.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.7 $ + * @version $Id$ * @package phing.mappers */ class IdentityMapper implements FileNameMapper { diff --git a/buildscripts/phing/classes/phing/mappers/MergeMapper.php b/buildscripts/phing/classes/phing/mappers/MergeMapper.php old mode 100644 new mode 100755 index f10f41c0..dc60ab34 --- a/buildscripts/phing/classes/phing/mappers/MergeMapper.php +++ b/buildscripts/phing/classes/phing/mappers/MergeMapper.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.8 $ + * @version $Id$ * @package phing.mappers */ class MergeMapper implements FileNameMapper { @@ -37,10 +37,10 @@ class MergeMapper implements FileNameMapper { /** * The mapper implementation. Basically does nothing in this case. * - * @param mixed The data the mapper works on - * @returns mixed The data after the mapper has been applied - * @access public - * @author Andreas Aderhold, andi@binarycloud.com + * @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) { @@ -52,10 +52,10 @@ class MergeMapper implements FileNameMapper { /** * Accessor. Sets the to property * - * @param string To what this mapper should convert the from string - * @returns boolean True - * @access public - * @author Andreas Aderhold, andi@binarycloud.com + * @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; diff --git a/buildscripts/phing/classes/phing/mappers/RegexpMapper.php b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php old mode 100644 new mode 100755 index a3d51976..ca387241 --- a/buildscripts/phing/classes/phing/mappers/RegexpMapper.php +++ b/buildscripts/phing/classes/phing/mappers/RegexpMapper.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @version $Revision: 1.9 $ + * @version $Id$ * @package phing.mappers */ class RegexpMapper implements FileNameMapper { diff --git a/buildscripts/phing/classes/phing/parser/AbstractHandler.php b/buildscripts/phing/classes/phing/parser/AbstractHandler.php old mode 100644 new mode 100755 index 6f8d7705..1837bbbf --- a/buildscripts/phing/classes/phing/parser/AbstractHandler.php +++ b/buildscripts/phing/classes/phing/parser/AbstractHandler.php @@ -1,7 +1,7 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.6 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @package phing.parser */ abstract class AbstractHandler { diff --git a/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php old mode 100644 new mode 100755 index 60cf0c11..449386e7 --- a/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php +++ b/buildscripts/phing/classes/phing/parser/AbstractSAXParser.php @@ -1,6 +1,6 @@ * @author Hans Lellelid - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.13 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @package phing.parser */ abstract class AbstractSAXParser { @@ -60,26 +60,18 @@ abstract class AbstractSAXParser { /** * Method that gets invoked when the parser runs over a XML start element. * - * This method is called by PHP's internal parser funcitons and registered + * 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 * startElement() method. * - * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS - * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. - * * @param object the php's internal parser handle * @param string the open tag name * @param array the tag's attributes if any + * @throws Exception - Exceptions may be thrown by the Handler */ function startElement($parser, $name, $attribs) { - try { - $this->handler->startElement($name, $attribs); - } catch (Exception $e) { - print "[Exception in XML parsing]\n"; - print $e; - Phing::halt(-1); - } + $this->handler->startElement($name, $attribs); } /** @@ -91,20 +83,12 @@ abstract class AbstractSAXParser { * It gives control to the current active handler object by calling the * endElement() method. * - * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS - * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. - * * @param object the php's internal parser handle * @param string the closing tag name + * @throws Exception - Exceptions may be thrown by the Handler */ function endElement($parser, $name) { - try { - $this->handler->endElement($name); - } catch (Exception $e) { - print "[Exception in XML parsing]\n"; - print $e; - Phing::halt(-1); - } + $this->handler->endElement($name); } /** @@ -116,20 +100,12 @@ abstract class AbstractSAXParser { * It gives control to the current active handler object by calling the * characters() method. That processes the given CDATA. * - * BECAUSE OF PROBLEMS WITH EXCEPTIONS BUBBLING UP THROUGH xml_parse() THIS - * METHOD WILL CALL Phing::halt(-1) ON EXCEPTION. - * * @param resource $parser php's internal parser handle. * @param string $data the CDATA + * @throws Exception - Exceptions may be thrown by the Handler */ function characters($parser, $data) { - try { - $this->handler->characters($data); - } catch (Exception $e) { - print "[Exception in XML parsing]\n"; - print $e; - Phing::halt(-1); - } + $this->handler->characters($data); } /** diff --git a/buildscripts/phing/classes/phing/parser/DataTypeHandler.php b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php old mode 100644 new mode 100755 index 37d757c4..7531baaf --- a/buildscripts/phing/classes/phing/parser/DataTypeHandler.php +++ b/buildscripts/phing/classes/phing/parser/DataTypeHandler.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.8 $ $Date: 2005/11/02 13:55:33 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @access public * @package phing.parser */ diff --git a/buildscripts/phing/classes/phing/parser/ExpatParseException.php b/buildscripts/phing/classes/phing/parser/ExpatParseException.php old mode 100644 new mode 100755 index d5086c30..65461576 --- a/buildscripts/phing/classes/phing/parser/ExpatParseException.php +++ b/buildscripts/phing/classes/phing/parser/ExpatParseException.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.8 $ $Date: 2005/05/26 13:10:52 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @access public * @package phing.parser */ diff --git a/buildscripts/phing/classes/phing/parser/Location.php b/buildscripts/phing/classes/phing/parser/Location.php old mode 100644 new mode 100755 index fd79866c..4110bd00 --- a/buildscripts/phing/classes/phing/parser/Location.php +++ b/buildscripts/phing/classes/phing/parser/Location.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.6 $ $Date: 2003/12/24 13:02:09 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @access public * @package phing.parser */ @@ -69,4 +69,8 @@ class Location { } 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 old mode 100644 new mode 100755 index 8ecd0ed3..15d0e173 --- a/buildscripts/phing/classes/phing/parser/NestedElementHandler.php +++ b/buildscripts/phing/classes/phing/parser/NestedElementHandler.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.10 $ $Date: 2005/10/04 19:13:44 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @access public * @package phing.parser */ @@ -173,14 +173,14 @@ class NestedElementHandler extends AbstractHandler { */ function startElement($name, $attrs) { //print(get_class($this) . " name = $name, attrs = " . implode(",",$attrs) . "\n"); - if ($this->child instanceof TaskContainer) { + 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); - } + $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 @@ +. + */ + +/** + * Track the current state of the Xml parse operation. + * + * @author Bryan Davis + * @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 old mode 100644 new mode 100755 index 6b69e955..90471336 --- a/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php +++ b/buildscripts/phing/classes/phing/parser/ProjectConfigurator.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.17 $ $Date: 2006/01/06 14:57:18 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id: ae9b63bef4c1423d88bb36ddfc5196763828123e $ * @access public * @package phing.parser */ @@ -44,7 +46,24 @@ class ProjectConfigurator { 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. @@ -71,6 +90,64 @@ class ProjectConfigurator { $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; } /** @@ -82,20 +159,55 @@ class ProjectConfigurator { * @access private */ protected function parse() { - try { + 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)); - $reader->open(); $parser = new ExpatParser($reader); $parser->parserSetOption(XML_OPTION_CASE_FOLDING,0); $parser->setHandler(new RootHandler($parser, $this)); - $this->project->log("parsing buildfile ".$this->buildFile->getName(), PROJECT_MSG_VERBOSE); + $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. * @@ -106,22 +218,22 @@ class ProjectConfigurator { * @throws BuildException if attributes can not be configured * @access public */ - function configure($target, $attrs, Project $project) { + 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 ) after the original configuration. - // ... so, try to load it again: - if ($target instanceof UnknownElement) { - $tryTarget = $project->createTask($target->getTaskType()); - if ($tryTarget) { - $target = $tryTarget; - } - } + // 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 ) 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); @@ -151,7 +263,7 @@ class ProjectConfigurator { * @param string the element's #CDATA * @access public */ - function addText($project, $target, $text = null) { + public static function addText($project, $target, $text = null) { if ($text === null || strlen(trim($text)) === 0) { return; } @@ -169,12 +281,12 @@ class ProjectConfigurator { * @param string the XML tagname * @access public */ - function storeChild($project, $parent, $child, $tag) { + public static function storeChild($project, $parent, $child, $tag) { $ih = IntrospectionHelper::getHelper(get_class($parent)); $ih->storeElement($project, $parent, $child, $tag); } - // The following two properties are a sort of hack + // 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. @@ -182,19 +294,21 @@ class ProjectConfigurator { 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 the project that should be used for property look-ups - * @param string the string to be scanned for property references - * @param array proeprty keys + * @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 null if the string * itself was null */ - public static function replaceProperties(Project $project, $value, $keys) { + public static function replaceProperties(Project $project, $value, $keys, $logLevel = Project::MSG_VERBOSE) { if ($value === null) { return null; @@ -205,13 +319,29 @@ class ProjectConfigurator { // 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; + } + } - $sb = preg_replace_callback('/\$\{([^}]+)\}/', array('ProjectConfigurator', 'replacePropertyCallback'), $value); return $sb; } @@ -223,12 +353,23 @@ class ProjectConfigurator { { $propertyName = $matches[1]; if (!isset(self::$propReplaceProperties[$propertyName])) { - self::$propReplaceProject->log('Property ${'.$propertyName.'} has not been set.', PROJECT_MSG_VERBOSE); - return $matches[0]; + self::$propReplaceProject->log('Property ${'.$propertyName.'} has not been set.', self::$propReplaceLogLevel); + return $matches[0]; } else { - self::$propReplaceProject->log('Property ${'.$propertyName.'} => ' . self::$propReplaceProperties[$propertyName], PROJECT_MSG_DEBUG); - } - return self::$propReplaceProperties[$propertyName]; + 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; } /** @@ -238,7 +379,7 @@ class ProjectConfigurator { * @param object the element's object * @param array the element's attributes */ - function configureId(&$target, $attr) { + 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 old mode 100644 new mode 100755 index 54486ec9..a027c1e6 --- a/buildscripts/phing/classes/phing/parser/ProjectHandler.php +++ b/buildscripts/phing/classes/phing/parser/ProjectHandler.php @@ -1,6 +1,6 @@ * @copyright (c) 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.14 $ $Date: 2005/10/04 19:13:44 $ + * @version $Id: 393b1f3d8758281af2fd0153ffc6151333457527 $ * @access public * @package phing.parser */ @@ -67,7 +67,9 @@ class ProjectHandler extends AbstractHandler { $def = null; $name = null; $id = null; + $desc = null; $baseDir = null; + $ver = null; // some shorthands $project = $this->configurator->project; @@ -82,38 +84,62 @@ class ProjectHandler extends AbstractHandler { $id = $value; } elseif ($key === "basedir") { $baseDir = $value; + } elseif ($key === "description") { + $desc = $value; + } elseif ($key === "phingVersion") { + $ver = $value; } else { throw new ExpatParseException("Unexpected attribute '$key'"); } } - if ($def === null) { - throw new ExpatParseException("The default attribute of project is required"); + // 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()); } - $project->setDefaultTarget($def); - if ($name !== null) { + 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) { + } + + if ($id !== null) { $project->addReference($id, $project); - } + } + + if ($desc !== null) { + $project->setDescription($desc); + } - if ($project->getProperty("project.basedir") !== null) { + if($ver !== null) { + $project->setPhingVersion($ver); + } + + if ($project->getProperty("project.basedir") !== null) { $project->setBasedir($project->getProperty("project.basedir")); - } else { + } else { if ($baseDir === null) { - $project->setBasedir($buildFileParent->getAbsolutePath()); + $project->setBasedir($buildFileParent->getAbsolutePath()); } else { - // check whether the user has specified an absolute path - $f = new PhingFile($baseDir); - if ($f->isAbsolute()) { - $project->setBasedir($baseDir); - } else { - $project->setBaseDir($project->resolveFile($baseDir, $buildFileParent)); - } + // 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()))); + } } + } } } @@ -128,19 +154,23 @@ class ProjectHandler extends AbstractHandler { */ function startElement($name, $attrs) { - $project = $this->configurator->project; + $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])) { + + 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); + $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 old mode 100644 new mode 100755 index 28afb5d5..435aae40 --- a/buildscripts/phing/classes/phing/parser/RootHandler.php +++ b/buildscripts/phing/classes/phing/parser/RootHandler.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.7 $ + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id$ * @package phing.parser */ class RootHandler extends AbstractHandler { diff --git a/buildscripts/phing/classes/phing/parser/TargetHandler.php b/buildscripts/phing/classes/phing/parser/TargetHandler.php old mode 100644 new mode 100755 index 7ca94b44..a6c4d037 --- a/buildscripts/phing/classes/phing/parser/TargetHandler.php +++ b/buildscripts/phing/classes/phing/parser/TargetHandler.php @@ -1,6 +1,6 @@ * @copyright 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.10 $ + * @version $Id: f73d7c67a353cf16f048af3ba013d84ec726a926 $ * @package phing.parser */ class TargetHandler extends AbstractHandler { @@ -82,6 +82,7 @@ class TargetHandler extends AbstractHandler { $unlessCond = null; $id = null; $description = null; + $isHidden = false; foreach($attrs as $key => $value) { if ($key==="name") { @@ -94,6 +95,8 @@ class TargetHandler extends AbstractHandler { $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 { @@ -108,22 +111,54 @@ class TargetHandler extends AbstractHandler { // 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); - - $project->addTarget($name, $this->target); - - if ($id !== null && $id !== "") { - $project->addReference($id, $this->target); - } // take care of dependencies if (strlen($depends) > 0) { $this->target->setDepends($depends); } + $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); + } } /** @@ -146,4 +181,16 @@ class TargetHandler extends AbstractHandler { $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 old mode 100644 new mode 100755 index 976aebf2..53e07a56 --- a/buildscripts/phing/classes/phing/parser/TaskHandler.php +++ b/buildscripts/phing/classes/phing/parser/TaskHandler.php @@ -1,6 +1,6 @@ - * @copyright © 2001,2002 THYRELL. All rights reserved - * @version $Revision: 1.10 $ + * @author Andreas Aderhold + * @copyright 2001,2002 THYRELL. All rights reserved + * @version $Id: 3b31bb3e2c1ae122411833c67617e7cebf6967b8 $ * @package phing.parser */ class TaskHandler extends AbstractHandler { @@ -55,20 +55,20 @@ class TaskHandler extends AbstractHandler { * @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) - */ + + /** + * 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; /** @@ -84,7 +84,7 @@ class TaskHandler extends AbstractHandler { * @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 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) { @@ -94,16 +94,16 @@ class TaskHandler extends AbstractHandler { if (($container !== null) && !($container instanceof TaskContainer)) { throw new Exception("Argument expected to be a TaskContainer, got something else"); } - if (($parentWrapper !== null) && !($parentWrapper instanceof RuntimeConfigurable)) { + 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->configurator = $configurator; $this->container = $container; - $this->parentWrapper = $parentWrapper; + $this->parentWrapper = $parentWrapper; $this->target = $target; } @@ -149,25 +149,30 @@ class TaskHandler extends AbstractHandler { // add file position information to the task (from parser) // should be used in task exceptions to provide details $this->task->setLocation($this->parser->getLocation()); - $configurator->configureId($task, $attrs); - - if ($this->container) { - $this->container->addTask($this->task); - } - + $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. + // FIXME: if we do like Ant 1.6 and create an implicitTarget in the projectconfigurator object + // then we don't need to check for null here ... but there's a lot of stuff that will break if we + // do that at this point. if ($this->target !== null) { $this->task->setOwningTarget($this->target); $this->task->init(); $this->wrapper = $this->task->getRuntimeConfigurableWrapper(); $this->wrapper->setAttributes($attrs); - if ($this->parentWrapper !== null) { // this may not make sense only within this if-block, but it - // seems to address current use cases adequately - $this->parentWrapper->addChild($this->wrapper); - } + /* + 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); @@ -178,11 +183,11 @@ class TaskHandler extends AbstractHandler { * Executes the task at once if it's directly beneath the tag. */ protected function finished() { - if ($this->task !== null && $this->target === null) { + if ($this->task !== null && $this->target === null && $this->container === null) { try { - $this->task->main(); + $this->task->perform(); } catch (Exception $e) { - $this->task->log($e->getMessage(), PROJECT_MSG_ERR); + $this->task->log($e->getMessage(), Project::MSG_ERR); throw $e; } } diff --git a/buildscripts/phing/classes/phing/system/io/BufferedReader.php b/buildscripts/phing/classes/phing/system/io/BufferedReader.php old mode 100644 new mode 100755 index 4946985c..a392f5be --- a/buildscripts/phing/classes/phing/system/io/BufferedReader.php +++ b/buildscripts/phing/classes/phing/system/io/BufferedReader.php @@ -1,6 +1,6 @@ Yannick Lecaillez - * @version $Revision: 1.6 $ $Date: 2005/12/27 19:12:13 $ + * @version $Id$ * @access public * @see FilterReader * @package phing.system.io -*/ + */ class BufferedReader extends Reader { private $bufferSize = 0; @@ -53,37 +53,36 @@ class BufferedReader extends Reader { } /** - * Reads and returns $_bufferSize chunk of data. + * 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) { - // ignore $len param, not sure how to hanlde it, since - // this should only read bufferSize amount of data. - if ($len !== null) { - $this->currentPosition = ftell($this->fd); - } - if ( ($data = $this->in->read($this->bufferSize)) !== -1 ) { - - // not all files end with a newline character, so we also need to check EOF - if (!$this->in->eof()) { - - $notValidPart = strrchr($data, "\n"); - $notValidPartSize = strlen($notValidPart); - - if ( $notValidPartSize > 1 ) { - // Block doesn't finish on a EOL - // Find the last EOL and forgot all following stuff - $dataSize = strlen($data); - $validSize = $dataSize - $notValidPartSize + 1; - - $data = substr($data, 0, $validSize); - - // Rewind to the begining of the forgotten stuff. - $this->in->skip(-$notValidPartSize+1); - } - - } // if !EOF + // 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; } @@ -167,4 +166,3 @@ class BufferedReader extends Reader { return $this->in->getResource(); } } -?> diff --git a/buildscripts/phing/classes/phing/system/io/BufferedWriter.php b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php old mode 100644 new mode 100755 index c982db28..88520ce9 --- a/buildscripts/phing/classes/phing/system/io/BufferedWriter.php +++ b/buildscripts/phing/classes/phing/system/io/BufferedWriter.php @@ -1,6 +1,6 @@ - * @version $Revision: 1.10 $ + * @version $Id$ * @package phing.system.io */ class BufferedWriter extends Writer { @@ -36,37 +36,36 @@ class BufferedWriter extends Writer { private $bufferSize = 0; /** - * The Writer we are buffering output to. + * @var Writer The Writer we are buffering output to. */ private $out; - function __construct(Writer $writer, $buffsize = 8192) { + public function __construct(Writer $writer, $buffsize = 8192) { $this->out = $writer; $this->bufferSize = $buffsize; } - function write($buf, $off = null, $len = null) { + public function write($buf, $off = null, $len = null) { return $this->out->write($buf, $off, $len); } - function newLine() { - $this->write(Phing::getProperty('line.separator')); + public function newLine() { + $this->write(PHP_EOL); } - function getResource() { + public function getResource() { return $this->out->getResource(); } - - function reset() { - return $this->out->reset(); - } - function close() { - return $this->out->close(); + public function flush() { + $this->out->flush(); } - function open() { - return $this->out->open(); + /** + * 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 old mode 100644 new mode 100755 index 33b37619..048f1866 --- a/buildscripts/phing/classes/phing/system/io/ConsoleReader.php +++ b/buildscripts/phing/classes/phing/system/io/ConsoleReader.php @@ -1,6 +1,6 @@ * @author Matthew Hershberger - * @version $Revision: 1.4 $ + * @version $Id$ * @package phing.system.io */ class ConsoleReader extends Reader { @@ -58,11 +58,11 @@ class ConsoleReader extends Reader { } function close() { - // STDIN is always open + // STDIN is always open } function open() { - // STDIN is always open + // STDIN is always open } /** @@ -81,4 +81,4 @@ class ConsoleReader extends Reader { 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 @@ +. + */ + +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 @@ +. + */ + +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 index cbea2c7e..43ebda69 100644 --- a/buildscripts/phing/classes/phing/system/io/FileReader.php +++ b/buildscripts/phing/classes/phing/system/io/FileReader.php @@ -1,6 +1,6 @@ . */ - -include_once 'phing/system/io/PhingFile.php'; -include_once 'phing/system/io/Reader.php'; + +require_once 'phing/system/io/InputStreamReader.php'; +require_once 'phing/system/io/FileInputStream.php'; /** - * Convenience class for reading files. The constructor of this - * @package phing.system.io + * Convenience class for reading files. + * @package phing.system.io */ +class FileReader extends InputStreamReader { -class FileReader extends Reader { - - protected $file; - protected $fd; - - protected $currentPosition = 0; - protected $mark = 0; - - function __construct($file, $exclusive = false) { - - if ($file instanceof PhingFile) { - $this->file = $file; - } elseif (is_string($file)) { - $this->file = new PhingFile($file); - } else { - throw new Exception("Illegal argument type to " . __METHOD__); - } - } - - function skip($n) { - $this->open(); - - $start = $this->currentPosition; - - $ret = @fseek($this->fd, $n, SEEK_CUR); - if ( $ret === -1 ) - return -1; - - $this->currentPosition = ftell($this->fd); - - if ( $start > $this->currentPosition ) - $skipped = $start - $this->currentPosition; - else - $skipped = $this->currentPosition - $start; - - return $skipped; - } - /** - * Read data from file. - * @param int $len Num chars to read. - * @return string chars read or -1 if eof. + * Construct a new FileReader. + * @param mixed $file PhingFile or string pathname. */ - function read($len = null) { - $this->open(); - if (feof($this->fd)) { - return -1; - } - - // Compute length to read - // possible that filesize($this->file) will be larger than - // available bytes to read, but that's fine -- better to err on high end - $length = ($len === null) ? filesize($this->file->getAbsolutePath()) : $len; - - // Read data - $out = fread($this->fd, $length + 1); // adding 1 seems to ensure that next call to read() will return EOF (-1) - $this->currentPosition = ftell($this->fd); - - return $out; - } - - function mark($n = null) { - $this->mark = $this->currentPosition; - } - - function reset() { - // goes back to last mark, by default this would be 0 (i.e. rewind file). - fseek($this->fd, SEEK_SET, $this->mark); - $this->mark = 0; - } - - function close() { - if ($this->fd === null) { - return true; - } - - if (false === @fclose($this->fd)) { - // FAILED. - $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; - throw new IOException($msg); - } else { - $this->fd = null; - return true; - } + public function __construct($file) { + $in = new FileInputStream($file); + parent::__construct($in); } - - function open() { - global $php_errormsg; - if ($this->fd === null) { - $this->fd = @fopen($this->file->getAbsolutePath(), "rb"); - } - - if ($this->fd === false) { - // fopen FAILED. - // Add error from php to end of log message. $php_errormsg. - $msg = "Cannot fopen ".$this->file->getAbsolutePath().". $php_errormsg"; - throw new IOException($msg); - } - - if (false) { - // Locks don't seem to work on windows??? HELP!!!!!!!!! - // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. - $msg = "Cannot acquire flock on $file. $php_errormsg"; - throw new IOException($msg); - } - - return true; - } - - /** - * Whether eof has been reached with stream. - * @return boolean - */ - function eof() { - return feof($this->fd); - } - - /** - * Reads a entire file and stores the data in the variable - * passed by reference. - * - * @param string $file String. Path and/or name of file to read. - * @param object &$rBuffer Reference. Variable of where to put contents. - * - * @return TRUE on success. Err object on failure. - * @author Charlie Killian, charlie@tizac.com - */ - function readInto(&$rBuffer) { - - $this->open(); - - $fileSize = $this->file->length(); - if ($fileSize === false) { - $msg = "Cannot get filesize of " . $this->file->__toString() . " $php_errormsg"; - throw new IOException($msg); - } - $rBuffer = fread($this->fd, $fileSize); - $this->close(); - } - - /** - * Returns path to file we are reading. - * @return string - */ - function getResource() { - return $this->file->toString(); - } } -?> + diff --git a/buildscripts/phing/classes/phing/system/io/FileSystem.php b/buildscripts/phing/classes/phing/system/io/FileSystem.php old mode 100644 new mode 100755 index 2802ddfb..284be830 --- a/buildscripts/phing/classes/phing/system/io/FileSystem.php +++ b/buildscripts/phing/classes/phing/system/io/FileSystem.php @@ -1,7 +1,7 @@ * @author Hans Lellelid - * @version $Revision: 1.11 $ + * @version $Id$ * @package phing.system.io */ abstract class FileSystem { - /* properties for simple boolean attributes */ + /** + * @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. */ + /** + * 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 */ - function getFileSystem() { + public static function getFileSystem() { if (self::$fs === null) { switch(Phing::getProperty('host.fstype')) { case 'UNIX': @@ -69,7 +89,7 @@ abstract class FileSystem { self::$fs = new WinNTFileSystem(); break; default: - throw new Exception("Host uses unsupported filesystem, unable to proceed"); + throw new IOException("Host uses unsupported filesystem, unable to proceed"); } } return self::$fs; @@ -90,12 +110,16 @@ abstract class FileSystem { /** * 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); @@ -103,12 +127,17 @@ abstract class FileSystem { * 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); @@ -124,18 +153,23 @@ abstract class FileSystem { * 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) { @@ -148,9 +182,11 @@ abstract class FileSystem { * 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 Exception("SYSTEM ERROR method getBooleanAttributes() not implemented by fs driver"); + throw new IOException("getBooleanAttributes() not implemented by fs driver"); } /** @@ -160,6 +196,9 @@ abstract class FileSystem { * 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, @@ -189,11 +228,27 @@ abstract class FileSystem { 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) { @@ -203,20 +258,35 @@ abstract class FileSystem { @clearstatcache(); $strPath = (string) $f->getPath(); - $mtime = @filemtime($strPath); - if (false === $mtime) { - // FAILED. Log and return err. - $msg = "FileSystem::Filemtime() FAILED. Cannot can not get modified time of $strPath. $php_errormsg"; - throw new Exception($msg); + + if (@is_link($strPath)) { + $stats = @lstat($strPath); + + if (!isset($stats['mtime'])) { + $mtime = false; + } else { + $mtime = $stats['mtime']; + } } else { - return (int) $mtime; + $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(); @@ -225,7 +295,7 @@ abstract class FileSystem { return $fs; } else { $msg = "FileSystem::Read() FAILED. Cannot get filesize of $strPath. $php_errormsg"; - throw new Exception($msg); + throw new IOException($msg); } } @@ -237,9 +307,9 @@ abstract class FileSystem { * file or directory with the given pathname already exists. Throw an * IOException if an I/O error occurs. * - * @param string Path of the file to be created. - * - * @throws IOException + * @param string $strPathname Path of the file to be created. + * @throws IOException + * @return boolean */ function createNewFile($strPathname) { if (@file_exists($strPathname)) @@ -257,10 +327,14 @@ abstract class FileSystem { /** * 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) { + function delete(PhingFile $f, $recursive = false) { if ($f->isDirectory()) { - return $this->rmdir($f->getPath()); + return $this->rmdir($f->getPath(), $recursive); } else { return $this->unlink($f->getPath()); } @@ -269,16 +343,21 @@ abstract class FileSystem { /** * 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. + * true if and only if the operation succeeds. + * + * @param PhingFile $f + * @throws IOException */ function deleteOnExit($f) { - throw new Exception("deleteOnExit() not implemented by local fs driver"); + 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 null. + * + * @param PhingFile $f */ function listDir(PhingFile $f) { $strPath = (string) $f->getAbsolutePath(); @@ -300,9 +379,18 @@ abstract class FileSystem { /** * Create a new directory denoted by the given abstract pathname, * returning true if and only if the operation succeeds. - */ - function createDirectory(&$f) { - return @mkdir($f->getAbsolutePath(),0755); + * + * 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; } /** @@ -313,7 +401,7 @@ abstract class FileSystem { * @param PhingFile $f1 abstract source file * @param PhingFile $f2 abstract destination file * @return void - * @throws Exception if rename cannot be performed + * @throws IOException if rename cannot be performed */ function rename(PhingFile $f1, PhingFile $f2) { // get the canonical paths of the file to rename @@ -321,7 +409,7 @@ abstract class FileSystem { $dest = $f2->getAbsolutePath(); if (false === @rename($src, $dest)) { $msg = "Rename FAILED. Cannot rename $src to $dest. $php_errormsg"; - throw new Exception($msg); + throw new IOException($msg); } } @@ -329,14 +417,17 @@ abstract class FileSystem { * 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 Exception + * @throws IOException */ function setLastModifiedTime(PhingFile $f, $time) { $path = $f->getPath(); $success = @touch($path, $time); if (!$success) { - throw new Exception("Could not create directory due to: $php_errormsg"); + throw new IOException("Could not touch '" . $path . "' due to: $php_errormsg"); } } @@ -344,27 +435,34 @@ abstract class FileSystem { * Mark the file or directory denoted by the given abstract pathname as * read-only, returning true if and only if the operation * succeeds. + * + * @param PhingFile $f + * @throws IOException */ function setReadOnly($f) { - throw new Exception("setReadonle() not implemented by local fs driver"); + 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 Exception("SYSTEM ERROR [listRoots() not implemented by local fs driver]"); + 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($f1, $f2) { - throw new Exception("SYSTEM ERROR [compare() not implemented by local fs driver]"); + function compare(PhingFile $f1, PhingFile $f2) { + throw new IOException("compare() not implemented by local fs driver"); } /** @@ -374,17 +472,23 @@ abstract class FileSystem { * @param PhingFile $dest Destination path and name of new file. * * @return void - * @throws Exception if file cannot be copied. + * @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 Exception($msg); + throw new IOException($msg); } try { @@ -394,28 +498,106 @@ abstract class FileSystem { // eat it up for now. } } + + /** + * Copy a file, or recursively copy a folder and its contents + * + * @author Aidan Lister + * @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 pathname String. Path and name of file or directory. - * @param mode Int. The mode (permissions) of the file or - * directory. If using octal add leading 0. eg. 0777. - * Mode is affected by the umask system setting. + * @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 Exception if operation failed. + * @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. $php_errormsg"; - throw new Exception($msg); + $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 */ @@ -425,14 +607,15 @@ abstract class FileSystem { $result = @flock($fp, LOCK_EX); @fclose($fp); if (!$result) { - throw new Exception("Could not lock file '$filename'"); + throw new IOException("Could not lock file '$filename'"); } } /** * Unlocks a file and throws an IO Error if this is not possible. * - * @throws Exception + * @param PhingFile $f + * @throws IOException * @return void */ function unlock(PhingFile $f) { @@ -448,16 +631,16 @@ abstract class FileSystem { /** * Delete a file. * - * @param file String. Path and/or name of file to delete. + * @param string $file Path and/or name of file to delete. * * @return void - * @throws Exception - if an error is encountered. + * @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 Exception($msg); + throw new IOException($msg); } } @@ -478,7 +661,7 @@ abstract class FileSystem { if (false === @symlink($target, $link)) { // Add error from php to end of log message. $php_errormsg. $msg = "FileSystem::Symlink() FAILED. Cannot symlink '$target' to '$link'. $php_errormsg"; - throw new Exception($msg); + throw new IOException($msg); } } diff --git a/buildscripts/phing/classes/phing/system/io/FileWriter.php b/buildscripts/phing/classes/phing/system/io/FileWriter.php index d6265777..d58b0513 100644 --- a/buildscripts/phing/classes/phing/system/io/FileWriter.php +++ b/buildscripts/phing/classes/phing/system/io/FileWriter.php @@ -1,6 +1,6 @@ . */ - -include_once 'phing/system/io/PhingFile.php'; -include_once 'phing/system/io/Writer.php'; + +require_once 'phing/system/io/OutputStreamWriter.php'; +require_once 'phing/system/io/FileOutputStream.php'; /** - * Convenience class for reading files. The constructor of this + * Convenience class for performing file write operations. * * @package phing.system.io */ -class FileWriter extends Writer { - - protected $file; - protected $fd; - - /** Whether to append contents to file. */ - protected $append; - - /** Whether we should attempt to lock the file (currently disabled). */ - protected $exclusive; +class FileWriter extends OutputStreamWriter { /** * Construct a new FileWriter. * @param mixed $file PhingFile or string pathname. * @param boolean $append Append to existing file? - * @param boolean $exclusive Lock file? (currently disabled due to windows incompatibility) */ - function __construct($file, $append = false, $exclusive = false) { - if ($file instanceof PhingFile) { - $this->file = $file; - } elseif (is_string($file)) { - $this->file = new PhingFile($file); - } else { - throw new Exception("Invalid argument type for \$file."); - } - $this->append = $append; - $this->exclusive = $exclusive; - } - - function close() { - if ($this->fd === null) { - return true; - } - - if (false === @fclose($this->fd)) { - // FAILED. - $msg = "Cannot fclose " . $this->file->__toString() . " $php_errormsg"; - throw new IOException($msg); - } else { - $this->fd = null; - return true; - } - } - - function open() { - if ($this->fd === null) { - if ($this->append) { $flags = "ab"; } else { $flags = "wb"; } - $this->fd = @fopen($this->file->getPath(), $flags); - } - - if ($this->fd === false) { - // fopen FAILED. - // Add error from php to end of log message. $php_errormsg. - $msg = "Cannot fopen ".$this->file->getPath()." $php_errormsg"; - throw new IOException($msg); - } - - if (false) { - // Locks don't seem to work on windows??? HELP!!!!!!!!! - // if (FALSE === @flock($fp, LOCK_EX)) { // FAILED. - $msg = "Cannot acquire flock on $file. $php_errormsg"; - throw new IOException($msg); - } - - return true; - } - - function reset() { - // FIXME -- what exactly should this do, if anything? - // reset to beginning of file (i.e. re-open)? - } - - function writeBuffer($buffer) { - - if (!$this->file->canWrite()) { - throw new IOException("No permission to write to file: " . $this->file->__toString()); - } - - $this->open(); - $result = @fwrite($this->fd, $buffer); - $this->close(); - - if ($result === false) { - throw new IOException("Error writing file: ". $this->file->toString()); - } else { - return true; - } - } - - function write($buf, $off = null, $len = null) { - if ( $off === null && $len === null ) - $to_write = $buf; - else - $to_write = substr($buf, $off, $len); - - $this->open(); - $result = @fwrite($this->fd, $to_write); - - if ( $result === false ) { - throw new IOException("Error writing file."); - } else { - return true; - } - } - - function getResource() { - return $this->file->toString(); + 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 index 8c683408..527ce17f 100644 --- a/buildscripts/phing/classes/phing/system/io/FilterReader.php +++ b/buildscripts/phing/classes/phing/system/io/FilterReader.php @@ -1,6 +1,6 @@ . */ -include_once 'phing/system/io/Reader.php'; +require_once 'phing/system/io/Reader.php'; /** - * Convenience class for reading files. The constructor of this - * @package phing.system.io - * - * TODO: All filters should be ProjectComponents, too! + * 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; - //parent::__construct(new FileReader($file, $exclusive)); } public function setReader(Reader $in) { @@ -61,12 +61,8 @@ class FilterReader extends Reader { return $this->in->close(); } - public function open() { - return $this->in->open(); - } - function getResource() { return $this->in->getResource(); } } -?> + diff --git a/buildscripts/phing/classes/phing/system/io/IOException.php b/buildscripts/phing/classes/phing/system/io/IOException.php index e2c73b27..8aa1465f 100644 --- a/buildscripts/phing/classes/phing/system/io/IOException.php +++ b/buildscripts/phing/classes/phing/system/io/IOException.php @@ -1,6 +1,6 @@ \ No newline at end of file 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 @@ +. + */ + +/** + * 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 @@ +. + */ + +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 @@ +. + */ + +/** + * 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 @@ +. + */ + +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 old mode 100644 new mode 100755 index cd881963..871afedd --- a/buildscripts/phing/classes/phing/system/io/PhingFile.php +++ b/buildscripts/phing/classes/phing/system/io/PhingFile.php @@ -1,6 +1,6 @@ prefixLength; } /* -- constructors not called by signature match, so we need some helpers --*/ - function _constructPathname($pathname) { + /** + * + * Enter description here ... + * @param unknown_type $pathname + */ + protected function _constructPathname($pathname) { // obtain ref to the filesystem layer $fs = FileSystem::getFileSystem(); @@ -90,7 +102,13 @@ class PhingFile { $this->prefixLength = (int) $fs->prefixLength($this->path); } - function _constructStringParentStringChild($parent, $child = null) { + /** + * + * 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(); @@ -109,7 +127,13 @@ class PhingFile { $this->prefixLength = (int) $fs->prefixLength($this->path); } - function _constructFileParentStringChild($parent, $child = null) { + /** + * + * 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(); @@ -166,7 +190,7 @@ class PhingFile { // 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))) { + if (($this->prefixLength > 0) && (strlen($this->path) > $this->prefixLength)) { return substr($this->path, 0, $this->prefixLength); } return null; @@ -200,12 +224,34 @@ class PhingFile { * string uses the default name-separator character to separate the names * in the name sequence. * - * @return The string form of this abstract pathname + * @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 @@ -213,7 +259,7 @@ class PhingFile { * if its prefix is a drive specifier followed by "\\", or if its prefix * is "\\". * - * @return true if this abstract pathname is absolute, false otherwise + * @return boolean true if this abstract pathname is absolute, false otherwise */ function isAbsolute() { return ($this->prefixLength !== 0); @@ -235,9 +281,9 @@ class PhingFile { * pathname, if any; if not, it is resolved against the current user * directory. * - * @return The absolute pathname string denoting the same file or - * directory as this abstract pathname - * @see #isAbsolute() + * @return string The absolute pathname string denoting the same file or + * directory as this abstract pathname + * @see #isAbsolute() */ function getAbsolutePath() { $fs = FileSystem::getFileSystem(); @@ -248,8 +294,8 @@ class PhingFile { * Returns the absolute form of this abstract pathname. Equivalent to * getAbsolutePath. * - * @return The absolute abstract pathname denoting the same file or - * directory as this abstract pathname + * @return string The absolute abstract pathname denoting the same file or + * directory as this abstract pathname */ function getAbsoluteFile() { return new PhingFile((string) $this->getAbsolutePath()); @@ -277,8 +323,8 @@ class PhingFile { * file or directory may be different from the canonical form of the same * pathname after the file or directory is deleted. * - * @return The canonical pathname string denoting the same file or - * directory as this abstract pathname + * @return string The canonical pathname string denoting the same file or + * directory as this abstract pathname */ function getCanonicalPath() { $fs = FileSystem::getFileSystem(); @@ -309,8 +355,8 @@ class PhingFile { * URI, via the toURI() method, and then converting the URI * into a URL via the URI::toURL() * - * @return A URL object representing the equivalent file URL - * + * @return void A URL object representing the equivalent file URL + * @todo Not implemented yet * */ function toURL() { @@ -322,7 +368,8 @@ class PhingFile { /** * Constructs a file: URI that represents this abstract pathname. - * Not implemented yet + * @todo Not implemented yet + * @return void */ function toURI() { /* @@ -334,6 +381,13 @@ class PhingFile { */ } + /** + * + * Enter description here ... + * @param PhingFile|string $path + * @param boolean $isDirectory + * @return string + */ function _slashify($path, $isDirectory) { $p = (string) $path; @@ -358,15 +412,15 @@ class PhingFile { * Tests whether the application can read the file denoted by this * abstract pathname. * - * @return true if and only if the file specified by this - * abstract pathname exists and can be read by the - * application; false otherwise + * @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_readable($this->getAbsolutePath()); + return (boolean) @is_link($this->getAbsolutePath()) || @is_readable($this->getAbsolutePath()); } return false; } @@ -375,11 +429,10 @@ class PhingFile { * Tests whether the application can modify to the file denoted by this * abstract pathname. * - * @return true if and only if the file system actually - * contains a file denoted by this abstract pathname and - * the application is allowed to write to the file; - * false otherwise. - * + * @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(); @@ -389,13 +442,16 @@ class PhingFile { /** * Tests whether the file denoted by this abstract pathname exists. * - * @return true if and only if the file denoted by this - * abstract pathname exists; false otherwise - * + * @return boolean true if and only if the file denoted by this + * abstract pathname exists; false otherwise */ function exists() { - if ($this->isFile()) { - return @file_exists($this->path); + 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); } @@ -405,17 +461,17 @@ class PhingFile { * Tests whether the file denoted by this abstract pathname is a * directory. * - * @return true if and only if the file denoted by this - * abstract pathname exists and is a directory; - * false otherwise - * + * @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); + return @is_dir($this->path) && !@is_link($this->path); } /** @@ -424,11 +480,12 @@ class PhingFile { * addition, satisfies other system-dependent criteria. Any non-directory * file created by a Java application is guaranteed to be a normal file. * - * @return true if and only if the file denoted by this - * abstract pathname exists and is a normal file; - * false otherwise + * @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); } @@ -441,9 +498,9 @@ class PhingFile { * hidden if it has been marked as such in the filesystem. Currently there * seems to be no way to dermine isHidden on Win file systems via PHP * - * @return true if and only if the file denoted by this - * abstract pathname is hidden according to the conventions of the - * underlying platform + * @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(); @@ -452,15 +509,42 @@ class PhingFile { } 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 A integer value representing the time the file was - * last modified, measured in milliseconds since the epoch - * (00:00:00 GMT, January 1, 1970), or 0 if the - * file does not exist or if an I/O error occurs + * @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(); @@ -474,8 +558,8 @@ class PhingFile { * Returns the length of the file denoted by this abstract pathname. * The return value is unspecified if this pathname denotes a directory. * - * @return The length, in bytes, of the file denoted by this abstract - * pathname, or 0 if the file does not exist + * @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(); @@ -507,9 +591,9 @@ class PhingFile { * are a single operation that is atomic with respect to all other * filesystem activities that might affect the file. * - * @return true if the named file does not exist and was - * successfully created; false if the named file - * already exists + * @return boolean true if the named file does not exist and was + * successfully created; false if the named file + * already exists * @throws IOException if file can't be created */ function createNewFile($parents=true, $mode=0777) { @@ -522,15 +606,15 @@ class PhingFile { * this pathname denotes a directory, then the directory must be empty in * order to be deleted. * - * @return true if and only if the file or directory is - * successfully deleted; false otherwise + * @return boolean true if and only if the file or directory is + * successfully deleted; false otherwise */ - function delete() { + function delete($recursive = false) { $fs = FileSystem::getFileSystem(); - if ($fs->checkAccess($this, true) !== true) { - throw new IOException("No read access to " . $this->path."\n"); + if ($fs->canDelete($this) !== true) { + throw new IOException("Cannot delete " . $this->path . "\n"); } - return $fs->delete($this); + return $fs->delete($this, $recursive); } /** @@ -563,18 +647,23 @@ class PhingFile { * will appear in any specific order; they are not, in particular, * guaranteed to appear in alphabetical order. * - * @return An array of strings naming the files and directories in the - * directory denoted by this abstract pathname. The array will be - * empty if the directory is empty. Returns null if - * this abstract pathname does not denote a directory, or if an - * I/O error occurs. - * + * @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) { @@ -594,46 +683,46 @@ class PhingFile { * operation fails it may have succeeded in creating some of the necessary * parent directories. * - * @return true if and only if the directory was created, - * along with all necessary parent directories; false - * otherwise - * @throws IOException + * @return boolean true if and only if the directory was created, + * along with all necessary parent directories; false + * otherwise + * @throws IOException */ - function mkdirs() { + function mkdirs($mode = 0755) { if ($this->exists()) { return false; } - try { - if ($this->mkdir()) { - return true; - } - } catch (IOException $ioe) { - // IOException from mkdir() means that directory propbably didn't exist. - } + 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() && $this->mkdir())); + return (($parentFile !== null) && ($parentFile->mkdirs($mode) && $this->mkdir($mode))); } /** * Creates the directory named by this abstract pathname. * - * @return true if and only if the directory was created; false otherwise - * @throws IOException + * @return boolean true if and only if the directory was created; false otherwise + * @throws IOException */ - function mkdir() { + 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); + return $fs->createDirectory($this, $mode); } /** * Renames the file denoted by this abstract pathname. * - * @param destFile The new abstract pathname for the named file - * @return true if and only if the renaming succeeded; false otherwise + * @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(); @@ -647,8 +736,8 @@ class PhingFile { * Simple-copies file denoted by this abstract pathname into another * PhingFile * - * @param PhingFile $destFile The new abstract pathname for the named file - * @return true if and only if the renaming succeeded; false otherwise + * @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(); @@ -674,9 +763,9 @@ class PhingFile { * lastModified method will return the (possibly truncated) time argument * that was passed to this method. * - * @param time The new last-modified time, measured in milliseconds since - * the epoch (00:00:00 GMT, January 1, 1970) - * @return true if and only if the operation succeeded; false otherwise + * @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; @@ -684,11 +773,7 @@ class PhingFile { throw new Exception("IllegalArgumentException, Negative $time\n"); } - // FIXME check if accessible $fs = FileSystem::getFileSystem(); - if ($fs->checkAccess($this, true) !== true) { - throw new IOException("File::setLastModified(). No write access to file\n"); - } return $fs->setLastModifiedTime($this, $time); } @@ -699,7 +784,7 @@ class PhingFile { * marked to allow write access. Whether or not a read-only file or * directory may be deleted depends upon the underlying system. * - * @return true if and only if the operation succeeded; false otherwise + * @return boolean true if and only if the operation succeeded; false otherwise */ function setReadOnly() { $fs = FileSystem::getFileSystem(); @@ -710,6 +795,40 @@ class PhingFile { 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. @@ -757,10 +876,10 @@ class PhingFile { * platform will be returned by this method, while PhingFile * objects containing UNC pathnames will not be returned by this method. * - * @return An array of PhingFile objects denoting the available - * filesystem roots, or null if the set of roots - * could not be determined. The array will be empty if there are - * no filesystem roots. + * @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(); @@ -771,8 +890,9 @@ class PhingFile { /** * Returns the path to the temp directory. + * @return string */ - function getTempDir() { + public static function getTempDir() { return Phing::getProperty('php.tmpdir'); } @@ -782,11 +902,11 @@ class PhingFile { * is a reference to a PhingFile Object. * Then, the file is locked for exclusive reading/writing. * - * @author manuel holtgrewe, grin@gmx.net - * @throws IOException - * @access public + * @author manuel holtgrewe, grin@gmx.net + * @throws IOException + * @return PhingFile */ - function createTempFile($prefix, $suffix, PhingFile $directory) { + public static function createTempFile($prefix, $suffix, PhingFile $directory) { // quick but efficient hack to create a unique filename ;-) $result = null; @@ -853,14 +973,24 @@ class PhingFile { return false; } - /** Backwards compatibility -- use PHP5's native __tostring method. */ - function toString() { - return $this->getPath(); + /** + * Backwards compatibility - @see __toString() + * + * @return string + */ + public function toString() + { + return $this->__toString(); } - /** PHP5's native method. */ - function __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 old mode 100644 new mode 100755 index 1e377378..92159469 --- a/buildscripts/phing/classes/phing/system/io/Reader.php +++ b/buildscripts/phing/classes/phing/system/io/Reader.php @@ -1,6 +1,6 @@ * @author Yannick Lecaillez - * @version $Revision: 1.5 $ + * @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(); - /** - * Open stream for reading. - */ - abstract public function open(); - /** * Returns the filename, url, etc. that is being read from. * This is critical for, e.g., ExpatParser's ability to know @@ -76,13 +75,17 @@ abstract class Reader { * Whether marking is supported. * @return boolean */ - public function markSupported() {} + public function markSupported() { + return false; + } /** * Is stream ready for reading. * @return boolean */ - public function ready() {} + 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 index 689a2115..e8b493e9 100644 --- a/buildscripts/phing/classes/phing/system/io/StringReader.php +++ b/buildscripts/phing/classes/phing/system/io/StringReader.php @@ -1,6 +1,6 @@ _string . '"'; } } -?> + diff --git a/buildscripts/phing/classes/phing/system/io/TokenReader.php b/buildscripts/phing/classes/phing/system/io/TokenReader.php deleted file mode 100644 index a57d994c..00000000 --- a/buildscripts/phing/classes/phing/system/io/TokenReader.php +++ /dev/null @@ -1,51 +0,0 @@ -. -*/ - -include_once 'phing/system/io/Reader.php'; -include_once 'phing/filters/ReplaceTokens.php'; // for class Token - -/** - * Abstract class for reading Tokens from a resource - * - * @author Manuel Holtgewe - * @version $Revision: 1.3 $ - * @access public - * @package phing.system.io - */ -class TokenReader extends Reader { - - /** - * Constructor - */ - function __construct() { - } - - /** - * Reads a token from the resource and returns it as a - * Token object. - * - * @access public - */ - function readToken() { - } -} - -?> diff --git a/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php old mode 100644 new mode 100755 index fb4e49b4..739ff6f6 --- a/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php +++ b/buildscripts/phing/classes/phing/system/io/UnixFileSystem.php @@ -1,6 +1,6 @@ getName(); $hidden = (strlen($name) > 0) && ($name{0} == '.'); @@ -207,23 +207,47 @@ class UnixFileSystem extends FileSystem { $perms = (int) (@fileperms($strPath) & 0444); return FileSystem::Chmod($strPath, $perms); } else { - throw new Exception("IllegalArgutmentType: Argument is not File"); + throw new Exception("IllegalArgumentType: Argument is not File"); } } /** * compares file paths lexicographically */ - function compare($f1, $f2) { - if ( ($f1 instanceof PhingFile) && ($f2 instanceof PhingFile) ) { - $f1Path = $f1->getPath(); - $f2Path = $f2->getPath(); - return (boolean) strcmp((string) $f1Path, (string) $f2Path); - } else { - throw new Exception("IllegalArgutmentType: Argument is not PhingFile"); - } + 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() { @@ -263,4 +287,16 @@ class UnixFileSystem extends FileSystem { 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 index c32c21ff..58331cde 100644 --- a/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php +++ b/buildscripts/phing/classes/phing/system/io/Win32FileSystem.php @@ -1,6 +1,6 @@ isSlash($strPath{$src})) { $src++; @@ -349,7 +349,7 @@ class Win32FileSystem extends FileSystem { $pl = (int) $f->getPrefixLength(); if (($pl === 2) && ($path{0} === $this->slash)) { - return path; // UNC + return $path; // UNC } if ($pl === 3) { @@ -471,7 +471,7 @@ class Win32FileSystem extends FileSystem { @closedir($dir); return $vv; } - + } -?> + diff --git a/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php index 86f76d80..1eae49c4 100644 --- a/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php +++ b/buildscripts/phing/classes/phing/system/io/WinNTFileSystem.php @@ -1,6 +1,6 @@ + diff --git a/buildscripts/phing/classes/phing/system/io/Writer.php b/buildscripts/phing/classes/phing/system/io/Writer.php index 5e1a69b9..86fa67e9 100644 --- a/buildscripts/phing/classes/phing/system/io/Writer.php +++ b/buildscripts/phing/classes/phing/system/io/Writer.php @@ -1,6 +1,6 @@ diff --git a/buildscripts/phing/classes/phing/system/lang/Character.php b/buildscripts/phing/classes/phing/system/lang/Character.php index bb7a5589..60285df6 100644 --- a/buildscripts/phing/classes/phing/system/lang/Character.php +++ b/buildscripts/phing/classes/phing/system/lang/Character.php @@ -1,6 +1,6 @@ + diff --git a/buildscripts/phing/classes/phing/system/lang/EventObject.php b/buildscripts/phing/classes/phing/system/lang/EventObject.php index 4a2211bc..489a82a8 100644 --- a/buildscripts/phing/classes/phing/system/lang/EventObject.php +++ b/buildscripts/phing/classes/phing/system/lang/EventObject.php @@ -1,6 +1,6 @@ + diff --git a/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php index ff48c785..5da28838 100644 --- a/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php +++ b/buildscripts/phing/classes/phing/system/lang/FileNotFoundException.php @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/NullPointerException.php b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php index 38fa5c10..ccf080f5 100644 --- a/buildscripts/phing/classes/phing/system/lang/NullPointerException.php +++ b/buildscripts/phing/classes/phing/system/lang/NullPointerException.php @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/lang/SecurityException.php b/buildscripts/phing/classes/phing/system/lang/SecurityException.php index 21e8b1c3..74013bc0 100644 --- a/buildscripts/phing/classes/phing/system/lang/SecurityException.php +++ b/buildscripts/phing/classes/phing/system/lang/SecurityException.php @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/buildscripts/phing/classes/phing/system/util/Message.php b/buildscripts/phing/classes/phing/system/util/Message.php deleted file mode 100644 index bf7bb56b..00000000 --- a/buildscripts/phing/classes/phing/system/util/Message.php +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/buildscripts/phing/classes/phing/system/util/Properties.php b/buildscripts/phing/classes/phing/system/util/Properties.php old mode 100644 new mode 100755 index deff2cdf..4ffd04fc --- a/buildscripts/phing/classes/phing/system/util/Properties.php +++ b/buildscripts/phing/classes/phing/system/util/Properties.php @@ -1,7 +1,7 @@ $value) { + $this->setProperty($key, $value); + } + } + } /** * Load properties from a file. @@ -46,6 +65,8 @@ class Properties { 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()); } @@ -75,21 +96,17 @@ class Properties { $sec_name = ""; foreach($lines as $line) { + // strip comments and leading/trailing spaces + $line = trim(preg_replace("/\s+[;#]\s.+$/", "", $line)); - $line = trim($line); - - if($line == "") - continue; - - if ($line{0} == '#' or $line{0} == ';') { - // it's a comment, so continue to next line + if (empty($line) || $line[0] == ';' || $line[0] == '#') { continue; - } else { - $pos = strpos($line, '='); - $property = trim(substr($line, 0, $pos)); - $value = trim(substr($line, $pos + 1)); - $this->properties[$property] = $this->inVal($value); } + + $pos = strpos($line, '='); + $property = trim(substr($line, 0, $pos)); + $value = trim(substr($line, $pos + 1)); + $this->properties[$property] = $this->inVal($value); } // for each line } @@ -135,7 +152,7 @@ class Properties { public function toString() { $buf = ""; foreach($this->properties as $key => $item) { - $buf .= $key . "=" . $this->outVal($item) . Phing::getProperty('line.separator'); + $buf .= $key . "=" . $this->outVal($item) . PHP_EOL; } return $buf; } @@ -148,15 +165,22 @@ class Properties { * @return void * @throws IOException - on error writing properties file. */ - function store(PhingFile $file, $header = null) { + 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); - $fw->open(); if ($header !== null) { - $fw->write( "# " . $header . Phing::getProperty("line.separator") ); + $fw->write( "# " . $header . PHP_EOL ); } $fw->write($this->toString()); $fw->close(); @@ -215,7 +239,10 @@ class Properties { * @return mixed Old property value or NULL if none was set. */ function setProperty($key, $value) { - $oldValue = @$this->properties[$key]; + $oldValue = null; + if (isset($this->properties[$key])) { + $oldValue = $this->properties[$key]; + } $this->properties[$key] = $value; return $oldValue; } @@ -232,6 +259,23 @@ class Properties { 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 @@ -267,4 +311,4 @@ class Properties { } } -?> + diff --git a/buildscripts/phing/classes/phing/system/util/Register.php b/buildscripts/phing/classes/phing/system/util/Register.php old mode 100644 new mode 100755 index 5ef2b2fd..56ab0e45 --- a/buildscripts/phing/classes/phing/system/util/Register.php +++ b/buildscripts/phing/classes/phing/system/util/Register.php @@ -35,7 +35,7 @@ *
* * @author Hans Lellelid - * @version $Revision: 1.3 $ + * @version $Id$ * @package phing.system.util */ class Register { @@ -62,6 +62,8 @@ class Register { /** * Represents a slot in the register. + * + * @package phing.system.util */ class RegisterSlot { @@ -111,5 +113,37 @@ class RegisterSlot { 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 old mode 100644 new mode 100755 index a2a665b0..2d2bcc01 --- a/buildscripts/phing/classes/phing/system/util/Timer.php +++ b/buildscripts/phing/classes/phing/system/util/Timer.php @@ -1,6 +1,6 @@ * @package phing.system.util - * @version $Revision: 1.5 $ $Date: 2003/12/24 13:02:09 $ + * @version $Id$ */ class Timer { diff --git a/buildscripts/phing/classes/phing/tasks/defaults.properties b/buildscripts/phing/classes/phing/tasks/defaults.properties old mode 100644 new mode 100755 index d0e62eff..32a03295 --- a/buildscripts/phing/classes/phing/tasks/defaults.properties +++ b/buildscripts/phing/classes/phing/tasks/defaults.properties @@ -3,13 +3,15 @@ ; ------------------------------------- ; 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 @@ -17,7 +19,7 @@ cvspass=phing.tasks.system.CvsPassTask delete=phing.tasks.system.DeleteTask echo=phing.tasks.system.EchoTask exec=phing.tasks.system.ExecTask -fail=phing.tasks.system.ExitTask +fail=phing.tasks.system.FailTask foreach=phing.tasks.system.ForeachTask includepath=phing.tasks.system.IncludePathTask input=phing.tasks.system.InputTask @@ -38,32 +40,106 @@ 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. -sql=phing.tasks.ext.CreoleSQLExecTask +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 -phplint=phing.tasks.ext.PhpLintTask +unzip=phing.tasks.ext.UnzipTask +waitfor=phing.tasks.system.WaitForTask +trycatch=phing.tasks.system.TryCatchTask ; "ext" tasks -phpdoc=phing.tasks.ext.phpdoc.PHPDocumentorTask +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 -phpunit2=phing.tasks.ext.phpunit2.PHPUnit2Task -phpunit2report=phing.tasks.ext.phpunit2.PHPUnit2ReportTask +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 \ No newline at end of file +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 index aa43a0e4..13ccd73d 100644 --- a/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php +++ b/buildscripts/phing/classes/phing/tasks/ext/CapsuleTask.php @@ -1,7 +1,7 @@ - * @version $Revision: 1.17 $ + * @version $Id: 205bc55fd1f7f36783d105ff2d0e27357282bbed $ * @package phing.tasks.ext */ class CapsuleTask extends Task { @@ -185,7 +185,7 @@ class CapsuleTask extends Task { public function setOutputDirectory(PhingFile $outputDirectory) { try { if (!$outputDirectory->exists()) { - $this->log("Output directory does not exist, creating: " . $outputDirectory->getPath(),PROJECT_MSG_VERBOSE); + $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()); } @@ -393,7 +393,7 @@ class CapsuleTask extends Task { // reset value, and then // read in teh contents of the file into that var $value = ""; - $f = new PhingFile($project->resolveFile($value)->getCanonicalPath()); + $f = new PhingFile($this->project->resolveFile($value)->getCanonicalPath()); if ($f->exists()) { $fr = new FileReader($f); $fr->readInto($value); @@ -453,25 +453,27 @@ class CapsuleTask extends Task { /** * 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; - function setName($v) { + public function setName($v) { $this->name = $v; } - function setValue($v) { + public function setValue($v) { $this->value = $v; } - function getName() { + public function getName() { return $this->name; } - function getValue() { + public function getValue() { return $this->value; } diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php deleted file mode 100644 index d35e44f4..00000000 --- a/buildscripts/phing/classes/phing/tasks/ext/CreoleSQLExecTask.php +++ /dev/null @@ -1,556 +0,0 @@ -. - */ - -require_once 'phing/tasks/ext/CreoleTask.php'; -include_once 'phing/system/io/StringReader.php'; - -/** - * Executes a series of SQL statements on a database using Creole. - * - *

Statements can - * either be read in from a text file using the src attribute or from - * between the enclosing SQL tags.

- * - *

Multiple statements can be provided, separated by semicolons (or the - * defined delimiter). Individual lines within the statements can be - * commented using either --, // or REM at the start of the line.

- * - *

The autocommit 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.

- * - *

The onerror attribute specifies how to proceed when an error occurs - * during the execution of one of the statements. - * The possible values are: continue execution, only show the error; - * stop execution and commit transaction; - * and abort execution and transaction and fail task.

- * - * @author Hans Lellelid (Phing) - * @author Jeff Martin (Ant) - * @author Michael McCallum (Ant) - * @author Tim Stephenson (Ant) - * @package phing.tasks.ext - * @version $Revision: 1.21 $ - */ -class CreoleSQLExecTask extends CreoleTask { - - private $goodSql = 0; - private $totalSql = 0; - - const DELIM_ROW = "row"; - const DELIM_NORMAL = "normal"; - - /** - * Database connection - */ - private $conn = null; - - /** - * files to load - */ - private $filesets = array(); - - /** - * SQL statement - */ - private $statement = null; - - /** - * SQL input file - */ - private $srcFile = null; - - /** - * SQL input command - */ - private $sqlCommand = ""; - - /** - * SQL transactions to perform - */ - private $transactions = array(); - - /** - * SQL Statement delimiter - */ - private $delimiter = ";"; - - /** - * The delimiter type indicating whether the delimiter will - * only be recognized on a line by itself - */ - private $delimiterType = "normal"; // can't use constant just defined - - /** - * Print SQL results. - */ - private $print = false; - - /** - * Print header columns. - */ - private $showheaders = true; - - /** - * Results Output file. - */ - private $output = null; - - - /** - * Action to perform if an error is found - **/ - private $onError = "abort"; - - /** - * Encoding to use when reading SQL statements from a file - */ - private $encoding = null; - - /** - * Append to an existing file or overwrite it? - */ - private $append = false; - - /** - * Set the name of the SQL file to be run. - * Required unless statements are enclosed in the build file - */ - public function setSrc(PhingFile $srcFile) { - $this->srcFile = $srcFile; - } - - /** - * Set an inline SQL command to execute. - * NB: Properties are not expanded in this text. - */ - public function addText($sql) { - $this->sqlCommand .= $sql; - } - - /** - * Adds a set of files (nested fileset attribute). - */ - public function addFileset(FileSet $set) { - $this->filesets[] = $set; - } - - /** - * Add a SQL transaction to execute - */ - public function createTransaction() { - $t = new SQLExecTransaction($this); - $this->transactions[] = $t; - return $t; - } - - /** - * Set the file encoding to use on the SQL files read in - * - * @param encoding the encoding to use on the files - */ - public function setEncoding($encoding) { - $this->encoding = $encoding; - } - - /** - * Set the statement delimiter. - * - *

For example, set this to "go" and delimitertype to "ROW" for - * Sybase ASE or MS SQL Server.

- * - * @param delimiter - */ - public function setDelimiter($delimiter) - { - $this->delimiter = $delimiter; - } - - /** - * Set the Delimiter type for this sql task. The delimiter type takes two - * values - normal and row. Normal means that any occurence of the delimiter - * terminate the SQL command whereas with row, only a line containing just - * the delimiter is recognized as the end of the command. - * - * @param string $delimiterType - */ - public function setDelimiterType($delimiterType) - { - $this->delimiterType = $delimiterType; - } - - /** - * Set the print flag. - * - * @param boolean $print - */ - public function setPrint($print) - { - $this->print = (boolean) $print; - } - - /** - * Print headers for result sets from the - * statements; optional, default true. - * @param boolean $showheaders - */ - public function setShowheaders($showheaders) { - $this->showheaders = (boolean) $showheaders; - } - - /** - * Set the output file; - * optional, defaults to the console. - * @param PhingFile $output - */ - public function setOutput(PhingFile $output) { - $this->output = $output; - } - - /** - * whether output should be appended to or overwrite - * an existing file. Defaults to false. - * @param $append - */ - public function setAppend($append) { - $this->append = (boolean) $append; - } - - - /** - * Action to perform when statement fails: continue, stop, or abort - * optional; default "abort" - */ - public function setOnerror($action) { - $this->onError = $action; - } - - /** - * Load the sql file and then execute it - * @throws BuildException - */ - public function main() { - - $savedTransaction = array(); - for($i=0,$size=count($this->transactions); $i < $size; $i++) { - $savedTransaction[] = clone $this->transactions[$i]; - } - - $savedSqlCommand = $this->sqlCommand; - - $this->sqlCommand = trim($this->sqlCommand); - - try { - if ($this->srcFile === null && $this->sqlCommand === "" - && empty($this->filesets)) { - if (count($this->transactions) === 0) { - throw new BuildException("Source file or fileset, " - . "transactions or sql statement " - . "must be set!", $this->location); - } - } - - if ($this->srcFile !== null && !$this->srcFile->exists()) { - throw new BuildException("Source file does not exist!", $this->location); - } - - // deal with the filesets - for ($i = 0,$size=count($this->filesets); $i < $size; $i++) { - $fs = $this->filesets[$i]; - $ds = $fs->getDirectoryScanner($this->project); - $srcDir = $fs->getDir($this->project); - - $srcFiles = $ds->getIncludedFiles(); - - // Make a transaction for each file - for ($j=0, $size=count($srcFiles); $j < $size; $j++) { - $t = $this->createTransaction(); - $t->setSrc(new PhingFile($srcDir, $srcFiles[$j])); - } - } - - // Make a transaction group for the outer command - $t = $this->createTransaction(); - if ($this->srcFile) $t->setSrc($this->srcFile); - $t->addText($this->sqlCommand); - $this->conn = $this->getConnection(); - - try { - - $this->statement = $this->conn->createStatement(); - - $out = null; - - try { - - if ($this->output !== null) { - $this->log("Opening output file " . $this->output, PROJECT_MSG_VERBOSE); - $out = new BufferedWriter(new FileWriter($this->output->getAbsolutePath(), $this->append)); - } - - // Process all transactions - for ($i=0,$size=count($this->transactions); $i < $size; $i++) { - $this->transactions[$i]->runTransaction($out); - if (!$this->isAutocommit()) { - $this->log("Commiting transaction", PROJECT_MSG_VERBOSE); - $this->conn->commit(); - } - } - if ($out) $out->close(); - } catch (Exception $e) { - if ($out) $out->close(); - throw $e; - } - } catch (IOException $e) { - if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { - try { - $this->conn->rollback(); - } catch (SQLException $ex) {} - } - throw new BuildException($e->getMessage(), $this->location); - } catch (SQLException $e){ - if (!$this->isAutocommit() && $this->conn !== null && $this->onError == "abort") { - try { - $this->conn->rollback(); - } catch (SQLException $ex) {} - } - throw new BuildException($e->getMessage(), $this->location); - } - - $this->log($this->goodSql . " of " . $this->totalSql . - " SQL statements executed successfully"); - } catch (Exception $e) { - $this->transactions = $savedTransaction; - $this->sqlCommand = $savedSqlCommand; - throw $e; - } - // finally { - $this->transactions = $savedTransaction; - $this->sqlCommand = $savedSqlCommand; - - } - - - /** - * read in lines and execute them - * @throws SQLException, IOException - */ - public function runStatements(Reader $reader, $out = null) { - $sql = ""; - $line = ""; - $in = new BufferedReader($reader); - try { - while (($line = $in->readLine()) !== null) { - $line = trim($line); - $line = ProjectConfigurator::replaceProperties($this->project, $line, - $this->project->getProperties()); - - if (StringHelper::startsWith("//", $line) || - StringHelper::startsWith("--", $line) || - StringHelper::startsWith("#", $line)) { - continue; - } - - if (strlen($line) > 4 - && strtoupper(substr($line,0, 4)) == "REM ") { - continue; - } - - $sql .= " " . $line; - $sql = trim($sql); - - // SQL defines "--" as a comment to EOL - // and in Oracle it may contain a hint - // so we cannot just remove it, instead we must end it - if (strpos($line, "--") !== false) { - $sql .= "\n"; - } - - if ($this->delimiterType == self::DELIM_NORMAL - && StringHelper::endsWith($this->delimiter, $sql) - || $this->delimiterType == self::DELIM_ROW - && $line == $this->delimiter) { - $this->log("SQL: " . $sql, PROJECT_MSG_VERBOSE); - $this->execSQL(StringHelper::substring($sql, 0, strlen($sql) - strlen($this->delimiter)) - 1, $out); - $sql = ""; - } - } - - // Catch any statements not followed by ; - if ($sql !== "") { - $this->execSQL($sql, $out); - } - } catch (SQLException $e) { - throw new BuildException("Error running statements", $e); - } - } - - - /** - * Exec the sql statement. - * @throws SQLException - */ - protected function execSQL($sql, $out = null) { - // Check and ignore empty statements - if (trim($sql) == "") { - return; - } - - try { - $this->totalSql++; - if (!$this->statement->execute($sql)) { - $this->log($this->statement->getUpdateCount() . " rows affected", PROJECT_MSG_VERBOSE); - } else { - if ($this->print) { - $this->printResults($out); - } - } - - $this->goodSql++; - - } catch (SQLException $e) { - $this->log("Failed to execute: " . $sql, PROJECT_MSG_ERR); - if ($this->onError != "continue") { - throw new BuildException("Failed to execute SQL", $e); - } - $this->log($e->getMessage(), PROJECT_MSG_ERR); - } - } - - /** - * print any results in the statement. - * @throw SQLException - */ - protected function printResults($out = null) { - $lSep = Phing::getProperty('line.separator'); - $rs = null; - do { - $rs = $this->statement->getResultSet(); - - if ($rs !== null) { - - $this->log("Processing new result set.", PROJECT_MSG_VERBOSE); - - $line = ""; - - $colsprinted = false; - - while ($rs->next()) { - $fields = $rs->getRow(); - - if (!$colsprinted && $this->showheaders) { - $first = true; - foreach($fields as $fieldName => $ignore) { - if ($first) $first = false; else $line .= ","; - $line .= $fieldName; - } - if ($out !== null) { - $out->write($line); - $out->newLine(); - } else { - print($line.$lSep); - } - $line = ""; - $colsprinted = true; - } // if show headers - - $first = true; - foreach($fields as $columnValue) { - - if ($columnValue != null) { - $columnValue = trim($columnValue); - } - - if ($first) { - $first = false; - } else { - $line .= ","; - } - $line .= $columnValue; - } - - if ($out !== null) { - $out->write($line); - $out->newLine(); - } else { - print($line . $lSep); - } - $line = ""; - - } // while rs->next() - } - } while ($this->statement->getMoreResults()); - print($lSep); - if ($out !== null) $out->newLine(); - } -} - - -/** - * "Inner" class that contains the definition of a new transaction element. - * Transactions allow several files or blocks of statements - * to be executed using the same JDBC connection and commit - * operation in between. - */ -class SQLExecTransaction { - - private $tSrcFile = null; - private $tSqlCommand = ""; - private $parent; - - function __construct($parent) - { - // Parent is required so that we can log things ... - $this->parent = $parent; - } - - public function setSrc(PhingFile $src) - { - $this->tSrcFile = $src; - } - - public function addText($sql) - { - $this->tSqlCommand .= $sql; - } - - /** - * @throws IOException, SQLException - */ - public function runTransaction($out = null) - { - if (!empty($this->tSqlCommand)) { - $this->parent->log("Executing commands", PROJECT_MSG_INFO); - $this->parent->runStatements(new StringReader($this->tSqlCommand), $out); - } - - if ($this->tSrcFile !== null) { - $this->parent->log("Executing file: " . $this->tSrcFile->getAbsolutePath(), - PROJECT_MSG_INFO); - $reader = new FileReader($this->tSrcFile); - $this->parent->runStatements($reader, $out); - $reader->close(); - } - } -} - - diff --git a/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php b/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php deleted file mode 100644 index a1b439e5..00000000 --- a/buildscripts/phing/classes/phing/tasks/ext/CreoleTask.php +++ /dev/null @@ -1,242 +0,0 @@ -. - */ - -require_once 'phing/Task.php'; -include_once 'phing/types/Reference.php'; - -/** - * Handles Creole configuration needed by SQL type tasks. - * - * @author Hans Lellelid (Phing) - * @author Nick Chalko (Ant) - * @author Jeff Martin (Ant) - * @author Michael McCallum (Ant) - * @author Tim Stephenson (Ant) - * @version $Revision: 1.13 $ - * @package phing.tasks.system - */ -abstract class CreoleTask extends Task { - - /** - * Used for caching loaders / driver. This is to avoid - * getting an OutOfMemoryError when calling this task - * multiple times in a row. - * - * NOT IMPLEMENTED YET - */ - private static $loaderMap = array(); - - private $caching = true; - - /** - * Autocommit flag. Default value is false - */ - private $autocommit = false; - - /** - * [optional] Classpath to Creole driver to use. - * @param string - */ - private $driver; - - /** - * DB url. - */ - private $url; - - /** - * User name. - */ - private $userId; - - /** - * Password - */ - private $password; - - /** - * RDBMS Product needed for this SQL. - **/ - private $rdbms; - - /** - * Initialize CreoleTask. - * This method includes any necessary Creole libraries and triggers - * appropriate error if they cannot be found. This is not done in header - * because we may want this class to be loaded w/o triggering an error. - */ - function init() { - include_once 'creole/Creole.php'; - if (!class_exists('Creole')) { - throw new Exception("Creole task depends on Creole classes being on include_path. (i.e. include of 'creole/Creole.php' failed.)"); - } - } - - /** - * Caching loaders / driver. This is to avoid - * getting an OutOfMemoryError when calling this task - * multiple times in a row; default: true - * @param $enable - */ - public function setCaching($enable) { - $this->caching = $enable; - } - - /** - * Sets the database connection URL; required. - * @param url The url to set - */ - public function setUrl($url) { - $this->url = $url; - } - - /** - * Set the Creole driver to be used. - * - * @param string $driver driver class name - */ - public function setDriver($driver) - { - $this->driver = $driver; - } - - /** - * Sets the password; required. - * @param password The password to set - */ - public function setPassword($password) { - $this->password = $password; - } - - /** - * Auto commit flag for database connection; - * optional, default false. - * @param autocommit The autocommit to set - */ - public function setAutocommit($autocommit) { - $this->autocommit = $autocommit; - } - - /** - * Sets the version string, execute task only if - * rdbms version match; optional. - * @param version The version to set - */ - public function setVersion($version) { - $this->version = $version; - } - - protected function getLoaderMap() { - return self::$loaderMap; - } - - - /** - * Creates a new Connection as using the driver, url, userid and password specified. - * The calling method is responsible for closing the connection. - * @return Connection the newly created connection. - * @throws BuildException if the UserId/Password/Url is not set or there is no suitable driver or the driver fails to load. - */ - protected function getConnection() { - - if ($this->url === null) { - throw new BuildException("Url attribute must be set!", $this->location); - } - - try { - - $this->log("Connecting to " . $this->getUrl(), PROJECT_MSG_VERBOSE); - $info = new Properties(); - - $dsn = Creole::parseDSN($this->url); - - if (!isset($dsn["username"]) && $this->userId === null) { - throw new BuildException("Username must be in URL or userid attribute must be set.", $this->location); - } - - if ($this->userId) { - $dsn["username"] = $this->getUserId(); - } - - if ($this->password) { - $dsn["password"] = $this->getPassword(); - } - - if ($this->driver) { - Creole::registerDriver($dsn['phptype'], $this->driver); - } - - $conn = Creole::getConnection($dsn); - $conn->setAutoCommit($this->autocommit); - return $conn; - - } catch (SQLException $e) { - throw new BuildException($e->getMessage(), $this->location); - } - - } - - public function isCaching($value) { - $this->caching = $value; - } - - /** - * Gets the autocommit. - * @return Returns a boolean - */ - public function isAutocommit() { - return $this->autocommit; - } - - /** - * Gets the url. - * @return Returns a String - */ - public function getUrl() { - return $this->url; - } - - /** - * Gets the userId. - * @return Returns a String - */ - public function getUserId() { - return $this->userId; - } - - /** - * Set the user name for the connection; required. - * @param userId The userId to set - */ - public function setUserid($userId) { - $this->userId = $userId; - } - - /** - * Gets the password. - * @return Returns a String - */ - public function getPassword() { - return $this->password; - } - -} diff --git a/buildscripts/phing/classes/phing/tasks/ext/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 @@ +. + */ + +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 @@ +. + */ + +require_once 'phing/tasks/system/MatchingTask.php'; + +/** + * Base class for extracting tasks such as Unzip and Untar. + * + * @author Joakim Bodin + * @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 @@ +. + */ +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 + * @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 @@ +. + */ +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 + * @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 @@ +. + */ + +require_once 'phing/Task.php'; + +/** + * FtpDeployTask + * + * Deploys a set of files to a remote FTP server. + * + * + * Example usage: + * + * + * + * + * + * + * + * + * + * + * + * @author Jorrit Schippers + * @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 @@ +. + */ + +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 + * @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 @@ +. + */ + +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 + * @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 + */ + protected $_headers = array(); + + /** + * Holds additional config data for HTTP_Request2 + * + * @var array + */ + 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 + */ + 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 @@ +. + */ + +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 + * @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 old mode 100644 new mode 100755 index 16d29fb8..0fff88cc --- a/buildscripts/phing/classes/phing/tasks/ext/MailTask.php +++ b/buildscripts/phing/classes/phing/tasks/ext/MailTask.php @@ -1,6 +1,6 @@ The build process is a success... + * The build process is a success... * - * @author Francois Harvey at SecuriWeb (http://www.securiweb.net) - * @version $Revision: 1.1 $ - * @package phing.tasks.ext + * @author Michiel Rook + * @author Francois Harvey at SecuriWeb (http://www.securiweb.net) + * @version $Id: 901fb0efa435ae78d249a50ed0e0f6e5d31e0d32 $ + * @package phing.tasks.ext */ -class MailTask extends Task { - - protected $recipient; - - protected $subject; +class MailTask extends Task +{ + protected $tolist = null; + protected $subject = null; + protected $msg = null; + protected $from = null; + + protected $filesets = array(); - protected $msg; + 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(); - function main() { - $this->log('Sending mail to ' . $this->recipient ); - mail($this->recipient, $this->subject, $this->msg); + 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 */ - function setMsg($msg) { + /** + * Setter for message + */ + public function setMsg($msg) + { $this->setMessage($msg); } - /** alias setter */ - function setMessage($msg) { + /** + * Alias setter + */ + public function setMessage($msg) + { $this->msg = (string) $msg; } - /** setter for subject **/ - function setSubject($subject) { - $this->subject = (string) $subject; + /** + * Setter for subject + */ + public function setSubject($subject) + { + $this->subject = (string) $subject; } - /** setter for recipient **/ - function setRecipient($recipient) { - $this->recipient = (string) $recipient; + /** + * Setter for tolist + */ + public function setToList($tolist) + { + $this->tolist = $tolist; + } + + /** + * Alias for (deprecated) recipient + */ + public function setRecipient($recipient) + { + $this->tolist = (string) $recipient; } - /** alias for recipient **/ - function setTo($recipient) { - $this->recipient = (string) $recipient; + /** + * Alias for to + */ + public function setTo($to) + { + $this->tolist = (string) $to; } - /** Supporting the Message syntax. */ - function addText($msg) + /** + * Supports the Message 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 @@ +. + */ + +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: + * + * + * + * + * + * + * + * + * + * + * @author David Persson + * @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 index b8664aac..2db5ad69 100644 --- a/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php +++ b/buildscripts/phing/classes/phing/tasks/ext/PackageAsPathTask.php @@ -1,7 +1,7 @@ - * @version $Revision: 1.5 $ + * @version $Id: 976dafaf4cafd9ff8f47907a09943ae3963aea79 $ * @package phing.tasks.ext */ class PackageAsPathTask extends Task { 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 @@ +. + * + * @package phing.tasks.ext + */ + +/** + * Uses the DocBlox_Parallel library to run nested Phing tasks concurrently. + * + * WARNING: this task is highly experimental! + * + * @author Michiel Rook + * @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 @@ +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 num leading slashes + * from filenames. + * + * patch's --strip 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 @@ +. + */ + +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