Skip to content

Commit

Permalink
Extract Symlinks from Archives (#1718)
Browse files Browse the repository at this point in the history
re-create symlinks when extracting archives
  • Loading branch information
4e6 authored and iamrecursion committed Jun 24, 2021
1 parent 414ed34 commit dda4d6d
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@ import scala.util.{Try, Using}
*/
object Archive {

/** An archive entry representing a symbolic link. */
sealed trait Symlink
object Symlink {

/** The TAR archive entry representing a symbolic link.
*
* @param target the symlink target
*/
case class TarArchiveSymlink(target: Path) extends Symlink

/** The ZIP archive entry representing a symbolic lint.
* The entry's contents contains the symlink target.
*/
case object ZipArchiveSymlink extends Symlink
}

private val logger = Logger[Archive.type]

/** Extracts the archive at `archivePath` to `destinationDirectory`.
Expand Down Expand Up @@ -205,6 +221,16 @@ object Archive {
case None =>
missingPermissions += 1
}
getSymlink(entry).foreach {
case Archive.Symlink.TarArchiveSymlink(target) =>
Files.deleteIfExists(destinationPath)
Files.createSymbolicLink(destinationPath, target)
case Archive.Symlink.ZipArchiveSymlink =>
val target =
Path.of(Files.readString(destinationPath).trim)
Files.deleteIfExists(destinationPath)
Files.createSymbolicLink(destinationPath, target)
}
}
}
}
Expand Down Expand Up @@ -255,6 +281,19 @@ object Archive {
None
}

/** Get the symlink information associated with that `entry`. */
private def getSymlink(entry: ApacheArchiveEntry): Option[Symlink] = {
entry match {
case entry: TarArchiveEntry if entry.isSymbolicLink =>
val target = Path.of(entry.getLinkName)
Some(Symlink.TarArchiveSymlink(target))
case entry: ZipArchiveEntry if entry.isUnixSymlink =>
Some(Symlink.ZipArchiveSymlink)
case _ =>
None
}
}

/** Opens the archive at `path` and executes the provided action.
*
* The action is given an [[ArchiveInputStream]] that can be used to read
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ case class UninstallationError(message: String)
extends ComponentsException(message)

/** Indicates that the required executable was not found. */
// TODO: [DB] Mask sensitive user data
case class ExecutableNotFoundError(path: Path, name: String)
extends ComponentsException(
s"Executable with the name '$name' does not found on $path."
s"Executable with the name '$name' was not found on $path."
)
Original file line number Diff line number Diff line change
Expand Up @@ -719,31 +719,41 @@ class RuntimeVersionManager(
s"Loading temporary runtime ${runtimeTemporaryPath.toAbsolutePath}."
)
val temporaryRuntime =
loadGraalRuntime(runtimeTemporaryPath).getOrElse {
throw InstallationError(
"Cannot load the installed runtime. The package may have been " +
"corrupted. Reverting installation."
loadGraalRuntime(runtimeTemporaryPath).recoverWith { error =>
Failure(
InstallationError(
"Cannot load the installed runtime. The package may have " +
s"been corrupted. Reverting installation.",
error
)
)
}
}.get
logger.debug(s"Installing GraalVM components to $temporaryRuntime.")
installRequiredRuntimeComponents(temporaryRuntime).getOrElse {
throw InstallationError(
"fatal: Cannot install the required runtime components."
)
}
installRequiredRuntimeComponents(temporaryRuntime).recoverWith {
error =>
Failure(
InstallationError(
s"fatal: Cannot install the required runtime components.",
error
)
)
}.get

val runtimePath =
distributionManager.paths.runtimes / runtimeDirectoryName
logger.debug(
s"Moving ${runtimeTemporaryPath.toAbsolutePath} to ${runtimePath.toAbsolutePath}."
)
FileSystem.atomicMove(runtimeTemporaryPath, runtimePath)
val runtime = loadGraalRuntime(runtimePath).getOrElse {
val runtime = loadGraalRuntime(runtimePath).recoverWith { error =>
FileSystem.removeDirectory(runtimePath)
throw InstallationError(
"fatal: Cannot load the installed runtime."
Failure(
InstallationError(
s"fatal: Cannot load the installed runtime.",
error
)
)
}
}.get
logger.debug(s"Installed $runtime.")
userInterface.logInfo(s"Installed $runtime.")

Expand Down

0 comments on commit dda4d6d

Please sign in to comment.