1 /* 2 * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jpackage.internal; 27 28 import java.io.File; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.nio.file.Files; 32 import java.nio.file.Path; 33 import java.nio.file.StandardCopyOption; 34 import java.text.MessageFormat; 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Objects; 39 import java.util.ResourceBundle; 40 41 import static jdk.jpackage.internal.StandardBundlerParam.*; 42 43 public class LinuxAppImageBuilder extends AbstractAppImageBuilder { 44 45 private static final ResourceBundle I18N = ResourceBundle.getBundle( 46 "jdk.jpackage.internal.resources.LinuxResources"); 47 48 private static final String LIBRARY_NAME = "libapplauncher.so"; 49 final static String DEFAULT_ICON = "java32.png"; 50 51 private final Path root; 52 private final Path appDir; 53 private final Path appModsDir; 54 private final Path runtimeDir; 55 private final Path binDir; 56 private final Path mdir; 57 58 public static final BundlerParamInfo<File> ICON_PNG = 59 new StandardBundlerParam<>( 60 "icon.png", 61 File.class, 62 params -> { 63 File f = ICON.fetchFrom(params); 64 if (f != null && !f.getName().toLowerCase().endsWith(".png")) { 65 Log.error(MessageFormat.format(I18N.getString( 66 "message.icon-not-png"), f)); 67 return null; 68 } 69 return f; 70 }, 71 (s, p) -> new File(s)); 72 73 public LinuxAppImageBuilder(Map<String, Object> params, Path imageOutDir) 74 throws IOException { 75 super(params, 76 imageOutDir.resolve(APP_NAME.fetchFrom(params) + "/runtime")); 77 78 Objects.requireNonNull(imageOutDir); 79 80 this.root = imageOutDir.resolve(APP_NAME.fetchFrom(params)); 81 this.appDir = root.resolve("app"); 82 this.appModsDir = appDir.resolve("mods"); 83 this.runtimeDir = root.resolve("runtime"); 84 this.binDir = root.resolve("bin"); 85 this.mdir = runtimeDir.resolve("lib"); 86 Files.createDirectories(appDir); 87 Files.createDirectories(runtimeDir); 88 } 89 90 public LinuxAppImageBuilder(String appName, Path imageOutDir) 91 throws IOException { 92 super(null, imageOutDir.resolve(appName)); 93 94 Objects.requireNonNull(imageOutDir); 95 96 this.root = imageOutDir.resolve(appName); 97 this.appDir = null; 98 this.appModsDir = null; 99 this.runtimeDir = null; 100 this.binDir = null; 101 this.mdir = null; 102 } 103 104 private void writeEntry(InputStream in, Path dstFile) throws IOException { 105 Files.createDirectories(dstFile.getParent()); 106 Files.copy(in, dstFile); 107 } 108 109 public static String getLauncherName(Map<String, ? super Object> params) { 110 return APP_NAME.fetchFrom(params); 111 } 112 113 public static String getLauncherCfgName( 114 Map<String, ? super Object> params) { 115 return "app" + File.separator + APP_NAME.fetchFrom(params) + ".cfg"; 116 } 117 118 @Override 119 public Path getAppDir() { 120 return appDir; 121 } 122 123 @Override 124 public Path getAppModsDir() { 125 return appModsDir; 126 } 127 128 @Override 129 public void prepareApplicationFiles(Map<String, ? super Object> params) 130 throws IOException { 131 Map<String, ? super Object> originalParams = new HashMap<>(params); 132 133 try { 134 IOUtils.writableOutputDir(root); 135 IOUtils.writableOutputDir(binDir); 136 } catch (PackagerException pe) { 137 throw new RuntimeException(pe); 138 } 139 140 // create the primary launcher 141 createLauncherForEntryPoint(params); 142 143 // Copy library to the launcher folder 144 try (InputStream is_lib = getResourceAsStream(LIBRARY_NAME)) { 145 writeEntry(is_lib, binDir.resolve(LIBRARY_NAME)); 146 } 147 148 // create the additional launchers, if any 149 List<Map<String, ? super Object>> entryPoints 150 = StandardBundlerParam.ADD_LAUNCHERS.fetchFrom(params); 151 for (Map<String, ? super Object> entryPoint : entryPoints) { 152 createLauncherForEntryPoint( 153 AddLauncherArguments.merge(originalParams, entryPoint)); 154 } 155 156 // Copy class path entries to Java folder 157 copyApplication(params); 158 159 // Copy icon to Resources folder 160 copyIcon(params); 161 } 162 163 @Override 164 public void prepareJreFiles(Map<String, ? super Object> params) 165 throws IOException {} 166 167 private void createLauncherForEntryPoint( 168 Map<String, ? super Object> params) throws IOException { 169 // Copy executable to Linux folder 170 Path executableFile = binDir.resolve(getLauncherName(params)); 171 try (InputStream is_launcher = 172 getResourceAsStream("jpackageapplauncher")) { 173 writeEntry(is_launcher, executableFile); 174 } 175 176 executableFile.toFile().setExecutable(true, false); 177 executableFile.toFile().setWritable(true, true); 178 179 writeCfgFile(params, root.resolve(getLauncherCfgName(params)).toFile()); 180 } 181 182 private void copyIcon(Map<String, ? super Object> params) 183 throws IOException { 184 185 File icon = ICON_PNG.fetchFrom(params); 186 File iconTarget = binDir.resolve(APP_NAME.fetchFrom(params) + ".png").toFile(); 187 188 InputStream in = locateResource( 189 iconTarget.getName(), 190 "icon", 191 DEFAULT_ICON, 192 icon, 193 VERBOSE.fetchFrom(params), 194 RESOURCE_DIR.fetchFrom(params)); 195 196 Files.copy(in, iconTarget.toPath(), StandardCopyOption.REPLACE_EXISTING); 197 } 198 199 private void copyApplication(Map<String, ? super Object> params) 200 throws IOException { 201 for (RelativeFileSet appResources : 202 APP_RESOURCES_LIST.fetchFrom(params)) { 203 if (appResources == null) { 204 throw new RuntimeException("Null app resources?"); 205 } 206 File srcdir = appResources.getBaseDirectory(); 207 for (String fname : appResources.getIncludedFiles()) { 208 copyEntry(appDir, srcdir, fname); 209 } 210 } 211 } 212 213 }