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

Relocatable rpm symlink fix #685

Merged
merged 2 commits into from
Nov 7, 2015
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
Original file line number Diff line number Diff line change
Expand Up @@ -295,5 +295,4 @@ object JavaServerAppPackaging extends AutoPlugin {
case script => TemplateWriter generateScriptFromString (content + script, replacements)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ object LinuxPlugin extends AutoPlugin {
author = (maintainer in Linux).value,
description = (packageSummary in Linux).value,
execScript = (executableScriptName in Linux).value,
chdir = s"${defaultLinuxInstallLocation.value}/${(packageName in Linux).value}",
chdir = chdir(defaultLinuxInstallLocation.value, (packageName in Linux).value),
logdir = defaultLinuxLogsLocation.value,
appName = (packageName in Linux).value,
version = sbt.Keys.version.value,
Expand Down Expand Up @@ -249,4 +249,7 @@ object LinuxPlugin extends AutoPlugin {
)
}

final def chdir(installLocation: String, packageName: String): String =
s"$installLocation/$packageName"

Copy link
Contributor

Choose a reason for hiding this comment

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

I see little value in the addition of this function. It is another level of indirection and doesn't actually change the dir. :-)

Copy link
Contributor

Choose a reason for hiding this comment

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

Cancel that - I see that you're calling it from elsewhere

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, the chdir is actually not change directory - it's the chdir variable in the RPM scriptlet which is the actual directory where the application is installed.

}
3 changes: 0 additions & 3 deletions src/main/scala/com/typesafe/sbt/packager/rpm/RpmHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ object RpmHelper {
if file.exists && !file.isDirectory()
target = buildroot / dest
} copyWithZip(file, target, mapping.zipped)

// Now we create symlinks
LinuxSymlink.makeSymLinks(spec.symlinks, buildroot)
}

private[this] def writeSpecFile(spec: RpmSpec, workArea: File, log: sbt.Logger): File = {
Expand Down
94 changes: 87 additions & 7 deletions src/main/scala/com/typesafe/sbt/packager/rpm/RpmMetadata.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package com.typesafe.sbt
package packager
package rpm

import linux.{ LinuxPackageMapping, LinuxFileMetaData }
import com.typesafe.sbt.packager.linux.{ LinuxPlugin, LinuxPackageMapping, LinuxFileMetaData, LinuxSymlink }
import sbt._
import com.typesafe.sbt.packager.linux.LinuxSymlink
import java.io.File

case class RpmMetadata(
Expand Down Expand Up @@ -59,6 +58,41 @@ case class RpmScripts(
posttrans: Option[String] = None,
preun: Option[String] = None,
postun: Option[String] = None) {

def pretransContent(): String =
pretrans.fold("")("\n%pretrans\n" + _ + "\n\n")

def preContent(): String =
pre.fold("")("\n%pre\n" + _ + "\n\n")

def postContent(buildSymlinkScript: Option[String]): String = {
val scripts = Seq(post, buildSymlinkScript).flatten
if (scripts.isEmpty)
""
else
"\n%post\n" + scripts.mkString("\n") + "\n\n"
}

def posttransContent(): String =
posttrans.fold("")("\n%posttrans\n" + _ + "\n\n")

def verifyscriptContent(): String =
verifyscript.fold("")("\n%verifyscript\n" + _ + "\n\n")

def preunContent(): String =
preun.fold("")("\n%preun\n" + _ + "\n\n")

def postunContent(tearDownSymlinkScript: Option[String]): String = {
val scripts = Seq(postun, tearDownSymlinkScript).flatten
if (scripts.isEmpty)
""
else
"\n%postun\n" + scripts.mkString("\n") + "\n\n"
}

@deprecated(
"Call individual scriptlet content method instead, e.g. pretransContent(). This is to allow managing symlink during %post and %postun so it can be relocated",
since = "1.0.5-M4")
def contents(): String = {
val labelledScripts = Seq("%pretrans", "%pre", "%post", "%verifyscript", "%posttrans", "%preun", "%postun")
.zip(Seq(pretrans, pre, post, verifyscript, posttrans, preun, postun))
Expand All @@ -73,7 +107,11 @@ case class RpmSpec(
deps: RpmDependencies = RpmDependencies(),
scriptlets: RpmScripts = RpmScripts(),
mappings: Seq[LinuxPackageMapping] = Seq.empty,
symlinks: Seq[LinuxSymlink] = Seq.empty) {
symlinks: Seq[LinuxSymlink] = Seq.empty,
installLocation: String) {

def installDir: String =
LinuxPlugin.chdir(installLocation, meta.name)

// TODO - here we want to validate that all the data we have is ok to place
// in the RPM. e.g. the Description/vendor etc. must meet specific requirements.
Expand Down Expand Up @@ -141,9 +179,6 @@ case class RpmSpec(
mapping <- mappings
(file, dest) <- mapping.mappings
} sb append makeFilesLine(dest, mapping.fileData, file.isDirectory)
for {
link <- symlinks
} sb append (fixFilename(link.link) + "\n")
sb.toString
}

Expand Down Expand Up @@ -199,7 +234,13 @@ case class RpmSpec(
// TODO - Allow symlinks

// write scriptlets
sb append scriptlets.contents()
sb append scriptlets.pretransContent()
sb append scriptlets.preContent()
sb append scriptlets.postContent(buildSymlinkScript(meta.name, installDir, symlinks))
sb append scriptlets.verifyscriptContent()
sb append scriptlets.posttransContent()
sb append scriptlets.preunContent()
sb append scriptlets.postunContent(teardownSymlinkScript(meta.name, installDir, symlinks))

// Write file mappings
sb append fileSection
Expand All @@ -215,4 +256,43 @@ case class RpmSpec(
}
sb.toString
}

private def buildSymlinkScript(appName: String, installDir: String, symlinks: Seq[LinuxSymlink]): Option[String] =
if (symlinks.isEmpty)
None
else {
val relocateLinks = symlinks
.map { symlink =>
s"""rm -rf $$(relocateLink ${symlink.link} $installDir $appName $$RPM_INSTALL_PREFIX) && ln -s $$(relocateLink ${symlink.destination} $installDir $appName $$RPM_INSTALL_PREFIX) $$(relocateLink ${symlink.link} $installDir $appName $$RPM_INSTALL_PREFIX)"""
}
.mkString("\n")

Some(relocateLinkFunction + "\n" + relocateLinks)
}

private def teardownSymlinkScript(appName: String, installDir: String, symlinks: Seq[LinuxSymlink]): Option[String] =
if (symlinks.isEmpty)
None
else {
val sourceAppConfig = s"""[ -e /etc/sysconfig/$appName ] && . /etc/sysconfig/$appName"""
val cleanupLinks = symlinks
.map { symlink =>
s"""rm -rf $$(relocateLink ${symlink.link} $installDir $appName $$PACKAGE_PREFIX)"""
}
.mkString("\n")

Some(relocateLinkFunction + "\n" + sourceAppConfig + "\n" + cleanupLinks)
}

private def relocateLinkFunction: String =
"""
|relocateLink() {
| if [ -n "$4" ] ;
| then
| RELOCATED_INSTALL_DIR="$4/$3"
| echo "${1/$2/$RELOCATED_INSTALL_DIR}"
| else
| echo "$1"
| fi
|}""".stripMargin
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ object RpmPlugin extends AutoPlugin {
rpmScripts <<=
(rpmPretrans, rpmPre, rpmPost, rpmVerifyscript, rpmPosttrans, rpmPreun, rpmPostun) apply RpmScripts,
rpmSpecConfig <<=
(rpmMetadata, rpmDescription, rpmDependencies, rpmScripts, linuxPackageMappings, linuxPackageSymlinks) map RpmSpec,
(rpmMetadata, rpmDescription, rpmDependencies, rpmScripts, linuxPackageMappings, linuxPackageSymlinks, defaultLinuxInstallLocation) map RpmSpec,
packageBin <<= (rpmSpecConfig, target, streams) map { (spec, dir, s) =>
spec.validate(s.log)
RpmHelper.buildRpm(spec, dir, s.log)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,7 @@ object Archives {
def makeTarball(compressor: File => File, ext: String)(target: File, name: String, mappings: Seq[(File, String)], top: Option[String]): File =
makeTarballWithOptions(compressor, ext)(target, name, mappings, top, options = Seq("--force-local", "-pcvf"))


/**
/**
* Helper method used to construct tar-related compression functions.
* @param target folder to build package in
* @param name of output (without extension)
Expand Down
16 changes: 13 additions & 3 deletions src/sbt-test/jar/classpath-jar/src/main/scala/test/Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,27 @@ package test
// use dependency library

import akka.actor._
import akka.pattern._
import akka.routing.RoundRobinRouter
import akka.util.Timeout
import scala.concurrent.duration._

class PrintActor extends Actor{
def receive = {
case msg => println(msg)
case msg =>
println(msg)
context.sender ! "ok"
}
}

object Test extends App {
implicit val timeout = Timeout(3 seconds)

val system = ActorSystem("testSystem")
import system.dispatcher

val router = system.actorOf(Props[PrintActor])
router ! "SUCCESS!!"
system.shutdown
(router ? "SUCCESS!!").foreach { _ =>
system.shutdown
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@muuki88 - this is not related to the RPM symlink issue, but I have intermittent failure on this test today, and hence the fix.

The failure is originally caused by the race condition where the actor system may be shutdown before the actor under test has the chance to print the expected message.

}
34 changes: 34 additions & 0 deletions src/sbt-test/rpm/scriptlets-rpm/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,44 @@ TaskKey[Unit]("check-spec-file") <<= (target, streams) map { (target, out) =>
val spec = IO.read(target / "rpm" / "SPECS" / "rpm-test.spec")
assert(spec contains "%pre\necho \"pre-install\"", "Spec doesn't contain %pre scriptlet")
assert(spec contains "%post\necho \"post-install\"", "Spec doesn't contain %post scriptlet")
assert(spec contains
"""
|%post
|echo "post-install"
|
|relocateLink() {
| if [ -n "$4" ] ;
| then
| RELOCATED_INSTALL_DIR="$4/$3"
| echo "${1/$2/$RELOCATED_INSTALL_DIR}"
| else
| echo "$1"
| fi
|}
|rm -rf $(relocateLink /etc/rpm-test /usr/share/rpm-test rpm-test $RPM_INSTALL_PREFIX) && ln -s $(relocateLink /usr/share/rpm-test/conf /usr/share/rpm-test rpm-test $RPM_INSTALL_PREFIX) $(relocateLink /etc/rpm-test /usr/share/rpm-test rpm-test $RPM_INSTALL_PREFIX)
|""".stripMargin, "%post scriptlet does not contain relocateLink")

assert(spec contains "%pretrans\necho \"pretrans\"", "Spec doesn't contain %pretrans scriptlet")
assert(spec contains "%posttrans\necho \"posttrans\"", "Spec doesn't contain %posttrans scriptlet")
assert(spec contains "%preun\necho \"pre-uninstall\"", "Spec doesn't contain %preun scriptlet")
assert(spec contains "%postun\necho \"post-uninstall\"", "Spec doesn't contain %postun scriptlet")
assert(spec contains
"""
|%postun
|echo "post-uninstall"
|
|relocateLink() {
| if [ -n "$4" ] ;
| then
| RELOCATED_INSTALL_DIR="$4/$3"
| echo "${1/$2/$RELOCATED_INSTALL_DIR}"
| else
| echo "$1"
| fi
|}
|[ -e /etc/sysconfig/rpm-test ] && . /etc/sysconfig/rpm-test
|rm -rf $(relocateLink /etc/rpm-test /usr/share/rpm-test rpm-test $PACKAGE_PREFIX)
|""".stripMargin, "%postun scriptlet does not contain relocate link")
out.log.success("Successfully tested rpm test file")
()
}
Expand Down