8231283: Add support to jpackage to create install Linux packages in /usr hierarchy

Reviewed-by: herrick, almatvee
This commit is contained in:
Alexey Semenyuk 2020-06-10 11:12:33 -04:00
parent 714b345bf5
commit 268d870187
26 changed files with 877 additions and 165 deletions

View File

@ -432,10 +432,18 @@ public class LinuxDebBundler extends LinuxPackageBundler {
}
private File getConfig_CopyrightFile(Map<String, ? super Object> params) {
PlatformPackage thePackage = createMetaPackage(params);
return thePackage.sourceRoot().resolve(Path.of(".",
LINUX_INSTALL_DIR.fetchFrom(params), PACKAGE_NAME.fetchFrom(
params), "share/doc/copyright")).toFile();
final String installDir = LINUX_INSTALL_DIR.fetchFrom(params);
final String packageName = PACKAGE_NAME.fetchFrom(params);
final Path installPath;
if (isInstallDirInUsrTree(installDir) || installDir.startsWith("/usr/")) {
installPath = Path.of("/usr/share/doc/", packageName, "copyright");
} else {
installPath = Path.of(installDir, packageName, "share/doc/copyright");
}
return createMetaPackage(params).sourceRoot().resolve(
Path.of("/").relativize(installPath)).toFile();
}
private File buildDeb(Map<String, ? super Object> params,

View File

@ -31,6 +31,7 @@ import java.text.MessageFormat;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static jdk.incubator.jpackage.internal.DesktopIntegration.*;
@ -114,8 +115,8 @@ abstract class LinuxPackageBundler extends AbstractBundler {
initAppImageLayout.apply(appImage).copy(
thePackage.sourceApplicationLayout());
} else {
appImage = appImageBundler.execute(params,
thePackage.sourceRoot().toFile());
final Path srcAppImageRoot = thePackage.sourceRoot().resolve("src");
appImage = appImageBundler.execute(params, srcAppImageRoot.toFile());
ApplicationLayout srcAppLayout = initAppImageLayout.apply(
appImage);
if (appImage.equals(PREDEFINED_RUNTIME_IMAGE.fetchFrom(params))) {
@ -126,11 +127,7 @@ abstract class LinuxPackageBundler extends AbstractBundler {
// Application image is a newly created directory tree.
// Move it.
srcAppLayout.move(thePackage.sourceApplicationLayout());
if (appImage.exists()) {
// Empty app image directory might remain after all application
// directories have been moved.
appImage.delete();
}
IOUtils.deleteRecursive(srcAppImageRoot.toFile());
}
}
@ -240,6 +237,17 @@ abstract class LinuxPackageBundler extends AbstractBundler {
final protected PlatformPackage createMetaPackage(
Map<String, ? super Object> params) {
Supplier<ApplicationLayout> packageLayout = () -> {
String installDir = LINUX_INSTALL_DIR.fetchFrom(params);
if (isInstallDirInUsrTree(installDir)) {
return ApplicationLayout.linuxUsrTreePackageImage(
Path.of("/").relativize(Path.of(installDir)),
packageName.fetchFrom(params));
}
return appImageLayout(params);
};
return new PlatformPackage() {
@Override
public String name() {
@ -253,19 +261,23 @@ abstract class LinuxPackageBundler extends AbstractBundler {
@Override
public ApplicationLayout sourceApplicationLayout() {
return appImageLayout(params).resolveAt(
return packageLayout.get().resolveAt(
applicationInstallDir(sourceRoot()));
}
@Override
public ApplicationLayout installedApplicationLayout() {
return appImageLayout(params).resolveAt(
return packageLayout.get().resolveAt(
applicationInstallDir(Path.of("/")));
}
private Path applicationInstallDir(Path root) {
Path installDir = Path.of(LINUX_INSTALL_DIR.fetchFrom(params),
name());
String installRoot = LINUX_INSTALL_DIR.fetchFrom(params);
if (isInstallDirInUsrTree(installRoot)) {
return root;
}
Path installDir = Path.of(installRoot, name());
if (installDir.isAbsolute()) {
installDir = Path.of("." + installDir.toString()).normalize();
}
@ -284,10 +296,6 @@ abstract class LinuxPackageBundler extends AbstractBundler {
private static void validateInstallDir(String installDir) throws
ConfigException {
if (installDir.startsWith("/usr/") || installDir.equals("/usr")) {
throw new ConfigException(MessageFormat.format(I18N.getString(
"error.unsupported-install-dir"), installDir), null);
}
if (installDir.isEmpty()) {
throw new ConfigException(MessageFormat.format(I18N.getString(
@ -312,6 +320,10 @@ abstract class LinuxPackageBundler extends AbstractBundler {
}
}
protected static boolean isInstallDirInUsrTree(String installDir) {
return Set.of("/usr/local", "/usr").contains(installDir);
}
private final BundlerParamInfo<String> packageName;
private final Bundler appImageBundler;
private boolean withFindNeededPackages;

View File

@ -159,8 +159,15 @@ public class LinuxRpmBundler extends LinuxPackageBundler {
Map<String, ? super Object> params) throws IOException {
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_DIRECTORY", Path.of(LINUX_INSTALL_DIR.fetchFrom(
params), PACKAGE_NAME.fetchFrom(params)).toString());
final Path prefix = Path.of(LINUX_INSTALL_DIR.fetchFrom(params));
Path appDirectory = prefix;
if (!isInstallDirInUsrTree(prefix.toString())) {
appDirectory = appDirectory.resolve(PACKAGE_NAME.fetchFrom(params));
}
data.put("APPLICATION_PREFIX", prefix.toString());
data.put("APPLICATION_DIRECTORY", appDirectory.toString());
data.put("APPLICATION_SUMMARY", APP_NAME.fetchFrom(params));
data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params));

View File

@ -44,7 +44,6 @@ error.tool-not-found.advice=Please install required packages
error.tool-old-version.advice=Please install required packages
error.invalid-install-dir=Invalid installation directory "{0}"
error.unsupported-install-dir=Installing to system directory "{0}" is currently unsupported
error.invalid-value-for-package-name=Invalid value "{0}" for the bundle name.
error.invalid-value-for-package-name.advice=Set the "linux-bundle-name" option to a valid Debian package name. Note that the package names must consist only of lower case letters (a-z), digits (0-9), plus (+) and minus (-) signs, and periods (.). They must be at least two characters long and must start with an alphanumeric character.

View File

@ -44,7 +44,6 @@ error.tool-not-found.advice=\u5FC5\u8981\u306A\u30D1\u30C3\u30B1\u30FC\u30B8\u30
error.tool-old-version.advice=\u5FC5\u8981\u306A\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044
error.invalid-install-dir=\u7121\u52B9\u306A\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u30FB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA"{0}"
error.unsupported-install-dir=\u30B7\u30B9\u30C6\u30E0\u30FB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA"{0}"\u3078\u306E\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u306F\u73FE\u5728\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093
error.invalid-value-for-package-name=\u30D0\u30F3\u30C9\u30EB\u540D\u306E\u5024"{0}"\u304C\u7121\u52B9\u3067\u3059\u3002
error.invalid-value-for-package-name.advice="linux-bundle-name"\u30AA\u30D7\u30B7\u30E7\u30F3\u3092\u6709\u52B9\u306ADebian\u30D1\u30C3\u30B1\u30FC\u30B8\u540D\u306B\u8A2D\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D1\u30C3\u30B1\u30FC\u30B8\u540D\u306B\u306F\u3001\u5C0F\u6587\u5B57(a-z)\u3001\u6570\u5B57(0-9)\u3001\u30D7\u30E9\u30B9(+)\u3068\u30DE\u30A4\u30CA\u30B9(-)\u306E\u8A18\u53F7\u304A\u3088\u3073\u30D4\u30EA\u30AA\u30C9(.)\u306E\u307F\u3092\u542B\u3081\u308B\u3088\u3046\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u9577\u3055\u306F2\u6587\u5B57\u4EE5\u4E0A\u3068\u3057\u3001\u82F1\u6570\u5B57\u3067\u59CB\u3081\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002

View File

@ -44,7 +44,6 @@ error.tool-not-found.advice=\u8BF7\u5B89\u88C5\u6240\u9700\u7684\u7A0B\u5E8F\u53
error.tool-old-version.advice=\u8BF7\u5B89\u88C5\u6240\u9700\u7684\u7A0B\u5E8F\u5305
error.invalid-install-dir=\u5B89\u88C5\u76EE\u5F55 "{0}" \u65E0\u6548
error.unsupported-install-dir=\u5F53\u524D\u4E0D\u652F\u6301\u5B89\u88C5\u5230\u7CFB\u7EDF\u76EE\u5F55 "{0}"
error.invalid-value-for-package-name=\u5305\u540D\u7684\u503C "{0}" \u65E0\u6548\u3002
error.invalid-value-for-package-name.advice=\u5C06 "linux-bundle-name" \u9009\u9879\u8BBE\u7F6E\u4E3A\u6709\u6548\u7684 Debian \u7A0B\u5E8F\u5305\u540D\u79F0\u3002\u8BF7\u6CE8\u610F\uFF0C\u7A0B\u5E8F\u5305\u540D\u79F0\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD (a-z)\u3001\u6570\u5B57 (0-9)\u3001\u52A0\u53F7 (+) \u548C\u51CF\u53F7 (-) \u4EE5\u53CA\u53E5\u70B9 (.)\u3002\u540D\u79F0\u957F\u5EA6\u5FC5\u987B\u81F3\u5C11\u4E3A\u4E24\u4E2A\u5B57\u7B26\u5E76\u4E14\u5FC5\u987B\u4EE5\u5B57\u6BCD\u6570\u5B57\u5B57\u7B26\u5F00\u5934\u3002

View File

@ -4,8 +4,13 @@ Version: APPLICATION_VERSION
Release: APPLICATION_RELEASE
License: APPLICATION_LICENSE_TYPE
Vendor: APPLICATION_VENDOR
Prefix: %{dirname:APPLICATION_DIRECTORY}
%if "xAPPLICATION_PREFIX" != x
Prefix: APPLICATION_PREFIX
%endif
Provides: APPLICATION_PACKAGE
%if "xAPPLICATION_GROUP" != x
Group: APPLICATION_GROUP
%endif
@ -21,6 +26,12 @@ Requires: PACKAGE_DEFAULT_DEPENDENCIES PACKAGE_CUSTOM_DEPENDENCIES
#build time will substantially increase and it may require unpack200/system java to install
%define __jar_repack %{nil}
%define package_filelist %{_tmppath}/%{name}.files
%define app_filelist %{_tmppath}/%{name}.app.files
%define filesystem_filelist %{_tmppath}/%{name}.filesystem.files
%define default_filesystem / /opt /usr /usr/bin /usr/lib /usr/local /usr/local/bin /usr/local/lib
%description
APPLICATION_DESCRIPTION
@ -34,19 +45,22 @@ install -d -m 755 %{buildroot}APPLICATION_DIRECTORY
cp -r %{_sourcedir}APPLICATION_DIRECTORY/* %{buildroot}APPLICATION_DIRECTORY
%if "xAPPLICATION_LICENSE_FILE" != x
%define license_install_file %{_defaultlicensedir}/%{name}-%{version}/%{basename:APPLICATION_LICENSE_FILE}
install -d -m 755 %{buildroot}%{dirname:%{license_install_file}}
install -m 644 APPLICATION_LICENSE_FILE %{buildroot}%{license_install_file}
install -d -m 755 "%{buildroot}%{dirname:%{license_install_file}}"
install -m 644 "APPLICATION_LICENSE_FILE" "%{buildroot}%{license_install_file}"
%endif
(cd %{buildroot} && find . -type d) | sed -e 's/^\.//' -e '/^$/d' | sort > %{app_filelist}
{ rpm -ql filesystem || echo %{default_filesystem}; } | sort > %{filesystem_filelist}
comm -23 %{app_filelist} %{filesystem_filelist} > %{package_filelist}
sed -i -e 's/.*/%dir "&"/' %{package_filelist}
(cd %{buildroot} && find . -not -type d) | sed -e 's/^\.//' -e 's/.*/"&"/' >> %{package_filelist}
%if "xAPPLICATION_LICENSE_FILE" != x
sed -i -e 's|"%{license_install_file}"||' -e '/^$/d' %{package_filelist}
%endif
%files
%files -f %{package_filelist}
%if "xAPPLICATION_LICENSE_FILE" != x
%license %{license_install_file}
%{dirname:%{license_install_file}}
%license "%{license_install_file}"
%endif
# If installation directory for the application is /a/b/c, we want only root
# component of the path (/a) in the spec file to make sure all subdirectories
# are owned by the package.
%(echo APPLICATION_DIRECTORY | sed -e "s|\(^/[^/]\{1,\}\).*$|\1|")
%post
DESKTOP_COMMANDS_INSTALL

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdio.h>
#include <stdlib.h>
#include "Executor.h"
#include "Log.h"
#include "ErrorHandling.h"
int executeCommandLineAndReadStdout(const std::string& cmd,
CommandOutputConsumer& consumer) {
FILE * stream = popen(cmd.c_str(), "r");
if (!stream) {
JP_THROW(tstrings::any() << "popen(" << cmd
<< ") failed. Error: " << lastCRTError());
}
LOG_TRACE(tstrings::any() << "Reading output of [" << cmd << "] command");
try {
bool useConsumer = true;
std::string buf;
for (;;) {
const int c = fgetc(stream);
if(c == EOF) {
if (useConsumer && !buf.empty()) {
LOG_TRACE(tstrings::any() << "Next line: [" << buf << "]");
consumer.accept(buf);
}
break;
}
if (c == '\n' && useConsumer) {
LOG_TRACE(tstrings::any() << "Next line: [" << buf << "]");
useConsumer = !consumer.accept(buf);
buf.clear();
} else {
buf.push_back(static_cast<char>(c));
}
}
return pclose(stream);
} catch (...) {
if (stream) {
pclose(stream);
}
throw;
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include "tstrings.h"
class CommandOutputConsumer {
public:
virtual ~CommandOutputConsumer() {}
virtual bool accept(const std::string& line) {
return true;
};
};
int executeCommandLineAndReadStdout(const std::string& cmd,
CommandOutputConsumer& consumer);
#endif // #ifndef EXECUTOR_H

View File

@ -23,29 +23,41 @@
* questions.
*/
#include <stdio.h>
#include "AppLauncher.h"
#include "FileUtils.h"
#include "UnixSysInfo.h"
#include "Package.h"
namespace {
void launchApp() {
setlocale(LC_ALL, "en_US.utf8");
const tstring launcherPath = SysInfo::getProcessModulePath();
// Launcher should be in "bin" subdirectory of app image.
const tstring appImageRoot = FileUtils::dirname(
FileUtils::dirname(launcherPath));
const Package ownerPackage = Package::findOwnerOfFile(launcherPath);
AppLauncher()
.setImageRoot(appImageRoot)
.addJvmLibName(_T("lib/libjli.so"))
.setAppDir(FileUtils::mkpath() << appImageRoot << _T("lib/app"))
.setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot
<< _T("lib/runtime"))
.launch();
AppLauncher appLauncher;
appLauncher.addJvmLibName(_T("lib/libjli.so"));
if (ownerPackage.name().empty()) {
// Launcher should be in "bin" subdirectory of app image.
const tstring appImageRoot = FileUtils::dirname(
FileUtils::dirname(launcherPath));
appLauncher
.setImageRoot(appImageRoot)
.setAppDir(FileUtils::mkpath() << appImageRoot << _T("lib/app"))
.setDefaultRuntimePath(FileUtils::mkpath() << appImageRoot
<< _T("lib/runtime"));
} else {
ownerPackage.initAppLauncher(appLauncher);
}
appLauncher.launch();
}
} // namespace

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include "Package.h"
#include "Executor.h"
#include "AppLauncher.h"
#include "ErrorHandling.h"
Package::Package(): type(Unknown) {
}
namespace {
class FirstLineConsumer : public CommandOutputConsumer {
public:
FirstLineConsumer(): processed(false) {
}
virtual bool accept(const std::string& line) {
if (!processed) {
value = line;
processed = true;
}
return processed;
};
std::string getValue() const {
if (!processed) {
JP_THROW("No output captured");
}
return value;
}
private:
bool processed;
std::string value;
};
std::string findOwnerOfFile(const std::nothrow_t&, const std::string& cmdline,
const std::string& path) {
try {
FirstLineConsumer consumer;
int exitCode = executeCommandLineAndReadStdout(
cmdline + " \'" + path + "\' 2>/dev/null", consumer);
if (exitCode == 0) {
return consumer.getValue();
}
} catch (...) {
}
return "";
}
} // namespace
Package Package::findOwnerOfFile(const std::string& path) {
Package result;
result.theName = ::findOwnerOfFile(std::nothrow,
"rpm --queryformat '%{NAME}' -qf", path);
if (!result.theName.empty()) {
result.type = RPM;
} else {
tstring_array components = tstrings::split(::findOwnerOfFile(
std::nothrow, "dpkg -S", path), ":");
if (!components.empty()) {
result.theName = components.front();
if (!result.theName.empty()) {
result.type = DEB;
}
}
}
return result;
}
namespace {
class AppLauncherInitializer : public CommandOutputConsumer {
public:
AppLauncherInitializer() {
}
virtual bool accept(const std::string& line) {
if (appDir.empty()) {
if (tstrings::endsWith(line, "/app")) {
appDir = line;
}
}
if (runtimeDir.empty()) {
if (tstrings::endsWith(line, "/runtime")) {
runtimeDir = line;
}
}
return !appDir.empty() && !runtimeDir.empty();
};
void apply(AppLauncher& launcher) {
launcher.setDefaultRuntimePath(runtimeDir);
launcher.setAppDir(appDir);
}
private:
std::string appDir;
std::string runtimeDir;
};
} // namespace
void Package::initAppLauncher(AppLauncher& appLauncher) const {
AppLauncherInitializer consumer;
int exitCode = -1;
if (type == RPM) {
exitCode = executeCommandLineAndReadStdout(
"rpm -ql \'" + theName + "\'", consumer);
} else if (type == DEB) {
exitCode = executeCommandLineAndReadStdout(
"dpkg -L \'" + theName + "\'", consumer);
}
if (exitCode == 0) {
consumer.apply(appLauncher);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef PACKAGE_H
#define PACKAGE_H
#include "tstrings.h"
class AppLauncher;
class Package {
public:
Package();
std::string name() const {
return theName;
}
void initAppLauncher(AppLauncher& appLauncher) const;
static Package findOwnerOfFile(const std::string& path);
private:
enum Type { Unknown, RPM, DEB };
Type type;
std::string theName;
};
#endif // #ifndef PACKAGE_H

View File

@ -177,5 +177,18 @@ public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayo
return new ApplicationLayout(Map.of(PathRole.RUNTIME, Path.of("")));
}
public static ApplicationLayout linuxUsrTreePackageImage(Path prefix,
String packageName) {
final Path lib = prefix.resolve(Path.of("lib", packageName));
return new ApplicationLayout(Map.of(
PathRole.LAUNCHERS, prefix.resolve("bin"),
PathRole.APP, lib.resolve("app"),
PathRole.RUNTIME, lib.resolve("runtime"),
PathRole.RUNTIME_HOME, lib.resolve("runtime"),
PathRole.DESKTOP, lib,
PathRole.MODULES, lib.resolve("app/mods")
));
}
private final PathGroup data;
}

View File

@ -55,7 +55,6 @@ final class CfgFile {
ApplicationLayout appCfgLayout = createAppCfgLayout();
content.add(Map.entry("[Application]", SECTION_TAG));
content.add(Map.entry("app.runtime", appCfgLayout.runtimeDirectory()));
if (launcherData.isModular()) {
content.add(Map.entry("app.mainmodule", launcherData.moduleName()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -213,7 +213,7 @@ public final class AdditionalLauncher {
TKit.assertExecutableFileExists(launcherPath);
if (cmd.isFakeRuntime(String.format(
if (!cmd.canRunLauncher(String.format(
"Not running %s launcher", launcherPath))) {
return;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -280,7 +280,7 @@ public final class HelloApp {
private static AppOutputVerifier getVerifier(JPackageCommand cmd,
String... args) {
final Path launcherPath = cmd.appLauncherPath();
if (cmd.isFakeRuntime(String.format("Not running [%s] launcher",
if (!cmd.canRunLauncher(String.format("Not running [%s] launcher",
launcherPath))) {
return null;
}

View File

@ -353,8 +353,17 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
* corresponding layout.
*/
public ApplicationLayout appLayout() {
final ApplicationLayout layout;
if (isRuntime()) {
ApplicationLayout layout = onLinuxPackageInstallDir(null,
installDir -> {
String packageName = LinuxHelper.getPackageName(this);
// Convert '/usr' to 'usr'. It will be set to proper root in
// subsequent ApplicationLayout.resolveAt() call.
return ApplicationLayout.linuxUsrTreePackageImage(Path.of(
"/").relativize(installDir), packageName);
});
if (layout != null) {
} else if (isRuntime()) {
layout = ApplicationLayout.javaRuntime();
} else {
layout = ApplicationLayout.platformAppImage();
@ -364,7 +373,25 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
return layout.resolveAt(outputBundle());
}
return layout.resolveAt(appInstallationDirectory());
return layout.resolveAt(pathToUnpackedPackageFile(
appInstallationDirectory()));
}
/**
* Returns path to package file in unpacked package directory or the given
* path if the package is not unpacked.
*/
public Path pathToUnpackedPackageFile(Path path) {
Path unpackDir = unpackedPackageDirectory();
if (unpackDir == null) {
return path;
}
return unpackDir.resolve(TKit.removeRootFromAbsolutePath(path));
}
Path unpackedPackageDirectory() {
verifyIsOfType(PackageType.NATIVE);
return getArgumentValue(UNPACKED_PATH_ARGNAME, () -> null, Path::of);
}
/**
@ -372,28 +399,19 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
* this is build image command.
*
* E.g. on Linux for app named Foo default the function will return
* `/opt/foo`
* `/opt/foo`.
* On Linux for install directory in `/usr` tree the function returns `/`.
*
*/
public Path appInstallationDirectory() {
Path unpackedDir = getArgumentValue(UNPACKED_PATH_ARGNAME, () -> null,
Path::of);
if (unpackedDir != null) {
return unpackedDir;
}
if (isImagePackageType()) {
return null;
}
if (TKit.isLinux()) {
if (isRuntime()) {
// Not fancy, but OK.
return Path.of(getArgumentValue("--install-dir", () -> "/opt"),
LinuxHelper.getPackageName(this));
}
// Launcher is in "bin" subfolder of the installation directory.
return appLauncherPath().getParent().getParent();
return onLinuxPackageInstallDir(installDir -> installDir.resolve(
LinuxHelper.getPackageName(this)),
installDir -> Path.of("/"));
}
if (TKit.isWindows()) {
@ -444,14 +462,6 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
launcherName = launcherName + ".exe";
}
if (isImagePackageType() || isPackageUnpacked()) {
return appLayout().launchersDirectory().resolve(launcherName);
}
if (TKit.isLinux()) {
return LinuxHelper.getLauncherPath(this).getParent().resolve(launcherName);
}
return appLayout().launchersDirectory().resolve(launcherName);
}
@ -514,6 +524,23 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
return false;
}
public boolean canRunLauncher(String msg) {
if (isFakeRuntime(msg)) {
return false;
}
if (isPackageUnpacked()) {
return Boolean.FALSE != onLinuxPackageInstallDir(null, installDir -> {
TKit.trace(String.format(
"%s because the package in [%s] directory is not installed ",
msg, installDir));
return Boolean.FALSE;
});
}
return true;
}
public boolean isPackageUnpacked(String msg) {
if (isPackageUnpacked()) {
TKit.trace(String.format(
@ -523,7 +550,7 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
return false;
}
boolean isPackageUnpacked() {
public boolean isPackageUnpacked() {
return hasArgument(UNPACKED_PATH_ARGNAME);
}
@ -780,6 +807,22 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
return !immutable;
}
private <T> T onLinuxPackageInstallDir(Function<Path, T> anyInstallDirConsumer,
Function<Path, T> usrInstallDirConsumer) {
if (TKit.isLinux()) {
Path installDir = Path.of(getArgumentValue("--install-dir",
() -> "/opt"));
if (Set.of("/usr", "/usr/local").contains(installDir.toString())) {
if (usrInstallDirConsumer != null) {
return usrInstallDirConsumer.apply(installDir);
}
} else if (anyInstallDirConsumer != null) {
return anyInstallDirConsumer.apply(installDir);
}
}
return null;
}
private final class Actions implements Runnable {
Actions() {
actions = new ArrayList<>();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -165,8 +165,7 @@ public class LinuxHelper {
.addArgument(cmd.outputBundle())
.addArgument(destinationDir)
.execute();
return destinationDir.resolve(String.format(".%s",
cmd.appInstallationDirectory())).normalize();
return destinationDir;
};
return deb;
}
@ -191,8 +190,7 @@ public class LinuxHelper {
cmd.outputBundle().toAbsolutePath().toString())))
.setDirectory(destinationDir)
.execute();
return destinationDir.resolve(String.format(".%s",
cmd.appInstallationDirectory())).normalize();
return destinationDir;
};
return rpm;

View File

@ -102,20 +102,27 @@ public class MacHelper {
withExplodedDmg(cmd, dmgImage -> {
Executor.of("sudo", "cp", "-r")
.addArgument(dmgImage)
.addArgument("/Applications")
.addArgument(getInstallationDirectory(cmd).getParent())
.execute();
});
};
dmg.unpackHandler = (cmd, destinationDir) -> {
Path[] unpackedFolder = new Path[1];
Path unpackDir = destinationDir.resolve(
TKit.removeRootFromAbsolutePath(
getInstallationDirectory(cmd)).getParent());
try {
Files.createDirectories(unpackDir);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
withExplodedDmg(cmd, dmgImage -> {
Executor.of("cp", "-r")
.addArgument(dmgImage)
.addArgument(destinationDir)
.addArgument(unpackDir)
.execute();
unpackedFolder[0] = destinationDir.resolve(dmgImage.getFileName());
});
return unpackedFolder[0];
return destinationDir;
};
dmg.uninstallHandler = cmd -> {
cmd.verifyIsOfType(PackageType.MAC_DMG);
@ -143,13 +150,25 @@ public class MacHelper {
.addArgument(cmd.outputBundle())
.addArgument(destinationDir.resolve("data")) // We need non-existing folder
.execute();
final Path unpackRoot = destinationDir.resolve("unpacked");
Path installDir = TKit.removeRootFromAbsolutePath(
getInstallationDirectory(cmd)).getParent();
final Path unpackDir = unpackRoot.resolve(installDir);
try {
Files.createDirectories(unpackDir);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
Executor.of("tar", "-C")
.addArgument(destinationDir)
.addArgument(unpackDir)
.addArgument("-xvf")
.addArgument(Path.of(destinationDir.toString(), "data",
cmd.name() + "-app.pkg", "Payload"))
.execute();
return destinationDir.resolve(cmd.name() + ".app");
return unpackRoot;
};
pkg.uninstallHandler = cmd -> {
cmd.verifyIsOfType(PackageType.MAC_PKG);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,15 +27,30 @@ import java.awt.GraphicsEnvironment;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.jpackage.test.Functional.ThrowingConsumer;
import jdk.incubator.jpackage.internal.AppImageFile;
import jdk.incubator.jpackage.internal.ApplicationLayout;
import jdk.jpackage.test.Functional.ThrowingBiConsumer;
import jdk.jpackage.test.Functional.ThrowingConsumer;
import jdk.jpackage.test.Functional.ThrowingRunnable;
import static jdk.jpackage.test.PackageType.*;
import jdk.jpackage.test.Functional.ThrowingSupplier;
/**
* Instance of PackageTest is for configuring and running a single jpackage
@ -170,7 +185,7 @@ public final class PackageTest extends RunnablePackageTest {
}
public PackageTest addBundleDesktopIntegrationVerifier(boolean integrated) {
forTypes(LINUX, () -> {
forTypes(PackageType.LINUX, () -> {
LinuxHelper.addBundleDesktopIntegrationVerifier(this, integrated);
});
return this;
@ -549,8 +564,19 @@ public final class PackageTest extends RunnablePackageTest {
}
}
TKit.assertPathExists(AppImageFile.getPathInAppImage(
cmd.appInstallationDirectory()), false);
if (cmd.isPackageUnpacked()) {
final Path appImageFile = AppImageFile.getPathInAppImage(
Path.of(""));
try (Stream<Path> walk = ThrowingSupplier.toSupplier(
() -> Files.walk(cmd.unpackedPackageDirectory())).get()) {
walk.filter(path -> path.getFileName().equals(appImageFile))
.findFirst()
.ifPresent(path -> TKit.assertPathExists(path, false));
}
} else {
TKit.assertPathExists(AppImageFile.getPathInAppImage(
cmd.appInstallationDirectory()), false);
}
installVerifiers.forEach(v -> v.accept(cmd));
}
@ -566,7 +592,13 @@ public final class PackageTest extends RunnablePackageTest {
}
}
TKit.assertPathExists(cmd.appInstallationDirectory(), false);
Path appInstallDir = cmd.appInstallationDirectory();
if (TKit.isLinux() && Path.of("/").equals(appInstallDir)) {
ApplicationLayout appLayout = cmd.appLayout();
TKit.assertPathExists(appLayout.runtimeDirectory(), false);
} else {
TKit.assertPathExists(appInstallDir, false);
}
uninstallVerifiers.forEach(v -> v.accept(cmd));
}

View File

@ -209,6 +209,17 @@ final public class TKit {
}
}
static Path removeRootFromAbsolutePath(Path v) {
if (!v.isAbsolute()) {
throw new IllegalArgumentException();
}
if (v.getNameCount() == 0) {
return Path.of("");
}
return v.subpath(0, v.getNameCount());
}
public static void createTextFile(Path propsFilename, Collection<String> lines) {
createTextFile(propsFilename, lines.stream());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,14 +41,18 @@ public class WindowsHelper {
}
static Path getInstallationDirectory(JPackageCommand cmd) {
Path installSubDir = getInstallationSubDirectory(cmd);
if (isUserLocalInstall(cmd)) {
return USER_LOCAL.resolve(installSubDir);
}
return PROGRAM_FILES.resolve(installSubDir);
return getInstallationRootDirectory(cmd).resolve(
getInstallationSubDirectory(cmd));
}
static Path getInstallationSubDirectory(JPackageCommand cmd) {
private static Path getInstallationRootDirectory(JPackageCommand cmd) {
if (isUserLocalInstall(cmd)) {
return USER_LOCAL;
}
return PROGRAM_FILES;
}
private static Path getInstallationSubDirectory(JPackageCommand cmd) {
cmd.verifyIsOfType(PackageType.WINDOWS);
return Path.of(cmd.getArgumentValue("--install-dir", () -> cmd.name()));
}
@ -81,11 +85,21 @@ public class WindowsHelper {
msi.uninstallHandler = cmd -> installMsi.accept(cmd, false);
msi.unpackHandler = (cmd, destinationDir) -> {
cmd.verifyIsOfType(PackageType.WIN_MSI);
runMsiexecWithRetries(Executor.of("msiexec", "/a")
.addArgument(cmd.outputBundle().normalize())
.addArguments("/qn", String.format("TARGETDIR=%s",
destinationDir.toAbsolutePath().normalize())));
return destinationDir.resolve(getInstallationSubDirectory(cmd));
final Path unpackBat = destinationDir.resolve("unpack.bat");
final Path unpackDir = destinationDir.resolve(
TKit.removeRootFromAbsolutePath(
getInstallationRootDirectory(cmd)));
// Put msiexec in .bat file because can't pass value of TARGETDIR
// property containing spaces through ProcessBuilder properly.
TKit.createTextFile(unpackBat, List.of(String.join(" ", List.of(
"msiexec",
"/a",
String.format("\"%s\"", cmd.outputBundle().normalize()),
"/qn",
String.format("TARGETDIR=\"%s\"",
unpackDir.toAbsolutePath().normalize())))));
runMsiexecWithRetries(Executor.of("cmd", "/c", unpackBat.toString()));
return destinationDir;
};
return msi;
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.LinuxHelper;
import jdk.jpackage.test.Annotations.Test;
/**
* Simple Linux specific packaging test. Resulting package should be installed
* in /usr directory tree.
*/
/*
* @test
* @summary jpackage command run installing app in /usr directory tree
* @library ../../../../helpers
* @key jpackagePlatformPackage
* @requires jpackage.test.SQETest == null
* @requires (os.family == "linux")
* @build jdk.jpackage.test.*
* @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
* @compile UsrTreeTest.java
* @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=UsrTreeTest
*/
public class UsrTreeTest {
@Test
public static void testUsr() {
test("/usr", true);
}
@Test
public static void testUsrLocal() {
test("/usr/local", true);
}
@Test
public static void testUsrCustom() {
test("/usr/foo", false);
}
@Test
public static void testUsrCustom2() {
test("/usrbuz", false);
}
private static void test(String installDir, boolean expectedImageSplit) {
new PackageTest()
.forTypes(PackageType.LINUX)
.configureHelloApp()
.addInitializer(cmd -> cmd.addArguments("--install-dir", installDir))
.addBundleDesktopIntegrationVerifier(false)
.addBundleVerifier(cmd -> {
final String packageName = LinuxHelper.getPackageName(cmd);
final Path launcherPath = cmd.appLauncherPath();
final Path launcherCfgPath = cmd.appLauncherCfgPath(null);
final Path commonPath = commonPath(launcherPath, launcherCfgPath);
final boolean actualImageSplit = !commonPath.getFileName().equals(
Path.of(packageName));
TKit.assertTrue(expectedImageSplit == actualImageSplit,
String.format(
"Check there is%spackage name [%s] in common path [%s] between [%s] and [%s]",
expectedImageSplit ? " no " : " ", packageName,
commonPath, launcherPath, launcherCfgPath));
List<Path> packageFiles = LinuxHelper.getPackageFiles(cmd).collect(
Collectors.toList());
Consumer<Path> packageFileVerifier = file -> {
TKit.assertTrue(packageFiles.stream().filter(
path -> path.equals(file)).findFirst().orElse(
null) != null, String.format(
"Check file [%s] is in [%s] package", file,
packageName));
};
packageFileVerifier.accept(launcherPath);
packageFileVerifier.accept(launcherCfgPath);
})
.run();
}
private static Path commonPath(Path a, Path b) {
if (a.equals(b)) {
return a;
}
final int minCount = Math.min(a.getNameCount(), b.getNameCount());
for (int i = minCount; i > 0; i--) {
Path sp = a.subpath(0, i);
if (sp.equals(b.subpath(0, i))) {
return a.getRoot().resolve(sp);
}
}
return a.getRoot();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -76,7 +76,7 @@ import jdk.jpackage.test.Annotations.Parameter;
* @requires (os.family == "linux")
* @requires (jpackage.test.SQETest == null)
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=InstallDirTest.testLinuxInvalid,testLinuxUnsupported
* --jpt-run=InstallDirTest.testLinuxInvalid
*/
public class InstallDirTest {
@ -90,11 +90,12 @@ public class InstallDirTest {
reply.put(PackageType.LINUX_RPM, reply.get(PackageType.LINUX_DEB));
reply.put(PackageType.MAC_PKG, Path.of("/Applications/jpackage"));
reply.put(PackageType.MAC_DMG, reply.get(PackageType.MAC_PKG));
return reply;
}).get();
new PackageTest().excludeTypes(PackageType.MAC_DMG).configureHelloApp()
new PackageTest().configureHelloApp()
.addInitializer(cmd -> {
cmd.addArguments("--install-dir", INSTALL_DIRS.get(
cmd.packageType()));
@ -109,13 +110,6 @@ public class InstallDirTest {
testLinuxBad(installDir, "Invalid installation directory");
}
@Parameter("/usr")
@Parameter("/usr/local")
@Parameter("/usr/foo")
public static void testLinuxUnsupported(String installDir) {
testLinuxBad(installDir, "currently unsupported");
}
private static void testLinuxBad(String installDir,
String errorMessageSubstring) {
new PackageTest().configureHelloApp()

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -78,47 +78,47 @@ import jdk.jpackage.test.TKit;
* @summary jpackage with --license-file
* @library ../helpers
* @key jpackagePlatformPackage
* @build jdk.jpackage.test.*
* @compile LicenseTest.java
* @requires (os.family == "linux")
* @requires (jpackage.test.SQETest == null)
* @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* @run main/othervm/timeout=1440 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=LicenseTest.testCustomDebianCopyright
* --jpt-run=LicenseTest.testCustomDebianCopyrightSubst
* --jpt-run=LicenseTest.testLinuxLicenseInUsrTree
* --jpt-run=LicenseTest.testLinuxLicenseInUsrTree2
* --jpt-run=LicenseTest.testLinuxLicenseInUsrTree3
* --jpt-run=LicenseTest.testLinuxLicenseInUsrTree4
*/
public class LicenseTest {
public static void testCommon() {
new PackageTest().configureHelloApp()
PackageTest test = new PackageTest().configureHelloApp()
.addInitializer(cmd -> {
cmd.addArguments("--license-file", TKit.createRelativePathCopy(
LICENSE_FILE));
})
.forTypes(PackageType.LINUX)
.addBundleVerifier(cmd -> {
verifyLicenseFileInLinuxPackage(cmd, linuxLicenseFile(cmd));
})
.addInstallVerifier(cmd -> {
Path path = linuxLicenseFile(cmd);
if (path != null) {
TKit.assertReadableFileExists(path);
}
})
.addUninstallVerifier(cmd -> {
verifyLicenseFileNotInstalledLinux(linuxLicenseFile(cmd));
})
.forTypes(PackageType.LINUX_DEB)
.addInstallVerifier(cmd -> {
verifyLicenseFileInstalledDebian(debLicenseFile(cmd));
})
.forTypes(PackageType.LINUX_RPM)
.addInstallVerifier(cmd -> {
Path path = rpmLicenseFile(cmd);
if (path != null) {
verifyLicenseFileInstalledRpm(path);
}
})
.run();
});
initLinuxLicenseVerifier(test.forTypes(PackageType.LINUX));
test.run();
}
public static void testLinuxLicenseInUsrTree() {
testLinuxLicenseInUsrTree("/usr");
}
public static void testLinuxLicenseInUsrTree2() {
testLinuxLicenseInUsrTree("/usr/local");
}
public static void testLinuxLicenseInUsrTree3() {
testLinuxLicenseInUsrTree("/usr/foo");
}
public static void testLinuxLicenseInUsrTree4() {
testLinuxLicenseInUsrTree("/usrbuz");
}
public static void testCustomDebianCopyright() {
@ -129,38 +129,78 @@ public class LicenseTest {
new CustomDebianCopyrightTest().withSubstitution(true).run();
}
private static Path rpmLicenseFile(JPackageCommand cmd) {
if (cmd.isPackageUnpacked("Not checking for rpm license file")) {
return null;
}
private static PackageTest initLinuxLicenseVerifier(PackageTest test) {
return test
.addBundleVerifier(cmd -> {
verifyLicenseFileInLinuxPackage(cmd, linuxLicenseFile(cmd));
})
.addInstallVerifier(cmd -> {
verifyLicenseFileInstalledLinux(cmd);
})
.addUninstallVerifier(cmd -> {
verifyLicenseFileNotInstalledLinux(linuxLicenseFile(cmd));
});
}
private static void testLinuxLicenseInUsrTree(String installDir) {
PackageTest test = new PackageTest()
.forTypes(PackageType.LINUX)
.configureHelloApp()
.addInitializer(cmd -> {
cmd.setFakeRuntime();
cmd.addArguments("--license-file", TKit.createRelativePathCopy(
LICENSE_FILE));
cmd.addArguments("--install-dir", installDir);
});
initLinuxLicenseVerifier(test);
test.run();
}
private static Path rpmLicenseFile(JPackageCommand cmd) {
final Path licenseRoot = Path.of(
new Executor()
.setExecutable("rpm")
.addArguments("--eval", "%{_defaultlicensedir}")
.executeAndGetFirstLineOfOutput());
final Path licensePath = licenseRoot.resolve(String.format("%s-%s",
LinuxHelper.getPackageName(cmd), cmd.version())).resolve(
LICENSE_FILE.getFileName());
return licensePath;
}
private static Path debLicenseFile(JPackageCommand cmd) {
Path installDir = cmd.appInstallationDirectory();
if (installDir.equals(Path.of("/")) || installDir.startsWith("/usr")) {
// Package is in '/usr' tree
return Path.of("/usr/share/doc/", LinuxHelper.getPackageName(cmd),
"copyright");
}
return installDir.resolve("share/doc/copyright");
}
private static Path linuxLicenseFile(JPackageCommand cmd) {
cmd.verifyIsOfType(PackageType.LINUX);
final Path licenseFile;
switch (cmd.packageType()) {
case LINUX_DEB:
return debLicenseFile(cmd);
licenseFile = debLicenseFile(cmd);
break;
case LINUX_RPM:
return rpmLicenseFile(cmd);
licenseFile = rpmLicenseFile(cmd);
break;
default:
return null;
throw new IllegalArgumentException();
}
}
private static Path debLicenseFile(JPackageCommand cmd) {
return cmd.appInstallationDirectory().resolve("share/doc/copyright");
return cmd.pathToUnpackedPackageFile(licenseFile);
}
private static void verifyLicenseFileInLinuxPackage(JPackageCommand cmd,
@ -199,6 +239,26 @@ public class LicenseTest {
licenseFile, LICENSE_FILE));
}
private static void verifyLicenseFileInstalledLinux(JPackageCommand cmd)
throws IOException {
final Path licenseFile = linuxLicenseFile(cmd);
TKit.assertReadableFileExists(licenseFile);
switch (cmd.packageType()) {
case LINUX_DEB:
verifyLicenseFileInstalledDebian(licenseFile);
break;
case LINUX_RPM:
verifyLicenseFileInstalledRpm(licenseFile);
break;
default:
throw new IllegalArgumentException();
}
}
private static void verifyLicenseFileNotInstalledLinux(Path licenseFile) {
TKit.assertPathExists(licenseFile.getParent(), false);
}
@ -266,7 +326,7 @@ public class LicenseTest {
licenseFileText());
})
.addInstallVerifier(cmd -> {
Path installedLicenseFile = debLicenseFile(cmd);
Path installedLicenseFile = linuxLicenseFile(cmd);
TKit.assertStringListEquals(expetedLicenseFileText(),
DEBIAN_COPYRIGT_FILE_STRIPPER.apply(Files.readAllLines(
installedLicenseFile)), String.format(

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -50,18 +50,53 @@ import jdk.jpackage.test.Annotations.Test;
* @library ../helpers
* @key jpackagePlatformPackage
* @build jdk.jpackage.test.*
* @comment Temporary disable for Linux and OSX until functionality implemented
* @comment Temporary disable for OSX until functionality implemented
* @requires (os.family != "mac")
* @requires (jpackage.test.SQETest == null)
* @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
* @compile RuntimePackageTest.java
* @run main/othervm/timeout=1400 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=RuntimePackageTest
*/
/*
* @test
* @summary jpackage with --runtime-image
* @library ../helpers
* @key jpackagePlatformPackage
* @build jdk.jpackage.test.*
* @comment Temporary disable for OSX until functionality implemented
* @requires (os.family != "mac")
* @requires (jpackage.test.SQETest != null)
* @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
* @compile RuntimePackageTest.java
* @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=RuntimePackageTest
* --jpt-run=RuntimePackageTest.test
*/
public class RuntimePackageTest {
@Test
public static void test() {
new PackageTest()
init(PackageType.NATIVE).run();
}
@Test
public static void testUsrInstallDir() {
init(PackageType.LINUX)
.addInitializer(cmd -> cmd.addArguments("--install-dir", "/usr"))
.run();
}
@Test
public static void testUsrInstallDir2() {
init(PackageType.LINUX)
.addInitializer(cmd -> cmd.addArguments("--install-dir", "/usr/lib/Java"))
.run();
}
private static PackageTest init(Set<PackageType> types) {
return new PackageTest()
.forTypes(types)
.addInitializer(cmd -> {
cmd.addArguments("--runtime-image", Optional.ofNullable(
JPackageCommand.DEFAULT_RUNTIME_IMAGE).orElse(Path.of(
@ -83,8 +118,7 @@ public class RuntimePackageTest {
assertFileListEmpty(srcRuntime, "Missing");
assertFileListEmpty(dstRuntime, "Unexpected");
})
.run();
});
}
private static Set<Path> listFiles(Path root) throws IOException {