-
Notifications
You must be signed in to change notification settings - Fork 26
/
MakePom.scala
179 lines (162 loc) · 7.47 KB
/
MakePom.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/* sbt -- Simple Build Tool
* Copyright 2008, 2009, 2010 Mark Harrah
*/
// based on Ivy's PomModuleDescriptorWriter, which is Apache Licensed, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package sbt;
import java.io.{BufferedWriter, File, OutputStreamWriter, FileOutputStream}
import scala.xml.{Node => XNode, NodeSeq, PrettyPrinter, XML}
import org.apache.ivy.{core, plugins, Ivy}
import core.settings.IvySettings
import core.module.{descriptor, id}
import descriptor.{DependencyDescriptor, License, ModuleDescriptor}
import id.ModuleRevisionId
import plugins.resolver.{ChainResolver, DependencyResolver, IBiblioResolver}
class MakePom
{
def encoding = "UTF-8"
def write(ivy: Ivy, module: ModuleDescriptor, configurations: Option[Iterable[Configuration]], extra: NodeSeq, process: XNode => XNode, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean, output: File): Unit =
write(process(toPom(ivy, module, configurations, extra, filterRepositories, allRepositories)), output)
// use \n as newline because toString uses PrettyPrinter, which hard codes line endings to be \n
def write(node: XNode, output: File): Unit = write(toString(node), output, "\n")
def write(xmlString: String, output: File, newline: String)
{
output.getParentFile.mkdirs()
val out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(output), encoding))
try
{
out.write("<?xml version='1.0' encoding='" + encoding + "'?>" + newline)
out.write(xmlString)
}
finally { out.close() }
}
def toString(node: XNode): String = new PrettyPrinter(1000, 4).format(node)
def toPom(ivy: Ivy, module: ModuleDescriptor, configurations: Option[Iterable[Configuration]], extra: NodeSeq, filterRepositories: MavenRepository => Boolean, allRepositories: Boolean): XNode =
(<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
{ makeModuleID(module) }
{ extra }
{ makeDependencies(module, configurations) }
{ makeRepositories(ivy.getSettings, allRepositories, filterRepositories) }
</project>)
def makeModuleID(module: ModuleDescriptor): NodeSeq =
{
val mrid = moduleDescriptor(module)
val a: NodeSeq =
(<groupId>{ mrid.getOrganisation }</groupId>
<artifactId>{ mrid.getName }</artifactId>
<packaging>{ packaging(module) }</packaging>)
val b: NodeSeq =
( (description(module.getDescription) ++
homePage(module.getHomePage) ++
revision(mrid.getRevision) ++
licenses(module.getLicenses)) : NodeSeq )
a ++ b
}
def description(d: String) = if((d eq null) || d.isEmpty) NodeSeq.Empty else <description>{d}</description>
def licenses(ls: Array[License]) = if(ls == null || ls.isEmpty) NodeSeq.Empty else <licenses>{ls.map(license)}</licenses>
def license(l: License) =
<license>
<name>{l.getName}</name>
<url>{l.getUrl}</url>
<distribution>jar</distribution>
</license>
def homePage(homePage: String) = if(homePage eq null) NodeSeq.Empty else <url>{homePage}</url>
def revision(version: String) = if(version ne null) <version>{version}</version> else NodeSeq.Empty
def packaging(module: ModuleDescriptor) =
module.getAllArtifacts match
{
case Array() => "pom"
case Array(x) => x.getType
case xs =>
val types = xs.map(_.getType)
val notpom = types.toList - "pom"
if(notpom.isEmpty) "pom" else if(notpom contains "jar") "jar" else notpom.head
}
def makeDependencies(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): NodeSeq =
{
val dependencies = depsInConfs(module, configurations)
if(dependencies.isEmpty) NodeSeq.Empty
else
<dependencies>
{ dependencies.map(makeDependency) }
</dependencies>
}
def makeDependency(dependency: DependencyDescriptor): NodeSeq =
{
val mrid = dependency.getDependencyRevisionId
<dependency>
<groupId>{mrid.getOrganisation}</groupId>
<artifactId>{mrid.getName}</artifactId>
<version>{mrid.getRevision}</version>
{ scope(dependency)}
{ optional(dependency) }
</dependency>
}
def scope(dependency: DependencyDescriptor): NodeSeq =
scope(getScope(dependency.getModuleConfigurations))
def scope(scope: String): NodeSeq = if(scope ne null) <scope>{scope}</scope> else NodeSeq.Empty
def optional(dependency: DependencyDescriptor) =
if(isOptional(dependency.getModuleConfigurations)) <optional>true</optional> else NodeSeq.Empty
def moduleDescriptor(module: ModuleDescriptor) = module.getModuleRevisionId
def getScope(confs: Array[String]) =
{
Configurations.defaultMavenConfigurations.find(conf => confs.contains(conf.name)) match
{
case Some(conf) => conf.name
case None =>
if(confs.isEmpty || confs(0) == Configurations.Default.name)
null
else
confs(0)
}
}
def isOptional(confs: Array[String]) = confs.isEmpty || (confs.length == 1 && confs(0) == Configurations.Optional.name)
def makeRepositories(settings: IvySettings, includeAll: Boolean, filterRepositories: MavenRepository => Boolean) =
{
class MavenRepo(name: String, snapshots: Boolean, releases: Boolean)
val repositories = if(includeAll) allResolvers(settings) else resolvers(settings.getDefaultResolver)
val mavenRepositories =
repositories.flatMap {
case m: IBiblioResolver if m.isM2compatible && m.getRoot != IBiblioResolver.DEFAULT_M2_ROOT =>
MavenRepository(m.getName, m.getRoot) :: Nil
case _ => Nil
}
val repositoryElements = mavenRepositories.filter(filterRepositories).map(mavenRepository)
if(repositoryElements.isEmpty) repositoryElements else <repositories>{repositoryElements}</repositories>
}
def allResolvers(settings: IvySettings): Seq[DependencyResolver] = flatten(castResolvers(settings.getResolvers)).distinct
def flatten(rs: Seq[DependencyResolver]): Seq[DependencyResolver] = if(rs eq null) Nil else rs.flatMap(resolvers)
def resolvers(r: DependencyResolver): Seq[DependencyResolver] =
r match { case c: ChainResolver => flatten(castResolvers(c.getResolvers)); case _ => r :: Nil }
// cast the contents of a pre-generics collection
private def castResolvers(s: java.util.Collection[_]): Seq[DependencyResolver] =
s.toArray.map(_.asInstanceOf[DependencyResolver])
def toID(name: String) = checkID(name.filter(isValidIDCharacter).mkString, name)
def isValidIDCharacter(c: Char) = c.isLetterOrDigit
private def checkID(id: String, name: String) = if(id.isEmpty) error("Could not convert '" + name + "' to an ID") else id
def mavenRepository(repo: MavenRepository): XNode =
mavenRepository(toID(repo.name), repo.name, repo.root)
def mavenRepository(id: String, name: String, root: String): XNode =
<repository>
<id>{id}</id>
<name>{name}</name>
<url>{root}</url>
</repository>
/** Retain dependencies only with the configurations given, or all public configurations of `module` if `configurations` is None.
* This currently only preserves the information required by makePom*/
private def depsInConfs(module: ModuleDescriptor, configurations: Option[Iterable[Configuration]]): Seq[DependencyDescriptor] =
{
val keepConfigurations = IvySbt.getConfigurations(module, configurations)
val keepSet = Set(keepConfigurations.toSeq : _*)
def translate(dependency: DependencyDescriptor) =
{
val keep = dependency.getModuleConfigurations.filter(keepSet.contains)
if(keep.isEmpty)
None
else // TODO: translate the dependency to contain only configurations to keep
Some(dependency)
}
module.getDependencies flatMap translate
}
}