77 *******************************************************************************/
88package io.typefox.publishing
99
10+ import com.google.common.collect.AbstractIterator
1011import com.google.common.io.Files
1112import java.io.File
13+ import java.io.FileOutputStream
1214import java.io.FilenameFilter
15+ import java.io.IOException
1316import java.nio.charset.Charset
1417import java.util.concurrent.Callable
18+ import java.util.jar.JarFile
19+ import java.util.jar.JarOutputStream
20+ import java.util.zip.ZipEntry
21+ import javax.xml.parsers.DocumentBuilderFactory
22+ import javax.xml.transform.TransformerFactory
23+ import javax.xml.transform.dom.DOMSource
24+ import javax.xml.transform.stream.StreamResult
1525import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
26+ import org.gradle.api.GradleException
1627import org.gradle.api.InvalidUserDataException
1728import org.gradle.api.Project
1829import org.gradle.api.tasks.Copy
1930import org.gradle.api.tasks.Delete
2031import org.gradle.api.tasks.bundling.Zip
32+ import org.w3c.dom.Element
2133import pw.prok.download.Download
2234
2335@FinalFieldsConstructor
@@ -99,6 +111,13 @@ class EclipsePublishing {
99111 ] as Callable<File []> )
100112 outputDir = file(' ' ' «rootDir»/build-result/p2.repository/features' ' ' )
101113 ]
114+
115+ task(' ' ' update«repoName»ArtifactsChecksum' ' ' ) = > [
116+ doLast [
117+ updateArtifactsXml(' ' ' «buildDir»/p2-«repoName.toLowerCase»/repository-unsigned' ' ' ,
118+ ' ' ' «rootDir»/build-result/p2.repository' ' ' )
119+ ]
120+ ]
102121 }
103122
104123 val copyP2MetadataTask = task(#{' type' - > Copy }, ' ' ' copy«repoName»P2Metadata' ' ' ) = > [ task |
@@ -109,6 +128,7 @@ class EclipsePublishing {
109128 from = ' ' ' «buildDir»/p2-«repoName.toLowerCase»/repository-unsigned' ' '
110129 into = ' ' ' «rootDir»/build-result/p2.repository' ' '
111130 if (osspub. signJars) {
131+ exclude(' **/artifacts.jar' )
112132 for (namespace : repository. namespaces) {
113133 exclude(' ' ' **/«namespace»*.jar' ' ' )
114134 }
@@ -121,7 +141,7 @@ class EclipsePublishing {
121141 description = ' ' ' Create a zip file from the «repoName» P2 repository' ' '
122142 dependsOn(copyP2MetadataTask)
123143 if (osspub. signJars)
124- dependsOn(' ' ' sign«repoName»P2Plugins' ' ' , ' ' ' sign«repoName»P2Features' ' ' )
144+ dependsOn(' ' ' sign«repoName»P2Plugins' ' ' , ' ' ' sign«repoName»P2Features' ' ' , ' ' ' update«repoName»ArtifactsChecksum ' ' ' )
125145 from = ' ' ' «rootDir»/build-result/p2.repository' ' '
126146 destinationDir = file(' ' ' «rootDir»/build-result/downloads' ' ' )
127147 doFirst[ task2 |
@@ -189,15 +209,22 @@ class EclipsePublishing {
189209
190210 private def getBuildTimestamp (P2Repository repository ) {
191211 if (! repository. referenceFeature. nullOrEmpty) {
192- val referencePrefix = ' ' ' «repository.referenceFeature»_«mainVersion».«repository.timestampPrefix» ' ' '
212+ val referencePrefix = ' ' ' «repository.referenceFeature»_«mainVersion».' ' '
193213 val bundleDir = new File (buildDir, ' ' ' p2-«repository.name.toLowerCase»/repository-unsigned/features' ' ' )
194214 val FilenameFilter filter = [ dir, name |
195215 name. startsWith(referencePrefix) && name. endsWith(' .jar' )
196216 ]
197217 val referenceFeatureFiles = bundleDir. listFiles(filter)
198218 if (referenceFeatureFiles. length > 0 ) {
199219 val fileName = referenceFeatureFiles. get(0 ). name
200- return fileName. substring(referencePrefix. length, fileName. length - ' .jar' . length). replace(' -' , ' ' )
220+ val qualifier = fileName. substring(referencePrefix. length, fileName. length - ' .jar' . length)
221+ val timestamp = new StringBuilder
222+ for (var i = 0 ; i < qualifier. length; i++ ) {
223+ val c = qualifier. charAt(i)
224+ if (Character . isDigit(c))
225+ timestamp. append(c)
226+ }
227+ return timestamp. toString
201228 }
202229 }
203230 }
@@ -210,4 +237,72 @@ class EclipsePublishing {
210237 }
211238 }
212239
240+ private def updateArtifactsXml (String sourceDir , String destDir ) {
241+ var JarFile sourceJar
242+ var JarOutputStream targetJar
243+ try {
244+ sourceJar = new JarFile (' ' ' «sourceDir»/artifacts.jar' ' ' )
245+ val artifactsEntry = sourceJar. getEntry(' artifacts.xml' )
246+ if (artifactsEntry == = null )
247+ throw new GradleException (' artifacts.jar does not contain artifacts.xml' )
248+ val builder = DocumentBuilderFactory . newInstance. newDocumentBuilder
249+ val document = builder. parse(sourceJar. getInputStream(artifactsEntry))
250+ val xmlRoot = document. documentElement
251+ if (xmlRoot. tagName == ' repository' ) {
252+ for (artifacts : xmlRoot. getElements(' artifacts' )) {
253+ for (artifact : artifacts. getElements(' artifact' )) {
254+ for (properties : artifact. getElements(' properties' )) {
255+ for (property : properties. getElements(' property' )) {
256+ if (property. getAttribute(' name' ) == ' download.md5' ) {
257+ val id = artifact. getAttribute(' id' )
258+ val version = artifact. getAttribute(' version' )
259+ val classifier = artifact. getAttribute(' classifier' )
260+ if (! id. empty && ! version. empty && ! classifier. empty) {
261+ val md5 = computeMd5Checksum(sourceDir, id, version, classifier)
262+ property. setAttribute(' value' , md5)
263+ }
264+ }
265+ }
266+ }
267+ }
268+ }
269+ }
270+
271+ targetJar = new JarOutputStream (new FileOutputStream (' ' ' «destDir»/artifacts.jar' ' ' ))
272+ targetJar. putNextEntry(new ZipEntry (' artifacts.xml' ))
273+ val transformer = TransformerFactory . newInstance. newTransformer
274+ transformer. transform(new DOMSource (document), new StreamResult (targetJar))
275+ targetJar. closeEntry()
276+ } finally {
277+ try {
278+ sourceJar? . close()
279+ targetJar? . close()
280+ } catch (IOException e) {}
281+ }
282+ }
283+
284+ private def Iterable<Element > getElements (Element e , String name ) {
285+ val nodeList = e. getElementsByTagName(name)
286+ return [
287+ new AbstractIterator<Element > {
288+ int i = 0
289+ override protected computeNext() {
290+ if (i < nodeList. length)
291+ return nodeList. item(i++ ) as Element
292+ else
293+ return endOfData
294+ }
295+ }
296+ ]
297+ }
298+
299+ private def computeMd5Checksum (String sourceDir , String id , String version , String classifier ) {
300+ val sourcePath = switch classifier {
301+ case ' osgi.bundle' : ' ' ' «sourceDir»/plugins/«id»_«version».jar' ' '
302+ case ' org.eclipse.update.feature' : ' ' ' «sourceDir»/features/«id»_«version».jar' ' '
303+ }
304+ val bytes = FileChecksums . getMd5Checksum(new File (sourcePath))
305+ return FileChecksums . toString(bytes)
306+ }
307+
213308}
0 commit comments