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.incubator.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.text.MessageFormat; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 import static jdk.incubator.jpackage.internal.OverridableResource.createResource; 38 39 import static jdk.incubator.jpackage.internal.StandardBundlerParam.*; 40 41 public class LinuxAppImageBuilder extends AbstractAppImageBuilder { 42 43 private static final String LIBRARY_NAME = "libapplauncher.so"; 44 final static String DEFAULT_ICON = "java32.png"; 45 46 private final ApplicationLayout appLayout; 47 48 public static final BundlerParamInfo<File> ICON_PNG = 49 new StandardBundlerParam<>( 50 "icon.png", 51 File.class, 52 params -> { 53 File f = ICON.fetchFrom(params); 54 if (f != null && !f.getName().toLowerCase().endsWith(".png")) { 55 Log.error(MessageFormat.format(I18N.getString( 56 "message.icon-not-png"), f)); 57 return null; 58 } 59 return f; 60 }, 61 (s, p) -> new File(s)); 62 63 private static ApplicationLayout createAppLayout(Map<String, Object> params, 64 Path imageOutDir) { 65 return ApplicationLayout.linuxAppImage().resolveAt( 66 imageOutDir.resolve(APP_NAME.fetchFrom(params))); 67 } 68 69 public LinuxAppImageBuilder(Map<String, Object> params, Path imageOutDir) 70 throws IOException { 71 super(params, createAppLayout(params, imageOutDir).runtimeDirectory()); 72 73 appLayout = createAppLayout(params, imageOutDir); 74 } 75 76 private void writeEntry(InputStream in, Path dstFile) throws IOException { 77 Files.createDirectories(dstFile.getParent()); 78 Files.copy(in, dstFile); 79 } 80 81 public static String getLauncherName(Map<String, ? super Object> params) { 82 return APP_NAME.fetchFrom(params); 83 } 84 85 private Path getLauncherCfgPath(Map<String, ? super Object> params) { 86 return appLayout.appDirectory().resolve( 87 APP_NAME.fetchFrom(params) + ".cfg"); 88 } 89 90 @Override 91 public Path getAppDir() { 92 return appLayout.appDirectory(); 93 } 94 95 @Override 96 public Path getAppModsDir() { 97 return appLayout.appModsDirectory(); 98 } 99 100 @Override 101 protected String getCfgAppDir() { 102 return Path.of("$ROOTDIR").resolve( 103 ApplicationLayout.linuxAppImage().appDirectory()).toString() 104 + File.separator; 105 } 106 107 @Override 108 protected String getCfgRuntimeDir() { 109 return Path.of("$ROOTDIR").resolve( 110 ApplicationLayout.linuxAppImage().runtimeDirectory()).toString(); 111 } 112 113 @Override 114 public void prepareApplicationFiles(Map<String, ? super Object> params) 115 throws IOException { 116 Map<String, ? super Object> originalParams = new HashMap<>(params); 117 118 appLayout.roots().stream().forEach(dir -> { 119 try { 120 IOUtils.writableOutputDir(dir); 121 } catch (PackagerException pe) { 122 throw new RuntimeException(pe); 123 } 124 }); 125 126 // create the primary launcher 127 createLauncherForEntryPoint(params); 128 129 // Copy library to the launcher folder 130 try (InputStream is_lib = getResourceAsStream(LIBRARY_NAME)) { 131 writeEntry(is_lib, appLayout.dllDirectory().resolve(LIBRARY_NAME)); 132 } 133 134 // create the additional launchers, if any 135 List<Map<String, ? super Object>> entryPoints 136 = StandardBundlerParam.ADD_LAUNCHERS.fetchFrom(params); 137 for (Map<String, ? super Object> entryPoint : entryPoints) { 138 createLauncherForEntryPoint( 139 AddLauncherArguments.merge(originalParams, entryPoint)); 140 } 141 142 // Copy class path entries to Java folder 143 copyApplication(params); 144 145 // Copy icon to Resources folder 146 copyIcon(params); 147 } 148 149 @Override 150 public void prepareJreFiles(Map<String, ? super Object> params) 151 throws IOException {} 152 153 private void createLauncherForEntryPoint( 154 Map<String, ? super Object> params) throws IOException { 155 // Copy executable to launchers folder 156 Path executableFile = appLayout.launchersDirectory().resolve(getLauncherName(params)); 157 try (InputStream is_launcher = 158 getResourceAsStream("jpackageapplauncher")) { 159 writeEntry(is_launcher, executableFile); 160 } 161 162 executableFile.toFile().setExecutable(true, false); 163 executableFile.toFile().setWritable(true, true); 164 165 writeCfgFile(params, getLauncherCfgPath(params).toFile()); 166 } 167 168 private void copyIcon(Map<String, ? super Object> params) 169 throws IOException { 170 171 Path iconTarget = appLayout.destktopIntegrationDirectory().resolve( 172 APP_NAME.fetchFrom(params) + IOUtils.getSuffix(Path.of( 173 DEFAULT_ICON))); 174 175 createResource(DEFAULT_ICON, params) 176 .setCategory("icon") 177 .setExternal(ICON_PNG.fetchFrom(params)) 178 .saveToFile(iconTarget); 179 } 180 181 private void copyApplication(Map<String, ? super Object> params) 182 throws IOException { 183 for (RelativeFileSet appResources : 184 APP_RESOURCES_LIST.fetchFrom(params)) { 185 if (appResources == null) { 186 throw new RuntimeException("Null app resources?"); 187 } 188 File srcdir = appResources.getBaseDirectory(); 189 for (String fname : appResources.getIncludedFiles()) { 190 copyEntry(appLayout.appDirectory(), srcdir, fname); 191 } 192 } 193 } 194 195 }