Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First refactoring to provide multiple debian packaging strategies #284

Merged
merged 2 commits into from
Jul 7, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ organization := "com.typesafe.sbt"

scalacOptions in Compile += "-deprecation"

libraryDependencies += "org.apache.commons" % "commons-compress" % "1.4.1"
libraryDependencies ++= Seq(
"org.apache.commons" % "commons-compress" % "1.4.1",
"org.vafer" % "jdeb" % "1.2" artifacts (Artifact("jdeb", "jar", "jar"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nice, I had been watching this guy.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using the jdeb library at our company without any problems. The
artifacts (Artifact("jdeb","jar","jar")) part was the hardest to get :P

)

site.settings

Expand Down
416 changes: 190 additions & 226 deletions src/main/scala/com/typesafe/sbt/packager/debian/DebianPlugin.scala

Large diffs are not rendered by default.

104 changes: 104 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/debian/JDebPackaging.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.typesafe.sbt
package packager
package debian

import Keys._
import sbt._
import sbt.Keys.{ target, name, normalizedName, TaskStreams }
import linux.{ LinuxFileMetaData, LinuxPackageMapping, LinuxSymlink }
import linux.Keys.{ linuxScriptReplacements, daemonShell }
import com.typesafe.sbt.packager.linux.LinuxPackageMapping
import scala.collection.JavaConversions._

import org.vafer.jdeb.{ DebMaker, DataProducer }
import org.vafer.jdeb.mapping._
import org.vafer.jdeb.producers._
import DebianPlugin.Names

/**
* This provides a java based debian packaging implementation based
* on the jdeb maven-plugin. To use this, put this into your build.sbt
*
* {{
* packageBin in Debian <<= debianJDebPackaging in Debian
* }}
*
* @author Nepomuk Seiler
* @see https://github.com/tcurdt/jdeb/blob/master/src/main/java/org/vafer/jdeb/maven/DebMojo.java#L503
*
*/
trait JDebPackaging { this: DebianPlugin with linux.LinuxPlugin =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we may be going over the top with cake :) I'm almost regretting having used it in the first place. Did this feel like it made things simpler, or just more complicated to find things?


private[debian] def debianJDebSettings: Seq[Setting[_]] = Seq(

/**
* Depends on the 'debianExplodedPackage' task as this creates all the files
* which are defined in the mappings.
*/
debianJDebPackaging <<= (debianExplodedPackage, linuxPackageMappings, linuxPackageSymlinks,
debianControlFile, debianMaintainerScripts, debianConffilesFile,
normalizedName, version, target, streams) map {
(_, mappings, symlinks, controlfile, controlscripts, conffile,
name, version, target, s) =>
s.log.info("Building debian package with java based implementation 'jdeb'")
val console = new JDebConsole(s.log)

val debianFile = target.getParentFile / "%s_%s_all.deb".format(name, version)
val debMaker = new DebMaker(console,
fileAndDirectoryProducers(mappings, target) ++ linkProducers(symlinks),
conffileProducers()
)
debMaker setDeb debianFile
debMaker setControl (target / Names.Debian)

// TODO set compression, gzip is default
// TODO add signing with setKeyring, setKey, setPassphrase, setSignPackage, setSignMethod, setSignRole
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, depending on the pgpPlugin may not be "safe to do", we should have a big auto-plugins discussion across the plugin authors to see what kinds of conventions/dependencies we'd liek to expose and how we do so.

debMaker validate ()
debMaker makeDeb ()
debianFile
})

/**
* Creating file and directory producers. These "produce" the
* files for the debian packaging
*/
private[debian] def fileAndDirectoryProducers(mappings: Seq[LinuxPackageMapping], target: File): Seq[DataProducer] = mappings.map {
case LinuxPackageMapping(paths, perms, zipped) =>
// TODO implement mappers here or use the maintainerscripts logic?
val (dirs, files) = paths.partition(_._1.isDirectory)
paths map {
case (path, name) if path.isDirectory =>
new DataProducerDirectory(target / name, null, Array("**"), null)
case (path, name) =>
new DataProducerFile(target / name, name, null, null, null)
}
}.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.
* This is currently handled by the debian plugin itself.
*/
private[debian] def conffileProducers(): Seq[DataProducer] = Seq.empty

}

/**
* 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
}
3 changes: 3 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ trait DebianKeys {
val debianPackageMetadata = SettingKey[PackageMetaData]("debian-package-metadata", "Meta data used when constructing a debian package.")
val debianChangelog = SettingKey[Option[File]]("debian-changelog", "The changelog for this deb file")
// Package building
val debianNativePackaging = TaskKey[File]("debian-packaging-native", "Builds the debian package with native cli tools")
val debianJDebPackaging = TaskKey[File]("debian-packaging-jdeb", "Builds the debian package with jdeb (java-based)")

val debianControlFile = TaskKey[File]("debian-control-file", "Makes the debian package control file.")
val debianMaintainerScripts = TaskKey[Seq[(File, String)]]("debian-maintainer-scripts", "Makes the debian maintainer scripts.")
val debianConffilesFile = TaskKey[File]("debian-conffiles-file", "Makes the debian package conffiles file.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.typesafe.sbt
package packager
package debian

import Keys._
import sbt._
import sbt.Keys.{ target, name, normalizedName, TaskStreams }
import linux.{ LinuxFileMetaData, LinuxPackageMapping, LinuxSymlink }
import linux.Keys.{ linuxScriptReplacements, daemonShell }
import com.typesafe.sbt.packager.Hashing
import com.typesafe.sbt.packager.archetypes.TemplateWriter

/**
* This provides a dpgk based implementation for debian packaging.
* Your machine must have dpkg installed to use this.
*
* {{
* packageBin in Debian <<= debianNativePackaging in Debian
* }}
*
*
*
*/
trait NativePackaging { this: DebianPlugin with linux.LinuxPlugin =>

import com.typesafe.sbt.packager.universal.Archives
import DebianPlugin.Names
import linux.LinuxPlugin.Users

private[debian] def debianNativeSettings: Seq[Setting[_]] = Seq(
genChanges <<= (packageBin, target, debianChangelog, name, version, debianPackageMetadata) map {
(pkg, tdir, changelog, name, version, data) =>
changelog match {
case None => sys.error("Cannot generate .changes file without a changelog")
case Some(chlog) => {
// dpkg-genchanges needs a debian "source" directory, different from the DEBIAN "binary" directory
val debSrc = tdir / "../tmp" / Names.DebianSource
debSrc.mkdirs()
copyAndFixPerms(chlog, debSrc / Names.Changelog, LinuxFileMetaData("0644"))
IO.writeLines(debSrc / Names.Files, List(pkg.getName + " " + data.section + " " + data.priority))
// dpkg-genchanges needs a "source" control file, located in a "debian" directory
IO.writeLines(debSrc / Names.Control, List(data.makeSourceControl()))
val changesFileName = name + "_" + version + "_" + data.architecture + ".changes"
val changesFile: File = tdir / ".." / changesFileName
try {
val changes = Process(Seq("dpkg-genchanges", "-b"), Some(tdir / "../tmp")) !!
val allChanges = List(changes)
IO.writeLines(changesFile, allChanges)
} catch {
case e: Exception => sys.error("Failure generating changes file." + e.getStackTraceString)
}
changesFile
}
}

},
debianSign <<= (packageBin, debianSignRole, streams) map { (deb, role, s) =>
Process(Seq("dpkg-sig", "-s", role, deb.getAbsolutePath), Some(deb.getParentFile())) ! s.log match {
case 0 => ()
case x => sys.error("Failed to sign debian package! exit code: " + x)
}
deb
},
lintian <<= packageBin map { file =>
Process(Seq("lintian", "-c", "-v", file.getName), Some(file.getParentFile)).!
},

/** Implementation of the actual packaging */
debianNativePackaging <<= (debianExplodedPackage, debianMD5sumsFile, debianSection, debianPriority, name, version, packageArchitecture, target, streams) map {
(pkgdir, _, section, priority, name, version, arch, tdir, s) =>
s.log.info("Building debian package with native implementation")
// Make the package. We put this in fakeroot, so we can build the package with root owning files.
val archive = name + "_" + version + "_" + arch + ".deb"
Process(Seq("fakeroot", "--", "dpkg-deb", "--build", pkgdir.getAbsolutePath, "../" + archive), Some(tdir)) ! s.log match {
case 0 => ()
case x => sys.error("Failure packaging debian file. Exit code: " + x)
}
tdir / ".." / archive
}
)

}

/**
* This provides the task for building a debian packaging with
* native tools
*
*/
object Native {

/* static assets definitions */

private[debian] def postinstGroupaddTemplateSource: java.net.URL = getClass.getResource("postinst-groupadd")
private[debian] def postinstUseraddTemplateSource: java.net.URL = getClass.getResource("postinst-useradd")
private[debian] def postinstChownTemplateSource: java.net.URL = getClass.getResource("postinst-chown")
private[debian] def postrmPurgeTemplateSource: java.net.URL = getClass.getResource("postrm-purge")
private[debian] def headerSource: java.net.URL = getClass.getResource("header")
}
22 changes: 22 additions & 0 deletions src/sbt-test/debian/simple-jdeb/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import NativePackagerKeys._

packagerSettings

mapGenericFilesToLinux

name := "debian-test"

version := "0.1.0"

maintainer := "Josh Suereth <[email protected]>"

packageSummary := "Test debian package"

packageDescription := """A fun package description of our software,
with multiple lines."""

debianPackageDependencies in Debian ++= Seq("java2-runtime", "bash (>= 2.05a-11)")

debianPackageRecommends in Debian += "git"

packageBin in Debian <<= debianJDebPackaging in Debian
1 change: 1 addition & 0 deletions src/sbt-test/debian/simple-jdeb/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version"))
3 changes: 3 additions & 0 deletions src/sbt-test/debian/simple-jdeb/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Run the debian packaging.
> debian:package-bin
$ exists target/debian-test_0.1.0_all.deb