-
Notifications
You must be signed in to change notification settings - Fork 436
/
JDebPackaging.scala
193 lines (166 loc) · 7.02 KB
/
JDebPackaging.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package com.typesafe.sbt
package packager
package debian
import com.typesafe.sbt.packager.archetypes.TemplateWriter
import com.typesafe.sbt.packager.universal.Archives
import sbt._
import sbt.Keys.{ target, normalizedName, version, streams, mappings, packageBin }
import linux.{ LinuxSymlink, LinuxPackageMapping, LinuxFileMetaData }
import linux.LinuxPlugin.autoImport.{ linuxPackageMappings, linuxPackageSymlinks, packageArchitecture, linuxScriptReplacements }
import scala.collection.JavaConversions._
import org.vafer.jdeb.{ DebMaker, DataProducer }
import org.vafer.jdeb.mapping._
import org.vafer.jdeb.producers._
import DebianPlugin.{ Names }
import DebianPlugin.autoImport._
/**
* == JDeb Plugin ==
* This provides a java based debian packaging implementation based
* on the jdeb maven-plugin. To use this, put this into your build.sbt
*
* @example Enable the plugin in the `build.sbt`
* {{{
* enablePlugins(JDebPackaging)
* }}}
*
* @author Nepomuk Seiler
* @see [[https://github.com/tcurdt/jdeb/blob/master/src/main/java/org/vafer/jdeb/maven/DebMojo.java#L503]]
*
*/
object JDebPackaging extends AutoPlugin with DebianPluginLike {
override def requires = DebianPlugin
override lazy val projectSettings = inConfig(Debian)(jdebSettings)
def jdebSettings = Seq(
// FIXME do nothing. Java7 posix needed
debianConffilesFile := {
target.value / Names.Debian / Names.Conffiles
},
// FIXME copied from the debian plugin. Java7 posix needed
debianControlFile <<= (debianPackageMetadata, debianPackageInstallSize, target) map {
(data, size, dir) =>
if (data.info.description == null || data.info.description.isEmpty) {
sys.error(
"""packageDescription in Debian cannot be empty. Use
packageDescription in Debian := "My package Description""""
)
}
val cfile = dir / Names.Debian / Names.Control
IO.write(cfile, data.makeContent(size), java.nio.charset.Charset.defaultCharset)
cfile
},
/**
* Depends on the 'debianExplodedPackage' task as this creates all the files
* which are defined in the mappings.
*/
packageBin := {
val targetDir = target.value
val log = streams.value.log
val mappings = linuxPackageMappings.value
val symlinks = linuxPackageSymlinks.value
// unused, but needed as dependency
val controlDir = targetDir / Names.Debian
val control = debianControlFile.value
val conffile = debianConffilesFile.value
val replacements = debianMakeChownReplacements.value +: linuxScriptReplacements.value
val controlScripts = debianMaintainerScripts.value
for ((file, name) <- controlScripts) {
val targetFile = controlDir / name
copyFiles(file, targetFile, LinuxFileMetaData())
filterFiles(targetFile, replacements, LinuxFileMetaData())
}
log.info("Building debian package with java based implementation 'jdeb'")
val console = new JDebConsole(log)
val archive = archiveFilename(normalizedName.value, version.value, packageArchitecture.value)
val debianFile = targetDir.getParentFile / archive
val debMaker = new DebMaker(
console,
fileAndDirectoryProducers(mappings, targetDir) ++ linkProducers(symlinks),
conffileProducers(mappings, targetDir)
)
debMaker setDepends ""
debMaker setDeb debianFile
debMaker setControl (targetDir / Names.Debian)
// TODO set compression, gzip is default
// TODO add signing with setKeyring, setKey, setPassphrase, setSignPackage, setSignMethod, setSignRole
debMaker validate ()
debMaker makeDeb ()
debianFile
}
)
/**
* The same as [[DebianPluginLike.copyAndFixPerms]] except chmod invocation (for windows compatibility).
* Permissions will be handled by jDeb packager itself.
*/
private[this] def copyFiles(from: File, to: File, perms: LinuxFileMetaData, zipped: Boolean = false): Unit = {
if (zipped) {
IO.withTemporaryDirectory { dir =>
val tmp = dir / from.getName
IO.copyFile(from, tmp)
val zipped = Archives.gzip(tmp)
IO.copyFile(zipped, to, true)
}
} else IO.copyFile(from, to, true)
}
/**
* The same as [[DebianPluginLike.filterAndFixPerms]] except chmod invocation (for windows compatibility).
* Permissions will be handled by jDeb packager itself.
*/
private[this] final def filterFiles(script: File, replacements: Seq[(String, String)], perms: LinuxFileMetaData): File = {
val filtered = TemplateWriter.generateScript(script.toURI.toURL, replacements)
IO.delete(script)
IO.write(script, filtered)
script
}
/**
* Creating file and directory producers. These "produce" the
* files for the debian packaging.
*
* May create duplicates together with the conffileProducers.
* This will be an performance improvement (reducing IO)
*/
private[debian] def fileAndDirectoryProducers(mappings: Seq[LinuxPackageMapping], target: File): Seq[DataProducer] = mappings.map {
case LinuxPackageMapping(paths, perms, zipped) => paths map {
// Directories need to be created so jdeb can pick them up
case (path, name) if path.isDirectory =>
val permMapper = new PermMapper(-1, -1, perms.user, perms.group, null, perms.permissions, -1, null)
(target / cleanPath(name)) mkdirs ()
new DataProducerDirectory(target, Array(cleanPath(name)), null, Array(permMapper))
// Files are just referenced
case (path, name) => new DataProducerFile(path, cleanPath(name), null, null, Array(filePermissions(perms)))
}
}.flatten
/**
* Creating link producers for symlinks.
*/
private[debian] def linkProducers(symlinks: Seq[LinuxSymlink]): Seq[DataProducer] = symlinks map {
case LinuxSymlink(link, destination) => new DataProducerLink(link, destination, true, null, null, null)
}
/**
* Creating the files which should be added as conffiles.
*/
private[debian] def conffileProducers(linuxMappings: Seq[LinuxPackageMapping], target: File): Seq[DataProducer] = {
val producers = linuxMappings map {
case mapping @ LinuxPackageMapping(mappings, perms, _) if perms.config == "true" =>
mappings collect {
case (path, name) if path.isFile =>
val permMapper = filePermissions(perms.withPerms("0644"))
new DataProducerFile(path, cleanPath(name), null, null, Array(permMapper))
}
case _ => Seq.empty
}
producers.flatten
}
private[debian] def cleanPath(path: String): String =
if (path startsWith "/") path drop 1 else path
private[this] def filePermissions(perms: LinuxFileMetaData): PermMapper =
new PermMapper(-1, -1, perms.user, perms.group, perms.permissions, null, -1, null)
}
/**
* This provides the task for building a debian packaging with
* the java-based implementation jdeb
*/
class JDebConsole(log: Logger) extends org.vafer.jdeb.Console {
def debug(message: String) = log debug message
def info(message: String) = log info message
def warn(message: String) = log warn message
}