From f2b71e8c0b539c57fc18e003abd6ddde06ebabfb Mon Sep 17 00:00:00 2001 From: Xavier Hanin Date: Thu, 16 Jun 2005 11:18:39 +0000 Subject: [PATCH] migration from private cvs repository git-svn-id: https://svn.apache.org/repos/asf/incubator/ivy/trunk@483981 13f79535-47bb-0310-9956-ffa450edef68 --- .classpath | 15 + .project | 17 + CHANGES.txt | 170 ++ LICENSE.txt | 26 + build.properties | 9 + build.xml | 87 + doc/announce/announce-0.5.txt | 35 + doc/announce/announce-0.6.txt | 16 + doc/announce/announce-0.7.txt | 16 + doc/announce/announce-0.8.txt | 12 + doc/announce/announce-1.0-rc1.txt | 13 + doc/announce/announce-1.0.txt | 40 + doc/announce/announce-1.1.txt | 14 + doc/conflict-solving-algo.html | 97 ++ doc/index.html | 13 + ivy.xml | 10 + src/example/chained-resolvers/build.xml | 18 + .../chainedresolvers-project/build.xml | 68 + .../chainedresolvers-project/ivy.xml | 7 + .../src/example/Hello.java | 20 + .../chained-resolvers/config/ivyconf.xml | 11 + .../config/repository/test-1.0.jar | Bin 0 -> 1131 bytes src/example/dependence/build.xml | 24 + .../dependence/config/ivyconf.properties | 1 + src/example/dependence/config/ivyconf.xml | 14 + src/example/dependence/depending/build.xml | 68 + src/example/dependence/depending/ivy.xml | 6 + .../depending/src/depending/Main.java | 23 + src/example/dependence/standalone/build.xml | 97 ++ src/example/dependence/standalone/ivy.xml | 6 + .../standalone/src/standalone/Main.java | 48 + src/example/dual/build.xml | 18 + src/example/dual/config/ivyconf.xml | 11 + src/example/dual/project/build.xml | 69 + src/example/dual/project/ivy.xml | 7 + .../dual/project/src/example/Hello.java | 37 + .../commons-httpclient-ivy-2.0.2.xml | 11 + src/example/hello-ivy/build.xml | 58 + src/example/hello-ivy/ivy.xml | 6 + src/example/hello-ivy/src/example/Hello.java | 19 + src/example/ivyrep/build.xml | 62 + src/example/ivyrep/ivy.xml | 7 + src/example/ivyrep/src/example/Hello.java | 35 + .../fr/jayasoft/ivy/AbstractArtifact.java | 40 + src/java/fr/jayasoft/ivy/Artifact.java | 35 + src/java/fr/jayasoft/ivy/ArtifactId.java | 77 + src/java/fr/jayasoft/ivy/ArtifactInfo.java | 11 + .../fr/jayasoft/ivy/ArtifactRevisionId.java | 79 + src/java/fr/jayasoft/ivy/Configuration.java | 109 ++ src/java/fr/jayasoft/ivy/ConflictManager.java | 22 + src/java/fr/jayasoft/ivy/DefaultArtifact.java | 60 + .../DefaultDependencyArtifactDescriptor.java | 92 ++ .../ivy/DefaultDependencyDescriptor.java | 192 +++ .../jayasoft/ivy/DefaultModuleDescriptor.java | 274 +++ .../jayasoft/ivy/DefaultModuleRevision.java | 67 + .../ivy/DefaultPublishingDRResolver.java | 13 + .../ivy/DependencyArtifactDescriptor.java | 46 + .../fr/jayasoft/ivy/DependencyDescriptor.java | 33 + .../fr/jayasoft/ivy/DependencyResolver.java | 60 + src/java/fr/jayasoft/ivy/Ivy.java | 1469 +++++++++++++++++ src/java/fr/jayasoft/ivy/IvyAware.java | 10 + src/java/fr/jayasoft/ivy/IvyNode.java | 974 +++++++++++ src/java/fr/jayasoft/ivy/LatestStrategy.java | 24 + src/java/fr/jayasoft/ivy/License.java | 24 + src/java/fr/jayasoft/ivy/MDArtifact.java | 77 + src/java/fr/jayasoft/ivy/Main.java | 203 +++ .../fr/jayasoft/ivy/ModuleDescriptor.java | 99 ++ src/java/fr/jayasoft/ivy/ModuleId.java | 48 + .../fr/jayasoft/ivy/ModuleRevisionId.java | 81 + .../PublishingDependencyRevisionResolver.java | 24 + src/java/fr/jayasoft/ivy/ResolveData.java | 83 + .../jayasoft/ivy/ResolvedModuleRevision.java | 21 + src/java/fr/jayasoft/ivy/ResolvedURL.java | 48 + src/java/fr/jayasoft/ivy/Status.java | 52 + .../fr/jayasoft/ivy/ant/AntMessageImpl.java | 50 + .../jayasoft/ivy/ant/IvyArtifactProperty.java | 110 ++ .../fr/jayasoft/ivy/ant/IvyCachePath.java | 116 ++ src/java/fr/jayasoft/ivy/ant/IvyCheck.java | 74 + .../fr/jayasoft/ivy/ant/IvyConfigure.java | 144 ++ src/java/fr/jayasoft/ivy/ant/IvyDeliver.java | 265 +++ .../ivy/ant/IvyExtractFromSources.java | 185 +++ src/java/fr/jayasoft/ivy/ant/IvyPublish.java | 220 +++ src/java/fr/jayasoft/ivy/ant/IvyReport.java | 202 +++ src/java/fr/jayasoft/ivy/ant/IvyResolve.java | 108 ++ src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java | 89 + src/java/fr/jayasoft/ivy/ant/IvyTask.java | 126 ++ src/java/fr/jayasoft/ivy/ant/IvyVar.java | 121 ++ .../fr/jayasoft/ivy/ant/PackageMapping.java | 48 + src/java/fr/jayasoft/ivy/ant/antlib.xml | 14 + src/java/fr/jayasoft/ivy/ant/ivy.properties | 15 + .../ivy/conflict/AbstractConflictManager.java | 35 + .../ivy/conflict/FixedConflictManager.java | 37 + .../ivy/conflict/LatestConflictManager.java | 115 ++ .../ivy/conflict/NoConflictManager.java | 19 + src/java/fr/jayasoft/ivy/ivyconf.xml | 6 + .../ivy/latest/AbstractLatestStrategy.java | 36 + .../latest/LatestLexicographicStrategy.java | 67 + .../ivy/latest/LatestRevisionStrategy.java | 125 ++ .../ivy/latest/LatestTimeStrategy.java | 33 + .../ivy/report/ArtifactDownloadReport.java | 48 + .../report/ConfigurationResolveReport.java | 211 +++ .../jayasoft/ivy/report/DownloadReport.java | 45 + .../jayasoft/ivy/report/DownloadStatus.java | 27 + .../ivy/report/LogReportOutputter.java | 123 ++ .../jayasoft/ivy/report/ReportOutputter.java | 16 + .../fr/jayasoft/ivy/report/ResolveReport.java | 80 + .../ivy/report/XmlReportOutputter.java | 160 ++ .../jayasoft/ivy/report/ivy-report-graph.xsl | 67 + .../fr/jayasoft/ivy/report/ivy-report.css | 261 +++ .../fr/jayasoft/ivy/report/ivy-report.xsl | 468 ++++++ .../fr/jayasoft/ivy/repository.properties | 7 + .../ivy/repository/AbstractRepository.java | 107 ++ .../jayasoft/ivy/repository/Repository.java | 32 + .../fr/jayasoft/ivy/repository/Resource.java | 14 + .../ivy/repository/TransferEvent.java | 249 +++ .../ivy/repository/TransferListener.java | 15 + .../ivy/repository/file/FileRepository.java | 92 ++ .../ivy/repository/file/FileResource.java | 39 + .../ivy/repository/url/URLRepository.java | 90 + .../ivy/repository/url/URLResource.java | 76 + .../ivy/resolver/AbstractResolver.java | 101 ++ .../resolver/AbstractResourceResolver.java | 205 +++ .../ivy/resolver/AbstractURLResolver.java | 540 ++++++ .../ivy/resolver/ApacheHttpURLLister.java | 26 + .../jayasoft/ivy/resolver/BasicResolver.java | 518 ++++++ .../jayasoft/ivy/resolver/ChainResolver.java | 134 ++ .../jayasoft/ivy/resolver/DualResolver.java | 138 ++ .../ivy/resolver/FileSystemResolver.java | 21 + .../jayasoft/ivy/resolver/FileURLLister.java | 49 + .../ivy/resolver/IBiblioResolver.java | 101 ++ .../jayasoft/ivy/resolver/IvyRepResolver.java | 201 +++ .../fr/jayasoft/ivy/resolver/ModuleEntry.java | 37 + .../ivy/resolver/OrganisationEntry.java | 27 + .../ivy/resolver/RepositoryResolver.java | 154 ++ .../ivy/resolver/ResolvedResource.java | 31 + .../jayasoft/ivy/resolver/ResolverHelper.java | 265 +++ .../jayasoft/ivy/resolver/RevisionEntry.java | 46 + .../fr/jayasoft/ivy/resolver/URLLister.java | 22 + .../fr/jayasoft/ivy/resolver/URLResolver.java | 21 + src/java/fr/jayasoft/ivy/typedef.properties | 14 + .../fr/jayasoft/ivy/url/ApacheURLLister.java | 154 ++ .../fr/jayasoft/ivy/url/BasicURLHandler.java | 104 ++ .../jayasoft/ivy/url/HttpClientHandler.java | 178 ++ src/java/fr/jayasoft/ivy/url/URLHandler.java | 41 + .../ivy/url/URLHandlerDispatcher.java | 61 + .../jayasoft/ivy/url/URLHandlerRegistry.java | 65 + .../fr/jayasoft/ivy/util/Configurator.java | 335 ++++ .../jayasoft/ivy/util/CopyProgressEvent.java | 41 + .../ivy/util/CopyProgressListener.java | 15 + .../jayasoft/ivy/util/DefaultMessageImpl.java | 36 + src/java/fr/jayasoft/ivy/util/FileUtil.java | 89 + src/java/fr/jayasoft/ivy/util/IvyPattern.java | 22 + .../jayasoft/ivy/util/IvyPatternHelper.java | 168 ++ src/java/fr/jayasoft/ivy/util/Message.java | 123 ++ .../fr/jayasoft/ivy/util/MessageImpl.java | 13 + .../fr/jayasoft/ivy/util/StringUtils.java | 27 + src/java/fr/jayasoft/ivy/util/XMLHelper.java | 85 + .../ivy/xml/XmlIvyConfigurationParser.java | 160 ++ .../ivy/xml/XmlModuleDescriptorParser.java | 458 +++++ .../ivy/xml/XmlModuleDescriptorUpdater.java | 225 +++ .../ivy/xml/XmlModuleDescriptorWriter.java | 42 + .../fr/jayasoft/ivy/xml/XmlReportParser.java | 85 + src/java/fr/jayasoft/ivy/xml/ivy.xsd | 188 +++ test/java/fr/jayasoft/ivy/ResolveTest.java | 716 ++++++++ test/java/fr/jayasoft/ivy/RetrieveTest.java | 89 + test/java/fr/jayasoft/ivy/SortTest.java | 55 + .../ivy/ant/IvyArtifactPropertyTest.java | 55 + .../fr/jayasoft/ivy/ant/IvyCachePathTest.java | 82 + .../fr/jayasoft/ivy/ant/IvyConfigureTest.java | 79 + .../fr/jayasoft/ivy/ant/IvyPublishTest.java | 94 ++ .../fr/jayasoft/ivy/ant/IvyResolveTest.java | 86 + .../fr/jayasoft/ivy/ant/IvyRetrieveTest.java | 85 + test/java/fr/jayasoft/ivy/ant/IvyVarTest.java | 61 + test/java/fr/jayasoft/ivy/ant/ivy-failure.xml | 10 + test/java/fr/jayasoft/ivy/ant/ivy-simple.xml | 10 + .../java/fr/jayasoft/ivy/ant/ivyconf-test.xml | 11 + .../fr/jayasoft/ivy/ant/vartest.properties | 2 + .../fr/jayasoft/ivy/dualchainresolverconf.xml | 23 + test/java/fr/jayasoft/ivy/ivy-148.xml | 13 + test/java/fr/jayasoft/ivy/ivy-148b.xml | 13 + .../fr/jayasoft/ivy/ivy-dualchainresolver.xml | 7 + .../latest/LatestRevisionStrategyTest.java | 41 + .../ivy/resolver/ChainResolverTest.java | 126 ++ .../ivy/resolver/DualResolverTest.java | 113 ++ .../ivy/resolver/FileSystemResolverTest.java | 291 ++++ .../jayasoft/ivy/resolver/IBiblioHelper.java | 66 + .../ivy/resolver/IBiblioResolverTest.java | 197 +++ .../ivy/resolver/IvyRepResolverTest.java | 137 ++ .../jayasoft/ivy/resolver/MockResolver.java | 72 + .../ivy/resolver/ResolverTestHelper.java | 99 ++ .../ivy/resolver/URLResolverTest.java | 246 +++ .../ivy/resolver/chainresolverconf.xml | 10 + .../ivy/resolver/dualresolverconf-bad.xml | 9 + .../ivy/resolver/dualresolverconf.xml | 11 + .../ivy/resolver/ibiblioresolverconf.xml | 7 + .../jayasoft/ivy/url/ApacheURLListerTest.java | 74 + .../jayasoft/ivy/url/BasicURLHandlerTest.java | 29 + .../jayasoft/ivy/util/ConfiguratorTest.java | 247 +++ .../xml/XmlIvyConfigurationParserTest.java | 97 ++ .../xml/XmlModuleDescriptorParserTest.java | 399 +++++ .../ivy/xml/XmlModuleUpdaterTest.java | 49 + .../java/fr/jayasoft/ivy/xml/ivyconf-test.xml | 25 + .../fr/jayasoft/ivy/xml/ivyconf-typedef.xml | 10 + .../fr/jayasoft/ivy/xml/ivyconf.properties | 1 + .../fr/jayasoft/ivy/xml/test-bad-version.xml | 6 + test/java/fr/jayasoft/ivy/xml/test-bad.xml | 6 + test/java/fr/jayasoft/ivy/xml/test-bug60.xml | 12 + .../fr/jayasoft/ivy/xml/test-defaultconf.xml | 13 + .../fr/jayasoft/ivy/xml/test-noartifact.xml | 6 + .../jayasoft/ivy/xml/test-nopublication.xml | 14 + .../fr/jayasoft/ivy/xml/test-novalidate.xml | 9 + test/java/fr/jayasoft/ivy/xml/test-simple.xml | 5 + test/java/fr/jayasoft/ivy/xml/test.xml | 84 + test/java/fr/jayasoft/ivy/xml/updated.xml | 80 + .../1/org1/mod1.1/ivys/ivy-1.0.1.xml | 11 + .../1/org1/mod1.1/ivys/ivy-1.0.xml | 11 + .../1/org1/mod1.1/ivys/ivy-1.1.xml | 11 + .../1/org1/mod1.1/ivys/ivy-2.0.xml | 11 + .../1/org1/mod1.1/jars/mod1.1-1.0.jar | 1 + .../1/org1/mod1.1/jars/mod1.1-1.1.jar | 1 + .../1/org1/mod1.1/jars/mod1.1-2.0.jar | 1 + .../1/org1/mod1.2/jars/mod1.2-2.0.jar | 1 + .../1/org1/mod1.2/jars/mod1.2-2.1.jar | 1 + .../1/org1/mod1.2/jars/mod1.2-2.2.jar | 1 + .../1/org1/mod1.3/jars/mod1.3-A-3.0.jar | 1 + .../1/org1/mod1.3/jars/mod1.3-B-3.0.jar | 1 + .../1/org1/mod1.4/ivys/ivy-1.0.1.xml | 12 + .../1/org2/mod2.1/ivys/ivy-0.3.xml | 15 + .../1/org2/mod2.1/ivys/ivy-0.4.xml | 20 + .../1/org2/mod2.1/jars/art21A-0.3.jar | 1 + .../1/org2/mod2.1/jars/art21A-0.4.jar | 1 + .../1/org2/mod2.1/jars/art21B-0.3.jar | 1 + .../1/org2/mod2.1/jars/art21B-0.4.jar | 1 + .../1/org2/mod2.2/ivys/ivy-0.5.xml | 18 + .../1/org2/mod2.2/jars/mod2.2-0.5.jar | 1 + .../1/org2/mod2.3/ivys/ivy-0.4.xml | 23 + .../1/org2/mod2.3/ivys/ivy-0.5.xml | 12 + .../1/org2/mod2.3/ivys/ivy-0.6.xml | 12 + .../1/org2/mod2.3/jars/mod2.3-0.4.jar | 1 + .../1/org6/mod6.1/ivys/ivy-0.3.xml | 17 + test/repositories/2/mod3.1/ivy-1.0.xml | 11 + test/repositories/2/mod3.1/ivy-1.1.xml | 10 + test/repositories/2/mod3.1/mod3.1-1.0.jar | 1 + test/repositories/2/mod3.1/mod3.1-1.1.jar | 1 + test/repositories/2/mod4.1/ivy-4.0.xml | 12 + test/repositories/2/mod4.1/ivy-4.1.xml | 12 + test/repositories/2/mod4.1/ivy-4.2.xml | 12 + test/repositories/2/mod4.1/mod4.1-4.0.jar | 1 + test/repositories/2/mod4.1/mod4.1-4.1.jar | 1 + test/repositories/2/mod5.1/art51A-4.0.jar | 1 + test/repositories/2/mod5.1/art51A-4.1.jar | 1 + test/repositories/2/mod5.1/art51A-4.2.jar | 1 + test/repositories/2/mod5.1/art51B-4.0.jar | 1 + test/repositories/2/mod5.1/art51B-4.1.jar | 1 + test/repositories/2/mod5.1/art51B-4.2.jar | 1 + test/repositories/2/mod5.1/ivy-4.0.xml | 16 + test/repositories/2/mod5.1/ivy-4.1.xml | 16 + test/repositories/2/mod5.1/ivy-4.2.xml | 19 + test/repositories/2/mod5.2/ivy-1.0.xml | 11 + test/repositories/2/mod5.2/ivy-2.0.xml | 15 + test/repositories/2/mod5.2/mod5.2-1.0.jar | 1 + test/repositories/2/mod5.2/mod5.2-2.0.jar | 1 + test/repositories/2/mod6.1/ivy-1.0.xml | 12 + test/repositories/2/mod6.1/ivy-1.1.xml | 12 + test/repositories/2/mod6.1/ivy-1.2.xml | 16 + test/repositories/2/mod6.1/ivy-1.3.xml | 16 + test/repositories/2/mod6.2/ivy-1.0.xml | 11 + test/repositories/2/mod6.3/ivy-1.0.xml | 11 + .../barcode/LinearBarCode-4.10.jar | 0 .../idautomation/barcode/idapdf417-4.10.jar | 0 .../idautomation/barcode/ivy-barcode-4.10.xml | 7 + test/repositories/bug148/ivyconf.properties | 2 + test/repositories/bug148/ivyconf.xml | 17 + .../bug148/jtv/jtv-foo/bar/bar-1.1.0.0.jar | 0 .../jtv/jtv-foo/bar/bar-src-1.1.0.0.jar | 0 .../jtv/jtv-foo/bar/ivy-bar-1.1.0.0.xml | 14 + .../checkmodified/ivy-1.0-after.xml | 11 + .../checkmodified/ivy-1.0-before.xml | 11 + test/repositories/checkmodified/ivy-1.0.xml | 11 + .../dual-local/xerces/xerces/ivy-2.6.2.xml | 10 + .../dual-remote/xerces/xercesImpl-2.6.2.jar | 1 + .../xerces/xmlParserAPIs-2.6.2.jar | 1 + test/repositories/ivyconf.properties | 2 + test/repositories/ivyconf.xml | 20 + test/xsl/test.xml | 70 + 285 files changed, 20411 insertions(+) create mode 100644 .classpath create mode 100644 .project create mode 100644 CHANGES.txt create mode 100644 LICENSE.txt create mode 100644 build.properties create mode 100644 build.xml create mode 100644 doc/announce/announce-0.5.txt create mode 100644 doc/announce/announce-0.6.txt create mode 100644 doc/announce/announce-0.7.txt create mode 100644 doc/announce/announce-0.8.txt create mode 100644 doc/announce/announce-1.0-rc1.txt create mode 100644 doc/announce/announce-1.0.txt create mode 100644 doc/announce/announce-1.1.txt create mode 100644 doc/conflict-solving-algo.html create mode 100644 doc/index.html create mode 100644 ivy.xml create mode 100644 src/example/chained-resolvers/build.xml create mode 100644 src/example/chained-resolvers/chainedresolvers-project/build.xml create mode 100644 src/example/chained-resolvers/chainedresolvers-project/ivy.xml create mode 100644 src/example/chained-resolvers/chainedresolvers-project/src/example/Hello.java create mode 100644 src/example/chained-resolvers/config/ivyconf.xml create mode 100644 src/example/chained-resolvers/config/repository/test-1.0.jar create mode 100644 src/example/dependence/build.xml create mode 100644 src/example/dependence/config/ivyconf.properties create mode 100644 src/example/dependence/config/ivyconf.xml create mode 100644 src/example/dependence/depending/build.xml create mode 100644 src/example/dependence/depending/ivy.xml create mode 100644 src/example/dependence/depending/src/depending/Main.java create mode 100644 src/example/dependence/standalone/build.xml create mode 100644 src/example/dependence/standalone/ivy.xml create mode 100644 src/example/dependence/standalone/src/standalone/Main.java create mode 100644 src/example/dual/build.xml create mode 100644 src/example/dual/config/ivyconf.xml create mode 100644 src/example/dual/project/build.xml create mode 100644 src/example/dual/project/ivy.xml create mode 100644 src/example/dual/project/src/example/Hello.java create mode 100644 src/example/dual/repository/commons-httpclient-ivy-2.0.2.xml create mode 100644 src/example/hello-ivy/build.xml create mode 100644 src/example/hello-ivy/ivy.xml create mode 100644 src/example/hello-ivy/src/example/Hello.java create mode 100644 src/example/ivyrep/build.xml create mode 100644 src/example/ivyrep/ivy.xml create mode 100644 src/example/ivyrep/src/example/Hello.java create mode 100644 src/java/fr/jayasoft/ivy/AbstractArtifact.java create mode 100644 src/java/fr/jayasoft/ivy/Artifact.java create mode 100644 src/java/fr/jayasoft/ivy/ArtifactId.java create mode 100644 src/java/fr/jayasoft/ivy/ArtifactInfo.java create mode 100644 src/java/fr/jayasoft/ivy/ArtifactRevisionId.java create mode 100644 src/java/fr/jayasoft/ivy/Configuration.java create mode 100644 src/java/fr/jayasoft/ivy/ConflictManager.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultArtifact.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultDependencyArtifactDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultModuleDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultModuleRevision.java create mode 100644 src/java/fr/jayasoft/ivy/DefaultPublishingDRResolver.java create mode 100644 src/java/fr/jayasoft/ivy/DependencyArtifactDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/DependencyDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/DependencyResolver.java create mode 100644 src/java/fr/jayasoft/ivy/Ivy.java create mode 100644 src/java/fr/jayasoft/ivy/IvyAware.java create mode 100644 src/java/fr/jayasoft/ivy/IvyNode.java create mode 100644 src/java/fr/jayasoft/ivy/LatestStrategy.java create mode 100644 src/java/fr/jayasoft/ivy/License.java create mode 100644 src/java/fr/jayasoft/ivy/MDArtifact.java create mode 100644 src/java/fr/jayasoft/ivy/Main.java create mode 100644 src/java/fr/jayasoft/ivy/ModuleDescriptor.java create mode 100644 src/java/fr/jayasoft/ivy/ModuleId.java create mode 100644 src/java/fr/jayasoft/ivy/ModuleRevisionId.java create mode 100644 src/java/fr/jayasoft/ivy/PublishingDependencyRevisionResolver.java create mode 100644 src/java/fr/jayasoft/ivy/ResolveData.java create mode 100644 src/java/fr/jayasoft/ivy/ResolvedModuleRevision.java create mode 100644 src/java/fr/jayasoft/ivy/ResolvedURL.java create mode 100644 src/java/fr/jayasoft/ivy/Status.java create mode 100644 src/java/fr/jayasoft/ivy/ant/AntMessageImpl.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyArtifactProperty.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyCachePath.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyCheck.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyConfigure.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyDeliver.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyExtractFromSources.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyPublish.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyReport.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyResolve.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyTask.java create mode 100644 src/java/fr/jayasoft/ivy/ant/IvyVar.java create mode 100644 src/java/fr/jayasoft/ivy/ant/PackageMapping.java create mode 100644 src/java/fr/jayasoft/ivy/ant/antlib.xml create mode 100644 src/java/fr/jayasoft/ivy/ant/ivy.properties create mode 100644 src/java/fr/jayasoft/ivy/conflict/AbstractConflictManager.java create mode 100644 src/java/fr/jayasoft/ivy/conflict/FixedConflictManager.java create mode 100644 src/java/fr/jayasoft/ivy/conflict/LatestConflictManager.java create mode 100644 src/java/fr/jayasoft/ivy/conflict/NoConflictManager.java create mode 100644 src/java/fr/jayasoft/ivy/ivyconf.xml create mode 100644 src/java/fr/jayasoft/ivy/latest/AbstractLatestStrategy.java create mode 100644 src/java/fr/jayasoft/ivy/latest/LatestLexicographicStrategy.java create mode 100644 src/java/fr/jayasoft/ivy/latest/LatestRevisionStrategy.java create mode 100644 src/java/fr/jayasoft/ivy/latest/LatestTimeStrategy.java create mode 100644 src/java/fr/jayasoft/ivy/report/ArtifactDownloadReport.java create mode 100644 src/java/fr/jayasoft/ivy/report/ConfigurationResolveReport.java create mode 100644 src/java/fr/jayasoft/ivy/report/DownloadReport.java create mode 100644 src/java/fr/jayasoft/ivy/report/DownloadStatus.java create mode 100644 src/java/fr/jayasoft/ivy/report/LogReportOutputter.java create mode 100644 src/java/fr/jayasoft/ivy/report/ReportOutputter.java create mode 100644 src/java/fr/jayasoft/ivy/report/ResolveReport.java create mode 100644 src/java/fr/jayasoft/ivy/report/XmlReportOutputter.java create mode 100644 src/java/fr/jayasoft/ivy/report/ivy-report-graph.xsl create mode 100644 src/java/fr/jayasoft/ivy/report/ivy-report.css create mode 100644 src/java/fr/jayasoft/ivy/report/ivy-report.xsl create mode 100644 src/java/fr/jayasoft/ivy/repository.properties create mode 100644 src/java/fr/jayasoft/ivy/repository/AbstractRepository.java create mode 100644 src/java/fr/jayasoft/ivy/repository/Repository.java create mode 100644 src/java/fr/jayasoft/ivy/repository/Resource.java create mode 100644 src/java/fr/jayasoft/ivy/repository/TransferEvent.java create mode 100644 src/java/fr/jayasoft/ivy/repository/TransferListener.java create mode 100644 src/java/fr/jayasoft/ivy/repository/file/FileRepository.java create mode 100644 src/java/fr/jayasoft/ivy/repository/file/FileResource.java create mode 100644 src/java/fr/jayasoft/ivy/repository/url/URLRepository.java create mode 100644 src/java/fr/jayasoft/ivy/repository/url/URLResource.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/AbstractResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/AbstractResourceResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/AbstractURLResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/ApacheHttpURLLister.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/BasicResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/ChainResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/DualResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/FileSystemResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/FileURLLister.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/IBiblioResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/IvyRepResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/ModuleEntry.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/OrganisationEntry.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/RepositoryResolver.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/ResolvedResource.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/ResolverHelper.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/RevisionEntry.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/URLLister.java create mode 100644 src/java/fr/jayasoft/ivy/resolver/URLResolver.java create mode 100644 src/java/fr/jayasoft/ivy/typedef.properties create mode 100644 src/java/fr/jayasoft/ivy/url/ApacheURLLister.java create mode 100644 src/java/fr/jayasoft/ivy/url/BasicURLHandler.java create mode 100644 src/java/fr/jayasoft/ivy/url/HttpClientHandler.java create mode 100644 src/java/fr/jayasoft/ivy/url/URLHandler.java create mode 100644 src/java/fr/jayasoft/ivy/url/URLHandlerDispatcher.java create mode 100644 src/java/fr/jayasoft/ivy/url/URLHandlerRegistry.java create mode 100644 src/java/fr/jayasoft/ivy/util/Configurator.java create mode 100644 src/java/fr/jayasoft/ivy/util/CopyProgressEvent.java create mode 100644 src/java/fr/jayasoft/ivy/util/CopyProgressListener.java create mode 100644 src/java/fr/jayasoft/ivy/util/DefaultMessageImpl.java create mode 100644 src/java/fr/jayasoft/ivy/util/FileUtil.java create mode 100644 src/java/fr/jayasoft/ivy/util/IvyPattern.java create mode 100644 src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java create mode 100644 src/java/fr/jayasoft/ivy/util/Message.java create mode 100644 src/java/fr/jayasoft/ivy/util/MessageImpl.java create mode 100644 src/java/fr/jayasoft/ivy/util/StringUtils.java create mode 100644 src/java/fr/jayasoft/ivy/util/XMLHelper.java create mode 100644 src/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParser.java create mode 100644 src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParser.java create mode 100644 src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorUpdater.java create mode 100644 src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorWriter.java create mode 100644 src/java/fr/jayasoft/ivy/xml/XmlReportParser.java create mode 100644 src/java/fr/jayasoft/ivy/xml/ivy.xsd create mode 100644 test/java/fr/jayasoft/ivy/ResolveTest.java create mode 100644 test/java/fr/jayasoft/ivy/RetrieveTest.java create mode 100644 test/java/fr/jayasoft/ivy/SortTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyArtifactPropertyTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyCachePathTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyConfigureTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyPublishTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyResolveTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyRetrieveTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/IvyVarTest.java create mode 100644 test/java/fr/jayasoft/ivy/ant/ivy-failure.xml create mode 100644 test/java/fr/jayasoft/ivy/ant/ivy-simple.xml create mode 100644 test/java/fr/jayasoft/ivy/ant/ivyconf-test.xml create mode 100644 test/java/fr/jayasoft/ivy/ant/vartest.properties create mode 100644 test/java/fr/jayasoft/ivy/dualchainresolverconf.xml create mode 100644 test/java/fr/jayasoft/ivy/ivy-148.xml create mode 100644 test/java/fr/jayasoft/ivy/ivy-148b.xml create mode 100644 test/java/fr/jayasoft/ivy/ivy-dualchainresolver.xml create mode 100644 test/java/fr/jayasoft/ivy/latest/LatestRevisionStrategyTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/ChainResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/DualResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/IBiblioHelper.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/IBiblioResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/IvyRepResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/MockResolver.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/ResolverTestHelper.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/URLResolverTest.java create mode 100644 test/java/fr/jayasoft/ivy/resolver/chainresolverconf.xml create mode 100644 test/java/fr/jayasoft/ivy/resolver/dualresolverconf-bad.xml create mode 100644 test/java/fr/jayasoft/ivy/resolver/dualresolverconf.xml create mode 100644 test/java/fr/jayasoft/ivy/resolver/ibiblioresolverconf.xml create mode 100644 test/java/fr/jayasoft/ivy/url/ApacheURLListerTest.java create mode 100644 test/java/fr/jayasoft/ivy/url/BasicURLHandlerTest.java create mode 100644 test/java/fr/jayasoft/ivy/util/ConfiguratorTest.java create mode 100644 test/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParserTest.java create mode 100644 test/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParserTest.java create mode 100644 test/java/fr/jayasoft/ivy/xml/XmlModuleUpdaterTest.java create mode 100644 test/java/fr/jayasoft/ivy/xml/ivyconf-test.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/ivyconf-typedef.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/ivyconf.properties create mode 100644 test/java/fr/jayasoft/ivy/xml/test-bad-version.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-bad.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-bug60.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-defaultconf.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-noartifact.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-nopublication.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-novalidate.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test-simple.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/test.xml create mode 100644 test/java/fr/jayasoft/ivy/xml/updated.xml create mode 100644 test/repositories/1/org1/mod1.1/ivys/ivy-1.0.1.xml create mode 100644 test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml create mode 100644 test/repositories/1/org1/mod1.1/ivys/ivy-1.1.xml create mode 100644 test/repositories/1/org1/mod1.1/ivys/ivy-2.0.xml create mode 100644 test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar create mode 100644 test/repositories/1/org1/mod1.1/jars/mod1.1-1.1.jar create mode 100644 test/repositories/1/org1/mod1.1/jars/mod1.1-2.0.jar create mode 100644 test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar create mode 100644 test/repositories/1/org1/mod1.2/jars/mod1.2-2.1.jar create mode 100644 test/repositories/1/org1/mod1.2/jars/mod1.2-2.2.jar create mode 100644 test/repositories/1/org1/mod1.3/jars/mod1.3-A-3.0.jar create mode 100644 test/repositories/1/org1/mod1.3/jars/mod1.3-B-3.0.jar create mode 100644 test/repositories/1/org1/mod1.4/ivys/ivy-1.0.1.xml create mode 100644 test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml create mode 100644 test/repositories/1/org2/mod2.1/ivys/ivy-0.4.xml create mode 100644 test/repositories/1/org2/mod2.1/jars/art21A-0.3.jar create mode 100644 test/repositories/1/org2/mod2.1/jars/art21A-0.4.jar create mode 100644 test/repositories/1/org2/mod2.1/jars/art21B-0.3.jar create mode 100644 test/repositories/1/org2/mod2.1/jars/art21B-0.4.jar create mode 100644 test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml create mode 100644 test/repositories/1/org2/mod2.2/jars/mod2.2-0.5.jar create mode 100644 test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml create mode 100644 test/repositories/1/org2/mod2.3/ivys/ivy-0.5.xml create mode 100644 test/repositories/1/org2/mod2.3/ivys/ivy-0.6.xml create mode 100644 test/repositories/1/org2/mod2.3/jars/mod2.3-0.4.jar create mode 100644 test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml create mode 100644 test/repositories/2/mod3.1/ivy-1.0.xml create mode 100644 test/repositories/2/mod3.1/ivy-1.1.xml create mode 100644 test/repositories/2/mod3.1/mod3.1-1.0.jar create mode 100644 test/repositories/2/mod3.1/mod3.1-1.1.jar create mode 100644 test/repositories/2/mod4.1/ivy-4.0.xml create mode 100644 test/repositories/2/mod4.1/ivy-4.1.xml create mode 100644 test/repositories/2/mod4.1/ivy-4.2.xml create mode 100644 test/repositories/2/mod4.1/mod4.1-4.0.jar create mode 100644 test/repositories/2/mod4.1/mod4.1-4.1.jar create mode 100644 test/repositories/2/mod5.1/art51A-4.0.jar create mode 100644 test/repositories/2/mod5.1/art51A-4.1.jar create mode 100644 test/repositories/2/mod5.1/art51A-4.2.jar create mode 100644 test/repositories/2/mod5.1/art51B-4.0.jar create mode 100644 test/repositories/2/mod5.1/art51B-4.1.jar create mode 100644 test/repositories/2/mod5.1/art51B-4.2.jar create mode 100644 test/repositories/2/mod5.1/ivy-4.0.xml create mode 100644 test/repositories/2/mod5.1/ivy-4.1.xml create mode 100644 test/repositories/2/mod5.1/ivy-4.2.xml create mode 100644 test/repositories/2/mod5.2/ivy-1.0.xml create mode 100644 test/repositories/2/mod5.2/ivy-2.0.xml create mode 100644 test/repositories/2/mod5.2/mod5.2-1.0.jar create mode 100644 test/repositories/2/mod5.2/mod5.2-2.0.jar create mode 100644 test/repositories/2/mod6.1/ivy-1.0.xml create mode 100644 test/repositories/2/mod6.1/ivy-1.1.xml create mode 100644 test/repositories/2/mod6.1/ivy-1.2.xml create mode 100644 test/repositories/2/mod6.1/ivy-1.3.xml create mode 100644 test/repositories/2/mod6.2/ivy-1.0.xml create mode 100644 test/repositories/2/mod6.3/ivy-1.0.xml create mode 100644 test/repositories/bug148/3rd/idautomation/barcode/LinearBarCode-4.10.jar create mode 100644 test/repositories/bug148/3rd/idautomation/barcode/idapdf417-4.10.jar create mode 100644 test/repositories/bug148/3rd/idautomation/barcode/ivy-barcode-4.10.xml create mode 100644 test/repositories/bug148/ivyconf.properties create mode 100644 test/repositories/bug148/ivyconf.xml create mode 100644 test/repositories/bug148/jtv/jtv-foo/bar/bar-1.1.0.0.jar create mode 100644 test/repositories/bug148/jtv/jtv-foo/bar/bar-src-1.1.0.0.jar create mode 100644 test/repositories/bug148/jtv/jtv-foo/bar/ivy-bar-1.1.0.0.xml create mode 100644 test/repositories/checkmodified/ivy-1.0-after.xml create mode 100644 test/repositories/checkmodified/ivy-1.0-before.xml create mode 100644 test/repositories/checkmodified/ivy-1.0.xml create mode 100644 test/repositories/dual-local/xerces/xerces/ivy-2.6.2.xml create mode 100644 test/repositories/dual-remote/xerces/xercesImpl-2.6.2.jar create mode 100644 test/repositories/dual-remote/xerces/xmlParserAPIs-2.6.2.jar create mode 100644 test/repositories/ivyconf.properties create mode 100644 test/repositories/ivyconf.xml create mode 100644 test/xsl/test.xml diff --git a/.classpath b/.classpath new file mode 100644 index 00000000..fc4d9324 --- /dev/null +++ b/.classpath @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 00000000..e4f4f022 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + ivy + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 00000000..326a5fca --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,170 @@ + version 1.1 - 2005-06-13 +=============================== +- remote configuration (if available) of ivyrep and ibiblio patterns and roots +- new detailed messages when ivy fails to reach an url (thanks to Nicolas) +- new artifactproperty task, which enables to set a property for each dependency artifacts + resolved by ivy +- new defaultconf attribute in ivy file dependencies, to change the default conf to use in the file + when no conf is specified for a dependency +- add the ability to change the xsl file and report name pattern used by report task +- http listing now compatible with tomcat listing (tested with 5.0.28) +- pub revision in deliver task now defaults to timestamp if not provided by any other way +- debug messages improvements, with configuration dump among others +- new var task, enables to set ivy variables from ant +- now defaults for ivyrep and ibiblio resolver are configurable by variables +- refactoring: introduce the notion of BasicResolver, Repository, Resource, RepositoryResolver, + making much easier the task of writing basic resolvers +- added checkmodified attribute on all basic resolvers, which defaults to ${ivy.resolver.default.check.modified} + This makes ivy check last modified date of ivy files to see it its cache is up to date +- artifacts download are now first made to a temp file, which is renamed + only at the end of the download. This prevent interrupted downloads to be + considered as finished +- FIX: handle proxy configuration with http-client (thanks to Nicolas) +- FIX: remove dependency on ant outside of ant integration classes +- FIX: resolve problem when conflicts on latest revisions +- FIX: allow use of any kind of URL in IvyRepResolver (both ivyroot and artroot) and IBibiblioResolver +- FIX: chain resolver can now be used for artifacts part of dual resolver +- FIX: now detects and warn about circular dependencies +- FIX: cachepath task now takes pathid as parameter instead of id, to prevent + special handling from ant +- FIX: ivy.xsd: set artifact minOccurs to 0 in publications + +Thanks to John Shields from Robert Half International, Inc.: +- FIX: no more infinite loop when a conflict occurs between a latest subversion and a fully resolved revision +- FIX: BasicURLHandler now closes its connections +- FIX: ApacheURLLister now works with capital letter in revisions and truncated names +- now use of ivy variables is allowed in ivy files +- added a null check in pattern helper substitute + + version 1.0 - 2005-04-26 +=============================== +1.0-rc3 has been promoted to 1.0 on 2005-04-26 + +Known bugs and limitations: +- cyclic dependencies result in StackOverflowError +- infinite loop in rare cases when a conflict occur between a latest subversion and a fully resolved revision +- url connections not closed properly when not using commons-httpclient +- latest does not work with http urls in some cases, when the name of the link is truncated in the web page + + version 1.0-rc3 - 2005-04-21 +=============================== +- IMPROVE: added debug messages on variables setting +- FIX: ivyconf now able to load a properties file given as url +- FIX: deliver pub date now actually defaults to 'now' +- FIX: all tasks attributes now substitute ivy variables + + version 1.0-rc2 - 2005-04-18 +=============================== +- IMPROVE: improved messages: more debug, more verbose, and more details on failures +- FIX: bug with '\' in path patterns +- FIX: bug with relative paths patterns +- FIX: configure task tries ivy.conf.file as relative to base dir and to current dir +- FIX: file system resolver publishes ivy files with ivy pattern +- FIX: 0 content length considered as non existing (behaviour of jre 5.0 on linux) + => empty ressources are now considered as non existing + + version 1.0-rc1 - 2005-04-12 +=============================== +- add report task, which enables to generates reports of dependencies, including a graph + ready to be layed out by yEd +- add exclude feature in dependency +- include exclude feature now handles regexps +- new latest strategy: latest revision now uses a "php version_compare" like algorithm, whereas + lexicographic comparison is now available in latest lexicographic +- enhance xml resolve report details +- FIX: better separation between root configurations +- FIX: XmlModuleDescriptorUpdater now preserves xml header +- FIX: modules number in report (displayed at the end of resolve) + + version 0.9 - 2005-04-06 +=========================== +- clearly differenciate pattern tokens from variables, by using brackets as delimiter in pattern tokens + => WARNING: this introduce changes in all patterns syntax, and thus does not provide compatibility + with previous versions +- ChainResolver are now able to publish (delegating the call to the first resolver in the chain) +- DualResolver sub resolvers are now registered in Ivy +- more precise message on eviction +- add validate attribute on most resolvers +- ivy files validation handling review +- use ivy variables in ant tasks to get default values for attributes +- documentation update for configuring ivy +- FIX: dependencies order not taken into account during resolve +- FIX: evicting modules also evict confs +- FIX: NPE during resolve when a dependency ivy file has no publication date +- FIX: check nullity of artifact download reports + + version 0.8 - 2005-03-30 +=========================== +- added validate attribute on resolve, retrieve and publish, which allows to disable ivy file validation + against ivy.xsd (useful to parse future compatible ivy files) +- ant properties are now available in ivyconf file +- unified default properties in ivyconf, with better independance from url or file +- added ext on artifacts: this enable to distinguish artifact extension from artifact + type, util in cases where it differs (example: 'src' type with 'zip' extension, 'ivy' type with 'xml' extension, ...) +- added publish artifacts feature, which enable to publish declared artifacts of a module to a repository + described by a dependency resolver. It currently works only with filesystem resolver. +- url resolver now handles latest with file urls and http ones (tested only with apache server) +- added latest strategy concept: the way to determine which artifact is the latest + is now configurable on resolvers handling latest. +- added parameter on chain resolver to say if it should return first found or + try to find the latest among all if asked +- a module can now publish no artifact, useful for virtual modules consisting only + of integration of other modules +- added conflict management at resolve time: during resolve, modules in conflict can be evicted + and thus not downloaded +- added ivyrep resolver, using ivyrep to find ivy files, and ibiblio for artifacts +- use ivyrep instead of ibiblio as default resolver +- added more info in ivy files (description, homepage, ivy authors, license, public repository, ...) +- now cache layout is configurable, using cacheIvyPattern and cacheArtifactPattern + attributes on conf element in ivyconf.xml +- changed default cache layout: artifacts are separated by type +- added cachepath task, which enables to build an ant path of artifacts in cache required for a conf + + version 0.7 - 2005-03-11 +=========================== +- added latest sub revision feature: you can now select the latest sub revision of a module + using a +. For instance, "1.0+" selects the latest revision starting with 1.0. (thanks to jonas for the idea) +- haltonfailure now defaults to true (as suggested by Jeroen) +- shorter info lines to better view important info (as suggested by Jeroen) +- retrieve now checks if files are up to date before copying them from cache. This feature + can be disabled using the checkUpToDate attribute in ivy configuration file. +- do not download dependencies when not necessary during publication (as suggested by Daniele) +- bug fix: better handling of publish without recursive delivery + + version 0.6.1 - 2005-02-11 +============================= +- bug fix: conf extends problem with publications +- bug fix: typedef badly handled in ivyconf.xml +- bug fix: default properties loading in ivy configure loaded using task classloader + + version 0.6 - 2005-02-03 +=========================== ++ functional +- added haltonfailure attribute on resolve and retrieve task, so that build can be halt when + resolve or retrieve fails +- added dependency artifacts filtering feature, enabling to work better with ibiblio +- ibiblio resolver can now be configured to use any maven like repository, with root and pattern attributes +- added download progression info on resolve +- default cache is now in user home (.ivy-cache in user home), so that cache is shared + by default for all projects of the same user +- added public access to method getDependencies(...) in Ivy, which resolve dependencies without + downloading artifacts +- added DualResolver, which allows to have ivy files in one place and artifacts in another one + ++ non functional +- added some unit tests +- deep review of ivy file reference documentation + ++ bugs and refactoring +- bug fix: SimpleURLResolver not handling the case when there is no ivy file +- refactoring: URLResolver renamed to AbstractURLResolver +- refactoring: SimpleURLResolver renamed to URLResolver + + version 0.5.1 - 2005-01-16 +============================= +- Bug Fix: NPE in publish task when no delivery.list.file is provided +- documentation update + + version 0.5 - 2005-01-12 +=========================== +initial public version \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..3e623397 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,26 @@ +BSD License for Ivy +Copyright (c) 2005, JAYASOFT +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * 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. + * Neither the name of JAYASOFT nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/build.properties b/build.properties new file mode 100644 index 00000000..3f9154b4 --- /dev/null +++ b/build.properties @@ -0,0 +1,9 @@ +lib.dir=lib +src.dir=src/java +test.dir=test/java +build.dir=build +classes.build.dir=build/classes +test.build.dir=build/test +artifacts.build.dir=build/artifact +test.report.dir=build/report + diff --git a/build.xml b/build.xml new file mode 100644 index 00000000..6391c794 --- /dev/null +++ b/build.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/announce/announce-0.5.txt b/doc/announce/announce-0.5.txt new file mode 100644 index 00000000..942fdf0b --- /dev/null +++ b/doc/announce/announce-0.5.txt @@ -0,0 +1,35 @@ +################################ French ######################################## +La société Jayasoft (http://www.jayasoft.org) a le plaisir d'annoncer la version 0.5, première version publique, de son outil de résolution de dépendances nommé Ivy. +Ivy est un outil, écrit en Java, qui peut etre utilisé avec ant ou bien seul. + +Les principaux atouts d'Ivy sont : +- la simplicité, +- la flexibilité, +- l'extensibilité, +- l'intégration avec ant, +- le support de dépendance de dépendance, +- la comptatibilité avec le repository maven sur ibiblio, +- facilite l'intégration continue, +- la gratuité, en licence BSD. + +Plus d'informations et téléchargement sur le site : http://ivy.jayasoft.org + + +################################ English ######################################## +Jayasoft (http://www.jayasoft.org) is pleased to announce the availabilty of the first public beta of Ivy, version 0.5. +Ivy is a java based simple but powerful dependency manager. + +Key features are : + * simple to use + * extremely flexible + * easily extensible + * xml based + * integrated with ant + * ready to use with maven ibiblio repository + * dependencies of dependencies + * eases continuous integration + * make your software component a lot simpler to use + * free (BSD license) ! + +Download and information on : http://ivy.jayasoft.org + diff --git a/doc/announce/announce-0.6.txt b/doc/announce/announce-0.6.txt new file mode 100644 index 00000000..2b29bcfd --- /dev/null +++ b/doc/announce/announce-0.6.txt @@ -0,0 +1,16 @@ +Jayasoft (http://www.jayasoft.org) is pleased +to announce the availability of Ivy version 0.6, a free java based simple but powerful +dependency manager, featuring transitive dependencies, ant integration, +maven repository compatibility and many more. + +Main changes in this version are : +- dependency artifacts filtering feature, enabling to work better with ibiblio +- ibiblio resolver can now be configured to use any maven like repository +- a new dependency resolver which allows to have ivy files in one place + and artifacts in another one (named dual resolver) +- a new logo, many thanks to ultroniks (at) hotmail.com + +And more... + +Download and information on : http://ivy.jayasoft.org + diff --git a/doc/announce/announce-0.7.txt b/doc/announce/announce-0.7.txt new file mode 100644 index 00000000..cd83d0b1 --- /dev/null +++ b/doc/announce/announce-0.7.txt @@ -0,0 +1,16 @@ +Jayasoft (http://www.jayasoft.org) is pleased +to announce the availability of Ivy version 0.7, a free java based simple but powerful +dependency manager, featuring transitive dependencies, ant integration, +maven repository compatibility, continuous integration features and many more. + +Main changes in this version are : +- added latest sub revision feature: you can now select the latest sub revision of a module + using a +. For instance, "1.0+" selects the latest revision starting with 1.0. +- retrieve now checks if files are up to date before copying them from cache. This feature + can be disabled using the checkUpToDate attribute in ivy configuration file. +- do not download dependencies when not necessary during publication + +And more... + +Download and information on : http://ivy.jayasoft.org + diff --git a/doc/announce/announce-0.8.txt b/doc/announce/announce-0.8.txt new file mode 100644 index 00000000..67f8758a --- /dev/null +++ b/doc/announce/announce-0.8.txt @@ -0,0 +1,12 @@ +Jayasoft (http://www.jayasoft.org) is pleased to announce the availability of Ivy version 0.8, a free java based simple but powerful dependency manager, featuring transitive dependencies, ant integration, maven repository compatibility, continuous integration features and many more. + +Main changes in this version are : +- a brand new public repository of ivy files, ivyrep, which helps leverage the transitive dependencies feature +- url resolver now handles latest with file urls and http ones: you can now use continuous integration feature with ibiblio ! +- publish artifacts feature, which enable to easily publish declared artifacts of a module to a repository +- conflict management at resolve time, which gives great control over conflicts management and evict modules before downloading them + +And many more... + +Download and information on : http://ivy.jayasoft.org + diff --git a/doc/announce/announce-1.0-rc1.txt b/doc/announce/announce-1.0-rc1.txt new file mode 100644 index 00000000..aaa53b69 --- /dev/null +++ b/doc/announce/announce-1.0-rc1.txt @@ -0,0 +1,13 @@ +After several months of development and testing, Jayasoft is pleased to announce the availability of Ivy version 1.0-rc1. + +Ivy is a free java based dependency manager, with powerful features such as transitive dependencies, ant integration, maven repository compatibility, continuous integration and many more. + +Main changes in this version are : +- new report, which indicates all the dependencies resolved, direct and transitives, with the status and place in the dependency graph for each +- new graph report, showing all dependencies as a graph +- better include/exclude feature, helping to get only what you need from a dependency you do not control + +And many more... + +Download and information on : http://ivy.jayasoft.org + diff --git a/doc/announce/announce-1.0.txt b/doc/announce/announce-1.0.txt new file mode 100644 index 00000000..d48eb5fa --- /dev/null +++ b/doc/announce/announce-1.0.txt @@ -0,0 +1,40 @@ +English: +-------- + +After several months of development and testing, Jayasoft is pleased to announce the availability of Ivy version 1.0. + +Ivy is a free java based dependency manager, with powerful features such as transitive dependencies, ant integration, maven repository compatibility, continuous integration, html reports and many more. + +Apart its strong dependency management engine, Ivy also benefits from a growing user community, a public repository of common ivy files, and professional quality services from the source. + +And leverage the power of Ivy with an evolving set of tools and plugins: +Ivy CruiseControl Plugin lets you integrate ivy in the famous continuous integration tool from thoughtworks: cruisecontrol. +Ivy Eclipse UI strongly helps eclipse users to write their ivy files, with structural and data completion. + +Coming soon: +Subversion Dependency Resolver, lets you use subversion to store your libraries +Ivy Eclipse Classpath, lets you use ivy files as a library container + +Finally, many thanks to the users feedbacks and contributions who made this possible. + +Download and information on : http://ivy.jayasoft.org + +French : +-------- +Après plusieurs mois de développement et de tests, Jayasoft a le plaisir d'annoncer la version 1.0 de Ivy. + +Ivy est un outil de gestion de dépendances écrit en java, doté de fonctionalités avancées telles que la gestion de dépendances transitives, l'intégration dans ant, la compatibilité avec les repository maven, l'intégration continue, des fonctions de rapport avancées et bien d'autres encore. + +En plus de son puissant moteur de gestion de dépendances, Ivy bénéficie également d'une communauté utilisateurs grandissante, d'un repository public de fichiers ivy communs et de services professionnels directement par ses auteurs. + +Et profitez de toute la puissance d'une ensemble d'outils en pleine évolution : +Ivy CruiseControl Plugin vous permet d'intégrer ivy dans l'outil d'intégration continue de thoughtworks: cruisecontrol. +Ivy Eclipse UI permet aux utilisateurs d'eclipse d'écrire leurs fichiers de dépendances encore plus rapidement, grâce à de la completion de structure et de données ! + +Et bientôt : +Subversion Dependency Resolver vous permettra d'utiliser subversion comme repository +Ivy Eclipse Classpath vous permettra d'utiliser les dépendances Ivy directement comme library container eclipse + +Finalement, un grand merci aux utilisateurs, dont les retours et les contributions ont permis de faire de Ivy ce qu'il est aujourd'hui. + +Plus d'informations et téléchargement sur le site : http://ivy.jayasoft.org diff --git a/doc/announce/announce-1.1.txt b/doc/announce/announce-1.1.txt new file mode 100644 index 00000000..1615a86e --- /dev/null +++ b/doc/announce/announce-1.1.txt @@ -0,0 +1,14 @@ +English: +-------- + +Jayasoft is pleased to announce the availability of Ivy version 1.1. + +Ivy is a free java based dependency manager, with powerful features such as transitive dependencies, ant integration, maven repository compatibility, continuous integration, html reports and many more. + +Apart its strong dependency management engine, Ivy also benefits from a growing user community, a public repository of common ivy files, and professional quality services from the source. + +This release includes many bug fixes, better download management, better information and debug messages, improved documentation and a brand new web site ! + +Finally, many thanks to the users feedbacks and contributions who made this possible. + +Download and information at : http://ivy.jayasoft.org diff --git a/doc/conflict-solving-algo.html b/doc/conflict-solving-algo.html new file mode 100644 index 00000000..4a3a1ef1 --- /dev/null +++ b/doc/conflict-solving-algo.html @@ -0,0 +1,97 @@ + +Here are some explanations about the conflict management algorithm in Ivy.

+ +First, one should have a good understanding on how Ivy resolves dependencies, and especially +transitive dependencies.

+ +During the resolve process, ivy visits each module of the dependency graph.
+Let's call each module a node, including the module we are trying to resolve dependencies for.

+ +Each node should be able to give a conflict manager for a particular ModuleId.
+Let's name it node.cm(mid).

+ +Each node should be able to matain a map from ModuleId to a resolved Collection of nodes.
+This resolved collection will never contain any evicted node FOR the concerned node as far +as ivy knows, dependening on where it is in graph visit.
+Let's call this map resolved, and the corresponding resolved collection node.resolved(mid).

+ +During the visit, ivy should always know from which node it came to visit another node. Let's call +the first node from which ivy came node.parent. Note that this concept is slightly different from +node parent, since a node can have several parents in the graph, but there is also one node.parent +during the visit.

+ +Let's say that a conflict manager is able to filter a collection of nodes to return only those +that are not evicted. Let's call that cm.resolveConflicts(collection).

+ +Let's call node.dependencies the collection of direct dependencies of a node.

+ +Let's call node.revision the module revision id of a node.

+ +And now for the algo. This algo attempts to evict nodes on the fly, i.e. during the ivy visit, +to minimize the number of resolved modules, and thus the number of ivy files to download.

+ +It is presented in a very simplified description language, far away from the whole real complexity, +but giving a good understanding of how it works. In particular, it completely hides some complexity due +to configurations management.

+ +
+resolve(node) {
+	node.resolved(node.mid) = collection(node);
+	resolveConflict(node, node.parent, empty);
+	if (!node.evicted && !node.alreadyResolved) {
+		node.loadData();
+		resolveConflict(node, node.parent, empty);
+		if (!node.evicted) {
+			// actually do resolve
+			foreach (dep in node.dependencies) {
+				resolve(dep);
+			}
+		}
+	}
+}
+
+resolveConflict(node, parent, toevict) {
+	if (node.revision.exact && parent.resolved(node.mid).revision.contains(node.revision)) { 
+		// exact revision already in resolved
+		// => job already done
+		return;
+	}
+	if (parent.resolved(node.mid).containsAny(toevict)) {
+		// parent.resolved(node.mid) is not up to date:
+		// recompute resolved from all sub nodes
+		resolved = parent.cm(node.mid).resolveConflicts(
+		                                 parent.dependencies.resolved(node.mid));
+	} else {
+		resolved = parent.cm(node.mid).resolveConflicts(collection(node, parent.resolved(node.mid)));
+	}
+	if (resolved.contains(node)) {
+		// node has been selected for the current parent
+		// we update its eviction... but it can still be evicted by parent !
+		node.evicted = false;
+		
+		// handle previously selected nodes that are now evicted by this new node
+		toevict = parent.resolved(node.mid) - resolved;
+		foreach (te in toevict) {
+			te.evicted = true;
+		}
+		
+		// it's very important to update resolved BEFORE recompute parent call
+		// to allow it to recompute its resolved collection with correct data
+		// if necessary
+		parent.resolved(node.mid) = resolved; 
+		if (parent.parent != null) {
+			resolveConflict(node, parent.parent, toevict);
+		}
+	} else {
+		// node has been evicted for the current parent
+		
+		// it's time to update parent resolved with found resolved...
+		// if they have not been recomputed, it does not change anything
+		parent.resolved(node.mid) = resolved; 
+		
+		node.evicted = true;
+	}
+}
+
+
+ \ No newline at end of file diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 00000000..f8c46cd4 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,13 @@ + + + + +Ivy Documentation Index + + +

Welcome to Ivy documentation index !

+ Here is what you can find in this documentation:
+ - Main documentation
+ - Javadoc
+ - JUnit tests report
+ \ No newline at end of file diff --git a/ivy.xml b/ivy.xml new file mode 100644 index 00000000..bf83fb2a --- /dev/null +++ b/ivy.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/example/chained-resolvers/build.xml b/src/example/chained-resolvers/build.xml new file mode 100644 index 00000000..7b966005 --- /dev/null +++ b/src/example/chained-resolvers/build.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/example/chained-resolvers/chainedresolvers-project/build.xml b/src/example/chained-resolvers/chainedresolvers-project/build.xml new file mode 100644 index 00000000..09c50989 --- /dev/null +++ b/src/example/chained-resolvers/chainedresolvers-project/build.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/example/chained-resolvers/chainedresolvers-project/ivy.xml b/src/example/chained-resolvers/chainedresolvers-project/ivy.xml new file mode 100644 index 00000000..749df755 --- /dev/null +++ b/src/example/chained-resolvers/chainedresolvers-project/ivy.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/example/chained-resolvers/chainedresolvers-project/src/example/Hello.java b/src/example/chained-resolvers/chainedresolvers-project/src/example/Hello.java new file mode 100644 index 00000000..b4fa90aa --- /dev/null +++ b/src/example/chained-resolvers/chainedresolvers-project/src/example/Hello.java @@ -0,0 +1,20 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package example; + +import org.apache.commons.lang.WordUtils; + +/** + * Simple example world to show how easy it is to retreive libs with ivy !!! + */ +public class Hello { + public static void main(String[] args) { + String message = "example world !"; + System.out.println("standard message :" + message); + System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); + System.out.println("upperCased by " + test.StringUtils.class.getName() + " : " + test.StringUtils.upperCase(message)); + } +} diff --git a/src/example/chained-resolvers/config/ivyconf.xml b/src/example/chained-resolvers/config/ivyconf.xml new file mode 100644 index 00000000..c8449e51 --- /dev/null +++ b/src/example/chained-resolvers/config/ivyconf.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/example/chained-resolvers/config/repository/test-1.0.jar b/src/example/chained-resolvers/config/repository/test-1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..68524338d8ea960c47b18425c907ac1c85d1264e GIT binary patch literal 1131 zcmWIWW@h1H00FnzYDQoNl;8x?zOEsTx}JV+`T~t1dKY=Ub+yi&Ilno`;EM5sr$uL+g$i{%e9n1-2+X;9CP=$?LGkne{;v$K;_DsTH|(C;A*l81YVpmb3!JYnXz$u*GGRsQ-`O)$ zZyf(z#cbdd?#SE4Bs!~ST94U6JKn_;&T=fuT+3mqe(zVyGeyroS3Vlq@t^&9&bsRH zUUAmPs@{h+W<>0tz{XiBDa&ic({%1nPp!rD*55tOSI;Kx{cQe*TWcxH)T4Q+_l*BX zBr;62|HQ}m<=fNHXR{Alf7H7veqp76$;Ahem;Umvy;bfp<#swprQ#uOSg3F?e3_+Y z6uLQv5#(KcCI$vkY+lYvEK3aakM%xcAW)DY){X zRz=l`@9j17r{yoLw(7e$Yr!-&?Mu(tOCDdm_k!Oo=>5a(p@loDHQ&uYJ+(Tm@Jjcq z;4K_2)3z0gxJL>p+44wR387J46zO5&X54uM7_vYh!0^@)L?h)Gm^SQr2Ba7SmNcpZNw_wo9E8te zP%4K2kj2}9OlX=%Sc)yx!!#{vyam&Okp~dgVoyd0GtL4N7uZ^4GeC(dz?+o~q>L2^ Lje&}km_a-MR6cZ( literal 0 HcmV?d00001 diff --git a/src/example/dependence/build.xml b/src/example/dependence/build.xml new file mode 100644 index 00000000..bb2e48b1 --- /dev/null +++ b/src/example/dependence/build.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/example/dependence/config/ivyconf.properties b/src/example/dependence/config/ivyconf.properties new file mode 100644 index 00000000..b5087d0f --- /dev/null +++ b/src/example/dependence/config/ivyconf.properties @@ -0,0 +1 @@ +repository.dir=${ivy.conf.dir}/repository diff --git a/src/example/dependence/config/ivyconf.xml b/src/example/dependence/config/ivyconf.xml new file mode 100644 index 00000000..363dcbfd --- /dev/null +++ b/src/example/dependence/config/ivyconf.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/example/dependence/depending/build.xml b/src/example/dependence/depending/build.xml new file mode 100644 index 00000000..58e6e070 --- /dev/null +++ b/src/example/dependence/depending/build.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/example/dependence/depending/ivy.xml b/src/example/dependence/depending/ivy.xml new file mode 100644 index 00000000..a692059c --- /dev/null +++ b/src/example/dependence/depending/ivy.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/example/dependence/depending/src/depending/Main.java b/src/example/dependence/depending/src/depending/Main.java new file mode 100644 index 00000000..8e2773ad --- /dev/null +++ b/src/example/dependence/depending/src/depending/Main.java @@ -0,0 +1,23 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package depending; + +/** + * TODO write javadoc + */ +public class Main { + public static void main(String[] args) { + String standaloneVersion = standalone.Main.getVersion(); + if (standaloneVersion!=null) { + System.out.println("you are using version " + standaloneVersion + " of class " + standalone.Main.class.getName()); + } else { + System.err.println("failed to get version of " + standalone.Main.class.getName()); + } + String message = "i am " + Main.class.getName() + " and " + standalone.Main.class.getName() + " will do the job for me"; + System.out.println("standard message : " + message); + System.out.println("capitalized message : " + standalone.Main.capitalizeWords(message)); + } +} diff --git a/src/example/dependence/standalone/build.xml b/src/example/dependence/standalone/build.xml new file mode 100644 index 00000000..eea31376 --- /dev/null +++ b/src/example/dependence/standalone/build.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/example/dependence/standalone/ivy.xml b/src/example/dependence/standalone/ivy.xml new file mode 100644 index 00000000..a1c83886 --- /dev/null +++ b/src/example/dependence/standalone/ivy.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/example/dependence/standalone/src/standalone/Main.java b/src/example/dependence/standalone/src/standalone/Main.java new file mode 100644 index 00000000..187b737d --- /dev/null +++ b/src/example/dependence/standalone/src/standalone/Main.java @@ -0,0 +1,48 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package standalone; + +import java.util.Properties; + +import org.apache.commons.lang.WordUtils; + +/** + * TODO write javadoc + */ +public class Main { + /** + * Returns the version of the project + * @return a string representation of the version, null if the version could not be retreived + */ + public static String getVersion() { + Properties p = new Properties(); + try { + p.load(Main.class.getResourceAsStream("/version.properties")); + String version = p.getProperty("version"); + if (version != null) { + return String.valueOf(Integer.parseInt(version)); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * Return the same string with all words capitalized. + * @param str the string conatining the words to capitalize + * @return null if the string was null, the string with all words capitalized otherwise + */ + public static String capitalizeWords(String str) { + System.out.println(" [" + Main.class.getName() + "] capitalizing string \"" + str + "\" using " + WordUtils.class.getName()); + return WordUtils.capitalizeFully(str); + } + public static void main(String[] args) { + String message="sentence to capitalize"; + System.out.println("standard message : " + message); + System.out.println("capitalized message : " + capitalizeWords(message)); + } +} diff --git a/src/example/dual/build.xml b/src/example/dual/build.xml new file mode 100644 index 00000000..27df8cf5 --- /dev/null +++ b/src/example/dual/build.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/example/dual/config/ivyconf.xml b/src/example/dual/config/ivyconf.xml new file mode 100644 index 00000000..340f7f3c --- /dev/null +++ b/src/example/dual/config/ivyconf.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/example/dual/project/build.xml b/src/example/dual/project/build.xml new file mode 100644 index 00000000..0859eaef --- /dev/null +++ b/src/example/dual/project/build.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/example/dual/project/ivy.xml b/src/example/dual/project/ivy.xml new file mode 100644 index 00000000..ded7017b --- /dev/null +++ b/src/example/dual/project/ivy.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/example/dual/project/src/example/Hello.java b/src/example/dual/project/src/example/Hello.java new file mode 100644 index 00000000..7378789e --- /dev/null +++ b/src/example/dual/project/src/example/Hello.java @@ -0,0 +1,37 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package example; + +import java.io.IOException; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.methods.HeadMethod; +import org.apache.commons.lang.WordUtils; + +/** + * Simple hello world example to show how easy it is to retrieve libs with ivy, + * including transitive dependencies + */ +public class Hello { + public static void main(String[] args) throws Exception { + String message = "hello ivy !"; + System.out.println("standard message : " + message); + System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); + + HttpClient client = new HttpClient(); + HeadMethod head = new HeadMethod("http://www.ibiblio.org/"); + client.executeMethod(head); + + int status = head.getStatusCode(); + System.out.println("head status code with httpclient: "+status); + head.releaseConnection(); + + System.out.println("now check if httpclient dependency on commons-logging has been realized"); + Class clss = Class.forName("org.apache.commons.logging.Log"); + System.out.println("found logging class in classpath: "+clss); + } +} diff --git a/src/example/dual/repository/commons-httpclient-ivy-2.0.2.xml b/src/example/dual/repository/commons-httpclient-ivy-2.0.2.xml new file mode 100644 index 00000000..45209841 --- /dev/null +++ b/src/example/dual/repository/commons-httpclient-ivy-2.0.2.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/example/hello-ivy/build.xml b/src/example/hello-ivy/build.xml new file mode 100644 index 00000000..1f3451a5 --- /dev/null +++ b/src/example/hello-ivy/build.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/example/hello-ivy/ivy.xml b/src/example/hello-ivy/ivy.xml new file mode 100644 index 00000000..c029195e --- /dev/null +++ b/src/example/hello-ivy/ivy.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/example/hello-ivy/src/example/Hello.java b/src/example/hello-ivy/src/example/Hello.java new file mode 100644 index 00000000..676d130d --- /dev/null +++ b/src/example/hello-ivy/src/example/Hello.java @@ -0,0 +1,19 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package example; + +import org.apache.commons.lang.WordUtils; + +/** + * Simple example world to show how easy it is to retreive libs with ivy !!! + */ +public class Hello { + public static void main(String[] args) { + String message = "hello ivy !"; + System.out.println("standard message : " + message); + System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); + } +} diff --git a/src/example/ivyrep/build.xml b/src/example/ivyrep/build.xml new file mode 100644 index 00000000..5a73db4a --- /dev/null +++ b/src/example/ivyrep/build.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/example/ivyrep/ivy.xml b/src/example/ivyrep/ivy.xml new file mode 100644 index 00000000..c1d36759 --- /dev/null +++ b/src/example/ivyrep/ivy.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/example/ivyrep/src/example/Hello.java b/src/example/ivyrep/src/example/Hello.java new file mode 100644 index 00000000..e97c1505 --- /dev/null +++ b/src/example/ivyrep/src/example/Hello.java @@ -0,0 +1,35 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package example; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.lang.WordUtils; + +/** + * Simple example to show how easy it is to retrieve transitive libs with ivy !!! + */ +public class Hello { + public static void main(String[] args) throws Exception { + Option msg = OptionBuilder.withArgName( "msg" ) + .hasArg() + .withDescription( "the message to capitalize" ) + .create( "message" ); + Options options = new Options(); + options.addOption(msg); + + CommandLineParser parser = new GnuParser(); + CommandLine line = parser.parse( options, args ); + + String message = line.getOptionValue("message", "hello ivy !"); + System.out.println("standard message : " + message); + System.out.println("capitalized by " + WordUtils.class.getName() + " : " + WordUtils.capitalizeFully(message)); + } +} diff --git a/src/java/fr/jayasoft/ivy/AbstractArtifact.java b/src/java/fr/jayasoft/ivy/AbstractArtifact.java new file mode 100644 index 00000000..70350d83 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/AbstractArtifact.java @@ -0,0 +1,40 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +/** + * @author Hanin + * + */ +public abstract class AbstractArtifact implements Artifact { + public boolean equals(Object obj) { + if (!(obj instanceof Artifact)) { + return false; + } + Artifact art = (Artifact)obj; + return getModuleRevisionId().equals(art.getModuleRevisionId()) + && getPublicationDate()==null?true:getPublicationDate().equals(art.getPublicationDate()) + && getName().equals(art.getName()) + && getExt().equals(art.getExt()) + && getType().equals(art.getType()); + } + + public int hashCode() { + int hash = 33; + hash = hash * 17 + getModuleRevisionId().hashCode(); + if (getPublicationDate() != null) { + hash = hash * 17 + getPublicationDate().hashCode(); + } + hash = hash * 17 + getName().hashCode(); + hash = hash * 17 + getExt().hashCode(); + hash = hash * 17 + getType().hashCode(); + return hash; + } + + public String toString() { + return getModuleRevisionId()+"/"+getName()+"."+getExt()+"["+getType()+"]"; + } +} diff --git a/src/java/fr/jayasoft/ivy/Artifact.java b/src/java/fr/jayasoft/ivy/Artifact.java new file mode 100644 index 00000000..248312eb --- /dev/null +++ b/src/java/fr/jayasoft/ivy/Artifact.java @@ -0,0 +1,35 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + + +/** + * @author x.hanin + * + */ +public interface Artifact { + /** + * Returns the resolved module revision id for this artifact + * @return + */ + ModuleRevisionId getModuleRevisionId(); + /** + * Returns the resolved publication date for this artifact + * @return the resolved publication date + */ + Date getPublicationDate(); + String getName(); + String getType(); + String getExt(); + String[] getConfigurations(); + + /** + * @return the id of the artifact + */ + ArtifactRevisionId getId(); +} diff --git a/src/java/fr/jayasoft/ivy/ArtifactId.java b/src/java/fr/jayasoft/ivy/ArtifactId.java new file mode 100644 index 00000000..ccaf10c1 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ArtifactId.java @@ -0,0 +1,77 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +/** + * Identifies an artifact in a module, without revision information + */ +public class ArtifactId { + private ModuleId _mid; + private String _name; + private String _type; + private String _ext; + + + /** + * @param mid + * @param name + * @param type + */ + public ArtifactId(ModuleId mid, String name, String type, String ext) { + _mid = mid; + _name = name; + _type = type; + _ext = ext; + } + + public boolean equals(Object obj) { + if (! (obj instanceof ArtifactId)) { + return false; + } + ArtifactId aid = (ArtifactId)obj; + return getModuleId().equals(aid.getModuleId()) + && getName().equals(aid.getName()) + && getExt().equals(aid.getExt()) + && getType().equals(aid.getType()); + } + + public int hashCode() { + int hash = 17; + hash += getModuleId().hashCode() * 37; + hash += getName().hashCode() * 37; + hash += getType().hashCode() * 37; + return hash; + } + + public String toString() { + return getModuleId()+" "+getName()+"."+getType(); + } + + /** + * @return Returns the module id. + */ + public ModuleId getModuleId() { + return _mid; + } + /** + * @return Returns the name. + */ + public String getName() { + return _name; + } + /** + * @return Returns the type. + */ + public String getType() { + return _type; + } + /** + * @return Returns the ext. + */ + public String getExt() { + return _ext; + } +} diff --git a/src/java/fr/jayasoft/ivy/ArtifactInfo.java b/src/java/fr/jayasoft/ivy/ArtifactInfo.java new file mode 100644 index 00000000..80a07924 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ArtifactInfo.java @@ -0,0 +1,11 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +public interface ArtifactInfo { + String getRevision(); + long getLastModified(); +} diff --git a/src/java/fr/jayasoft/ivy/ArtifactRevisionId.java b/src/java/fr/jayasoft/ivy/ArtifactRevisionId.java new file mode 100644 index 00000000..f5489d8f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ArtifactRevisionId.java @@ -0,0 +1,79 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +/** + * identifies an artifact in a particular module revision + */ +public class ArtifactRevisionId { + public static ArtifactRevisionId newInstance(ModuleRevisionId mrid, String name, String type, String ext) { + return new ArtifactRevisionId(new ArtifactId(mrid.getModuleId(), name, type, ext), mrid); + } + + private ArtifactId _artifactId; + private ModuleRevisionId _mrid; + + + /** + * @param revision + * @param artifactId + */ + public ArtifactRevisionId(ArtifactId artifactId, ModuleRevisionId mrid) { + _artifactId = artifactId; + _mrid = mrid; + } + + public boolean equals(Object obj) { + if (! (obj instanceof ArtifactRevisionId)) { + return false; + } + ArtifactRevisionId arid = (ArtifactRevisionId)obj; + return getArtifactId().equals(arid.getArtifactId()) + && getModuleRevisionId().equals(arid.getModuleRevisionId()); + } + + public int hashCode() { + int hash = 17; + hash += getArtifactId().hashCode() * 37; + hash += getModuleRevisionId().hashCode() * 37; + return hash; + } + + public String toString() { + return getModuleRevisionId()+" "+getName()+"."+getType(); + } + + /** + * @return Returns the artifactId. + */ + public ArtifactId getArtifactId() { + return _artifactId; + } + + public ModuleRevisionId getModuleRevisionId() { + return _mrid; + } + + public String getName() { + return _artifactId.getName(); + } + + public String getType() { + return _artifactId.getType(); + } + + public String getExt() { + return _artifactId.getExt(); + } + + /** + * @return Returns the revision. + */ + public String getRevision() { + return _mrid.getRevision(); + } + +} diff --git a/src/java/fr/jayasoft/ivy/Configuration.java b/src/java/fr/jayasoft/ivy/Configuration.java new file mode 100644 index 00000000..df9e0ee9 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/Configuration.java @@ -0,0 +1,109 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + + +/** + * Represents a module configuration + */ +public class Configuration { + public static class Visibility { + public static Visibility PUBLIC = new Visibility("public"); + public static Visibility PRIVATE = new Visibility("private"); + public static Visibility getVisibility(String name) { + if ("private".equals(name)) { + return PRIVATE; + } else if ("public".equals(name)) { + return PUBLIC; + } else { + throw new IllegalArgumentException("unknwon visibility "+name); + } + } + private String _name; + private Visibility(String name) { + _name = name; + } + } + + private String _name; + private String _description; + private String[] _extends; + private Visibility _visibility; + + /** + * @param name + * @param visibility + * @param description + * @param ext + */ + public Configuration(String name, Visibility visibility, + String description, String[] ext) { + if (name == null) { + throw new NullPointerException("null configuration name not allowed"); + } + if (visibility == null) { + throw new NullPointerException("null visibility not allowed"); + } + _name = name; + _visibility = visibility; + _description = description; + if (ext == null) { + _extends = new String[0]; + } else { + _extends = new String[ext.length]; + for (int i = 0; i < ext.length; i++) { + _extends[i] = ext[i].trim(); + } + } + } + + /** + * @param name + */ + public Configuration(String name) { + this(name, Visibility.PUBLIC, null, null); + } + + /** + * @return Returns the description. It may be null. + */ + public String getDescription() { + return _description; + } + /** + * @return Returns the extends. May be empty, but never null. + */ + public String[] getExtends() { + return _extends; + } + /** + * @return Returns the name. Never null; + */ + public String getName() { + return _name; + } + /** + * @return Returns the visibility. Never null. + */ + public Visibility getVisibility() { + return _visibility; + } + + public String toString() { + return _name; + } + + public boolean equals(Object obj) { + if (! (obj instanceof Configuration)) { + return false; + } + return ((Configuration)obj).getName().equals(getName()); + } + + public int hashCode() { + return getName().hashCode(); + } +} diff --git a/src/java/fr/jayasoft/ivy/ConflictManager.java b/src/java/fr/jayasoft/ivy/ConflictManager.java new file mode 100644 index 00000000..84e5a80b --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ConflictManager.java @@ -0,0 +1,22 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Collection; + +public interface ConflictManager { + /** + * Resolves the eventual conflicts found in the given collection of IvyNode. + * This method return a Collection of IvyNode which have not been evicted. + * The returned collection must contain at least one IvyNode. + * The given conflicts Collection contains at least two IvyNode. + * @param parent the ivy node parent for which the conflict is to be resolved + * @param conflicts the collection of IvyNode to check for conflicts + * @return a Collection of IvyNode which have not been evicted + */ + Collection resolveConflicts(IvyNode parent, Collection conflicts); + String getName(); +} diff --git a/src/java/fr/jayasoft/ivy/DefaultArtifact.java b/src/java/fr/jayasoft/ivy/DefaultArtifact.java new file mode 100644 index 00000000..c1aec900 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultArtifact.java @@ -0,0 +1,60 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + +/** + * @author Hanin + * + */ +public class DefaultArtifact extends AbstractArtifact { + Date _publicationDate; + ArtifactRevisionId _arid; + + public DefaultArtifact(ModuleRevisionId mrid, Date publicationDate, String name, String type, String ext) { + if (mrid == null) { + throw new NullPointerException("null mrid not allowed"); + } + if (publicationDate == null) { + throw new NullPointerException("null publication date not allowed"); + } + if (name == null) { + throw new NullPointerException("null name not allowed"); + } + if (type == null) { + throw new NullPointerException("null type not allowed"); + } + if (ext == null) { + throw new NullPointerException("null ext not allowed"); + } + _publicationDate = publicationDate; + _arid = ArtifactRevisionId.newInstance(mrid, name, type, ext); + } + + public ModuleRevisionId getModuleRevisionId() { + return _arid.getModuleRevisionId(); + } + public String getName() { + return _arid.getName(); + } + public Date getPublicationDate() { + return _publicationDate; + } + public String getType() { + return _arid.getType(); + } + public String getExt() { + return _arid.getExt(); + } + public ArtifactRevisionId getId() { + return _arid; + } + + public String[] getConfigurations() { + return new String[0]; + } +} diff --git a/src/java/fr/jayasoft/ivy/DefaultDependencyArtifactDescriptor.java b/src/java/fr/jayasoft/ivy/DefaultDependencyArtifactDescriptor.java new file mode 100644 index 00000000..293f808b --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultDependencyArtifactDescriptor.java @@ -0,0 +1,92 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * TODO write javadoc + */ +public class DefaultDependencyArtifactDescriptor implements DependencyArtifactDescriptor { + + private DefaultDependencyDescriptor _dd; + private ArtifactId _id; + private Collection _confs = new ArrayList(); + private boolean _includes; + + + /** + * @param dd + * @param name + * @param type + */ + public DefaultDependencyArtifactDescriptor(DefaultDependencyDescriptor dd, + String name, String type, String ext, boolean includes) { + if (dd == null) { + throw new NullPointerException("dependency descriptor must not be null"); + } + if (name == null) { + throw new NullPointerException("name must not be null"); + } + if (type == null) { + throw new NullPointerException("type must not be null"); + } + _dd = dd; + _id = new ArtifactId(dd.getDependencyId(), name, type, ext); + _includes = includes; + } + + public boolean equals(Object obj) { + if (!(obj instanceof DependencyArtifactDescriptor)) { + return false; + } + DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)obj; + return getId().equals(dad.getId()); + } + + public int hashCode() { + return getId().hashCode(); + } + + /** + * Add a configuration for this artifact (includes or excludes depending on this type dependency artifact descriptor). + * This method also updates the corresponding dependency descriptor + * @param conf + */ + public void addConfiguration(String conf) { + _confs.add(conf); + if (_includes) { + _dd.addDependencyArtifactIncludes(conf, this); + } else { + _dd.addDependencyArtifactExcludes(conf, this); + } + } + + public DependencyDescriptor getDependency() { + return _dd; + } + + public ArtifactId getId() { + return _id; + } + + public String getName() { + return _id.getName(); + } + + public String getType() { + return _id.getType(); + } + public String getExt() { + return _id.getExt(); + } + + public String[] getConfigurations() { + return (String[])_confs.toArray(new String[_confs.size()]); + } + +} diff --git a/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java b/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java new file mode 100644 index 00000000..55aeef19 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultDependencyDescriptor.java @@ -0,0 +1,192 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * This class can be used as the default implementation for DependencyDescriptor. + * It implements required methods and enables to fill dependency information + * with the addDependencyConfiguration method. + * + * @author Xavier Hanin + * + */ +public class DefaultDependencyDescriptor implements DependencyDescriptor { + private ModuleRevisionId _revId; + private Map _confs = new HashMap(); + private Map _artifactsIncludes = new HashMap(); // Map (String masterConf -> Collection(DependencyArtifactDescriptor)) + private Map _artifactsExcludes = new HashMap(); // Map (String masterConf -> Collection(DependencyArtifactDescriptor)) + private Set _extends = new HashSet(); + + /** + * Used to indicate that this revision must be used in case of conflicts, independently + * of conflicts manager + */ + private boolean _force; + private ModuleRevisionId _parentId; + + public DefaultDependencyDescriptor(ModuleDescriptor md, ModuleRevisionId mrid, boolean force) { + _parentId = md.getModuleRevisionId(); + _revId = mrid; + _force = force; + } + + public DefaultDependencyDescriptor(ModuleRevisionId mrid, boolean force) { + _revId = mrid; + _force = force; + } + + public ModuleId getDependencyId() { + return getDependencyRevisionId().getModuleId(); + } + + public ModuleRevisionId getDependencyRevisionId() { + return _revId; + } + + public String[] getModuleConfigurations() { +// if (_confs.isEmpty()) { // if no conf has been defined then all confs are required in all confs +// return new String[] {"*"}; +// } + return (String[]) _confs.keySet().toArray(new String[_confs.keySet().size()]); + } + + public String[] getDependencyConfigurations(String moduleConfiguration) { +// if (_confs.isEmpty()) { // if no conf has been defined then all confs are required in all confs +// return new String[] {"*"}; +// } + List confs = (List)_confs.get(moduleConfiguration); + List defConfs = (List)_confs.get("*"); + List ret = new ArrayList(); + if (confs != null) { + ret.addAll(confs); + } + if (defConfs != null) { + ret.addAll(defConfs); + } + return (String[])ret.toArray(new String[ret.size()]); + } + + public String[] getDependencyConfigurations(String[] moduleConfigurations) { + Set confs = new HashSet(); + for (int i = 0; i < moduleConfigurations.length; i++) { + confs.addAll(Arrays.asList(getDependencyConfigurations(moduleConfigurations[i]))); + } + if (confs.contains("*")) { + return new String[] {"*"}; + } + return (String[]) confs.toArray(new String[confs.size()]); + } + + public DependencyArtifactDescriptor[] getDependencyArtifactsIncludes(String moduleConfiguration) { + return getDependencyArtifacts(moduleConfiguration, _artifactsIncludes); + } + + public DependencyArtifactDescriptor[] getDependencyArtifactsExcludes(String moduleConfiguration) { + return getDependencyArtifacts(moduleConfiguration, _artifactsExcludes); + } + + private DependencyArtifactDescriptor[] getDependencyArtifacts(String moduleConfiguration, Map artifactsMap) { + if (artifactsMap.isEmpty()) { + return new DependencyArtifactDescriptor[0]; + } + Collection artifacts = (Collection)artifactsMap.get(moduleConfiguration); + Collection defArtifacts = (Collection)artifactsMap.get("*"); + Set ret = new HashSet(); + if (artifacts != null) { + ret.addAll(artifacts); + } + if (defArtifacts != null) { + ret.addAll(defArtifacts); + } + return (DependencyArtifactDescriptor[])ret.toArray(new DependencyArtifactDescriptor[ret.size()]); + } + + public DependencyArtifactDescriptor[] getDependencyArtifactsIncludes(String[] moduleConfigurations) { + Set artifacts = new HashSet(); + for (int i = 0; i < moduleConfigurations.length; i++) { + artifacts.addAll(Arrays.asList(getDependencyArtifactsIncludes(moduleConfigurations[i]))); + } + return (DependencyArtifactDescriptor[]) artifacts.toArray(new DependencyArtifactDescriptor[artifacts.size()]); + } + + public DependencyArtifactDescriptor[] getDependencyArtifactsExcludes(String[] moduleConfigurations) { + Set artifacts = new HashSet(); + for (int i = 0; i < moduleConfigurations.length; i++) { + artifacts.addAll(Arrays.asList(getDependencyArtifactsExcludes(moduleConfigurations[i]))); + } + return (DependencyArtifactDescriptor[]) artifacts.toArray(new DependencyArtifactDescriptor[artifacts.size()]); + } + + public DependencyArtifactDescriptor[] getAllDependencyArtifactsIncludes() { + return getAllDependencyArtifacts(_artifactsIncludes); + } + + public DependencyArtifactDescriptor[] getAllDependencyArtifactsExcludes() { + return getAllDependencyArtifacts(_artifactsExcludes); + } + + private DependencyArtifactDescriptor[] getAllDependencyArtifacts(Map artifactsMap) { + Set ret = new HashSet(); + for (Iterator it = artifactsMap.values().iterator(); it.hasNext();) { + Collection artifacts = (Collection)it.next(); + ret.addAll(artifacts); + } + return (DependencyArtifactDescriptor[])ret.toArray(new DependencyArtifactDescriptor[ret.size()]); + } + + public void addDependencyConfiguration(String masterConf, String depConf) { + List confs = (List)_confs.get(masterConf); + if (confs == null) { + confs = new ArrayList(); + _confs.put(masterConf, confs); + } + confs.add(depConf); + } + + public void addDependencyArtifactIncludes(String masterConf, DependencyArtifactDescriptor dad) { + addDependencyArtifacts(masterConf, dad, _artifactsIncludes); + } + + public void addDependencyArtifactExcludes(String masterConf, DependencyArtifactDescriptor dad) { + addDependencyArtifacts(masterConf, dad, _artifactsExcludes); + } + + private void addDependencyArtifacts(String masterConf, DependencyArtifactDescriptor dad, Map artifactsMap) { + Collection artifacts = (Collection)artifactsMap.get(masterConf); + if (artifacts == null) { + artifacts = new ArrayList(); + artifactsMap.put(masterConf, artifacts); + } + artifacts.add(dad); + } + + public void addExtends(String conf) { + _extends.add(conf); + } + + public String toString() { + return "dependency: "+_revId+" "+_confs; + } + + public boolean isForce() { + return _force; + } + + public ModuleRevisionId getParentRevisionId() { + return _parentId; + } + +} diff --git a/src/java/fr/jayasoft/ivy/DefaultModuleDescriptor.java b/src/java/fr/jayasoft/ivy/DefaultModuleDescriptor.java new file mode 100644 index 00000000..2dd229a4 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultModuleDescriptor.java @@ -0,0 +1,274 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +/** + * @author X.Hanin + * + */ +public class DefaultModuleDescriptor implements ModuleDescriptor { + + public static DefaultModuleDescriptor newDefaultInstance(ModuleRevisionId mrid) { + return newDefaultInstance(mrid, null); + } + + public static DefaultModuleDescriptor newDefaultInstance(ModuleRevisionId mrid, DependencyArtifactDescriptor[] artifacts) { + DefaultModuleDescriptor moduleDescriptor = new DefaultModuleDescriptor(mrid, "release", null, true); + moduleDescriptor.addConfiguration(new Configuration(DEFAULT_CONFIGURATION)); + if (artifacts != null && artifacts.length > 0) { + for (int i = 0; i < artifacts.length; i++) { + moduleDescriptor.addArtifact(DEFAULT_CONFIGURATION, new MDArtifact(moduleDescriptor, artifacts[i].getName(), artifacts[i].getType(), artifacts[i].getExt())); + } + } else { + moduleDescriptor.addArtifact(DEFAULT_CONFIGURATION, new MDArtifact(moduleDescriptor, mrid.getName(), "jar", "jar")); + } + moduleDescriptor.setLastModified(System.currentTimeMillis()); + return moduleDescriptor; + } + + private ModuleRevisionId _revId; + private ModuleRevisionId _resolvedRevId; + private String _status; + private Date _publicationDate; + private Date _resolvedPublicationDate; + private List _dependencies = new ArrayList(); + private Map _configurations = new HashMap(); // Map(String conf -> Configuration) + private Map _artifacts = new HashMap(); // Map (String conf -> Collection(Artifact)) + private String _resolverName; + private boolean _isDefault = false; + private Map _conflictManagers = new LinkedHashMap(); // Map (ModuleId -> ) + private List _licenses = new ArrayList(); // List(License) + private String _homePage; + private long _lastModified = 0; + + public DefaultModuleDescriptor(ModuleRevisionId id, String status, Date pubDate) { + this(id, status, pubDate, false); + } + + public DefaultModuleDescriptor(ModuleRevisionId id, String status, Date pubDate, boolean isDefault) { + if (id == null) { + throw new NullPointerException("null module reivsion id not allowed"); + } + _revId = id; + _resolvedRevId = id; + _status = status; + _publicationDate = pubDate; + _resolvedPublicationDate = _publicationDate==null?new Date():_publicationDate; + _isDefault = isDefault; + } + + /** + * IMPORTANT : at least call setModuleRevisionId and setResolvedPublicationDate + * with instances created by this constructor ! + * + */ + public DefaultModuleDescriptor() { + } + + public boolean isDefault() { + return _isDefault; + } + + public void setPublicationDate(Date publicationDate) { + _publicationDate = publicationDate; + if (_resolvedPublicationDate == null) { + _resolvedPublicationDate = _publicationDate==null?new Date():_publicationDate; + } + } + public Date getPublicationDate() { + return _publicationDate; + } + public void setResolvedPublicationDate(Date publicationDate) { + if (publicationDate == null) { + throw new NullPointerException("null publication date not allowed"); + } + _resolvedPublicationDate = publicationDate; + } + public Date getResolvedPublicationDate() { + return _resolvedPublicationDate; + } + + public void setModuleRevisionId(ModuleRevisionId revId) { + if (revId == null) { + throw new NullPointerException("null module revision id not allowed"); + } + _revId = revId; + if (_resolvedRevId == null) { + _resolvedRevId = _revId; + } + } + + public void setResolvedModuleRevisionId(ModuleRevisionId revId) { + _resolvedRevId = revId; + } + + public void setStatus(String status) { + _status = status; + } + + public void addDependency(DependencyDescriptor dependency) { + _dependencies.add(dependency); + } + + public void addConfiguration(Configuration conf) { + _configurations.put(conf.getName(), conf); + } + + /** + * Artifact configurations are not used since added artifact may not be + * entirely completed, so its configurations data may not be accurate + * @param conf + * @param artifact + */ + public void addArtifact(String conf, Artifact artifact) { + Collection artifacts = (Collection)_artifacts.get(conf); + if (artifacts == null) { + artifacts = new ArrayList(); + _artifacts.put(conf, artifacts); + } + artifacts.add(artifact); + } + + public ModuleRevisionId getModuleRevisionId() { + return _revId; + } + + public ModuleRevisionId getResolvedModuleRevisionId() { + return _resolvedRevId; + } + + public String getStatus() { + return _status; + } + + public Configuration[] getConfigurations() { + return (Configuration[])_configurations.values().toArray(new Configuration[_configurations.size()]); + } + + public String[] getConfigurationsNames() { + return (String[])_configurations.keySet().toArray(new String[_configurations.size()]); + } + + /** + * Returns the configuration object with the given name in the current module descriptor, null + * if not found. + */ + public Configuration getConfiguration(String confName) { + return (Configuration)_configurations.get(confName); + } + + public Artifact[] getArtifacts(String conf) { + Collection artifacts = (Collection)_artifacts.get(conf); + if (artifacts == null) { + return new Artifact[0]; + } else { + return (Artifact[])artifacts.toArray(new Artifact[artifacts.size()]); + } + } + public Artifact[] getAllArtifacts() { + Collection ret = new ArrayList(); + for (Iterator iter = _artifacts.keySet().iterator(); iter.hasNext();) { + String conf = (String)iter.next(); + ret.addAll((Collection)_artifacts.get(conf)); + } + return (Artifact[])ret.toArray(new Artifact[ret.size()]); + } + public DependencyDescriptor[] getDependencies() { + return (DependencyDescriptor[])_dependencies.toArray(new DependencyDescriptor[_dependencies.size()]); + } + + public boolean dependsOn(ModuleDescriptor md) { + for (Iterator iter = _dependencies.iterator(); iter.hasNext();) { + DependencyDescriptor dd = (DependencyDescriptor)iter.next(); + if (dd.getDependencyId().equals(md.getModuleRevisionId().getModuleId())) { + if (md.getResolvedModuleRevisionId().getRevision() == null) { + return true; + } else if (dd.getDependencyRevisionId().acceptRevision(md.getResolvedModuleRevisionId().getRevision())) { + return true; + } + } + } + return false; + } + + public String getResolverName() { + return _resolverName; + } + public void setResolverName(String resolverName) { + _resolverName = resolverName; + } + + public String toString() { + return "module: "+_revId+" status="+_status+" publication="+_publicationDate+" configurations="+_configurations+" artifacts="+_artifacts+" dependencies="+_dependencies; + } + + public void setDefault(boolean b) { + _isDefault = b; + } + + /** + * regular expressions as explained in Pattern class may be used in ModuleId + * organisation and name + * + * @param moduleId + * @param resolverName + */ + public void addConflictManager(ModuleId moduleId, ConflictManager manager) { + _conflictManagers.put(moduleId, manager); + } + public ConflictManager getConflictManager(ModuleId moduleId) { + ConflictManager cm = (ConflictManager)_conflictManagers.get(moduleId); + if (cm != null) { + return cm; + } + for (Iterator iter = _conflictManagers.keySet().iterator(); iter.hasNext();) { + ModuleId mid = (ModuleId)iter.next(); + if (Pattern.compile(mid.getOrganisation()).matcher(moduleId.getOrganisation()).matches() + && Pattern.compile(mid.getName()).matcher(moduleId.getName()).matches()) { + return (ConflictManager)_conflictManagers.get(mid); + } + } + return null; + } + + public void addLicense(License license) { + _licenses.add(license); + } + + public License[] getLicenses() { + return (License[])_licenses.toArray(new License[_licenses.size()]); + } + + public String getHomePage() { + return _homePage; + } + + + public void setHomePage(String homePage) { + _homePage = homePage; + } + + public long getLastModified() { + return _lastModified; + } + + + public void setLastModified(long lastModified) { + _lastModified = lastModified; + } + + +} diff --git a/src/java/fr/jayasoft/ivy/DefaultModuleRevision.java b/src/java/fr/jayasoft/ivy/DefaultModuleRevision.java new file mode 100644 index 00000000..05fccdcc --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultModuleRevision.java @@ -0,0 +1,67 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + + +/** + * @author x.hanin + * + */ +public class DefaultModuleRevision implements ResolvedModuleRevision { + private DependencyResolver _resolver; + private ModuleDescriptor _descriptor; + private boolean _isDownloaded; + private boolean _isSearched; + + public DefaultModuleRevision(DependencyResolver resolver, ModuleDescriptor descriptor, boolean searched, boolean downloaded) { + _resolver = resolver; + _descriptor = descriptor; + _isSearched = searched; + _isDownloaded = downloaded; + } + + public DependencyResolver getResolver() { + return _resolver; + } + + public ModuleDescriptor getDescriptor() { + return _descriptor; + } + + public ModuleRevisionId getId() { + return _descriptor.getResolvedModuleRevisionId(); + } + + public Date getPublicationDate() { + return _descriptor.getResolvedPublicationDate(); + } + + public boolean equals(Object obj) { + if (! (obj instanceof ResolvedModuleRevision)) { + return false; + } + return ((ResolvedModuleRevision)obj).getId().equals(getId()); + } + + public int hashCode() { + return getId().hashCode(); + } + + public String toString() { + return getId().toString(); + } + + public boolean isDownloaded() { + return _isDownloaded; + } + + public boolean isSearched() { + return _isSearched; + } + +} diff --git a/src/java/fr/jayasoft/ivy/DefaultPublishingDRResolver.java b/src/java/fr/jayasoft/ivy/DefaultPublishingDRResolver.java new file mode 100644 index 00000000..a8da79ad --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DefaultPublishingDRResolver.java @@ -0,0 +1,13 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + + +public final class DefaultPublishingDRResolver implements PublishingDependencyRevisionResolver { + public String resolve(ModuleDescriptor published, String publishedStatus, ModuleDescriptor dependency) { + return dependency.getResolvedModuleRevisionId().getRevision(); + } +} diff --git a/src/java/fr/jayasoft/ivy/DependencyArtifactDescriptor.java b/src/java/fr/jayasoft/ivy/DependencyArtifactDescriptor.java new file mode 100644 index 00000000..00b50a1f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DependencyArtifactDescriptor.java @@ -0,0 +1,46 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +/** + * This describes an artifact that is asked for a dependency. + * + * It is used to resctrict the artifacts asked for a dependency, or describe them + * when there is no ivy file. + */ +public interface DependencyArtifactDescriptor { + /** + * Returns the dependency descriptor in which this artifact is asked + * @return + */ + public DependencyDescriptor getDependency(); + + /** + * Returns the id of the described artifact, without revision information + * @return + */ + public ArtifactId getId(); + /** + * Returns the name of the artifact asked + * @return + */ + public String getName(); + /** + * Returns the type of the artifact asked + * @return + */ + public String getType(); + /** + * Returns the ext of the artifact asked + * @return + */ + public String getExt(); + /** + * Returns the configurations of the module in which the artifact is asked + * @return an array of configuration names in which the artifact is asked + */ + public String[] getConfigurations(); +} diff --git a/src/java/fr/jayasoft/ivy/DependencyDescriptor.java b/src/java/fr/jayasoft/ivy/DependencyDescriptor.java new file mode 100644 index 00000000..37f88891 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DependencyDescriptor.java @@ -0,0 +1,33 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + + +/** + * @author x.hanin + * + */ +public interface DependencyDescriptor { + ModuleId getDependencyId(); + /** + * Used to indicate that this revision must be used in case of conflicts, independently + * of conflicts manager. This only works for direct dependencies, and not transitive ones. + * @return true if this dependency should be used, false if conflicts manager + * can do its work. + */ + boolean isForce(); + ModuleRevisionId getParentRevisionId(); + ModuleRevisionId getDependencyRevisionId(); + String[] getModuleConfigurations(); + String[] getDependencyConfigurations(String moduleConfiguration); + String[] getDependencyConfigurations(String[] moduleConfigurations); + DependencyArtifactDescriptor[] getAllDependencyArtifactsIncludes(); + DependencyArtifactDescriptor[] getDependencyArtifactsIncludes(String moduleConfigurations); + DependencyArtifactDescriptor[] getDependencyArtifactsIncludes(String[] moduleConfigurations); + DependencyArtifactDescriptor[] getAllDependencyArtifactsExcludes(); + DependencyArtifactDescriptor[] getDependencyArtifactsExcludes(String moduleConfigurations); + DependencyArtifactDescriptor[] getDependencyArtifactsExcludes(String[] moduleConfigurations); +} diff --git a/src/java/fr/jayasoft/ivy/DependencyResolver.java b/src/java/fr/jayasoft/ivy/DependencyResolver.java new file mode 100644 index 00000000..ff06728e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/DependencyResolver.java @@ -0,0 +1,60 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; + +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.resolver.ModuleEntry; +import fr.jayasoft.ivy.resolver.OrganisationEntry; +import fr.jayasoft.ivy.resolver.RevisionEntry; + +/** + * @author x.hanin + * + */ +public interface DependencyResolver { + String getName(); + /** + * Should only be used by configurator + * @param name the new name of the resolver + */ + void setName(String name); + /** + * Resolve a module by id, getting its module descriptor and + * resolving the revision if it's a latest one (i.e. a revision + * uniquely identifying the revision of a module in the current environment - + * If this revision is not able to identify uniquelely the revision of the module + * outside of the current environment, then the resolved revision must begin by ##) + * @throws ParseException + */ + ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException; + DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache); + boolean exists(Artifact artifact); + void publish(Artifact artifact, File src) throws IOException; + + /** + * Reports last resolve failure as Messages + */ + void reportFailure(); + /** + * Reports last artifact download failure as Messages + * @param art + */ + void reportFailure(Artifact art); + + // listing methods, enable to know what is available from this resolver + // the listing methods must only list entries directly + // available from them, no recursion is needed as long as sub resolvers + // are registered in ivy too. + + OrganisationEntry[] listOrganisations(); + ModuleEntry[] listModules(OrganisationEntry org); + RevisionEntry[] listRevisions(ModuleEntry module); + void dumpConfig(); +} diff --git a/src/java/fr/jayasoft/ivy/Ivy.java b/src/java/fr/jayasoft/ivy/Ivy.java new file mode 100644 index 00000000..73c632cf --- /dev/null +++ b/src/java/fr/jayasoft/ivy/Ivy.java @@ -0,0 +1,1469 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Pattern; + +import javax.swing.event.EventListenerList; + +import org.xml.sax.SAXException; + +import fr.jayasoft.ivy.conflict.LatestConflictManager; +import fr.jayasoft.ivy.conflict.NoConflictManager; +import fr.jayasoft.ivy.latest.LatestLexicographicStrategy; +import fr.jayasoft.ivy.latest.LatestRevisionStrategy; +import fr.jayasoft.ivy.latest.LatestTimeStrategy; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.ConfigurationResolveReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.report.LogReportOutputter; +import fr.jayasoft.ivy.report.ReportOutputter; +import fr.jayasoft.ivy.report.ResolveReport; +import fr.jayasoft.ivy.report.XmlReportOutputter; +import fr.jayasoft.ivy.repository.TransferEvent; +import fr.jayasoft.ivy.repository.TransferListener; +import fr.jayasoft.ivy.resolver.ChainResolver; +import fr.jayasoft.ivy.resolver.DualResolver; +import fr.jayasoft.ivy.resolver.ModuleEntry; +import fr.jayasoft.ivy.resolver.OrganisationEntry; +import fr.jayasoft.ivy.resolver.RevisionEntry; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; +import fr.jayasoft.ivy.xml.XmlIvyConfigurationParser; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorParser; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorUpdater; +import fr.jayasoft.ivy.xml.XmlReportParser; + +/** + * @author x.hanin + * + */ +public class Ivy implements TransferListener { + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + private static final String DEFAULT_CACHE_ARTIFACT_PATTERN = "[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"; + private static final String DEFAULT_CACHE_IVY_PATTERN = "[organisation]/[module]/ivy-[revision].xml"; + + private Map _typeDefs = new HashMap(); + private Map _resolversMap = new HashMap(); + private DependencyResolver _defaultResolver; + private String _defaultResolverName; + private File _defaultCache; + private boolean _checkUpToDate = true; + private Map _moduleConfigurations = new LinkedHashMap(); // Map (ModuleId -> String resolverName) + + private Map _conflictsManager = new HashMap(); // Map (String conflictManagerName -> ConflictManager) + private Map _latestStrategies = new HashMap(); // Map (String latestStrategyName -> LatestStrategy) + + private Map _variables = new HashMap(); + + private ReportOutputter[] _reportOutputters = new ReportOutputter[] {new LogReportOutputter(), new XmlReportOutputter()}; + + private String _cacheIvyPattern = DEFAULT_CACHE_IVY_PATTERN; + private String _cacheArtifactPattern = DEFAULT_CACHE_ARTIFACT_PATTERN; + + private boolean _validate = true; + + private LatestStrategy _defaultLatestStrategy = null; + private ConflictManager _defaultConflictManager = null; + + private List _listingIgnore = new ArrayList(); + + private boolean _repositoriesConfigured; + + public Ivy() { + String ivyTypeDefs = System.getProperty("ivy.typedef.files"); + if (ivyTypeDefs != null) { + String[] files = ivyTypeDefs.split("\\,"); + for (int i = 0; i < files.length; i++) { + try { + typeDefs(new FileInputStream(new File(files[i].trim()))); + } catch (FileNotFoundException e) { + Message.warn("typedefs file not found: "+files[i].trim()); + } catch (IOException e) { + Message.warn("problem with typedef file: "+files[i].trim()+": "+e.getMessage()); + } + } + } else { + try { + typeDefs(Ivy.class.getResourceAsStream("typedef.properties")); + } catch (IOException e) { + Message.warn("impossible to load default type defs"); + } + } + LatestLexicographicStrategy latestLexicographicStrategy = new LatestLexicographicStrategy(); + LatestRevisionStrategy latestRevisionStrategy = new LatestRevisionStrategy(); + LatestTimeStrategy latestTimeStrategy = new LatestTimeStrategy(); + + addLatestStrategy("latest-revision", latestRevisionStrategy); + addLatestStrategy("latest-lexico", latestLexicographicStrategy); + addLatestStrategy("latest-time", latestTimeStrategy); + + addConflictManager("latest-revision", new LatestConflictManager("latest-revision", latestRevisionStrategy)); + addConflictManager("latest-time", new LatestConflictManager("latest-time", latestTimeStrategy)); + addConflictManager("all", new NoConflictManager()); + + _listingIgnore.add(".cvsignore"); + _listingIgnore.add("CVS"); + _listingIgnore.add(".svn"); + + addTransferListener(new TransferListener() { + public void transferProgress(TransferEvent evt) { + switch (evt.getEventType()) { + case TransferEvent.TRANSFER_PROGRESS: + Message.progress(); + break; + case TransferEvent.TRANSFER_COMPLETED: + Message.endProgress(" ("+(evt.getTotalLength() / 1024)+"kB)"); + break; + default: + break; + } + } + }); + } + + /** + * Call this method to ask ivy to configure some variables using a remote properties file + */ + public void configureRepositories() { + if (!_repositoriesConfigured) { + Properties props; + try { + props = new Properties(); + URL url = new URL("http://ivy.jayasoft.org/repository.properties"); + Message.verbose("configuring repositories with "+url); + props.load(url.openStream()); + } catch (Exception ex) { + Message.verbose("unable to use remote repository configuration: "+ex.getMessage()); + props = new Properties(); + try { + props.load(Ivy.class.getResourceAsStream("repository.properties")); + } catch (IOException e) { + Message.error("unable to use internal repository configuration: "+e.getMessage()); + } + } + addAllVariables(props, false); + _repositoriesConfigured = true; + } + } + + public void typeDefs(InputStream stream) throws IOException { + try { + Properties p = new Properties(); + p.load(stream); + typeDefs(p); + } finally { + stream.close(); + } + } + + public void typeDefs(Properties p) { + for (Iterator iter = p.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + try { + typeDef(name, Class.forName(p.getProperty(name))); + } catch (ClassNotFoundException e) { + Message.warn("impossible to define resolver "+name+": class not found: "+p.getProperty(name)); + } + } + } + + + ///////////////////////////////////////////////////////////////////////// + // CONFIGURATION + ///////////////////////////////////////////////////////////////////////// + public void configure(File configurationFile) throws ParseException, IOException { + Message.info(":: configuring :: file = "+configurationFile); + long start = System.currentTimeMillis(); + setVariable("ivy.conf.dir", new File(configurationFile.getAbsolutePath()).getParent()); + setVariable("ivy.conf.file", configurationFile.getAbsolutePath()); + setVariable("ivy.conf.url", configurationFile.toURL().toExternalForm()); + + try { + new XmlIvyConfigurationParser(this).parse(configurationFile.toURL()); + } catch (MalformedURLException e) { + IllegalArgumentException iae = new IllegalArgumentException("given file cannot be transformed to url: "+configurationFile); + iae.initCause(e); + throw iae; + } + Message.verbose("configuration done ("+(System.currentTimeMillis()-start)+"ms)"); + dumpConfig(); + } + + public void configure(URL configurationURL) throws ParseException, IOException { + Message.info(":: configuring :: url = "+configurationURL); + long start = System.currentTimeMillis(); + String confURL = configurationURL.toExternalForm(); + setVariable("ivy.conf.url", confURL); + int slashIndex = confURL.lastIndexOf('/'); + if (slashIndex != -1) { + setVariable("ivy.conf.dir", confURL.substring(0, slashIndex)); + } else { + Message.warn("configuration url does not contain any slash (/): ivy.conf.dir variable not set"); + } + + new XmlIvyConfigurationParser(this).parse(configurationURL); + Message.verbose("configuration done ("+(System.currentTimeMillis()-start)+"ms)"); + dumpConfig(); + } + + private void dumpConfig() { + Message.verbose("\tdefault cache: "+getDefaultCache()); + Message.verbose("\tdefault resolver: "+getDefaultResolver()); + Message.debug("\tdefault latest strategy: "+getDefaultLatestStrategy()); + Message.debug("\tdefault conflict manager: "+getDefaultConflictManager()); + Message.debug("\tvalidate: "+doValidate()); + Message.debug("\tcheck up2date: "+isCheckUpToDate()); + Message.debug("\tcache ivy pattern: "+getCacheIvyPattern()); + Message.debug("\tcache artifact pattern: "+getCacheArtifactPattern()); + + Message.verbose("\t-- "+_resolversMap.size()+" resolvers:"); + for (Iterator iter = _resolversMap.values().iterator(); iter.hasNext();) { + DependencyResolver resolver = (DependencyResolver)iter.next(); + resolver.dumpConfig(); + } + if (!_moduleConfigurations.isEmpty()) { + Message.debug("\tmodule configurations:"); + for (Iterator iter = _moduleConfigurations.keySet().iterator(); iter.hasNext();) { + ModuleId mid = (ModuleId)iter.next(); + String res = (String)_moduleConfigurations.get(mid); + Message.debug("\t\t"+mid+" -> "+res); + } + } + } + + public void loadProperties(URL url) throws IOException { + Properties properties = new Properties(); + properties.load(url.openStream()); + addAllVariables(properties); + } + public void loadProperties(File file) throws IOException { + Properties properties = new Properties(); + properties.load(new FileInputStream(file)); + addAllVariables(properties); + } + + public void setVariable(String varName, String value) { + Message.debug("setting '"+varName+"' to '"+value+"'"); + _variables.put(varName, substitute(value)); + } + + public void addAllVariables(Map variables) { + addAllVariables(variables, true); + } + + public void addAllVariables(Map variables, boolean overwrite) { + for (Iterator iter = variables.keySet().iterator(); iter.hasNext();) { + String key = (String)iter.next(); + if (overwrite || !_variables.containsKey(key)) { + String val = (String)variables.get(key); + setVariable(key, val); + } + } + } + + /** + * Substitute variables in the given string by their value found in the current + * set of variables + * + * @param str the string in which substitution should be made + * @return the string where all current ivy variables have been substituted by their value + */ + public String substitute(String str) { + return IvyPatternHelper.substituteVariables(str, getVariables()); + } + + /** + * Returns the variables loaded in configuration file. Those variables + * may better be seen as ant properties + * + * @return + */ + public Map getVariables() { + return _variables; + } + + public void typeDef(String name, Class clazz) { + _typeDefs.put(name, clazz); + } + + public Map getTypeDefs() { + return _typeDefs; + } + + public Class getTypeDef(String name) { + return (Class)_typeDefs.get(name); + } + + // methods which match ivy conf method signature specs + public void addConfigured(DependencyResolver resolver) { + addResolver(resolver); + } + + public void addResolver(DependencyResolver resolver) { + if (resolver == null) { + throw new NullPointerException("null resolver"); + } + if (resolver instanceof IvyAware) { + ((IvyAware)resolver).setIvy(this); + } + _resolversMap.put(resolver.getName(), resolver); + if (resolver instanceof ChainResolver) { + List subresolvers = ((ChainResolver)resolver).getResolvers(); + for (Iterator iter = subresolvers.iterator(); iter.hasNext();) { + DependencyResolver dr = (DependencyResolver)iter.next(); + addResolver(dr); + } + } else if (resolver instanceof DualResolver) { + DependencyResolver ivyResolver = ((DualResolver)resolver).getIvyResolver(); + if (ivyResolver != null) { + addResolver(ivyResolver); + } + DependencyResolver artifactResolver = ((DualResolver)resolver).getArtifactResolver(); + if (artifactResolver != null) { + addResolver(artifactResolver); + } + } + } + + public void setDefaultCache(File cacheDirectory) { + _defaultCache = cacheDirectory; + } + + public void setDefaultResolver(String resolverName) { + checkResolverName(resolverName); + _defaultResolverName = resolverName; + } + + private void checkResolverName(String resolverName) { + if (!_resolversMap.containsKey(resolverName)) { + throw new IllegalArgumentException("no resolver found called "+resolverName+": check your configuration"); + } + } + + /** + * regular expressions as explained in Pattern class may be used in ModuleId + * organisation and name + * + * @param moduleId + * @param resolverName + */ + public void addModuleConfiguration(ModuleId moduleId, String resolverName) { + checkResolverName(resolverName); + _moduleConfigurations.put(moduleId, resolverName); + } + + public File getDefaultCache() { + if (_defaultCache==null) { + _defaultCache = new File(System.getProperty("user.home"), ".ivy-cache"); + Message.verbose("no default cache defined: set to "+_defaultCache); + } + return _defaultCache; + } + + public DependencyResolver getResolver(ModuleId moduleId) { + String resolverName = getResolverName(moduleId); + return getResolver(resolverName); + } + + public DependencyResolver getResolver(String resolverName) { + DependencyResolver resolver = (DependencyResolver)_resolversMap.get(resolverName); + if (resolver == null) { + Message.error("unknown resolver "+resolverName); + } + return resolver; + } + + public DependencyResolver getDefaultResolver() { + if (_defaultResolver == null) { + _defaultResolver = (DependencyResolver)_resolversMap.get(_defaultResolverName); + } + return _defaultResolver; + } + + public String getResolverName(ModuleId moduleId) { + String name = (String)_moduleConfigurations.get(moduleId); + if (name != null) { + return name; + } + for (Iterator iter = _moduleConfigurations.keySet().iterator(); iter.hasNext();) { + ModuleId mid = (ModuleId)iter.next(); + if (Pattern.compile(mid.getOrganisation()).matcher(moduleId.getOrganisation()).matches() + && Pattern.compile(mid.getName()).matcher(moduleId.getName()).matches()) { + return (String)_moduleConfigurations.get(mid); + } + } + return _defaultResolverName; + } + + public void addConfigured(ConflictManager cm) { + addConflictManager(cm.getName(), cm); + } + + public ConflictManager getConflictManager(String name) { + if ("default".equals(name)) { + return getDefaultConflictManager(); + } + return (ConflictManager)_conflictsManager.get(name); + } + public void addConflictManager(String name, ConflictManager cm) { + if (cm instanceof IvyAware) { + ((IvyAware)cm).setIvy(this); + } + _conflictsManager.put(name, cm); + } + + public void addConfigured(LatestStrategy latest) { + addLatestStrategy(latest.getName(), latest); + } + + public LatestStrategy getLatestStrategy(String name) { + if ("default".equals(name)) { + return getDefaultLatestStrategy(); + } + return (LatestStrategy)_latestStrategies.get(name); + } + public void addLatestStrategy(String name, LatestStrategy latest) { + if (latest instanceof IvyAware) { + ((IvyAware)latest).setIvy(this); + } + _latestStrategies.put(name, latest); + } + + ///////////////////////////////////////////////////////////////////////// + // CHECK + ///////////////////////////////////////////////////////////////////////// + /** + * Checks the given ivy file using current configuration to see if all dependencies + * are available, with good confs. If a resolver name is given, it also checks that the declared + * publications are available in the corresponding resolver. + * Note that the check is not performed recursively, i.e. if a dependency has itself dependencies + * badly described or not available, this check will not discover it. + */ + public boolean check(URL ivyFile, String resolvername) { + try { + boolean result = true; + // parse ivy file + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(this, ivyFile, doValidate()); + + // check publications if possible + if (resolvername != null) { + DependencyResolver resolver = getResolver(resolvername); + String[] confs = md.getConfigurationsNames(); + Set artifacts = new HashSet(); + for (int i = 0; i < confs.length; i++) { + artifacts.addAll(Arrays.asList(md.getArtifacts(confs[i]))); + } + for (Iterator iter = artifacts.iterator(); iter.hasNext();) { + Artifact art = (Artifact)iter.next(); + if (!resolver.exists(art)) { + Message.info("declared publication not found: "+art); + result = false; + } + } + } + + // check dependencies + DependencyDescriptor[] dds = md.getDependencies(); + ResolveData data = new ResolveData(this, getDefaultCache(), new Date(), null, true); + for (int i = 0; i < dds.length; i++) { + // check master confs + String[] masterConfs = dds[i].getModuleConfigurations(); + for (int j = 0; j < masterConfs.length; j++) { + if (!"*".equals(masterConfs[j].trim()) && md.getConfiguration(masterConfs[j]) == null) { + Message.info("dependency required in non existing conf for "+ivyFile+" \n\tin "+dds[i].getDependencyRevisionId()+": "+masterConfs[j]); + result = false; + } + } + // resolve + DependencyResolver resolver = getResolver(dds[i].getDependencyId()); + ResolvedModuleRevision rmr = resolver.getDependency(dds[i], data); + if (rmr == null) { + Message.info("dependency not found in "+ivyFile+":\n\t"+dds[i]); + result = false; + } else { + String[] depConfs = dds[i].getDependencyConfigurations(md.getConfigurationsNames()); + for (int j = 0; j < depConfs.length; j++) { + if (!Arrays.asList(rmr.getDescriptor().getConfigurationsNames()).contains(depConfs[j])) { + Message.info("dependency configuration is missing for "+ivyFile+"\n\tin "+dds[i].getDependencyRevisionId()+": "+depConfs[j]); + result = false; + } + Artifact[] arts = rmr.getDescriptor().getArtifacts(depConfs[j]); + for (int k = 0; k < arts.length; k++) { + if (!resolver.exists(arts[k])) { + Message.info("dependency artifact is missing for "+ivyFile+"\n\t in "+dds[i].getDependencyRevisionId()+": "+arts[k]); + result = false; + } + } + } + } + } + return result; + } catch (ParseException e) { + Message.info("parse problem on "+ivyFile+": "+e.getMessage()); + return false; + } catch (IOException e) { + Message.info("io problem on "+ivyFile+": "+e.getMessage()); + return false; + } catch (Exception e) { + Message.info("problem on "+ivyFile+": "+e.getMessage()); + return false; + } + } + + ///////////////////////////////////////////////////////////////////////// + // RESOLVE + ///////////////////////////////////////////////////////////////////////// + + /** + * + * @param ivySource the url to the descriptor of the module for which dependencies should be resolved + * @param revision the revision of the module for which dependencies should be resolved. + * This revision is considered as the resolved revision of the module, unless it is null. + * If it is null, then a default revision is given if necessary (no revision found in ivy file) + * @param confs the configurations for which dependencies should be resolved + * @param cache the directory where to place resolved dependencies + * @param date the date for which the dependencies should be resolved. All obtained artifacts + * should have a publication date which is before or equal to the given date + * @throws ParseException + * @throws IOException + * @throws NullPointerException if any parameter is null except cache or date + */ + public ResolveReport resolve(URL ivySource, String revision, String[] confs, File cache, Date date, boolean validate) throws ParseException, IOException { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(this, ivySource, validate); + if (cache==null) { // ensure that a cache exists + cache = getDefaultCache(); + } + if (revision == null && md.getResolvedModuleRevisionId().getRevision() == null) { + revision = "working@"+getLocalHostName(); + } + if (revision != null) { + md.setResolvedModuleRevisionId(new ModuleRevisionId(md.getModuleRevisionId().getModuleId(), revision)); + } + if (confs.length == 1 && confs[0].equals("*")) { + confs = md.getConfigurationsNames(); + } + long start = System.currentTimeMillis(); + Message.info(":: resolving dependencies :: "+md.getResolvedModuleRevisionId()); + Message.info("\tconfs: "+Arrays.asList(confs)); + Message.verbose("\tvalidate = "+validate); + ResolveReport report = new ResolveReport(md); + + // resolve dependencies + IvyNode[] dependencies = getDependencies(md, confs, cache, date, report, validate); + + Message.verbose(":: downloading artifacts ::"); + Map resolvedRevisions = new HashMap(); // Map (ModuleId dependency -> String revision) + for (int i = 0; i < dependencies.length; i++) { + //download artifacts required in all asked configurations + if (!dependencies[i].isCompletelyEvicted() && !dependencies[i].hasProblem()) { + DependencyResolver resolver = dependencies[i].getModuleRevision().getResolver(); + DownloadReport dReport = resolver + .download(dependencies[i].getSelectedArtifacts(), this, cache); + ArtifactDownloadReport[] adrs = dReport.getArtifactsReports(DownloadStatus.FAILED); + for (int j = 0; j < adrs.length; j++) { + Message.warn("\t[NOT FOUND ] "+adrs[j].getArtifact()); + resolver.reportFailure(adrs[j].getArtifact()); + } + // update concerned reports + String[] dconfs = dependencies[i].getRootModuleConfigurations(); + for (int j = 0; j < dconfs.length; j++) { + // the report itself is responsible to take into account only + // artifacts required in its corresponding configuration + // (as described by the Dependency object) + if (dependencies[i].isEvicted(dconfs[j])) { + report.getConfigurationReport(dconfs[j]).addDependency(dependencies[i]); + } else { + report.getConfigurationReport(dconfs[j]).addDependency(dependencies[i], dReport); + } + } + + // update resolved dependencies map for resolved ivy file producing + resolvedRevisions.put(dependencies[i].getModuleId(), dependencies[i].getResolvedId().getRevision()); + } else if (dependencies[i].isCompletelyEvicted()) { + // dependencies has been evicted: it has not been added to the report yet + String[] dconfs = dependencies[i].getRootModuleConfigurations(); + for (int j = 0; j < dconfs.length; j++) { + report.getConfigurationReport(dconfs[j]).addDependency(dependencies[i]); + } + } + } + + // produce resolved ivy conf file in cache + File ivyFileInCache = getIvyFileInCache(cache, md.getResolvedModuleRevisionId()); + try { + XmlModuleDescriptorUpdater.update( + ivySource, + ivyFileInCache, + resolvedRevisions, + null, + md.getResolvedModuleRevisionId().getRevision(), + null); + } catch (SAXException e) { + ParseException ex = new ParseException(e.getMessage(), 0); + ex.initCause(e); + throw ex; + } + Message.verbose("\tresolved ivy file produced in "+ivyFileInCache); + + Message.info(":: resolution report ::"); + + // output report + report.output(getReportOutputters(), cache); + + Message.verbose("\tresolve done ("+(System.currentTimeMillis()-start)+"ms)"); + Message.sumupProblems(); + return report; + } + + public ReportOutputter[] getReportOutputters() { + return _reportOutputters; + } + + + /** + * Resolve the dependencies of a module without downloading corresponding artifacts. + * The module to resolve is given by its ivy file URL. This method requires + * appropriate configuration of the ivy instance, especially resolvers. + * + * @param ivySource url of the ivy file to use for dependency resolving + * @param confs an array of configuration names to resolve - must not be null nor empty + * @param cache the cache to use - default cache is used if null + * @param date the date to which resolution must be done - may be null + * @return an array of the resolved dependencies + * @throws ParseException if a parsing problem occured in the ivy file + * @throws IOException if an IO problem was raised during ivy file parsing + */ + public IvyNode[] getDependencies(URL ivySource, String[] confs, File cache, Date date, boolean validate) throws ParseException, IOException { + return getDependencies(XmlModuleDescriptorParser.parseDescriptor(this, ivySource, validate), confs, cache, date, null, validate); + } + + /** + * Resolve the dependencies of a module without downloading corresponding artifacts. + * The module to resolve is given by its module descriptor.This method requires + * appropriate configuration of the ivy instance, especially resolvers. + * + * @param md the descriptor of the module for which we want to get dependencies - must not be null + * @param confs an array of configuration names to resolve - must not be null nor empty + * @param cache the cache to use - default cache is used if null + * @param date the date to which resolution must be done - may be null + * @param report a resolve report to fill during resolution - may be null + * @return an array of the resolved Dependencies + */ + public IvyNode[] getDependencies(ModuleDescriptor md, String[] confs, File cache, Date date, ResolveReport report, boolean validate) { + if (md == null) { + throw new NullPointerException("module descriptor must not be null"); + } + if (cache==null) { // ensure that a cache exists + cache = getDefaultCache(); + } + if (confs.length == 1 && confs[0].equals("*")) { + confs = md.getConfigurationsNames(); + } + + Map dependenciesMap = new HashMap(); + Date reportDate = new Date(); + for (int i = 0; i < confs.length; i++) { + Configuration configuration = md.getConfiguration(confs[i]); + if (configuration == null) { + Message.error("asked configuration not found in "+md.getModuleRevisionId()+": "+confs[i]); + } else { + ConfigurationResolveReport confReport = null; + if (report != null) { + confReport = report.getConfigurationReport(confs[i]); + if (confReport == null) { + confReport = new ConfigurationResolveReport(this, md, confs[i], reportDate); + report.addReport(confs[i], confReport); + } + } + ResolveData data = new ResolveData(this, cache, date, confReport, validate, dependenciesMap); + IvyNode node = new IvyNode(data, md, confs[i]); + node.setRootModuleConf(confs[i]); + fetchDependencies(node, confs[i], false); + } + } + + // prune and reverse sort fectched dependencies + Collection dependencies = new HashSet(dependenciesMap.size()); // use a Set to avoids duplicates + for (Iterator iter = dependenciesMap.values().iterator(); iter.hasNext();) { + IvyNode dep = (IvyNode) iter.next(); + if (dep != null) { + dependencies.add(dep); + } + } + List sortedDependencies = sortNodes(dependencies); + Collections.reverse(sortedDependencies); + return (IvyNode[])sortedDependencies.toArray(new IvyNode[sortedDependencies.size()]); + } + + + + + private void fetchDependencies(IvyNode node, String conf, boolean shouldBePublic) { + resolveConflict(node, node.getParent(), Collections.EMPTY_SET); + if (node.loadData(conf)) { + node = node.getRealNode(); // if data loading discarded the node, get the real one + resolveConflict(node, node.getParent(), Collections.EMPTY_SET); + if (!node.isEvicted(node.getRootModuleConf())) { + if ("*".equals(conf)) { + String[] confs = node.getDescriptor().getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + doFetchDependencies(node, confs[i], shouldBePublic); + } + } else { + doFetchDependencies(node, conf, shouldBePublic); + } + } + } + if (node.isEvicted(node.getRootModuleConf())) { + // update selected nodes with confs asked in evicted one + IvyNode.EvictionData ed = node.getEvictedData(node.getRootModuleConf()); + for (Iterator iter = ed.getSelected().iterator(); iter.hasNext();) { + IvyNode selected = (IvyNode)iter.next(); + fetchDependencies(selected, conf, shouldBePublic); + } + } + } + + private void doFetchDependencies(IvyNode node, String conf, boolean shouldBePublic) { + Configuration c = node.getConfiguration(conf); + if (c == null) { + Message.error("configuration not found in "+node+": "+conf+". It was required from "+node.getParent()+" "+node.getParentConf()); + } else if (c.getVisibility() != Configuration.Visibility.PUBLIC && shouldBePublic) { + Message.error("configuration not public in "+node+": "+c+". It was required from "+node.getParent()+" "+node.getParentConf()); + } else { + // we handle the case where the asked configuration extends others: + // we have to first fetch the extended configurations + String[] extendedConfs = c.getExtends(); + if (extendedConfs.length > 0) { + node.updateConfsToFetch(Arrays.asList(extendedConfs)); + } + for (int i = 0; i < extendedConfs.length; i++) { + fetchDependencies(node, extendedConfs[i], false); + } + + Collection dependencies = node.getDependencies(conf, true); + for (Iterator iter = dependencies.iterator(); iter.hasNext();) { + IvyNode dep = (IvyNode)iter.next(); + if (dep.isCircular()) { + Message.warn("circular dependency found ! "+node.getId()+" depends on "+dep.getId()+" which is already on the same branch of dependency"); + continue; + } + String[] confs = dep.getRequiredConfigurations(node, conf); + for (int i = 0; i < confs.length; i++) { + fetchDependencies(dep, confs[i], shouldBePublic); + } + // if there are still confs to fetch (usually because they have + // been updated when evicting another module), we fetch them now + confs = dep.getConfsToFetch(); + for (int i = 0; i < confs.length; i++) { + fetchDependencies(dep, confs[i], shouldBePublic); + } + } + } + } + + + private void resolveConflict(IvyNode node, IvyNode parent, Collection toevict) { + if (parent == null) { + return; + } + if (node.getId().equals(node.getResolvedId()) && parent.getResolvedRevisions(node.getModuleId(), node.getRootModuleConf()).contains(node.getId())) { + // resolve conflict has already be done with node with the same id + // => job already done + return; + } + Collection conflicts = new HashSet(); + if (parent.getResolvedNodes(node.getModuleId(), node.getRootModuleConf()).removeAll(toevict)) { + // parent.resolved(node.mid) is not up to date: + // recompute resolved from all sub nodes + Collection deps = parent.getDependencies(parent.getRequiredConfigurations()); + for (Iterator iter = deps.iterator(); iter.hasNext();) { + IvyNode dep = (IvyNode)iter.next(); + conflicts.addAll(dep.getResolvedNodes(node.getModuleId(), node.getRootModuleConf())); + } + } else { + conflicts.add(node); + conflicts.addAll(parent.getResolvedNodes(node.getModuleId(), node.getRootModuleConf())); + } + Collection resolved = parent.getConflictManager(node.getModuleId()).resolveConflicts(parent, conflicts); + if (resolved.contains(node)) { + // node has been selected for the current parent + // we update its eviction... but it can still be evicted by parent ! + node.markSelected(node.getRootModuleConf()); + Message.debug("selecting "+node+" in "+parent); + + // handle previously selected nodes that are now evicted by this new node + toevict = parent.getResolvedNodes(node.getModuleId(), node.getRootModuleConf()); + toevict.removeAll(resolved); + + for (Iterator iter = toevict.iterator(); iter.hasNext();) { + IvyNode te = (IvyNode)iter.next(); + te.markEvicted(node.getRootModuleConf(), parent, parent.getConflictManager(node.getModuleId()), resolved); + + Message.debug("evicting "+te+" by "+te.getEvictedData(node.getRootModuleConf())); + } + + // it's very important to update resolved BEFORE recompute parent call + // to allow it to recompute its resolved collection with correct data + // if necessary + parent.setResolvedNodes(node.getModuleId(), node.getRootModuleConf(), resolved); + resolveConflict(node, parent.getParent(), toevict); + } else { + // node has been evicted for the current parent + + // it's time to update parent resolved with found resolved... + // if they have not been recomputed, it does not change anything + parent.setResolvedNodes(node.getModuleId(), node.getRootModuleConf(), resolved); + + node.markEvicted(node.getRootModuleConf(), parent, parent.getConflictManager(node.getModuleId()), resolved); + Message.debug("evicting "+node+" by "+node.getEvictedData(node.getRootModuleConf())); + } + } + + public ResolvedModuleRevision findModuleInCache(ModuleRevisionId mrid, File cache, boolean validate) { + // first, check if it is in cache + if (mrid.isExactRevision()) { + File ivyFile = getIvyFileInCache(cache, mrid); + if (ivyFile.exists()) { + // found in cache ! + try { + ModuleDescriptor depMD = XmlModuleDescriptorParser.parseDescriptor(this, ivyFile.toURL(), validate); + DependencyResolver resolver = (DependencyResolver)_resolversMap.get(depMD.getResolverName()); + if (resolver != null) { + Message.debug("\tfound ivy file in cache for "+mrid+": "+ivyFile); + return new DefaultModuleRevision(resolver, depMD, false, false); + } else { + Message.debug("\tresolver not found: "+depMD.getResolverName()+" => cannot use cached ivy file for "+mrid); + } + } catch (Exception e) { + // will try with resolver + Message.debug("\tproblem while parsing cached ivy file for: "+mrid+": "+e.getMessage()); + } + } else { + Message.debug("\tno ivy file in cache for "+mrid+": tried "+ivyFile); + } + } + return null; + } + + + ///////////////////////////////////////////////////////////////////////// + // RETRIEVE + ///////////////////////////////////////////////////////////////////////// + + + /** + * example of destFilePattern : + * - lib/[organisation]/[module]/[artifact]-[revision].[type] + * - lib/[artifact].[type] : flatten with no revision + * moduleId is used with confs and localCacheDirectory to determine + * an ivy report file, used as input for the copy + * If such a file does not exist for any conf (resolve has not been called before ?) + * then an IllegalStateException is thrown and nothing is copied. + */ + public void retrieve(ModuleId moduleId, String[] confs, final File cache, String destFilePattern) { + Message.info(":: retrieving :: "+moduleId); + Message.info("\tconfs: "+Arrays.asList(confs)); + long start = System.currentTimeMillis(); + + destFilePattern = IvyPatternHelper.substituteVariables(destFilePattern, getVariables()); + try { + // find what we must retrieve where + final Map artifactsToCopy = new HashMap(); // Artifact source -> Set (String copyDestAbsolutePath) + final Map conflictsMap = new HashMap(); // String copyDestAbsolutePath -> Set (Artifact source) + final Map conflictsConfMap = new HashMap(); // String copyDestAbsolutePath -> Set (String conf) + XmlReportParser parser = new XmlReportParser(); + for (int i = 0; i < confs.length; i++) { + final String conf = confs[i]; + Artifact[] artifacts = parser.getArtifacts(moduleId, conf, cache); + for (int j = 0; j < artifacts.length; j++) { + Artifact artifact = artifacts[j]; + String destFileName = IvyPatternHelper.substitute(destFilePattern, artifact.getModuleRevisionId().getOrganisation(), artifact.getModuleRevisionId().getName(), artifact.getModuleRevisionId().getRevision(), artifact.getName(), artifact.getType(), artifact.getExt(), conf); + Set dest = (Set)artifactsToCopy.get(artifact); + if (dest == null) { + dest = new HashSet(); + artifactsToCopy.put(artifact, dest); + } + String copyDest = new File(destFileName).getAbsolutePath(); + dest.add(copyDest); + + Set conflicts = (Set)conflictsMap.get(copyDest); + Set conflictsConf = (Set)conflictsConfMap.get(copyDest); + if (conflicts == null) { + conflicts = new HashSet(); + conflictsMap.put(copyDest, conflicts); + } + if (conflictsConf == null) { + conflictsConf = new HashSet(); + conflictsConfMap.put(copyDest, conflictsConf); + } + conflicts.add(artifact); + conflictsConf.add(conf); + } + } + + // resolve conflicts if any + for (Iterator iter = conflictsMap.keySet().iterator(); iter.hasNext();) { + String copyDest = (String)iter.next(); + Set artifacts = (Set)conflictsMap.get(copyDest); + Set conflictsConfs = (Set)conflictsConfMap.get(copyDest); + if (artifacts.size() > 1) { + List artifactsList = new ArrayList(artifacts); + // conflicts battle is resolved by a sort using a conflict resolving policy comparator + // which consider as greater a winning artifact + Collections.sort(artifactsList, getConflictResolvingPolicy()); + // after the sort, the winning artifact is the greatest one, i.e. the last one + Message.info("\tconflict on "+copyDest+" in "+conflictsConfs+": "+((Artifact)artifactsList.get(artifactsList.size() -1)).getModuleRevisionId().getRevision()+" won"); + + // we now iterate over the list beginning with the artifact preceding the winner, + // and going backward to the least artifact + for (int i=artifactsList.size() - 2; i >=0; i--) { + Artifact looser = (Artifact)artifactsList.get(i); + Message.verbose("\t\tremoving conflict looser artifact: "+looser); + // for each loser, we remove the pair (loser - copyDest) in the artifactsToCopy map + Set dest = (Set)artifactsToCopy.get(looser); + dest.remove(copyDest); + if (dest.isEmpty()) { + artifactsToCopy.remove(looser); + } + } + } + } + + // do retrieve + int targetsCopied = 0; + int targetsUpToDate = 0; + for (Iterator iter = artifactsToCopy.keySet().iterator(); iter.hasNext();) { + Artifact artifact = (Artifact)iter.next(); + File archive = getArchiveFileInCache(cache, artifact); + Set dest = (Set)artifactsToCopy.get(artifact); + Message.verbose("\tretrieving "+archive); + for (Iterator it2 = dest.iterator(); it2.hasNext();) { + File destFile = new File((String)it2.next()); + if (!_checkUpToDate || !upToDate(archive, destFile)) { + Message.verbose("\t\tto "+destFile); + FileUtil.copy(archive, destFile, null); + targetsCopied++; + } else { + Message.verbose("\t\tto "+destFile+" [NOT REQUIRED]"); + targetsUpToDate++; + } + } + } + Message.info("\t"+targetsCopied+" artifacts copied, "+targetsUpToDate+" already retrieved"); + Message.verbose("\tretrieve done ("+(System.currentTimeMillis()-start)+"ms)"); + } catch (Exception ex) { + IllegalStateException ise = new IllegalStateException("problem during retrieve of "+moduleId); + ise.initCause(ex); + throw ise; + } + } + + private boolean upToDate(File source, File target) { + if (!target.exists()) { + return false; + } + return source.lastModified() == target.lastModified(); + } + + /** + * The returned comparator should consider greater the artifact which + * gains the conflict battle. + * This is used only during retrieve... prefer resolve conflict manager + * to resolve conflicts. + * @return + */ + private Comparator getConflictResolvingPolicy() { + return new Comparator() { + // younger conflict resolving policy + public int compare(Object o1, Object o2) { + Artifact a1 = (Artifact)o1; + Artifact a2 = (Artifact)o2; + if (a1.getPublicationDate().after(a2.getPublicationDate())) { + // a1 is after a2 <=> a1 is younger than a2 <=> a1 wins the conflict battle + return +1; + } else if (a1.getPublicationDate().before(a2.getPublicationDate())) { + // a1 is before a2 <=> a2 is younger than a1 <=> a2 wins the conflict battle + return -1; + } else { + return 0; + } + } + }; + } + + ///////////////////////////////////////////////////////////////////////// + // PUBLISH + ///////////////////////////////////////////////////////////////////////// + /** + * delivers a resolved ivy file based upon last resolve call status and + * the given PublishingDependencyRevisionResolver. + * If resolve report file cannot be found in cache, then it throws + * an IllegalStateException (maybe resolve has not been called before ?) + * Moreover, the given PublishingDependencyRevisionResolver is used for each + * dependency to get its published information. This can particularly useful + * when the publish is made for a delivery, and when we wish to deliver each + * dependency which is still in integration. The PublishingDependencyRevisionResolver + * can then do the delivering work for the dependency and return the new (delivered) + * dependency info (with the delivered revision). Note that + * PublishingDependencyRevisionResolver is only called for each direct dependency. + * + * @param status the new status, null to keep the old one + * @throws ParseException + */ + public void deliver(ModuleRevisionId mrid, + String revision, + File cache, + String destIvyPattern, + String status, + Date pubdate, + PublishingDependencyRevisionResolver pdrResolver, + boolean validate) throws IOException, ParseException { + Message.info(":: delivering :: "+mrid+" :: "+revision+" :: "+status+" :: "+pubdate); + Message.verbose("\tvalidate = "+validate); + long start = System.currentTimeMillis(); + destIvyPattern = substitute(destIvyPattern); + + // 1) find the resolved module descriptor in cache + File ivyFile = getIvyFileInCache(cache, mrid); + if (!ivyFile.exists()) { + throw new IllegalStateException("ivy file not found in cache for "+mrid+": please resolve dependencies before publishing ("+ivyFile+")"); + } + ModuleDescriptor md = null; + URL ivyFileURL = null; + try { + ivyFileURL = ivyFile.toURL(); + md = XmlModuleDescriptorParser.parseDescriptor(this, ivyFileURL, validate); + md.setResolvedModuleRevisionId(new ModuleRevisionId(mrid.getModuleId(), revision)); + md.setResolvedPublicationDate(pubdate); + } catch (MalformedURLException e) { + throw new RuntimeException("malformed url obtained for file "+ivyFile); + } catch (ParseException e) { + throw new IllegalStateException("bad ivy file in cache for "+mrid+": please clean and resolve again"); + } + // 2) use pdrResolver to resolve dependencies info + Map resolvedDependencies = new HashMap(); // Map (ModuleId -> String revision) + DependencyDescriptor[] dependencies = md.getDependencies(); + for (int i = 0; i < dependencies.length; i++) { + DependencyResolver resolver = getResolver(dependencies[i].getDependencyId()); + ResolvedModuleRevision dependency = resolver.getDependency(dependencies[i], new ResolveData(this, cache, pubdate, null, validate)); + if (dependency == null) { + Message.warn(resolver.getName()+": unresolved dependency while publishing: "+dependencies[i].getDependencyRevisionId()); + } else { + resolvedDependencies.put(dependencies[i].getDependencyId(), pdrResolver.resolve(md, status, dependency.getDescriptor())); + } + } + + // 3) copy the source resolved ivy to the destination specified, + // updating status, revision and dependency revisions obtained by + // PublishingDependencyRevisionResolver + String publishedIvy = IvyPatternHelper.substitute(destIvyPattern, md.getResolvedModuleRevisionId()); + Message.info("\tdelivering ivy file to "+publishedIvy); + try { + XmlModuleDescriptorUpdater.update(ivyFileURL, + new File(publishedIvy), + resolvedDependencies, status, revision, pubdate); + } catch (SAXException ex) { + throw new IllegalStateException("bad ivy file in cache for "+mrid+": please clean and resolve again"); + } + + Message.verbose("\tdeliver done ("+(System.currentTimeMillis()-start)+"ms)"); + } + + /** + * + * @param pubrevision + * @param resolverName the name of a resolver to use for publication + * @param artifactsPattern a pattern to find artifacts to publish with the given resolver + * @return a collection of missing artifacts (those that are not published) + * @throws ParseException + */ + public Collection publish(ModuleRevisionId mrid, String pubrevision, File cache, String srcArtifactPattern, String resolverName, boolean publishivy, boolean validate) throws IOException { + Message.info(":: publishing :: "+mrid); + Message.verbose("\tvalidate = "+validate); + long start = System.currentTimeMillis(); + srcArtifactPattern = substitute(srcArtifactPattern); + // 1) find the resolved module descriptor in cache + File ivyFile = getIvyFileInCache(cache, mrid); + if (!ivyFile.exists()) { + throw new IllegalStateException("ivy file not found in cache for "+mrid+": please resolve dependencies before publishing ("+ivyFile+")"); + } + DependencyResolver resolver = getResolver(resolverName); + if (resolver == null) { + throw new IllegalArgumentException("unknown resolver "+resolverName); + } + ModuleDescriptor md = null; + URL ivyFileURL = null; + try { + ivyFileURL = ivyFile.toURL(); + md = XmlModuleDescriptorParser.parseDescriptor(this, ivyFileURL, false); + md.setResolvedModuleRevisionId(new ModuleRevisionId(mrid.getModuleId(), pubrevision)); + } catch (MalformedURLException e) { + throw new RuntimeException("malformed url obtained for file "+ivyFile); + } catch (ParseException e) { + throw new IllegalStateException("bad ivy file in cache for "+mrid+": please clean cache and resolve again"); + } + + // collect all declared artifacts of this module + Collection missing = new ArrayList(); + Set artifactsSet = new HashSet(); + String[] confs = md.getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + Artifact[] artifacts = md.getArtifacts(confs[i]); + for (int j = 0; j < artifacts.length; j++) { + artifactsSet.add(artifacts[j]); + } + } + // for each declared published artifact in this descriptor, do: + for (Iterator iter = artifactsSet.iterator(); iter.hasNext();) { + Artifact artifact = (Artifact) iter.next(); + // 1) copy the artifact using src pattern and resolver + if (!publish(artifact, srcArtifactPattern, resolver)) { + missing.add(artifact); + } + } + if (publishivy) { + Artifact artifact = new MDArtifact(md, "ivy", "ivy", "xml"); + if (!publish(artifact, srcArtifactPattern, resolver)) { + missing.add(artifact); + } + } + Message.verbose("\tpublish done ("+(System.currentTimeMillis()-start)+"ms)"); + return missing; + } + + private boolean publish(Artifact artifact, String srcArtifactPattern, DependencyResolver resolver) { + File src = new File(IvyPatternHelper.substitute(srcArtifactPattern, artifact)); + if (src.exists()) { + try { + resolver.publish(artifact, src); + return true; + } catch (Exception ex) { + Message.error("impossible to publish "+artifact+" with "+resolver.getName()+": "+ex.getMessage()); + } + } + return false; + } + + ///////////////////////////////////////////////////////////////////////// + // SORT + ///////////////////////////////////////////////////////////////////////// + + public static List sortNodes(Collection nodes) { + /* here we want to use the sort algorithm which work on module descriptors : + * so we first put dependencies on a map from descriptors to dependency, then we + * sort the keySet (i.e. a collection of descriptors), then we replace + * in the sorted list each descriptor by the corresponding dependency + */ + + Map dependenciesMap = new HashMap(); + List nulls = new ArrayList(); + for (Iterator iter = nodes.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + if (node.getDescriptor() == null) { + nulls.add(node); + } else { + List n = (List)dependenciesMap.get(node.getDescriptor()); + if (n == null) { + n = new ArrayList(); + dependenciesMap.put(node.getDescriptor(), n); + } + n.add(node); + } + } + List list = sortModuleDescriptors(dependenciesMap.keySet()); + List ret = new ArrayList((int)(list.size()*1.3+nulls.size())); + for (int i=0; i=0; i-=2) { + if (listeners[i]==TransferListener.class) { + ((TransferListener)listeners[i+1]).transferProgress(evt); + } + } + } + + public void transferProgress(TransferEvent evt) { + fireTransferEvent(evt); + } + +} diff --git a/src/java/fr/jayasoft/ivy/IvyAware.java b/src/java/fr/jayasoft/ivy/IvyAware.java new file mode 100644 index 00000000..a4f33d9e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/IvyAware.java @@ -0,0 +1,10 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +public interface IvyAware { + void setIvy(Ivy ivy); +} diff --git a/src/java/fr/jayasoft/ivy/IvyNode.java b/src/java/fr/jayasoft/ivy/IvyNode.java new file mode 100644 index 00000000..dbb7d536 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/IvyNode.java @@ -0,0 +1,974 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +import fr.jayasoft.ivy.util.Message; + +public class IvyNode { + public static class EvictionData { + private IvyNode _node; + private ConflictManager _conflictManager; + private Collection _selected; + private String _rootModuleConf; + + public EvictionData(String rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection selected) { + _rootModuleConf = rootModuleConf; + _node = node; + _conflictManager = conflictManager; + _selected = selected; + } + + public String toString() { + return _selected + " in "+ _node+" ("+_conflictManager+") ["+_rootModuleConf+"]"; + } + + public ConflictManager getConflictManager() { + return _conflictManager; + } + + + public IvyNode getNode() { + return _node; + } + + public Collection getSelected() { + return _selected; + } + + + public String getRootModuleConf() { + return _rootModuleConf; + } + + + } + + public static class Caller { + private ModuleRevisionId _mrid; + private Map _confs = new HashMap(); // Map (String callerConf -> String[] dependencyConfs) + private ModuleRevisionId _askedDependencyId; + + public Caller(ModuleRevisionId mrid, ModuleRevisionId askedDependencyId) { + _mrid = mrid; + _askedDependencyId = askedDependencyId; + } + public void addConfiguration(String callerConf, String[] dependencyConfs) { + String[] prevDepConfs = (String[])_confs.get(callerConf); + if (prevDepConfs != null) { + Set newDepConfs = new HashSet(Arrays.asList(prevDepConfs)); + newDepConfs.addAll(Arrays.asList(dependencyConfs)); + _confs.put(callerConf, (String[])newDepConfs.toArray(new String[newDepConfs.size()])); + } else { + _confs.put(callerConf, dependencyConfs); + } + } + public String[] getCallerConfigurations() { + return (String[])_confs.keySet().toArray(new String[_confs.keySet().size()]); + } + public ModuleRevisionId getModuleRevisionId() { + return _mrid; + } + public boolean equals(Object obj) { + if (! (obj instanceof Caller)) { + return false; + } + Caller other = (Caller)obj; + return other._confs.equals(_confs) + && _mrid.equals(other._mrid); + } + public int hashCode() { + int hash = 31; + hash = hash * 13 + _confs.hashCode(); + hash = hash * 13 + _mrid.hashCode(); + return hash; + } + public String toString() { + return _mrid.toString(); + } + public ModuleRevisionId getAskedDependencyId() { + return _askedDependencyId; + } + } + private static final class NodeConf { + private IvyNode _node; + private String _conf; + + public NodeConf(IvyNode node, String conf) { + _node = node; + _conf = conf; + } + + public final String getConf() { + return _conf; + } + + public final IvyNode getNode() { + return _node; + } + public boolean equals(Object obj) { + if (!(obj instanceof NodeConf)) { + return false; + } + return getNode().equals(((NodeConf)obj).getNode()) + && getConf().equals(((NodeConf)obj).getConf()); + } + public int hashCode() { + int hash = 33; + hash += getNode().hashCode() * 17; + hash += getConf().hashCode() * 17; + return hash; + } + } + + private static final class ModuleIdConf { + private ModuleId _moduleId; + private String _conf; + + public ModuleIdConf(ModuleId mid, String conf) { + _moduleId = mid; + _conf = conf; + } + + public final String getConf() { + return _conf; + } + + public final ModuleId getModuleId() { + return _moduleId; + } + public boolean equals(Object obj) { + if (!(obj instanceof ModuleIdConf)) { + return false; + } + return getModuleId().equals(((ModuleIdConf)obj).getModuleId()) + && getConf().equals(((ModuleIdConf)obj).getConf()); + } + public int hashCode() { + int hash = 33; + hash += getModuleId().hashCode() * 17; + hash += getConf().hashCode() * 17; + return hash; + } + } + + private ModuleRevisionId _id; // id as requested, i.e. may be with latest rev + + /** + * Represents the current parent of the node during ivy visit + * of dependency graph. + * Use callers on Dependency to know all the callers + * of a dependency + */ + private IvyNode _parent = null; + private String _parentConf = null; + private String _rootModuleConf; + + private Map _selected = new HashMap(); // Map (ModuleIdConf -> Set(Node)) + private Map _evicted = new HashMap(); // Map (root module conf -> EvictionData) + + // Map (String rootModuleConf -> Map (ModuleRevisionId -> Caller)): key in second map is used to easily get a caller by its mrid + private Map _callersByRootConf = new HashMap(); + + // Map (String rootConfName -> Set(String confName)) + // used to know which configurations of the dependency are required by root + // module configuration + private Map _rootModuleConfs = new HashMap(); + + // Map (String rootModuleConf -> Set(DependencyArtifactDescriptor)) + private Map _dependencyArtifactsIncludes = new HashMap(); + // Map (String rootModuleConf -> Set(DependencyArtifactDescriptor)) + private Map _dependencyArtifactsExcludes = new HashMap(); + + + // shared data + private ResolveData _data; + + private Collection _confsToFetch = new HashSet(); + private Collection _fetchedConfigurations = new HashSet(); + + // set only when node has been built from DependencyDescriptor + private DependencyDescriptor _dd; + + // Set when data has been loaded only + private ModuleDescriptor _md; + + private ResolvedModuleRevision _module; + + private Exception _problem = null; + + private boolean _downloaded = false; + private boolean _searched = false; + + + private Map _requiredConfs = new HashMap(); // Map (NodeConf in -> Set(String conf)) + + + public IvyNode(ResolveData data, DependencyDescriptor dd) { + _id = dd.getDependencyRevisionId(); + _dd = dd; + + init(data, true); + } + + public IvyNode(ResolveData data, ModuleDescriptor md, String conf) { + _id = md.getModuleRevisionId(); + _md = md; + _confsToFetch.add(conf); + + // we do not register nodes created from ModuleDescriptor, cause they are + // the root of resolve + init(data, false); + } + + private void init(ResolveData data, boolean register) { + _data = data; + if (register) { + _data.register(this); + } + } + + public ConflictManager getConflictManager(ModuleId mid) { + if (_md == null) { + throw new IllegalStateException("impossible to get conflict manager when data has not been loaded"); + } + ConflictManager cm = _md.getConflictManager(mid); + return cm == null ? _data.getIvy().getDefaultConflictManager() : cm; + } + + public Collection getResolvedNodes(ModuleId mid, String rootModuleConf) { + Collection resolved = (Collection)_selected.get(new ModuleIdConf(mid, rootModuleConf)); + Set ret = new HashSet(); + if (resolved != null) { + for (Iterator iter = resolved.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + ret.add(node.getRealNode()); + } + } + return ret; + } + public Collection getResolvedRevisions(ModuleId mid, String rootModuleConf) { + Collection resolved = (Collection)_selected.get(new ModuleIdConf(mid, rootModuleConf)); + if (resolved == null) { + return new HashSet(); + } else { + Collection ret = new HashSet(); + for (Iterator iter = resolved.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + ret.add(node.getRealNode().getId()); + } + return ret; + } + } + + public void setResolvedNodes(ModuleId moduleId, String rootModuleConf, Collection resolved) { + _selected.put(new ModuleIdConf(moduleId, rootModuleConf), new HashSet(resolved)); + } + + + public boolean isEvicted(String rootModuleConf) { + cleanEvicted(); + return _evicted.containsKey(rootModuleConf); + } + + private void cleanEvicted() { + // check if it was evicted by a node that we are now the real node for + for (Iterator iter = _evicted.keySet().iterator(); iter.hasNext();) { + String rootModuleConf = (String)iter.next(); + EvictionData ed = (EvictionData)_evicted.get(rootModuleConf); + Collection sel = ed.getSelected(); + for (Iterator iterator = sel.iterator(); iterator.hasNext();) { + IvyNode n = (IvyNode)iterator.next(); + if (n.getRealNode().equals(this)) { + // yes, we are the real node for a selected one ! + // we are no more evicted in this conf ! + iter.remove(); + } + } + } + } + + public void markSelected(String rootModuleConf) { + _evicted.remove(rootModuleConf); + } + + public void markEvicted(String rootModuleConf, IvyNode node, ConflictManager conflictManager, Collection resolved) { + _evicted.put(rootModuleConf, new EvictionData(rootModuleConf, node, conflictManager, resolved)); + if (!_rootModuleConfs.keySet().contains(rootModuleConf)) { + _rootModuleConfs.put(rootModuleConf, null); + } + + // bug 105: update selected data with evicted one + for (Iterator iter = resolved.iterator(); iter.hasNext();) { + IvyNode selected = (IvyNode)iter.next(); + selected.updateDataFrom(this, rootModuleConf); + } + } + private void updateDataFrom(IvyNode node, String rootModuleConf) { + // update callers + Map nodecallers = (Map)node._callersByRootConf.get(rootModuleConf); + if (nodecallers != null) { + Map thiscallers = (Map)_callersByRootConf.get(rootModuleConf); + if (thiscallers == null) { + thiscallers = new HashMap(); + _callersByRootConf.put(rootModuleConf, thiscallers); + } + for (Iterator iter = nodecallers.values().iterator(); iter.hasNext();) { + Caller caller = (Caller)iter.next(); + if (!thiscallers.containsKey(caller.getModuleRevisionId())) { + thiscallers.put(caller.getModuleRevisionId(), caller); + } + } + } + + // update requiredConfs + updateMapOfSet(node._requiredConfs, _requiredConfs); + + // update rootModuleConfs + updateMapOfSetForKey(node._rootModuleConfs, _rootModuleConfs, rootModuleConf); + + // update dependencyArtifactsIncludes + updateMapOfSetForKey(node._dependencyArtifactsIncludes, _dependencyArtifactsIncludes, rootModuleConf); + + // update dependencyArtifactsExcludes + updateMapOfSetForKey(node._dependencyArtifactsExcludes, _dependencyArtifactsExcludes, rootModuleConf); + + // update confsToFetch + updateConfsToFetch(node._fetchedConfigurations); + updateConfsToFetch(node._confsToFetch); + } + + private void updateMapOfSet(Map from, Map to) { + for (Iterator iter = from.keySet().iterator(); iter.hasNext();) { + Object key = iter.next(); + updateMapOfSetForKey(from, to, key); + } + } + + private void updateMapOfSetForKey(Map from, Map to, Object key) { + Set set = (Set)from.get(key); + if (set != null) { + Set toupdate = (Set)to.get(key); + if (toupdate != null) { + toupdate.addAll(set); + } else { + to.put(key, new HashSet(set)); + } + } + } + + public EvictionData getEvictedData(String rootModuleConf) { + cleanEvicted(); + return (EvictionData)_evicted.get(rootModuleConf); + } + public String[] getEvictedConfs() { + cleanEvicted(); + return (String[])_evicted.keySet().toArray(new String[_evicted.keySet().size()]); + } + + public boolean isCompletelyEvicted() { + cleanEvicted(); + return _evicted.keySet().containsAll(_rootModuleConfs.keySet()); + } + + public Collection getAllEvictingNodes() { + Collection allEvictingNodes = new HashSet(); + for (Iterator iter = _evicted.values().iterator(); iter.hasNext();) { + EvictionData ed = (EvictionData)iter.next(); + allEvictingNodes.addAll(ed.getSelected()); + } + return allEvictingNodes; + } + + + public IvyNode getParent() { + return _parent; + } + + public void setParent(IvyNode parent) { + _parent = parent; + } + + public String getParentConf() { + return _parentConf; + } + + public void setParentConf(String parentConf) { + _parentConf = parentConf; + } + + + public boolean hasConfigurationsToLoad() { + return !_confsToFetch.isEmpty(); + } + + /** + * After the call node may be discarded. To avoid using discarded node, make sure + * to get the real node after the call + * IvyNode node = ... + * node.loadData(); + * node = node.getRealNode(); + * ... + */ + public boolean loadData(String conf) { + boolean loaded = _md != null; + if (!isEvicted(_rootModuleConf) && hasConfigurationsToLoad() && !hasProblem()) { + if (_md == null) { + DependencyResolver resolver = _data.getIvy().getResolver(getModuleId()); + try { + Message.debug("\tusing "+resolver+" to resolve "+getId()); + _module = resolver.getDependency(_dd, _data); + if (_module != null) { + if (!getId().isExactRevision()) { + IvyNode resolved = _data.getNode(_module.getId()); + if (resolved != null) { + // exact revision has already been resolved + // => update it and discard this node + resolved._downloaded |= _module.isDownloaded(); + resolved._searched |= _module.isSearched(); + resolved.markSelected(_rootModuleConf); + resolved.updateDataFrom(this, _rootModuleConf); + resolved.loadData(conf); + if (_dd != null) { + resolved.addDependencyArtifactsIncludes(_rootModuleConf, _dd.getDependencyArtifactsIncludes(getParentConf())); + resolved.addDependencyArtifactsExcludes(_rootModuleConf, _dd.getDependencyArtifactsExcludes(getParentConf())); + } + _data.register(getId(), resolved); // this actually discards the node + return true; + } + } + _downloaded = _module.isDownloaded(); + _searched = _module.isSearched(); + } else { + Message.warn("\tmodule not found: "+getId()); + resolver.reportFailure(); + _problem = new RuntimeException("not found"); + } + } catch (ParseException e) { + _problem = e; + } + + // still not resolved, report error + if (_module == null) { + _data.getReport().addDependency(this); + return false; + } else { + loaded = true; + if (!getId().isExactRevision()) { + Message.info("\t["+_module.getId().getRevision()+"] "+getId()); + } + _md = _module.getDescriptor(); + // if the revision was a latest one (which has now be resolved) + // store also it to cache the result + if (!getId().isExactRevision()) { + _data.register(_module.getId(), this); + } + _confsToFetch.remove("*"); + updateConfsToFetch(Arrays.asList(resolveSpecialConfigurations(getRequiredConfigurations(getParent(), getParentConf()), this))); + } + } + } + if (hasProblem()) { + _data.getReport().addDependency(this); + return loaded; + } + if ("*".equals(conf)) { + if (_md != null) { + _fetchedConfigurations.addAll(Arrays.asList(_md.getConfigurationsNames())); + _confsToFetch.clear(); + addRootModuleConfigurations(_rootModuleConf, _md.getConfigurationsNames()); + } + } else { + if (loaded) { + _fetchedConfigurations.add(conf); + _confsToFetch.remove(conf); + } + addRootModuleConfigurations(_rootModuleConf, new String[] {conf}); + } + if (_dd != null) { + addDependencyArtifactsIncludes(_rootModuleConf, _dd.getDependencyArtifactsIncludes(getParentConf())); + addDependencyArtifactsExcludes(_rootModuleConf, _dd.getDependencyArtifactsExcludes(getParentConf())); + } + return loaded; + + } + + public IvyNode getRealNode() { + IvyNode node = _data.getNode(getId()); + return node == null ? this : node; + } + + public Collection getDependencies(String[] confs) { + if (_md == null) { + throw new IllegalStateException("impossible to get dependencies when data has not been loaded"); + } + if (Arrays.asList(confs).contains("*")) { + confs = _md.getConfigurationsNames(); + } + Collection deps = new HashSet(); + for (int i = 0; i < confs.length; i++) { + deps.addAll(getDependencies(confs[i], false)); + } + return deps; + } + + public Collection getDependencies(String conf, boolean traverse) { + if (_md == null) { + throw new IllegalStateException("impossible to get dependencies when data has not been loaded"); + } + DependencyDescriptor[] dds = _md.getDependencies(); + Collection dependencies = new LinkedHashSet(); // it's important to respect dependencies order + for (int i = 0; i < dds.length; i++) { + DependencyDescriptor dd = dds[i]; + String[] dependencyConfigurations = dd.getDependencyConfigurations(conf); + if (dependencyConfigurations.length == 0) { + // no configuration of the dependency is required for current confs : + // it is exactly the same as if there was no dependency at all on it + continue; + } + IvyNode depNode = _data.getNode(dd.getDependencyRevisionId()); + if (depNode == null) { + depNode = new IvyNode(_data, dd); + } else if (depNode.hasProblem()) { + // dependency already tried to be resolved, but unsuccessfully + // nothing special to do + + } + Collection confs = Arrays.asList(resolveSpecialConfigurations(dependencyConfigurations, depNode)); + depNode.updateConfsToFetch(confs); + depNode.setRequiredConfs(this, conf, confs); + + depNode.addCaller(_rootModuleConf, _md.getModuleRevisionId(), conf, dependencyConfigurations, dd.getDependencyRevisionId()); + dependencies.add(depNode); + + if (traverse) { + depNode.setParent(this); + depNode.setParentConf(conf); + depNode.setRootModuleConf(getRootModuleConf()); + depNode._data = _data; + } + } + return dependencies; + } + + public ModuleRevisionId getId() { + return _id; + } + + public void updateConfsToFetch(Collection confs) { + _confsToFetch.addAll(confs); + _confsToFetch.removeAll(_fetchedConfigurations); + } + + public ModuleId getModuleId() { + return _id.getModuleId(); + } + + /** + * resolve the '*' special configurations if necessary and possible + */ + private String[] resolveSpecialConfigurations(String[] dependencyConfigurations, IvyNode node) { + if (dependencyConfigurations.length == 1 + && "*".equals(dependencyConfigurations[0]) + && node != null + && node.isLoaded()) { + return node.getDescriptor().getConfigurationsNames(); + } + return dependencyConfigurations; + } + + public boolean isLoaded() { + return _md != null; + } + + public ModuleDescriptor getDescriptor() { + return _md; + } + + /** + * returns the required configurations from the given node + * @param in + * @return + */ + public String[] getRequiredConfigurations(IvyNode in, String inConf) { + Collection req = (Collection)_requiredConfs.get(new NodeConf(in, inConf)); + return req == null?new String[0]:(String[])req.toArray(new String[req.size()]); + } + + /** + * returns all the current required configurations of the node + * @return + */ + public String[] getRequiredConfigurations() { + Collection required = new ArrayList(_confsToFetch.size() + _fetchedConfigurations.size()); + required.addAll(_fetchedConfigurations); + required.addAll(_confsToFetch); + return (String[])required.toArray(new String[required.size()]); + } + + private void setRequiredConfs(IvyNode parent, String parentConf, Collection confs) { + _requiredConfs.put(new NodeConf(parent, parentConf), new HashSet(confs)); + } + + public Configuration getConfiguration(String conf) { + if (_md == null) { + throw new IllegalStateException("impossible to get configuration when data has not been loaded"); + } + return _md.getConfiguration(conf); + } + + public ResolvedModuleRevision getModuleRevision() { + return _module; + } + + + /** + * + * @param rootModuleConf + * @param mrid + * @param callerConf + * @param dependencyConfs '*' must have been resolved + * @param askedDependencyId the dependency revision id asked by the caller + */ + public void addCaller(String rootModuleConf, ModuleRevisionId mrid, String callerConf, String[] dependencyConfs, ModuleRevisionId askedDependencyId) { + Map callers = (Map)_callersByRootConf.get(rootModuleConf); + if (callers == null) { + callers = new HashMap(); + _callersByRootConf.put(rootModuleConf, callers); + } + Caller caller = (Caller)callers.get(mrid); + if (caller == null) { + caller = new Caller(mrid, askedDependencyId); + callers.put(mrid, caller); + } + caller.addConfiguration(callerConf, dependencyConfs); + } + public Caller[] getCallers(String rootModuleConf) { + Map callers = (Map)_callersByRootConf.get(rootModuleConf); + if (callers == null) { + return new Caller[0]; + } + return (Caller[])callers.values().toArray(new Caller[callers.values().size()]); + } + + public String toString() { + return getResolvedId().toString(); + } + + public boolean equals(Object obj) { + if (! (obj instanceof IvyNode)) { + return false; + } + IvyNode node = (IvyNode)obj; + return node.getId().equals(getId()); + } + + public int hashCode() { + return getId().hashCode(); + } + + /** + * Returns the configurations of the dependency required in a given + * root module configuration. + * @param rootModuleConf + * @return + */ + public String[] getConfigurations(String rootModuleConf) { + Set depConfs = (Set) _rootModuleConfs.get(rootModuleConf); + if (depConfs == null) { + return new String[0]; + } + return (String[]) depConfs.toArray(new String[depConfs.size()]); + } + + private void addRootModuleConfigurations(String rootModuleConf, String[] dependencyConfs) { + Set depConfs = (Set) _rootModuleConfs.get(rootModuleConf); + if (depConfs == null) { + depConfs = new HashSet(); + _rootModuleConfs.put(rootModuleConf, depConfs); + } + if (_md != null) { + // add all given dependency configurations to the set + extended ones + for (int i = 0; i < dependencyConfs.length; i++) { + Configuration conf = _md.getConfiguration(dependencyConfs[i]); + if (conf != null) { + String[] exts = conf.getExtends(); + addRootModuleConfigurations(rootModuleConf, exts); // recursive add of extended configurations + depConfs.add(conf.getName()); + } else { + Message.warn("unknown configuration in "+getId()+": "+dependencyConfs[i]); + } + } + } else { + for (int i = 0; i < dependencyConfs.length; i++) { + depConfs.add(dependencyConfs[i]); + } + } + } + + /** + * Returns the root module configurations in which this dependency is required + * @return + */ + public String[] getRootModuleConfigurations() { + return (String[])_rootModuleConfs.keySet().toArray(new String[_rootModuleConfs.size()]); + } + + /** + * Returns all the artifacts of this dependency required in all the + * root module configurations + * @return + */ + public Artifact[] getAllArtifacts() { + Set ret = new HashSet(); + for (Iterator it = _rootModuleConfs.keySet().iterator(); it.hasNext();) { + String rootModuleConf = (String)it.next(); + ret.addAll(Arrays.asList(getArtifacts(rootModuleConf))); + } + return (Artifact[])ret.toArray(new Artifact[ret.size()]); + } + + /** + * Returns all the artifacts of this dependency required in the + * root module configurations in which the node is not evicted + * @return + */ + public Artifact[] getSelectedArtifacts() { + Set ret = new HashSet(); + for (Iterator it = _rootModuleConfs.keySet().iterator(); it.hasNext();) { + String rootModuleConf = (String)it.next(); + if (!isEvicted(rootModuleConf)) { + ret.addAll(Arrays.asList(getArtifacts(rootModuleConf))); + } + } + return (Artifact[])ret.toArray(new Artifact[ret.size()]); + } + + /** + * Returns the artifacts of this dependency required in the + * configurations themselves required in the given root module configuration + * @param rootModuleConf + * @return + */ + public Artifact[] getArtifacts(String rootModuleConf) { + // first we look for the dependency configurations required + // in the given root module configuration + Set confs = (Set) _rootModuleConfs.get(rootModuleConf); + if (confs == null) { + // no configuration required => no artifact required + return new Artifact[0]; + } + + Set artifacts = new HashSet(); // the set we fill before returning + + // we check if we have dependencyArtifacts includes description for this rootModuleConf + Set includes = (Set)_dependencyArtifactsIncludes.get(rootModuleConf); + + if (_md.isDefault() && includes != null && !includes.isEmpty()) { + // the descriptor is a default one: it has been generated from nothing + // moreover, we have dependency artifacts description + // these descritions are thus used as if they were declared in the module + // descriptor. If one is not really present, the error will be raised + // at download time + for (Iterator it = includes.iterator(); it.hasNext();) { + DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)it.next(); + artifacts.add(new MDArtifact(_md, dad.getName(), dad.getType(), dad.getExt())); + } + } else { + if (includes == null || includes.isEmpty()) { + // no artifacts includes: we get all artifacts as defined by the descriptor + for (Iterator iter = confs.iterator(); iter.hasNext();) { + String conf = (String) iter.next(); + artifacts.addAll(Arrays.asList(_md.getArtifacts(conf))); + } + } else { + // we have to get only artifacts listed as "includes" + + // first we get all artifacts as defined by the module descriptor + // and classify them by artifact id + Map allArtifacts = new HashMap(); + for (Iterator iter = confs.iterator(); iter.hasNext();) { + String conf = (String) iter.next(); + Artifact[] arts = _md.getArtifacts(conf); + for (int i = 0; i < arts.length; i++) { + allArtifacts.put(arts[i].getId().getArtifactId(), arts[i]); + } + } + + // now we can keep only listed ones + for (Iterator it = includes.iterator(); it.hasNext();) { + DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)it.next(); + Collection arts = findArtifactsMatching(dad.getId(), allArtifacts); + if (arts.isEmpty()) { + Message.error("a required artifact is not listed by module descriptor: "+dad.getId()); + // we remove it from required list to prevent message to be displayed more than once + it.remove(); + } else { + Message.debug(this+" in "+rootModuleConf+": including "+arts); + artifacts.addAll(arts); + } + } + } + } + + // now excludes artifacts in the exclude list + Set excludes = (Set)_dependencyArtifactsExcludes.get(rootModuleConf); + if (excludes != null) { + for (Iterator it = excludes.iterator(); it.hasNext();) { + DependencyArtifactDescriptor dad = (DependencyArtifactDescriptor)it.next(); + for (Iterator iter = artifacts.iterator(); iter.hasNext();) { + Artifact artifact = (Artifact)iter.next(); + if (artifactIdMatch(dad.getId(), artifact.getId().getArtifactId())) { + Message.debug(this+" in "+rootModuleConf+": excluding "+artifact); + iter.remove(); + } + } + } + } + return (Artifact[]) artifacts.toArray(new Artifact[artifacts.size()]); + } + + private Collection findArtifactsMatching(ArtifactId id, Map allArtifacts) { + Artifact art = (Artifact)allArtifacts.get(id); + if (art != null) { + return Collections.singleton(art); + } + Collection ret = new ArrayList(); + for (Iterator iter = allArtifacts.keySet().iterator(); iter.hasNext();) { + ArtifactId aid = (ArtifactId)iter.next(); + if (artifactIdMatch(id, aid)) { + ret.add(allArtifacts.get(aid)); + } + } + return ret; + } + + + private boolean artifactIdMatch(ArtifactId id, ArtifactId aid) { + if (aid.equals(id)) { + return true; + } + return stringMatch(id.getModuleId().getOrganisation(), aid.getModuleId().getOrganisation()) + && stringMatch(id.getModuleId().getName(), aid.getModuleId().getName()) + && stringMatch(id.getName(), aid.getName()) + && stringMatch(id.getExt(), aid.getExt()) + && stringMatch(id.getType(), aid.getType()) + ; + } + + private boolean stringMatch(String pattern, String test) { + if (test.equals(pattern)) { + return true; + } + return Pattern.matches(pattern, test); + } + + private void addDependencyArtifactsIncludes(String rootModuleConf, DependencyArtifactDescriptor[] dependencyArtifacts) { + addDependencyArtifacts(rootModuleConf, dependencyArtifacts, _dependencyArtifactsIncludes); + } + + private void addDependencyArtifactsExcludes(String rootModuleConf, DependencyArtifactDescriptor[] dependencyArtifacts) { + addDependencyArtifacts(rootModuleConf, dependencyArtifacts, _dependencyArtifactsExcludes); + } + + private void addDependencyArtifacts(String rootModuleConf, DependencyArtifactDescriptor[] dependencyArtifacts, Map artifactsMap) { + Set depArtifacts = (Set) artifactsMap.get(rootModuleConf); + if (depArtifacts == null) { + depArtifacts = new HashSet(); + artifactsMap.put(rootModuleConf, depArtifacts); + } + depArtifacts.addAll(Arrays.asList(dependencyArtifacts)); + } + + public long getPublication() { + if (_module != null) { + return _module.getPublicationDate().getTime(); + } + return 0; + } + + public DependencyDescriptor getDependencyDescriptor() { + return _dd; + } + + public boolean hasProblem() { + return _problem != null; + } + + public ModuleRevisionId getResolvedId() { + if (_md != null && _md.getResolvedModuleRevisionId().getRevision() != null) { + return _md.getResolvedModuleRevisionId(); + } else if (_module != null) { + return _module.getId(); + } else { + return getId(); + } + } + + public Exception getProblem() { + return _problem; + } + + public boolean isDownloaded() { + return _downloaded; + } + + public boolean isSearched() { + return _searched; + } + + public String getRootModuleConf() { + return _rootModuleConf; + } + + + public void setRootModuleConf(String rootModuleConf) { + if (rootModuleConf != null && rootModuleConf.equals(_rootModuleConf)) { + _selected.put(new ModuleIdConf(_id.getModuleId(), rootModuleConf), Collections.singleton(this)); + } + _rootModuleConf = rootModuleConf; + } + + public String[] getConfsToFetch() { + return (String[])_confsToFetch.toArray(new String[_confsToFetch.size()]); + } + + /** + * Returns true if this node can already be found among its callers + * @return + */ + public boolean isCircular() { + return isCircular(this); + } + + private boolean isCircular(IvyNode node) { + boolean isCircular = false; + IvyNode.Caller[] callers = node.getCallers(getRootModuleConf()); + for (int i = 0; i < callers.length && !isCircular; i++) { + ModuleRevisionId mrid = callers[i].getModuleRevisionId(); + if (getId().equals(mrid)) { + return true; + } + IvyNode parent = _data.getNode(mrid); + if (parent != null) { + isCircular = isCircular(parent); + } + } + return isCircular; + } +} diff --git a/src/java/fr/jayasoft/ivy/LatestStrategy.java b/src/java/fr/jayasoft/ivy/LatestStrategy.java new file mode 100644 index 00000000..465beed4 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/LatestStrategy.java @@ -0,0 +1,24 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + + +public interface LatestStrategy { + /** + * Finds the latest artifact among the given artifacts info. + * The definition of 'latest' depends on the strategy itself. + * Given artifacts info are all good candidate. If the given date is not + * null, then found artifact should not be later than this date. + * + * @param infos + * @param date + * @return the latest artifact among the given ones. + */ + ArtifactInfo findLatest(ArtifactInfo[] infos, Date date); + String getName(); +} diff --git a/src/java/fr/jayasoft/ivy/License.java b/src/java/fr/jayasoft/ivy/License.java new file mode 100644 index 00000000..77fdd196 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/License.java @@ -0,0 +1,24 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +public class License { + private String _name; + private String _url; + public License(String name, String url) { + _name = name; + _url = url; + } + + public String getName() { + return _name; + } + + public String getUrl() { + return _url; + } + +} diff --git a/src/java/fr/jayasoft/ivy/MDArtifact.java b/src/java/fr/jayasoft/ivy/MDArtifact.java new file mode 100644 index 00000000..33c69a25 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/MDArtifact.java @@ -0,0 +1,77 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @author x.hanin + * + */ +public class MDArtifact extends AbstractArtifact { + private ModuleDescriptor _md; + private String _name; + private String _type; + private String _ext; + private List _confs = new ArrayList(); + private ArtifactRevisionId _arid; + + public MDArtifact(ModuleDescriptor md, String name, String type, String ext) { + if (md == null) { + throw new NullPointerException("null module descriptor not allowed"); + } + if (name == null) { + throw new NullPointerException("null name not allowed"); + } + if (type == null) { + throw new NullPointerException("null type not allowed"); + } + if (ext == null) { + throw new NullPointerException("null ext not allowed"); + } + _md = md; + _name = name; + _type = type; + _ext = ext; + } + + public ModuleRevisionId getModuleRevisionId() { + return _md.getResolvedModuleRevisionId(); + } + + public Date getPublicationDate() { + return _md.getResolvedPublicationDate(); + } + public ArtifactRevisionId getId() { + if (_arid == null) { + _arid = ArtifactRevisionId.newInstance(_md.getResolvedModuleRevisionId(), _name, _type, _ext); + } + return _arid; + } + + public String getName() { + return _name; + } + + public String getType() { + return _type; + } + + public String getExt() { + return _ext; + } + + public String[] getConfigurations() { + return (String[])_confs.toArray(new String[_confs.size()]); + } + + public void addConfiguration(String conf) { + _confs.add(conf); + } + +} diff --git a/src/java/fr/jayasoft/ivy/Main.java b/src/java/fr/jayasoft/ivy/Main.java new file mode 100644 index 00000000..acddc170 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/Main.java @@ -0,0 +1,203 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; +import java.util.Date; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +import fr.jayasoft.ivy.util.DefaultMessageImpl; +import fr.jayasoft.ivy.util.Message; + +/** + * class used to launch ivy as a standalone tool + * arguments are : + * -conf : indicates the path to the ivy configuration file + * ivyconf.xml is assumed if not given + * -cache : indicates the path to the cache directory + * cache is assumed if not given + * -ivy : indicates the path to the ivy file to use + * ivy.xml is assumed if not given + * -retrieve : when used, retrieve is also done using the given retrievepattern + * -revision : the revision with which the module should be published, required to publish + * -status : the status with which the module should be published, + * release is assumed if not given + * -publish : the pattern used to publish the resolved ivy file, + * ivy-[revision].xml is assumed if not given + */ +public class Main { + private static Options getOptions() { + Option conf = OptionBuilder.withArgName( "conffile" ) + .hasArg() + .withDescription( "use given file for configuration" ) + .create( "conf" ); + Option cache = OptionBuilder.withArgName( "cachedir" ) + .hasArg() + .withDescription( "use given directory for cache" ) + .create( "cache" ); + Option ivyfile = OptionBuilder.withArgName( "ivyfile" ) + .hasArg() + .withDescription( "use given file as ivy file" ) + .create( "ivy" ); + Option confs = OptionBuilder.withArgName( "configurations" ) + .hasArgs() + .withDescription( "resolve given configurations" ) + .create( "confs" ); + Option retrieve = OptionBuilder.withArgName( "retrievepattern" ) + .hasArg() + .withDescription( "use given pattern as retrieve pattern" ) + .create( "retrieve" ); + Option revision = OptionBuilder.withArgName( "revision" ) + .hasArg() + .withDescription( "use given revision to publish the module" ) + .create( "revision" ); + Option status = OptionBuilder.withArgName( "status" ) + .hasArg() + .withDescription( "use given status to publish the module" ) + .create( "status" ); + Option publish = OptionBuilder.withArgName( "publishpattern" ) + .hasArg() + .withDescription( "use given pattern as resolved ivy file pattern" ) + .create( "publish" ); + + Options options = new Options(); + + options.addOption("debug", false, "set message level to debug"); + options.addOption("verbose", false, "set message level to verbose"); + options.addOption("warn", false, "set message level to warn"); + options.addOption("error", false, "set message level to error"); + options.addOption("novalidate", false, "do not validate ivy files against xsd"); + options.addOption("?", false, "display this help"); + options.addOption(conf); + options.addOption(confs); + options.addOption(cache); + options.addOption(ivyfile); + options.addOption(retrieve); + options.addOption(revision); + options.addOption(status); + options.addOption(publish); + + return options; + } + public static void main(String[] args) throws Exception { + Options options = getOptions(); + + CommandLineParser parser = new GnuParser(); + try { + // parse the command line arguments + CommandLine line = parser.parse( options, args ); + + if (line.hasOption("?")) { + usage(options); + return; + } + + if (line.hasOption("debug")) { + Message.init(new DefaultMessageImpl(Message.MSG_DEBUG)); + } else if (line.hasOption("verbose")) { + Message.init(new DefaultMessageImpl(Message.MSG_VERBOSE)); + } else if (line.hasOption("warn")) { + Message.init(new DefaultMessageImpl(Message.MSG_WARN)); + } else if (line.hasOption("error")) { + Message.init(new DefaultMessageImpl(Message.MSG_ERR)); + } else { + Message.init(new DefaultMessageImpl(Message.MSG_INFO)); + } + + boolean validate = line.hasOption("novalidate")?false:true; + + Ivy ivy = new Ivy(); + + String confPath = line.getOptionValue("conf", ""); + if ("".equals(confPath)) { + ivy.configure(Ivy.class.getResource("ivyconf.xml")); + } else { + File conffile = new File(confPath); + if (!conffile.exists()) { + error(options, "ivy configuration file not found: "+conffile); + } else if (conffile.isDirectory()) { + error(options, "ivy configuration file is not a file: "+conffile); + } + ivy.configure(conffile); + } + + File cache = new File(ivy.substitute(line.getOptionValue("cache", "cache"))); + if (!cache.exists()) { + cache.mkdirs(); + } else if (!cache.isDirectory()) { + error(options, cache+" is not a directory"); + } + File ivyfile = new File(ivy.substitute(line.getOptionValue("ivy", "ivy.xml"))); + if (!ivyfile.exists()) { + error(options, "ivy file not found: "+ivyfile); + } else if (ivyfile.isDirectory()) { + error(options, "ivy file is not a file: "+ivyfile); + } + String[] confs; + if (line.hasOption("confs")) { + confs = line.getOptionValues("confs"); + } else { + confs = new String[] {"*"}; + } + + Date date = new Date(); + + ModuleDescriptor md = ivy.resolve( + ivyfile.toURL(), + null, + confs, + cache, + date, + validate).getModuleDescriptor(); + + if (line.hasOption("retrieve")) { + String retrievePattern = ivy.substitute(line.getOptionValue("retrieve")); + if (retrievePattern.indexOf("[") == -1) { + retrievePattern = retrievePattern + "/lib/[conf]/[artifact].[type]"; + } + ivy.retrieve(md.getModuleRevisionId().getModuleId(), confs, cache, retrievePattern); + } + + if (line.hasOption("revision")) { + ivy.deliver( + md.getResolvedModuleRevisionId(), + ivy.substitute(line.getOptionValue("revision")), + cache, + ivy.substitute(line.getOptionValue("publish", "ivy-[revision].xml")), + ivy.substitute(line.getOptionValue("status", "release")), + date, + new DefaultPublishingDRResolver(), + validate); + } + } catch( ParseException exp ) { + // oops, something went wrong + System.err.println( "Parsing failed. Reason: " + exp.getMessage() ); + + usage(options); + } + } + + private static void error(Options options, String msg) { + System.err.println(msg); + usage(options); + System.exit(1); + } + + private static void usage(Options options) { + // automatically generate the help statement + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp( "ivy", options ); + } + +} diff --git a/src/java/fr/jayasoft/ivy/ModuleDescriptor.java b/src/java/fr/jayasoft/ivy/ModuleDescriptor.java new file mode 100644 index 00000000..8f084302 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ModuleDescriptor.java @@ -0,0 +1,99 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + +/** + * @author x.hanin + * + */ +public interface ModuleDescriptor { + public static final String DEFAULT_CONFIGURATION = "default"; + /** + * Returns true if this descriptor is a default one, i.e. + * one generated for a module not actually having one. + * @return + */ + boolean isDefault(); + ModuleRevisionId getModuleRevisionId(); + /** + * The module revision id returned here is the resolved one, + * i.e. it is never a latest one. If the revision has not been + * resolved, a null revision should be returned by getRevision() + * of the returned ModuleRevisionId. + * This revision must be the same as the module descriptor resolved + * revision id unless no module descriptor is defined + * @return + */ + ModuleRevisionId getResolvedModuleRevisionId(); + /** + * This method update the resolved module revision id + * @param revId + */ + void setResolvedModuleRevisionId(ModuleRevisionId revId); + /** + * This method update the resolved publication date + * @param publicationDate + */ + void setResolvedPublicationDate(Date publicationDate); + + String getResolverName(); + void setResolverName(String resolverName); + + String getStatus(); + /** + * may be null if unknown in the descriptor itself + * @return + */ + Date getPublicationDate(); + /** + * the publication date of the module revision should be the date at which it has been published, + * i.e. in general the date of any of its published artifacts, since all published artifact + * of a module should follow the same publishing cycle. + */ + Date getResolvedPublicationDate(); + /** + * Returns all the configurations declared by this module as an array. + * This array is never empty (a 'default' conf is assumed when none is declared + * in the ivy file) + * @return all the configurations declared by this module as an array. + */ + Configuration[] getConfigurations(); + String[] getConfigurationsNames(); + Artifact[] getArtifacts(String conf); + DependencyDescriptor[] getDependencies(); + + /** + * Returns true if the module described by this descriptor dependes directly upon the + * given module descriptor + * @param md + * @return + */ + boolean dependsOn(ModuleDescriptor md); + /** + * @param confName + * @return + */ + Configuration getConfiguration(String confName); + + /** + * Returns the conflict manager to use for the given ModuleId + * + * @param id + * @return + */ + ConflictManager getConflictManager(ModuleId id); + + /** + * Returns the licenses of the module described by this descriptor + * @return + */ + License[] getLicenses(); + + String getHomePage(); + long getLastModified(); +} diff --git a/src/java/fr/jayasoft/ivy/ModuleId.java b/src/java/fr/jayasoft/ivy/ModuleId.java new file mode 100644 index 00000000..7b201c0b --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ModuleId.java @@ -0,0 +1,48 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + + +/** + * @author x.hanin + * + */ +public class ModuleId { + private String _organisation; + private String _name; + + public ModuleId(String organisation, String name) { + if (name == null) { + throw new IllegalArgumentException("null name not allowed"); + } + _organisation = organisation; + _name = name; + } + + public String getName() { + return _name; + } + public String getOrganisation() { + return _organisation; + } + + public boolean equals(Object obj) { + if (! (obj instanceof ModuleId)) { + return false; + } + ModuleId other = (ModuleId)obj; + return other._organisation.equals(_organisation) && other._name.equals(_name); + } + public int hashCode() { + int hash = 31; + hash = hash * 13 + _organisation.hashCode(); + hash = hash * 13 + _name.hashCode(); + return hash; + } + public String toString() { + return _organisation+"/"+_name; + } +} diff --git a/src/java/fr/jayasoft/ivy/ModuleRevisionId.java b/src/java/fr/jayasoft/ivy/ModuleRevisionId.java new file mode 100644 index 00000000..10ad854e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ModuleRevisionId.java @@ -0,0 +1,81 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + + +/** + * @author x.hanin + * + */ +public class ModuleRevisionId { + public static ModuleRevisionId newInstance(String organisation, String name, String revision) { + return new ModuleRevisionId(new ModuleId(organisation, name), revision); + } + + private ModuleId _moduleId; + private String _revision; + + public ModuleRevisionId(ModuleId moduleId, String revision) { + _moduleId = moduleId; + _revision = revision; + } + public ModuleId getModuleId() { + return _moduleId; + } + public String getName() { + return getModuleId().getName(); + } + public String getOrganisation() { + return getModuleId().getOrganisation(); + } + public String getRevision() { + return _revision; + } + + public boolean equals(Object obj) { + if (! (obj instanceof ModuleRevisionId)) { + return false; + } + ModuleRevisionId other = (ModuleRevisionId)obj; + return (other.getRevision() == null ? getRevision() == null : other.getRevision().equals(getRevision())) + && other.getModuleId().equals(getModuleId()); + } + public int hashCode() { + int hash = 31; + hash = hash * 13 + (getRevision() == null ? 0 : getRevision().hashCode()); + hash = hash * 13 + getModuleId().hashCode(); + return hash; + } + + public String toString() { + return _moduleId+"-"+_revision; + } + /** + * Returns true if the given revision can be considered as a revision of this module revision id. + * This is the case if the revision is equal to the current revision, or if the + * current revision is a 'latest.' one, or if it is a xx+ one matching the given one. + * @param revision + * @return true if the given revision can be considered as a revision of this module revision id. + */ + public boolean acceptRevision(String revision) { + if (_revision.equals(revision)) { + return true; + } + if (_revision.startsWith("latest.")) { + return true; + } + if (_revision.endsWith("+") && revision.startsWith(_revision.substring(0, _revision.length() - 1))) { + return true; + } + return false; + } + /** + * @return true if the revision is an exact one, i.e. not a 'latest.' nor a xx+ one. + */ + public boolean isExactRevision() { + return !_revision.startsWith("latest.") && !_revision.endsWith("+"); + } +} diff --git a/src/java/fr/jayasoft/ivy/PublishingDependencyRevisionResolver.java b/src/java/fr/jayasoft/ivy/PublishingDependencyRevisionResolver.java new file mode 100644 index 00000000..7815f626 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/PublishingDependencyRevisionResolver.java @@ -0,0 +1,24 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +/** + * @author Xavier Hanin + * + */ +public interface PublishingDependencyRevisionResolver { + + /** + * Returns the revision of the dependency for the publishing of the 'published' module + * in 'publishedStatus' status. + * @param published + * @param publishedStatus + * @param dependency + * @return the revision of the dependency + */ + String resolve(ModuleDescriptor published, String publishedStatus, ModuleDescriptor dependency); + +} diff --git a/src/java/fr/jayasoft/ivy/ResolveData.java b/src/java/fr/jayasoft/ivy/ResolveData.java new file mode 100644 index 00000000..829b8ab3 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ResolveData.java @@ -0,0 +1,83 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import fr.jayasoft.ivy.report.ConfigurationResolveReport; + +public class ResolveData { + private Map _nodes; // shared map of all nodes: Map (ModuleRevisionId -> IvyNode) + private Ivy _ivy; + private File _cache; + private Date _date; + private boolean _validate; + private ConfigurationResolveReport _report; + + public ResolveData(ResolveData data, boolean validate) { + this(data._ivy, data._cache, data._date, data._report, validate, data._nodes); + } + + public ResolveData(Ivy ivy, File cache, Date date, ConfigurationResolveReport report, boolean validate) { + this(ivy, cache, date, report, validate, new HashMap()); + } + + public ResolveData(Ivy ivy, File cache, Date date, ConfigurationResolveReport report, boolean validate, Map nodes) { + _ivy = ivy; + _cache = cache; + _date = date; + _report = report; + _validate = validate; + _nodes = nodes; + } + + public File getCache() { + return _cache; + } + + + public Date getDate() { + return _date; + } + + + public Ivy getIvy() { + return _ivy; + } + + + public Map getNodes() { + return _nodes; + } + + + public ConfigurationResolveReport getReport() { + return _report; + } + + + public boolean isValidate() { + return _validate; + } + + public IvyNode getNode(ModuleRevisionId mrid) { + return (IvyNode)_nodes.get(mrid); + } + + public void register(IvyNode node) { + _nodes.put(node.getId(), node); + } + + public void register(ModuleRevisionId id, IvyNode node) { + _nodes.put(id, node); + } + + + +} diff --git a/src/java/fr/jayasoft/ivy/ResolvedModuleRevision.java b/src/java/fr/jayasoft/ivy/ResolvedModuleRevision.java new file mode 100644 index 00000000..5b6c0954 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ResolvedModuleRevision.java @@ -0,0 +1,21 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.Date; + +/** + * @author x.hanin + * + */ +public interface ResolvedModuleRevision { + DependencyResolver getResolver(); + ModuleRevisionId getId(); + Date getPublicationDate(); + ModuleDescriptor getDescriptor(); + boolean isDownloaded(); + boolean isSearched(); +} diff --git a/src/java/fr/jayasoft/ivy/ResolvedURL.java b/src/java/fr/jayasoft/ivy/ResolvedURL.java new file mode 100644 index 00000000..5c435da9 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ResolvedURL.java @@ -0,0 +1,48 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +import fr.jayasoft.ivy.util.Message; + +public class ResolvedURL implements ArtifactInfo { + URL url; + String revision; + private Long _lastModified; + + public ResolvedURL(URL url, String revision) { + this.url = url; + this.revision = revision; + } + + public String toString() { + return url + "(" + revision + ")"; + } + + public String getRevision() { + return revision; + } + + public long getLastModified() { + if (_lastModified == null) { + try { + URLConnection con = url.openConnection(); + _lastModified = new Long(con.getLastModified()); + } catch (IOException e) { + Message.warn("impossible to open connection to "+url+": "+e.getMessage()); + _lastModified = new Long(0); + } + } + return _lastModified.longValue(); + } + + public URL getURL() { + return url; + } +} diff --git a/src/java/fr/jayasoft/ivy/Status.java b/src/java/fr/jayasoft/ivy/Status.java new file mode 100644 index 00000000..2f3be4c5 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/Status.java @@ -0,0 +1,52 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author x.hanin + * + */ +public class Status { + public static final String DEFAULT_STATUS = "integration"; + private static final String[] STATUSES = new String[] {"release", "milestone", "integration"}; + private static final boolean[] IS_INTEGRATION = new boolean[] {false, false, true}; + private static Map _statusPriorityMap; + private static Map _statusIntegrationMap; + static { + _statusPriorityMap = new HashMap(); + for (int i = 0; i < STATUSES.length; i++) { + _statusPriorityMap.put(STATUSES[i], new Integer(i)); + } + _statusIntegrationMap = new HashMap(); + for (int i = 0; i < IS_INTEGRATION.length; i++) { + _statusIntegrationMap.put(STATUSES[i], new Boolean(IS_INTEGRATION[i])); + } + } + + public static int getPriority(String status) { + Integer priority = (Integer)_statusPriorityMap.get(status); + if (priority == null) { + throw new IllegalArgumentException("unknown status "+status); + } + return priority.intValue(); + } + + public static boolean isIntegration(String status) { + Boolean isIntegration = (Boolean)_statusIntegrationMap.get(status); + if (isIntegration == null) { + throw new IllegalArgumentException("unknown status "+status); + } + return isIntegration.booleanValue(); + } + + public static String getDeliveryStatusListString() { + // TODO : use constants + return "milestone,release"; + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/AntMessageImpl.java b/src/java/fr/jayasoft/ivy/ant/AntMessageImpl.java new file mode 100644 index 00000000..a7e6283d --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/AntMessageImpl.java @@ -0,0 +1,50 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import org.apache.tools.ant.Project; + +import fr.jayasoft.ivy.util.MessageImpl; + +public class AntMessageImpl implements MessageImpl { + private Project _project; + + private static long _lastProgressFlush = 0; + private static StringBuffer _buf = new StringBuffer(); + + /** + * @param project + */ + public AntMessageImpl(Project project) { + _project = project; + } + + public void log(String msg, int level) { + _project.log(msg, level); + } + + public void progress() { + _buf.append("."); + if (_lastProgressFlush == 0) { + _lastProgressFlush = System.currentTimeMillis(); + } + if (_project != null) { + // log with ant causes a new line -> we do it only once in a while + if (System.currentTimeMillis() - _lastProgressFlush > 1500) { + _project.log(_buf.toString()); + _buf.setLength(0); + _lastProgressFlush = System.currentTimeMillis(); + } + } + } + + public void endProgress(String msg) { + _project.log(_buf + msg); + _buf.setLength(0); + _lastProgressFlush = 0; + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyArtifactProperty.java b/src/java/fr/jayasoft/ivy/ant/IvyArtifactProperty.java new file mode 100644 index 00000000..250b51d1 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyArtifactProperty.java @@ -0,0 +1,110 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; + +import org.apache.tools.ant.BuildException; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.xml.XmlReportParser; + +public class IvyArtifactProperty extends IvyTask { + private String _conf; + private String _name; + private String _value; + + private String _organisation; + private String _module; + private boolean _haltOnFailure = true; + private File _cache; + + public String getConf() { + return _conf; + } + public void setConf(String conf) { + _conf = conf; + } + public String getName() { + return _name; + } + public void setName(String name) { + _name = name; + } + public String getValue() { + return _value; + } + public void setValue(String value) { + _value = value; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public boolean isHaltonfailure() { + return _haltOnFailure; + } + public void setHaltonfailure(boolean haltOnFailure) { + _haltOnFailure = haltOnFailure; + } + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + ensureResolved(isHaltonfailure()); + _conf = getProperty(_conf, ivy, "ivy.resolved.configurations"); + if (_conf.equals("*")) { + _conf = getProperty(ivy, "ivy.resolved.configurations"); + } + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + + if (_organisation == null || _module == null) { + throw new BuildException("no module id provided for ivy artifact property: either call resolve, give paramaters to ivy:retrieve, or provide ivy.module and ivy.organisation properties"); + } + try { + XmlReportParser parser = new XmlReportParser(); + String[] confs = splitConfs(_conf); + Collection all = new HashSet(); + for (int i = 0; i < confs.length; i++) { + Artifact[] artifacts = parser.getArtifacts(new ModuleId(_organisation, _module), confs[i], _cache); + all.addAll(Arrays.asList(artifacts)); + } + for (Iterator iter = all.iterator(); iter.hasNext();) { + Artifact artifact = (Artifact)iter.next(); + String name = IvyPatternHelper.substitute(ivy.substitute(getName()), artifact); + String value = IvyPatternHelper.substitute(ivy.substitute(getValue()), artifact); + getProject().setProperty(name, value); + } + } catch (Exception ex) { + throw new BuildException("impossible to add artifact properties: "+ex.getMessage(), ex); + } + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyCachePath.java b/src/java/fr/jayasoft/ivy/ant/IvyCachePath.java new file mode 100644 index 00000000..09cc8b23 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyCachePath.java @@ -0,0 +1,116 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Path; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.xml.XmlReportParser; + +public class IvyCachePath extends IvyTask { + private String _conf; + private String _pathid; + + private String _organisation; + private String _module; + private boolean _haltOnFailure = true; + private File _cache; + + public String getConf() { + return _conf; + } + + public void setConf(String conf) { + _conf = conf; + } + + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public boolean isHaltonfailure() { + return _haltOnFailure; + } + public void setHaltonfailure(boolean haltOnFailure) { + _haltOnFailure = haltOnFailure; + } + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getPathid() { + return _pathid; + } + public void setPathid(String id) { + _pathid = id; + } + /** + * @deprecated use setPathid instead + * @param id + */ + public void setId(String id) { + _pathid = id; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + if (_pathid == null) { + throw new BuildException("pathid is required in ivy classpath"); + } + ensureResolved(isHaltonfailure()); + _conf = getProperty(_conf, ivy, "ivy.resolved.configurations"); + if (_conf.equals("*")) { + _conf = getProperty(ivy, "ivy.resolved.configurations"); + } + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + + if (_organisation == null || _module == null) { + throw new BuildException("no module id provided for ivy path: either call resolve, give paramaters to ivy:retrieve, or provide ivy.module and ivy.organisation properties"); + } + try { + XmlReportParser parser = new XmlReportParser(); + Path path = new Path(getProject()); + getProject().addReference(_pathid, path); + String[] confs = splitConfs(_conf); + Collection all = new HashSet(); + for (int i = 0; i < confs.length; i++) { + Artifact[] artifacts = parser.getArtifacts(new ModuleId(_organisation, _module), confs[i], _cache); + all.addAll(Arrays.asList(artifacts)); + } + for (Iterator iter = all.iterator(); iter.hasNext();) { + Artifact artifact = (Artifact)iter.next(); + path.createPathElement().setLocation(ivy.getArchiveFileInCache(_cache, artifact)); + } + } catch (Exception ex) { + throw new BuildException("impossible to build ivy path: "+ex.getMessage(), ex); + } + + } + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyCheck.java b/src/java/fr/jayasoft/ivy/ant/IvyCheck.java new file mode 100644 index 00000000..df491eda --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyCheck.java @@ -0,0 +1,74 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.net.MalformedURLException; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.FileSet; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.util.Message; + +public class IvyCheck extends IvyTask { + private File _file = null; + private List _filesets = new ArrayList(); + private String _resolvername; + public File getFile() { + return _file; + } + public void setFile(File file) { + _file = file; + } + /** + * Adds a set of files to check. + * @param set a set of files to check + */ + public void addFileset(FileSet set) { + _filesets.add(set); + } + public String getResolvername() { + return _resolvername; + } + + public void setResolvername(String resolverName) { + _resolvername = resolverName; + } + + + public void execute() throws BuildException { + try { + Ivy ivy = getIvyInstance(); + if (_file != null) { + if (ivy.check(_file.toURL(), _resolvername)) { + Message.verbose("checked "+_file+": OK"); + } + } + for (int i = 0; i < _filesets.size(); i++) { + FileSet fs = (FileSet) _filesets.get(i); + DirectoryScanner ds = fs.getDirectoryScanner(getProject()); + + File fromDir = fs.getDir(getProject()); + + String[] srcFiles = ds.getIncludedFiles(); + for (int j = 0; j < srcFiles.length; j++) { + File file = new File(fromDir, srcFiles[j]); + if (ivy.check(file.toURL(), _resolvername)) { + Message.verbose("checked "+file+": OK"); + } + } + } + } catch (MalformedURLException e) { + throw new BuildException("impossible to convert a file to an url!", e); + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyConfigure.java b/src/java/fr/jayasoft/ivy/ant/IvyConfigure.java new file mode 100644 index 00000000..afde5425 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyConfigure.java @@ -0,0 +1,144 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Properties; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Property; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.url.URLHandlerDispatcher; +import fr.jayasoft.ivy.url.URLHandlerRegistry; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Hanin + * + */ +public class IvyConfigure extends IvyTask { + private File _file = null; + private URL _url = null; + private String _realm = null; + private String _host = null; + private String _userName = null; + private String _passwd = null; + + public File getFile() { + return _file; + } + public void setFile(File conf) { + _file = conf; + } + public URL getUrl() { + return _url; + } + public void setUrl(String url) throws MalformedURLException { + _url = new URL(url); + } + public String getPasswd() { + return _passwd; + } + public void setPasswd(String passwd) { + _passwd = passwd; + } + public String getRealm() { + return _realm; + } + public void setRealm(String realm) { + _realm = format(realm); + } + public String getHost() { + return _host; + } + public void setHost(String host) { + _host = format(host); + } + public String getUsername() { + return _userName; + } + public void setUsername(String userName) { + _userName = format(userName); + } + private String format(String str) { + return str == null ? str : (str.trim().length() == 0 ? null : str.trim()); + } + + public void execute() throws BuildException { + try { + loadDefaultProperties(); + } catch (Exception ex) { + throw new BuildException("impossible to load ivy default properties file: "+ex.getMessage(), ex); + } + Message.init(new AntMessageImpl(getProject())); + Ivy ivy = new Ivy(); + try { + configureURLHandler(); + ivy.addAllVariables(getProject().getProperties()); + if (_file == null && _url == null) { + _file = new File(getProject().getBaseDir(), getProject().getProperty("ivy.conf.file")); + Message.verbose("searching ivyconf file: trying "+_file); + if (!_file.exists()) { + _file = new File(getProject().getProperty("ivy.conf.file")); + Message.verbose("searching ivyconf file: trying "+_file); + if (!_file.exists()) { + Message.info("no configuration file found, using default..."); + _file = null; + _url = Ivy.class.getResource("ivyconf.xml"); + } + } + } + if (_file != null) { + if (!_file.exists()) { + throw new BuildException("configuration file does not exist: "+_file); + } else { + ivy.configure(_file); + } + } else { + ivy.configure(_url); + } + setIvyInstance(ivy); + } catch (Exception ex) { + throw new BuildException("impossible to configure ivy with given file: "+ex.getMessage(), ex); + } + } + private void loadDefaultProperties() { + Property prop = new Property() { + public void execute() throws BuildException { + URL url = IvyConfigure.class.getResource("ivy.properties"); + // this is copy of loadURL code from ant Property task (not available in 1.5.1) + Properties props = new Properties(); + log("Loading " + url, Project.MSG_VERBOSE); + try { + InputStream is = url.openStream(); + try { + props.load(is); + } finally { + if (is != null) { + is.close(); + } + } + addProperties(props); + } catch (IOException ex) { + throw new BuildException(ex, getLocation()); + } + } + }; + prop.setProject(getProject()); + prop.execute(); + } + private void configureURLHandler() { + URLHandlerDispatcher dispatcher = new URLHandlerDispatcher(); + dispatcher.setDownloader("http", URLHandlerRegistry.getHttp(getRealm(), getHost(), getUsername(), getPasswd())); + URLHandlerRegistry.setDefault(dispatcher); + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyDeliver.java b/src/java/fr/jayasoft/ivy/ant/IvyDeliver.java new file mode 100644 index 00000000..e0bd32c4 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyDeliver.java @@ -0,0 +1,265 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.util.Date; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.CallTarget; +import org.apache.tools.ant.taskdefs.Echo; +import org.apache.tools.ant.taskdefs.Input; +import org.apache.tools.ant.taskdefs.Property; + +import fr.jayasoft.ivy.DefaultPublishingDRResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.PublishingDependencyRevisionResolver; +import fr.jayasoft.ivy.Status; + +/** + * @author Hanin + * + */ +public class IvyDeliver extends IvyTask { + private final class DeliverDRResolver implements PublishingDependencyRevisionResolver { + public String resolve(ModuleDescriptor published, String publishedStatus, ModuleDescriptor dependency) { + if (Status.isIntegration(publishedStatus)) { + // published status is integration one, nothing to ask + return dependency.getResolvedModuleRevisionId().getRevision(); + } + + // we are publishing a delivery (a non integration module) + + if (!Status.isIntegration(dependency.getStatus())) { + // dependency is already a delivery, nothing to ask + return dependency.getResolvedModuleRevisionId().getRevision(); + } + + // the dependency is not a delivery + + // we must ask the user what version and status he want to have + // for the dependency + String statusProperty = dependency.getModuleRevisionId().getName()+"."+dependency.getModuleRevisionId().getRevision()+".status"; + String versionProperty = dependency.getModuleRevisionId().getName()+"."+dependency.getModuleRevisionId().getRevision()+".version"; + String version = getProject().getProperty(versionProperty); + String status = getProject().getProperty(statusProperty); + log("found version = "+version+" status="+status); + if (version != null && status != null) { + // delivery has already been done : just return the value + return version; + + } + + Input input = (Input)getProject().createTask("input"); + input.setOwningTarget(getOwningTarget()); + input.init(); + + // ask status + input.setMessage(dependency.getModuleRevisionId().getName()+" "+dependency.getModuleRevisionId().getRevision()+": please enter a status: "); + input.setValidargs(Status.getDeliveryStatusListString()); + input.setAddproperty(statusProperty); + input.perform(); + appendDeliveryList(statusProperty + " = "+getProject().getProperty(statusProperty)); + + // ask version + input.setMessage(dependency.getModuleRevisionId().getName()+" "+dependency.getModuleRevisionId().getRevision()+": please enter a version: "); + input.setValidargs(null); + input.setAddproperty(versionProperty); + input.perform(); + appendDeliveryList(versionProperty + " = "+getProject().getProperty(versionProperty)); + + version = getProject().getProperty(versionProperty); + deliverDependency(dependency, version); + + loadDeliveryList(); + + return version; + } + + public void deliverDependency(ModuleDescriptor dependency, String version) { + // call deliver target if any + if (_deliverTarget != null) { + String statusProperty = dependency.getModuleRevisionId().getName()+"."+dependency.getModuleRevisionId().getRevision()+".status"; + String status = getProject().getProperty(statusProperty); + + CallTarget ct = (CallTarget)getProject().createTask("antcall"); + ct.setOwningTarget(getOwningTarget()); + ct.init(); + ct.setTarget(_deliverTarget); + ct.setInheritAll(true); + ct.setInheritRefs(true); + Property param = ct.createParam(); + param.setName("dependency.name"); + param.setValue(dependency.getModuleRevisionId().getName()); + param = ct.createParam(); + param.setName("dependency.published.status"); + param.setValue(status); + param = ct.createParam(); + param.setName("dependency.published.version"); + param.setValue(version); + param = ct.createParam(); + param.setName("dependency.version"); + param.setValue(dependency.getModuleRevisionId().getRevision()); + ct.perform(); + } + } + + } + + private String _organisation; + private String _module; + private String _revision; + private String _pubRevision; + private File _cache; + private String _deliverpattern; + private String _status; + private String _pubdate; + private String _deliverTarget; + private File _deliveryList; + + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getDeliverpattern() { + return _deliverpattern; + } + public void setDeliverpattern(String destivypattern) { + _deliverpattern = destivypattern; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public String getPubdate() { + return _pubdate; + } + public void setPubdate(String pubdate) { + _pubdate = pubdate; + } + public String getPubrevision() { + return _pubRevision; + } + public void setPubrevision(String pubRevision) { + _pubRevision = pubRevision; + } + public String getRevision() { + return _revision; + } + public void setRevision(String revision) { + _revision = revision; + } + public String getStatus() { + return _status; + } + public void setStatus(String status) { + _status = status; + } + public void setDelivertarget(String deliverTarget) { + _deliverTarget = deliverTarget; + } + public void setDeliveryList(File deliveryList) { + _deliveryList = deliveryList; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + _revision = getProperty(_revision, ivy, "ivy.revision"); + _pubRevision = getProperty(_pubRevision, ivy, "ivy.deliver.revision"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + _deliverpattern = getProperty(_deliverpattern, ivy, "ivy.deliver.ivy.pattern"); + _status = getProperty(_status, ivy, "ivy.status"); + if (_deliveryList == null) { + String deliveryListPath = getProperty(ivy, "ivy.delivery.list.file"); + if (deliveryListPath == null) { + _deliveryList = new File(System.getProperty("java.io.tmpdir")+"/delivery.properties"); + } else { + _deliveryList = getProject().resolveFile(ivy.substitute(deliveryListPath)); + } + } + if (_module == null || _organisation == null || _revision == null) { + throw new BuildException("empty or incomplete module revision id provided for deliver: either call resolve, give paramaters to deliver, or provide ivy.module, ivy.organisation and ivy.revision properties"); + } + Date pubdate = getPubDate(_pubdate, new Date()); + if (_pubRevision == null) { + if (_revision.startsWith("working@")) { + _pubRevision = Ivy.DATE_FORMAT.format(pubdate); + } else { + _pubRevision = _revision; + } + } + if (_deliverpattern == null) { + throw new BuildException("deliver ivy pattern is missing: either provide it as parameters or through ivy.deliver.ivy.pattern properties"); + } + if (_status == null) { + throw new BuildException("no status provided: either provide it as parameter or through the ivy.status.default property"); + } + ModuleRevisionId mrid = ModuleRevisionId.newInstance(_organisation, _module, _revision); + boolean isLeading = false; + try { + if (!_deliveryList.exists()) { + isLeading = true; + } + + loadDeliveryList(); + + PublishingDependencyRevisionResolver drResolver; + if (_deliverTarget!=null) { + drResolver = new DeliverDRResolver(); + } else { + drResolver = new DefaultPublishingDRResolver(); + } + ivy.deliver(mrid, _pubRevision, _cache, _deliverpattern, _status, pubdate, + drResolver, doValidate(ivy)); + + } catch (Exception e) { + throw new BuildException("impossible to deliver "+mrid+": "+e.getMessage(), e); + } finally { + if (isLeading) { + if (_deliveryList.exists()) { + _deliveryList.delete(); + } + } + } + } + + private void loadDeliveryList() { + Property property = (Property)getProject().createTask("property"); + property.setOwningTarget(getOwningTarget()); + property.init(); + property.setFile(_deliveryList); + property.perform(); + } + private void appendDeliveryList(String msg) { + Echo echo = (Echo)getProject().createTask("echo"); + echo.setOwningTarget(getOwningTarget()); + echo.init(); + echo.setFile(_deliveryList); + echo.setMessage(msg+"${line.separator}"); + echo.setAppend(true); + echo.perform(); + } + + + + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyExtractFromSources.java b/src/java/fr/jayasoft/ivy/ant/IvyExtractFromSources.java new file mode 100644 index 00000000..bed7c1aa --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyExtractFromSources.java @@ -0,0 +1,185 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.filters.LineContainsRegExp; +import org.apache.tools.ant.filters.TokenFilter; +import org.apache.tools.ant.taskdefs.Concat; +import org.apache.tools.ant.types.FileSet; +import org.apache.tools.ant.types.FilterChain; +import org.apache.tools.ant.types.RegularExpression; + +import fr.jayasoft.ivy.ModuleRevisionId; + +/** + * Extracts imports from a set of java sources and generate corresponding + * ivy file + * + * @author Hanin + * + */ +public class IvyExtractFromSources extends IvyTask { + public static class Ignore { + String _package; + public String getPackage() { + return _package; + } + public void setPackage(String package1) { + _package = package1; + } + } + private String _organisation; + private String _module; + private String _revision; + private String _status; + private List _ignoredPackaged = new ArrayList(); // List (String package) + private Map _mapping = new HashMap(); // Map (String package -> ModuleRevisionId) + private Concat _concat = new Concat(); + private File _to; + + public void addConfiguredIgnore(Ignore ignore) { + _ignoredPackaged.add(ignore.getPackage()); + } + public File getTo() { + return _to; + } + public void setTo(File to) { + _to = to; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public String getRevision() { + return _revision; + } + public void setRevision(String revision) { + _revision = revision; + } + public String getStatus() { + return _status; + } + public void setStatus(String status) { + _status = status; + } + public void addConfiguredMapping(PackageMapping mapping) { + _mapping.put(mapping.getPackage(), mapping.getModuleRevisionId()); + } + public void addFileSet(FileSet fileSet) { + _concat.addFileset(fileSet); + } + + public void execute() throws BuildException { + configureConcat(); + Writer out = new StringWriter(); + _concat.setWriter(out); + _concat.execute(); + Set importsSet = new HashSet(Arrays.asList(out.toString().split("\n"))); + Set dependencies = new HashSet(); + for (Iterator iter = importsSet.iterator(); iter.hasNext();) { + String pack = ((String)iter.next()).trim(); + ModuleRevisionId mrid = getMapping(pack); + if (mrid != null) { + dependencies.add(mrid); + } + } + try { + PrintWriter writer = new PrintWriter(new FileOutputStream(_to)); + writer.println(""); + writer.println("\t"); + if (!dependencies.isEmpty()) { + writer.println("\t"); + for (Iterator iter = dependencies.iterator(); iter.hasNext();) { + ModuleRevisionId mrid = (ModuleRevisionId)iter.next(); + writer.println("\t\t"); + } + writer.println("\t"); + } + writer.println(""); + writer.close(); + log(dependencies.size()+" dependencies put in "+_to); + } catch (FileNotFoundException e) { + throw new BuildException("impossible to create file "+_to); + } + } + + /** + * @param pack + * @return + */ + private ModuleRevisionId getMapping(String pack) { + String askedPack = pack; + ModuleRevisionId ret = null; + while (ret == null && pack.length() > 0) { + if (_ignoredPackaged.contains(pack)) { + return null; + } + ret = (ModuleRevisionId)_mapping.get(pack); + int lastDotIndex = pack.lastIndexOf('.'); + if (lastDotIndex != -1) { + pack = pack.substring(0, lastDotIndex); + } else { + break; + } + } + if (ret == null) { + log("no mapping found for "+askedPack, Project.MSG_VERBOSE); + } + return ret; + } + private void configureConcat() { + _concat.setProject(getProject()); + _concat.setTaskName(getTaskName()); + FilterChain filterChain = new FilterChain(); + LineContainsRegExp lcre = new LineContainsRegExp(); + RegularExpression regexp = new RegularExpression(); + regexp.setPattern("^import .+;"); + lcre.addConfiguredRegexp(regexp); + filterChain.add(lcre); + TokenFilter tf = new TokenFilter(); + TokenFilter.ReplaceRegex rre = new TokenFilter.ReplaceRegex(); + rre.setPattern("import (.+);.*"); + rre.setReplace("\\1"); + tf.add(rre); + filterChain.add(tf); + _concat.addFilterChain(filterChain); + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyPublish.java b/src/java/fr/jayasoft/ivy/ant/IvyPublish.java new file mode 100644 index 00000000..3f147986 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyPublish.java @@ -0,0 +1,220 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.Echo; +import org.apache.tools.ant.taskdefs.Property; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Hanin + * + */ +public class IvyPublish extends IvyTask { + private String _organisation; + private String _module; + private String _revision; + private String _pubRevision; + private File _cache; + private String _deliverivypattern; + private String _status; + private String _pubdate; + private String _deliverTarget; + private String _publishResolverName = null; + private String _artifactspattern = null; + private File _deliveryList; + private boolean _publishivy = true; + private boolean _warnonmissing = true; + private boolean _haltonmissing = true; + + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getDeliverivypattern() { + return _deliverivypattern; + } + public void setDeliverivypattern(String destivypattern) { + _deliverivypattern = destivypattern; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public String getPubdate() { + return _pubdate; + } + public void setPubdate(String pubdate) { + _pubdate = pubdate; + } + public String getPubrevision() { + return _pubRevision; + } + public void setPubrevision(String pubRevision) { + _pubRevision = pubRevision; + } + public String getRevision() { + return _revision; + } + public void setRevision(String revision) { + _revision = revision; + } + public String getStatus() { + return _status; + } + public void setStatus(String status) { + _status = status; + } + public void setDelivertarget(String deliverTarget) { + _deliverTarget = deliverTarget; + } + public void setDeliveryList(File deliveryList) { + _deliveryList = deliveryList; + } + public String getResolver() { + return _publishResolverName; + } + public void setResolver(String publishResolverName) { + _publishResolverName = publishResolverName; + } + public String getArtifactspattern() { + return _artifactspattern; + } + public void setArtifactspattern(String artifactsPattern) { + _artifactspattern = artifactsPattern; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + _revision = getProperty(_revision, ivy, "ivy.revision"); + _pubRevision = getProperty(_pubRevision, ivy, "ivy.deliver.revision"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + _artifactspattern = getProperty(_artifactspattern, ivy, "ivy.publish.src.artifacts.pattern"); + if (_deliverivypattern == null) { + _deliverivypattern = _artifactspattern; + } + _status = getProperty(_status, ivy, "ivy.status"); + if (_module == null || _organisation == null || _revision == null) { + throw new BuildException("empty or incomplete module revision id provided for publish: either call resolve, give paramaters to publish, or provide ivy.module, ivy.organisation and ivy.revision properties"); + } + if (_artifactspattern == null) { + throw new BuildException("no artifacts pattern: either provide it through parameter or through ivy.publish.src.artifacts.pattern property"); + } + if (_publishResolverName == null) { + throw new BuildException("no publish deliver name: please provide it through parameter 'resolver'"); + } + Date pubdate = getPubDate(_pubdate, new Date()); + if (_pubRevision == null) { + if (_revision.startsWith("working@")) { + _pubRevision = Ivy.DATE_FORMAT.format(pubdate); + } else { + _pubRevision = _revision; + } + } + if (_status == null) { + throw new BuildException("no status provided: either provide it as parameter or through the ivy.status.default property"); + } + ModuleRevisionId mrid = ModuleRevisionId.newInstance(_organisation, _module, _revision); + try { + File ivyFile = new File(_cache, IvyPatternHelper.substitute(_deliverivypattern, _organisation, _module, _pubRevision, "ivy", "ivy", "xml")); + if (_publishivy && !ivyFile.exists()) { + IvyDeliver deliver = new IvyDeliver(); + deliver.setProject(getProject()); + deliver.setCache(getCache()); + deliver.setDeliverpattern(getDeliverivypattern()); + deliver.setDelivertarget(_deliverTarget); + deliver.setDeliveryList(_deliveryList); + deliver.setModule(getModule()); + deliver.setOrganisation(getOrganisation()); + deliver.setPubdate(Ivy.DATE_FORMAT.format(pubdate)); + deliver.setPubrevision(getPubrevision()); + deliver.setRevision(getRevision()); + deliver.setStatus(getStatus()); + deliver.setValidate(doValidate(ivy)); + + deliver.execute(); + } + + Collection missing = ivy.publish(mrid, _pubRevision, _cache, _artifactspattern, _publishResolverName, _publishivy, doValidate(ivy)); + if (_warnonmissing) { + for (Iterator iter = missing.iterator(); iter.hasNext();) { + Artifact artifact = (Artifact)iter.next(); + Message.warn("missing artifact: "+artifact); + } + } + if (_haltonmissing && !missing.isEmpty()) { + throw new BuildException("missing published artifacts for "+mrid+": "+missing); + } + + } catch (Exception e) { + e.printStackTrace(); + throw new BuildException("impossible to publish artifacts for "+mrid+": "+e.getMessage(), e); + } + } + + private void loadDeliveryList() { + Property property = (Property)getProject().createTask("property"); + property.setOwningTarget(getOwningTarget()); + property.init(); + property.setFile(_deliveryList); + property.perform(); + } + private void appendDeliveryList(String msg) { + Echo echo = (Echo)getProject().createTask("echo"); + echo.setOwningTarget(getOwningTarget()); + echo.init(); + echo.setFile(_deliveryList); + echo.setMessage(msg+"\n"); + echo.setAppend(true); + echo.perform(); + } + public boolean isPublishivy() { + return _publishivy; + } + + public void setPublishivy(boolean publishivy) { + _publishivy = publishivy; + } + public boolean isWarnonmissing() { + return _warnonmissing; + } + + public void setWarnonmissing(boolean warnonmissing) { + _warnonmissing = warnonmissing; + } + public boolean isHaltonmissing() { + return _haltonmissing; + } + + public void setHaltonmissing(boolean haltonmissing) { + _haltonmissing = haltonmissing; + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyReport.java b/src/java/fr/jayasoft/ivy/ant/IvyReport.java new file mode 100644 index 00000000..87f57ab8 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyReport.java @@ -0,0 +1,202 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.io.IOException; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.taskdefs.XSLTProcess; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.report.XmlReportOutputter; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; + +public class IvyReport extends IvyTask { + private File _todir; + private String _organisation; + private String _module; + private String _conf; + private File _cache; + private boolean _graph = true; + private String _xslFile; + private String _outputpattern; + + public File getTodir() { + return _todir; + } + public void setTodir(File todir) { + _todir = todir; + } + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getConf() { + return _conf; + } + public void setConf(String conf) { + _conf = conf; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + + public boolean isGraph() { + return _graph; + } + + public void setGraph(boolean graph) { + _graph = graph; + } + public String getXslfile() { + return _xslFile; + } + + public void setXslfile(String xslFile) { + _xslFile = xslFile; + } + public String getOutputpattern() { + return _outputpattern; + } + + public void setOutputpattern(String outputpattern) { + _outputpattern = outputpattern; + } + + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + _conf = getProperty(_conf, ivy, "ivy.resolved.configurations"); + if (_conf.equals("*")) { + _conf = getProperty(ivy, "ivy.resolved.configurations"); + } + if (_todir == null) { + String t = getProperty(ivy, "ivy.report.todir"); + if (t != null) { + _todir = new File(t); + } + } + _outputpattern = getProperty(_outputpattern, ivy, "ivy.report.output.pattern"); + if (_todir != null && _todir.exists()) { + _todir.mkdirs(); + } + if (_outputpattern == null) { + _outputpattern = "[organisation]-[module]-[conf].html"; + } + + if (!_todir.isDirectory()) { + throw new BuildException("destination directory should be a directory !"); + } + if (_organisation == null || _module == null) { + throw new BuildException("no module id provided for retrieve: either call resolve, give paramaters to ivy:retrieve, or provide ivy.module and ivy.organisation properties"); + } + try { + String[] confs = splitConfs(_conf); + for (int i = 0; i < confs.length; i++) { + genreport(ivy, _cache, _organisation, _module, confs[i]); + if (_graph) { + gengraph(ivy, _cache, _organisation, _module, confs[i]); + } + } + } catch (IOException e) { + throw new BuildException("impossible to generate report", e); + } + } + + private void genreport(Ivy ivy, File cache, String organisation, String module, String conf) throws IOException { + // first process the report with xslt + XSLTProcess xslt = new XSLTProcess(); + xslt.setTaskName(getTaskName()); + xslt.setProject(getProject()); + xslt.setIn(new File(cache, XmlReportOutputter.getReportFileName(new ModuleId(organisation, module), conf))); + File out; + if (_todir != null) { + out = new File(_todir, IvyPatternHelper.substitute(_outputpattern, organisation, module, "", "", "", "", conf)); + } else { + out = new File(IvyPatternHelper.substitute(_outputpattern, organisation, module, "", "", "", "", conf)); + } + if (out.getParentFile() != null && !out.getParentFile().exists()) { + out.getParentFile().mkdirs(); + } + xslt.setOut(out); + xslt.setStyle(getReportStylePath(cache)); + XSLTProcess.Param param = xslt.createParam(); + param.setName("confs"); + param.setExpression(_conf); + param = xslt.createParam(); + param.setName("extension"); + param.setExpression("html"); + xslt.execute(); + + // then copy the css if required + if (_todir != null && _xslFile == null) { + File css = new File(_todir, "ivy-report.css"); + if (!css.exists()) { + Message.debug("copying report css to "+_todir); + FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.css"), css, null); + } + FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.css"), new File(cache, "ivy-report.css"), null); + } + } + + private String getReportStylePath(File cache) throws IOException { + if (_xslFile != null) { + return _xslFile; + } + // style should be a file (and not an url) + // so we have to copy it from classpath to cache + File style = new File(cache, "ivy-report.xsl"); + FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report.xsl"), style, null); + return style.getAbsolutePath(); + } + + + private void gengraph(Ivy ivy, File cache, String organisation, String module, String conf) throws IOException { + // process the report with xslt to generate graphml + XSLTProcess xslt = new XSLTProcess(); + xslt.setTaskName(getTaskName()); + xslt.setProject(getProject()); + xslt.setDestdir(_todir); + xslt.setBasedir(cache); + xslt.setExtension(".graphml"); + xslt.setIncludes(XmlReportOutputter.getReportFileName(new ModuleId(organisation, module), conf)); + xslt.setStyle(getGraphStylePath(cache)); + xslt.execute(); + } + + private String getGraphStylePath(File cache) throws IOException { + // style should be a file (and not an url) + // so we have to copy it from classpath to cache + File style = new File(cache, "ivy-report-graph.xsl"); + FileUtil.copy(XmlReportOutputter.class.getResourceAsStream("ivy-report-graph.xsl"), style, null); + return style.getAbsolutePath(); + } + + + + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyResolve.java b/src/java/fr/jayasoft/ivy/ant/IvyResolve.java new file mode 100644 index 00000000..8e2185d7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyResolve.java @@ -0,0 +1,108 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.net.MalformedURLException; +import java.text.ParseException; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.report.ResolveReport; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Hanin + * + */ +public class IvyResolve extends IvyTask { + private File _file = null; + private String _conf = null; + private File _cache = null; + private String _revision = null; + private String _pubdate = null; + private boolean _haltOnFailure = true; + + public String getDate() { + return _pubdate; + } + public void setDate(String pubdate) { + _pubdate = pubdate; + } + public String getRevision() { + return _revision; + } + public void setRevision(String revision) { + _revision = revision; + } + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getConf() { + return _conf; + } + public void setConf(String conf) { + _conf = conf; + } + public File getFile() { + return _file; + } + public void setFile(File file) { + _file = file; + } + public boolean isHaltonfailure() { + return _haltOnFailure; + } + public void setHaltonfailure(boolean haltOnFailure) { + _haltOnFailure = haltOnFailure; + } + public void setShowprogress(boolean show) { + Message.setShowProgress(show); + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + try { + if (_file == null) { + _file = new File(getProject().getBaseDir(), getProperty(ivy, "ivy.dep.file")); + } + _conf = getProperty(_conf, ivy, "ivy.configurations"); + _revision = getProperty(_revision, ivy, "ivy.revision"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + String[] confs = splitConfs(_conf); + ResolveReport report = ivy.resolve(_file.toURL(), _revision, confs, _cache, getPubDate(_pubdate, null), doValidate(ivy)); + if (isHaltonfailure() && report.hasError()) { + throw new BuildException("resolve failed - see output for details"); + } + ModuleDescriptor md = report.getModuleDescriptor(); + setResolved(md); + getProject().setProperty("ivy.organisation", md.getModuleRevisionId().getOrganisation()); + getProject().setProperty("ivy.module", md.getModuleRevisionId().getName()); + getProject().setProperty("ivy.revision", md.getResolvedModuleRevisionId().getRevision()); + if (_conf.trim().equals("*")) { + getProject().setProperty("ivy.resolved.configurations", mergeConfs(md.getConfigurationsNames())); + } else { + getProject().setProperty("ivy.resolved.configurations", _conf); + } + } catch (MalformedURLException e) { + throw new BuildException("unable to convert given ivy file to url: "+_file, e); + } catch (ParseException e) { + log(e.getMessage(), Project.MSG_ERR); + throw new BuildException("syntax errors in ivy file", e); + } catch (Exception e) { + throw new BuildException("impossible to resolve dependencies: "+e.getMessage(), e); + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java b/src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java new file mode 100644 index 00000000..388d8fe1 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyRetrieve.java @@ -0,0 +1,89 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; + +import java.io.File; + +import org.apache.tools.ant.BuildException; + +/** + * @author Hanin + * + */ +public class IvyRetrieve extends IvyTask { + private String _organisation; + private String _module; + private String _conf; + private File _cache; + private String _pattern; + private boolean _haltOnFailure = true; + + public File getCache() { + return _cache; + } + public void setCache(File cache) { + _cache = cache; + } + public String getConf() { + return _conf; + } + public void setConf(String conf) { + _conf = conf; + } + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public String getPattern() { + return _pattern; + } + public void setPattern(String pattern) { + _pattern = pattern; + } + public boolean isHaltonfailure() { + return _haltOnFailure; + } + public void setHaltonfailure(boolean haltOnFailure) { + _haltOnFailure = haltOnFailure; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + ensureResolved(isHaltonfailure()); + + _organisation = getProperty(_organisation, ivy, "ivy.organisation"); + _module = getProperty(_module, ivy, "ivy.module"); + if (_cache == null) { + _cache = ivy.getDefaultCache(); + } + _pattern = getProperty(_pattern, ivy, "ivy.retrieve.pattern"); + _conf = getProperty(_conf, ivy, "ivy.resolved.configurations"); + if (_conf.equals("*")) { + _conf = getProperty(ivy, "ivy.resolved.configurations"); + } + + if (_organisation == null || _module == null) { + throw new BuildException("no module id provided for retrieve: either call resolve, give paramaters to ivy:retrieve, or provide ivy.module and ivy.organisation properties"); + } + try { + ivy.retrieve(new ModuleId(_organisation, _module), splitConfs(_conf), _cache, _pattern); + } catch (Exception ex) { + throw new BuildException("impossible to ivy retrieve: "+ex.getMessage(), ex); + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyTask.java b/src/java/fr/jayasoft/ivy/ant/IvyTask.java new file mode 100644 index 00000000..da68fbbe --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyTask.java @@ -0,0 +1,126 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Task; + +/** + * @author Hanin + * + */ +public class IvyTask extends Task { + private Boolean _validate = null; + + protected boolean doValidate(Ivy ivy) { + if (_validate != null) { + return _validate.booleanValue(); + } + return ivy.doValidate(); + } + public boolean isValidate() { + return _validate == null ? true : _validate.booleanValue(); + } + public void setValidate(boolean validate) { + _validate = Boolean.valueOf(validate); + } + + protected Ivy getIvyInstance() { + Object reference = getProject().getReference("ivy.instance"); + if (reference == null) { + IvyConfigure configure = new IvyConfigure(); + configure.setProject(getProject()); + configure.execute(); + reference = getProject().getReference("ivy.instance"); + if (reference == null) { + throw new BuildException("ivy internal problem: impossible to get ivy instance !"); + } + } + if (! (reference instanceof Ivy)) { + throw new BuildException("ivy internal problem: bad ivy instance class: "+reference.getClass()); + } + return (Ivy)reference; + } + + protected void setIvyInstance(Ivy ivy) { + getProject().addReference("ivy.instance", ivy); + } + + protected void setResolved(ModuleDescriptor md) { + getProject().addReference("ivy.resolved.descriptor", md); + } + + protected void ensureResolved(boolean haltOnFailure) { + Object reference = getProject().getReference("ivy.resolved.descriptor"); + if (reference == null) { + IvyResolve resolve = new IvyResolve(); + resolve.setProject(getProject()); + resolve.setHaltonfailure(haltOnFailure); + if (_validate != null) { + resolve.setValidate(_validate.booleanValue()); + } + resolve.execute(); + } + } + + protected String[] splitConfs(String conf) { + String[] confs = conf.split(","); + for (int i = 0; i < confs.length; i++) { + confs[i] = confs[i].trim(); + } + return confs; + } + + protected String mergeConfs(String[] conf) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < conf.length; i++) { + buf.append(conf[i]).append(", "); + } + if (conf.length > 0) { + buf.setLength(buf.length() - 2); // delete last comma + } + return buf.toString(); + } + + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + protected Date getPubDate(String date, Date def) { + if (date != null) { + if ("now".equalsIgnoreCase(date)) { + return new Date(); + } + try { + return DATE_FORMAT.parse(date); + } catch (Exception ex) { + throw new BuildException("publication date provided in bad format. should be yyyyMMddHHmmss and not "+date); + } + } else { + return def; + } + } + + protected String getProperty(String value, Ivy ivy, String name) { + if (value == null) { + return getProperty(ivy, name); + } else { + return ivy.substitute(value); + } + } + + protected String getProperty(Ivy ivy, String name) { + String val = ivy.getVariable(name); + val = val == null ? getProject().getProperty(name) : val; + return val == null ? null : ivy.substitute(val); + } + +} diff --git a/src/java/fr/jayasoft/ivy/ant/IvyVar.java b/src/java/fr/jayasoft/ivy/ant/IvyVar.java new file mode 100644 index 00000000..41b52cf2 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/IvyVar.java @@ -0,0 +1,121 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; +import java.util.Iterator; +import java.util.Properties; + +import org.apache.tools.ant.BuildException; + +import fr.jayasoft.ivy.Ivy; + +public class IvyVar extends IvyTask { + private String _name; + private String _value; + + private File _file; + private String _url; + + private String _prefix; + + public File getFile() { + return _file; + } + + + public void setFile(File file) { + _file = file; + } + + + public String getName() { + return _name; + } + + + public void setName(String name) { + _name = name; + } + + + public String getPrefix() { + return _prefix; + } + + + public void setPrefix(String prefix) { + _prefix = prefix; + } + + + public String getUrl() { + return _url; + } + + + public void setUrl(String url) { + _url = url; + } + + + public String getValue() { + return _value; + } + + + public void setValue(String value) { + _value = value; + } + + public void execute() throws BuildException { + Ivy ivy = getIvyInstance(); + if (getName() != null) { + ivy.setVariable(getVarName(getName()), getValue()); + } else { + Properties props = new Properties(); + InputStream is = null; + try { + if (getFile() != null) { + is = new FileInputStream(getFile()); + } else if (getUrl() != null) { + is = new URL(getUrl()).openStream(); + } else { + throw new BuildException("specify either name or file or url to ivy var task"); + } + props.load(is); + } catch (Exception ex) { + throw new BuildException("impossible to load variables from file", ex); + } finally { + if (is != null) { + try {is.close();} catch (Exception e) {} + } + } + for (Iterator iter = props.keySet().iterator(); iter.hasNext();) { + String name = (String)iter.next(); + String value = (String)props.get(name); + ivy.setVariable(getVarName(name), value); + } + } + } + + + private String getVarName(String name) { + String prefix = getPrefix(); + if (prefix != null) { + if (prefix.endsWith(".")) { + return prefix + name; + } else { + return prefix + "." + name; + } + } + return name; + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/PackageMapping.java b/src/java/fr/jayasoft/ivy/ant/PackageMapping.java new file mode 100644 index 00000000..cd897177 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/PackageMapping.java @@ -0,0 +1,48 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import fr.jayasoft.ivy.ModuleRevisionId; + + +/** + * @author Hanin + * + */ +public class PackageMapping { + private String _package; + private String _organisation; + private String _module; + private String _revision; + + public String getModule() { + return _module; + } + public void setModule(String module) { + _module = module; + } + public String getOrganisation() { + return _organisation; + } + public void setOrganisation(String organisation) { + _organisation = organisation; + } + public String getRevision() { + return _revision; + } + public void setRevision(String revision) { + _revision = revision; + } + public String getPackage() { + return _package; + } + public void setPackage(String package1) { + _package = package1; + } + public ModuleRevisionId getModuleRevisionId() { + return ModuleRevisionId.newInstance(_organisation, _module, _revision); + } +} diff --git a/src/java/fr/jayasoft/ivy/ant/antlib.xml b/src/java/fr/jayasoft/ivy/ant/antlib.xml new file mode 100644 index 00000000..f8f0c177 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/antlib.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/java/fr/jayasoft/ivy/ant/ivy.properties b/src/java/fr/jayasoft/ivy/ant/ivy.properties new file mode 100644 index 00000000..d4ce6f68 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ant/ivy.properties @@ -0,0 +1,15 @@ +ivy.project.dir = ${basedir} +ivy.lib.dir = ${ivy.project.dir}/lib +ivy.build.artifacts.dir = ${ivy.project.dir}/build/artifacts +ivy.distrib.dir = ${ivy.project.dir}/distrib + +ivy.configurations = * +ivy.resolver.default.check.modified = false +ivy.status = integration +ivy.dep.file = ivy.xml +ivy.conf.file = ivyconf.xml +ivy.retrieve.pattern = ${ivy.lib.dir}/[artifact]-[revision].[ext] +ivy.deliver.ivy.pattern = ${ivy.distrib.dir}/[type]s/[artifact]-[revision].[ext] +ivy.publish.src.artifacts.pattern = ${ivy.distrib.dir}/[type]s/[artifact]-[revision].[ext] + +ivy.report.output.pattern = [organisation]-[module]-[conf].html \ No newline at end of file diff --git a/src/java/fr/jayasoft/ivy/conflict/AbstractConflictManager.java b/src/java/fr/jayasoft/ivy/conflict/AbstractConflictManager.java new file mode 100644 index 00000000..41b7e495 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/conflict/AbstractConflictManager.java @@ -0,0 +1,35 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.conflict; + +import fr.jayasoft.ivy.ConflictManager; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyAware; + +public abstract class AbstractConflictManager implements ConflictManager, IvyAware { + private String _name; + private Ivy _ivy; + + public Ivy getIvy() { + return _ivy; + } + + public void setIvy(Ivy ivy) { + _ivy = ivy; + } + + public String getName() { + return _name; + } + + public void setName(String name) { + _name = name; + } + + public String toString() { + return _name; + } +} diff --git a/src/java/fr/jayasoft/ivy/conflict/FixedConflictManager.java b/src/java/fr/jayasoft/ivy/conflict/FixedConflictManager.java new file mode 100644 index 00000000..e1a90cf4 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/conflict/FixedConflictManager.java @@ -0,0 +1,37 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.conflict; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; + +import fr.jayasoft.ivy.IvyNode; + +public class FixedConflictManager extends AbstractConflictManager { + private Collection _revs; + public FixedConflictManager(String[] revs) { + _revs = Arrays.asList(revs); + setName("fixed"+_revs); + } + public Collection resolveConflicts(IvyNode parent, Collection conflicts) { + Collection resolved = new ArrayList(conflicts.size()); + for (Iterator iter = conflicts.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + String revision = node.getResolvedId().getRevision(); + if (_revs.contains(revision)) { + resolved.add(node); + } + } + return resolved; + } + + public Collection getRevs() { + return _revs; + } + +} diff --git a/src/java/fr/jayasoft/ivy/conflict/LatestConflictManager.java b/src/java/fr/jayasoft/ivy/conflict/LatestConflictManager.java new file mode 100644 index 00000000..e45d5494 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/conflict/LatestConflictManager.java @@ -0,0 +1,115 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.conflict; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import fr.jayasoft.ivy.ArtifactInfo; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.LatestStrategy; +import fr.jayasoft.ivy.util.Message; + +public class LatestConflictManager extends AbstractConflictManager { + private static class IvyNodeArtifactInfo implements ArtifactInfo { + private final IvyNode _node; + + private IvyNodeArtifactInfo(IvyNode dep) { + _node = dep; + } + + public long getLastModified() { + return _node.getPublication(); + } + + public String getRevision() { + return _node.getId().getRevision(); + } + + public IvyNode getNode() { + return _node; + } + } + + + + private LatestStrategy _strategy; + private String _strategyName; + + public LatestConflictManager() { + } + + public LatestConflictManager(LatestStrategy strategy) { + _strategy = strategy; + } + + public LatestConflictManager(String name, LatestStrategy strategy) { + setName(name); + _strategy = strategy; + } + + public Collection resolveConflicts(IvyNode parent, Collection conflicts) { + for (Iterator iter = conflicts.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + DependencyDescriptor dd = node.getDependencyDescriptor(); + if (dd != null && dd.isForce() && parent.getResolvedId().equals(dd.getParentRevisionId())) { + return Collections.singleton(node); + } + } + ArtifactInfo latest = getStrategy().findLatest(toArtifactInfo(conflicts), null); + if (latest != null) { + return Collections.singleton(((IvyNodeArtifactInfo)latest).getNode()); + } else { + return conflicts; + } + } + + private ArtifactInfo[] toArtifactInfo(Collection conflicts) { + List artifacts = new ArrayList(conflicts.size()); + for (Iterator iter = conflicts.iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + artifacts.add(new IvyNodeArtifactInfo(node)); + } + return (ArtifactInfo[])artifacts.toArray(new ArtifactInfo[artifacts.size()]); + } + + public LatestStrategy getStrategy() { + if (_strategy == null) { + if (_strategyName != null) { + _strategy = getIvy().getLatestStrategy(_strategyName); + if (_strategy == null) { + Message.error("unknown latest strategy: "+_strategyName); + _strategy = getIvy().getDefaultLatestStrategy(); + } + } else { + _strategy = getIvy().getDefaultLatestStrategy(); + } + } + return _strategy; + } + + + /** + * To conform to configurator API + * @param latestStrategy + */ + public void setLatest(String strategyName) { + _strategyName = strategyName; + } + + public void setStrategy(LatestStrategy strategy) { + _strategy = strategy; + } + + + public String toString() { + return String.valueOf(_strategy); + } +} diff --git a/src/java/fr/jayasoft/ivy/conflict/NoConflictManager.java b/src/java/fr/jayasoft/ivy/conflict/NoConflictManager.java new file mode 100644 index 00000000..30063d8f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/conflict/NoConflictManager.java @@ -0,0 +1,19 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.conflict; + +import java.util.Collection; + +import fr.jayasoft.ivy.IvyNode; + +public class NoConflictManager extends AbstractConflictManager { + public NoConflictManager() { + setName("all"); + } + public Collection resolveConflicts(IvyNode parent, Collection conflicts) { + return conflicts; + } +} diff --git a/src/java/fr/jayasoft/ivy/ivyconf.xml b/src/java/fr/jayasoft/ivy/ivyconf.xml new file mode 100644 index 00000000..7f485653 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/ivyconf.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/java/fr/jayasoft/ivy/latest/AbstractLatestStrategy.java b/src/java/fr/jayasoft/ivy/latest/AbstractLatestStrategy.java new file mode 100644 index 00000000..f05088b3 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/latest/AbstractLatestStrategy.java @@ -0,0 +1,36 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.latest; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyAware; +import fr.jayasoft.ivy.LatestStrategy; + +public abstract class AbstractLatestStrategy implements LatestStrategy, IvyAware { + private String _name; + private Ivy _ivy; + + public Ivy getIvy() { + return _ivy; + } + + public void setIvy(Ivy ivy) { + _ivy = ivy; + } + + public String getName() { + return _name; + } + + public void setName(String name) { + _name = name; + } + + public String toString() { + return _name; + } + +} diff --git a/src/java/fr/jayasoft/ivy/latest/LatestLexicographicStrategy.java b/src/java/fr/jayasoft/ivy/latest/LatestLexicographicStrategy.java new file mode 100644 index 00000000..b1976566 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/latest/LatestLexicographicStrategy.java @@ -0,0 +1,67 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.latest; + +import java.util.Comparator; +import java.util.Date; + +import fr.jayasoft.ivy.ArtifactInfo; + + +public class LatestLexicographicStrategy extends AbstractLatestStrategy { + /** + * Compares two revisions. + * Revisions are compared lexicographically unless + * a 'latest' revision is found. If the latest revision found + * is an absolute latest (latest. like), then it is assumed to be the greater. + * If a partial latest is found, then it is assumed to be greater + * than any matching fixed revision. + */ + private static Comparator COMPARATOR = new Comparator() { + public int compare(Object o1, Object o2) { + String rev1 = (String)o1; + String rev2 = (String)o2; + if (rev1.startsWith("latest")) { + return 1; + } + if (rev1.endsWith("+") && rev2.startsWith(rev1.substring(0, rev1.length() - 1))) { + return 1; + } + if (rev2.startsWith("latest")) { + return -1; + } + if (rev2.endsWith("+") && rev1.startsWith(rev2.substring(0, rev2.length() - 1))) { + return -1; + } + return rev1.compareTo(rev2); + } + + }; + + public LatestLexicographicStrategy() { + setName("latest-lexico"); + } + + public ArtifactInfo findLatest(ArtifactInfo[] artifacts, Date date) { + if (artifacts == null) { + return null; + } + ArtifactInfo found = null; + for (int i = 0; i < artifacts.length; i++) { + ArtifactInfo art = artifacts[i]; + if (found == null || COMPARATOR.compare(art.getRevision(), found.getRevision()) > 0) { + if (date != null) { + long lastModified = art.getLastModified(); + if (lastModified > date.getTime()) { + continue; + } + } + found = art; + } + } + return found; + } +} diff --git a/src/java/fr/jayasoft/ivy/latest/LatestRevisionStrategy.java b/src/java/fr/jayasoft/ivy/latest/LatestRevisionStrategy.java new file mode 100644 index 00000000..60498ddc --- /dev/null +++ b/src/java/fr/jayasoft/ivy/latest/LatestRevisionStrategy.java @@ -0,0 +1,125 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.latest; + +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import fr.jayasoft.ivy.ArtifactInfo; + + +public class LatestRevisionStrategy extends AbstractLatestStrategy { + private static final Map SPECIAL_MEANINGS; + static { + SPECIAL_MEANINGS = new HashMap(); + SPECIAL_MEANINGS.put("dev", new Integer(-1)); + SPECIAL_MEANINGS.put("rc", new Integer(1)); + SPECIAL_MEANINGS.put("final", new Integer(2)); + } + + /** + * Compares two revisions. + * Revisions are compared using an algorithm inspired by PHP + * version_compare one, unless + * a 'latest' revision is found. If the latest revision found + * is an absolute latest (latest. like), then it is assumed to be the greater. + * If a partial latest is found, then it is assumed to be greater + * than any matching fixed revision. + */ + public static Comparator COMPARATOR = new Comparator() { + + public int compare(Object o1, Object o2) { + String rev1 = (String)o1; + String rev2 = (String)o2; + if (rev1.startsWith("latest")) { + return 1; + } + if (rev1.endsWith("+") && rev2.startsWith(rev1.substring(0, rev1.length() - 1))) { + return 1; + } + if (rev2.startsWith("latest")) { + return -1; + } + if (rev2.endsWith("+") && rev1.startsWith(rev2.substring(0, rev2.length() - 1))) { + return -1; + } + + rev1 = rev1.replaceAll("([a-zA-Z])(\\d)", "$1.$2"); + rev1 = rev1.replaceAll("(\\d)([a-zA-Z])", "$1.$2"); + rev2 = rev2.replaceAll("([a-zA-Z])(\\d)", "$1.$2"); + rev2 = rev2.replaceAll("(\\d)([a-zA-Z])", "$1.$2"); + + String[] parts1 = rev1.split("[\\._\\-\\+]"); + String[] parts2 = rev2.split("[\\._\\-\\+]"); + + int i = 0; + for (; i < parts1.length && i 0) { + if (date != null) { + long lastModified = art.getLastModified(); + if (lastModified > date.getTime()) { + continue; + } + } + found = art; + } + } + return found; + } +} diff --git a/src/java/fr/jayasoft/ivy/latest/LatestTimeStrategy.java b/src/java/fr/jayasoft/ivy/latest/LatestTimeStrategy.java new file mode 100644 index 00000000..24769862 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/latest/LatestTimeStrategy.java @@ -0,0 +1,33 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.latest; + +import java.util.Date; + +import fr.jayasoft.ivy.ArtifactInfo; + + +public class LatestTimeStrategy extends AbstractLatestStrategy { + public LatestTimeStrategy() { + setName("latest-time"); + } + public ArtifactInfo findLatest(ArtifactInfo[] artifacts, Date date) { + if (artifacts == null) { + return null; + } + ArtifactInfo found = null; + long foundDate = 0; + for (int i = 0; i < artifacts.length; i++) { + ArtifactInfo art = artifacts[i]; + long lastModified = art.getLastModified(); + if (lastModified > foundDate && (date == null || lastModified <= date.getTime())) { + foundDate = lastModified; + found = art; + } + } + return found; + } +} diff --git a/src/java/fr/jayasoft/ivy/report/ArtifactDownloadReport.java b/src/java/fr/jayasoft/ivy/report/ArtifactDownloadReport.java new file mode 100644 index 00000000..0909dcb6 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ArtifactDownloadReport.java @@ -0,0 +1,48 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import fr.jayasoft.ivy.Artifact; + +/** + * @author x.hanin + * + */ +public class ArtifactDownloadReport { + private Artifact _artifact; + private DownloadStatus _downloadStatus; + private long _size; + + public ArtifactDownloadReport(Artifact artifact) { + _artifact = artifact; + } + public DownloadStatus getDownloadStatus() { + return _downloadStatus; + } + public void setDownloadStatus(DownloadStatus downloadStatus) { + _downloadStatus = downloadStatus; + } + public String getName() { + return _artifact.getName(); + } + public String getType() { + return _artifact.getType(); + } + public Artifact getArtifact() { + return _artifact; + } + public String getExt() { + return _artifact.getExt(); + } + public long getSize() { + return _size; + } + + public void setSize(long size) { + _size = size; + } + +} diff --git a/src/java/fr/jayasoft/ivy/report/ConfigurationResolveReport.java b/src/java/fr/jayasoft/ivy/report/ConfigurationResolveReport.java new file mode 100644 index 00000000..1ec6ff81 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ConfigurationResolveReport.java @@ -0,0 +1,211 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.util.Message; + +/** + * @author x.hanin + * + */ +public class ConfigurationResolveReport { + + private ModuleDescriptor _md; + private String _conf; + private Date _date; + private Map _dependencyReports = new HashMap(); + private Map _dependencies = new HashMap(); + private Ivy _ivy; + private Map _modulesIdsMap = new LinkedHashMap(); + private List _modulesIds; + + public ConfigurationResolveReport(Ivy ivy, ModuleDescriptor md, String conf, Date date) { + _ivy = ivy; + _md = md; + _conf = conf; + _date = date; + } + + public void addDependency(IvyNode node) { + _dependencies.put(node.getId(), node); + _dependencies.put(node.getResolvedId(), node); + _dependencyReports.put(node, Collections.EMPTY_LIST); + } + + public void addDependency(IvyNode node, DownloadReport report) { + _dependencies.put(node.getId(), node); + _dependencies.put(node.getResolvedId(), node); + List adrs = new ArrayList(); + Artifact[] artifacts = node.getArtifacts(_conf); + for (int i = 0; i < artifacts.length; i++) { + ArtifactDownloadReport artifactReport = report.getArtifactReport(artifacts[i]); + if (artifactReport != null) { + adrs.add(artifactReport); + } else { + Message.debug("no report found for "+artifacts[i]); + } + } + _dependencyReports.put(node, adrs); + } + + + public String getConfiguration() { + return _conf; + } + public Date getDate() { + return _date; + } + public ModuleDescriptor getModuleDescriptor() { + return _md; + } + public IvyNode[] getUnresolvedDependencies() { + List unresolved = new ArrayList(); + for (Iterator iter = _dependencies.values().iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + if (node.hasProblem()) { + unresolved.add(node); + } + } + return (IvyNode[])unresolved.toArray(new IvyNode[unresolved.size()]); + } + public IvyNode[] getEvictedNodes() { + List evicted = new ArrayList(); + for (Iterator iter = _dependencies.values().iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + if (node.isEvicted(_conf)) { + evicted.add(node); + } + } + return (IvyNode[])evicted.toArray(new IvyNode[evicted.size()]); + } + public IvyNode[] getDownloadedNodes() { + List downloaded = new ArrayList(); + for (Iterator iter = _dependencies.values().iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + if (node.isDownloaded()) { + downloaded.add(node); + } + } + return (IvyNode[])downloaded.toArray(new IvyNode[downloaded.size()]); + } + public IvyNode[] getSearchedNodes() { + List downloaded = new ArrayList(); + for (Iterator iter = _dependencies.values().iterator(); iter.hasNext();) { + IvyNode node = (IvyNode)iter.next(); + if (node.isSearched()) { + downloaded.add(node); + } + } + return (IvyNode[])downloaded.toArray(new IvyNode[downloaded.size()]); + } + + public ArtifactDownloadReport[] getDownloadReports(ModuleRevisionId mrid) { + Collection col = (Collection)_dependencyReports.get(getDependency(mrid)); + if (col == null) { + return new ArtifactDownloadReport[0]; + } + return (ArtifactDownloadReport[]) col.toArray(new ArtifactDownloadReport[col.size()]); + } + + public IvyNode getDependency(ModuleRevisionId mrid) { + return (IvyNode) _dependencies.get(mrid); + } + + /** + * gives all the modules ids concerned by this report, from the most dependent to the least one + * @return a list of ModuleId + */ + public List getModuleIds() { + if (_modulesIds == null) { + List sortedDependencies = Ivy.sortNodes(_dependencies.values()); + Collections.reverse(sortedDependencies); + for (Iterator iter = sortedDependencies.iterator(); iter.hasNext();) { + IvyNode dependency = (IvyNode) iter.next(); + ModuleId mid = dependency.getResolvedId().getModuleId(); + Collection deps = (Collection)_modulesIdsMap.get(mid); + if (deps == null) { + deps = new HashSet(); + _modulesIdsMap.put(mid, deps); + } + deps.add(dependency); + } + _modulesIds = new ArrayList(_modulesIdsMap.keySet()); + } + return Collections.unmodifiableList(_modulesIds); + } + + public Collection getNodes(ModuleId mid) { + if (_modulesIds == null) { + getModuleIds(); + } + return (Collection)_modulesIdsMap.get(mid); + } + + public Ivy getIvy() { + return _ivy; + } + + public int getArtifactsNumber() { + int total = 0; + for (Iterator iter = _dependencyReports.values().iterator(); iter.hasNext();) { + Collection reports = (Collection)iter.next(); + total += reports==null?0:reports.size(); + } + return total; + } + public ArtifactDownloadReport[] getDownloadedArtifactsReports() { + List result = new ArrayList(); + for (Iterator iter = _dependencyReports.values().iterator(); iter.hasNext();) { + Collection reports = (Collection)iter.next(); + for (Iterator iterator = reports.iterator(); iterator.hasNext();) { + ArtifactDownloadReport adr = (ArtifactDownloadReport)iterator.next(); + if (adr.getDownloadStatus() == DownloadStatus.SUCCESSFUL) { + result.add(adr); + } + } + } + return (ArtifactDownloadReport[])result.toArray(new ArtifactDownloadReport[result.size()]); + } + public ArtifactDownloadReport[] getFailedArtifactsReports() { + List result = new ArrayList(); + for (Iterator iter = _dependencyReports.values().iterator(); iter.hasNext();) { + Collection reports = (Collection)iter.next(); + for (Iterator iterator = reports.iterator(); iterator.hasNext();) { + ArtifactDownloadReport adr = (ArtifactDownloadReport)iterator.next(); + if (adr.getDownloadStatus() == DownloadStatus.FAILED) { + result.add(adr); + } + } + } + return (ArtifactDownloadReport[])result.toArray(new ArtifactDownloadReport[result.size()]); + } + public boolean hasError() { + return getUnresolvedDependencies().length > 0 || getFailedArtifactsReports().length > 0; + } + + public int getNodesNumber() { + return new HashSet(_dependencies.values()).size(); + } + + +} diff --git a/src/java/fr/jayasoft/ivy/report/DownloadReport.java b/src/java/fr/jayasoft/ivy/report/DownloadReport.java new file mode 100644 index 00000000..188f552a --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/DownloadReport.java @@ -0,0 +1,45 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import fr.jayasoft.ivy.Artifact; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * @author x.hanin + * + */ +public class DownloadReport { + private Map _artifacts = new HashMap(); + + public void addArtifactReport(ArtifactDownloadReport adr) { + _artifacts.put(adr.getArtifact(), adr); + } + + public ArtifactDownloadReport[] getArtifactsReports() { + return (ArtifactDownloadReport[])_artifacts.values().toArray(new ArtifactDownloadReport[_artifacts.size()]); + } + + public ArtifactDownloadReport[] getArtifactsReports(DownloadStatus status) { + List ret = new ArrayList(_artifacts.size()); + for (Iterator iter = _artifacts.values().iterator(); iter.hasNext();) { + ArtifactDownloadReport adr = (ArtifactDownloadReport)iter.next(); + if (adr.getDownloadStatus() == status) { + ret.add(adr); + } + } + return (ArtifactDownloadReport[])ret.toArray(new ArtifactDownloadReport[ret.size()]); + } + + public ArtifactDownloadReport getArtifactReport(Artifact artifact) { + return (ArtifactDownloadReport)_artifacts.get(artifact); + } +} diff --git a/src/java/fr/jayasoft/ivy/report/DownloadStatus.java b/src/java/fr/jayasoft/ivy/report/DownloadStatus.java new file mode 100644 index 00000000..48b7137e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/DownloadStatus.java @@ -0,0 +1,27 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +/** + * @author x.hanin + * + */ +public class DownloadStatus { + private String _name; + private DownloadStatus(String name) { + _name = name; + } + + /** + * means that download was not required + */ + public static final DownloadStatus NO = new DownloadStatus("no"); + public static final DownloadStatus SUCCESSFUL = new DownloadStatus("successful"); + public static final DownloadStatus FAILED = new DownloadStatus("failed"); + public String toString() { + return _name; + } +} diff --git a/src/java/fr/jayasoft/ivy/report/LogReportOutputter.java b/src/java/fr/jayasoft/ivy/report/LogReportOutputter.java new file mode 100644 index 00000000..05cb47c4 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/LogReportOutputter.java @@ -0,0 +1,123 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import java.io.File; +import java.util.Arrays; + +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class LogReportOutputter implements ReportOutputter { + + public void output(ResolveReport report, File destDir) { + IvyNode[] evicted = report.getEvictedNodes(); + if (evicted.length > 0) { + Message.info("\t:: evicted modules:"); + for (int i = 0; i < evicted.length; i++) { + Message.info("\t"+evicted[i]+" by "+evicted[i].getAllEvictingNodes()+" in "+Arrays.asList(evicted[i].getEvictedConfs())); + String[] confs = evicted[i].getEvictedConfs(); + for (int j = 0; j < confs.length; j++) { + IvyNode.EvictionData evictedData = evicted[i].getEvictedData(confs[j]); + Message.verbose("\t in "+evictedData.getNode()+" with "+evictedData.getConflictManager()); + } + } + } + + char[] sep = new char[69]; + Arrays.fill(sep, '-'); + Message.info("\t"+new String(sep)); + StringBuffer line = new StringBuffer("\t"); + append(line, "", 18); + append(line, "modules", 31); + line.append("|"); + append(line, "artifacts", 15); + line.append("|"); + Message.info(line.toString()); + + line = new StringBuffer("\t"); + append(line, "conf", 18); + append(line, "number", 7); + append(line, "search", 7); + append(line, "dwnlded", 7); + append(line, "evicted", 7); + line.append("|"); + append(line, "number", 7); + append(line, "dwnlded", 7); + line.append("|"); + Message.info(line.toString()); + Message.info("\t"+new String(sep)); + + String[] confs = report.getConfigurations(); + for (int i = 0; i < confs.length; i++) { + output(report.getConfigurationReport(confs[i])); + } + Message.info("\t"+new String(sep)); + + IvyNode[] unresolved = report.getUnresolvedDependencies(); + if (unresolved.length > 0) { + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); + Message.warn("\t:: UNRESOLVED DEPENDENCIES ::"); + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); + } + for (int i = 0; i < unresolved.length; i++) { + Message.warn("\t:: "+unresolved[i]+": "+unresolved[i].getProblem().getMessage()); + } + if (unresolved.length > 0) { + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::\n"); + } + + ArtifactDownloadReport[] errors = report.getFailedArtifactsReports(); + if (errors.length > 0) { + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); + Message.warn("\t:: FAILED DOWNLOADS ::"); + Message.warn("\t:: ^ see resolution messages for details ^ ::"); + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::"); + } + for (int i = 0; i < errors.length; i++) { + Message.warn("\t:: "+errors[i].getArtifact()); + } + if (errors.length > 0) { + Message.warn("\t::::::::::::::::::::::::::::::::::::::::::::::\n"); + } + } + + public void output(ConfigurationResolveReport report) { + StringBuffer line = new StringBuffer("\t"); + append(line, report.getConfiguration(), 18); + append(line, String.valueOf(report.getNodesNumber()), 7); + append(line, String.valueOf(report.getSearchedNodes().length), 7); + append(line, String.valueOf(report.getDownloadedNodes().length), 7); + append(line, String.valueOf(report.getEvictedNodes().length), 7); + line.append("|"); + append(line, String.valueOf(report.getArtifactsNumber()), 7); + append(line, String.valueOf(report.getDownloadedArtifactsReports().length), 7); + line.append("|"); + + Message.info(line.toString()); + } + + private void append(StringBuffer line, Object o, int limit) { + String v = String.valueOf(o); + if (v.length() >= limit) { + v = v.substring(0, limit); + } else { + int missing = limit - v.length(); + int half = missing / 2; + char[] c = new char[limit]; + Arrays.fill(c, ' '); + System.arraycopy(v.toCharArray(), 0, c, missing - half, v.length()); + v = new String(c); + } + line.append("|"); + line.append(v); + } + +} diff --git a/src/java/fr/jayasoft/ivy/report/ReportOutputter.java b/src/java/fr/jayasoft/ivy/report/ReportOutputter.java new file mode 100644 index 00000000..fa4a2620 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ReportOutputter.java @@ -0,0 +1,16 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import java.io.File; + +/** + * @author x.hanin + * + */ +public interface ReportOutputter { + public abstract void output(ResolveReport report, File destDir); +} diff --git a/src/java/fr/jayasoft/ivy/report/ResolveReport.java b/src/java/fr/jayasoft/ivy/report/ResolveReport.java new file mode 100644 index 00000000..606fb7cf --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ResolveReport.java @@ -0,0 +1,80 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import java.io.File; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.ModuleDescriptor; + +/** + * Represents a whole resolution report for a module + */ +public class ResolveReport { + private ModuleDescriptor _md; + private Map _confReports = new HashMap(); + public ResolveReport(ModuleDescriptor md) { + _md = md; + } + public void addReport(String conf, ConfigurationResolveReport report) { + _confReports.put(conf, report); + } + public ConfigurationResolveReport getConfigurationReport(String conf) { + return (ConfigurationResolveReport)_confReports.get(conf); + } + public String[] getConfigurations() { + return (String[])_confReports.keySet().toArray(new String[_confReports.size()]); + } + public boolean hasError() { + boolean hasError = false; + for (Iterator it = _confReports.values().iterator(); it.hasNext() && !hasError;) { + ConfigurationResolveReport report = (ConfigurationResolveReport)it.next(); + hasError |= report.hasError(); + } + return hasError; + } + + public void output(ReportOutputter[] outputters, File cache) { + for (int i = 0; i < outputters.length; i++) { + outputters[i].output(this, cache); + } + } + + public ModuleDescriptor getModuleDescriptor() { + return _md; + } + + public IvyNode[] getEvictedNodes() { + Collection all = new HashSet(); + for (Iterator iter = _confReports.values().iterator(); iter.hasNext();) { + ConfigurationResolveReport report = (ConfigurationResolveReport)iter.next(); + all.addAll(Arrays.asList(report.getEvictedNodes())); + } + return (IvyNode[])all.toArray(new IvyNode[all.size()]); + } + public IvyNode[] getUnresolvedDependencies() { + Collection all = new HashSet(); + for (Iterator iter = _confReports.values().iterator(); iter.hasNext();) { + ConfigurationResolveReport report = (ConfigurationResolveReport)iter.next(); + all.addAll(Arrays.asList(report.getUnresolvedDependencies())); + } + return (IvyNode[])all.toArray(new IvyNode[all.size()]); + } + public ArtifactDownloadReport[] getFailedArtifactsReports() { + Collection all = new HashSet(); + for (Iterator iter = _confReports.values().iterator(); iter.hasNext();) { + ConfigurationResolveReport report = (ConfigurationResolveReport)iter.next(); + all.addAll(Arrays.asList(report.getFailedArtifactsReports())); + } + return (ArtifactDownloadReport[])all.toArray(new ArtifactDownloadReport[all.size()]); + } +} diff --git a/src/java/fr/jayasoft/ivy/report/XmlReportOutputter.java b/src/java/fr/jayasoft/ivy/report/XmlReportOutputter.java new file mode 100644 index 00000000..a0f3b5f7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/XmlReportOutputter.java @@ -0,0 +1,160 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.report; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import java.util.Iterator; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.License; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class XmlReportOutputter implements ReportOutputter { + + public void output(ResolveReport report, File destDir) { + String[] confs = report.getConfigurations(); + for (int i = 0; i < confs.length; i++) { + output(report.getConfigurationReport(confs[i]), destDir); + } + } + + public void output(ConfigurationResolveReport report, File destDir) { + PrintWriter out = null; + try { + destDir.mkdirs(); + File reportFile = new File(destDir, getReportFileName(report)); + out = new PrintWriter(new FileOutputStream(reportFile)); + ModuleRevisionId mrid = report.getModuleDescriptor().getModuleRevisionId(); + out.println(""); + out.println(""); + out.println(""); + out.println("\t"); + + out.println("\t"); + for (Iterator iter = report.getModuleIds().iterator(); iter.hasNext();) { + ModuleId mid = (ModuleId) iter.next(); + out.println("\t\t"); + for (Iterator it2 = report.getNodes(mid).iterator(); it2.hasNext();) { + IvyNode dep = (IvyNode)it2.next(); + ModuleDescriptor md = null; + if (dep.getModuleRevision() != null) { + md = dep.getModuleRevision().getDescriptor(); + } + String details = ""; + if (dep.isLoaded()) { + details += " status=\""+dep.getDescriptor().getStatus()+"\"" + + " pubdate=\""+Ivy.DATE_FORMAT.format(new Date(dep.getPublication()))+"\"" + + " resolver=\""+dep.getModuleRevision().getResolver().getName()+"\""; + } + if (dep.isEvicted(report.getConfiguration())) { + IvyNode.EvictionData ed = dep.getEvictedData(report.getConfiguration()); + details += " evicted=\""+ed.getConflictManager()+"\""; + } + if (dep.hasProblem()) { + details += " error=\""+dep.getProblem().getMessage()+"\""; + } + if (md != null && md.getHomePage() != null) { + details += " homepage=\""+md.getHomePage()+"\""; + } + out.println("\t\t\t"); + if (md != null) { + License[] licenses = md.getLicenses(); + for (int i = 0; i < licenses.length; i++) { + String lurl; + if (licenses[i].getUrl() != null) { + lurl = " url=\""+licenses[i].getUrl()+"\""; + } else { + lurl = ""; + } + out.println("\t\t\t\t"); + } + } + if (dep.isEvicted(report.getConfiguration())) { + IvyNode.EvictionData ed = dep.getEvictedData(report.getConfiguration()); + for (Iterator it3 = ed.getSelected().iterator(); it3.hasNext();) { + IvyNode sel = (IvyNode)it3.next(); + out.println("\t\t\t\t"); + } + } + IvyNode.Caller[] callers = dep.getCallers(report.getConfiguration()); + for (int i = 0; i < callers.length; i++) { + out.println("\t\t\t\t"); + } + ArtifactDownloadReport[] adr = report.getDownloadReports(dep.getResolvedId()); + out.println("\t\t\t\t"); + for (int i = 0; i < adr.length; i++) { + out.print("\t\t\t\t\t"); + } + out.println("\t\t\t\t"); + out.println("\t\t\t"); + } + out.println("\t\t"); + } + out.println("\t"); + + out.println(""); + Message.verbose("\treport for "+mrid+" "+report.getConfiguration()+" produced in "+reportFile); + } catch (IOException ex) { + Message.error("impossible to produce report for "+report.getModuleDescriptor()+": "+ex.getMessage()); + } finally { + if (out != null) { + out.close(); + } + } + } + + private String toString(String[] strs) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < strs.length; i++) { + buf.append(strs[i]); + if (i + 1 < strs.length) { + buf.append(", "); + } + } + return buf.toString(); + } + + public static String getReportFileName(ConfigurationResolveReport report) { + return getReportFileName(report.getModuleDescriptor().getModuleRevisionId().getModuleId(), + report.getConfiguration()); + } + + public static String getReportFileName(ModuleId mid, String conf) { + return + mid.getOrganisation() + + "-" + mid.getName() + + "-" + conf+".xml"; + } + +} diff --git a/src/java/fr/jayasoft/ivy/report/ivy-report-graph.xsl b/src/java/fr/jayasoft/ivy/report/ivy-report-graph.xsl new file mode 100644 index 00000000..8e69e528 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ivy-report-graph.xsl @@ -0,0 +1,67 @@ + + + + + + + + + + - + + + + + + + + + + + + + + - + + + + + + + + + + (error) (evicted) + + + + + + + + + + --- + - + - + + + + + + + + + + + + + + + + + diff --git a/src/java/fr/jayasoft/ivy/report/ivy-report.css b/src/java/fr/jayasoft/ivy/report/ivy-report.css new file mode 100644 index 00000000..5a4486e3 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ivy-report.css @@ -0,0 +1,261 @@ +body { + font-family:"Trebuchet MS",Verdana,Geneva,Arial,Helvetica,sans-serif; + font-size:small; +} + +div#logo { + float: right; + padding-left: 10px; + padding-bottom: 10px; + background: white; + text-align: center; +} + +#logo img { + border: 0; +} + +div#date { + font-style: italic; + padding-left: 60px; + padding-bottom: 40px; +} + + +h1 { + margin-bottom:2px; + + border-color:#7A9437; + border-style:solid; + border-width:0 0 3px 0; +} + +span#module { + color:#7A9437; + text-decoration:none; +} + +span#organisation { + color:black; + text-decoration:none; +} + +#confmenu { + color: #000; + border-bottom: 2px solid black; + margin: 12px 0px 0px 0px; + padding: 0px; + z-index: 1; + padding-left: 10px +} + +#confmenu li { + display: inline; + overflow: hidden; + list-style-type: none; +} + +#confmenu a, a.active { + color: #DEDECF; + background: #898B5E; + font: bold 1em "Trebuchet MS", Arial, sans-serif; + border: 2px solid black; + padding: 2px 5px 0px 5px; + text-decoration: none; +} + +/* +background: #ABAD85 #CED4BD +background: #DEE4CD + */ + +#confmenu a.active { + color: #7A9437; + background: #DEE4CD; + border-bottom: 3px solid #DEE4CD; +} + +#confmenu a:hover { + color: #fff; + background: #ADC09F; +} + +#confmenu a:visited { + color: #DEDECF; +} + +#confmenu a.active:visited { + color: #7A9437; +} + +#confmenu a.active:hover { + background: #DEE4CD; + color: #DEDECF; +} + +#content { + background: #DEE4CD; + padding: 20px; + border: 2px solid black; + border-top: none; + z-index: 2; +} + +#content a { + text-decoration: none; + color: #E8E9BE; +} + +#content a:hover { + background: #898B5E; +} + + +h2 { + margin-bottom:2px; + font-size:medium; + + border-color:#7A9437; + border-style:solid; + border-width:0 0 2px 0; +} + +h3 { + margin-top:30px; + margin-bottom:2px; + padding: 5 5 5 0; + font-size: 24px; + border-style:solid; + border-width:0 0 2px 0; +} + +h4 { + margin-bottom:2px; + margin-top:2px; + font-size:medium; + + border-color:#7A9437; + border-style:dashed; + border-width:0 0 1px 0; +} + +h5 { + margin-bottom:2px; + margin-top:2px; + margin-left:20px; + font-size:medium; +} + +span.resolved { + padding-left: 15px; + font-weight: 500; + font-size: small; +} + + +#content table { + border-collapse:collapse; + width:90%; + margin:auto; + margin-top: 5px; +} +#content thead { + background-color:#CED4BD; + border:1px solid #7A9437; +} +#content tbody { + border-collapse:collapse; + background-color:#FFFFFF; + border:1px solid #7A9437; +} + +#content th { + font-family:monospace; + border:1px solid #7A9437; + padding:5px; +} + +#content td { + border:1px dotted #7A9437; + padding:0 3 0 3; +} + +#content table a { + color:#7A9437; + text-decoration:none; +} + +#content table a:hover { + background-color:#CED4BD; + color:#7A9437; +} + + + +table.deps { + border-collapse:collapse; + width:90%; + margin:auto; + margin-top: 5px; +} + +table.deps thead { + background-color:#CED4BD; + border:1px solid #7A9437; +} +table.deps tbody { + border-collapse:collapse; + background-color:#FFFFFF; + border:1px solid #7A9437; +} + +table.deps th { + font-family:monospace; + border:1px solid #7A9437; + padding:2; +} + +table.deps td { + border:1px dotted #7A9437; + padding:0 3 0 3; +} + + + + + +table.header { + border:0; + width:90%; + margin:auto; + margin-top: 5px; +} + +table.header thead { + border:0; +} +table.header tbody { + border:0; +} +table.header tr { + padding:0px; + border:0; +} +table.header td { + padding:0 3 0 3; + border:0; +} + +td.title { + width:150px; + margin-right:15px; + + font-size:small; + font-weight:700; +} + +td.title:first-letter { + color:#7A9437; + background-color:transparent; +} + diff --git a/src/java/fr/jayasoft/ivy/report/ivy-report.xsl b/src/java/fr/jayasoft/ivy/report/ivy-report.xsl new file mode 100644 index 00000000..5e6da916 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/report/ivy-report.xsl @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ No dependency +
+
+ + + + + + + + + + + + + + + + + + + + +
ModuleRevisionStatusLicensesSize
+
+
+ + + + + + + + + + + + + #- + + + by + + + + + + #-- + + + + + + + + + + + + + kB + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + searched + + + downloaded + + + + http://ivy.jayasoft.org/images/evicted.gif + evicted + evicted by + + + + + http://ivy.jayasoft.org/images/error.gif + error + error: + + + + + + + + + + + + + #- + + by + + + + + + #-- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  • + + + active + + --. + + +
  • +
    + + + + + -- + + :: + + + + + + + + Ivy report :: <xsl:value-of select="info/@module"/> by <xsl:value-of select="info/@organisation"/> :: <xsl:value-of select="info/@conf"/> + + + + + + + +

    + + - + + + + + by + + + +

    +
    + resolved on + + + +
    +
      + + + +
    + +
    +

    Dependencies Stats

    + + + + + +
    Modules
    Revisions + ( searched searched, + downloaded downloaded, + evicted evicted, + errors error)
    Artifacts + ( downloaded, + failed)
    Artifacts size kB + ( kB downloaded, + kB in cache)
    + + +

    Errors

    + + + + + + + + + + + + + + + + + + +
    ModuleRevisionError
    +
    + + +

    Conflicts

    + + + + + + + + + + + + + + + + + +
    ModuleSelectedEvicted
    + + #- + + by + + + + + + #-- + + + + + + + + #-- + + + + +
    +
    + +

    Dependencies Overview

    + + + + + +

    Details

    + +

    + + - + + by + resolved by +

    + +

    + + -- + + Revision: + + + + + +

    + + + + + + + + + + + + + + + + +
    Home Page + + + +
    Status
    Publication
    Resolver
    Configurations
    Artifacts size kB + ( kB downloaded, + kB in cache)
    Licenses + + + +
    Evicted by + + + + in conflict manager +
    +
    Required by
    + + + + + + + + + + + + + + + + + + + +
    OrganisationNameIn ConfigurationsAsked Revision
    + + #- + + +
    + + +
    Dependencies
    + + + + +
    Artifacts
    + +
    + No artifact +
    +
    + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeExtDownloadSize
    kB
    +
    + +
    +
    +
    +
    + + +
    + +
    diff --git a/src/java/fr/jayasoft/ivy/repository.properties b/src/java/fr/jayasoft/ivy/repository.properties new file mode 100644 index 00000000..062a3df2 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository.properties @@ -0,0 +1,7 @@ +ivy.ibiblio.default.artifact.root = http://www.ibiblio.org/maven/ +ivy.ibiblio.default.artifact.pattern = [module]/[type]s/[artifact]-[revision].[ext] + +ivy.ivyrep.default.ivy.root = http://ivyrep.jayasoft.org/ +ivy.ivyrep.default.ivy.pattern = [organisation]/[module]/ivy-[revision].xml +ivy.ivyrep.default.artifact.root = ${ivy.ibiblio.default.artifact.root} +ivy.ivyrep.default.artifact.pattern = ${ivy.ibiblio.default.artifact.pattern} \ No newline at end of file diff --git a/src/java/fr/jayasoft/ivy/repository/AbstractRepository.java b/src/java/fr/jayasoft/ivy/repository/AbstractRepository.java new file mode 100644 index 00000000..de78cf37 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/AbstractRepository.java @@ -0,0 +1,107 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository; + +import java.util.Arrays; + +import javax.swing.event.EventListenerList; + +public abstract class AbstractRepository implements Repository { + private EventListenerList _listeners = new EventListenerList(); + private String _name; + private TransferEvent _evt; + + public void addTransferListener(TransferListener listener) { + _listeners.add(TransferListener.class, listener); + } + + public void removeTransferListener(TransferListener listener) { + _listeners.remove(TransferListener.class, listener); + } + + public boolean hasTransferListener(TransferListener listener) { + return Arrays.asList(_listeners.getListeners(TransferListener.class)).contains(listener); + } + + protected void fireTransferInitiated(Resource res, int requestType) { + _evt = new TransferEvent(this, res, TransferEvent.TRANSFER_INITIATED, requestType); + fireTransferEvent(_evt); + } + + protected void fireTransferStarted() { + _evt.setEventType(TransferEvent.TRANSFER_STARTED); + fireTransferEvent(_evt); + } + + protected void fireTransferProgress(byte[] buffer, long length) { + _evt.setEventType(TransferEvent.TRANSFER_PROGRESS); + _evt.setBuffer(buffer); + _evt.setLength(length); + _evt.setTotalLength(_evt.getTotalLength() + length); + fireTransferEvent(_evt); + } + + protected void fireTransferCompleted(byte[] buffer, long length) { + _evt.setEventType(TransferEvent.TRANSFER_COMPLETED); + _evt.setBuffer(buffer); + _evt.setLength(length); + _evt.setTotalLength(_evt.getTotalLength() + length); + fireTransferEvent(_evt); + _evt = null; + } + + protected void fireTransferCompleted(int totalLength) { + _evt.setEventType(TransferEvent.TRANSFER_COMPLETED); + _evt.setBuffer(null); + _evt.setTotalLength(totalLength); + fireTransferEvent(_evt); + _evt = null; + } + + protected void fireTransferError() { + _evt.setEventType(TransferEvent.TRANSFER_ERROR); + fireTransferEvent(_evt); + _evt = null; + } + + protected void fireTransferError(Exception ex) { + _evt.setEventType(TransferEvent.TRANSFER_ERROR); + _evt.setException(ex); + fireTransferEvent(_evt); + _evt = null; + } + + protected void fireTransferEvent(TransferEvent evt) { + Object[] listeners = _listeners.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TransferListener.class) { + ((TransferListener)listeners[i+1]).transferProgress(evt); + } + } + } + + public String getFileSeparator() { + return "/"; + } + + public String standardize(String source) { + return source.replace('\\', '/'); + } + + public String getName() { + return _name; + } + + + public void setName(String name) { + _name = name; + } + + public String toString() { + return getName(); + } +} diff --git a/src/java/fr/jayasoft/ivy/repository/Repository.java b/src/java/fr/jayasoft/ivy/repository/Repository.java new file mode 100644 index 00000000..89d9510a --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/Repository.java @@ -0,0 +1,32 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public interface Repository { + Resource getResource(String source) throws IOException; + void get(String source, File destination) throws IOException; + void put(File source, String destination) throws IOException; + /** + * Returns the list of all resources names that can be found in the given + * parent. + * @param parent + * @return a List of String, the names of the resources that can be found in the given + * parent + */ + List list(String parent) throws IOException; + + void addTransferListener(TransferListener listener); + void removeTransferListener(TransferListener listener); + boolean hasTransferListener(TransferListener listener); + String getFileSeparator(); + String standardize(String source); + String getName(); +} diff --git a/src/java/fr/jayasoft/ivy/repository/Resource.java b/src/java/fr/jayasoft/ivy/repository/Resource.java new file mode 100644 index 00000000..6fe8fb34 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/Resource.java @@ -0,0 +1,14 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository; + +public interface Resource { + public String getName(); + public long getLastModified(); + public long getContentLength(); + public boolean exists(); +} diff --git a/src/java/fr/jayasoft/ivy/repository/TransferEvent.java b/src/java/fr/jayasoft/ivy/repository/TransferEvent.java new file mode 100644 index 00000000..93981e39 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/TransferEvent.java @@ -0,0 +1,249 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository; + +import java.io.File; + +/** + * TransferEvent is used to notify TransferListeners about progress in transfer + * of resources form/to the respository + * + * This class is LARGELY inspired by org.apache.maven.wagon.events.TransferEvent + * released under the following copyright license: + * + *
    + * 
    + *  Copyright 2001-2005 The Apache Software Foundation.
    + * 
    + *  Licensed under the Apache License, Version 2.0 (the "License");
    + *  you may not use this file except in compliance with the License.
    + *  You may obtain a copy of the License at
    + * 
    + *       http://www.apache.org/licenses/LICENSE-2.0
    + * 
    + *  Unless required by applicable law or agreed to in writing, software
    + *  distributed under the License is distributed on an "AS IS" BASIS,
    + *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + *  See the License for the specific language governing permissions and
    + *  limitations under the License.
    + *  
    + * 
    + * + * Orginal class written by Michal Maczka. + * + */ +public class TransferEvent { + /** + * A transfer was attempted, but has not yet commenced. + */ + public static final int TRANSFER_INITIATED = 0; + + /** + * A transfer was started. + */ + public final static int TRANSFER_STARTED = 1; + + /** + * A transfer is completed. + */ + public final static int TRANSFER_COMPLETED = 2; + + /** + * A transfer is in progress. + */ + public final static int TRANSFER_PROGRESS = 3; + + /** + * An error occured during transfer + */ + public final static int TRANSFER_ERROR = 4; + + /** + * Indicates GET transfer (from the repository) + */ + public final static int REQUEST_GET = 5; + + /** + * Indicates PUT transfer (to the repository) + */ + public final static int REQUEST_PUT = 6; + + private Resource _resource; + + private int _eventType; + + private int _requestType; + + private Exception _exception; + + private File _localFile; + + private Repository _repository; + private byte[] _buffer; + private long _length; + + private long _totalLength; + + public TransferEvent(final Repository repository, final Resource resource, final int eventType, final int requestType) { + _repository = repository; + _resource = resource; + + setEventType(eventType); + + setRequestType(requestType); + + } + + public TransferEvent(final Repository repository, final Resource resource, final Exception exception, final int requestType) { + this(repository, resource, TRANSFER_ERROR, requestType); + + _exception = exception; + } + + public TransferEvent(final Repository repository, final Resource resource, byte[] buffer, long length, final int requestType) { + this(repository, resource, TRANSFER_PROGRESS, requestType); + + _buffer = buffer; + _length = length; + _totalLength = length; + } + + /** + * @return Returns the resource. + */ + public Resource getResource() { + return _resource; + } + + /** + * @return Returns the exception. + */ + public Exception getException() { + return _exception; + } + + /** + * Returns the request type. + * + * @return Returns the request type. The Request type is one of + * TransferEvent.REQUEST_GET or TransferEvent.REQUEST_PUT + */ + public int getRequestType() { + return _requestType; + } + + /** + * Sets the request type + * + * @param requestType + * The requestType to set. The Request type value should be + * either + * TransferEvent.REQUEST_GET or TransferEvent.REQUEST_PUT. + * @throws IllegalArgumentException when + */ + protected void setRequestType(final int requestType) { + switch (requestType) { + + case REQUEST_PUT: + break; + case REQUEST_GET: + break; + + default: + throw new IllegalArgumentException("Illegal request type: " + requestType); + } + + _requestType = requestType; + } + + /** + * @return Returns the eventType. + */ + public int getEventType() { + return _eventType; + } + + /** + * @param eventType + * The eventType to set. + */ + protected void setEventType(final int eventType) { + switch (eventType) { + + case TRANSFER_INITIATED: + break; + case TRANSFER_STARTED: + break; + case TRANSFER_COMPLETED: + break; + case TRANSFER_PROGRESS: + break; + case TRANSFER_ERROR: + break; + default: + throw new IllegalArgumentException("Illegal event type: " + eventType); + } + + this._eventType = eventType; + } + + /** + * @param _resource + * The resource to set. + */ + protected void setResource(final Resource resource) { + _resource = resource; + } + + /** + * @return Returns the local file. + */ + public File getLocalFile() { + return _localFile; + } + + /** + * @param localFile + * The local file to set. + */ + protected void setLocalFile(File localFile) { + _localFile = localFile; + } + + public byte[] getBuffer() { + return _buffer; + } + + + protected void setBuffer(byte[] buffer) { + _buffer = buffer; + } + + + public long getLength() { + return _length; + } + + + protected void setLength(long length) { + _length = length; + } + + public long getTotalLength() { + return _totalLength; + } + + protected void setTotalLength(long totalLength) { + _totalLength = totalLength; + } + + public void setException(Exception exception) { + _exception = exception; + } + + + +} diff --git a/src/java/fr/jayasoft/ivy/repository/TransferListener.java b/src/java/fr/jayasoft/ivy/repository/TransferListener.java new file mode 100644 index 00000000..8989b41f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/TransferListener.java @@ -0,0 +1,15 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository; + +import java.util.EventListener; + +/** + * Listen to repository transfer + */ +public interface TransferListener extends EventListener { + void transferProgress(TransferEvent evt); +} diff --git a/src/java/fr/jayasoft/ivy/repository/file/FileRepository.java b/src/java/fr/jayasoft/ivy/repository/file/FileRepository.java new file mode 100644 index 00000000..262c0f66 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/file/FileRepository.java @@ -0,0 +1,92 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository.file; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import fr.jayasoft.ivy.repository.AbstractRepository; +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.repository.TransferEvent; +import fr.jayasoft.ivy.util.CopyProgressEvent; +import fr.jayasoft.ivy.util.CopyProgressListener; +import fr.jayasoft.ivy.util.FileUtil; + +public class FileRepository extends AbstractRepository { + private CopyProgressListener _progress = new CopyProgressListener() { + public void start(CopyProgressEvent evt) { + fireTransferStarted(); + } + public void progress(CopyProgressEvent evt) { + fireTransferProgress(evt.getBuffer(), evt.getReadBytes()); + } + public void end(CopyProgressEvent evt) { + fireTransferCompleted(evt.getBuffer(), evt.getReadBytes()); + } + }; + private File _baseDir; + + public FileRepository() { + _baseDir = null; + } + + public FileRepository(File basedir) { + _baseDir = basedir; + } + + public Resource getResource(String source) throws IOException { + return new FileResource(getFile(source)); + } + + public void get(String source, File destination) throws IOException { + fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); + copy(getFile(source), destination); + } + + public void put(File source, String destination) throws IOException { + fireTransferInitiated(getResource(destination), TransferEvent.REQUEST_PUT); + copy(source, getFile(destination)); + } + + private void copy(File src, File destination) throws IOException { + try { + FileUtil.copy(src, destination, _progress); + } catch (IOException ex) { + fireTransferError(ex); + throw ex; + } catch (RuntimeException ex) { + fireTransferError(ex); + throw ex; + } + } + + public List list(String parent) throws IOException { + File dir = getFile(parent); + if (dir.exists() && dir.isDirectory()) { + String[] names = dir.list(); + if (names != null) { + List ret = new ArrayList(names.length); + for (int i = 0; i < names.length; i++) { + ret.add(parent+getFileSeparator()+names[i]); + } + return ret; + } + } + return null; + } + + private File getFile(String source) { + if (_baseDir != null) { + return new File(_baseDir, source); + } else { + return new File(source); + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/repository/file/FileResource.java b/src/java/fr/jayasoft/ivy/repository/file/FileResource.java new file mode 100644 index 00000000..767e017c --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/file/FileResource.java @@ -0,0 +1,39 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository.file; + +import java.io.File; + +import fr.jayasoft.ivy.repository.Resource; + +public class FileResource implements Resource { + private File _file; + + public FileResource(File f) { + _file = f; + } + + public String getName() { + return _file.getPath(); + } + + public long getLastModified() { + return _file.lastModified(); + } + + public long getContentLength() { + return _file.length(); + } + + public boolean exists() { + return _file.exists(); + } + + public String toString() { + return getName(); + } +} diff --git a/src/java/fr/jayasoft/ivy/repository/url/URLRepository.java b/src/java/fr/jayasoft/ivy/repository/url/URLRepository.java new file mode 100644 index 00000000..fdfe0af5 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/url/URLRepository.java @@ -0,0 +1,90 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository.url; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.ListIterator; + +import fr.jayasoft.ivy.repository.AbstractRepository; +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.repository.TransferEvent; +import fr.jayasoft.ivy.url.ApacheURLLister; +import fr.jayasoft.ivy.util.CopyProgressEvent; +import fr.jayasoft.ivy.util.CopyProgressListener; +import fr.jayasoft.ivy.util.FileUtil; + +public class URLRepository extends AbstractRepository { + private final CopyProgressListener _progress = new CopyProgressListener() { + public void start(CopyProgressEvent evt) { + fireTransferStarted(); + } + public void progress(CopyProgressEvent evt) { + fireTransferProgress(evt.getBuffer(), evt.getReadBytes()); + } + public void end(CopyProgressEvent evt) { + fireTransferCompleted(evt.getBuffer(), evt.getReadBytes()); + } + }; + + public Resource getResource(String source) throws IOException { + return new URLResource(new URL(source)); + } + + public void get(String source, File destination) throws IOException { + fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET); + try { + FileUtil.copy(new URL(source), destination, _progress); + } catch (IOException ex) { + fireTransferError(ex); + throw ex; + } catch (RuntimeException ex) { + fireTransferError(ex); + throw ex; + } + } + + public void put(File source, String destination) throws IOException { + throw new UnsupportedOperationException("URL repository is not able to put files for the moment"); + } + + private ApacheURLLister _lister = new ApacheURLLister(); + public List list(String parent) throws IOException { + if (parent.startsWith("http")) { + List urls = _lister.listAll(new URL(parent)); + if (urls != null) { + List ret = new ArrayList(urls.size()); + for (ListIterator iter = urls.listIterator(); iter.hasNext();) { + URL url = (URL)iter.next(); + ret.add(url.toExternalForm()); + } + return ret; + } + } else if (parent.startsWith("file")) { + String path = new URL(parent).getPath(); + File file = new File(path); + if (file.exists() && file.isDirectory()) { + String[] files = file.list(); + List ret = new ArrayList(files.length); + URL context = path.endsWith("/") ? new URL(parent) : new URL(parent+"/"); + for (int i = 0; i < files.length; i++) { + ret.add(new URL(context, files[i]).toExternalForm()); + } + return ret; + } else { + return Collections.EMPTY_LIST; + } + + } + return null; + } + +} diff --git a/src/java/fr/jayasoft/ivy/repository/url/URLResource.java b/src/java/fr/jayasoft/ivy/repository/url/URLResource.java new file mode 100644 index 00000000..ff0a8d56 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/repository/url/URLResource.java @@ -0,0 +1,76 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.repository.url; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.url.URLHandlerRegistry; +import fr.jayasoft.ivy.util.Message; + +public class URLResource implements Resource { + private URL _url; + private boolean _init = false; + private long _lastModified; + private long _contentLength; + private boolean _exists; + + public URLResource(URL url) { + _url = url; + } + + public String getName() { + return _url.toExternalForm(); + } + + public long getLastModified() { + if (!_init) { + init(); + } + return _lastModified; + } + + private void init() { + try { + _lastModified = 0; + _contentLength = 0; + _exists = URLHandlerRegistry.getDefault().isReachable(_url); + if (_exists) { + URLConnection con = _url.openConnection(); + _lastModified = con.getLastModified(); + _contentLength = con.getContentLength(); + } + } catch (IOException e) { + Message.verbose("impossible to open connection to "+_url+":"+e.getMessage()); + _exists = false; + } + _init = true; + } + + public long getContentLength() { + if (!_init) { + init(); + } + return _contentLength; + } + + public boolean exists() { + if (!_init) { + init(); + } + return _exists; + } + + public URL getURL() { + return _url; + } + public String toString() { + return getName(); + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/AbstractResolver.java b/src/java/fr/jayasoft/ivy/resolver/AbstractResolver.java new file mode 100644 index 00000000..f111b0c7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/AbstractResolver.java @@ -0,0 +1,101 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyAware; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.util.Message; + +/** + * This abstract resolver only provides handling for resolver name + */ +public abstract class AbstractResolver implements DependencyResolver, IvyAware { + + /** + * True if parsed ivy files should be validated against xsd, false if they should not, + * null if default behaviour should be used + */ + private Boolean _validate = null; + private String _name; + private Ivy _ivy; + + public Ivy getIvy() { + return _ivy; + } + + public void setIvy(Ivy ivy) { + _ivy = ivy; + } + + public String getName() { + return _name; + } + + public void setName(String name) { + _name = name; + } + + protected boolean doValidate(ResolveData data) { + if (_validate != null) { + return _validate.booleanValue(); + } else { + return data.isValidate(); + } + } + + public boolean isValidate() { + return _validate == null ? true: _validate.booleanValue(); + } + + + public void setValidate(boolean validate) { + _validate = Boolean.valueOf(validate); + } + + public void reportFailure() { + Message.verbose("no failure report implemented by "+getName()); + } + + public void reportFailure(Artifact art) { + Message.verbose("no failure report implemented by "+getName()); + } + + public OrganisationEntry[] listOrganisations() { + return new OrganisationEntry[0]; + } + public ModuleEntry[] listModules(OrganisationEntry org) { + return new ModuleEntry[0]; + } + public RevisionEntry[] listRevisions(ModuleEntry module) { + return new RevisionEntry[0]; + } + + public String toString() { + return getName(); + } + public void dumpConfig() { + Message.verbose("\t"+getName()+" ["+getTypeName()+"]"); + } + + public String getTypeName() { + return getClass().getName(); + } + /** + * Default implementation actually download the artifact + * Subclasses should overwrite this to avoid the download + */ + public boolean exists(Artifact artifact) { + DownloadReport dr = download(new Artifact[] {artifact}, getIvy(), getIvy().getDefaultCache()); + ArtifactDownloadReport adr = dr.getArtifactReport(artifact); + return adr.getDownloadStatus() != DownloadStatus.FAILED; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/AbstractResourceResolver.java b/src/java/fr/jayasoft/ivy/resolver/AbstractResourceResolver.java new file mode 100644 index 00000000..8584f934 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/AbstractResourceResolver.java @@ -0,0 +1,205 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.util.IvyPattern; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public abstract class AbstractResourceResolver extends BasicResolver { + + private List _ivyPatterns = new ArrayList(); // List (String pattern) + private List _artifactPatterns = new ArrayList(); // List (String pattern) + + + public AbstractResourceResolver() { + } + + protected ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data) { + return findResourceUsingPatterns(dd.getDependencyRevisionId(), _ivyPatterns, "ivy", "ivy", "xml", data.getDate()); + } + + protected ResolvedResource findFirstArtifactRef(ModuleDescriptor md, DependencyDescriptor dd, ResolveData data) { + ResolvedResource ret = null; + String[] conf = md.getConfigurationsNames(); + for (int i = 0; i < conf.length; i++) { + Artifact[] artifacts = md.getArtifacts(conf[i]); + for (int j = 0; j < artifacts.length; j++) { + ret = findResourceUsingPatterns(dd.getDependencyRevisionId(), _artifactPatterns, artifacts[j].getName(), artifacts[j].getType(), artifacts[j].getExt(), data.getDate()); + if (ret != null) { + return ret; + } + } + } + return null; + } + + protected ResolvedResource findArtifactRef(Artifact artifact) { + return findResourceUsingPatterns(artifact.getModuleRevisionId(), _artifactPatterns, artifact.getName(), artifact.getType(), artifact.getExt(), null); + } + + protected ResolvedResource findResourceUsingPatterns(ModuleRevisionId moduleRevision, List patternList, String artifact, String type, String ext, Date date) { + ResolvedResource rres = null; + for (Iterator iter = patternList.iterator(); iter.hasNext() && rres == null;) { + String pattern = (String)iter.next(); + rres = findResourceUsingPattern(moduleRevision, pattern, artifact, type, ext, date); + } + return rres; + } + + protected abstract ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, String pattern, String artifact, String type, String ext, Date date); + protected abstract ResolvedResource[] findAll(ModuleRevisionId mrid, String pattern, String artifact, String type, String ext); + protected abstract long get(Resource resource, File ivyTempFile) throws IOException; + + /** + * Output message to log indicating what have been done to look for an artifact which + * has finally not been found + * + * @param artifact the artifact which has not been found + */ + protected void logIvyNotFound(ModuleRevisionId mrid) { + Artifact artifact = new DefaultArtifact(mrid, new Date(), "ivy", "ivy", "xml"); + String revisionToken = mrid.getRevision().startsWith("latest.")?"[any "+mrid.getRevision().substring("latest.".length())+"]":"["+mrid.getRevision()+"]"; + Artifact latestArtifact = new DefaultArtifact(new ModuleRevisionId(mrid.getModuleId(), revisionToken), new Date(), "ivy", "ivy", "xml"); + if (_ivyPatterns.isEmpty()) { + logIvyAttempt("no ivy pattern => no attempt to find ivy file for "+mrid); + } else { + for (Iterator iter = _ivyPatterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String resolvedFileName = IvyPatternHelper.substitute(pattern, artifact); + logIvyAttempt(resolvedFileName); + if (!mrid.isExactRevision()) { + resolvedFileName = IvyPatternHelper.substitute(pattern, latestArtifact); + logIvyAttempt(resolvedFileName); + } + } + } + } + + /** + * Output message to log indicating what have been done to look for an artifact which + * has finally not been found + * + * @param artifact the artifact which has not been found + */ + protected void logArtifactNotFound(Artifact artifact) { + if (_artifactPatterns.isEmpty()) { + logArtifactAttempt(artifact, "no artifact pattern => no attempt to find artifact "+artifact); + } + for (Iterator iter = _artifactPatterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String resolvedFileName = IvyPatternHelper.substitute(pattern, artifact); + logArtifactAttempt(artifact, resolvedFileName); + } + } + + protected Collection findNames(Map tokenValues, String token) { + Collection names = new HashSet(); + names.addAll(findIvyNames(tokenValues, token)); + names.addAll(findArtifactNames(tokenValues, token)); + return names; + } + + protected Collection findIvyNames(Map tokenValues, String token) { + Collection names = new HashSet(); + tokenValues = new HashMap(tokenValues); + tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy"); + tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy"); + tokenValues.put(IvyPatternHelper.EXT_KEY, "xml"); + findTokenValues(names, getIvyPatterns(), tokenValues, token); + getIvy().filterIgnore(names); + return names; + } + + protected Collection findArtifactNames(Map tokenValues, String token) { + Collection names = new HashSet(); + tokenValues = new HashMap(tokenValues); + tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, tokenValues.get(IvyPatternHelper.MODULE_KEY)); + tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar"); + tokenValues.put(IvyPatternHelper.EXT_KEY, "jar"); + findTokenValues(names, getArtifactPatterns(), tokenValues, token); + getIvy().filterIgnore(names); + return names; + } + + // should be overridden by subclasses wanting to have listing features + protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { + } + /** + * example of pattern : ~/Workspace/[module]/[module].ivy.xml + * @param pattern + */ + public void addIvyPattern(String pattern) { + _ivyPatterns.add(pattern); + } + + public void addArtifactPattern(String pattern) { + _artifactPatterns.add(pattern); + } + + public List getIvyPatterns() { + return Collections.unmodifiableList(_ivyPatterns); + } + + public List getArtifactPatterns() { + return Collections.unmodifiableList(_artifactPatterns); + } + protected void setIvyPatterns(List ivyPatterns) { + _ivyPatterns = ivyPatterns; + } + protected void setArtifactPatterns(List artifactPatterns) { + _artifactPatterns = artifactPatterns; + } + + /* + * Methods respecting ivy conf method specifications + */ + public void addConfiguredIvy(IvyPattern p) { + _ivyPatterns.add(p.getPattern()); + } + + public void addConfiguredArtifact(IvyPattern p) { + _artifactPatterns.add(p.getPattern()); + } + + public void dumpConfig() { + super.dumpConfig(); + Message.debug("\t\tivy patterns:"); + for (ListIterator iter = _ivyPatterns.listIterator(); iter.hasNext();) { + String p = (String)iter.next(); + Message.debug("\t\t\t"+p); + } + Message.debug("\t\tartifact patterns:"); + for (ListIterator iter = _artifactPatterns.listIterator(); iter.hasNext();) { + String p = (String)iter.next(); + Message.debug("\t\t\t"+p); + } + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/AbstractURLResolver.java b/src/java/fr/jayasoft/ivy/resolver/AbstractURLResolver.java new file mode 100644 index 00000000..79039b12 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/AbstractURLResolver.java @@ -0,0 +1,540 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultModuleDescriptor; +import fr.jayasoft.ivy.DefaultModuleRevision; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.LatestStrategy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.ResolvedURL; +import fr.jayasoft.ivy.Status; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.repository.url.URLResource; +import fr.jayasoft.ivy.util.CopyProgressEvent; +import fr.jayasoft.ivy.util.CopyProgressListener; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.IvyPattern; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorParser; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorUpdater; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorWriter; + +/** + * @deprecated use RepositoryResolver instead + * @author Xavier Hanin + * + */ +public abstract class AbstractURLResolver extends AbstractResolver { + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + protected String _workspaceName; + /** + * True if the files resolved are dependent of the environment from which they have been resolved, false otherwise. In general, relative paths are dependent of the environment, and absolute paths including machine reference are not. + */ + private boolean _envDependent = true; + + /** + * The latest strategy to use to find latest among several artifacts + */ + private LatestStrategy _latestStrategy; + + private String _latestStrategyName; + + private List _ivyattempts = new ArrayList(); + + + public AbstractURLResolver() { + _workspaceName = Ivy.getLocalHostName(); + } + + public String getWorkspaceName() { + return _workspaceName; + } + + public void setWorkspaceName(String workspaceName) { + _workspaceName = workspaceName; + } + + public boolean isEnvDependent() { + return _envDependent; + } + + public void setEnvDependent(boolean envDependent) { + _envDependent = envDependent; + } + + public LatestStrategy getLatestStrategy() { + if (_latestStrategy == null) { + if (_latestStrategyName != null) { + _latestStrategy = getIvy().getLatestStrategy(_latestStrategyName); + if (_latestStrategy == null) { + Message.error("unknown latest strategy: "+_latestStrategyName); + _latestStrategy = getIvy().getDefaultLatestStrategy(); + } + } else { + _latestStrategy = getIvy().getDefaultLatestStrategy(); + Message.debug(getName()+": no latest strategy defined: using default"); + } + } + return _latestStrategy; + } + + + public void setLatestStrategy(LatestStrategy latestStrategy) { + _latestStrategy = latestStrategy; + } + + public void setLatest(String strategyName) { + _latestStrategyName = strategyName; + } + + public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { + _ivyattempts.clear(); + boolean downloaded = false; + ModuleRevisionId mrid = dd.getDependencyRevisionId(); + // check revision + int index = mrid.getRevision().indexOf("@"); + if (index != -1 && !mrid.getRevision().substring(index+1).equals(_workspaceName)) { + Message.verbose("\t"+getName()+": unhandled revision => "+mrid.getRevision()); + return null; + } + + if (!mrid.isExactRevision() && !acceptLatest()) { + Message.error("latest revisions not handled by "+getClass().getName()+". impossible to resolve "+mrid); + return null; + } + + // look for ivy file + ResolvedURL ivyURL = getIvyURL(mrid, data.getDate()); + URL cachedIvyURL = null; + // get module descriptor + ModuleDescriptor md; + if (ivyURL == null) { + md = DefaultModuleDescriptor.newDefaultInstance(mrid, dd.getAllDependencyArtifactsIncludes()); + ResolvedURL artifactURL = findFirstArtifact(md, mrid, data.getDate()); + if (artifactURL == null) { + Message.verbose("\t"+getName()+": no ivy file nor artifact found for "+mrid); + logIvyNotFound(mrid); + return null; + } else { + Message.verbose("\t"+getName()+": no ivy file found for "+mrid+": using default data"); + logIvyNotFound(mrid); + if (!mrid.isExactRevision()) { + md.setResolvedModuleRevisionId(new ModuleRevisionId(mrid.getModuleId(), artifactURL.getRevision())); + } + } + } else { + Message.verbose("\t"+getName()+": found ivy file for "+mrid); + Message.verbose("\t\t=> "+ivyURL); + // first check if this dependency has not yet been resolved + if (!mrid.isExactRevision()) { + ModuleRevisionId resolvedMrid = new ModuleRevisionId(mrid.getModuleId(), ivyURL.getRevision()); + IvyNode node = data.getNode(resolvedMrid); + if (node != null) { + // this revision has already be resolved : return it + Message.verbose("\t"+getName()+": revision already resolved: "+resolvedMrid); + return node.getModuleRevision(); + } + + // now let's see if we can find it in cache + ResolvedModuleRevision rmr = data.getIvy().findModuleInCache(resolvedMrid, data.getCache(), doValidate(data)); + if (rmr != null) { + Message.verbose("\t"+getName()+": revision in cache: "+resolvedMrid); + return rmr; + } + + } + + + // now download ivy file and parse it + cachedIvyURL = ivyURL.getURL(); // default value: the source itself + try { + // temp file is used to prevent downloading twice + File ivyTempFile = File.createTempFile("ivy", "xml"); + ivyTempFile.deleteOnExit(); + Message.debug("\t"+getName()+": downloading "+ivyURL.getURL()); + FileUtil.copy(ivyURL.getURL(), ivyTempFile, null); + downloaded = true; + try { + cachedIvyURL = ivyTempFile.toURL(); + } catch (MalformedURLException ex) { + // ignored, will not used temp file + Message.warn("malformed url exception for temp file: "+ivyTempFile+": "+ex.getMessage()); + } + } catch (IOException ex) { + // ignored, will not used temp file + Message.warn("problem while downloading ivy file: "+ivyURL+": "+ex.getMessage()); + } + try { + md = XmlModuleDescriptorParser.parseDescriptor(data.getIvy(), cachedIvyURL, new URLResource(ivyURL.getURL()), doValidate(data)); + Message.debug("\t"+getName()+": parsed downloaded ivy file for "+mrid+" parsed="+md.getModuleRevisionId()); + } catch (IOException ex) { + Message.warn("io problem while parsing ivy file: "+ivyURL+": "+ex.getMessage()); + return null; + } + } + md.setResolverName(getName()); + + // check module descriptor revision + if (mrid.getRevision().startsWith("latest.")) { + String askedStatus = mrid.getRevision().substring("latest.".length()); + if (Status.getPriority(askedStatus) < Status.getPriority(md.getStatus())) { + Message.info("\t"+getName()+": unacceptable status => was="+md.getStatus()+" required="+askedStatus); + return null; + } + } else if (!mrid.acceptRevision(md.getModuleRevisionId().getRevision())) { + Message.info("\t"+getName()+": unacceptable revision => was="+md.getModuleRevisionId().getRevision()+" required="+mrid.getRevision()); + return null; + } + + // resolve revision + ModuleRevisionId resolvedMrid = mrid; + if (!resolvedMrid.isExactRevision()) { + resolvedMrid = md.getResolvedModuleRevisionId(); + if (resolvedMrid.getRevision() == null || resolvedMrid.getRevision().length() == 0) { + if (ivyURL.getRevision() == null || ivyURL.getRevision().length() == 0) { + resolvedMrid = new ModuleRevisionId(resolvedMrid.getModuleId(), (_envDependent?"##":"")+DATE_FORMAT.format(data.getDate())+"@"+_workspaceName); + } else { + resolvedMrid = new ModuleRevisionId(resolvedMrid.getModuleId(), ivyURL.getRevision()); + } + } + Message.verbose("\t\t["+resolvedMrid.getRevision()+"] "+mrid.getModuleId()); + } + md.setResolvedModuleRevisionId(resolvedMrid); + + // resolve and check publication date + if (data.getDate() != null) { + long pubDate = getPublicationDate(md, resolvedMrid, data.getDate()); + if (pubDate > data.getDate().getTime()) { + Message.info("\t"+getName()+": unacceptable publication date => was="+new Date(pubDate)+" required="+data.getDate()); + return null; + } else if (pubDate == -1) { + Message.info("\t"+getName()+": impossible to guess publication date: artifact missing for "+mrid); + return null; + } + md.setResolvedPublicationDate(new Date(pubDate)); + } + + try { + if (ivyURL == null) { + // a basic ivy file is written containing default data + XmlModuleDescriptorWriter.write(md, data.getIvy().getIvyFileInCache(data.getCache(), md.getResolvedModuleRevisionId())); + } else { + // copy and update ivy file from source to cache + XmlModuleDescriptorUpdater.update( + cachedIvyURL != null?cachedIvyURL:ivyURL.getURL(), + data.getIvy().getIvyFileInCache(data.getCache(), md.getResolvedModuleRevisionId()), + Collections.EMPTY_MAP, + md.getStatus(), + md.getResolvedModuleRevisionId().getRevision(), + md.getResolvedPublicationDate(), getName()); + } + } catch (Exception e) { + Message.warn("impossible to copy ivy file to cache : "+ivyURL.getURL()); + } + + return new DefaultModuleRevision(this, md, true, downloaded); + } + + public void reportFailure() { + for (ListIterator iter = _ivyattempts.listIterator(); iter.hasNext();) { + String m = (String)iter.next(); + Message.warn("\t\t"+getName()+": tried "+m); + } + } + + protected boolean acceptLatest() { + return true; + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + DownloadReport dr = new DownloadReport(); + for (int i = 0; i < artifacts.length; i++) { + final ArtifactDownloadReport adr = new ArtifactDownloadReport(artifacts[i]); + dr.addArtifactReport(adr); + File archiveFile = ivy.getArchiveFileInCache(cache, artifacts[i]); + if (archiveFile.exists()) { + Message.verbose("\t[NOT REQUIRED] "+artifacts[i]); + adr.setDownloadStatus(DownloadStatus.NO); + adr.setSize(archiveFile.length()); + } else { + ResolvedURL artifactURL = getArtifactURL(artifacts[i]); + if (artifactURL != null) { + long start = System.currentTimeMillis(); + try { + Message.info("downloading "+artifactURL+" ..."); + FileUtil.copy(artifactURL.getURL(), archiveFile, new CopyProgressListener() { + public void start(CopyProgressEvent evt) { + } + public void progress(CopyProgressEvent evt) { + Message.progress(); + } + public void end(CopyProgressEvent evt) { + Message.endProgress(" ("+(evt.getTotalReadBytes() / 1024)+"kB)"); + adr.setSize(evt.getTotalReadBytes()); + } + }); + Message.info("\t[SUCCESSFUL ] "+artifacts[i]+" ("+(System.currentTimeMillis()-start)+"ms)"); + adr.setDownloadStatus(DownloadStatus.SUCCESSFUL); + } catch (Exception ex) { + Message.warn("\t[FAILED ] "+artifacts[i]+" ("+(System.currentTimeMillis()-start)+"ms)"); + adr.setDownloadStatus(DownloadStatus.FAILED); + } + } else { + Message.warn("\t[NOT FOUND ] "+artifacts[i]); + logNotFound(artifacts[i]); + adr.setDownloadStatus(DownloadStatus.FAILED); + } + } + } + return dr; + } + + protected long getPublicationDate(ModuleDescriptor md, ModuleRevisionId mrid, Date date) { + if (md.getPublicationDate() != null) { + return md.getPublicationDate().getTime(); + } + ResolvedURL artifactURL = findFirstArtifact(md, mrid, date); + if (artifactURL != null) { + try { + return artifactURL.getURL().openConnection().getLastModified(); + } catch (IOException e) { + return 0; + } + } + return -1; + } + + public String toString() { + return getName(); + } + + private List _ivyPatterns = new ArrayList(); // List (String pattern) + private List _artifactPatterns = new ArrayList(); // List (String pattern) + + /** + * example of pattern : ~/Workspace/[module]/[module].ivy.xml + * @param pattern + */ + public void addIvyPattern(String pattern) { + _ivyPatterns.add(pattern); + } + + public void addArtifactPattern(String pattern) { + _artifactPatterns.add(pattern); + } + + public List getIvyPatterns() { + return Collections.unmodifiableList(_ivyPatterns); + } + + public List getArtifactPatterns() { + return Collections.unmodifiableList(_artifactPatterns); + } + protected void setIvyPatterns(List ivyPatterns) { + _ivyPatterns = ivyPatterns; + } + protected void setArtifactPatterns(List artifactPatterns) { + _artifactPatterns = artifactPatterns; + } + + /* + * Methods respecting ivy conf method specifications + */ + public void addConfiguredIvy(IvyPattern p) { + _ivyPatterns.add(p.getPattern()); + } + + public void addConfiguredArtifact(IvyPattern p) { + _artifactPatterns.add(p.getPattern()); + } + + protected ResolvedURL getIvyURL(ModuleRevisionId moduleRevision, Date date) { + return findURLUsingPatterns(moduleRevision, _ivyPatterns, "ivy", "ivy", "xml", date); + } + + protected ResolvedURL getArtifactURL(Artifact artifact) { + return findURLUsingPatterns(artifact.getModuleRevisionId(), _artifactPatterns, artifact.getName(), artifact.getType(), artifact.getExt(), null); + } + + private ResolvedURL findURLUsingPatterns(ModuleRevisionId moduleRevision, List patternList, String artifact, String type, String ext, Date date) { + ResolvedURL rurl = null; + for (Iterator iter = patternList.iterator(); iter.hasNext() && rurl == null;) { + String pattern = (String)iter.next(); + rurl = findURLUsingPattern(moduleRevision, pattern, artifact, type, ext, date); + } + return rurl; + } + + protected ResolvedURL findFirstArtifact(ModuleDescriptor md, ModuleRevisionId mrid, Date date) { + ResolvedURL ret = null; + String[] conf = md.getConfigurationsNames(); + for (int i = 0; i < conf.length; i++) { + Artifact[] artifacts = md.getArtifacts(conf[i]); + for (int j = 0; j < artifacts.length; j++) { + ret = findURLUsingPatterns(mrid, _artifactPatterns, artifacts[j].getName(), artifacts[j].getType(), artifacts[j].getExt(), date); + if (ret != null) { + return ret; + } + } + } + return null; + } + + /** + * Output message to log indicating what have been done to look for an artifact which + * has finally not been found + * + * @param artifact the artifact which has not been found + */ + protected void logIvyNotFound(ModuleRevisionId mrid) { + Artifact artifact = new DefaultArtifact(mrid, new Date(), "ivy", "ivy", "xml"); + String revisionToken = mrid.getRevision().startsWith("latest.")?"[any "+mrid.getRevision().substring("latest.".length())+"]":"["+mrid.getRevision()+"]"; + Artifact latestArtifact = new DefaultArtifact(new ModuleRevisionId(mrid.getModuleId(), revisionToken), new Date(), "ivy", "ivy", "xml"); + for (Iterator iter = _ivyPatterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String resolvedFileName = IvyPatternHelper.substitute(pattern, artifact); + Message.verbose("\t\ttried "+resolvedFileName); + _ivyattempts.add(resolvedFileName); + if (!mrid.isExactRevision()) { + resolvedFileName = IvyPatternHelper.substitute(pattern, latestArtifact); + Message.verbose("\t\ttried "+resolvedFileName); + _ivyattempts.add(resolvedFileName); + } + } + } + + /** + * Output message to log indicating what have been done to look for an artifact which + * has finally not been found + * + * @param artifact the artifact which has not been found + */ + protected void logNotFound(Artifact artifact) { + for (Iterator iter = _artifactPatterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String resolvedFileName = IvyPatternHelper.substitute(pattern, artifact); + Message.warn("\t\ttried "+resolvedFileName); + } + } + + protected abstract ResolvedURL findURLUsingPattern(ModuleRevisionId moduleRevision, String pattern, String artifact, String type, String ext, Date date); + + + public OrganisationEntry[] listOrganisations() { + Collection names = findNames(Collections.EMPTY_MAP, IvyPatternHelper.ORGANISATION_KEY); + OrganisationEntry[] ret = new OrganisationEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String org = (String)iter.next(); + ret[i] = new OrganisationEntry(this, org); + } + return ret; + } + + public ModuleEntry[] listModules(OrganisationEntry org) { + Map tokenValues = new HashMap(); + tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); + Collection names = findNames(tokenValues, IvyPatternHelper.MODULE_KEY); + ModuleEntry[] ret = new ModuleEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String name = (String)iter.next(); + ret[i] = new ModuleEntry(org, name); + } + return ret; + } + + public RevisionEntry[] listRevisions(ModuleEntry mod) { + Map tokenValues = new HashMap(); + tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, mod.getOrganisation()); + tokenValues.put(IvyPatternHelper.MODULE_KEY, mod.getModule()); + Collection names = findNames(tokenValues, IvyPatternHelper.REVISION_KEY); + RevisionEntry[] ret = new RevisionEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String name = (String)iter.next(); + ret[i] = new RevisionEntry(mod, name); + } + return ret; + } + + protected Collection findNames(Map tokenValues, String token) { + Collection names = new HashSet(); + names.addAll(findIvyNames(tokenValues, token)); + names.addAll(findArtifactNames(tokenValues, token)); + return names; + } + + protected Collection findIvyNames(Map tokenValues, String token) { + Collection names = new HashSet(); + tokenValues = new HashMap(tokenValues); + tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, "ivy"); + tokenValues.put(IvyPatternHelper.TYPE_KEY, "ivy"); + tokenValues.put(IvyPatternHelper.EXT_KEY, "xml"); + findTokenValues(names, getIvyPatterns(), tokenValues, token); + getIvy().filterIgnore(names); + return names; + } + + protected Collection findArtifactNames(Map tokenValues, String token) { + Collection names = new HashSet(); + tokenValues = new HashMap(tokenValues); + tokenValues.put(IvyPatternHelper.ARTIFACT_KEY, tokenValues.get(IvyPatternHelper.MODULE_KEY)); + tokenValues.put(IvyPatternHelper.TYPE_KEY, "jar"); + tokenValues.put(IvyPatternHelper.EXT_KEY, "jar"); + findTokenValues(names, getArtifactPatterns(), tokenValues, token); + getIvy().filterIgnore(names); + return names; + } + + // should be overwritten by subclasses wanting to have listing features + protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { + } + + protected void findTokenValues(Collection names, List listers, String prefix, List patterns, Map tokenValues, String token) { + for (Iterator iter = patterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues); + for (Iterator iterator = listers.iterator(); iterator.hasNext();) { + URLLister lister = (URLLister)iterator.next(); + String[] values = ResolverHelper.listTokenValues(lister, prefix+partiallyResolvedPattern, token); + if (values != null) { + names.addAll(Arrays.asList(values)); + } + } + } + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/ApacheHttpURLLister.java b/src/java/fr/jayasoft/ivy/resolver/ApacheHttpURLLister.java new file mode 100644 index 00000000..67928535 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/ApacheHttpURLLister.java @@ -0,0 +1,26 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.IOException; +import java.net.URL; +import java.util.List; + +import fr.jayasoft.ivy.url.ApacheURLLister; + +public class ApacheHttpURLLister implements URLLister { + private ApacheURLLister _lister = new ApacheURLLister(); + public boolean accept(String pattern) { + return pattern.startsWith("http"); + } + public List listAll(URL url) throws IOException { + return _lister.listAll(url); + } + + public String toString() { + return "apache http lister"; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java b/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java new file mode 100644 index 00000000..1cde2302 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/BasicResolver.java @@ -0,0 +1,518 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultModuleDescriptor; +import fr.jayasoft.ivy.DefaultModuleRevision; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.IvyNode; +import fr.jayasoft.ivy.LatestStrategy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.Status; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorParser; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorUpdater; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorWriter; + +/** + * @author Xavier Hanin + * + */ +public abstract class BasicResolver extends AbstractResolver { + public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss"); + + protected String _workspaceName; + /** + * True if the files resolved are dependent of the environment from which they have been resolved, false otherwise. In general, relative paths are dependent of the environment, and absolute paths including machine reference are not. + */ + private boolean _envDependent = true; + + /** + * The latest strategy to use to find latest among several artifacts + */ + private LatestStrategy _latestStrategy; + + private String _latestStrategyName; + + private List _ivyattempts = new ArrayList(); + private Map _artattempts = new HashMap(); + + private Boolean _checkmodified = null; + + + public BasicResolver() { + _workspaceName = Ivy.getLocalHostName(); + } + + public String getWorkspaceName() { + return _workspaceName; + } + + public void setWorkspaceName(String workspaceName) { + _workspaceName = workspaceName; + } + + public boolean isEnvDependent() { + return _envDependent; + } + + public void setEnvDependent(boolean envDependent) { + _envDependent = envDependent; + } + + /** + * True if this resolver should check lastmodified date to know if ivy files are up to date. + * @return + */ + public boolean isCheckmodified() { + if (_checkmodified == null) { + if (getIvy() != null) { + String check = getIvy().getVariable("ivy.resolver.default.check.modified"); + return check != null ? Boolean.valueOf(check).booleanValue() : false; + } else { + return false; + } + } else { + return _checkmodified.booleanValue(); + } + } + + + public void setCheckmodified(boolean check) { + _checkmodified = Boolean.valueOf(check); + } + + public LatestStrategy getLatestStrategy() { + if (_latestStrategy == null) { + if (getIvy() != null) { + if (_latestStrategyName != null) { + _latestStrategy = getIvy().getLatestStrategy(_latestStrategyName); + if (_latestStrategy == null) { + Message.error("unknown latest strategy: "+_latestStrategyName); + _latestStrategy = getIvy().getDefaultLatestStrategy(); + } + } else { + _latestStrategy = getIvy().getDefaultLatestStrategy(); + Message.debug(getName()+": no latest strategy defined: using default"); + } + } else { + throw new IllegalStateException("no ivy instance found: impossible to get a latest strategy without ivy instance"); + } + } + return _latestStrategy; + } + + + public void setLatestStrategy(LatestStrategy latestStrategy) { + _latestStrategy = latestStrategy; + } + + public void setLatest(String strategyName) { + _latestStrategyName = strategyName; + } + + public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { + _ivyattempts.clear(); + boolean downloaded = false; + boolean searched = false; + ModuleRevisionId mrid = dd.getDependencyRevisionId(); + // check revision + int index = mrid.getRevision().indexOf("@"); + if (index != -1 && !mrid.getRevision().substring(index+1).equals(_workspaceName)) { + Message.verbose("\t"+getName()+": unhandled revision => "+mrid.getRevision()); + return null; + } + + if (!mrid.isExactRevision() && !acceptLatest()) { + Message.error("latest revisions not handled by "+getClass().getName()+". impossible to resolve "+mrid); + return null; + } + + // if we do not have to check modified and if the revision is exact, we first + // search for it in cache + if (mrid.isExactRevision() && !isCheckmodified()) { + ResolvedModuleRevision rmr = data.getIvy().findModuleInCache(mrid, data.getCache(), doValidate(data)); + if (rmr != null) { + Message.verbose("\t"+getName()+": revision in cache: "+mrid); + return rmr; + } + } + URL cachedIvyURL = null; + ResolvedResource ivyRef = findIvyFileRef(dd, data); + searched = true; + + // get module descriptor + ModuleDescriptor md; + if (ivyRef == null) { + md = DefaultModuleDescriptor.newDefaultInstance(mrid, dd.getAllDependencyArtifactsIncludes()); + ResolvedResource artifactRef = findFirstArtifactRef(md, dd, data); + if (artifactRef == null) { + Message.verbose("\t"+getName()+": no ivy file nor artifact found for "+mrid); + logIvyNotFound(mrid); + String[] conf = md.getConfigurationsNames(); + for (int i = 0; i < conf.length; i++) { + Artifact[] artifacts = md.getArtifacts(conf[i]); + for (int j = 0; j < artifacts.length; j++) { + logArtifactNotFound(artifacts[j]); + } + } + return null; + } else { + Message.verbose("\t"+getName()+": no ivy file found for "+mrid+": using default data"); + logIvyNotFound(mrid); + if (!mrid.isExactRevision()) { + md.setResolvedModuleRevisionId(new ModuleRevisionId(mrid.getModuleId(), artifactRef.getRevision())); + } + } + } else { + Message.verbose("\t"+getName()+": found ivy file for "+mrid); + Message.verbose("\t\t=> "+ivyRef); + + ModuleRevisionId resolvedMrid = mrid; + // first check if this dependency has not yet been resolved + if (!mrid.isExactRevision()) { + resolvedMrid = new ModuleRevisionId(mrid.getModuleId(), ivyRef.getRevision()); + IvyNode node = data.getNode(resolvedMrid); + if (node != null && node.getModuleRevision() != null) { + // this revision has already be resolved : return it + Message.verbose("\t"+getName()+": revision already resolved: "+resolvedMrid); + return searchedRmr(node.getModuleRevision()); + } + } + + // now let's see if we can find it in cache and if it is up to date + ResolvedModuleRevision rmr = data.getIvy().findModuleInCache(resolvedMrid, data.getCache(), doValidate(data)); + if (rmr != null) { + if (!isCheckmodified()) { + Message.verbose("\t"+getName()+": revision in cache: "+resolvedMrid); + return searchedRmr(rmr); + } + long repLastModified = ivyRef.getLastModified(); + long cacheLastModified = rmr.getDescriptor().getLastModified(); + if (rmr.getDescriptor().isDefault() || repLastModified <= cacheLastModified) { + Message.verbose("\t"+getName()+": revision in cache (not updated): "+resolvedMrid); + return searchedRmr(rmr); + } else { + Message.verbose("\t"+getName()+": revision in cache is not up to date: "+resolvedMrid); + } + } + + // now download ivy file and parse it + try { + // temp file is used to prevent downloading twice + File ivyTempFile = File.createTempFile("ivy", "xml"); + ivyTempFile.deleteOnExit(); + Message.debug("\t"+getName()+": downloading "+ivyRef.getResource()); + get(ivyRef.getResource(), ivyTempFile); + downloaded = true; + try { + cachedIvyURL = ivyTempFile.toURL(); + } catch (MalformedURLException ex) { + Message.warn("malformed url exception for temp file: "+ivyTempFile+": "+ex.getMessage()); + return null; + } + } catch (IOException ex) { + Message.warn("problem while downloading ivy file: "+ivyRef.getResource()+": "+ex.getMessage()); + return null; + } + try { + md = XmlModuleDescriptorParser.parseDescriptor(data.getIvy(), cachedIvyURL, ivyRef.getResource(), doValidate(data)); + Message.debug("\t"+getName()+": parsed downloaded ivy file for "+mrid+" parsed="+md.getModuleRevisionId()); + } catch (IOException ex) { + Message.warn("io problem while parsing ivy file: "+ivyRef.getResource()+": "+ex.getMessage()); + return null; + } + } + md.setResolverName(getName()); + + // check module descriptor revision + if (mrid.getRevision().startsWith("latest.")) { + String askedStatus = mrid.getRevision().substring("latest.".length()); + if (Status.getPriority(askedStatus) < Status.getPriority(md.getStatus())) { + Message.info("\t"+getName()+": unacceptable status => was="+md.getStatus()+" required="+askedStatus); + return null; + } + } else if (!mrid.acceptRevision(md.getModuleRevisionId().getRevision())) { + Message.info("\t"+getName()+": unacceptable revision => was="+md.getModuleRevisionId().getRevision()+" required="+mrid.getRevision()); + return null; + } + + // resolve revision + ModuleRevisionId resolvedMrid = mrid; + if (!resolvedMrid.isExactRevision()) { + resolvedMrid = md.getResolvedModuleRevisionId(); + if (resolvedMrid.getRevision() == null || resolvedMrid.getRevision().length() == 0) { + if (ivyRef.getRevision() == null || ivyRef.getRevision().length() == 0) { + resolvedMrid = new ModuleRevisionId(resolvedMrid.getModuleId(), (_envDependent?"##":"")+DATE_FORMAT.format(data.getDate())+"@"+_workspaceName); + } else { + resolvedMrid = new ModuleRevisionId(resolvedMrid.getModuleId(), ivyRef.getRevision()); + } + } + Message.verbose("\t\t["+resolvedMrid.getRevision()+"] "+mrid.getModuleId()); + } + md.setResolvedModuleRevisionId(resolvedMrid); + + // resolve and check publication date + if (data.getDate() != null) { + long pubDate = getPublicationDate(md, dd, data); + if (pubDate > data.getDate().getTime()) { + Message.info("\t"+getName()+": unacceptable publication date => was="+new Date(pubDate)+" required="+data.getDate()); + return null; + } else if (pubDate == -1) { + Message.info("\t"+getName()+": impossible to guess publication date: artifact missing for "+mrid); + return null; + } + md.setResolvedPublicationDate(new Date(pubDate)); + } + + try { + File ivyFile = data.getIvy().getIvyFileInCache(data.getCache(), md.getResolvedModuleRevisionId()); + if (ivyRef == null) { + // a basic ivy file is written containing default data + XmlModuleDescriptorWriter.write(md, ivyFile); + } else { + // copy and update ivy file from source to cache + XmlModuleDescriptorUpdater.update( + cachedIvyURL, + ivyFile, + Collections.EMPTY_MAP, + md.getStatus(), + md.getResolvedModuleRevisionId().getRevision(), + md.getResolvedPublicationDate(), getName()); + long repLastModified = ivyRef.getLastModified(); + if (repLastModified > 0) { + ivyFile.setLastModified(repLastModified); + } + } + } catch (Exception e) { + Message.warn("impossible to copy ivy file to cache : "+ivyRef.getResource()); + } + + return new DefaultModuleRevision(this, md, searched, downloaded); + } + + private ResolvedModuleRevision searchedRmr(final ResolvedModuleRevision rmr) { + // delegate all to previously found except isSearched + return new ResolvedModuleRevision() { + public boolean isSearched() { + return true; + } + + public boolean isDownloaded() { + return rmr.isDownloaded(); + } + + public ModuleDescriptor getDescriptor() { + return rmr.getDescriptor(); + } + + public Date getPublicationDate() { + return rmr.getPublicationDate(); + } + + public ModuleRevisionId getId() { + return rmr.getId(); + } + + public DependencyResolver getResolver() { + return rmr.getResolver(); + } + }; + } + + protected void logIvyAttempt(String attempt) { + _ivyattempts.add(attempt); + Message.verbose("\t\ttried "+attempt); + } + + protected void logArtifactAttempt(Artifact art, String attempt) { + List attempts = (List)_artattempts.get(art); + if (attempts == null) { + attempts = new ArrayList(); + _artattempts.put(art, attempts); + } + attempts.add(attempt); + Message.verbose("\t\ttried "+attempt); + } + + public void reportFailure() { + for (ListIterator iter = _ivyattempts.listIterator(); iter.hasNext();) { + String m = (String)iter.next(); + Message.warn("\t\t"+getName()+": tried "+m); + } + for (Iterator iter = _artattempts.keySet().iterator(); iter.hasNext();) { + Artifact art = (Artifact)iter.next(); + List attempts = (List)_artattempts.get(art); + if (attempts != null) { + Message.warn("\t\t"+getName()+": tried artifact "+art+":"); + for (ListIterator iterator = attempts.listIterator(); iterator.hasNext();) { + String m = (String)iterator.next(); + Message.warn("\t\t\t"+m); + } + } + } + } + + public void reportFailure(Artifact art) { + List attempts = (List)_artattempts.get(art); + if (attempts != null) { + for (ListIterator iter = attempts.listIterator(); iter.hasNext();) { + String m = (String)iter.next(); + Message.warn("\t\t"+getName()+": tried "+m); + } + } + } + + protected boolean acceptLatest() { + return true; + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + _artattempts.clear(); + DownloadReport dr = new DownloadReport(); + for (int i = 0; i < artifacts.length; i++) { + final ArtifactDownloadReport adr = new ArtifactDownloadReport(artifacts[i]); + dr.addArtifactReport(adr); + File archiveFile = ivy.getArchiveFileInCache(cache, artifacts[i]); + if (archiveFile.exists()) { + Message.verbose("\t[NOT REQUIRED] "+artifacts[i]); + adr.setDownloadStatus(DownloadStatus.NO); + adr.setSize(archiveFile.length()); + } else { + ResolvedResource artifactRef = findArtifactRef(artifacts[i]); + if (artifactRef != null) { + long start = System.currentTimeMillis(); + try { + Message.info("downloading "+artifactRef.getResource()+" ..."); + File tmp = ivy.getArchiveFileInCache(cache, + new DefaultArtifact( + artifacts[i].getModuleRevisionId(), + artifacts[i].getPublicationDate(), + artifacts[i].getName(), + artifacts[i].getType(), + artifacts[i].getExt()+".part")); + adr.setSize(get(artifactRef.getResource(), tmp)); + tmp.renameTo(archiveFile); + Message.info("\t[SUCCESSFUL ] "+artifacts[i]+" ("+(System.currentTimeMillis()-start)+"ms)"); + adr.setDownloadStatus(DownloadStatus.SUCCESSFUL); + } catch (Exception ex) { + Message.warn("\t[FAILED ] "+artifacts[i]+" ("+(System.currentTimeMillis()-start)+"ms)"); + adr.setDownloadStatus(DownloadStatus.FAILED); + } + } else { + logArtifactNotFound(artifacts[i]); + adr.setDownloadStatus(DownloadStatus.FAILED); + } + } + } + return dr; + } + + public boolean exists(Artifact artifact) { + ResolvedResource artifactRef = findArtifactRef(artifact); + if (artifactRef != null) { + return artifactRef.getResource().exists(); + } + return false; + } + + protected long getPublicationDate(ModuleDescriptor md, DependencyDescriptor dd, ResolveData data) { + if (md.getPublicationDate() != null) { + return md.getPublicationDate().getTime(); + } + ResolvedResource artifactRef = findFirstArtifactRef(md, dd, data); + if (artifactRef != null) { + return artifactRef.getLastModified(); + } + return -1; + } + + public String toString() { + return getName(); + } + + public OrganisationEntry[] listOrganisations() { + Collection names = findNames(Collections.EMPTY_MAP, IvyPatternHelper.ORGANISATION_KEY); + OrganisationEntry[] ret = new OrganisationEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String org = (String)iter.next(); + ret[i] = new OrganisationEntry(this, org); + } + return ret; + } + + public ModuleEntry[] listModules(OrganisationEntry org) { + Map tokenValues = new HashMap(); + tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); + Collection names = findNames(tokenValues, IvyPatternHelper.MODULE_KEY); + ModuleEntry[] ret = new ModuleEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String name = (String)iter.next(); + ret[i] = new ModuleEntry(org, name); + } + return ret; + } + + public RevisionEntry[] listRevisions(ModuleEntry mod) { + Map tokenValues = new HashMap(); + tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, mod.getOrganisation()); + tokenValues.put(IvyPatternHelper.MODULE_KEY, mod.getModule()); + Collection names = findNames(tokenValues, IvyPatternHelper.REVISION_KEY); + RevisionEntry[] ret = new RevisionEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String name = (String)iter.next(); + ret[i] = new RevisionEntry(mod, name); + } + return ret; + } + + protected abstract Collection findNames(Map tokenValues, String token); + + protected abstract ResolvedResource findIvyFileRef(DependencyDescriptor dd, ResolveData data); + + protected abstract ResolvedResource findFirstArtifactRef(ModuleDescriptor md, DependencyDescriptor dd, ResolveData data); + + protected abstract ResolvedResource findArtifactRef(Artifact artifact); + + protected abstract long get(Resource resource, File ivyTempFile) throws IOException; + + protected abstract void logIvyNotFound(ModuleRevisionId mrid); + + protected abstract void logArtifactNotFound(Artifact artifact); + + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/ChainResolver.java b/src/java/fr/jayasoft/ivy/resolver/ChainResolver.java new file mode 100644 index 00000000..dcf3a1dc --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/ChainResolver.java @@ -0,0 +1,134 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Hanin + * + */ +public class ChainResolver extends AbstractResolver { + private boolean _returnFirst = false; + private List _chain = new ArrayList(); + + public void add(DependencyResolver resolver) { + _chain.add(resolver); + } + + public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { + data = new ResolveData(data, doValidate(data)); + ResolvedModuleRevision ret = null; + + for (Iterator iter = _chain.iterator(); iter.hasNext();) { + DependencyResolver resolver = (DependencyResolver) iter.next(); + ResolvedModuleRevision mr = resolver.getDependency(dd, data); + if (mr != null) { + // check if latest is asked and compare to return the most recent + if (!_returnFirst && !dd.getDependencyRevisionId().isExactRevision()) { + if (ret == null || mr.getPublicationDate().after(ret.getPublicationDate())) { + Message.debug("\tmodule revision kept as younger: "+mr.getId()); + ret = mr; + } else { + Message.debug("\tmodule revision discarded as older: "+mr.getId()); + } + } else { + return mr; + } + } + } + return ret; + } + + public void reportFailure() { + for (Iterator iter = _chain.iterator(); iter.hasNext();) { + DependencyResolver resolver = (DependencyResolver) iter.next(); + resolver.reportFailure(); + } + } + + public void reportFailure(Artifact art) { + for (Iterator iter = _chain.iterator(); iter.hasNext();) { + DependencyResolver resolver = (DependencyResolver) iter.next(); + resolver.reportFailure(art); + } + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + List artifactsToDownload = new ArrayList(Arrays.asList(artifacts)); + DownloadReport report = new DownloadReport(); + for (Iterator iter = _chain.iterator(); iter.hasNext() && !artifactsToDownload.isEmpty();) { + DependencyResolver resolver = (DependencyResolver) iter.next(); + DownloadReport r = resolver.download((Artifact[])artifactsToDownload.toArray(new Artifact[artifactsToDownload.size()]), ivy, cache); + ArtifactDownloadReport[] adr = r.getArtifactsReports(); + for (int i = 0; i < adr.length; i++) { + if (adr[i].getDownloadStatus() != DownloadStatus.FAILED) { + artifactsToDownload.remove(adr[i].getArtifact()); + report.addArtifactReport(adr[i]); + } + } + } + for (Iterator iter = artifactsToDownload.iterator(); iter.hasNext();) { + Artifact art = (Artifact)iter.next(); + ArtifactDownloadReport adr = new ArtifactDownloadReport(art); + adr.setDownloadStatus(DownloadStatus.FAILED); + report.addArtifactReport(adr); + } + return report; + } + public List getResolvers() { + return _chain; + } + public void publish(Artifact artifact, File src) throws IOException { + if (_chain.isEmpty()) { + throw new IllegalStateException("invalid chain resolver with no sub resolver"); + } + ((DependencyResolver)_chain.get(0)).publish(artifact, src); + } + public boolean isReturnFirst() { + return _returnFirst; + } + + public void setReturnFirst(boolean returnFirst) { + _returnFirst = returnFirst; + } + + public void dumpConfig() { + Message.verbose("\t"+getName()+" [chain] "+_chain); + Message.debug("\t\treturn first: "+isReturnFirst()); + for (Iterator iter = _chain.iterator(); iter.hasNext();) { + DependencyResolver r = (DependencyResolver)iter.next(); + Message.debug("\t\t-> "+r.getName()); + } + } + + public boolean exists(Artifact artifact) { + for (Iterator iter = _chain.iterator(); iter.hasNext();) { + DependencyResolver resolver = (DependencyResolver)iter.next(); + if (resolver.exists(artifact)) { + return true; + } + } + return false; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/DualResolver.java b/src/java/fr/jayasoft/ivy/resolver/DualResolver.java new file mode 100644 index 00000000..26c1597b --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/DualResolver.java @@ -0,0 +1,138 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.Date; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.util.Message; + +/** + * DualResolver is used to resolve dependencies with one dependency revolver, called ivy resolver, + * and then download artifacts found in the resolved dependencies from a second dependency resolver, + * called artifact resolver. + * + * It is especially useful with resolvers using repository where there is a lot of artifact, but no + * ivy file, like the maven ibiblio repository. + * + * If no ivy file is found by the ivy resolver, the artifact resolver is used to check if there is + * artifact corresponding to the request (with default ivy file). + * + * For artifact download, however, only the artifact resolver is used. + * + * Exactly two resolvers should be added to this resolver for it to work properly. The first resolver added + * if the ivy resolver, the second is the artifact one. + */ +public class DualResolver extends AbstractResolver { + private DependencyResolver _ivyResolver; + private DependencyResolver _artifactResolver; + + public void add(DependencyResolver resolver) { + if (_ivyResolver == null) { + _ivyResolver = resolver; + } else if (_artifactResolver == null) { + _artifactResolver = resolver; + } else { + throw new IllegalStateException("exactly two resolvers must be added: ivy(1) and artifact(2) one"); + } + } + + + public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { + if (_ivyResolver == null || _artifactResolver == null) { + throw new IllegalStateException("exactly two resolvers must be added: ivy(1) and artifact(2) one"); + } + data = new ResolveData(data, doValidate(data)); + final ResolvedModuleRevision mr = _ivyResolver.getDependency(dd, data); + if (mr == null) { + Message.verbose("ivy resolver didn't find "+dd.getDependencyRevisionId()+": trying with artifact resolver"); + return _artifactResolver.getDependency(dd, data); + } else { + // returns the same ResolvedModuleRevision except that we say that it is dual resolver + // which resolved the dependency, so that it's it that is used for artifact download + // ==> forward all except getResolver method + return new ResolvedModuleRevision() { + public DependencyResolver getResolver() { + return DualResolver.this; + } + + public ModuleRevisionId getId() { + return mr.getId(); + } + + public Date getPublicationDate() { + return mr.getPublicationDate(); + } + + public ModuleDescriptor getDescriptor() { + return mr.getDescriptor(); + } + public boolean isDownloaded() { + return mr.isDownloaded(); + } + public boolean isSearched() { + return mr.isSearched(); + } + }; + } + } + + public void reportFailure() { + _ivyResolver.reportFailure(); + _artifactResolver.reportFailure(); + } + + public void reportFailure(Artifact art) { + _ivyResolver.reportFailure(art); + _artifactResolver.reportFailure(art); + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + return _artifactResolver.download(artifacts, ivy, cache); + } + + public DependencyResolver getArtifactResolver() { + return _artifactResolver; + } + public void setArtifactResolver(DependencyResolver artifactResolver) { + _artifactResolver = artifactResolver; + } + public DependencyResolver getIvyResolver() { + return _ivyResolver; + } + public void setIvyResolver(DependencyResolver ivyResolver) { + _ivyResolver = ivyResolver; + } + public void publish(Artifact artifact, File src) throws IOException { + if ("ivy".equals(artifact.getType())) { + _ivyResolver.publish(artifact, src); + } else { + _artifactResolver.publish(artifact, src); + } + } + + public void dumpConfig() { + if (_ivyResolver == null || _artifactResolver == null) { + throw new IllegalStateException("exactly two resolvers must be added: ivy(1) and artifact(2) one"); + } + Message.verbose("\t"+getName()+" [dual "+_ivyResolver.getName()+" "+_artifactResolver.getName()+"]"); + } + + public boolean exists(Artifact artifact) { + return _artifactResolver.exists(artifact); + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/FileSystemResolver.java b/src/java/fr/jayasoft/ivy/resolver/FileSystemResolver.java new file mode 100644 index 00000000..2ee225b3 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/FileSystemResolver.java @@ -0,0 +1,21 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.repository.file.FileRepository; + +/** + * @author X.Hanin + * + */ +public class FileSystemResolver extends RepositoryResolver { + public FileSystemResolver() { + setRepository(new FileRepository()); + } + public String getTypeName() { + return "file"; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/FileURLLister.java b/src/java/fr/jayasoft/ivy/resolver/FileURLLister.java new file mode 100644 index 00000000..a9df5317 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/FileURLLister.java @@ -0,0 +1,49 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + + +public class FileURLLister implements URLLister { + private File _basedir; + + public FileURLLister() { + this(null); + } + public FileURLLister(File baseDir) { + _basedir = baseDir; + } + + public boolean accept(String pattern) { + return pattern.startsWith("file"); + } + + public List listAll(URL url) throws IOException { + String path = url.getPath(); + File file = _basedir == null ? new File(path) : new File(_basedir, path); + if (file.exists() && file.isDirectory()) { + String[] files = file.list(); + List ret = new ArrayList(files.length); + URL context = url.getPath().endsWith("/") ? url : new URL(url.toExternalForm()+"/"); + for (int i = 0; i < files.length; i++) { + ret.add(new URL(context, files[i])); + } + return ret; + } else { + return Collections.EMPTY_LIST; + } + } + + public String toString() { + return "file lister"; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/IBiblioResolver.java b/src/java/fr/jayasoft/ivy/resolver/IBiblioResolver.java new file mode 100644 index 00000000..225aaf5c --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/IBiblioResolver.java @@ -0,0 +1,101 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.util.Collections; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; + +/** + * IBiblioResolver is a resolver which can be used to resolve dependencies found + * in the ibiblio maven repository, or similar repositories. + * For more flexibility with url and patterns, see {@link fr.jayasoft.ivy.resolver.URLResolver}. + */ +public class IBiblioResolver extends URLResolver { + public static final String DEFAULT_PATTERN = "[module]/[type]s/[artifact]-[revision].[ext]"; + public static final String DEFAULT_ROOT = "http://www.ibiblio.org/maven/"; + private String _root = null; + private String _pattern = null; + + public IBiblioResolver() { + } + + public void setIvy(Ivy ivy) { + super.setIvy(ivy); + ivy.configureRepositories(); + if (_root == null) { + String root = ivy.getVariable("ivy.ibiblio.default.artifact.root"); + if (root != null) { + _root = root; + } else { + _root = DEFAULT_ROOT; + } + } + if (_pattern == null) { + String pattern = ivy.getVariable("ivy.ibiblio.default.artifact.pattern"); + if (pattern != null) { + _pattern = pattern; + } else { + _pattern = DEFAULT_PATTERN; + } + } + updateWholePattern(); + } + + private String getWholePattern() { + return _root + _pattern; + } + public String getPattern() { + return _pattern; + } + public void setPattern(String pattern) { + if (pattern == null) { + throw new NullPointerException("pattern must not be null"); + } + _pattern = pattern; + updateWholePattern(); + } + public String getRoot() { + return _root; + } + /** + * Sets the root of the maven like repository. + * The maven like repository is necessarily an http repository. + * @param root the root of the maven like repository + * @throws IllegalArgumentException if root does not start with "http://" + */ + public void setRoot(String root) { + if (root == null) { + throw new NullPointerException("root must not be null"); + } + if (!root.endsWith("/")) { + _root = root + "/"; + } else { + _root = root; + } + updateWholePattern(); + } + + private void updateWholePattern() { + setArtifactPatterns(Collections.singletonList(getWholePattern())); + } + public void publish(Artifact artifact, File src) { + throw new UnsupportedOperationException("publish not supported by IBiblioResolver"); + } + + public OrganisationEntry[] listOrganisations() { + return null; + } + public ModuleEntry[] listModules(OrganisationEntry org) { + return null; + } + public String getTypeName() { + return "ibiblio"; + } + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/IvyRepResolver.java b/src/java/fr/jayasoft/ivy/resolver/IvyRepResolver.java new file mode 100644 index 00000000..2e7307ca --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/IvyRepResolver.java @@ -0,0 +1,201 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; +import fr.jayasoft.ivy.util.XMLHelper; + +/** + * IvyRepResolver is a resolver which can be used to resolve dependencies found + * in the ivy official repository for ivy files and ibiblio maven repository for the artifacts, + * or similar repositories. + * For more flexibility with url and patterns, see {@link fr.jayasoft.ivy.resolver.URLResolver}. + */ +public class IvyRepResolver extends URLResolver { + public static final String DEFAULT_IVYPATTERN = "[organisation]/[module]/ivy-[revision].xml"; + public static final String DEFAULT_IVYROOT = "http://ivyrep.jayasoft.org/"; + private String _ivyroot = null; + private String _ivypattern = null; + + private String _artroot = null; + private String _artpattern = null; + + public IvyRepResolver() { + } + + public void setIvy(Ivy ivy) { + super.setIvy(ivy); + ivy.configureRepositories(); + if (_ivyroot == null) { + String root = ivy.getVariable("ivy.ivyrep.default.ivy.root"); + if (root != null) { + _ivyroot = root; + } else { + _ivyroot = DEFAULT_IVYROOT; + } + } + if (_ivypattern == null) { + String pattern = ivy.getVariable("ivy.ivyrep.default.ivy.pattern"); + if (pattern != null) { + _ivypattern = pattern; + } else { + _ivypattern = DEFAULT_IVYPATTERN; + } + } + if (_artroot == null) { + String root = ivy.getVariable("ivy.ivyrep.default.artifact.root"); + if (root != null) { + _artroot = root; + } else { + _artroot = IBiblioResolver.DEFAULT_ROOT; + } + } + if (_artpattern == null) { + String pattern = ivy.getVariable("ivy.ivyrep.default.artifact.pattern"); + if (pattern != null) { + _artpattern = pattern; + } else { + _artpattern = IBiblioResolver.DEFAULT_PATTERN; + } + } + updateWholeIvyPattern(); + updateWholeArtPattern(); + } + + private String getWholeIvyPattern() { + return _ivyroot + _ivypattern; + } + private String getWholeArtPattern() { + return _artroot + _artpattern; + } + public String getIvypattern() { + return _ivypattern; + } + public void setIvypattern(String pattern) { + if (pattern == null) { + throw new NullPointerException("pattern must not be null"); + } + _ivypattern = pattern; + updateWholeIvyPattern(); + } + public String getIvyroot() { + return _ivyroot; + } + /** + * Sets the root of the maven like repository. + * The maven like repository is necessarily an http repository. + * @param root the root of the maven like repository + * @throws IllegalArgumentException if root does not start with "http://" + */ + public void setIvyroot(String root) { + if (root == null) { + throw new NullPointerException("root must not be null"); + } + if (!root.endsWith("/")) { + _ivyroot = root + "/"; + } else { + _ivyroot = root; + } + updateWholeIvyPattern(); + } + + private void updateWholeIvyPattern() { + setIvyPatterns(Collections.singletonList(getWholeIvyPattern())); + } + private void updateWholeArtPattern() { + setArtifactPatterns(Collections.singletonList(getWholeArtPattern())); + } + public void publish(Artifact artifact, File src) { + throw new UnsupportedOperationException("publish not supported by IBiblioResolver"); + } + + public String getArtroot() { + return _artroot; + } + + + public String getArtpattern() { + return _artpattern; + } + + + public void setArtpattern(String pattern) { + if (pattern == null) { + throw new NullPointerException("pattern must not be null"); + } + _artpattern = pattern; + updateWholeArtPattern(); + } + + public void setArtroot(String root) { + if (root == null) { + throw new NullPointerException("root must not be null"); + } + if (!root.endsWith("/")) { + _artroot = root + "/"; + } else { + _artroot = root; + } + updateWholeArtPattern(); + } + + public OrganisationEntry[] listOrganisations() { + try { + URL content = new URL(_ivyroot + "content.xml"); + final List ret = new ArrayList(); + XMLHelper.parse(content, null, new DefaultHandler() { + public void startElement(String uri,String localName,String qName,org.xml.sax.Attributes attributes) throws SAXException { + if ("organisation".equals(qName)) { + String org = attributes.getValue("name"); + if (org != null) { + ret.add(new OrganisationEntry(IvyRepResolver.this, org)); + } + } + } + }); + return (OrganisationEntry[])ret.toArray(new OrganisationEntry[ret.size()]); + } catch (MalformedURLException e) { + } catch (Exception e) { + Message.warn("unable to parse content.xml file on ivyrep: "+e.getMessage()); + } + return super.listOrganisations(); + } + + // overwrite parent to use only ivy patterns (and not artifact ones, cause ibiblio is too slow to answer) + public ModuleEntry[] listModules(OrganisationEntry org) { + Map tokenValues = new HashMap(); + tokenValues.put(IvyPatternHelper.ORGANISATION_KEY, org.getOrganisation()); + Collection names = findIvyNames(tokenValues, IvyPatternHelper.MODULE_KEY); + ModuleEntry[] ret = new ModuleEntry[names.size()]; + int i =0; + for (Iterator iter = names.iterator(); iter.hasNext(); i++) { + String name = (String)iter.next(); + ret[i] = new ModuleEntry(org, name); + } + return ret; + } + + public String getTypeName() { + return "ivyrep"; + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/ModuleEntry.java b/src/java/fr/jayasoft/ivy/resolver/ModuleEntry.java new file mode 100644 index 00000000..e8a0de3a --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/ModuleEntry.java @@ -0,0 +1,37 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.DependencyResolver; + + +public class ModuleEntry { + private OrganisationEntry _organisationEntry; + private String _module; + + public ModuleEntry(OrganisationEntry org, String name) { + _organisationEntry = org; + _module = name; + } + + public String getOrganisation() { + return _organisationEntry.getOrganisation(); + } + + public DependencyResolver getResolver() { + return _organisationEntry.getResolver(); + } + + public String getModule() { + return _module; + } + + + public OrganisationEntry getOrganisationEntry() { + return _organisationEntry; + } + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/OrganisationEntry.java b/src/java/fr/jayasoft/ivy/resolver/OrganisationEntry.java new file mode 100644 index 00000000..6af1a2f0 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/OrganisationEntry.java @@ -0,0 +1,27 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.DependencyResolver; + +public class OrganisationEntry { + private DependencyResolver _resolver; + private String _organisation; + + public OrganisationEntry(DependencyResolver resolver, String organisation) { + _resolver = resolver; + _organisation = organisation; + } + + public String getOrganisation() { + return _organisation; + } + + public DependencyResolver getResolver() { + return _resolver; + } + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/RepositoryResolver.java b/src/java/fr/jayasoft/ivy/resolver/RepositoryResolver.java new file mode 100644 index 00000000..2191ac9b --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/RepositoryResolver.java @@ -0,0 +1,154 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.LatestStrategy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.repository.AbstractRepository; +import fr.jayasoft.ivy.repository.Repository; +import fr.jayasoft.ivy.repository.Resource; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class RepositoryResolver extends AbstractResourceResolver { + + private Repository _repository; + + + public RepositoryResolver() { + } + + public Repository getRepository() { + return _repository; + } + + public void setRepository(Repository repository) { + _repository = repository; + } + + public void setName(String name) { + super.setName(name); + if (_repository instanceof AbstractRepository) { + ((AbstractRepository)_repository).setName(name); + } + } + + + protected ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, String pattern, String artifact, String type, String ext, Date date) { + return findResourceUsingPattern(getName(), getRepository(), getLatestStrategy(), mrid, pattern, artifact, type, ext, date); + } + public static ResolvedResource findResourceUsingPattern(String name, Repository repository, LatestStrategy strategy, ModuleRevisionId mrid, String pattern, String artifact, String type, String ext, Date date) { + String resourceName = IvyPatternHelper.substitute(pattern, mrid, artifact, type, ext); + Message.debug("\t trying "+resourceName); + try { + Resource res = repository.getResource(resourceName); + long start = System.currentTimeMillis(); + boolean reachable = res.exists(); + if (reachable) { + return new ResolvedResource(res, mrid.getRevision()); + } else if (!mrid.isExactRevision()) { + ResolvedResource[] rress = ResolverHelper.findAll(repository, mrid, pattern, artifact, type, ext); + if (rress == null) { + Message.debug("\t"+name+": unable to list resources for "+mrid+": pattern="+pattern); + return null; + } else { + for (int i = 0; i < rress.length; i++) { + Message.debug("\t"+name+": found "+rress[i]); + } + } + ResolvedResource found = (ResolvedResource)strategy.findLatest(rress, date); + if (found == null) { + Message.debug("\t"+name+": no resource found for "+mrid+": pattern="+pattern); + } + return found; + } else { + Message.debug("\t"+name+": resource not reachable for "+mrid+": res="+res); + return null; + } + } catch (Exception ex) { + Message.debug("\t"+name+": unable to get resource for "+mrid+": res="+resourceName+": "+ex.getMessage()); + return null; + } + } + + /** + * Returns all resolved res matching the given pattern and matching given mrid, + * or null if no lister is able to handle the given pattern + * + * @param mrid + * @param pattern + * @param artifact + * @param type + * @param ext + * @return + */ + protected ResolvedResource[] findAll(ModuleRevisionId mrid, String pattern, String artifact, String type, String ext) { + return ResolverHelper.findAll(_repository, mrid, pattern, artifact, type, ext); + } + + protected long get(Resource resource, File ivyTempFile) throws IOException { + _repository.get(resource.getName(), ivyTempFile); + return ivyTempFile.length(); + } + + public void publish(Artifact artifact, File src) throws IOException { + String destPattern; + if ("ivy".equals(artifact.getType()) && !getIvyPatterns().isEmpty()) { + destPattern = (String)getIvyPatterns().get(0); + } else { + destPattern = (String)getArtifactPatterns().get(0); + } + String dest = IvyPatternHelper.substitute(destPattern, artifact); + _repository.put(src, dest); + Message.info("\tpublished "+artifact.getName()+" to "+dest); + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + try { + _repository.addTransferListener(ivy); + return super.download(artifacts, ivy, cache); + } finally { + if (ivy != null) { + _repository.removeTransferListener(ivy); + } + } + } + + protected void findTokenValues(Collection names, List patterns, Map tokenValues, String token) { + for (Iterator iter = patterns.iterator(); iter.hasNext();) { + String pattern = (String)iter.next(); + String partiallyResolvedPattern = IvyPatternHelper.substituteTokens(pattern, tokenValues); + String[] values = ResolverHelper.listTokenValues(_repository, partiallyResolvedPattern, token); + if (values != null) { + names.addAll(Arrays.asList(values)); + } + } + } + + public String getTypeName() { + return "repository"; + } + public void dumpConfig() { + super.dumpConfig(); + Message.debug("\t\trepository: "+getRepository()); + } +} diff --git a/src/java/fr/jayasoft/ivy/resolver/ResolvedResource.java b/src/java/fr/jayasoft/ivy/resolver/ResolvedResource.java new file mode 100644 index 00000000..a0d66015 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/ResolvedResource.java @@ -0,0 +1,31 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.ArtifactInfo; +import fr.jayasoft.ivy.repository.Resource; + +public class ResolvedResource implements ArtifactInfo { + private Resource _res; + private String _rev; + public ResolvedResource(Resource res, String rev) { + _res = res; + _rev = rev; + } + public String getRevision() { + return _rev; + } + public Resource getResource() { + return _res; + } + public String toString() { + return _res + " ("+_rev+")"; + } + public long getLastModified() { + return getResource().getLastModified(); + } +} \ No newline at end of file diff --git a/src/java/fr/jayasoft/ivy/resolver/ResolverHelper.java b/src/java/fr/jayasoft/ivy/resolver/ResolverHelper.java new file mode 100644 index 00000000..2ae9aab1 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/ResolverHelper.java @@ -0,0 +1,265 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolvedURL; +import fr.jayasoft.ivy.repository.Repository; +import fr.jayasoft.ivy.util.IvyPatternHelper; +import fr.jayasoft.ivy.util.Message; + +public class ResolverHelper { + // lists all the values a token can take in a pattern, as listed by a given url lister + public static String[] listTokenValues(Repository rep, String pattern, String token) { + String fileSep = rep.getFileSeparator(); + pattern = rep.standardize(pattern); + String tokenString = IvyPatternHelper.getTokenString(token); + int index = pattern.indexOf(tokenString); + if (index == -1) { + Message.verbose("unable to list "+token+" in "+pattern+": token not found in pattern"); + return null; + } + if (((pattern.length() <= index + tokenString.length()) + || fileSep.equals(pattern.substring(index + tokenString.length(), index + tokenString.length() + 1))) + && (index == 0 || fileSep.equals(pattern.substring(index - 1, index)))) { + // the searched token is a whole name + String root = pattern.substring(0, index); + return listAll(rep, root); + } else { + int slashIndex = pattern.substring(0, index).lastIndexOf(fileSep); + String root = slashIndex == -1 ? "" : pattern.substring(0, slashIndex); + + try { + Message.debug("\tusing "+rep+" to list all in "+root); + List all = rep.list(root); + if (all != null) { + Message.debug("\t\tfound "+all.size()+" urls"); + List ret = new ArrayList(all.size()); + int endNameIndex = pattern.indexOf(fileSep, slashIndex + 1); + String namePattern; + if (endNameIndex != -1) { + namePattern = pattern.substring(slashIndex+1, endNameIndex); + } else { + namePattern = pattern.substring(slashIndex + 1); + } + String acceptNamePattern = IvyPatternHelper.substituteToken(namePattern, token, "(.+)"); + Pattern p = Pattern.compile(acceptNamePattern); + for (Iterator iter = all.iterator(); iter.hasNext();) { + String path = (String)iter.next(); + int pathSlashIndex = path.lastIndexOf(fileSep); + String name = pathSlashIndex == -1 ? path : path.substring(pathSlashIndex+1); + Matcher m = p.matcher(name); + if (m.matches()) { + String value = m.group(1); + ret.add(value); + } + } + Message.debug("\t\t"+ret.size()+" matched "+pattern); + return (String[])ret.toArray(new String[ret.size()]); + } else { + return null; + } + } catch (Exception e) { + Message.warn("problem while listing resources in "+root+" with "+rep+": "+e.getMessage()); + return null; + } + } + } + + public static String[] listAll(Repository rep, String parent) { + try { + String fileSep = rep.getFileSeparator(); + Message.debug("\tusing "+rep+" to list all in "+parent); + List all = rep.list(parent); + Message.debug("\t\tfound "+all.size()+" resources"); + List names = new ArrayList(all.size()); + for (Iterator iter = all.iterator(); iter.hasNext();) { + String path = (String)iter.next(); + if (path.endsWith(fileSep)) { + path = path.substring(0, path.length() - 1); + } + int slashIndex = path.lastIndexOf(fileSep); + names.add(path.substring(slashIndex +1)); + } + return (String[])names.toArray(new String[names.size()]); + } catch (Exception e) { + Message.warn("problem while listing resources in "+parent+" with "+rep+": "+e.getMessage()); + return null; + } + } + + public static ResolvedResource[] findAll(Repository rep, ModuleRevisionId mrid, String pattern, String artifact, String type, String ext) { + // substitute all but revision + String partiallyResolvedPattern = IvyPatternHelper.substitute(pattern, new ModuleRevisionId(mrid.getModuleId(), IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY)), artifact, type, ext); + Message.debug("\tlisting all in "+partiallyResolvedPattern); + + String[] revs = listTokenValues(rep, partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY); + if (revs != null) { + Message.debug("\tfound revs: "+Arrays.asList(revs)); + List ret = new ArrayList(revs.length); + String rres = null; + for (int i = 0; i < revs.length; i++) { + if (mrid.acceptRevision(revs[i])) { + rres = IvyPatternHelper.substituteToken(partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY, revs[i]); + try { + ret.add(new ResolvedResource(rep.getResource(rres), revs[i])); + } catch (IOException e) { + Message.warn("impossible to get resource from name listed by repository: "+rres+": "+e.getMessage()); + } + } + } + if (revs.length != ret.size()) { + Message.debug("\tfound resolved res: "+ret); + } + return (ResolvedResource[])ret.toArray(new ResolvedResource[ret.size()]); + } else { + Message.debug("\tno revision found"); + } + return null; + } + + + + +// TODO: remove this code + + + + // lists all the values a token can take in a pattern, as listed by a given url lister + public static String[] listTokenValues(URLLister lister, String pattern, String token) { + pattern = standardize(pattern); + if (lister.accept(pattern)) { + String tokenString = IvyPatternHelper.getTokenString(token); + int index = pattern.indexOf(tokenString); + if (index == -1) { + Message.verbose("unable to list "+token+" in "+pattern+": token not found in pattern"); + return null; + } + if (((pattern.length() <= index + tokenString.length()) + || "/".equals(pattern.substring(index + tokenString.length(), index + tokenString.length() + 1))) + && (index == 0 || "/".equals(pattern.substring(index - 1, index)))) { + // the searched token is a whole name + String root = pattern.substring(0, index); + try { + return listAll(lister, new URL(root)); + } catch (MalformedURLException e) { + Message.warn("malformed url from pattern root: "+root+": "+e.getMessage()); + return null; + } + } else { + int slashIndex = pattern.substring(0, index).lastIndexOf('/'); + String root = slashIndex == -1 ? "" : pattern.substring(0, slashIndex); + + try { + Message.debug("\tusing "+lister+" to list all in "+root); + List all = lister.listAll(new URL(root)); + Message.debug("\t\tfound "+all.size()+" urls"); + List ret = new ArrayList(all.size()); + int endNameIndex = pattern.indexOf('/', slashIndex + 1); + String namePattern; + if (endNameIndex != -1) { + namePattern = pattern.substring(slashIndex+1, endNameIndex); + } else { + namePattern = pattern.substring(slashIndex + 1); + } + String acceptNamePattern = IvyPatternHelper.substituteToken(namePattern, token, "(.+)"); + Pattern p = Pattern.compile(acceptNamePattern); + for (Iterator iter = all.iterator(); iter.hasNext();) { + URL url = (URL)iter.next(); + String path = standardize(url.getPath()); + int pathSlashIndex = path.lastIndexOf('/'); + String name = pathSlashIndex == -1 ? path : path.substring(pathSlashIndex+1); + Matcher m = p.matcher(name); + if (m.matches()) { + String value = m.group(1); + ret.add(value); + } + } + Message.debug("\t\t"+ret.size()+" matched "+pattern); + return (String[])ret.toArray(new String[ret.size()]); + } catch (Exception e) { + Message.warn("problem while listing files in "+root+": "+e.getMessage()); + return null; + } + } + } + return null; + } + + private static String standardize(String path) { + return path.replace('\\', '/'); + } + + public static ResolvedURL[] findAll(URLLister lister, ModuleRevisionId mrid, String pattern, String artifact, String type, String ext) { + if (lister.accept(pattern)) { + // substitute all but revision + String partiallyResolvedPattern = IvyPatternHelper.substitute(pattern, new ModuleRevisionId(mrid.getModuleId(), IvyPatternHelper.getTokenString(IvyPatternHelper.REVISION_KEY)), artifact, type, ext); + Message.debug("\tlisting all in "+partiallyResolvedPattern); + + String[] revs = listTokenValues(lister, partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY); + if (revs != null) { + Message.debug("\tfound revs: "+Arrays.asList(revs)); + List ret = new ArrayList(revs.length); + String resolvedUrl = null; + try { + for (int i = 0; i < revs.length; i++) { + if (mrid.acceptRevision(revs[i])) { + resolvedUrl = IvyPatternHelper.substituteToken(partiallyResolvedPattern, IvyPatternHelper.REVISION_KEY, revs[i]); + ret.add(new ResolvedURL(new URL(resolvedUrl), revs[i])); + } + } + if (revs.length != ret.size()) { + Message.debug("\tfound resolvedURL: "+ret); + } + return (ResolvedURL[])ret.toArray(new ResolvedURL[ret.size()]); + } catch (MalformedURLException e) { + Message.warn("unable to make URL from pattern: "+pattern+" url: "+resolvedUrl+" reason: "+e.getMessage()); + } + } else { + Message.debug("\tno revision found"); + } + } else { + Message.debug("\tno list all done: given lister does not accept pattern: lister="+lister+" pattern="+pattern); + } + return null; + } + + public static String[] listAll(URLLister lister, URL root) { + try { + if (lister.accept(root.toExternalForm())) { + Message.debug("\tusing "+lister+" to list all in "+root); + List all = lister.listAll(root); + Message.debug("\t\tfound "+all.size()+" urls"); + List names = new ArrayList(all.size()); + for (Iterator iter = all.iterator(); iter.hasNext();) { + URL dir = (URL)iter.next(); + String path = dir.getPath(); + if (path.endsWith("/")) { + path = path.substring(0, path.length() - 1); + } + int slashIndex = path.lastIndexOf('/'); + names.add(path.substring(slashIndex +1)); + } + return (String[])names.toArray(new String[names.size()]); + } + return null; + } catch (Exception e) { + Message.warn("problem while listing directories in "+root+": "+e.getMessage()); + return null; + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/RevisionEntry.java b/src/java/fr/jayasoft/ivy/resolver/RevisionEntry.java new file mode 100644 index 00000000..bd41fa42 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/RevisionEntry.java @@ -0,0 +1,46 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.DependencyResolver; + + + +public class RevisionEntry { + private ModuleEntry _moduleEntry; + private String _revision; + + public RevisionEntry(ModuleEntry mod, String name) { + _moduleEntry = mod; + _revision = name; + } + + public ModuleEntry getModuleEntry() { + return _moduleEntry; + } + + + public String getRevision() { + return _revision; + } + + public String getModule() { + return _moduleEntry.getModule(); + } + + public String getOrganisation() { + return _moduleEntry.getOrganisation(); + } + + public OrganisationEntry getOrganisationEntry() { + return _moduleEntry.getOrganisationEntry(); + } + + public DependencyResolver getResolver() { + return _moduleEntry.getResolver(); + } + +} diff --git a/src/java/fr/jayasoft/ivy/resolver/URLLister.java b/src/java/fr/jayasoft/ivy/resolver/URLLister.java new file mode 100644 index 00000000..e6e548e9 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/URLLister.java @@ -0,0 +1,22 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.IOException; +import java.net.URL; +import java.util.List; + +public interface URLLister { + /** + * Indicates if this lister is able to list urls with the given pattern. + * In general, only protocol is used. + * @param pattern + * @return + */ + boolean accept(String pattern); + + List listAll(URL url) throws IOException; +} diff --git a/src/java/fr/jayasoft/ivy/resolver/URLResolver.java b/src/java/fr/jayasoft/ivy/resolver/URLResolver.java new file mode 100644 index 00000000..8211e2b7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/resolver/URLResolver.java @@ -0,0 +1,21 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import fr.jayasoft.ivy.repository.url.URLRepository; + +/** + * This resolver is able to work with any URLs, it handles latest revisions + * with file and http urls only, and it does not handle publishing + */ +public class URLResolver extends RepositoryResolver { + public URLResolver() { + setRepository(new URLRepository()); + } + public String getTypeName() { + return "url"; + } +} diff --git a/src/java/fr/jayasoft/ivy/typedef.properties b/src/java/fr/jayasoft/ivy/typedef.properties new file mode 100644 index 00000000..d5dc9f82 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/typedef.properties @@ -0,0 +1,14 @@ +filesystem = fr.jayasoft.ivy.resolver.FileSystemResolver +chain = fr.jayasoft.ivy.resolver.ChainResolver +ibiblio = fr.jayasoft.ivy.resolver.IBiblioResolver +url = fr.jayasoft.ivy.resolver.URLResolver +dual = fr.jayasoft.ivy.resolver.DualResolver +ivyrep = fr.jayasoft.ivy.resolver.IvyRepResolver + +latest-revision = fr.jayasoft.ivy.latest.LatestRevisionStrategy +latest-lexico = fr.jayasoft.ivy.latest.LatestLexicographicStrategy +latest-time = fr.jayasoft.ivy.latest.LatestTimeStrategy + +fixed-cm = fr.jayasoft.ivy.conflict.FixedConflictManager +latest-cm = fr.jayasoft.ivy.conflict.LatestConflictManager +no-cm = fr.jayasoft.ivy.conflict.NoConflictManager \ No newline at end of file diff --git a/src/java/fr/jayasoft/ivy/url/ApacheURLLister.java b/src/java/fr/jayasoft/ivy/url/ApacheURLLister.java new file mode 100644 index 00000000..336cc5a3 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/ApacheURLLister.java @@ -0,0 +1,154 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.Message; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * Utility class which helps to list urls under a given url. This has been + * tested with Apache 1.3.33 server listing, as the one used at ibiblio, and + * with Apache 2.0.53 server listing, as the one on mirrors.sunsite.dk. + * + * @author Glen Marchesani + * @author Xavier Hanin + * @author John M. Shields + */ +public class ApacheURLLister { + //~ Static variables/initializers ------------------------------------------ + + private static final Pattern PATTERN = + Pattern.compile("]*href=\"([^\"]*)\"[^>]*>(?:<[^>]+>)*?([^<>]+?)(?:<[^>]+>)*?", + Pattern.CASE_INSENSITIVE); + + //~ Methods ---------------------------------------------------------------- + + /** + * Returns a list of sub urls of the given url. The returned list is a list + * of URL. + * + * @param url The base URL from which to retrieve the listing. + * + * @return a list of sub urls of the given url. + * + * @throws IOException If an error occures retrieving the HTML. + */ + public List listAll(URL url) throws IOException { + return retrieveListing(url, true, true); + } + + + /** + * Returns a list of sub 'directories' of the given url. The returned list + * is a list of URL. + * + * @param url The base URL from which to retrieve the listing. + * + * @return a list of sub 'directories' of the given url. + * + * @throws IOException If an error occures retrieving the HTML. + */ + public List listDirectories(URL url) throws IOException { + return retrieveListing(url, false, true); + } + + + /** + * Returns a list of sub 'files' (in opposition to directories) of the + * given url. The returned list is a list of URL. + * + * @param url The base URL from which to retrieve the listing. + * + * @return a list of sub 'files' of the given url. + * + * @throws IOException If an error occures retrieving the HTML. + */ + public List listFiles(URL url) throws IOException { + return retrieveListing(url, true, false); + } + + + /** + * Retrieves a {@link List} of {@link URL}s corresponding to the files + * and/or directories found at the supplied base URL. + * + * @param url The base URL from which to retrieve the listing. + * @param includeFiles If true include files in the returned list. + * @param includeDirectories If true include directories in the returned + * list. + * + * @return A {@link List} of {@link URL}s. + * + * @throws IOException If an error occures retrieving the HTML. + */ + public List retrieveListing(URL url, boolean includeFiles, + boolean includeDirectories) throws IOException { + List urlList = new ArrayList(); + + // add trailing slash for relative urls + if (!url.getPath().endsWith("/")) { + url = new URL(url.getProtocol(), url.getHost(), url.getPort(), + url.getPath() + "/"); + } + + BufferedReader r = + new BufferedReader(new InputStreamReader(URLHandlerRegistry.getDefault() + .openStream(url))); + + String htmlText = FileUtil.readEntirely(r); + + Matcher matcher = PATTERN.matcher(htmlText); + + while (matcher.find()) { + // get the href text and the displayed text + String href = matcher.group(1); + String text = matcher.group(2); + + if ((href == null) || (text == null)) { + // the groups were not found (shouldn't happen, really) + continue; + } + + // absolute href: convert to relative one + if (href.startsWith("/")) { + int slashIndex = href.substring(0, href.length() - 1).lastIndexOf('/'); + href= href.substring(slashIndex+1); + } + + // exclude those where they do not match + // href will never be truncated, text may be truncated by apache + // may have a '.' from either the extension (.jar) or "..>" + int dotIndex = text.indexOf('.'); + + if ( ((dotIndex != -1) && !href.startsWith(text.substring(0, dotIndex))) + || ((dotIndex == -1) && !href.equalsIgnoreCase(text)) ) { + // the href and the text do not "match" + continue; + } + + boolean directory = href.endsWith("/"); + + if ((directory && includeDirectories) + || (!directory && includeFiles)) { + URL child = new URL(url, href); + urlList.add(child); + Message.debug("ApacheURLLister found URL=[" + child + "]."); + } + } + + return urlList; + } +} diff --git a/src/java/fr/jayasoft/ivy/url/BasicURLHandler.java b/src/java/fr/jayasoft/ivy/url/BasicURLHandler.java new file mode 100644 index 00000000..0ea30a67 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/BasicURLHandler.java @@ -0,0 +1,104 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; + +import org.apache.commons.httpclient.HttpStatus; + +import fr.jayasoft.ivy.util.CopyProgressListener; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class BasicURLHandler implements URLHandler { + public boolean isReachable(URL url) { + return isReachable(url, 0); + } + public boolean isReachable(URL url, int timeout) { + try { + URLConnection con = url.openConnection(); + if (con instanceof HttpURLConnection) { + int status = ((HttpURLConnection)con).getResponseCode(); + if (status == HttpStatus.SC_OK) { + return true; + } + if (status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) { + Message.warn("Your proxy requires authentication."); + }else if (String.valueOf(status).startsWith("4")) { + Message.verbose("CLIENT ERROR: "+((HttpURLConnection)con).getResponseMessage()+" url="+url); + }else if (String.valueOf(status).startsWith("5")) { + Message.error("SERVER ERROR: "+((HttpURLConnection)con).getResponseMessage()+" url="+url); + } + Message.debug("HTTP response status: "+status+" url="+url); + } else { + int contentLength = con.getContentLength(); + return contentLength > 0; + } + } catch (UnknownHostException e) { + Message.warn("Host " + e.getMessage() +" not found. url="+url); + Message.info("You probably access the destination server through a proxy server that is not well configured."); + } catch (IOException e) { + Message.error("Server access Error: "+e.getMessage()+" url="+url); + } + return false; + } + + public InputStream openStream(URL url) throws IOException { + URLConnection conn = null; + InputStream inStream = null; + try { + conn = url.openConnection(); + inStream = conn.getInputStream(); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + + byte[] buffer = new byte[4096]; + int len; + while ((len = inStream.read(buffer)) > 0) { + outStream.write(buffer, 0, len); + } + return new ByteArrayInputStream(outStream.toByteArray()); + } + finally { + if (inStream != null) { + inStream.close(); + } + + if (conn != null) { + if (conn instanceof HttpURLConnection) { + //System.out.println("Closing HttpURLConnection"); + ((HttpURLConnection) conn).disconnect(); + } + } + } + } + public void download(URL src, File dest, CopyProgressListener l) throws IOException { + URLConnection srcConn = null; + try { + srcConn = src.openConnection(); + FileUtil.copy(srcConn.getInputStream(), dest, l); + } + finally { + if (srcConn != null) { + if (srcConn instanceof HttpURLConnection) { + //System.out.println("Closing HttpURLConnection"); + ((HttpURLConnection) srcConn).disconnect(); + } + } + } + } +} diff --git a/src/java/fr/jayasoft/ivy/url/HttpClientHandler.java b/src/java/fr/jayasoft/ivy/url/HttpClientHandler.java new file mode 100644 index 00000000..2042f518 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/HttpClientHandler.java @@ -0,0 +1,178 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.UnknownHostException; + +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.UsernamePasswordCredentials; +import org.apache.commons.httpclient.methods.GetMethod; +import org.apache.commons.httpclient.methods.HeadMethod; + +import fr.jayasoft.ivy.util.CopyProgressListener; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class HttpClientHandler implements URLHandler { + private String _realm = null; + private String _host = null; + private String _userName = null; + private String _passwd = null; + + // proxy configuration: obtain from system properties + private int _proxyPort; + + private String _proxyRealm = null; + private String _proxyHost = null; + private String _proxyUserName = null; + private String _proxyPasswd = null; + + public HttpClientHandler() { + configureProxy(); + } + + /** + * @param realm may be null + * @param host may be null + * @param userName may be null + * @param passwd may be null + */ + public HttpClientHandler(String realm, String host, String userName, String passwd) { + _realm = realm; + _host = host; + _userName = userName; + _passwd = passwd; + if (useAuthentication()) { + Message.verbose("using authentication in realm "+_realm+" and host "+_host+" for user "+_userName); + } else { + Message.verbose("no http authentication will be used"); + } + configureProxy(); + } + + private void configureProxy() { + _proxyRealm = null; + //no equivalent for realm in jdk proxy support ? + _proxyHost = System.getProperty("http.proxyHost"); + //TODO constant is better ... + if(useProxy()) { + _proxyPort = Integer.parseInt(System.getProperty("http.proxyPort", "80")); + _proxyUserName = System.getProperty("http.proxyUser"); + _proxyPasswd = System.getProperty("http.proxyPassword"); + //It seems there is no equivalent in HttpClient for + // 'http.nonProxyHosts' property + Message.verbose("proxy configured: host="+_proxyHost+" port="+_proxyPort+" user="+_proxyUserName); + } else { + Message.verbose("no proxy configured"); + } + } + + + + public InputStream openStream(URL url) throws IOException { + GetMethod get = doGet(url); + byte[] response = get.getResponseBody(); + get.releaseConnection(); + + return new ByteArrayInputStream(response); + } + + public void download(URL src, File dest, CopyProgressListener l) throws IOException { + GetMethod get = doGet(src); + FileUtil.copy(get.getResponseBodyAsStream(), dest, l); + get.releaseConnection(); + } + + public boolean isReachable(URL url) { + return isReachable(url, 0); + } + + public boolean isReachable(URL url, int timeout) { + try { + HeadMethod head = doHead(url, timeout); + int status = head.getStatusCode(); + head.releaseConnection(); + if (status == HttpStatus.SC_OK) { + return true; + } + if (status == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) { + Message.error("Your proxy requires authentication."); + }else if (String.valueOf(status).startsWith("4")) { + Message.verbose("CLIENT ERROR: "+head.getStatusText()+" url="+url); + }else if (String.valueOf(status).startsWith("5")) { + Message.warn("SERVER ERROR: "+head.getStatusText()+" url="+url); + } + Message.debug("HTTP response status: "+status +"="+head.getStatusText()+" url="+url); + } catch (HttpException e) { + Message.error("HttpClientHandler: "+e.getMessage()+":" + e.getReasonCode()+"="+e.getReason()+" url="+url); + } catch (UnknownHostException e) { + Message.warn("Host " + e.getMessage() +" not found. url="+url); + Message.info("You probably access the destination server through a proxy server that is not well configured."); + }catch (IOException e) { + Message.error("HttpClientHandler: "+e.getMessage()+" url="+url); + } + return false; + } + + private GetMethod doGet(URL url) throws IOException, HttpException { + HttpClient client = getClient(); + + GetMethod get = new GetMethod(url.toExternalForm()); + get.setDoAuthentication(useAuthentication() || useProxyAuthentication()); + client.executeMethod(get); + return get; + } + + private HeadMethod doHead(URL url, int timeout) throws IOException, HttpException { + HttpClient client = getClient(); + client.setTimeout(timeout); + + HeadMethod head = new HeadMethod(url.toExternalForm()); + head.setDoAuthentication(useAuthentication() || useProxyAuthentication()); + client.executeMethod(head); + return head; + } + + private HttpClient getClient() { + HttpClient client = new HttpClient(); + if (useProxy()) { + client.getHostConfiguration().setProxy(_proxyHost, _proxyPort); + if (useProxyAuthentication()) { + client.getState().setProxyCredentials(_proxyRealm, _proxyHost, + new UsernamePasswordCredentials(_proxyUserName, _proxyPasswd)); + } + } + if (useAuthentication()) { + client.getState().setCredentials( + _realm, + _host, + new UsernamePasswordCredentials(_userName, _passwd) + ); + } + return client; + } + + private boolean useProxy() { + return _proxyHost != null && _proxyHost.trim().length() > 0; + } + private boolean useAuthentication() { + return (_userName != null && _userName.trim().length() > 0); + } + private boolean useProxyAuthentication() { + return (_proxyUserName != null && _proxyUserName.trim().length() > 0); + } +} diff --git a/src/java/fr/jayasoft/ivy/url/URLHandler.java b/src/java/fr/jayasoft/ivy/url/URLHandler.java new file mode 100644 index 00000000..855bacb8 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/URLHandler.java @@ -0,0 +1,41 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import fr.jayasoft.ivy.util.CopyProgressListener; + +/** + * This interface is responsible for handling some URL manipulation + * (stream opening, downloading, check reachability, ...). + * + * @author Xavier Hanin + * + */ +public interface URLHandler { + /** + * Returns true if the given url is reachable, and without + * error code in case of http urls. + * @param url the url to check + * @return true if the given url is reachable + */ + public boolean isReachable(URL url); + /** + * Returns true if the given url is reachable, and without + * error code in case of http urls. + * @param url the url to check + * @param timeout the maximum time before considering an url is not reachable + * a timeout of zero indicates no timeout + * @return true if the given url is reachable + */ + public boolean isReachable(URL url, int timeout); + public InputStream openStream(URL url) throws IOException; + public void download(URL src, File dest, CopyProgressListener l) throws IOException; +} diff --git a/src/java/fr/jayasoft/ivy/url/URLHandlerDispatcher.java b/src/java/fr/jayasoft/ivy/url/URLHandlerDispatcher.java new file mode 100644 index 00000000..0f1c9c5d --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/URLHandlerDispatcher.java @@ -0,0 +1,61 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import fr.jayasoft.ivy.util.CopyProgressListener; + +/** + * This class is used to dispatch downloading requests + * + * @author Xavier Hanin + * + */ +public class URLHandlerDispatcher implements URLHandler { + protected Map _handlers = new HashMap(); + protected URLHandler _default = new BasicURLHandler(); + + public URLHandlerDispatcher() { + } + + public boolean isReachable(URL url) { + return getHandler(url.getProtocol()).isReachable(url); + } + + public boolean isReachable(URL url, int timeout) { + return getHandler(url.getProtocol()).isReachable(url, timeout); + } + + public InputStream openStream(URL url) throws IOException { + return getHandler(url.getProtocol()).openStream(url); + } + + public void download(URL src, File dest, CopyProgressListener l) throws IOException { + getHandler(src.getProtocol()).download(src, dest, l); + } + + public void setDownloader(String protocol, URLHandler downloader) { + _handlers.put(protocol, downloader); + } + + public URLHandler getHandler(String protocol) { + URLHandler downloader = (URLHandler)_handlers.get(protocol); + return downloader == null ? _default : downloader; + } + + public URLHandler getDefault() { + return _default; + } + public void setDefault(URLHandler default1) { + _default = default1; + } +} diff --git a/src/java/fr/jayasoft/ivy/url/URLHandlerRegistry.java b/src/java/fr/jayasoft/ivy/url/URLHandlerRegistry.java new file mode 100644 index 00000000..bec49588 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/url/URLHandlerRegistry.java @@ -0,0 +1,65 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import fr.jayasoft.ivy.util.Message; + +/** + * @author Xavier Hanin + * + */ +public class URLHandlerRegistry { + private static URLHandler _default = new BasicURLHandler(); + + public static URLHandler getDefault() { + return _default; + } + public static void setDefault(URLHandler def) { + _default = def; + } + + /** + * This method is used to get appropriate http downloader + * dependening on Jakarta Commons HttpClient + * availability in classpath, or simply use jdk url + * handling in other cases. + * + * @param realm + * @param host + * @param userName + * @param passwd + * + * @return most accurate http downloader + */ + public static URLHandler getHttp(String realm, String host, String userName, String passwd) { + try { + Class.forName("org.apache.commons.httpclient.HttpClient"); + Message.verbose("jakarta commons httpclient detected: using it for http downloading"); + return new HttpClientHandler(realm, host, userName, passwd); + } catch (ClassNotFoundException e) { + Message.verbose("jakarta commons httpclient not found: no authentication will be done"); + return new BasicURLHandler(); + } + } + + /** + * This method is used to get appropriate http downloader + * dependening on Jakarta Commons HttpClient + * availability in classpath, or simply use jdk url + * handling in other cases. + * + * @param realm + * @param host + * @param userName + * @param passwd + * + * @return most accurate http downloader + */ + public static URLHandler getHttp() { + return getHttp(null, null, null, null); + } + +} diff --git a/src/java/fr/jayasoft/ivy/util/Configurator.java b/src/java/fr/jayasoft/ivy/util/Configurator.java new file mode 100644 index 00000000..c009f03e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/Configurator.java @@ -0,0 +1,335 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Stack; + +/** + * Ant 1.6.1 like Configurator + * + * This configurator is used to configure elements (initialised with setRoot) + * using the behaviour defined by ant for its tasks. + * + * Example (based on Ant Example) : + * Configurator conf = new Configurator(); + * conf.typeDef("buildpath", "Sample$BuildPath"); + * conf.typeDef("xinterface", "Sample$XInterface"); + * + * Sample.MyFileSelector mfs = new Sample.MyFileSelector(); + * conf.setRoot(mfs); + * conf.startCreateChild("buildpath"); + * conf.setAttribute("path", "."); + * conf.setAttribute("url", "abc"); + * conf.startCreateChild("xinterface"); + * conf.setAttribute("count", "4"); + * conf.endCreateChild(); // xinterface + * conf.endCreateChild(); // buildpath + * + * @author x.hanin + * + */ +public class Configurator { + private static class ObjectDescriptor { + private Object _obj; + private String _objName; + private Map _createMethods = new HashMap(); + private Map _addMethods = new HashMap(); + private Map _addConfiguredMethods = new HashMap(); + private Map _setMethods = new HashMap(); + private Map _typeAddMethods = new HashMap(); + private Map _typeAddConfiguredMethods = new HashMap(); + + public ObjectDescriptor(Object object, String objName) { + _obj = object; + _objName = objName; + Method[] methods = object.getClass().getMethods(); + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName().startsWith("create") + && m.getParameterTypes().length == 0 + && !Void.TYPE.equals(m.getReturnType())) { + String name = StringUtils.uncapitalize(m.getName().substring("create".length())); + if (name.length() == 0) { + continue; + } + addCreateMethod(name, m); + } else if (m.getName().startsWith("addConfigured") + && m.getParameterTypes().length == 1 + && Void.TYPE.equals(m.getReturnType())) { + String name = StringUtils.uncapitalize(m.getName().substring("addConfigured".length())); + if (name.length() == 0) { + addAddConfiguredMethod(m); + } + addAddConfiguredMethod(name, m); + } else if (m.getName().startsWith("add") + && !m.getName().startsWith("addConfigured") + && m.getParameterTypes().length == 1 + && Void.TYPE.equals(m.getReturnType())) { + String name = StringUtils.uncapitalize(m.getName().substring("add".length())); + if (name.length() == 0) { + addAddMethod(m); + } + addAddMethod(name, m); + } else if (m.getName().startsWith("set") + && m.getParameterTypes().length == 1 + && Void.TYPE.equals(m.getReturnType())) { + String name = StringUtils.uncapitalize(m.getName().substring("set".length())); + if (name.length() == 0) { + continue; + } + addSetMethod(name, m); + } + } + } + public void addCreateMethod(String name, Method m) { + _createMethods.put(name, m); + } + public void addAddMethod(String name, Method m) { + _addMethods.put(name, m); + } + public void addAddConfiguredMethod(String name, Method m) { + _addConfiguredMethods.put(name, m); + } + private void addAddMethod(Method m) { + _typeAddMethods.put(m.getParameterTypes()[0], m); + } + private void addAddConfiguredMethod(Method m) { + _typeAddConfiguredMethods.put(m.getParameterTypes()[0], m); + } + public void addSetMethod(String name, Method m) { + _setMethods.put(name, m); + } + public Object getObject() { + return _obj; + } + public Method getCreateMethod(String name) { + return (Method)_createMethods.get(name); + } + public Method getAddMethod(String name) { + return (Method)_addMethods.get(name); + } + public Method getAddConfiguredMethod(String name) { + return (Method)_addConfiguredMethods.get(name); + } + public Method getAddMethod(Class type) { + return getTypeMatchingMethod(type, _typeAddMethods); + } + public Method getAddConfiguredMethod(Class type) { + return getTypeMatchingMethod(type, _typeAddConfiguredMethods); + } + private Method getTypeMatchingMethod(Class type, Map typeMethods) { + Method m = (Method)typeMethods.get(type); + if (m != null) { + return m; + } + for (Iterator iter = typeMethods.keySet().iterator(); iter.hasNext();) { + Class clss = (Class)iter.next(); + if (clss.isAssignableFrom(type)) { + return (Method)typeMethods.get(clss); + } + } + return null; + } + public Method getSetMethod(String name) { + return (Method)_setMethods.get(name); + } + public String getObjectName() { + return _objName; + } + } + private Map _typedefs = new HashMap(); + + // stack in which the top is current configured object descriptor + private Stack _objectStack = new Stack(); + + private static final List TRUE_VALUES = Arrays.asList(new String[] {"true", "yes", "on"}); + + public void typeDef(String name, String className) throws ClassNotFoundException { + typeDef(name, Class.forName(className)); + } + + public void typeDef(String name, Class clazz) { + _typedefs.put(name, clazz); + } + + public void setRoot(Object root) { + if (root == null) { + throw new NullPointerException(); + } + _objectStack.clear(); + setCurrent(root, null); + } + + public void clear() { + _objectStack.clear(); + } + + private void setCurrent(Object object, String name) { + _objectStack.push(new ObjectDescriptor(object, name)); + } + + public Object startCreateChild(String name) { + if (_objectStack.isEmpty()) { + throw new IllegalStateException("set root before creating child"); + } + ObjectDescriptor parentOD = (ObjectDescriptor)_objectStack.peek(); + Object parent = parentOD.getObject(); + Object child = null; + Class childClass = (Class)_typedefs.get(name); + Method addChild = null; + try { + if (childClass != null) { + addChild = parentOD.getAddMethod(childClass); + if (addChild != null) { + child = childClass.newInstance(); + addChild.invoke(parent, new Object[] {child}); + setCurrent(child, name); + return child; + } + addChild = parentOD.getAddConfiguredMethod(childClass); + if (addChild != null) { + child = childClass.newInstance(); + setCurrent(child, name); + return child; + } + } else { + addChild = parentOD.getCreateMethod(name); + if (addChild != null) { + child = addChild.invoke(parent, new Object[0]); + setCurrent(child, name); + return child; + } + addChild = parentOD.getAddMethod(name); + if (addChild != null) { + childClass = addChild.getParameterTypes()[0]; + child = childClass.newInstance(); + addChild.invoke(parent, new Object[] {child}); + setCurrent(child, name); + return child; + } + addChild = parentOD.getAddConfiguredMethod(name); + if (addChild != null) { + childClass = addChild.getParameterTypes()[0]; + child = childClass.newInstance(); + setCurrent(child, name); + return child; + } + } + } catch (InstantiationException ex) { + throw new IllegalArgumentException("no default constructor on "+childClass+" for adding "+name+" on "+parent.getClass()); + } catch (Exception ex) { + IllegalArgumentException iae = new IllegalArgumentException("bad method found for "+name+" on "+parent.getClass()); + iae.initCause(ex); + throw iae; + } + throw new IllegalArgumentException("no appropriate method found for adding "+name+" on "+parent.getClass()); + } + + public void setAttribute(String attributeName, String value) { + if (_objectStack.isEmpty()) { + throw new IllegalStateException("set root before setting attribute"); + } + ObjectDescriptor od = (ObjectDescriptor)_objectStack.peek(); + Method m = od.getSetMethod(attributeName); + if (m == null) { + throw new IllegalArgumentException("no set method found for "+attributeName+" on "+od.getObject().getClass()); + } + Object convertedValue = null; + Class paramClass = m.getParameterTypes()[0]; + try { + if (paramClass.equals(String.class)) { + convertedValue = value; + } else if (paramClass.equals(Boolean.class) || paramClass.equals(boolean.class)) { + convertedValue = Boolean.valueOf(TRUE_VALUES.contains(value)); + } else if (paramClass.equals(Character.class) || paramClass.equals(char.class)) { + convertedValue = new Character(value.length() > 0 ? value.charAt(0) : ' '); + } else if (paramClass.equals(Short.class) || paramClass.equals(short.class)) { + convertedValue = Short.valueOf(value); + } else if (paramClass.equals(Integer.class) || paramClass.equals(int.class)) { + convertedValue = Integer.valueOf(value); + } else if (paramClass.equals(Long.class) || paramClass.equals(long.class)) { + convertedValue = Long.valueOf(value); + } else if (paramClass.equals(Class.class)) { + convertedValue = Class.forName(value); + } else { + convertedValue = paramClass.getConstructor(new Class[] {String.class}).newInstance(new Object[] {value}); + } + } catch (Exception ex) { + IllegalArgumentException iae = new IllegalArgumentException("impossible to convert "+value+" to "+paramClass+" for setting "+attributeName+" on "+od.getObject().getClass()); + iae.initCause(ex); + throw iae; + } + try { + m.invoke(od.getObject(), new Object[] {convertedValue}); + } catch (Exception ex) { + IllegalArgumentException iae = new IllegalArgumentException("impossible to set "+attributeName+" to "+convertedValue+" on "+od.getObject().getClass()); + iae.initCause(ex); + throw iae; + } + } + + public void addText(String text) { + if (_objectStack.isEmpty()) { + throw new IllegalStateException("set root before adding text"); + } + ObjectDescriptor od = (ObjectDescriptor)_objectStack.peek(); + try { + od.getObject().getClass().getMethod("addText", new Class[] {String.class}).invoke(od.getObject(), new Object[] {text}); + } catch (Exception ex) { + IllegalArgumentException iae = new IllegalArgumentException("impossible to add text on "+od.getObject().getClass()); + iae.initCause(ex); + throw iae; + } + } + + /** + * + * @return the finished child + */ + public Object endCreateChild() { + if (_objectStack.isEmpty()) { + throw new IllegalStateException("set root before ending child"); + } + ObjectDescriptor od = (ObjectDescriptor)_objectStack.pop(); + if (_objectStack.isEmpty()) { + _objectStack.push(od); // back to previous state + throw new IllegalStateException("cannot end root"); + } + ObjectDescriptor parentOD = (ObjectDescriptor)_objectStack.peek(); + String name = od.getObjectName(); + Class childClass = (Class)_typedefs.get(name); + Method m = null; + if (childClass != null) { + m = parentOD.getAddConfiguredMethod(childClass); + } else { + m = parentOD.getAddConfiguredMethod(name); + } + try { + if (m != null) { + m.invoke(parentOD.getObject(), new Object[] {od.getObject()}); + } + return od.getObject(); + } catch (Exception ex) { + IllegalArgumentException iae = new IllegalArgumentException("impossible to add configured child for "+name+" on "+parentOD.getObject().getClass()); + iae.initCause(ex); + throw iae; + } + } + + public Object getCurrent() { + return _objectStack.isEmpty()?null:((ObjectDescriptor)_objectStack.peek()).getObject(); + } + + public int getDepth() { + return _objectStack.size(); + } +} diff --git a/src/java/fr/jayasoft/ivy/util/CopyProgressEvent.java b/src/java/fr/jayasoft/ivy/util/CopyProgressEvent.java new file mode 100644 index 00000000..24553321 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/CopyProgressEvent.java @@ -0,0 +1,41 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +/** + * Event reporting a stream copy progression + */ +public class CopyProgressEvent { + private long _totalReadBytes; + private byte[] _buffer; + private int _readBytes; + + public CopyProgressEvent() { + } + public CopyProgressEvent(byte[] buffer, int read, long total) { + update(buffer, read, total); + } + public CopyProgressEvent(byte[] buffer, long total) { + update(buffer, 0, total); + } + protected CopyProgressEvent update(byte[] buffer, int read, long total) { + _buffer = buffer; + _readBytes = read; + _totalReadBytes = total; + return this; + } + public long getTotalReadBytes() { + return _totalReadBytes; + } + public byte[] getBuffer() { + return _buffer; + } + + public int getReadBytes() { + return _readBytes; + } + +} diff --git a/src/java/fr/jayasoft/ivy/util/CopyProgressListener.java b/src/java/fr/jayasoft/ivy/util/CopyProgressListener.java new file mode 100644 index 00000000..1b3d6ee9 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/CopyProgressListener.java @@ -0,0 +1,15 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +/** + * Listen to copy progression + */ +public interface CopyProgressListener { + void start(CopyProgressEvent evt); + void progress(CopyProgressEvent evt); + void end(CopyProgressEvent evt); +} diff --git a/src/java/fr/jayasoft/ivy/util/DefaultMessageImpl.java b/src/java/fr/jayasoft/ivy/util/DefaultMessageImpl.java new file mode 100644 index 00000000..7e31d60f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/DefaultMessageImpl.java @@ -0,0 +1,36 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +public class DefaultMessageImpl implements MessageImpl { + private int _level = Message.MSG_INFO; + + /** + * @param level + */ + public DefaultMessageImpl(int level) { + _level = level; + } + + public void log(String msg, int level) { + if (level <= _level) { + System.out.println(msg); + } + } + + public void progress() { + System.out.print("."); + } + + public void endProgress(String msg) { + System.out.println(msg); + } + + public int getLevel() { + return _level; + } +} diff --git a/src/java/fr/jayasoft/ivy/util/FileUtil.java b/src/java/fr/jayasoft/ivy/util/FileUtil.java new file mode 100644 index 00000000..ebe3592e --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/FileUtil.java @@ -0,0 +1,89 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; + +import fr.jayasoft.ivy.url.URLHandlerRegistry; + +/** + * @author x.hanin + * + */ +public class FileUtil { + // tried some other values with empty files... seems to be the best one (512 * 1024 is very bad) + // 8 * 1024 is also the size used by ant in its FileUtils... maybe they've done more study about it ;-) + private static final int BUFFER_SIZE = 8 * 1024; + public static void copy(File src, File dest, CopyProgressListener l) throws IOException { + copy(new FileInputStream(src), dest, l); + dest.setLastModified(src.lastModified()); + } + + public static void copy(URL src, File dest, CopyProgressListener l) throws IOException { + URLHandlerRegistry.getDefault().download(src, dest, l); + } + + public static void copy(InputStream src, File dest, CopyProgressListener l) throws IOException { + if (dest.getParentFile() != null) { + dest.getParentFile().mkdirs(); + } + copy(src, new FileOutputStream(dest), l); + } + + public static void copy(InputStream src, OutputStream dest, CopyProgressListener l) throws IOException { + try { + CopyProgressEvent evt = null; + if (l != null) { + evt = new CopyProgressEvent(); + } + byte buffer[]=new byte[BUFFER_SIZE]; + int c; + long total = 0; + + if (l != null) { + l.start(evt); + } + while( (c = src.read(buffer)) != -1 ) { + dest.write(buffer, 0, c); + total += c; + if (l != null) { + l.progress(evt.update(buffer, c, total)); + } + } + if (l != null) { + l.end(evt.update(buffer, 0, total)); + } + } finally { + try { + src.close(); + } catch (IOException ex) { + dest.close(); + throw ex; + } + dest.close(); + } + } + + public static String readEntirely(BufferedReader in) throws IOException { + StringBuffer buf = new StringBuffer(); + + String line = in.readLine(); + while (line != null) { + buf.append(line + "\n"); + line = in.readLine(); + } + in.close(); + return buf.toString(); + } + +} diff --git a/src/java/fr/jayasoft/ivy/util/IvyPattern.java b/src/java/fr/jayasoft/ivy/util/IvyPattern.java new file mode 100644 index 00000000..a2a1ce03 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/IvyPattern.java @@ -0,0 +1,22 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +/** + * @author x.hanin + * + */ +public class IvyPattern { + private String _pattern; + + public String getPattern() { + return _pattern; + } + + public void setPattern(String pattern) { + _pattern = pattern; + } +} diff --git a/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java b/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java new file mode 100644 index 00000000..0265187f --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/IvyPatternHelper.java @@ -0,0 +1,168 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.ModuleRevisionId; + +/** + * @author x.hanin + * + */ +public class IvyPatternHelper { + public static final String CONF_KEY = "conf"; + public static final String TYPE_KEY = "type"; + public static final String EXT_KEY = "ext"; + public static final String ARTIFACT_KEY = "artifact"; + public static final String REVISION_KEY = "revision"; + public static final String MODULE_KEY = "module"; + public static final String ORGANISATION_KEY = "organisation"; + + private static final Pattern VAR_PATTERN = Pattern.compile("\\$\\{(.*?)\\}"); + private static final Pattern TOKEN_PATTERN = Pattern.compile("\\[(.*?)\\]"); + + public static String substitute(String pattern, ModuleRevisionId moduleRevision) { + return substitute(pattern, + moduleRevision.getOrganisation(), + moduleRevision.getName(), + moduleRevision.getRevision(), + "ivy", + "ivy", + "xml", + null); + } + public static String substitute(String pattern, ModuleRevisionId moduleRevision, String artifact, String type, String ext) { + return substitute(pattern, + moduleRevision.getOrganisation(), + moduleRevision.getName(), + moduleRevision.getRevision(), + artifact, + type, + ext, + null); + } + public static String substitute(String pattern, Artifact artifact) { + return substitute(pattern, + artifact.getModuleRevisionId().getOrganisation(), + artifact.getModuleRevisionId().getName(), + artifact.getModuleRevisionId().getRevision(), + artifact.getName(), + artifact.getType(), + artifact.getExt(), + null); + } + + public static String substitute(String pattern, String org, String module, String revision, String artifact, String type, String ext) { + return substitute(pattern, org, module, revision, artifact, type, ext, null); + } + + public static String substitute(String pattern, String org, String module, String revision, String artifact, String type, String ext, String conf) { + Map tokens = new HashMap(); + tokens.put(ORGANISATION_KEY, org==null?"":org); + tokens.put(MODULE_KEY, module==null?"":module); + tokens.put(REVISION_KEY, revision==null?"":revision); + tokens.put(ARTIFACT_KEY, artifact==null?module:artifact); + tokens.put(TYPE_KEY, type==null?"jar":type); + tokens.put(EXT_KEY, ext==null?"jar":ext); + tokens.put(CONF_KEY, conf==null?"default":conf); + return substituteTokens(pattern, tokens); + } + + public static String substitute(String pattern, Map variables, Map tokens) { + return substituteTokens(substituteVariables(pattern, variables), tokens); + } + + public static String substituteVariables(String pattern, Map variables) { + // if you supply null, null is what you get + if (pattern == null) { + return null; + } + + Matcher m = VAR_PATTERN.matcher(pattern); + + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String var = m.group(1); + String val = (String)variables.get(var); + if (val != null) { + val = substituteVariables(val, variables); + } else { + val = m.group(); + } + m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "\\\\\\$")); + } + m.appendTail(sb); + + return sb.toString(); + } + + public static String substituteTokens(String pattern, Map tokens) { + Matcher m = TOKEN_PATTERN.matcher(pattern); + + StringBuffer sb = new StringBuffer(); + while (m.find()) { + String var = m.group(1); + String val = (String)tokens.get(var); + if (val == null) { + val = m.group(); + } + m.appendReplacement(sb, val.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\$", "\\\\\\$")); + } + m.appendTail(sb); + + return sb.toString(); + } + + public static String substituteVariable(String pattern, String variable, String value) { + StringBuffer buf = new StringBuffer(pattern); + substituteVariable(buf, variable, value); + return buf.toString(); + } + + public static void substituteVariable(StringBuffer buf, String variable, String value) { + String from = "${"+variable+"}"; + int fromLength = from.length(); + for (int index = buf.indexOf(from); index != -1; index = buf.indexOf(from, index)) { + buf.replace(index, index + fromLength, value); + } + } + + public static String substituteToken(String pattern, String token, String value) { + StringBuffer buf = new StringBuffer(pattern); + substituteToken(buf, token, value); + return buf.toString(); + } + + public static void substituteToken(StringBuffer buf, String token, String value) { + String from = getTokenString(token); + int fromLength = from.length(); + for (int index = buf.indexOf(from); index != -1; index = buf.indexOf(from, index)) { + buf.replace(index, index + fromLength, value); + } + } + public static String getTokenString(String token) { + return "["+token+"]"; + } + + public static void main(String[] args) { + String pattern = "[organisation]/[module]/build/archives/[type]s/[artifact]-[revision].[ext]"; + System.out.println("pattern= "+pattern); + System.out.println("resolved= "+substitute(pattern, "jayasoft", "Test", "1.0", "test", "jar", "jar")); + + Map variables = new HashMap(); + variables.put("test", "mytest"); + variables.put("test2", "${test}2"); + pattern = "${test} ${test2} ${nothing}"; + System.out.println("pattern= "+pattern); + System.out.println("resolved= "+substituteVariables(pattern, variables)); + } + +} diff --git a/src/java/fr/jayasoft/ivy/util/Message.java b/src/java/fr/jayasoft/ivy/util/Message.java new file mode 100644 index 00000000..5974d665 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/Message.java @@ -0,0 +1,123 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +/** + * @author x.hanin + * + */ +public class Message { + // messages level copied from ant project, to avoid dependency on ant + /** Message priority of "error". */ + public static final int MSG_ERR = 0; + /** Message priority of "warning". */ + public static final int MSG_WARN = 1; + /** Message priority of "information". */ + public static final int MSG_INFO = 2; + /** Message priority of "verbose". */ + public static final int MSG_VERBOSE = 3; + /** Message priority of "debug". */ + public static final int MSG_DEBUG = 4; + + private static MessageImpl _impl = new DefaultMessageImpl(2); + + private static StringBuffer _problems = new StringBuffer(); + + private static boolean _showProgress = true; + + public static void init(MessageImpl impl) { + _impl = impl; + showInfo(); + } + + private static void showInfo() { + Properties props = new Properties(); + InputStream module = Message.class.getResourceAsStream("/module.properties"); + if (module != null) { + try { + props.load(module); + info(":: Ivy "+props.getProperty("version")+" - "+props.getProperty("date")+" :: http://ivy.jayasoft.org/ ::"); + } catch (IOException e) { + info(":: Ivy non official version :: http://ivy.jayasoft.org/ ::"); + } + } else { + info(":: Ivy non official version :: http://ivy.jayasoft.org/ ::"); + } + } + + public static void debug(String msg) { + if (_impl != null) { + _impl.log(msg, MSG_DEBUG); + } else { + System.err.println(msg); + } + } + public static void verbose(String msg) { + if (_impl != null) { + _impl.log(msg, MSG_VERBOSE); + } else { + System.err.println(msg); + } + } + public static void info(String msg) { + if (_impl != null) { + _impl.log(msg, MSG_INFO); + } else { + System.err.println(msg); + } + } + public static void warn(String msg) { + if (_impl != null) { + _impl.log("WARN: "+msg, MSG_WARN); + } else { + System.err.println(msg); + } + _problems.append("\tWARN: "+msg).append("\n"); + } + public static void error(String msg) { + if (_impl != null) { + _impl.log("ERROR: "+msg, MSG_VERBOSE); + } else { + System.err.println(msg); + } + _problems.append("\tERROR: "+msg).append("\n"); + } + public static void sumupProblems() { + if (_problems.length() > 0) { + info("\n:: problems summary ::"); + info(_problems.toString()); + info("\t--- USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS ---"); + _problems = new StringBuffer(); + } + } + + public static void progress() { + if (_showProgress) { + _impl.progress(); + } + } + + public static void endProgress() { + endProgress(""); + } + + public static void endProgress(String msg) { + if (_showProgress) { + _impl.endProgress(msg); + } + } + + public static boolean isShowProgress() { + return _showProgress; + } + public static void setShowProgress(boolean progress) { + _showProgress = progress; + } +} diff --git a/src/java/fr/jayasoft/ivy/util/MessageImpl.java b/src/java/fr/jayasoft/ivy/util/MessageImpl.java new file mode 100644 index 00000000..7ccf74c7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/MessageImpl.java @@ -0,0 +1,13 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +public interface MessageImpl { + public void log(String msg, int level); + public void progress(); + public void endProgress(String msg); +} diff --git a/src/java/fr/jayasoft/ivy/util/StringUtils.java b/src/java/fr/jayasoft/ivy/util/StringUtils.java new file mode 100644 index 00000000..90699ab7 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/StringUtils.java @@ -0,0 +1,27 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +/** + * Convenient class used only for uncapitalization + * Usually use commons lang but here we do not want to have such + * a dependency for only one feature + * + * @author X. Hanin + * + */ +public class StringUtils { + public static String uncapitalize(String string) { + if (string == null || string.length() == 0) { + return string; + } + if (string.length() == 1) { + return string.toLowerCase(); + } + return string.substring(0,1).toLowerCase() + string.substring(1); + } + +} diff --git a/src/java/fr/jayasoft/ivy/util/XMLHelper.java b/src/java/fr/jayasoft/ivy/util/XMLHelper.java new file mode 100644 index 00000000..e9d11042 --- /dev/null +++ b/src/java/fr/jayasoft/ivy/util/XMLHelper.java @@ -0,0 +1,85 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.url.URLHandlerRegistry; + +public abstract class XMLHelper { + private static SAXParserFactory _validatingFactory = SAXParserFactory.newInstance(); + + private static SAXParserFactory _factory = SAXParserFactory.newInstance(); + + static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; + + private static boolean _canUseSchemaValidation = true; + + static { + // _factory.setNamespaceAware(true); + _validatingFactory.setValidating(true); + } + + private static SAXParser newSAXParser(URL schema, InputStream schemaStream) throws ParserConfigurationException, SAXException { + if (!_canUseSchemaValidation || schema == null) { + return _factory.newSAXParser(); + } + try { + SAXParser parser = _validatingFactory.newSAXParser(); + parser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream); + return parser; + } catch (SAXNotRecognizedException ex) { + System.err.println("WARNING: problem while setting JAXP validating property on SAXParser... XML validation will not be done: " + ex.getMessage()); + _canUseSchemaValidation = false; + return _factory.newSAXParser(); + } + } + + // IMPORTANT: validation errors are only notified to the given handler, and + // do not cause exception + // implement warning error and fatalError methods in handler to be informed + // of validation errors + public static void parse(URL xmlURL, URL schema, DefaultHandler handler) throws SAXException, IOException, ParserConfigurationException { + InputStream xmlStream = null; + InputStream schemaStream = null; + try { + if (schema != null) { + schemaStream = URLHandlerRegistry.getDefault().openStream(schema); + } + xmlStream = URLHandlerRegistry.getDefault().openStream(xmlURL); + XMLHelper.newSAXParser(schema, schemaStream).parse(xmlStream, handler); + } finally { + if (xmlStream != null) { + try { + xmlStream.close(); + } catch (IOException ex) { + } + } + if (schemaStream != null) { + try { + schemaStream.close(); + } catch (IOException ex) { + } + } + } + } + +} diff --git a/src/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParser.java b/src/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParser.java new file mode 100644 index 00000000..e6adf2bf --- /dev/null +++ b/src/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParser.java @@ -0,0 +1,160 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.util.Configurator; +import fr.jayasoft.ivy.util.Message; + +/** + * @author Hanin + * + */ +public class XmlIvyConfigurationParser extends DefaultHandler { + private Configurator _configurator = new Configurator(); + private List _configuratorTags = Arrays.asList(new String[] {"resolvers", "latest-strategies", "conflict-managers"}); + + private Ivy _ivy; + + private String _defaultResolver; + private String _defaultCM; + private String _defaultLatest; + + public XmlIvyConfigurationParser(Ivy ivy) { + _ivy = ivy; + } + + public void parse(URL configuration) throws ParseException, IOException { + // put every type definition from ivy to configurator + Map typeDefs = _ivy.getTypeDefs(); + for (Iterator iter = typeDefs.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + _configurator.typeDef(name, (Class)typeDefs.get(name)); + } + + InputStream stream = null; + try { + stream = configuration.openStream(); + SAXParserFactory.newInstance().newSAXParser().parse( + stream, + this); + } catch (IOException e) { + throw e; + } catch (Exception e) { + ParseException pe = new ParseException("failed to configure with "+configuration+": "+e.getMessage(), 0); + pe.initCause(e); + throw pe; + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + try { + if (_configurator.getCurrent() != null) { + _configurator.startCreateChild(qName); + for (int i=0; i 0) { + return last; + } else { + Message.debug("impossible to get date for "+_res+": using 'now'"); + return System.currentTimeMillis(); + } + } + + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + try { + if ("ivy-module".equals(qName)) { + String version = attributes.getValue("version"); + if (!ALLOWED_VERSIONS.contains(version)) { + addError("invalid version "+version); + throw new SAXException("invalid version "+version); + } + } else if ("info".equals(qName)) { + _state = INFO; + String org = _ivy.substitute(attributes.getValue("organisation")); + String module = _ivy.substitute(attributes.getValue("module")); + String revision = _ivy.substitute(attributes.getValue("revision")); + _md.setModuleRevisionId(ModuleRevisionId.newInstance(org, module, revision)); + String status = _ivy.substitute(attributes.getValue("status")); + _md.setStatus(status == null ? Status.DEFAULT_STATUS : status); + _md.setResolverName(_ivy.substitute(attributes.getValue("resolver"))); + _md.setDefault(Boolean.valueOf(_ivy.substitute(attributes.getValue("default"))).booleanValue()); + String pubDate = _ivy.substitute(attributes.getValue("publication")); + if (pubDate != null && pubDate.length() > 0) { + try { + _md.setPublicationDate(Ivy.DATE_FORMAT.parse(pubDate)); + } catch (ParseException e) { + addError("invalid publication date format: "+pubDate); + _md.setPublicationDate(getDefaultPubDate()); + } + } else { + _md.setPublicationDate(getDefaultPubDate()); + } + } else if ("license".equals(qName)) { + _md.addLicense(new License(attributes.getValue("name"), attributes.getValue("url"))); + } else if ("description".equals(qName)) { + _md.setHomePage(attributes.getValue("homepage")); + } else if ("configurations".equals(qName)) { + _state = CONF; + } else if ("publications".equals(qName)) { + _state = PUB; + _artifactsDeclared = true; + checkConfigurations(); + } else if ("dependencies".equals(qName)) { + _state = DEP; + _defaultConf = attributes.getValue("defaultconf"); + _defaultConf = _defaultConf == null ? "*->*" : _defaultConf; + checkConfigurations(); + } else if ("conflicts".equals(qName)) { + _state = CONFLICT; + checkConfigurations(); + } else if ("artifact".equals(qName)) { + if (_state == PUB) { + // this is a published artifact + String ext = attributes.getValue("ext"); + ext = ext != null?ext:attributes.getValue("type"); + _artifact = new MDArtifact(_md, attributes.getValue("name"), attributes.getValue("type"), ext); + String confs = attributes.getValue("conf"); + // only add confs if they are specified. if they aren't, endElement will handle this + // only if there are no conf defined in sub elements + if (confs != null && confs.length() > 0) { + String[] conf; + if ("*".equals(confs)) { + conf = _md.getConfigurationsNames(); + } else { + conf = confs.split(","); + } + for (int i = 0; i < conf.length; i++) { + _artifact.addConfiguration(conf[i].trim()); + _md.addArtifact(conf[i].trim(), _artifact); + } + } + } else if (_state == DEP) { + // this is an artifact asked for a particular dependency + addDependencyArtifactsIncludes(attributes); + } else if (_validate) { + addError("artifact tag found in invalid tag: "+_state); + } + } else if ("include".equals(qName)) { + addDependencyArtifactsIncludes(attributes); + } else if ("exclude".equals(qName)) { + addDependencyArtifactsExcludes(attributes); + } else if ("dependency".equals(qName)) { + String org = _ivy.substitute(attributes.getValue("org")); + if (org == null) { + org = _md.getModuleRevisionId().getOrganisation(); + } + boolean force = Boolean.valueOf(attributes.getValue("force")).booleanValue(); + String name = _ivy.substitute(attributes.getValue("name")); + String rev = _ivy.substitute(attributes.getValue("rev")); + _dd = new DefaultDependencyDescriptor(_md, ModuleRevisionId.newInstance(org, name, rev), force); + _md.addDependency(_dd); + String confs = attributes.getValue("conf"); + if (confs != null && confs.length() > 0) { + parseDepsConfs(confs); + } + } else if ("conf".equals(qName)) { + String conf = attributes.getValue("name"); + switch (_state) { + case CONF: + String visibility = attributes.getValue("visibility"); + String ext = attributes.getValue("extends"); + _md.addConfiguration(new Configuration( + conf, + Configuration.Visibility.getVisibility(visibility == null ? "public":visibility), + attributes.getValue("description"), + ext==null?null:ext.split(","))); + break; + case PUB: + if ("*".equals(conf)) { + String[] confs = _md.getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + _artifact.addConfiguration(confs[i]); + _md.addArtifact(confs[i], _artifact); + } + } else { + _artifact.addConfiguration(conf); + _md.addArtifact(conf, _artifact); + } + break; + case DEP: + _conf = conf; + String mappeds = attributes.getValue("mapped"); + if (mappeds != null) { + String[] mapped = mappeds.split(","); + for (int i = 0; i < mapped.length; i++) { + _dd.addDependencyConfiguration(_conf, mapped[i].trim()); + } + } + break; + case ARTIFACT_INCLUDE: + case ARTIFACT_EXCLUDE: + _dad.addConfiguration(conf); + break; + default: + if (_validate) { + addError("conf tag found in invalid tag: "+_state); + } + break; + } + } else if ("mapped".equals(qName)) { + _dd.addDependencyConfiguration(_conf, attributes.getValue("name")); + } else if ("manager".equals(qName) && _state == CONFLICT) { + String org = _ivy.substitute(attributes.getValue("org")); + org = org == null ? ".*" : org; + String mod = _ivy.substitute(attributes.getValue("module")); + mod = mod == null ? ".*" : mod; + ConflictManager cm; + String name = _ivy.substitute(attributes.getValue("name")); + String rev = _ivy.substitute(attributes.getValue("rev")); + if (rev != null) { + String[] revs = rev.split(","); + for (int i = 0; i < revs.length; i++) { + revs[i] = revs[i].trim(); + } + cm = new FixedConflictManager(revs); + } else if (name != null) { + cm = _ivy.getConflictManager(name); + if (cm == null) { + addError("unknown conflict manager: "+name); + return; + } + } else { + addError("bad conflict manager: no name nor rev"); + return; + } + _md.addConflictManager(new ModuleId(org, mod), cm); + } else if (_validate && _state != INFO) { + addError("unknwon tag "+qName); + } + } catch (Exception ex) { + addError("exception while parsing: "+ex.getMessage()); + throw new SAXException("exception while parsing: "+ex.getMessage(), ex); + } + } + + private void parseDepsConfs(String confs) { + String[] conf = confs.split(";"); + for (int i = 0; i < conf.length; i++) { + String[] ops = conf[i].split("->"); + if (ops.length == 1) { + if (ops[0].indexOf(",") != -1) { + addError("invalid conf "+conf[i]+" for "+_dd.getDependencyRevisionId()+": mapping required in a list of confs"); + } else { + _dd.addDependencyConfiguration(ops[0].trim(), ops[0].trim()); + } + } else if (ops.length == 2) { + String[] modConfs = ops[0].split(","); + String[] depConfs = ops[1].split(","); + for (int j = 0; j < modConfs.length; j++) { + for (int k = 0; k < depConfs.length; k++) { + _dd.addDependencyConfiguration(modConfs[j].trim(), depConfs[k].trim()); + } + } + } else { + addError("invalid conf "+conf[i]+" for "+_dd.getDependencyRevisionId()); + } + } + } + + private void addDependencyArtifactsIncludes(Attributes attributes) { + _state = ARTIFACT_INCLUDE; + addDependencyArtifact(attributes, true); + } + + private void addDependencyArtifactsExcludes(Attributes attributes) { + _state = ARTIFACT_EXCLUDE; + addDependencyArtifact(attributes, false); + } + + private void addDependencyArtifact(Attributes attributes, boolean includes) { + String name = attributes.getValue("name"); + name = name == null ? ".*" : name; + String type = attributes.getValue("type"); + type = type == null ? ".*" : type; + String ext = attributes.getValue("ext"); + ext = ext != null?ext:type; + _dad = new DefaultDependencyArtifactDescriptor(_dd, name, type, ext, includes); + String confs = attributes.getValue("conf"); + // only add confs if they are specified. if they aren't, endElement will handle this + // only if there are no conf defined in sub elements + if (confs != null && confs.length() > 0) { + String[] conf; + if ("*".equals(confs)) { + conf = _md.getConfigurationsNames(); + } else { + conf = confs.split(","); + } + for (int i = 0; i < conf.length; i++) { + _dad.addConfiguration(conf[i].trim()); + } + } + } + + public void endElement(String uri, String localName, String qName) throws SAXException { + if (_state == PUB && "artifact".equals(qName) && _artifact.getConfigurations().length == 0) { + String[] confs = _md.getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + _artifact.addConfiguration(confs[i]); + _md.addArtifact(confs[i], _artifact); + } + } else if ("configurations".equals(qName)) { + checkConfigurations(); + } else if ((_state == ARTIFACT_INCLUDE && ("artifact".equals(qName) || "include".equals(qName))) + || (_state == ARTIFACT_EXCLUDE && "exclude".equals(qName))){ + _state = DEP; + if (_dad.getConfigurations().length == 0) { + String[] confs = _md.getConfigurationsNames(); + for (int i = 0; i < confs.length; i++) { + _dad.addConfiguration(confs[i]); + } + } + } else if ("dependency".equals(qName) && _dd.getModuleConfigurations().length == 0) { + parseDepsConfs(_defaultConf); + } + } + + private void checkConfigurations() { + if (_md.getConfigurations().length == 0) { + _md.addConfiguration(new Configuration("default")); + } + } + + public void warning(SAXParseException ex) { + Message.warn("xml parsing: " + + getLocationString(ex)+": "+ + ex.getMessage()); + } + + public void error(SAXParseException ex) { + Message.error("xml parsing: " + + getLocationString(ex)+": "+ + ex.getMessage()); + } + + public void fatalError(SAXParseException ex) throws SAXException { + addError("[Fatal Error] "+ + getLocationString(ex)+": "+ + ex.getMessage()); + } + + /** Returns a string of the location. */ + private String getLocationString(SAXParseException ex) { + StringBuffer str = new StringBuffer(); + + String systemId = ex.getSystemId(); + if (systemId != null) { + int index = systemId.lastIndexOf('/'); + if (index != -1) + systemId = systemId.substring(index + 1); + str.append(systemId); + } else if (_res != null) { + str.append(_res.toString()); + } + str.append(':'); + str.append(ex.getLineNumber()); + str.append(':'); + str.append(ex.getColumnNumber()); + + return str.toString(); + + } // getLocationString(SAXParseException):String + + private void addError(String msg) { + if (_res != null) { + _errors.add(msg+" in "+_res+"\n"); + } else { + _errors.add(msg+"\n"); + } + } + + public static void main(String[] args) throws Exception { + System.out.println(parseDescriptor(new Ivy(), new File("test/xml/module1/module1.ivy.xml").toURL(), true)); + } +} diff --git a/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorUpdater.java b/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorUpdater.java new file mode 100644 index 00000000..c90a69fc --- /dev/null +++ b/src/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorUpdater.java @@ -0,0 +1,225 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.URL; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.util.XMLHelper; + +/** + * Used to update ivy files. Uses ivy file as source and not ModuleDescriptor to preserve + * as much as possible the original syntax + * + * @author Hanin + * + */ +public class XmlModuleDescriptorUpdater { + public static String LINE_SEPARATOR = System.getProperty("line.separator"); + /** + * used to copy a module descriptor xml file (also known as ivy file) + * and update the revisions of its dependencies, its status and revision + * + * @param srcURL the url of the source module descriptor file + * @param destFile The file to which the updated module descriptor should be output + * @param resolvedRevisions Map from ModuleId of dependencies to new revision (as String) + * @param status the new status, null to keep the old one + * @param revision the new revision, null to keep the old one + */ + public static void update(URL srcURL, File destFile, final Map resolvedRevisions, final String status, final String revision, final Date pubdate) + throws IOException, SAXException { + update(srcURL, destFile, resolvedRevisions, status, revision, pubdate, null); + } + + /** + * used to copy a module descriptor xml file (also known as ivy file) + * and update the revisions of its dependencies, its status and revision + * + * @param srcURL the url of the source module descriptor file + * @param destFile The file to which the updated module descriptor should be output + * @param resolvedRevisions Map from ModuleId of dependencies to new revision (as String) + * @param status the new status, null to keep the old one + * @param revision the new revision, null to keep the old one + */ + public static void update(URL srcURL, File destFile, final Map resolvedRevisions, final String status, + final String revision, final Date pubdate, final String resolverName) + throws IOException, SAXException { + if (destFile.getParentFile() != null) { + destFile.getParentFile().mkdirs(); + } + FileOutputStream fos = null; + try { + fos = new FileOutputStream(destFile); + final PrintWriter out = new PrintWriter(fos); + copyHeader(srcURL, out); + XMLHelper.parse(srcURL, null, new DefaultHandler() { + // never print *ln* cause \n is found in copied characters stream + // nor do we need do handle indentation, original one is maintained except for attributes + + private String _organisation = null; + private String _justOpen = null; // used to know if the last open tag was empty, to adjust termination with /> instead of > + public void startElement(String uri, String localName, + String qName, Attributes attributes) + throws SAXException { + if (_justOpen != null) { + out.print(">"); + } + if ("info".equals(qName)) { + _organisation = attributes.getValue("organisation"); + out.print(""); + _justOpen = null; + } + for (int i = start; i < start + length; i++) { + out.print(ch[i]); + } + } + + public void endElement(String uri, String localName, + String qName) throws SAXException { + if (qName.equals(_justOpen)) { + out.print("/>"); + } else { + out.print(""); + } + _justOpen = null; + } + + public void endDocument() throws SAXException { + out.flush(); + out.close(); + } + + public void warning(SAXParseException e) throws SAXException { + throw e; + } + public void error(SAXParseException e) throws SAXException { + throw e; + } + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + }); + } catch (IOException ex) { + throw ex; + } catch (ParserConfigurationException e) { + IllegalStateException ise = new IllegalStateException("impossible to update "+srcURL+": parser problem"); + ise.initCause(e); + throw ise; + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + } + } + } + } + + /** + * Copy xml header from src url ivy file to given printwriter + * In fact, copies everything before "); + out.println("\t"); + out.println(""); + } finally { + out.close(); + } + } +} diff --git a/src/java/fr/jayasoft/ivy/xml/XmlReportParser.java b/src/java/fr/jayasoft/ivy/xml/XmlReportParser.java new file mode 100644 index 00000000..1de6ecef --- /dev/null +++ b/src/java/fr/jayasoft/ivy/xml/XmlReportParser.java @@ -0,0 +1,85 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.report.XmlReportOutputter; + +public class XmlReportParser { + public Artifact[] getArtifacts(ModuleId moduleId, String conf, File cache) throws ParseException, IOException { + File report = new File(cache, XmlReportOutputter.getReportFileName(moduleId, conf)); + if (!report.exists()) { + throw new IllegalStateException("no report file found for "+moduleId+" "+conf+" in "+cache); + } + final Collection artifacts = new ArrayList(); + try { + SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + saxParser.parse(report, new DefaultHandler() { + private String _organisation; + private String _module; + private String _revision; + private Date _pubdate; + private boolean _skip; + public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { + if ("module".equals(qName)) { + _organisation = attributes.getValue("organisation"); + _module = attributes.getValue("name"); + } else if ("revision".equals(qName)) { + _revision = attributes.getValue("name"); + if (attributes.getValue("error") != null || attributes.getValue("evicted") != null) { + _skip = true; + } else { + try { + _pubdate = Ivy.DATE_FORMAT.parse(attributes.getValue("pubdate")); + _skip = false; + } catch (ParseException e) { + throw new IllegalArgumentException("invalid publication date for "+_organisation+" "+_module+" "+_revision+": "+attributes.getValue("pubdate")); + } + } + } else if ("artifact".equals(qName)) { + if (_skip) { + return; + } + String status = attributes.getValue("status"); + if (status != null && "failed".equals(status)) { + return; + } + String artifactName = attributes.getValue("name"); + String type = attributes.getValue("type"); + String ext = attributes.getValue("ext"); + Artifact artifact = new DefaultArtifact(ModuleRevisionId.newInstance(_organisation, _module, _revision), _pubdate, artifactName, type, ext); + artifacts.add(artifact); + } + } + }); + return (Artifact[])artifacts.toArray(new Artifact[artifacts.size()]); + } catch (Exception ex) { + ParseException pe = new ParseException("failed to parse report for "+moduleId+" "+conf+": "+ex.getMessage(), 0); + pe.initCause(ex); + throw pe; + } + } + + +} diff --git a/src/java/fr/jayasoft/ivy/xml/ivy.xsd b/src/java/fr/jayasoft/ivy/xml/ivy.xsd new file mode 100644 index 00000000..4cb65b2d --- /dev/null +++ b/src/java/fr/jayasoft/ivy/xml/ivy.xsd @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/java/fr/jayasoft/ivy/ResolveTest.java b/test/java/fr/jayasoft/ivy/ResolveTest.java new file mode 100644 index 00000000..d075f3c8 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ResolveTest.java @@ -0,0 +1,716 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import fr.jayasoft.ivy.report.ConfigurationResolveReport; +import fr.jayasoft.ivy.report.ResolveReport; +import fr.jayasoft.ivy.report.XmlReportOutputter; +import fr.jayasoft.ivy.resolver.DualResolver; + +/** + * @author Xavier Hanin + * + */ +public class ResolveTest extends TestCase { + private final Ivy _ivy; + private File _cache; + + public ResolveTest() throws Exception { + _ivy = new Ivy(); + _ivy.configure(new File("test/repositories/ivyconf.xml")); + } + + protected void setUp() throws Exception { + createCache(); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testResolveSimple() throws Exception { + // mod1.1 depends on mod1.2 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testChangeCacheLayout() throws Exception { + Ivy ivy = new Ivy(); + ivy.configure(new File("test/repositories/ivyconf.xml")); + ivy.setCacheIvyPattern("[module]/ivy.xml"); + ivy.setCacheArtifactPattern("[artifact].[ext]"); + + // mod1.1 depends on mod1.2 + ResolveReport report = ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(ivy.getIvyFileInCache(_cache, mrid).exists()); + assertTrue(new File(_cache, "mod1.1/ivy.xml").exists()); + + // dependencies + assertTrue(ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(new File(_cache, "mod1.2/ivy.xml").exists()); + assertTrue(ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + assertTrue(new File(_cache, "mod1.2.jar").exists()); + } + + public void testResolveExtends() throws Exception { + // mod6.1 depends on mod1.2 2.0 in conf default, and conf extension extends default + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml").toURL(), + null, new String[] {"extension"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "0.3"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies from default + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testResolveExtended() throws Exception { + // mod6.1 depends on mod1.2 2.0 in conf default, and conf extension extends default + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml").toURL(), + null, new String[] {"default"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "0.3"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies from default + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testResolveExtendedAndExtends() throws Exception { + // mod6.1 depends on mod1.2 2.0 in conf default, and conf extension extends default + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml").toURL(), + null, new String[] {"default", "extension"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "0.3"); + assertEquals(mrid, md.getModuleRevisionId()); + ConfigurationResolveReport crr = report.getConfigurationReport("default"); + assertNotNull(crr); + assertEquals(1, crr.getArtifactsNumber()); + crr = report.getConfigurationReport("extension"); + assertNotNull(crr); + assertEquals(1, crr.getArtifactsNumber()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testResolveDefaultWithArtifactsConf1() throws Exception { + // mod2.2 depends on mod1.3 and selects its artifacts + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml").toURL(), + null, new String[] {"myconf1"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.2", "0.5"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.3", "3.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3-A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3-B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3", "jar", "jar").exists()); + } + + public void testResolveDefaultWithArtifactsConf2() throws Exception { + // mod2.2 depends on mod1.3 and selects its artifacts + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml").toURL(), + null, new String[] {"myconf2"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.2", "0.5"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.3", "3.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3-A", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3-B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org1", "mod1.3", "3.0", "mod1.3", "jar", "jar").exists()); + } + + public void testResolveWithDependencyArtifactsConf1() throws Exception { + // mod2.3 depends on mod2.1 and selects its artifacts in myconf1 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml").toURL(), + null, new String[] {"myconf1"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.3", "0.4"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org2", "mod2.1", "0.3")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21A", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "mod2.1", "jar", "jar").exists()); + } + + public void testResolveWithDependencyArtifactsConf2() throws Exception { + // mod2.3 depends on mod2.1 and selects its artifacts in myconf1 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml").toURL(), + null, new String[] {"myconf2"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.3", "0.4"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org2", "mod2.1", "0.3")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "mod2.1", "jar", "jar").exists()); + } + + public void testResolveWithDependencyArtifactsWithoutConf() throws Exception { + // mod2.3 depends on mod2.1 and selects its artifacts + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.3/ivys/ivy-0.5.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.3", "0.5"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org2", "mod2.1", "0.3")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21A", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "mod2.1", "jar", "jar").exists()); + } + + public void testResolveWithExcludesArtifacts() throws Exception { + // mod2.3 depends on mod2.1 and selects its artifacts + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.3/ivys/ivy-0.6.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.3", "0.6"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org2", "mod2.1", "0.3")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21A", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "art21B", "jar", "jar").exists()); + assertTrue(!_ivy.getArchiveFileInCache(_cache, "org2", "mod2.1", "0.3", "mod2.1", "jar", "jar").exists()); + } + + public void testResolveTransitiveDependencies() throws Exception { + // mod2.1 depends on mod1.1 which depends on mod1.2 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.1", "0.3"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testResolveDiamond() throws Exception { + // mod4.1 depends on + // - mod1.1 which depends on mod1.2 + // - mod3.1 which depends on mod1.2 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod4.1/ivy-4.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org4", "mod4.1", "4.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org3", "mod3.1", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org3", "mod3.1", "1.0", "mod3.1", "jar", "jar").exists()); + } + + public void testResolveConflict() throws Exception { + // mod4.1 v 4.1 depends on + // - mod1.1 v 1.0 which depends on mod1.2 v 2.0 + // - mod3.1 v 1.1 which depends on mod1.2 v 2.1 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod4.1/ivy-4.1.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org4", "mod4.1", "4.1"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + ConfigurationResolveReport crr = report.getConfigurationReport("default"); + assertNotNull(crr); + assertEquals(0, crr.getDownloadReports(ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).length); + assertEquals(1, crr.getDownloadReports(ModuleRevisionId.newInstance("org1", "mod1.2", "2.1")).length); + + File r = new File(_cache, XmlReportOutputter.getReportFileName(mrid.getModuleId(), "default")); + assertTrue(r.exists()); + final boolean[] found = new boolean[] {false}; + SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + saxParser.parse(r, new DefaultHandler() { + public void startElement(String uri,String localName,String qName,org.xml.sax.Attributes attributes) throws SAXException { + if ("revision".equals(qName) && "2.0".equals(attributes.getValue("name"))) { + found[0] = true; + } + } + }); + assertTrue(found[0]); // the report should contain the evicted revision + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org3", "mod3.1", "1.1")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org3", "mod3.1", "1.1", "mod3.1", "jar", "jar").exists()); + + assertFalse(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.1")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.1", "mod1.2", "jar", "jar").exists()); + } + + public void testResolveConflictInConf() throws Exception { + // conflicts in separate confs are not conflicts + + // mod2.1 conf A depends on mod1.1 which depends on mod1.2 2.0 + // mod2.1 conf B depends on mod1.2 2.1 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org2/mod2.1/ivys/ivy-0.4.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org2", "mod2.1", "0.4"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.1", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.1", "1.0", "mod1.1", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.1")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.1", "mod1.2", "jar", "jar").exists()); + } + + public void testEvictWithConf() throws Exception { + // bug 105 - test #1 + + // mod6.1 r1.0 depends on + // mod5.1 r4.2 conf A + // mod5.2 r1.0 which depends on mod5.1 r4.0 conf B + // + // mod5.1 r4.2 conf B depends on mod1.2 r2.0 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod6.1/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "1.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51B", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.2", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.2", "1.0", "mod5.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + // should have been evicted before download + assertFalse(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.0")).exists()); + assertFalse(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51A", "jar", "jar").exists()); + assertFalse(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51B", "jar", "jar").exists()); + } + + public void testEvictWithConf2() throws Exception { + // same as preceding one but with inverse order, so that + // eviction is done after download + // bug 105 - test #2 + + // mod6.1 r1.1 depends on + // mod5.2 r1.0 which depends on mod5.1 r4.0 conf B + // mod5.1 r4.2 conf A + // + // mod5.1 r4.2 conf B depends on mod1.2 r2.0 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod6.1/ivy-1.1.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "1.1"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51B", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.2", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.2", "1.0", "mod5.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testEvictWithConfInMultiConf() throws Exception { + // same as preceding ones but the conflict appears in several root confs + // bug 105 - test #3 + + // mod6.1 r1.2 conf A and conf B depends on + // mod5.2 r1.0 which depends on mod5.1 r4.0 conf B + // mod5.1 r4.2 conf A + // + // mod5.1 r4.2 conf B depends on mod1.2 r2.0 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod6.1/ivy-1.2.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "1.2"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51B", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.2", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.2", "1.0", "mod5.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + // all artifacts should be present in both confs + ConfigurationResolveReport crr = report.getConfigurationReport("A"); + assertNotNull(crr); + assertEquals(2, crr.getDownloadReports(ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).length); + + crr = report.getConfigurationReport("B"); + assertNotNull(crr); + assertEquals(2, crr.getDownloadReports(ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).length); + } + + public void testEvictWithConfInMultiConf2() throws Exception { + // same as preceding one but the conflict appears in a root conf and not in another + // which should keep the evicted + // bug 105 - test #4 + + // mod6.1 r1.3 conf A depends on + // mod5.2 r1.0 which depends on mod5.1 r4.0 conf B + // + // mod6.1 r1.3 conf B depends on + // mod5.2 r1.0 which depends on mod5.1 r4.0 conf B + // mod5.1 r4.2 conf A + // + // mod5.1 r4.2 conf B depends on mod1.2 r2.0 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod6.1/ivy-1.3.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org6", "mod6.1", "1.3"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.2", "art51B", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51B", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.2", "1.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.2", "1.0", "mod5.2", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + // 4.2 artifacts should be present in conf B only + ConfigurationResolveReport crr = report.getConfigurationReport("A"); + assertNotNull(crr); + assertEquals(0, crr.getDownloadReports(ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).length); + + crr = report.getConfigurationReport("B"); + assertNotNull(crr); + assertEquals(2, crr.getDownloadReports(ModuleRevisionId.newInstance("org5", "mod5.1", "4.2")).length); + } + + public void testResolveForce() throws Exception { + // mod4.1 v 4.2 depends on + // - mod1.2 v 2.0 and forces it + // - mod3.1 v 1.1 which depends on mod1.2 v 2.1 + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod4.1/ivy-4.2.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org4", "mod4.1", "4.2"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org3", "mod3.1", "1.1")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org3", "mod3.1", "1.1", "mod3.1", "jar", "jar").exists()); + + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + + assertFalse(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.1")).exists()); + assertFalse(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.1", "mod1.2", "jar", "jar").exists()); + } + + public void testExtends() throws Exception { + // mod 5.2 depends on mod5.1 conf B + // mod5.1 conf B publishes art51B + // mod5.1 conf B extends conf A + // mod5.1 conf A publishes art51A + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod5.2/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org5", "mod5.2", "1.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + assertTrue(_ivy.getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org5", "mod5.1", "4.0")).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51B", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.0", "art51A", "jar", "jar").exists()); + } + + public void testMultiConfs() throws Exception { + // mod 5.2 depends on mod5.1 conf B in its conf B and conf A in its conf A + // mod5.1 conf B publishes art51B + // mod5.1 conf A publishes art51A + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod5.2/ivy-2.0.xml").toURL(), + null, new String[] {"B", "A"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org5", "mod5.2", "2.0"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + ModuleRevisionId depId = ModuleRevisionId.newInstance("org5", "mod5.1", "4.1"); + + ConfigurationResolveReport crr = report.getConfigurationReport("A"); + assertNotNull(crr); + assertEquals(1, crr.getDownloadReports(depId).length); + + File r = new File(_cache, XmlReportOutputter.getReportFileName(mrid.getModuleId(), "A")); + assertTrue(r.exists()); + final boolean[] found = new boolean[] {false}; + SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + saxParser.parse(r, new DefaultHandler() { + public void startElement(String uri,String localName,String qName,org.xml.sax.Attributes attributes) throws SAXException { + if ("artifact".equals(qName) && "art51B".equals(attributes.getValue("name"))) { + found[0] = true; + } + } + }); + assertFalse(found[0]); + + assertTrue(_ivy.getIvyFileInCache(_cache, depId).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.1", "art51A", "jar", "jar").exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org5", "mod5.1", "4.1", "art51B", "jar", "jar").exists()); + } + + public void testLatest() throws Exception { + // mod1.4 depends on latest mod1.2 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org1/mod1.4/ivys/ivy-1.0.1.xml").toURL(), + null, new String[] {"default"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.4", "1.0.1"); + assertEquals(mrid, md.getModuleRevisionId()); + + assertTrue(_ivy.getIvyFileInCache(_cache, mrid).exists()); + + // dependencies + ModuleRevisionId depId = ModuleRevisionId.newInstance("org1", "mod1.2", "2.2"); + + ConfigurationResolveReport crr = report.getConfigurationReport("default"); + assertNotNull(crr); + assertEquals(1, crr.getDownloadReports(depId).length); + + File r = new File(_cache, XmlReportOutputter.getReportFileName(mrid.getModuleId(), "default")); + assertTrue(r.exists()); + final boolean[] found = new boolean[] {false}; + SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser(); + saxParser.parse(r, new DefaultHandler() { + public void startElement(String uri,String localName,String qName,org.xml.sax.Attributes attributes) throws SAXException { + if ("artifact".equals(qName) && "mod1.2".equals(attributes.getValue("name"))) { + found[0] = true; + } + } + }); + assertTrue(found[0]); + + assertTrue(_ivy.getIvyFileInCache(_cache, depId).exists()); + assertTrue(_ivy.getArchiveFileInCache(_cache, "org1", "mod1.2", "2.2", "mod1.2", "jar", "jar").exists()); + } + + public void testCircular() throws Exception { + // mod6.3 depends on mod6.2, which itself depends on mod6.3 ! + ResolveReport report = _ivy.resolve(new File("test/repositories/2/mod6.3/ivy-1.0.xml").toURL(), + null, new String[] {"default"}, _cache, null, true); + assertNotNull(report); + } + + public void testResolveDualChain() throws Exception { + Ivy ivy = new Ivy(); + ivy.configure(ResolveTest.class.getResource("dualchainresolverconf.xml")); + + DependencyResolver resolver = ivy.getResolver("default"); + assertNotNull(resolver); + assertTrue(resolver instanceof DualResolver); + DualResolver dual = (DualResolver)resolver; + + // first without cache + ivy.resolve(ResolveTest.class.getResource("ivy-dualchainresolver.xml"), null, new String[] {"default"}, new File("build/cache"), null, true); + + assertTrue(new File("build/cache/xerces/xerces/ivy-2.6.2.xml").exists()); + assertTrue(new File("build/cache/xerces/xerces/jars/xmlParserAPIs-2.6.2.jar").exists()); + assertTrue(new File("build/cache/xerces/xerces/jars/xercesImpl-2.6.2.jar").exists()); + + // second with cache for ivy file only + new File("build/cache/xerces/xerces/jars/xmlParserAPIs-2.6.2.jar").delete(); + new File("build/cache/xerces/xerces/jars/xercesImpl-2.6.2.jar").delete(); + assertFalse(new File("build/cache/xerces/xerces/jars/xmlParserAPIs-2.6.2.jar").exists()); + assertFalse(new File("build/cache/xerces/xerces/jars/xercesImpl-2.6.2.jar").exists()); + ivy.resolve(ResolveTest.class.getResource("ivy-dualchainresolver.xml"), null, new String[] {"default"}, new File("build/cache"), null, true); + + assertTrue(new File("build/cache/xerces/xerces/ivy-2.6.2.xml").exists()); + assertTrue(new File("build/cache/xerces/xerces/jars/xmlParserAPIs-2.6.2.jar").exists()); + assertTrue(new File("build/cache/xerces/xerces/jars/xercesImpl-2.6.2.jar").exists()); + } + + + public void testBug148() throws Exception { + Ivy ivy = new Ivy(); + ivy.configure(new File("test/repositories/bug148/ivyconf.xml")); + + ivy.resolve(ResolveTest.class.getResource("ivy-148.xml"), null, new String[] {"*"}, new File("build/cache"), null, true); + + assertTrue(new File("build/cache/jtv-foo/bar/ivy-1.1.0.0.xml").exists()); + assertTrue(new File("build/cache/jtv-foo/bar/jars/bar-1.1.0.0.jar").exists()); + assertTrue(new File("build/cache/idautomation/barcode/ivy-4.10.xml").exists()); + assertTrue(new File("build/cache/idautomation/barcode/jars/LinearBarCode-4.10.jar").exists()); + } + + public void testBug148b() throws Exception { + Ivy ivy = new Ivy(); + ivy.configure(new File("test/repositories/bug148/ivyconf.xml")); + + ivy.resolve(ResolveTest.class.getResource("ivy-148b.xml"), null, new String[] {"*"}, new File("build/cache"), null, true); + + assertTrue(new File("build/cache/jtv-foo/bar/ivy-1.1.0.0.xml").exists()); + assertTrue(new File("build/cache/jtv-foo/bar/jars/bar-1.1.0.0.jar").exists()); + assertTrue(new File("build/cache/idautomation/barcode/ivy-4.10.xml").exists()); + assertTrue(new File("build/cache/idautomation/barcode/jars/LinearBarCode-4.10.jar").exists()); + } +} diff --git a/test/java/fr/jayasoft/ivy/RetrieveTest.java b/test/java/fr/jayasoft/ivy/RetrieveTest.java new file mode 100644 index 00000000..03770d4a --- /dev/null +++ b/test/java/fr/jayasoft/ivy/RetrieveTest.java @@ -0,0 +1,89 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.io.File; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.report.ResolveReport; +import fr.jayasoft.ivy.util.IvyPatternHelper; + +import junit.framework.TestCase; + +public class RetrieveTest extends TestCase { + private final Ivy _ivy; + private File _cache; + + public RetrieveTest() throws Exception { + _ivy = new Ivy(); + _ivy.configure(new File("test/repositories/ivyconf.xml")); + } + + protected void setUp() throws Exception { + createCache(); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(new File("build/test/retrieve")); + del.execute(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testRetrieveSimple() throws Exception { + // mod1.1 depends on mod1.2 + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + + String pattern = "build/test/retrieve/[module]/[conf]/[artifact]-[revision].[ext]"; + _ivy.retrieve(md.getModuleRevisionId().getModuleId(), md.getConfigurationsNames(), _cache, pattern); + assertTrue(new File(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default")).exists()); + + pattern = "build/test/retrieve/[module]/[conf]/[type]s/[artifact]-[revision].[ext]"; + _ivy.retrieve(md.getModuleRevisionId().getModuleId(), md.getConfigurationsNames(), _cache, pattern); + assertTrue(new File(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default")).exists()); + } + + public void testRetrieveWithVariable() throws Exception { + // mod1.1 depends on mod1.2 + _ivy.setVariable("retrieve.dir", "retrieve"); + ResolveReport report = _ivy.resolve(new File("test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml").toURL(), + null, new String[] {"*"}, _cache, null, true); + assertNotNull(report); + ModuleDescriptor md = report.getModuleDescriptor(); + assertNotNull(md); + + String pattern = "build/test/${retrieve.dir}/[module]/[conf]/[artifact]-[revision].[ext]"; + _ivy.retrieve(md.getModuleRevisionId().getModuleId(), md.getConfigurationsNames(), _cache, pattern); + pattern = IvyPatternHelper.substituteVariable(pattern, "retrieve.dir", "retrieve"); + assertTrue(new File(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default")).exists()); + + pattern = "build/test/${retrieve.dir}/[module]/[conf]/[type]s/[artifact]-[revision].[ext]"; + _ivy.retrieve(md.getModuleRevisionId().getModuleId(), md.getConfigurationsNames(), _cache, pattern); + pattern = IvyPatternHelper.substituteVariable(pattern, "retrieve.dir", "retrieve"); + assertTrue(new File(IvyPatternHelper.substitute(pattern, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar", "default")).exists()); + } + + +} diff --git a/test/java/fr/jayasoft/ivy/SortTest.java b/test/java/fr/jayasoft/ivy/SortTest.java new file mode 100644 index 00000000..e4347d20 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/SortTest.java @@ -0,0 +1,55 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import junit.framework.TestCase; + +/** + * @author Xavier Hanin + * + */ +public class SortTest extends TestCase { + + public void testSort() { + ModuleRevisionId mrid1 = ModuleRevisionId.newInstance("org", "md1", "rev1"); + ModuleRevisionId mrid2 = ModuleRevisionId.newInstance("org", "md2", "rev2"); + ModuleRevisionId mrid3 = ModuleRevisionId.newInstance("org", "md3", "rev3"); + DefaultModuleDescriptor[] md = new DefaultModuleDescriptor[] { + new DefaultModuleDescriptor(mrid1, "integration", new Date()), + new DefaultModuleDescriptor(mrid2, "integration", new Date()), + new DefaultModuleDescriptor(mrid3, "integration", new Date()), + }; + md[1].addDependency(new DefaultDependencyDescriptor(mrid1, false)); + md[2].addDependency(new DefaultDependencyDescriptor(mrid2, false)); + + List toSort; + + toSort = new ArrayList(Arrays.asList(new Object[] {md[0], md[2], md[1]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + toSort = new ArrayList(Arrays.asList(new Object[] {md[0], md[1], md[2]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + toSort = new ArrayList(Arrays.asList(new Object[] {md[1], md[0], md[2]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + toSort = new ArrayList(Arrays.asList(new Object[] {md[1], md[2], md[0]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + toSort = new ArrayList(Arrays.asList(new Object[] {md[2], md[1], md[0]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + toSort = new ArrayList(Arrays.asList(new Object[] {md[2], md[0], md[1]})); + assertSorted(md, Ivy.sortModuleDescriptors(toSort)); + } + + private void assertSorted(DefaultModuleDescriptor[] md, List sorted) { + assertEquals(md.length, sorted.size()); + for (int i = 0; i < md.length; i++) { + assertEquals(md[i], sorted.get(i)); + } + } +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyArtifactPropertyTest.java b/test/java/fr/jayasoft/ivy/ant/IvyArtifactPropertyTest.java new file mode 100644 index 00000000..034ffd02 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyArtifactPropertyTest.java @@ -0,0 +1,55 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +public class IvyArtifactPropertyTest extends TestCase { + private File _cache; + private IvyArtifactProperty _prop; + private Project _project; + + protected void setUp() throws Exception { + createCache(); + _project = new Project(); + _project.setProperty("ivy.conf.file", "test/repositories/ivyconf.xml"); + + _prop = new IvyArtifactProperty(); + _prop.setProject(_project); + _prop.setCache(_cache); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testSimple() throws Exception { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-simple.xml"); + _prop.setName("[module].[artifact]-[revision]"); + _prop.setValue("${cache.dir}/[module]/[artifact]-[revision].[type]"); + _prop.execute(); + String val = _project.getProperty("mod1.2.mod1.2-2.0"); + assertNotNull(val); + assertEquals("build/cache/mod1.2/mod1.2-2.0.jar", val); + } +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyCachePathTest.java b/test/java/fr/jayasoft/ivy/ant/IvyCachePathTest.java new file mode 100644 index 00000000..521880df --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyCachePathTest.java @@ -0,0 +1,82 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; +import org.apache.tools.ant.types.Path; + +public class IvyCachePathTest extends TestCase { + private File _cache; + private IvyCachePath _path; + private Project _project; + + protected void setUp() throws Exception { + createCache(); + _project = new Project(); + _project.setProperty("ivy.conf.file", "test/repositories/ivyconf.xml"); + + _path = new IvyCachePath(); + _path.setProject(_project); + _path.setCache(_cache); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testSimple() throws Exception { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-simple.xml"); + _path.setPathid("simple-pathid"); + _path.execute(); + Object ref = _project.getReference("simple-pathid"); + assertNotNull(ref); + assertTrue(ref instanceof Path); + Path p = (Path)ref; + assertEquals(1, p.size()); + assertEquals(_path.getIvyInstance().getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").getAbsolutePath(), + new File(p.list()[0]).getAbsolutePath()); + } + + public void testFailure() throws Exception { + try { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-failure.xml"); + _path.setPathid("failure-pathid"); + _path.execute(); + fail("failure didn't raised an exception with default haltonfailure setting"); + } catch (BuildException ex) { + // ok => should raised an exception + } + } + + public void testHaltOnFailure() throws Exception { + try { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-failure.xml"); + _path.setPathid("haltfailure-pathid"); + _path.setHaltonfailure(false); + _path.execute(); + } catch (BuildException ex) { + fail("failure raised an exception with haltonfailure set to false"); + } + } +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyConfigureTest.java b/test/java/fr/jayasoft/ivy/ant/IvyConfigureTest.java new file mode 100644 index 00000000..28944746 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyConfigureTest.java @@ -0,0 +1,79 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; + +import fr.jayasoft.ivy.Ivy; + +public class IvyConfigureTest extends TestCase { + private File _cache; + private IvyConfigure _configure; + + protected void setUp() throws Exception { + Project project = new Project(); + project.setProperty("myproperty", "myvalue"); + + _configure = new IvyConfigure(); + _configure.setProject(project); + } + + public void testFile() throws Exception { + _configure.setFile(new File("test/repositories/ivyconf.xml")); + + _configure.execute(); + + Ivy ivy = getIvyInstance(); + assertNotNull(ivy); + + assertEquals(new File("build/cache"), ivy.getDefaultCache()); + assertEquals(new File("test/repositories/ivyconf.xml").getAbsolutePath(), ivy.getVariables().get("ivy.conf.file")); + assertEquals(new File("test/repositories/ivyconf.xml").toURL().toExternalForm(), ivy.getVariables().get("ivy.conf.url")); + assertEquals(new File("test/repositories").getAbsolutePath(), ivy.getVariables().get("ivy.conf.dir")); + assertEquals("myvalue", ivy.getVariables().get("myproperty")); + } + + public void testURL() throws Exception { + String confUrl = new File("test/repositories/ivyconf.xml").toURL().toExternalForm(); + String confDirUrl = new File("test/repositories").toURL().toExternalForm(); + if (confDirUrl.endsWith("/")) { + confDirUrl = confDirUrl.substring(0, confDirUrl.length() - 1); + } + _configure.setUrl(confUrl); + + _configure.execute(); + + Ivy ivy = getIvyInstance(); + assertNotNull(ivy); + + assertEquals(new File("build/cache"), ivy.getDefaultCache()); + assertEquals(confUrl, ivy.getVariables().get("ivy.conf.url")); + assertEquals(confDirUrl, ivy.getVariables().get("ivy.conf.dir")); + assertEquals("myvalue", ivy.getVariables().get("myproperty")); + } + + public void testAntProperties() throws Exception { + String confUrl = IvyConfigureTest.class.getResource("ivyconf-test.xml").toExternalForm(); + _configure.setUrl(confUrl); + + _configure.execute(); + + Ivy ivy = getIvyInstance(); + assertNotNull(ivy); + + assertEquals("myvalue", ivy.getVariables().get("myproperty")); + assertEquals("myvalue", ivy.getDefaultCache().getName()); + } + + private Ivy getIvyInstance() { + return (Ivy)_configure.getProject().getReference("ivy.instance"); + } + +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyPublishTest.java b/test/java/fr/jayasoft/ivy/ant/IvyPublishTest.java new file mode 100644 index 00000000..b17fd84c --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyPublishTest.java @@ -0,0 +1,94 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.util.FileUtil; +import fr.jayasoft.ivy.xml.XmlModuleDescriptorParser; + +public class IvyPublishTest extends TestCase { + private File _cache; + private IvyPublish _publish; + private Project _project; + + protected void setUp() throws Exception { + cleanTestDir(); + cleanRep(); + createCache(); + _project = new Project(); + _project.setProperty("ivy.conf.file", "test/repositories/ivyconf.xml"); + _project.setProperty("build", "build/test/publish"); + + _publish = new IvyPublish(); + _publish.setProject(_project); + _publish.setCache(_cache); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + cleanTestDir(); + cleanRep(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + private void cleanTestDir() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(new File("build/test/publish")); + del.execute(); + } + + private void cleanRep() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(new File("test/repositories/1/jayasoft")); + del.execute(); + } + + public void testSimple() throws Exception { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-simple.xml"); + IvyResolve res = new IvyResolve(); + res.setProject(_project); + res.execute(); + + _publish.setPubrevision("1.2"); + _publish.setResolver("1"); + File art = new File("build/test/publish/resolve-simple-1.2.jar"); + FileUtil.copy(new File("test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar"), art, null); + _publish.execute(); + + // should have do the ivy delivering + assertTrue(new File("build/test/publish/ivy-1.2.xml").exists()); + + // should have published the files with "1" resolver + assertTrue(new File("test/repositories/1/jayasoft/resolve-simple/ivys/ivy-1.2.xml").exists()); + assertTrue(new File("test/repositories/1/jayasoft/resolve-simple/jars/resolve-simple-1.2.jar").exists()); + + // should have updated published ivy version + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(new Ivy(), new File("test/repositories/1/jayasoft/resolve-simple/ivys/ivy-1.2.xml").toURL(), false); + assertEquals("1.2", md.getModuleRevisionId().getRevision()); + } + +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyResolveTest.java b/test/java/fr/jayasoft/ivy/ant/IvyResolveTest.java new file mode 100644 index 00000000..67948054 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyResolveTest.java @@ -0,0 +1,86 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; + +public class IvyResolveTest extends TestCase { + private File _cache; + private IvyResolve _resolve; + + protected void setUp() throws Exception { + createCache(); + Project project = new Project(); + project.setProperty("ivy.conf.file", "test/repositories/ivyconf.xml"); + + _resolve = new IvyResolve(); + _resolve.setProject(project); + _resolve.setCache(_cache); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testSimple() throws Exception { + _resolve.setFile(new File("test/java/fr/jayasoft/ivy/ant/ivy-simple.xml")); + _resolve.execute(); + + assertTrue(getIvy().getIvyFileInCache(_cache, ModuleRevisionId.newInstance("jayasoft", "resolve-simple", "1.0")).exists()); + + // dependencies + assertTrue(getIvy().getIvyFileInCache(_cache, ModuleRevisionId.newInstance("org1", "mod1.2", "2.0")).exists()); + assertTrue(getIvy().getArchiveFileInCache(_cache, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar").exists()); + } + + public void testFailure() throws Exception { + try { + _resolve.setFile(new File("test/java/fr/jayasoft/ivy/ant/ivy-failure.xml")); + _resolve.execute(); + fail("failure didn't raised an exception with default haltonfailure setting"); + } catch (BuildException ex) { + // ok => should raised an exception + } + } + + public void testHaltOnFailure() throws Exception { + try { + _resolve.setFile(new File("test/java/fr/jayasoft/ivy/ant/ivy-failure.xml")); + _resolve.setHaltonfailure(false); + _resolve.execute(); + } catch (BuildException ex) { + ex.printStackTrace(); + fail("failure raised an exception with haltonfailure set to false"); + } + } + + private Ivy getIvy() { + return _resolve.getIvyInstance(); + } + + +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyRetrieveTest.java b/test/java/fr/jayasoft/ivy/ant/IvyRetrieveTest.java new file mode 100644 index 00000000..41f90130 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyRetrieveTest.java @@ -0,0 +1,85 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import java.io.File; + +import junit.framework.TestCase; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.util.IvyPatternHelper; + +public class IvyRetrieveTest extends TestCase { + private static final String RETRIEVE_PATTERN = "build/test/lib/[artifact]-[revision].[type]"; + private File _cache; + private IvyRetrieve _retrieve; + private Project _project; + + protected void setUp() throws Exception { + createCache(); + cleanTestLib(); + _project = new Project(); + _project.setProperty("ivy.conf.file", "test/repositories/ivyconf.xml"); + + _retrieve = new IvyRetrieve(); + _retrieve.setProject(_project); + _retrieve.setCache(_cache); + _retrieve.setPattern(RETRIEVE_PATTERN); + } + + private void createCache() { + _cache = new File("build/cache"); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + cleanCache(); + cleanTestLib(); + } + + private void cleanCache() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + private void cleanTestLib() { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(new File("build/test/lib")); + del.execute(); + } + + public void testSimple() throws Exception { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-simple.xml"); + _retrieve.execute(); + assertTrue(new File(IvyPatternHelper.substitute(RETRIEVE_PATTERN, "org1", "mod1.2", "2.0", "mod1.2", "jar", "jar")).exists()); + } + + public void testFailure() throws Exception { + try { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-failure.xml"); + _retrieve.execute(); + fail("failure didn't raised an exception with default haltonfailure setting"); + } catch (BuildException ex) { + // ok => should raised an exception + } + } + + public void testHaltOnFailure() throws Exception { + try { + _project.setProperty("ivy.dep.file", "test/java/fr/jayasoft/ivy/ant/ivy-failure.xml"); + _retrieve.setHaltonfailure(false); + _retrieve.execute(); + } catch (BuildException ex) { + fail("failure raised an exception with haltonfailure set to false"); + } + } +} diff --git a/test/java/fr/jayasoft/ivy/ant/IvyVarTest.java b/test/java/fr/jayasoft/ivy/ant/IvyVarTest.java new file mode 100644 index 00000000..dd040ee9 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/IvyVarTest.java @@ -0,0 +1,61 @@ +/* + * This file is subject to the licence found in LICENCE.TXT in the root directory of the project. + * Copyright Jayasoft 2005 - All rights reserved + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.ant; + +import org.apache.tools.ant.Project; + +import fr.jayasoft.ivy.Ivy; + +import junit.framework.TestCase; + +public class IvyVarTest extends TestCase { + public void testSimple() { + IvyVar task = new IvyVar(); + task.setProject(new Project()); + task.setName("mytest"); + task.setValue("myvalue"); + task.execute(); + Ivy ivy = task.getIvyInstance(); + assertNotNull(ivy); + assertEquals("myvalue", ivy.getVariable("mytest")); + } + + public void testPrefix() { + IvyVar task = new IvyVar(); + task.setProject(new Project()); + task.setName("mytest"); + task.setValue("myvalue"); + task.setPrefix("myprefix"); + task.execute(); + Ivy ivy = task.getIvyInstance(); + assertNotNull(ivy); + assertEquals("myvalue", ivy.getVariable("myprefix.mytest")); + } + + public void testURL() { + IvyVar task = new IvyVar(); + task.setProject(new Project()); + task.setUrl(IvyVarTest.class.getResource("vartest.properties").toExternalForm()); + task.execute(); + Ivy ivy = task.getIvyInstance(); + assertNotNull(ivy); + assertEquals("myvalue1", ivy.getVariable("mytest1")); + assertEquals("myvalue2", ivy.getVariable("mytest2")); + } + + public void testURLPrefix() { + IvyVar task = new IvyVar(); + task.setProject(new Project()); + task.setUrl(IvyVarTest.class.getResource("vartest.properties").toExternalForm()); + task.setPrefix("myprefix."); + task.execute(); + Ivy ivy = task.getIvyInstance(); + assertNotNull(ivy); + assertEquals("myvalue1", ivy.getVariable("myprefix.mytest1")); + assertEquals("myvalue2", ivy.getVariable("myprefix.mytest2")); + } +} diff --git a/test/java/fr/jayasoft/ivy/ant/ivy-failure.xml b/test/java/fr/jayasoft/ivy/ant/ivy-failure.xml new file mode 100644 index 00000000..552ef02e --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/ivy-failure.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ant/ivy-simple.xml b/test/java/fr/jayasoft/ivy/ant/ivy-simple.xml new file mode 100644 index 00000000..8008d00a --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/ivy-simple.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ant/ivyconf-test.xml b/test/java/fr/jayasoft/ivy/ant/ivyconf-test.xml new file mode 100644 index 00000000..af4ab623 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/ivyconf-test.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ant/vartest.properties b/test/java/fr/jayasoft/ivy/ant/vartest.properties new file mode 100644 index 00000000..0400d9a4 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ant/vartest.properties @@ -0,0 +1,2 @@ +mytest1=myvalue1 +mytest2=myvalue2 \ No newline at end of file diff --git a/test/java/fr/jayasoft/ivy/dualchainresolverconf.xml b/test/java/fr/jayasoft/ivy/dualchainresolverconf.xml new file mode 100644 index 00000000..d721572c --- /dev/null +++ b/test/java/fr/jayasoft/ivy/dualchainresolverconf.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ivy-148.xml b/test/java/fr/jayasoft/ivy/ivy-148.xml new file mode 100644 index 00000000..d52702b0 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ivy-148.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ivy-148b.xml b/test/java/fr/jayasoft/ivy/ivy-148b.xml new file mode 100644 index 00000000..9f7dae48 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ivy-148b.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/ivy-dualchainresolver.xml b/test/java/fr/jayasoft/ivy/ivy-dualchainresolver.xml new file mode 100644 index 00000000..0eb5b315 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/ivy-dualchainresolver.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/latest/LatestRevisionStrategyTest.java b/test/java/fr/jayasoft/ivy/latest/LatestRevisionStrategyTest.java new file mode 100644 index 00000000..8830e406 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/latest/LatestRevisionStrategyTest.java @@ -0,0 +1,41 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.latest; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import junit.framework.TestCase; + +public class LatestRevisionStrategyTest extends TestCase { + public void testComparator() { + String[] revs = new String[] { + "0.2a", + "0.2_b", + "0.2rc1", + "0.2-final", + "1.0-dev1", + "1.0-dev2", + "1.0-alpha1", + "1.0-alpha2", + "1.0-beta1", + "1.0-beta2", + "1.0-gamma", + "1.0-rc1", + "1.0-rc2", + "1.0", + "1.0.1", + "2.0" + }; + + List shuffled = new ArrayList(Arrays.asList(revs)); + Collections.shuffle(shuffled); + Collections.sort(shuffled, LatestRevisionStrategy.COMPARATOR); + assertEquals(Arrays.asList(revs), shuffled); + } +} diff --git a/test/java/fr/jayasoft/ivy/resolver/ChainResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/ChainResolverTest.java new file mode 100644 index 00000000..004d7946 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/ChainResolverTest.java @@ -0,0 +1,126 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.util.Arrays; +import java.util.GregorianCalendar; +import java.util.List; + +import junit.framework.TestCase; +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.xml.XmlIvyConfigurationParser; + +/** + * Tests ChainResolver + */ +public class ChainResolverTest extends TestCase { + private ResolveData _data = new ResolveData(new Ivy(), null, null, null, true); + public void testOrderFromConf() throws Exception { + new XmlIvyConfigurationParser(_data.getIvy()).parse(ChainResolverTest.class.getResource("chainresolverconf.xml")); + DependencyResolver resolver = _data.getIvy().getResolver("chain"); + assertNotNull(resolver); + assertTrue(resolver instanceof ChainResolver); + ChainResolver chain = (ChainResolver)resolver; + assertResolversSizeAndNames(chain, 3); + } + + private void assertResolversSizeAndNames(ChainResolver chain, int size) { + List resolvers = chain.getResolvers(); + assertEquals(size, resolvers.size()); + for (int i=0; i < resolvers.size(); i++) { + DependencyResolver r = (DependencyResolver)resolvers.get(i); + assertEquals(String.valueOf(i+1), r.getName()); + } + } + + public void testName() throws Exception { + ChainResolver chain = new ChainResolver(); + chain.setName("chain"); + assertEquals("chain", chain.getName()); + } + + public void testResolveOrder() throws Exception { + ChainResolver chain = new ChainResolver(); + MockResolver[] resolvers = new MockResolver[] { + MockResolver.buildMockResolver("1", false, null), + MockResolver.buildMockResolver("2", true, null), + MockResolver.buildMockResolver("3", true, null) + }; + for (int i = 0; i < resolvers.length; i++) { + chain.add(resolvers[i]); + } + assertResolversSizeAndNames(chain, resolvers.length); + + + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "rev"), false); + ResolvedModuleRevision rmr = chain.getDependency(dd, _data); + assertNotNull(rmr); + assertEquals("2", rmr.getResolver().getName()); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), resolvers[0].askedDeps); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), resolvers[1].askedDeps); + assertTrue(resolvers[2].askedDeps.isEmpty()); + } + + public void testLatestResolve() throws Exception { + ChainResolver chain = new ChainResolver(); + MockResolver[] resolvers = new MockResolver[] { + MockResolver.buildMockResolver("1", true, new GregorianCalendar(2005, 1, 20).getTime()), + MockResolver.buildMockResolver("2", false, null), + MockResolver.buildMockResolver("3", true, new GregorianCalendar(2005, 1, 25).getTime()), // younger -> should the one kept + MockResolver.buildMockResolver("4", false, null), + MockResolver.buildMockResolver("5", true, new GregorianCalendar(2005, 1, 22).getTime()), + MockResolver.buildMockResolver("6", true, new GregorianCalendar(2005, 1, 18).getTime()), + MockResolver.buildMockResolver("7", false, null) + }; + for (int i = 0; i < resolvers.length; i++) { + chain.add(resolvers[i]); + } + assertResolversSizeAndNames(chain, resolvers.length); + + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "latest.integration"), false); + ResolvedModuleRevision rmr = chain.getDependency(dd, _data); + assertNotNull(rmr); + assertEquals("3", rmr.getResolver().getName()); + List ddAsList = Arrays.asList(new DependencyDescriptor[] {dd}); + for (int i = 0; i < resolvers.length; i++) { + assertEquals(ddAsList, resolvers[i].askedDeps); + } + } + + public void testReturnFirst() throws Exception { + ChainResolver chain = new ChainResolver(); + chain.setReturnFirst(true); + MockResolver[] resolvers = new MockResolver[] { + MockResolver.buildMockResolver("1", true, new GregorianCalendar(2005, 1, 20).getTime()), + MockResolver.buildMockResolver("2", false, null), + MockResolver.buildMockResolver("3", true, new GregorianCalendar(2005, 1, 25).getTime()), // younger -> should the one kept + MockResolver.buildMockResolver("4", false, null), + MockResolver.buildMockResolver("5", true, new GregorianCalendar(2005, 1, 22).getTime()), + MockResolver.buildMockResolver("6", true, new GregorianCalendar(2005, 1, 18).getTime()), + MockResolver.buildMockResolver("7", false, null) + }; + for (int i = 0; i < resolvers.length; i++) { + chain.add(resolvers[i]); + } + assertResolversSizeAndNames(chain, resolvers.length); + + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "latest.integration"), false); + ResolvedModuleRevision rmr = chain.getDependency(dd, _data); + assertNotNull(rmr); + assertEquals("1", rmr.getResolver().getName()); + List ddAsList = Arrays.asList(new DependencyDescriptor[] {dd}); + for (int i = 1; i < resolvers.length; i++) { + assertTrue(resolvers[i].askedDeps.isEmpty()); + } + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/DualResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/DualResolverTest.java new file mode 100644 index 00000000..351e427a --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/DualResolverTest.java @@ -0,0 +1,113 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.util.Arrays; +import java.util.GregorianCalendar; + +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.xml.XmlIvyConfigurationParser; +import junit.framework.TestCase; + +/** + * Test for DualResolver + */ +public class DualResolverTest extends TestCase { + private ResolveData _data = new ResolveData(new Ivy(), null, null, null, true); + + public void testFromConf() throws Exception { + Ivy ivy = new Ivy(); + new XmlIvyConfigurationParser(ivy).parse(DualResolverTest.class.getResource("dualresolverconf.xml")); + + DependencyResolver resolver = ivy.getResolver("dualok"); + assertNotNull(resolver); + assertTrue(resolver instanceof DualResolver); + DualResolver dual = (DualResolver)resolver; + assertNotNull(dual.getIvyResolver()); + assertEquals("ivy", dual.getIvyResolver().getName()); + assertNotNull(dual.getArtifactResolver()); + assertEquals("artifact", dual.getArtifactResolver().getName()); + + resolver = ivy.getResolver("dualnotenough"); + assertNotNull(resolver); + assertTrue(resolver instanceof DualResolver); + dual = (DualResolver)resolver; + assertNotNull(dual.getIvyResolver()); + assertNull(dual.getArtifactResolver()); + } + + public void testFromBadConf() throws Exception { + Ivy ivy = new Ivy(); + try { + new XmlIvyConfigurationParser(ivy).parse(DualResolverTest.class.getResource("dualresolverconf-bad.xml")); + fail("bad dual resolver configuration should raise exception"); + } catch (Exception ex) { + // ok -> bad conf has raised an exception + } + } + + public void testBad() throws Exception { + DualResolver dual = new DualResolver(); + dual.setIvyResolver(new IBiblioResolver()); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "rev"), false); + try { + dual.getDependency(dd, _data); + fail("bad dual resolver configuration should raise exception"); + } catch (Exception ex) { + // ok -> should have raised an exception + } + } + + public void testResolve() throws Exception { + DualResolver dual = new DualResolver(); + MockResolver ivyResolver = MockResolver.buildMockResolver("ivy", true, new GregorianCalendar(2005, 1, 20).getTime()); + MockResolver artifactResolver = MockResolver.buildMockResolver("artifact", false, new GregorianCalendar(2005, 1, 20).getTime()); + dual.setIvyResolver(ivyResolver); + dual.setArtifactResolver(artifactResolver); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "rev"), false); + ResolvedModuleRevision rmr = dual.getDependency(dd, _data); + + assertNotNull(rmr); + assertEquals(dual, rmr.getResolver()); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), ivyResolver.askedDeps); + assertTrue(artifactResolver.askedDeps.isEmpty()); + } + + public void testResolveFromArtifact() throws Exception { + DualResolver dual = new DualResolver(); + MockResolver ivyResolver = MockResolver.buildMockResolver("ivy", false, new GregorianCalendar(2005, 1, 20).getTime()); + MockResolver artifactResolver = MockResolver.buildMockResolver("artifact", true, new GregorianCalendar(2005, 1, 20).getTime()); + dual.setIvyResolver(ivyResolver); + dual.setArtifactResolver(artifactResolver); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "rev"), false); + ResolvedModuleRevision rmr = dual.getDependency(dd, _data); + + assertNotNull(rmr); + assertEquals(artifactResolver, rmr.getResolver()); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), ivyResolver.askedDeps); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), artifactResolver.askedDeps); + } + + public void testResolveFail() throws Exception { + DualResolver dual = new DualResolver(); + MockResolver ivyResolver = MockResolver.buildMockResolver("ivy", false, new GregorianCalendar(2005, 1, 20).getTime()); + MockResolver artifactResolver = MockResolver.buildMockResolver("artifact", false, new GregorianCalendar(2005, 1, 20).getTime()); + dual.setIvyResolver(ivyResolver); + dual.setArtifactResolver(artifactResolver); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org","mod", "rev"), false); + ResolvedModuleRevision rmr = dual.getDependency(dd, _data); + + assertNull(rmr); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), ivyResolver.askedDeps); + assertEquals(Arrays.asList(new DependencyDescriptor[] {dd}), artifactResolver.askedDeps); + } +} diff --git a/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java new file mode 100644 index 00000000..2b81c9af --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/FileSystemResolverTest.java @@ -0,0 +1,291 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.util.Date; +import java.util.GregorianCalendar; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.latest.LatestRevisionStrategy; +import fr.jayasoft.ivy.latest.LatestTimeStrategy; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; +import fr.jayasoft.ivy.util.FileUtil; + +/** + * + */ +public class FileSystemResolverTest extends TestCase { + + private static final String FS = System.getProperty("file.separator"); + private static final String IVY_PATTERN = "test"+FS+"repositories"+FS+"1"+FS+"[organisation]"+FS+"[module]"+FS+"ivys"+FS+"ivy-[revision].xml"; + private File _cache; + private ResolveData _data; + private Ivy _ivy = new Ivy(); + + protected void setUp() throws Exception { + _cache = new File("build/cache"); + _data = new ResolveData(_ivy, _cache, null, null, true); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testFixedRevision() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + + + // test to ask to download + DefaultArtifact artifact = new DefaultArtifact(mrid, pubdate, "mod1.1", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testCheckModified() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + _ivy.addResolver(resolver); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern("test"+FS+"repositories"+FS+"checkmodified"+FS+"ivy-[revision].xml"); + FileUtil.copy(new File("test/repositories/checkmodified/ivy-1.0-before.xml"), new File("test/repositories/checkmodified/ivy-1.0.xml"), null); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + + // updates ivy file in repository + FileUtil.copy(new File("test/repositories/checkmodified/ivy-1.0-after.xml"), new File("test/repositories/checkmodified/ivy-1.0.xml"), null); + + // should not get the new version + resolver.setCheckmodified(false); + rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + + // should now get the new version + resolver.setCheckmodified(true); + rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + pubdate = new GregorianCalendar(2005, 4, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testLatestTime() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + resolver.setLatestStrategy(new LatestTimeStrategy()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "2.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "latest.integration"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 1, 15, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testLatestRevision() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + resolver.setLatestStrategy(new LatestRevisionStrategy()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "2.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "latest.integration"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 1, 15, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testRelativePath() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(new File("src/java").getAbsolutePath()+"/../../"+IVY_PATTERN); + resolver.addArtifactPattern("src/../test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + resolver.setLatestStrategy(new LatestRevisionStrategy()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "2.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "latest.integration"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 1, 15, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testFormattedLatestTime() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + resolver.setLatestStrategy(new LatestTimeStrategy()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.1"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "1+"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 0, 2, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testFormattedLatestRevision() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + + resolver.setLatestStrategy(new LatestRevisionStrategy()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.1"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "1+"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 0, 2, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testPublish() throws Exception { + try { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern("test"+FS+"repositories"+FS+"1"+FS+"[organisation]"+FS+"[module]"+FS+"[revision]"+FS+"[artifact].[ext]"); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("myorg", "mymodule", "myrevision"); + Artifact ivyArtifact = new DefaultArtifact(mrid, new Date(), "ivy", "ivy", "xml"); + Artifact artifact = new DefaultArtifact(mrid, new Date(), "myartifact", "mytype", "myext"); + File src = new File("test/repositories/ivyconf.xml"); + resolver.publish(ivyArtifact, src); + resolver.publish(artifact, src); + + assertTrue(new File("test/repositories/1/myorg/mymodule/myrevision/ivy.xml").exists()); + assertTrue(new File("test/repositories/1/myorg/mymodule/mytypes/myartifact-myrevision.myext").exists()); + } finally { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(new File("test/repositories/1/myorg")); + del.execute(); + } + } + + public void testListing() throws Exception { + FileSystemResolver resolver = new FileSystemResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + resolver.addIvyPattern(IVY_PATTERN); + resolver.addArtifactPattern("test/repositories/1/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"); + + OrganisationEntry[] orgs = resolver.listOrganisations(); + ResolverTestHelper.assertOrganisationEntries(resolver, new String[] {"org1", "org2", "org6"}, orgs); + + OrganisationEntry org = ResolverTestHelper.getEntry(orgs, "org1"); + ModuleEntry[] mods = resolver.listModules(org); + ResolverTestHelper.assertModuleEntries(resolver, org, new String[] {"mod1.1", "mod1.2", "mod1.3", "mod1.4"}, mods); + + ModuleEntry mod = ResolverTestHelper.getEntry(mods, "mod1.1"); + RevisionEntry[] revs = resolver.listRevisions(mod); + ResolverTestHelper.assertRevisionEntries(resolver, mod, new String[] {"1.0", "1.0.1", "1.1", "2.0"}, revs); + + mod = ResolverTestHelper.getEntry(mods, "mod1.2"); + revs = resolver.listRevisions(mod); + ResolverTestHelper.assertRevisionEntries(resolver, mod, new String[] {"2.0", "2.1", "2.2"}, revs); + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/IBiblioHelper.java b/test/java/fr/jayasoft/ivy/resolver/IBiblioHelper.java new file mode 100644 index 00000000..8b479a0d --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/IBiblioHelper.java @@ -0,0 +1,66 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.net.URL; + +import fr.jayasoft.ivy.url.URLHandler; +import fr.jayasoft.ivy.url.URLHandlerRegistry; + +/** + * TODO write javadoc + */ +public class IBiblioHelper { + private static boolean _checked = false; + private static String _mirror = null; + private static URLHandler handler = URLHandlerRegistry.getHttp(); + public static String getIBiblioMirror() throws Exception { +// String[] mirrors = new String[] { +// "http://download.au.kde.org", +// "http://ftp.up.ac.za", +// "http://mirrors.sunsite.dk", +// "http://planetmirror.com", +// "http://www.ibiblio.org" +// }; + String[] mirrors = new String[] { + "http://ftp.up.ac.za/pub/linux/maven", + "http://mirrors.sunsite.dk/maven", + "http://public.planetmirror.com/pub/maven", + "http://www.ibiblio.org/maven" + }; + String[] mirrorsRoot = new String[] { + "http://ftp.up.ac.za/pub/linux/maven", + "http://mirrors.sunsite.dk/maven", + "http://public.planetmirror.com/pub/maven", + "http://www.ibiblio.org/maven" + }; + if (!_checked) { + long best = -1; + for (int i = 0; i < mirrors.length; i++) { + long start = System.currentTimeMillis(); + if (handler.isReachable(new URL(mirrors[i]), 300)) { + long took = System.currentTimeMillis() - start; + System.out.println("reached "+mirrors[i]+" in "+took+"ms"); + if (best == -1 || took < best) { + best = took; + _mirror = mirrorsRoot[i]; + } + } + } + if (_mirror == null) { + System.out.println("No ibiblio mirror available: no ibiblio test done"); + } + } + return _mirror; + } + + public static void main(String[] args) throws Exception { + long start = System.currentTimeMillis(); + String biblioMirror = getIBiblioMirror(); + System.out.println("best mirror is "+biblioMirror+ " - found in "+(System.currentTimeMillis() - start)+"ms"); + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/IBiblioResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/IBiblioResolverTest.java new file mode 100644 index 00000000..f7c6a8c3 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/IBiblioResolverTest.java @@ -0,0 +1,197 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultDependencyArtifactDescriptor; +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; + +/** + * + */ +public class IBiblioResolverTest extends TestCase { + private File _cache; + private ResolveData _data; + private Ivy _ivy; + + protected void setUp() throws Exception { + _cache = new File("build/cache"); + _ivy = new Ivy(); + _data = new ResolveData(_ivy, _cache, null, null, true); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testDefaults() { + IBiblioResolver resolver = new IBiblioResolver(); + Ivy ivy = new Ivy(); + ivy.setVariable("ivy.ibiblio.default.artifact.root", "http://www.ibiblio.org/mymaven/"); + ivy.setVariable("ivy.ibiblio.default.artifact.pattern", "[module]/jars/[artifact]-[revision].jar"); + resolver.setIvy(ivy); + List l = resolver.getArtifactPatterns(); + assertNotNull(l); + assertEquals(1, l.size()); + assertEquals("http://www.ibiblio.org/mymaven/[module]/jars/[artifact]-[revision].jar", l.get(0)); + } + + public void testInitFromConf() throws Exception { + Ivy ivy = new Ivy(); + ivy.setVariable("ivy.ibiblio.default.artifact.root", "http://www.ibiblio.org/maven/"); + ivy.setVariable("ivy.ibiblio.default.artifact.pattern", "[module]/jars/[artifact]-[revision].jar"); + ivy.setVariable("my.ibiblio.root", "http://www.ibiblio.org/mymaven/"); + ivy.setVariable("my.ibiblio.pattern", "[module]/[artifact]-[revision].jar"); + ivy.configure(IBiblioResolverTest.class.getResource("ibiblioresolverconf.xml")); + IBiblioResolver resolver = (IBiblioResolver)ivy.getResolver("ibiblio"); + assertNotNull(resolver); + List l = resolver.getArtifactPatterns(); + assertNotNull(l); + assertEquals(1, l.size()); + assertEquals("http://www.ibiblio.org/mymaven/[module]/[artifact]-[revision].jar", l.get(0)); + resolver = (IBiblioResolver)ivy.getResolver("ibiblio2"); + assertNotNull(resolver); + l = resolver.getArtifactPatterns(); + assertNotNull(l); + assertEquals(1, l.size()); + assertEquals("http://www.ibiblio.org/mymaven/[organisation]/jars/[artifact]-[revision].jar", l.get(0)); + } + + public void testIBiblio() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + IBiblioResolver resolver = new IBiblioResolver(); + resolver.setRoot(ibiblioRoot); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("apache", "commons-fileupload", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + assertEquals(mrid, rmr.getId()); + + DefaultArtifact artifact = new DefaultArtifact(mrid, rmr.getPublicationDate(), "commons-fileupload", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testIBiblioArtifacts() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + IBiblioResolver resolver = new IBiblioResolver(); + resolver.setRoot(ibiblioRoot); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("apache", "nanning", "0.9"); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(mrid, false); + dd.addDependencyArtifactIncludes("default", new DefaultDependencyArtifactDescriptor(dd, "nanning-profiler", "jar", "jar", true)); + dd.addDependencyArtifactIncludes("default", new DefaultDependencyArtifactDescriptor(dd, "nanning-trace", "jar", "jar", true)); + ResolvedModuleRevision rmr = resolver.getDependency(dd, _data); + assertNotNull(rmr); + assertEquals(mrid, rmr.getId()); + + DefaultArtifact profiler = new DefaultArtifact(mrid, rmr.getPublicationDate(), "nanning-profiler", "jar", "jar"); + DefaultArtifact trace = new DefaultArtifact(mrid, rmr.getPublicationDate(), "nanning-trace", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {profiler, trace}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(2, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(profiler); + assertNotNull(ar); + + assertEquals(profiler, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + ar = report.getArtifactReport(trace); + assertNotNull(ar); + + assertEquals(trace, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {profiler, trace}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(2, report.getArtifactsReports().length); + + ar = report.getArtifactReport(profiler); + assertNotNull(ar); + + assertEquals(profiler, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + + ar = report.getArtifactReport(trace); + assertNotNull(ar); + + assertEquals(trace, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testUnknown() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + IBiblioResolver resolver = new IBiblioResolver(); + resolver.setRoot(ibiblioRoot); + resolver.setName("test"); + resolver.setIvy(_ivy); + + assertNull(resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("unknown", "unknown", "1.0"), false), _data)); + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/IvyRepResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/IvyRepResolverTest.java new file mode 100644 index 00000000..df34d11a --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/IvyRepResolverTest.java @@ -0,0 +1,137 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.util.List; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; + +/** + * + */ +public class IvyRepResolverTest extends TestCase { + private File _cache; + private ResolveData _data; + private Ivy _ivy; + + protected void setUp() throws Exception { + _cache = new File("build/cache"); + _ivy = new Ivy(); + _data = new ResolveData(_ivy, _cache, null, null, false); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testDefaults() { + IvyRepResolver resolver = new IvyRepResolver(); + Ivy ivy = new Ivy(); + ivy.setVariable("ivy.ivyrep.default.ivy.root", "http://www.jayasoft.fr/myivyrep/"); + ivy.setVariable("ivy.ivyrep.default.ivy.pattern", "[organisation]/[module]/ivy-[revision].[ext]"); + ivy.setVariable("ivy.ivyrep.default.artifact.root", "http://www.ibiblio.org/mymaven/"); + ivy.setVariable("ivy.ivyrep.default.artifact.pattern", "[module]/jars/[artifact]-[revision].jar"); + resolver.setIvy(ivy); + List l = resolver.getIvyPatterns(); + assertNotNull(l); + assertEquals(1, l.size()); + assertEquals("http://www.jayasoft.fr/myivyrep/[organisation]/[module]/ivy-[revision].[ext]", l.get(0)); + l = resolver.getArtifactPatterns(); + assertNotNull(l); + assertEquals(1, l.size()); + assertEquals("http://www.ibiblio.org/mymaven/[module]/jars/[artifact]-[revision].jar", l.get(0)); + } + + public void testIvyRep() throws Exception { + IvyRepResolver resolver = new IvyRepResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("apache", "commons-cli", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + assertEquals(mrid, rmr.getId()); + assertEquals(2, rmr.getDescriptor().getDependencies().length); + + DefaultArtifact artifact = new DefaultArtifact(mrid, rmr.getPublicationDate(), "commons-cli", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + /* + * Tests IvyRepResolver with a root path given as 'file:/path_to_root' + */ + public void testIvyRepLocalURL() throws Exception { + IvyRepResolver resolver = new IvyRepResolver(); + String rootpath = new File("test/repositories/1").getAbsolutePath(); + + resolver.setName("testLocal"); + resolver.setIvyroot("file:" + rootpath); + resolver.setIvypattern("[organisation]/[module]/ivys/ivy-[revision].xml"); + resolver.setIvy(_ivy); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + } + + public void testListing() { + IvyRepResolver resolver = new IvyRepResolver(); + resolver.setName("test"); + resolver.setIvy(_ivy); + + OrganisationEntry[] orgs = resolver.listOrganisations(); + ResolverTestHelper.assertOrganisationEntriesContains(resolver, new String[] {"hibernate", "apache"}, orgs); + + OrganisationEntry org = ResolverTestHelper.getEntry(orgs, "apache"); + ModuleEntry[] mods = resolver.listModules(org); + ResolverTestHelper.assertModuleEntriesContains(resolver, org, new String[] {"commons-logging", "commons-lang"}, mods); + + ModuleEntry mod = ResolverTestHelper.getEntry(mods, "commons-logging"); + RevisionEntry[] revs = resolver.listRevisions(mod); + ResolverTestHelper.assertRevisionEntriesContains(resolver, mod, new String[] {"1.0", "1.0.2", "1.0.3", "1.0.4"}, revs); + } +} diff --git a/test/java/fr/jayasoft/ivy/resolver/MockResolver.java b/test/java/fr/jayasoft/ivy/resolver/MockResolver.java new file mode 100644 index 00000000..50d670ee --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/MockResolver.java @@ -0,0 +1,72 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.io.IOException; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.DownloadReport; + + +public class MockResolver extends AbstractResolver { + static MockResolver buildMockResolver(String name, boolean findRevision, final Date publicationDate) { + final MockResolver r = new MockResolver(); + r.setName(name); + if (findRevision) { + r.rmr = new ResolvedModuleRevision() { + public DependencyResolver getResolver() { + return r; + } + + public ModuleRevisionId getId() { + return null; + } + + public Date getPublicationDate() { + return publicationDate; + } + + public ModuleDescriptor getDescriptor() { + return null; + } + public boolean isDownloaded() { + return true; + } + public boolean isSearched() { + return true; + } + }; + } + return r; + } + + List askedDeps = new ArrayList(); + ResolvedModuleRevision rmr; + + public ResolvedModuleRevision getDependency(DependencyDescriptor dd, ResolveData data) throws ParseException { + askedDeps.add(dd); + return rmr; + } + + public DownloadReport download(Artifact[] artifacts, Ivy ivy, File cache) { + return null; + } + public void publish(Artifact artifact, File src) throws IOException { + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/ResolverTestHelper.java b/test/java/fr/jayasoft/ivy/resolver/ResolverTestHelper.java new file mode 100644 index 00000000..64c8aade --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/ResolverTestHelper.java @@ -0,0 +1,99 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import junit.framework.Assert; +import fr.jayasoft.ivy.DependencyResolver; + +/** + * + */ +public class ResolverTestHelper { + static void assertOrganisationEntries(DependencyResolver resolver, String[] orgNames, OrganisationEntry[] orgs) { + Assert.assertNotNull(orgs); + Assert.assertEquals(orgNames.length, orgs.length); + assertOrganisationEntriesContains(resolver, orgNames, orgs); + } + + static void assertOrganisationEntriesContains(DependencyResolver resolver, String[] orgNames, OrganisationEntry[] orgs) { + Assert.assertNotNull(orgs); + for (int i = 0; i < orgNames.length; i++) { + boolean found = false; + for (int j = 0; j < orgs.length; j++) { + if (orgNames[i].equals(orgs[j].getOrganisation())) { + found = true; + Assert.assertEquals(resolver, orgs[j].getResolver()); + } + } + Assert.assertTrue("organisation not found: "+orgNames[i], found); + } + } + + static void assertModuleEntries(DependencyResolver resolver, OrganisationEntry org, String[] names, ModuleEntry[] mods) { + Assert.assertNotNull(mods); + Assert.assertEquals(names.length, mods.length); + assertModuleEntriesContains(resolver, org, names, mods); + } + + + static void assertModuleEntriesContains(DependencyResolver resolver, OrganisationEntry org, String[] names, ModuleEntry[] mods) { + Assert.assertNotNull(mods); + for (int i = 0; i < names.length; i++) { + boolean found = false; + for (int j = 0; j < mods.length; j++) { + if (names[i].equals(mods[j].getModule())) { + found = true; + Assert.assertEquals(resolver, mods[j].getResolver()); + Assert.assertEquals(org, mods[j].getOrganisationEntry()); + } + } + Assert.assertTrue("module not found: "+names[i], found); + } + } + + + static void assertRevisionEntries(DependencyResolver resolver, ModuleEntry mod, String[] names, RevisionEntry[] revs) { + Assert.assertNotNull(revs); + Assert.assertEquals(names.length, revs.length); + assertRevisionEntriesContains(resolver, mod, names, revs); + } + + static void assertRevisionEntriesContains(DependencyResolver resolver, ModuleEntry mod, String[] names, RevisionEntry[] revs) { + Assert.assertNotNull(revs); + for (int i = 0; i < names.length; i++) { + boolean found = false; + for (int j = 0; j < revs.length; j++) { + if (names[i].equals(revs[j].getRevision())) { + found = true; + Assert.assertEquals(resolver, revs[j].getResolver()); + Assert.assertEquals(mod, revs[j].getModuleEntry()); + } + } + Assert.assertTrue("revision not found: "+names[i], found); + } + } + + static OrganisationEntry getEntry(OrganisationEntry[] orgs, String name) { + for (int i = 0; i < orgs.length; i++) { + if (name.equals(orgs[i].getOrganisation())) { + return orgs[i]; + } + } + Assert.fail("organisation not found: "+name); + return null; // for compilation only + } + + static ModuleEntry getEntry(ModuleEntry[] mods, String name) { + for (int i = 0; i < mods.length; i++) { + if (name.equals(mods[i].getModule())) { + return mods[i]; + } + } + Assert.fail("module not found: "+name); + return null; // for compilation only + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/URLResolverTest.java b/test/java/fr/jayasoft/ivy/resolver/URLResolverTest.java new file mode 100644 index 00000000..25f51628 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/URLResolverTest.java @@ -0,0 +1,246 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.resolver; + +import java.io.File; +import java.util.Date; +import java.util.GregorianCalendar; + +import junit.framework.TestCase; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Delete; + +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.DefaultArtifact; +import fr.jayasoft.ivy.DefaultDependencyArtifactDescriptor; +import fr.jayasoft.ivy.DefaultDependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.ModuleRevisionId; +import fr.jayasoft.ivy.ResolveData; +import fr.jayasoft.ivy.ResolvedModuleRevision; +import fr.jayasoft.ivy.report.ArtifactDownloadReport; +import fr.jayasoft.ivy.report.DownloadReport; +import fr.jayasoft.ivy.report.DownloadStatus; + +/** + * Tests URLResolver. Http tests are based upon ibiblio site. + * + */ +public class URLResolverTest extends TestCase { + private File _cache; + private ResolveData _data; + private Ivy _ivy = new Ivy(); + + protected void setUp() throws Exception { + _cache = new File("build/cache"); + _data = new ResolveData(_ivy, _cache, null, null, true); + _cache.mkdirs(); + } + + protected void tearDown() throws Exception { + Delete del = new Delete(); + del.setProject(new Project()); + del.setDir(_cache); + del.execute(); + } + + public void testFile() throws Exception { + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + String rootpath = new File("test/repositories/1").getAbsolutePath(); + resolver.addIvyPattern("file:"+rootpath + "/[organisation]/[module]/ivys/ivy-[revision].xml"); + resolver.addArtifactPattern("file:"+rootpath + "/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + + + // test to ask to download + DefaultArtifact artifact = new DefaultArtifact(mrid, pubdate, "mod1.1", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testLatestFile() throws Exception { + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + String rootpath = new File("test/repositories/1").getAbsolutePath().replaceAll("\\\\", "/"); + resolver.addIvyPattern("file:"+rootpath + "/[organisation]/[module]/ivys/ivy-[revision].xml"); + resolver.addArtifactPattern("file:"+rootpath + "/[organisation]/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("org1", "mod1.1", "2.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("org1", "mod1.1", "latest.integration"), false), _data); + assertNotNull(rmr); + + assertEquals(mrid, rmr.getId()); + Date pubdate = new GregorianCalendar(2005, 1, 15, 11, 0, 0).getTime(); + assertEquals(pubdate, rmr.getPublicationDate()); + } + + public void testIBiblio() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + resolver.addArtifactPattern(ibiblioRoot+"/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("apache", "commons-fileupload", "1.0"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + assertEquals(mrid, rmr.getId()); + + DefaultArtifact artifact = new DefaultArtifact(mrid, rmr.getPublicationDate(), "commons-fileupload", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {artifact}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(1, report.getArtifactsReports().length); + + ar = report.getArtifactReport(artifact); + assertNotNull(ar); + + assertEquals(artifact, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testIBiblioArtifacts() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + resolver.addArtifactPattern(ibiblioRoot+"/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("apache", "nanning", "0.9"); + DefaultDependencyDescriptor dd = new DefaultDependencyDescriptor(mrid, false); + dd.addDependencyArtifactIncludes("default", new DefaultDependencyArtifactDescriptor(dd, "nanning-profiler", "jar", "jar", true)); + dd.addDependencyArtifactIncludes("default", new DefaultDependencyArtifactDescriptor(dd, "nanning-trace", "jar", "jar", true)); + ResolvedModuleRevision rmr = resolver.getDependency(dd, _data); + assertNotNull(rmr); + assertEquals(mrid, rmr.getId()); + + DefaultArtifact profiler = new DefaultArtifact(mrid, rmr.getPublicationDate(), "nanning-profiler", "jar", "jar"); + DefaultArtifact trace = new DefaultArtifact(mrid, rmr.getPublicationDate(), "nanning-trace", "jar", "jar"); + DownloadReport report = resolver.download(new Artifact[] {profiler, trace}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(2, report.getArtifactsReports().length); + + ArtifactDownloadReport ar = report.getArtifactReport(profiler); + assertNotNull(ar); + + assertEquals(profiler, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + ar = report.getArtifactReport(trace); + assertNotNull(ar); + + assertEquals(trace, ar.getArtifact()); + assertEquals(DownloadStatus.SUCCESSFUL, ar.getDownloadStatus()); + + // test to ask to download again, should use cache + report = resolver.download(new Artifact[] {profiler, trace}, _data.getIvy(), _cache); + assertNotNull(report); + + assertEquals(2, report.getArtifactsReports().length); + + ar = report.getArtifactReport(profiler); + assertNotNull(ar); + + assertEquals(profiler, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + + ar = report.getArtifactReport(trace); + assertNotNull(ar); + + assertEquals(trace, ar.getArtifact()); + assertEquals(DownloadStatus.NO, ar.getDownloadStatus()); + } + + public void testLatestIBiblio() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + resolver.addArtifactPattern(ibiblioRoot+"/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + assertEquals("test", resolver.getName()); + + ModuleRevisionId mrid = ModuleRevisionId.newInstance("objectweb", "asm", "1.4+"); + ResolvedModuleRevision rmr = resolver.getDependency(new DefaultDependencyDescriptor(mrid, false), _data); + assertNotNull(rmr); + assertEquals("1.4.3", rmr.getId().getRevision()); + } + + public void testUnknown() throws Exception { + String ibiblioRoot = IBiblioHelper.getIBiblioMirror(); + if (ibiblioRoot == null) { + return; + } + + URLResolver resolver = new URLResolver(); + resolver.setIvy(_ivy); + resolver.addIvyPattern(ibiblioRoot+"/[module]/ivys/ivy-[revision].xml"); + resolver.addArtifactPattern(ibiblioRoot+"/maven/[module]/[type]s/[artifact]-[revision].[type]"); + resolver.setName("test"); + + assertNull(resolver.getDependency(new DefaultDependencyDescriptor(ModuleRevisionId.newInstance("unknown", "unknown", "1.0"), false), _data)); + } + +} diff --git a/test/java/fr/jayasoft/ivy/resolver/chainresolverconf.xml b/test/java/fr/jayasoft/ivy/resolver/chainresolverconf.xml new file mode 100644 index 00000000..6140a53d --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/chainresolverconf.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/resolver/dualresolverconf-bad.xml b/test/java/fr/jayasoft/ivy/resolver/dualresolverconf-bad.xml new file mode 100644 index 00000000..af9c36e5 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/dualresolverconf-bad.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/resolver/dualresolverconf.xml b/test/java/fr/jayasoft/ivy/resolver/dualresolverconf.xml new file mode 100644 index 00000000..7020e540 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/dualresolverconf.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/resolver/ibiblioresolverconf.xml b/test/java/fr/jayasoft/ivy/resolver/ibiblioresolverconf.xml new file mode 100644 index 00000000..5734ed58 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/resolver/ibiblioresolverconf.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/url/ApacheURLListerTest.java b/test/java/fr/jayasoft/ivy/url/ApacheURLListerTest.java new file mode 100644 index 00000000..97e73f06 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/url/ApacheURLListerTest.java @@ -0,0 +1,74 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import junit.framework.TestCase; + +import java.net.URL; +import java.util.Iterator; +import java.util.List; + + +/** + * Tests {@link ApacheURLLister}. + * + * @author Xavier Hanin + * @author John M. Shields + */ +public class ApacheURLListerTest extends TestCase { + //~ Methods ---------------------------------------------------------------- + + /** + * Tests {@link ApacheURLLister#retrieveListing(URL, boolean, boolean)}. + * + * @throws Exception + */ + public void testRetrieveListing() throws Exception { + URL url = new URL("http://www.ibiblio.org/maven/ant/jars/"); + + ApacheURLLister lister = new ApacheURLLister(); + + List files = lister.retrieveListing(url, true, false); + assertNotNull(files); + assertTrue(files.size() > 0); + + Iterator iter = files.iterator(); + + while (iter.hasNext()) { + URL file = (URL) iter.next(); + assertNotNull(file); + assertTrue("found non matching file: "+file.getPath(), file.getPath().matches(".*/ant/jars/[^/]*$")); + } + + // try a directory listing + url = new URL("http://www.ibiblio.org/maven/ant/"); + + List dirs = lister.retrieveListing(url, false, true); + assertNotNull(dirs); + assertTrue(dirs.size() > 0); + + iter = dirs.iterator(); + + while (iter.hasNext()) { + URL dir = (URL) iter.next(); + assertNotNull(dir); + assertTrue("found non matching dir: "+dir.getPath(), dir.getPath().matches(".*/$")); + } + + List empty = lister.retrieveListing(url, true, false); + assertTrue(empty.isEmpty()); + } + +// public void testRetrieveTomcatListing() throws Exception { +// URL url = new URL("http://localhost:8080/ivyrep/apache/commons-collections/"); +// +// ApacheURLLister lister = new ApacheURLLister(); +// +// List files = lister.retrieveListing(url, true, false); +// assertNotNull(files); +// assertTrue(files.size() > 0); +// } +} diff --git a/test/java/fr/jayasoft/ivy/url/BasicURLHandlerTest.java b/test/java/fr/jayasoft/ivy/url/BasicURLHandlerTest.java new file mode 100644 index 00000000..cf833893 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/url/BasicURLHandlerTest.java @@ -0,0 +1,29 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.url; + +import java.io.File; +import java.net.URL; + +import junit.framework.TestCase; + +/** + * Test BasicURLHandler + */ +public class BasicURLHandlerTest extends TestCase { + public void testIsReachable() throws Exception { + URLHandler handler = new BasicURLHandler(); + assertTrue(handler.isReachable(new URL("http://www.google.fr/"))); + assertFalse(handler.isReachable(new URL("http://www.google.fr/unknownpage.html"))); + + assertTrue(handler.isReachable(new File("build.xml").toURL())); + assertFalse(handler.isReachable(new File("unknownfile.xml").toURL())); + + // to test ftp we should know of an anonymous ftp site... ! +// assertTrue(handler.isReachable(new URL("ftp://ftp.mozilla.org/pub/dir.sizes"))); + assertFalse(handler.isReachable(new URL("ftp://ftp.mozilla.org/unknown.file"))); + } +} diff --git a/test/java/fr/jayasoft/ivy/util/ConfiguratorTest.java b/test/java/fr/jayasoft/ivy/util/ConfiguratorTest.java new file mode 100644 index 00000000..3f45b279 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/util/ConfiguratorTest.java @@ -0,0 +1,247 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.util; + +import java.util.ArrayList; +import java.util.List; + +import fr.jayasoft.ivy.util.Configurator; + +import junit.framework.TestCase; + +/** + * @author x.hanin + * + */ +public class ConfiguratorTest extends TestCase { + public static class City { + private List _housings = new ArrayList(); + private List _streets = new ArrayList(); + + private String _name; + public String getName() { + return _name; + } + public void setName(String name) { + _name = name; + } + public List getHousings() { + return _housings; + } + public List getStreets() { + return _streets; + } + public void add(Housing h) { + _housings.add(h); + } + public void add(Street s) { + _streets.add(s); + } + } + + public static class Street { + private Class _clazz; + private List _trees = new ArrayList(); + public List getTrees() { + return _trees; + } + public void addConfiguredTree(Tree tree) { + _trees.add(tree); + } + public Class getClazz() { + return _clazz; + } + public void setClazz(Class clazz) { + _clazz = clazz; + } + } + + public static abstract class Housing { + private List _rooms = new ArrayList(); + private boolean _isEmpty; + private Person _proprietary; + + public List getRooms() { + return _rooms; + } + public void addRoom(Room r) { + _rooms.add(r); + } + public boolean isEmpty() { + return _isEmpty; + } + public void setEmpty(boolean isEmpty) { + _isEmpty = isEmpty; + } + public Person getProprietary() { + return _proprietary; + } + public void setProprietary(Person proprietary) { + _proprietary = proprietary; + } + } + + public static class House extends Housing { + } + + public static class Tree { + private short _age; + public short getAge() { + return _age; + } + public void setAge(short age) { + _age = age; + } + } + + public static class Flat extends Housing { + private int _stage; + public int getStage() { + return _stage; + } + public void setStage(int stage) { + _stage = stage; + } + } + + public static class Room { + private short _surface; + public short getSurface() { + return _surface; + } + public void setSurface(short surface) { + _surface = surface; + } + } + + public static class Person { + private String _name; + + public Person(String name) { + _name = name; + } + public String getName() { + return _name; + } + } + + private Configurator _conf; + + protected void setUp() throws Exception { + _conf = new Configurator(); + } + + public void testSetRoot() { + City city = new City(); + _conf.setRoot(city); + assertEquals(city, _conf.getCurrent()); + } + + public void testStringAttribute() { + City city = new City(); + _conf.setRoot(city); + _conf.setAttribute("name", "bordeaux"); + assertEquals("bordeaux", city.getName()); + } + + public void testIntAttribute() { + Flat flat = new Flat(); + _conf.setRoot(flat); + _conf.setAttribute("stage", "4"); + assertEquals(4, flat.getStage()); + } + + public void testBooleanAttribute() { + Housing housing = new House(); + _conf.setRoot(housing); + _conf.setAttribute("empty", "true"); + assertEquals(true, housing.isEmpty()); + _conf.setAttribute("empty", "false"); + assertEquals(false, housing.isEmpty()); + _conf.setAttribute("empty", "yes"); + assertEquals(true, housing.isEmpty()); + _conf.setAttribute("empty", "no"); + assertEquals(false, housing.isEmpty()); + _conf.setAttribute("empty", "on"); + assertEquals(true, housing.isEmpty()); + _conf.setAttribute("empty", "off"); + assertEquals(false, housing.isEmpty()); + } + + public void testClassAttribute() { + Street street = new Street(); + _conf.setRoot(street); + _conf.setAttribute("clazz", getClass().getName()); + assertEquals(getClass(), street.getClazz()); + } + + public void testPersonAttribute() { + Housing housing = new House(); + _conf.setRoot(housing); + _conf.setAttribute("proprietary", "jean"); + assertEquals("jean", housing.getProprietary().getName()); + } + + public void testAddRoom() { + Housing housing = new House(); + _conf.setRoot(housing); + _conf.startCreateChild("room"); + assertEquals(1, housing.getRooms().size()); + _conf.setAttribute("surface", "24"); + assertEquals(24, ((Room)housing.getRooms().get(0)).getSurface()); + _conf.endCreateChild(); + assertEquals(housing, _conf.getCurrent()); + } + public void testAddConfiguredTree() { + Street street = new Street(); + _conf.setRoot(street); + _conf.startCreateChild("tree"); + assertTrue(street.getTrees().isEmpty()); + _conf.setAttribute("age", "400"); + _conf.endCreateChild(); + assertEquals(1, street.getTrees().size()); + assertEquals(400, ((Tree)street.getTrees().get(0)).getAge()); + assertEquals(street, _conf.getCurrent()); + } + public void testAddWithTypeDef() throws Exception { + City city = new City(); + _conf.typeDef("house", House.class.getName()); + _conf.typeDef("flat", Flat.class.getName()); + _conf.typeDef("street", Street.class.getName()); + _conf.setRoot(city); + _conf.startCreateChild("house"); + assertEquals(1, city.getHousings().size()); + assertTrue(city.getHousings().get(0) instanceof House); + _conf.endCreateChild(); + _conf.startCreateChild("flat"); + assertEquals(2, city.getHousings().size()); + assertTrue(city.getHousings().get(1) instanceof Flat); + _conf.endCreateChild(); + _conf.startCreateChild("street"); + assertEquals(1, city.getStreets().size()); + _conf.endCreateChild(); + assertEquals(city, _conf.getCurrent()); + } + public void testNested() throws Exception { + City city = new City(); + _conf.typeDef("house", House.class.getName()); + _conf.typeDef("flat", Flat.class.getName()); + _conf.typeDef("street", Street.class.getName()); + _conf.setRoot(city); + _conf.startCreateChild("house"); + _conf.startCreateChild("room"); + _conf.setAttribute("surface", "20"); + _conf.endCreateChild(); + _conf.startCreateChild("room"); + _conf.setAttribute("surface", "25"); + _conf.endCreateChild(); + _conf.endCreateChild(); + assertEquals(city, _conf.getCurrent()); + assertEquals(2, ((Housing)city.getHousings().get(0)).getRooms().size()); + assertEquals(20, ((Room)((Housing)city.getHousings().get(0)).getRooms().get(0)).getSurface()); + assertEquals(25, ((Room)((Housing)city.getHousings().get(0)).getRooms().get(1)).getSurface()); + } +} diff --git a/test/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParserTest.java b/test/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParserTest.java new file mode 100644 index 00000000..5b516699 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/XmlIvyConfigurationParserTest.java @@ -0,0 +1,97 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.File; +import java.util.List; + +import junit.framework.TestCase; +import fr.jayasoft.ivy.DependencyResolver; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.LatestStrategy; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.latest.LatestRevisionStrategy; +import fr.jayasoft.ivy.latest.LatestTimeStrategy; +import fr.jayasoft.ivy.resolver.ChainResolver; +import fr.jayasoft.ivy.resolver.FileSystemResolver; +import fr.jayasoft.ivy.resolver.MockResolver; + +/** + * TODO write javadoc + */ +public class XmlIvyConfigurationParserTest extends TestCase { + public void test() throws Exception { + Ivy ivy = new Ivy(); + XmlIvyConfigurationParser parser = new XmlIvyConfigurationParser(ivy); + parser.parse(XmlIvyConfigurationParserTest.class.getResource("ivyconf-test.xml")); + + File defaultCache = ivy.getDefaultCache(); + assertNotNull(defaultCache); + assertEquals("mycache", defaultCache.getName()); + + assertFalse(ivy.isCheckUpToDate()); + assertFalse(ivy.doValidate()); + + assertEquals("[module]/ivys/ivy-[revision].xml", ivy.getCacheIvyPattern()); + assertEquals("[module]/[type]s/[artifact]-[revision].[ext]", ivy.getCacheArtifactPattern()); + + DependencyResolver defaultResolver = ivy.getDefaultResolver(); + assertNotNull(defaultResolver); + assertEquals("libraries", defaultResolver.getName()); + assertTrue(defaultResolver instanceof FileSystemResolver); + FileSystemResolver fsres = (FileSystemResolver)defaultResolver; + List ivyPatterns = fsres.getIvyPatterns(); + assertNotNull(ivyPatterns); + assertEquals(1, ivyPatterns.size()); + assertEquals("lib/[organisation]/[module]/ivys/ivy-[revision].xml", ivyPatterns.get(0)); + + LatestStrategy strategy = fsres.getLatestStrategy(); + assertNotNull(strategy); + assertTrue(strategy instanceof LatestRevisionStrategy); + + DependencyResolver internal = ivy.getResolver("internal"); + assertNotNull(internal); + assertTrue(internal instanceof ChainResolver); + ChainResolver chain = (ChainResolver)internal; + List subresolvers = chain.getResolvers(); + assertNotNull(subresolvers); + assertEquals(2, subresolvers.size()); + FileSystemResolver fsInt1 = (FileSystemResolver)subresolvers.get(0); + assertEquals("int1", fsInt1.getName()); + assertEquals("int2", ((DependencyResolver)subresolvers.get(1)).getName()); + + strategy = fsInt1.getLatestStrategy(); + assertNotNull(strategy); + assertTrue(strategy instanceof LatestTimeStrategy); + + assertEquals("libraries", ivy.getResolver(new ModuleId("unknown", "lib")).getName()); + assertEquals("internal", ivy.getResolver(new ModuleId("jayasoft", "ivy")).getName()); + + } + + public void testTypedef() throws Exception { + Ivy ivy = new Ivy(); + XmlIvyConfigurationParser parser = new XmlIvyConfigurationParser(ivy); + parser.parse(XmlIvyConfigurationParserTest.class.getResource("ivyconf-typedef.xml")); + + DependencyResolver mock = ivy.getResolver("mock3"); + assertNotNull(mock); + assertTrue(mock instanceof MockResolver); + + DependencyResolver internal = ivy.getResolver("internal"); + assertNotNull(internal); + assertTrue(internal instanceof ChainResolver); + ChainResolver chain = (ChainResolver)internal; + List subresolvers = chain.getResolvers(); + assertNotNull(subresolvers); + assertEquals(2, subresolvers.size()); + + assertEquals("mock1", ((DependencyResolver)subresolvers.get(0)).getName()); + assertEquals("mock2", ((DependencyResolver)subresolvers.get(1)).getName()); + assertTrue(subresolvers.get(0) instanceof MockResolver); + assertTrue(subresolvers.get(1) instanceof MockResolver); + } +} diff --git a/test/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParserTest.java b/test/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParserTest.java new file mode 100644 index 00000000..1c3fd4b5 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/XmlModuleDescriptorParserTest.java @@ -0,0 +1,399 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.IOException; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashSet; + +import junit.framework.TestCase; +import fr.jayasoft.ivy.Artifact; +import fr.jayasoft.ivy.Configuration; +import fr.jayasoft.ivy.ConflictManager; +import fr.jayasoft.ivy.DependencyArtifactDescriptor; +import fr.jayasoft.ivy.DependencyDescriptor; +import fr.jayasoft.ivy.Ivy; +import fr.jayasoft.ivy.License; +import fr.jayasoft.ivy.ModuleDescriptor; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.Configuration.Visibility; +import fr.jayasoft.ivy.conflict.FixedConflictManager; +import fr.jayasoft.ivy.conflict.NoConflictManager; + +/** + * + */ +public class XmlModuleDescriptorParserTest extends TestCase { + private Ivy _ivy = new Ivy(); + public void testSimple() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-simple.xml"), true); + assertNotNull(md); + assertEquals("myorg", md.getModuleRevisionId().getOrganisation()); + assertEquals("mymodule", md.getModuleRevisionId().getName()); + assertEquals(null, md.getModuleRevisionId().getRevision()); + assertEquals("integration", md.getStatus()); + + assertNotNull(md.getConfigurations()); + assertEquals(Arrays.asList(new Configuration[] {new Configuration("default")}), Arrays.asList(md.getConfigurations())); + + assertNotNull(md.getArtifacts("default")); + assertEquals(1, md.getArtifacts("default").length); + assertEquals("mymodule", md.getArtifacts("default")[0].getName()); + assertEquals("jar", md.getArtifacts("default")[0].getType()); + + assertNotNull(md.getDependencies()); + assertEquals(0, md.getDependencies().length); + } + + public void testBad() throws IOException { + try { + XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-bad.xml"), true); + fail("bad ivy file raised no error"); + } catch (ParseException ex) { + // ok + } + } + + public void testNoValidate() throws IOException, ParseException { + XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-novalidate.xml"), false); + } + + public void testBadVersion() throws IOException { + try { + XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-bad-version.xml"), true); + fail("bad version ivy file raised no error"); + } catch (ParseException ex) { + // ok + } + } + + public void testFull() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test.xml"), true); + assertNotNull(md); + assertEquals("myorg", md.getModuleRevisionId().getOrganisation()); + assertEquals("mymodule", md.getModuleRevisionId().getName()); + assertEquals("myrev", md.getModuleRevisionId().getRevision()); + assertEquals("integration", md.getStatus()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, md.getPublicationDate()); + + License[] licenses = md.getLicenses(); + assertEquals(1, licenses.length); + assertEquals("MyLicense", licenses[0].getName()); + assertEquals("http://www.my.org/mymodule/mylicense.html", licenses[0].getUrl()); + + assertEquals("http://www.my.org/mymodule/", md.getHomePage()); + + Configuration[] confs = md.getConfigurations(); + assertNotNull(confs); + assertEquals(5, confs.length); + + assertConf(md, "myconf1", "desc 1", Configuration.Visibility.PUBLIC, new String[0]); + assertConf(md, "myconf2", "desc 2", Configuration.Visibility.PUBLIC, new String[0]); + assertConf(md, "myconf3", "desc 3", Configuration.Visibility.PRIVATE, new String[0]); + assertConf(md, "myconf4", "desc 4", Configuration.Visibility.PUBLIC, new String[] {"myconf1", "myconf2"}); + assertConf(md, "myoldconf", "my old desc", Configuration.Visibility.PUBLIC, new String[0]); + + assertArtifacts(md.getArtifacts("myconf1"), new String[] {"myartifact1", "myartifact2", "myartifact3", "myartifact4"}); + assertArtifacts(md.getArtifacts("myconf2"), new String[] {"myartifact1", "myartifact3"}); + assertArtifacts(md.getArtifacts("myconf3"), new String[] {"myartifact1", "myartifact3", "myartifact4"}); + assertArtifacts(md.getArtifacts("myconf4"), new String[] {"myartifact1"}); + + DependencyDescriptor[] dependencies = md.getDependencies(); + assertNotNull(dependencies); + assertEquals(11, dependencies.length); + + // no conf def => equivalent to *->* + DependencyDescriptor dd = getDependency(dependencies, "mymodule2"); + assertNotNull(dd); + assertEquals("myorg", dd.getDependencyId().getOrganisation()); + assertEquals("2.0", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"*"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"*"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {"*"}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf2", "myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + // conf="myconf1" => equivalent to myconf1->myconf1 + dd = getDependency(dependencies, "yourmodule1"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("1.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"myconf1"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"myconf1"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf2", "myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + // conf="myconf1->yourconf1" + dd = getDependency(dependencies, "yourmodule2"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("2+", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"myconf1"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"yourconf1"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf2", "myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + // conf="myconf1->yourconf1, yourconf2" + dd = getDependency(dependencies, "yourmodule3"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("3.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"myconf1"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf2", "myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + // conf="myconf1, myconf2->yourconf1, yourconf2" + dd = getDependency(dependencies, "yourmodule4"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("4.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"myconf1", "myconf2"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf2"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + // conf="myconf1->yourconf1;myconf2->yourconf1, yourconf2" + dd = getDependency(dependencies, "yourmodule5"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("5.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"myconf1", "myconf2"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertEquals(Arrays.asList(new String[] {"yourconf1"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf2"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + dd = getDependency(dependencies, "yourmodule6"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("latest.integration", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"myconf1", "myconf2"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertEquals(Arrays.asList(new String[] {"yourconf1"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf2"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + dd = getDependency(dependencies, "yourmodule7"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("7.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"myconf1", "myconf2"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertEquals(Arrays.asList(new String[] {"yourconf1"}), Arrays.asList(dd.getDependencyConfigurations("myconf1"))); + assertEquals(Arrays.asList(new String[] {"yourconf1", "yourconf2"}), Arrays.asList(dd.getDependencyConfigurations("myconf2"))); + assertEquals(Arrays.asList(new String[] {}), Arrays.asList(dd.getDependencyConfigurations(new String[] {"myconf3", "myconf4"}))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1", "myconf2", "myconf3", "myconf4"}, new String[0]); + + dd = getDependency(dependencies, "yourmodule8"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("8.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"*"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1"}, new String[] {"yourartifact8-1", "yourartifact8-2"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf2"}, new String[] {"yourartifact8-1", "yourartifact8-2"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf3"}, new String[] {"yourartifact8-1", "yourartifact8-2"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf4"}, new String[] {"yourartifact8-1", "yourartifact8-2"}); + + dd = getDependency(dependencies, "yourmodule9"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("9.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"myconf1", "myconf2", "myconf3"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1"}, new String[] {"yourartifact9-1"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf2"}, new String[] {"yourartifact9-1", "yourartifact9-2"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf3"}, new String[] {"yourartifact9-2"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf4"}, new String[] {}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf1"}, new String[] {}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf2"}, new String[] {}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf3"}, new String[] {}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf4"}, new String[] {}); + + dd = getDependency(dependencies, "yourmodule10"); + assertNotNull(dd); + assertEquals("yourorg", dd.getDependencyId().getOrganisation()); + assertEquals("10.1", dd.getDependencyRevisionId().getRevision()); + assertEquals(new HashSet(Arrays.asList(new String[] {"*"})), new HashSet(Arrays.asList(dd.getModuleConfigurations()))); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf1"}, new String[] {"your.*", ".*"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf2"}, new String[] {"your.*", ".*"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf3"}, new String[] {"your.*", ".*"}); + assertDependencyArtifactsIncludes(dd, new String[] {"myconf4"}, new String[] {"your.*", ".*"}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf1"}, new String[] {"toexclude"}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf2"}, new String[] {"toexclude"}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf3"}, new String[] {"toexclude"}); + assertDependencyArtifactsExcludes(dd, new String[] {"myconf4"}, new String[] {"toexclude"}); + + ConflictManager cm = md.getConflictManager(new ModuleId("yourorg", "yourmodule1")); + assertNotNull(cm); + assertTrue(cm instanceof NoConflictManager); + + cm = md.getConflictManager(new ModuleId("yourorg", "yourmodule2")); + assertNotNull(cm); + assertTrue(cm instanceof NoConflictManager); + + cm = md.getConflictManager(new ModuleId("theirorg", "theirmodule1")); + assertNotNull(cm); + assertTrue(cm instanceof FixedConflictManager); + FixedConflictManager fcm = (FixedConflictManager)cm; + assertEquals(2, fcm.getRevs().size()); + assertTrue(fcm.getRevs().contains("1.0")); + assertTrue(fcm.getRevs().contains("1.1")); + + cm = md.getConflictManager(new ModuleId("theirorg", "theirmodule2")); + assertNull(cm); + } + + public void testBug60() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-bug60.xml"), true); + assertNotNull(md); + assertEquals("myorg", md.getModuleRevisionId().getOrganisation()); + assertEquals("mymodule", md.getModuleRevisionId().getName()); + assertEquals("myrev", md.getModuleRevisionId().getRevision()); + assertEquals("integration", md.getStatus()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, md.getPublicationDate()); + + assertEquals(Arrays.asList(new Configuration[] {new Configuration("default")}), Arrays.asList(md.getConfigurations())); + + assertArtifacts(md.getArtifacts("default"), new String[] {"myartifact1", "myartifact2"}); + } + + public void testNoArtifact() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-noartifact.xml"), true); + assertNotNull(md); + assertEquals("myorg", md.getModuleRevisionId().getOrganisation()); + assertEquals("mymodule", md.getModuleRevisionId().getName()); + assertEquals(null, md.getModuleRevisionId().getRevision()); + assertEquals("integration", md.getStatus()); + + assertNotNull(md.getConfigurations()); + assertEquals(Arrays.asList(new Configuration[] {new Configuration("default")}), Arrays.asList(md.getConfigurations())); + + assertNotNull(md.getArtifacts("default")); + assertEquals(0, md.getArtifacts("default").length); + + assertNotNull(md.getDependencies()); + assertEquals(0, md.getDependencies().length); + } + + public void testNoPublication() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-nopublication.xml"), true); + assertNotNull(md); + assertEquals("myorg", md.getModuleRevisionId().getOrganisation()); + assertEquals("mymodule", md.getModuleRevisionId().getName()); + assertEquals("myrev", md.getModuleRevisionId().getRevision()); + assertEquals("integration", md.getStatus()); + Date pubdate = new GregorianCalendar(2004, 10, 1, 11, 0, 0).getTime(); + assertEquals(pubdate, md.getPublicationDate()); + + assertNotNull(md.getConfigurations()); + assertEquals(Arrays.asList(new Configuration[] {new Configuration("default")}), Arrays.asList(md.getConfigurations())); + + assertNotNull(md.getArtifacts("default")); + assertEquals(1, md.getArtifacts("default").length); + + assertNotNull(md.getDependencies()); + assertEquals(1, md.getDependencies().length); + } + + public void testDefaultConf() throws Exception { + ModuleDescriptor md = XmlModuleDescriptorParser.parseDescriptor(_ivy, getClass().getResource("test-defaultconf.xml"), true); + assertNotNull(md); + + DependencyDescriptor[] dependencies = md.getDependencies(); + assertNotNull(dependencies); + assertEquals(2, dependencies.length); + + // no conf def => defaults to defaultConf: default + DependencyDescriptor dd = getDependency(dependencies, "mymodule1"); + assertNotNull(dd); + assertEquals("myorg", dd.getDependencyId().getOrganisation()); + assertEquals("1.0", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"default"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"default"}), Arrays.asList(dd.getDependencyConfigurations("default"))); + + // confs def: *->* + dd = getDependency(dependencies, "mymodule2"); + assertNotNull(dd); + assertEquals("myorg", dd.getDependencyId().getOrganisation()); + assertEquals("2.0", dd.getDependencyRevisionId().getRevision()); + assertEquals(Arrays.asList(new String[] {"*"}), Arrays.asList(dd.getModuleConfigurations())); + assertEquals(Arrays.asList(new String[] {"*"}), Arrays.asList(dd.getDependencyConfigurations("default"))); + } + + private DependencyDescriptor getDependency(DependencyDescriptor[] dependencies, String name) { + for (int i = 0; i < dependencies.length; i++) { + assertNotNull(dependencies[i]); + assertNotNull(dependencies[i].getDependencyId()); + if (name.equals(dependencies[i].getDependencyId().getName())) { + return dependencies[i]; + } + } + return null; + } + + private void assertArtifacts(Artifact[] artifacts, String[] artifactsNames) { + assertNotNull(artifacts); + assertEquals(artifactsNames.length, artifacts.length); + for (int i = 0; i < artifactsNames.length; i++) { + boolean found = false; + for (int j = 0; j < artifacts.length; j++) { + assertNotNull(artifacts[j]); + if (artifacts[j].getName().equals(artifactsNames[i])) { + found = true; + break; + } + } + assertTrue("artifact not found: "+artifactsNames[i], found); + } + } + + private void assertDependencyArtifactsIncludes(DependencyDescriptor dd, String[] confs, String[] artifactsNames) { + DependencyArtifactDescriptor[] dads = dd.getDependencyArtifactsIncludes(confs); + assertNotNull(dads); + assertEquals(artifactsNames.length, dads.length); + for (int i = 0; i < artifactsNames.length; i++) { + boolean found = false; + for (int j = 0; j < dads.length; j++) { + assertNotNull(dads[j]); + if (dads[j].getName().equals(artifactsNames[i])) { + found = true; + break; + } + } + assertTrue("dependency artifact include not found: "+artifactsNames[i], found); + } + } + + private void assertDependencyArtifactsExcludes(DependencyDescriptor dd, String[] confs, String[] artifactsNames) { + DependencyArtifactDescriptor[] dads = dd.getDependencyArtifactsExcludes(confs); + assertNotNull(dads); + assertEquals(artifactsNames.length, dads.length); + for (int i = 0; i < artifactsNames.length; i++) { + boolean found = false; + for (int j = 0; j < dads.length; j++) { + assertNotNull(dads[j]); + if (dads[j].getName().equals(artifactsNames[i])) { + found = true; + break; + } + } + assertTrue("dependency artifact exclude not found: "+artifactsNames[i], found); + } + } + + private void assertConf(ModuleDescriptor md, String name, String desc, Visibility visibility, String[] exts) { + Configuration conf = md.getConfiguration(name); + assertNotNull("configuration not found: "+name, conf); + assertEquals(name, conf.getName()); + assertEquals(desc, conf.getDescription()); + assertEquals(visibility, conf.getVisibility()); + assertEquals(Arrays.asList(exts), Arrays.asList(conf.getExtends())); + } +} diff --git a/test/java/fr/jayasoft/ivy/xml/XmlModuleUpdaterTest.java b/test/java/fr/jayasoft/ivy/xml/XmlModuleUpdaterTest.java new file mode 100644 index 00000000..855afc2b --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/XmlModuleUpdaterTest.java @@ -0,0 +1,49 @@ +/* + * This file is subject to the license found in LICENCE.TXT in the root directory of the project. + * + * #SNAPSHOT# + */ +package fr.jayasoft.ivy.xml; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.InputStreamReader; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; +import fr.jayasoft.ivy.ModuleId; +import fr.jayasoft.ivy.util.FileUtil; + +public class XmlModuleUpdaterTest extends TestCase { + + public void testUpdate() throws Exception { + /* + * For updated file to be equals to updated.xml, + * we have to fix the line separator to the one used + * in updated.xml, in order for this test to works in + * all platforms (default line separator used in + * updater being platform dependent + */ + XmlModuleDescriptorUpdater.LINE_SEPARATOR = "\n"; + File dest = new File("build/updated-test.xml"); + dest.deleteOnExit(); + Map resolvedRevisions = new HashMap(); + resolvedRevisions.put(new ModuleId("yourorg", "yourmodule2"), "2.5"); + resolvedRevisions.put(new ModuleId("yourorg", "yourmodule6"), "6.3"); + + GregorianCalendar cal = new GregorianCalendar(); + cal.set(2005, 2, 22, 14, 32, 54); + + XmlModuleDescriptorUpdater.update( + XmlModuleUpdaterTest.class.getResource("test.xml"), + dest, resolvedRevisions, "release", "mynewrev", cal.getTime(), "myresolver"); + + assertTrue(dest.exists()); + String expected = FileUtil.readEntirely(new BufferedReader(new InputStreamReader(XmlModuleUpdaterTest.class.getResourceAsStream("updated.xml")))); + String updated = FileUtil.readEntirely(new BufferedReader(new FileReader(dest))); + assertEquals(expected, updated); + } +} diff --git a/test/java/fr/jayasoft/ivy/xml/ivyconf-test.xml b/test/java/fr/jayasoft/ivy/xml/ivyconf-test.xml new file mode 100644 index 00000000..e443c867 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/ivyconf-test.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/ivyconf-typedef.xml b/test/java/fr/jayasoft/ivy/xml/ivyconf-typedef.xml new file mode 100644 index 00000000..691c110c --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/ivyconf-typedef.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/ivyconf.properties b/test/java/fr/jayasoft/ivy/xml/ivyconf.properties new file mode 100644 index 00000000..7d10aca2 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/ivyconf.properties @@ -0,0 +1 @@ +libraries.dir=lib \ No newline at end of file diff --git a/test/java/fr/jayasoft/ivy/xml/test-bad-version.xml b/test/java/fr/jayasoft/ivy/xml/test-bad-version.xml new file mode 100644 index 00000000..7221b419 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-bad-version.xml @@ -0,0 +1,6 @@ + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-bad.xml b/test/java/fr/jayasoft/ivy/xml/test-bad.xml new file mode 100644 index 00000000..2eb00c4a --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-bad.xml @@ -0,0 +1,6 @@ + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-bug60.xml b/test/java/fr/jayasoft/ivy/xml/test-bug60.xml new file mode 100644 index 00000000..fcf57ede --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-bug60.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-defaultconf.xml b/test/java/fr/jayasoft/ivy/xml/test-defaultconf.xml new file mode 100644 index 00000000..24a98ef0 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-defaultconf.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-noartifact.xml b/test/java/fr/jayasoft/ivy/xml/test-noartifact.xml new file mode 100644 index 00000000..c4261d9f --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-noartifact.xml @@ -0,0 +1,6 @@ + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-nopublication.xml b/test/java/fr/jayasoft/ivy/xml/test-nopublication.xml new file mode 100644 index 00000000..abb501d5 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-nopublication.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-novalidate.xml b/test/java/fr/jayasoft/ivy/xml/test-novalidate.xml new file mode 100644 index 00000000..741b302e --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-novalidate.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test-simple.xml b/test/java/fr/jayasoft/ivy/xml/test-simple.xml new file mode 100644 index 00000000..2b75131d --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test-simple.xml @@ -0,0 +1,5 @@ + + + diff --git a/test/java/fr/jayasoft/ivy/xml/test.xml b/test/java/fr/jayasoft/ivy/xml/test.xml new file mode 100644 index 00000000..b77ea161 --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/test.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + This module is great !
    + You can use it especially with myconf1 and myconf2, and myconf4 is not too bad too. +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/test/java/fr/jayasoft/ivy/xml/updated.xml b/test/java/fr/jayasoft/ivy/xml/updated.xml new file mode 100644 index 00000000..22ace16b --- /dev/null +++ b/test/java/fr/jayasoft/ivy/xml/updated.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + This module is great !
    + You can use it especially with myconf1 and myconf2, and myconf4 is not too bad too. +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    \ No newline at end of file diff --git a/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.1.xml b/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.1.xml new file mode 100644 index 00000000..603e12cc --- /dev/null +++ b/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.1.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml b/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml new file mode 100644 index 00000000..c3d6a682 --- /dev/null +++ b/test/repositories/1/org1/mod1.1/ivys/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/1/org1/mod1.1/ivys/ivy-1.1.xml b/test/repositories/1/org1/mod1.1/ivys/ivy-1.1.xml new file mode 100644 index 00000000..ec3e9abc --- /dev/null +++ b/test/repositories/1/org1/mod1.1/ivys/ivy-1.1.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/1/org1/mod1.1/ivys/ivy-2.0.xml b/test/repositories/1/org1/mod1.1/ivys/ivy-2.0.xml new file mode 100644 index 00000000..c05d8afa --- /dev/null +++ b/test/repositories/1/org1/mod1.1/ivys/ivy-2.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar b/test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.1/jars/mod1.1-1.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.1/jars/mod1.1-1.1.jar b/test/repositories/1/org1/mod1.1/jars/mod1.1-1.1.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.1/jars/mod1.1-1.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.1/jars/mod1.1-2.0.jar b/test/repositories/1/org1/mod1.1/jars/mod1.1-2.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.1/jars/mod1.1-2.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.2/jars/mod1.2-2.1.jar b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.1.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.2/jars/mod1.2-2.2.jar b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.2.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.2/jars/mod1.2-2.2.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.3/jars/mod1.3-A-3.0.jar b/test/repositories/1/org1/mod1.3/jars/mod1.3-A-3.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.3/jars/mod1.3-A-3.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.3/jars/mod1.3-B-3.0.jar b/test/repositories/1/org1/mod1.3/jars/mod1.3-B-3.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org1/mod1.3/jars/mod1.3-B-3.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org1/mod1.4/ivys/ivy-1.0.1.xml b/test/repositories/1/org1/mod1.4/ivys/ivy-1.0.1.xml new file mode 100644 index 00000000..e18d1f15 --- /dev/null +++ b/test/repositories/1/org1/mod1.4/ivys/ivy-1.0.1.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml b/test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml new file mode 100644 index 00000000..fb4d8402 --- /dev/null +++ b/test/repositories/1/org2/mod2.1/ivys/ivy-0.3.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/test/repositories/1/org2/mod2.1/ivys/ivy-0.4.xml b/test/repositories/1/org2/mod2.1/ivys/ivy-0.4.xml new file mode 100644 index 00000000..737cc7d5 --- /dev/null +++ b/test/repositories/1/org2/mod2.1/ivys/ivy-0.4.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + diff --git a/test/repositories/1/org2/mod2.1/jars/art21A-0.3.jar b/test/repositories/1/org2/mod2.1/jars/art21A-0.3.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.1/jars/art21A-0.3.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org2/mod2.1/jars/art21A-0.4.jar b/test/repositories/1/org2/mod2.1/jars/art21A-0.4.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.1/jars/art21A-0.4.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org2/mod2.1/jars/art21B-0.3.jar b/test/repositories/1/org2/mod2.1/jars/art21B-0.3.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.1/jars/art21B-0.3.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org2/mod2.1/jars/art21B-0.4.jar b/test/repositories/1/org2/mod2.1/jars/art21B-0.4.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.1/jars/art21B-0.4.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml b/test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml new file mode 100644 index 00000000..3857c162 --- /dev/null +++ b/test/repositories/1/org2/mod2.2/ivys/ivy-0.5.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/test/repositories/1/org2/mod2.2/jars/mod2.2-0.5.jar b/test/repositories/1/org2/mod2.2/jars/mod2.2-0.5.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.2/jars/mod2.2-0.5.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml b/test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml new file mode 100644 index 00000000..7e7cf149 --- /dev/null +++ b/test/repositories/1/org2/mod2.3/ivys/ivy-0.4.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + diff --git a/test/repositories/1/org2/mod2.3/ivys/ivy-0.5.xml b/test/repositories/1/org2/mod2.3/ivys/ivy-0.5.xml new file mode 100644 index 00000000..037b3bec --- /dev/null +++ b/test/repositories/1/org2/mod2.3/ivys/ivy-0.5.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/test/repositories/1/org2/mod2.3/ivys/ivy-0.6.xml b/test/repositories/1/org2/mod2.3/ivys/ivy-0.6.xml new file mode 100644 index 00000000..367aeb89 --- /dev/null +++ b/test/repositories/1/org2/mod2.3/ivys/ivy-0.6.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/test/repositories/1/org2/mod2.3/jars/mod2.3-0.4.jar b/test/repositories/1/org2/mod2.3/jars/mod2.3-0.4.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/1/org2/mod2.3/jars/mod2.3-0.4.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml b/test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml new file mode 100644 index 00000000..9b013e4e --- /dev/null +++ b/test/repositories/1/org6/mod6.1/ivys/ivy-0.3.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/test/repositories/2/mod3.1/ivy-1.0.xml b/test/repositories/2/mod3.1/ivy-1.0.xml new file mode 100644 index 00000000..8404733b --- /dev/null +++ b/test/repositories/2/mod3.1/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/2/mod3.1/ivy-1.1.xml b/test/repositories/2/mod3.1/ivy-1.1.xml new file mode 100644 index 00000000..027d27f8 --- /dev/null +++ b/test/repositories/2/mod3.1/ivy-1.1.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/test/repositories/2/mod3.1/mod3.1-1.0.jar b/test/repositories/2/mod3.1/mod3.1-1.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod3.1/mod3.1-1.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod3.1/mod3.1-1.1.jar b/test/repositories/2/mod3.1/mod3.1-1.1.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod3.1/mod3.1-1.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod4.1/ivy-4.0.xml b/test/repositories/2/mod4.1/ivy-4.0.xml new file mode 100644 index 00000000..1a222b63 --- /dev/null +++ b/test/repositories/2/mod4.1/ivy-4.0.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/2/mod4.1/ivy-4.1.xml b/test/repositories/2/mod4.1/ivy-4.1.xml new file mode 100644 index 00000000..0e6b9133 --- /dev/null +++ b/test/repositories/2/mod4.1/ivy-4.1.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/2/mod4.1/ivy-4.2.xml b/test/repositories/2/mod4.1/ivy-4.2.xml new file mode 100644 index 00000000..b414a80f --- /dev/null +++ b/test/repositories/2/mod4.1/ivy-4.2.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/2/mod4.1/mod4.1-4.0.jar b/test/repositories/2/mod4.1/mod4.1-4.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod4.1/mod4.1-4.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod4.1/mod4.1-4.1.jar b/test/repositories/2/mod4.1/mod4.1-4.1.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod4.1/mod4.1-4.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51A-4.0.jar b/test/repositories/2/mod5.1/art51A-4.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.1/art51A-4.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51A-4.1.jar b/test/repositories/2/mod5.1/art51A-4.1.jar new file mode 100644 index 00000000..92c1a7a4 --- /dev/null +++ b/test/repositories/2/mod5.1/art51A-4.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51A-4.2.jar b/test/repositories/2/mod5.1/art51A-4.2.jar new file mode 100644 index 00000000..92c1a7a4 --- /dev/null +++ b/test/repositories/2/mod5.1/art51A-4.2.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51B-4.0.jar b/test/repositories/2/mod5.1/art51B-4.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.1/art51B-4.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51B-4.1.jar b/test/repositories/2/mod5.1/art51B-4.1.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.1/art51B-4.1.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/art51B-4.2.jar b/test/repositories/2/mod5.1/art51B-4.2.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.1/art51B-4.2.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.1/ivy-4.0.xml b/test/repositories/2/mod5.1/ivy-4.0.xml new file mode 100644 index 00000000..ea0ade91 --- /dev/null +++ b/test/repositories/2/mod5.1/ivy-4.0.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/test/repositories/2/mod5.1/ivy-4.1.xml b/test/repositories/2/mod5.1/ivy-4.1.xml new file mode 100644 index 00000000..f9f5ea3d --- /dev/null +++ b/test/repositories/2/mod5.1/ivy-4.1.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/test/repositories/2/mod5.1/ivy-4.2.xml b/test/repositories/2/mod5.1/ivy-4.2.xml new file mode 100644 index 00000000..b901d01f --- /dev/null +++ b/test/repositories/2/mod5.1/ivy-4.2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + diff --git a/test/repositories/2/mod5.2/ivy-1.0.xml b/test/repositories/2/mod5.2/ivy-1.0.xml new file mode 100644 index 00000000..3c3a8c96 --- /dev/null +++ b/test/repositories/2/mod5.2/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/2/mod5.2/ivy-2.0.xml b/test/repositories/2/mod5.2/ivy-2.0.xml new file mode 100644 index 00000000..0fe05864 --- /dev/null +++ b/test/repositories/2/mod5.2/ivy-2.0.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/test/repositories/2/mod5.2/mod5.2-1.0.jar b/test/repositories/2/mod5.2/mod5.2-1.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.2/mod5.2-1.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod5.2/mod5.2-2.0.jar b/test/repositories/2/mod5.2/mod5.2-2.0.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/2/mod5.2/mod5.2-2.0.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/2/mod6.1/ivy-1.0.xml b/test/repositories/2/mod6.1/ivy-1.0.xml new file mode 100644 index 00000000..b07d94c8 --- /dev/null +++ b/test/repositories/2/mod6.1/ivy-1.0.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/2/mod6.1/ivy-1.1.xml b/test/repositories/2/mod6.1/ivy-1.1.xml new file mode 100644 index 00000000..1458ba62 --- /dev/null +++ b/test/repositories/2/mod6.1/ivy-1.1.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/test/repositories/2/mod6.1/ivy-1.2.xml b/test/repositories/2/mod6.1/ivy-1.2.xml new file mode 100644 index 00000000..f53ebeb1 --- /dev/null +++ b/test/repositories/2/mod6.1/ivy-1.2.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/test/repositories/2/mod6.1/ivy-1.3.xml b/test/repositories/2/mod6.1/ivy-1.3.xml new file mode 100644 index 00000000..fd8ba805 --- /dev/null +++ b/test/repositories/2/mod6.1/ivy-1.3.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/test/repositories/2/mod6.2/ivy-1.0.xml b/test/repositories/2/mod6.2/ivy-1.0.xml new file mode 100644 index 00000000..5242a5de --- /dev/null +++ b/test/repositories/2/mod6.2/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/2/mod6.3/ivy-1.0.xml b/test/repositories/2/mod6.3/ivy-1.0.xml new file mode 100644 index 00000000..35f22c2e --- /dev/null +++ b/test/repositories/2/mod6.3/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/bug148/3rd/idautomation/barcode/LinearBarCode-4.10.jar b/test/repositories/bug148/3rd/idautomation/barcode/LinearBarCode-4.10.jar new file mode 100644 index 00000000..e69de29b diff --git a/test/repositories/bug148/3rd/idautomation/barcode/idapdf417-4.10.jar b/test/repositories/bug148/3rd/idautomation/barcode/idapdf417-4.10.jar new file mode 100644 index 00000000..e69de29b diff --git a/test/repositories/bug148/3rd/idautomation/barcode/ivy-barcode-4.10.xml b/test/repositories/bug148/3rd/idautomation/barcode/ivy-barcode-4.10.xml new file mode 100644 index 00000000..f76af1d4 --- /dev/null +++ b/test/repositories/bug148/3rd/idautomation/barcode/ivy-barcode-4.10.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/test/repositories/bug148/ivyconf.properties b/test/repositories/bug148/ivyconf.properties new file mode 100644 index 00000000..a965d004 --- /dev/null +++ b/test/repositories/bug148/ivyconf.properties @@ -0,0 +1,2 @@ +lib.jtv=${ivy.conf.dir}/jtv +lib.3rd=${ivy.conf.dir}/3rd diff --git a/test/repositories/bug148/ivyconf.xml b/test/repositories/bug148/ivyconf.xml new file mode 100644 index 00000000..964cb65e --- /dev/null +++ b/test/repositories/bug148/ivyconf.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + diff --git a/test/repositories/bug148/jtv/jtv-foo/bar/bar-1.1.0.0.jar b/test/repositories/bug148/jtv/jtv-foo/bar/bar-1.1.0.0.jar new file mode 100644 index 00000000..e69de29b diff --git a/test/repositories/bug148/jtv/jtv-foo/bar/bar-src-1.1.0.0.jar b/test/repositories/bug148/jtv/jtv-foo/bar/bar-src-1.1.0.0.jar new file mode 100644 index 00000000..e69de29b diff --git a/test/repositories/bug148/jtv/jtv-foo/bar/ivy-bar-1.1.0.0.xml b/test/repositories/bug148/jtv/jtv-foo/bar/ivy-bar-1.1.0.0.xml new file mode 100644 index 00000000..c79269d6 --- /dev/null +++ b/test/repositories/bug148/jtv/jtv-foo/bar/ivy-bar-1.1.0.0.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/test/repositories/checkmodified/ivy-1.0-after.xml b/test/repositories/checkmodified/ivy-1.0-after.xml new file mode 100644 index 00000000..820ce4a2 --- /dev/null +++ b/test/repositories/checkmodified/ivy-1.0-after.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/checkmodified/ivy-1.0-before.xml b/test/repositories/checkmodified/ivy-1.0-before.xml new file mode 100644 index 00000000..c3d6a682 --- /dev/null +++ b/test/repositories/checkmodified/ivy-1.0-before.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/checkmodified/ivy-1.0.xml b/test/repositories/checkmodified/ivy-1.0.xml new file mode 100644 index 00000000..820ce4a2 --- /dev/null +++ b/test/repositories/checkmodified/ivy-1.0.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/test/repositories/dual-local/xerces/xerces/ivy-2.6.2.xml b/test/repositories/dual-local/xerces/xerces/ivy-2.6.2.xml new file mode 100644 index 00000000..dd978a8b --- /dev/null +++ b/test/repositories/dual-local/xerces/xerces/ivy-2.6.2.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/repositories/dual-remote/xerces/xercesImpl-2.6.2.jar b/test/repositories/dual-remote/xerces/xercesImpl-2.6.2.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/dual-remote/xerces/xercesImpl-2.6.2.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/dual-remote/xerces/xmlParserAPIs-2.6.2.jar b/test/repositories/dual-remote/xerces/xmlParserAPIs-2.6.2.jar new file mode 100644 index 00000000..56f3b36e --- /dev/null +++ b/test/repositories/dual-remote/xerces/xmlParserAPIs-2.6.2.jar @@ -0,0 +1 @@ + diff --git a/test/repositories/ivyconf.properties b/test/repositories/ivyconf.properties new file mode 100644 index 00000000..1ddf813f --- /dev/null +++ b/test/repositories/ivyconf.properties @@ -0,0 +1,2 @@ +ivy.publish.src.artifacts.pattern=${build}/[artifact]-[revision].[ext] +cache.dir=build/cache \ No newline at end of file diff --git a/test/repositories/ivyconf.xml b/test/repositories/ivyconf.xml new file mode 100644 index 00000000..96fa1fcf --- /dev/null +++ b/test/repositories/ivyconf.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test/xsl/test.xml b/test/xsl/test.xml new file mode 100644 index 00000000..56455e39 --- /dev/null +++ b/test/xsl/test.xml @@ -0,0 +1,70 @@ + + + + + + + + This module is great !
    + You can use it especially with myconf1 and myconf2, and myconf4 is not too bad too.
    + And you can even use xhtml in this description. +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +