8374215: [macos] Clean and fix "lic_template.plist" to correctly work with multiple languages

Reviewed-by: asemenyuk
This commit is contained in:
Alexander Matveev 2026-01-15 03:53:53 +00:00
parent 2b1e11c254
commit 499b588202
9 changed files with 210 additions and 197 deletions

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2026, 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.
*/
package jdk.jpackage.internal;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.ResourceBundle;
import jdk.jpackage.internal.resources.ResourceLocator;
final class MacDmgLicense {
public static void prepareLicensePListFile(Path licenseFile, Path licensePListFile)
throws IOException {
byte[] licenseContentOriginal =
Files.readAllBytes(licenseFile);
String licenseInBase64 =
Base64.getEncoder().encodeToString(licenseContentOriginal);
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_LICENSE_TEXT", licenseInBase64);
data.put("STR_DATA_ENGLISH",
getSTRData("English", Locale.ENGLISH, "MacRoman"));
data.put("STR_DATA_GERMAN",
getSTRData("German", Locale.GERMAN, "MacRoman"));
data.put("STR_DATA_JAPANESE",
getSTRData("Japanese", Locale.JAPANESE, "Shift_JIS"));
data.put("STR_DATA_SIMPLIFIED_CHINESE",
getSTRData("Simplified Chinese", Locale.SIMPLIFIED_CHINESE, "GB2312"));
new OverridableResource(DEFAULT_LICENSE_PLIST, ResourceLocator.class)
.setCategory(I18N.getString("resource.license-setup"))
.setSubstitutionData(data)
.saveToFile(licensePListFile);
}
private static void writeSTRDataString(ByteArrayOutputStream bos,
String str, String charset) {
byte [] bytes = str.getBytes(Charset.forName(charset));
byte [] bytesLength = {(byte)bytes.length};
bos.writeBytes(bytesLength);
bos.writeBytes(bytes);
}
// Returns base64 decoded STR section data.
// Strings should be in following order:
// Language, message.dmg.license.button.agree,
// message.dmg.license.button.disagree, message.dmg.license.button.print
// message.dmg.license.button.save, message.dmg.license.message
// STR section data encoded:
// Number of strings in the list (unsigned 16-bit integer, big endian): 6
// A sequence of strings prefixed with string length (unsigned 8-bit integer)
// Note: Language should not be translated.
private static String getSTRData(String language, Locale locale, String charset) {
ResourceBundle bundle = ResourceBundle.getBundle(
"jdk.jpackage.internal.resources.MacResources", locale);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte [] numberOfStrings = {0x00, 0x06}; // Always 6
bos.writeBytes(numberOfStrings);
writeSTRDataString(bos, language, charset);
writeSTRDataString(bos, bundle.getString("message.dmg.license.button.agree"), charset);
writeSTRDataString(bos, bundle.getString("message.dmg.license.button.disagree"), charset);
writeSTRDataString(bos, bundle.getString("message.dmg.license.button.print"), charset);
writeSTRDataString(bos, bundle.getString("message.dmg.license.button.save"), charset);
writeSTRDataString(bos, bundle.getString("message.dmg.license.message"), charset);
return Base64.getEncoder().encodeToString(bos.toByteArray());
}
private static final String DEFAULT_LICENSE_PLIST = "lic_template.plist";
}

View File

@ -34,7 +34,6 @@ import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -105,7 +104,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir,
return env.configDir().resolve(pkg.app().name() + "-volume.icns");
}
Path licenseFile() {
Path licensePListFile() {
return env.configDir().resolve(pkg.app().name() + "-license.plist");
}
@ -175,26 +174,6 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir,
.saveToFile(dmgSetup);
}
private void prepareLicense() throws IOException {
final var licFile = pkg.licenseFile();
if (licFile.isEmpty()) {
return;
}
byte[] licenseContentOriginal =
Files.readAllBytes(licFile.orElseThrow());
String licenseInBase64 =
Base64.getEncoder().encodeToString(licenseContentOriginal);
Map<String, String> data = new HashMap<>();
data.put("APPLICATION_LICENSE_TEXT", licenseInBase64);
env.createResource(DEFAULT_LICENSE_PLIST)
.setCategory(I18N.getString("resource.license-setup"))
.setSubstitutionData(data)
.saveToFile(licenseFile());
}
private void prepareConfigFiles() throws IOException {
env.createResource(DEFAULT_BACKGROUND_IMAGE)
@ -206,7 +185,9 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir,
.setExternal(pkg.icon().orElse(null))
.saveToFile(volumeIcon());
prepareLicense();
if (pkg.licenseFile().isPresent()) {
MacDmgLicense.prepareLicensePListFile(pkg.licenseFile().get(), licensePListFile());
}
prepareDMGSetupScript();
}
@ -359,7 +340,7 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir,
"udifrez",
normalizedAbsolutePathString(finalDMG),
"-xml",
normalizedAbsolutePathString(licenseFile())
normalizedAbsolutePathString(licensePListFile())
).retry()
.setMaxAttemptsCount(10)
.setAttemptTimeout(3, TimeUnit.SECONDS)
@ -441,6 +422,4 @@ record MacDmgPackager(BuildEnv env, MacDmgPackage pkg, Path outputDir,
private static final String DEFAULT_BACKGROUND_IMAGE = "background_dmg.tiff";
private static final String DEFAULT_DMG_SETUP_SCRIPT = "DMGsetup.scpt";
private static final String TEMPLATE_BUNDLE_ICON = "JavaApp.icns";
private static final String DEFAULT_LICENSE_PLIST="lic_template.plist";
}

View File

@ -64,6 +64,11 @@ message.signing.pkg=Warning: For signing PKG, you might need to set "Always Trus
message.setfile.dmg=Setting custom icon on DMG file skipped because 'SetFile' utility was not found. Installing Xcode with Command Line Tools should resolve this issue.
message.codesign.failed.reason.app.content="codesign" failed and additional application content was supplied via the "--app-content" parameter. Probably the additional content broke the integrity of the application bundle and caused the failure. Ensure content supplied via the "--app-content" parameter does not break the integrity of the application bundle, or add it in the post-processing step.
message.codesign.failed.reason.xcode.tools=Possible reason for "codesign" failure is missing Xcode with command line developer tools. Install Xcode with command line developer tools to see if it resolves the problem.
message.dmg.license.button.agree=Agree
message.dmg.license.button.disagree=Disagree
message.dmg.license.button.print=Print
message.dmg.license.button.save=Save...
message.dmg.license.message=If you agree with the terms of this license, press "Agree" to install the software. If you do not agree, press "Disagree".
warning.unsigned.app.image=Warning: Using unsigned app-image to build signed {0}.
warning.per.user.app.image.signed=Warning: Support for per-user configuration of the installed application will not be supported due to missing "{0}" in predefined signed application image.
warning.non.standard.contents.sub.dir=Warning: The file name of the directory "{0}" specified for the --app-content option is not a standard subdirectory name in the "Contents" directory of the application bundle. The result application bundle may fail code signing and/or notarization.

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 2026, 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
@ -71,6 +71,11 @@ message.signing.pkg=Warnung: Zum Signieren von PKG müssen Sie möglicherweise m
message.setfile.dmg=Das Festlegen des benutzerdefinierten Symbols für die DMG-Datei wurde übersprungen, weil das Utility "SetFile" nicht gefunden wurde. Durch Installieren von Xcode mit Befehlszeilentools sollte dieses Problem behoben werden.
message.codesign.failed.reason.app.content="codesign" war nicht erfolgreich, und zusätzlicher Anwendungsinhalt wurde über den Parameter "--app-content" angegeben. Wahrscheinlich hat der zusätzliche Inhalt die Integrität des Anwendungs-Bundles beeinträchtigt und den Fehler verursacht. Stellen Sie sicher, das der über den Parameter "--app-content" angegebene Inhalt nicht die Integrität des Anwendungs-Bundles beeinträchtigt, oder fügen Sie ihn im Nachverarbeitungsschritt hinzu.
message.codesign.failed.reason.xcode.tools=Möglicher Grund für "codesign"-Fehler ist fehlender Xcode mit Befehlszeilen-Entwicklertools. Installieren Sie Xcode mit Befehlszeilen-Entwicklertools, und prüfen Sie, ob das Problem dadurch beseitigt wird.
message.dmg.license.button.agree=Akzeptieren
message.dmg.license.button.disagree=Ablehnen
message.dmg.license.button.print=Drucken
message.dmg.license.button.save=Sichern...
message.dmg.license.message=Klicken Sie in “Akzeptieren”, wenn Sie mit den Bestimmungen des Software-Lizenzvertrags einverstanden sind. Falls nicht, bitte “Ablehnen” anklicken. Sie können die Software nur installieren, wenn Sie “Akzeptieren” angeklickt haben.
warning.unsigned.app.image=Warnung: Nicht signiertes app-image wird zum Erstellen von signiertem {0} verwendet.
warning.per.user.app.image.signed=Warnung: Konfiguration der installierten Anwendung pro Benutzer wird nicht unterstützt, da "{0}" im vordefinierten signierten Anwendungsimage fehlt.
warning.non.standard.contents.sub.dir=Warnung: Der Dateiname des Verzeichnisses "{0}", das für die Option --app-content angegeben wurde, ist kein Standardunterverzeichnisname im Verzeichnis "Contents" des Anwendungs-Bundles. Möglicherweise verläuft die Codesignierung und/oder Notarisierung im Ergebnisanwendungs-Bundle nicht erfolgreich.

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 2026, 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
@ -71,6 +71,11 @@ message.signing.pkg=警告: PKGへの署名の場合、「キーチェーン・
message.setfile.dmg='SetFile'ユーティリティが見つからないため、DMGファイルでのカスタム・アイコンの設定がスキップされました。Xcodeとコマンド・ライン・ツールをインストールすると、この問題は解決されます。
message.codesign.failed.reason.app.content="codesign"が失敗したため、追加のアプリケーション・コンテンツが、"--app-content"パラメータを介して提供されました。追加のコンテンツにより、アプリケーション・バンドルの整合性が損われ、失敗の原因になった可能性があります。"--app-content"パラメータを介して提供されたコンテンツによって、アプリケーション・バンドルの整合性が損われていないことを確認するか、処理後のステップで追加してください。
message.codesign.failed.reason.xcode.tools="codesign"失敗の考えられる理由は、Xcodeとコマンドライン・デベロッパ・ツールの欠落です。Xcodeとコマンドライン・デベロッパ・ツールをインストールして、問題が解決されるかを確認してください。
message.dmg.license.button.agree=同意します
message.dmg.license.button.disagree=同意しません
message.dmg.license.button.print=印刷する
message.dmg.license.button.save=保存...
message.dmg.license.message=本ソフトウエア使用許諾契約の条件に同意される場合には、ソフトウエアをインストールするために「同意します」を押してください。 同意されない場合には、「同意しません」を押してください。
warning.unsigned.app.image=警告: 署名されていないapp-imageを使用して署名された{0}を作成します。
warning.per.user.app.image.signed=警告: 事前定義済の署名付きアプリケーション・イメージに"{0}"がないため、インストール済アプリケーションのユーザーごとの構成はサポートされません。
warning.non.standard.contents.sub.dir=警告: --app-contentオプションに指定されたディレクトリ"{0}"のファイル名が、アプリケーション・バンドルの"Contents"ディレクトリ内の標準サブディレクトリ名ではありません。結果アプリケーション・バンドルは、コード署名および/または公証に失敗することがあります。

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 2026, 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
@ -71,6 +71,11 @@ message.signing.pkg=警告:要对 PKG 进行签名,可能需要使用“密
message.setfile.dmg=由于未找到 'SetFile' 实用程序,跳过了针对 DMG 文件设置定制图标的操作。安装带命令行工具的 Xcode 应能解决此问题。
message.codesign.failed.reason.app.content="codesign" 失败,并通过 "--app-content" 参数提供了附加应用程序内容。可能是附加内容破坏了应用程序包的完整性,导致了故障。请确保通过 "--app-content" 参数提供的内容不会破坏应用程序包的完整性,或者在后处理步骤中添加该内容。
message.codesign.failed.reason.xcode.tools="codesign" 失败可能是因为缺少带命令行开发人员工具的 Xcode。请安装带命令行开发人员工具的 Xcode看看是否可以解决问题。
message.dmg.license.button.agree=同意
message.dmg.license.button.disagree=不同意
message.dmg.license.button.print=打印
message.dmg.license.button.save=存储...
message.dmg.license.message=如果您同意本许可协议的条款,请按“同意”来安装此软件。如果您不同意,请按“不同意”。
warning.unsigned.app.image=警告:使用未签名的 app-image 生成已签名的 {0}。
warning.per.user.app.image.signed=警告:由于预定义的已签名应用程序映像中缺少 "{0}",不支持对已安装应用程序的每用户配置提供支持。
warning.non.standard.contents.sub.dir=警告:为 --app-content 选项指定的目录 "{0}" 的文件名不是应用程序包的 "Contents" 目录中的标准子目录名称。结果应用程序包可能会使代码签名和/或公证失败。

View File

@ -8,7 +8,9 @@
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAAAAgAAAAAAAAAAAAQAAA==</data>
<data>
AAAABAAAAAAAAAADAAEAAAAOAAIAAQA0AAMAAQ==
</data>
<key>ID</key>
<string>5000</string>
<key>Name</key>
@ -21,17 +23,22 @@
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYPRW5nbGlzaCBkZWZhdWx0BUFncmVlCERpc2FncmVlBVByaW50B1NhdmUuLi56SWYgeW91IGFncmVlIHdpdGggdGhlIHRlcm1zIG9mIHRoaXMgbGljZW5zZSwgY2xpY2sgIkFncmVlIiB0byBhY2Nlc3MgdGhlIHNvZnR3YXJlLiAgSWYgeW91IGRvIG5vdCBhZ3JlZSwgcHJlc3MgIkRpc2FncmVlLiI=</data>
<data>
STR_DATA_ENGLISH
</data>
<key>ID</key>
<string>5000</string>
<!-- Note: Values if "Name" keys should not be localized for all languages. It is internal use only. -->
<key>Name</key>
<string>English buttons</string>
<string>English (United States)</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYHRGV1dHNjaAtBa3plcHRpZXJlbghBYmxlaG5lbgdEcnVja2VuClNpY2hlcm4uLi7nS2xpY2tlbiBTaWUgaW4g0kFremVwdGllcmVu0ywgd2VubiBTaWUgbWl0IGRlbiBCZXN0aW1tdW5nZW4gZGVzIFNvZnR3YXJlLUxpemVuenZlcnRyYWdzIGVpbnZlcnN0YW5kZW4gc2luZC4gRmFsbHMgbmljaHQsIGJpdHRlINJBYmxlaG5lbtMgYW5rbGlja2VuLiBTaWUga5pubmVuIGRpZSBTb2Z0d2FyZSBudXIgaW5zdGFsbGllcmVuLCB3ZW5uIFNpZSDSQWt6ZXB0aWVyZW7TIGFuZ2VrbGlja3QgaGFiZW4u</data>
<data>
STR_DATA_GERMAN
</data>
<key>ID</key>
<string>5001</string>
<key>Name</key>
@ -41,151 +48,25 @@
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYHRW5nbGlzaAVBZ3JlZQhEaXNhZ3JlZQVQcmludAdTYXZlLi4ue0lmIHlvdSBhZ3JlZSB3aXRoIHRoZSB0ZXJtcyBvZiB0aGlzIGxpY2Vuc2UsIHByZXNzICJBZ3JlZSIgdG8gaW5zdGFsbCB0aGUgc29mdHdhcmUuICBJZiB5b3UgZG8gbm90IGFncmVlLCBwcmVzcyAiRGlzYWdyZWUiLg==</data>
<data>
STR_DATA_JAPANESE
</data>
<key>ID</key>
<string>5002</string>
<key>Name</key>
<string>English</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYHRXNwYZZvbAdBY2VwdGFyCk5vIGFjZXB0YXIISW1wcmltaXIKR3VhcmRhci4uLsBTaSBlc3SHIGRlIGFjdWVyZG8gY29uIGxvcyB0jnJtaW5vcyBkZSBlc3RhIGxpY2VuY2lhLCBwdWxzZSAiQWNlcHRhciIgcGFyYSBpbnN0YWxhciBlbCBzb2Z0d2FyZS4gRW4gZWwgc3VwdWVzdG8gZGUgcXVlIG5vIGVzdI4gZGUgYWN1ZXJkbyBjb24gbG9zIHSOcm1pbm9zIGRlIGVzdGEgbGljZW5jaWEsIHB1bHNlICJObyBhY2VwdGFyLiI=</data>
<key>ID</key>
<string>5003</string>
<key>Name</key>
<string>Spanish</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYIRnJhbo1haXMIQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4=</data>
<key>ID</key>
<string>5004</string>
<key>Name</key>
<string>French</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYISXRhbGlhbm8HQWNjZXR0bwdSaWZpdXRvBlN0YW1wYQtSZWdpc3RyYS4uLn9TZSBhY2NldHRpIGxlIGNvbmRpemlvbmkgZGkgcXVlc3RhIGxpY2VuemEsIGZhaSBjbGljIHN1ICJBY2NldHRvIiBwZXIgaW5zdGFsbGFyZSBpbCBzb2Z0d2FyZS4gQWx0cmltZW50aSBmYWkgY2xpYyBzdSAiUmlmaXV0byIu</data>
<key>ID</key>
<string>5005</string>
<key>Name</key>
<string>Italian</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYISmFwYW5lc2UKk6+I04K1gtyCtwyTr4jTgrWC3IK5gvEIiPON/IK3gukHlduRti4uLrSWe4Ncg3SDZ4NFg0eDQY5nl3CLlpH4jF+W8YLMj/CMj4LJk6+I04KzguqC6Y/qjYeCyYLNgUGDXIN0g2eDRYNHg0GC8INDg5ODWINngVuDi4K3gumCvYLfgsmBdZOviNOCtYLcgreBdoLwiZ+CtYLEgq2CvoKzgqKBQoFAk6+I04KzguqCyIKij+qNh4LJgs2BQYF1k6+I04K1gtyCuYLxgXaC8ImfgrWCxIKtgr6Cs4KigUI=</data>
<key>ID</key>
<string>5006</string>
<key>Name</key>
<string>Japanese</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYKTmVkZXJsYW5kcwJKYQNOZWUFUHJpbnQJQmV3YWFyLi4upEluZGllbiB1IGFra29vcmQgZ2FhdCBtZXQgZGUgdm9vcndhYXJkZW4gdmFuIGRlemUgbGljZW50aWUsIGt1bnQgdSBvcCAnSmEnIGtsaWtrZW4gb20gZGUgcHJvZ3JhbW1hdHV1ciB0ZSBpbnN0YWxsZXJlbi4gSW5kaWVuIHUgbmlldCBha2tvb3JkIGdhYXQsIGtsaWt0IHUgb3AgJ05lZScu</data>
<data>
STR_DATA_SIMPLIFIED_CHINESE
</data>
<key>ID</key>
<string>5007</string>
<string>5003</string>
<key>Name</key>
<string>Dutch</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYGU3ZlbnNrCEdvZGuKbm5zBkF2YppqcwhTa3JpdiB1dAhTcGFyYS4uLpNPbSBEdSBnb2Rrim5uZXIgbGljZW5zdmlsbGtvcmVuIGtsaWNrYSBwjCAiR29ka4pubnMiIGaaciBhdHQgaW5zdGFsbGVyYSBwcm9ncmFtcHJvZHVrdGVuLiBPbSBEdSBpbnRlIGdvZGuKbm5lciBsaWNlbnN2aWxsa29yZW4sIGtsaWNrYSBwjCAiQXZimmpzIi4=</data>
<key>ID</key>
<string>5008</string>
<key>Name</key>
<string>Swedish</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYRUG9ydHVndZBzLCBCcmFzaWwJQ29uY29yZGFyCURpc2NvcmRhcghJbXByaW1pcglTYWx2YXIuLi6MU2UgZXN0hyBkZSBhY29yZG8gY29tIG9zIHRlcm1vcyBkZXN0YSBsaWNlbo1hLCBwcmVzc2lvbmUgIkNvbmNvcmRhciIgcGFyYSBpbnN0YWxhciBvIHNvZnR3YXJlLiBTZSBui28gZXN0hyBkZSBhY29yZG8sIHByZXNzaW9uZSAiRGlzY29yZGFyIi4=</data>
<key>ID</key>
<string>5009</string>
<key>Name</key>
<string>Brazilian Portuguese</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYSU2ltcGxpZmllZCBDaGluZXNlBM2s0uIGsrvNrNLiBLTy06EGtOa0oqGtVMjnufvE+s2s0uKxvtDtv8nQrdLptcTM9b/uo6zH67C0obDNrNLiobHAtLCy17C0y8jtvP6ho8jnufvE+rK7zazS4qOsx+uwtKGwsrvNrNLiobGhow==</data>
<key>ID</key>
<string>5010</string>
<key>Name</key>
<string>Simplified Chinese</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYTVHJhZGl0aW9uYWwgQ2hpbmVzZQSmULdOBqSjplC3TgSmQ6ZMBsB4pnOhS1CmcKpHsXqmULdOpbuzXKVpw9K4zKq6sfi02qFBvdCr9qGnplC3TqGopUimd7jLs27F6aFDpnCqR6SjplC3TqFBvdCr9qGnpKOmULdOoaihQw==</data>
<key>ID</key>
<string>5011</string>
<key>Name</key>
<string>Traditional Chinese</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYFRGFuc2sERW5pZwVVZW5pZwdVZHNrcml2CkFya2l2ZXIuLi6YSHZpcyBkdSBhY2NlcHRlcmVyIGJldGluZ2Vsc2VybmUgaSBsaWNlbnNhZnRhbGVuLCBza2FsIGR1IGtsaWtrZSBwjCDSRW5pZ9MgZm9yIGF0IGluc3RhbGxlcmUgc29mdHdhcmVuLiBLbGlrIHCMINJVZW5pZ9MgZm9yIGF0IGFubnVsbGVyZSBpbnN0YWxsZXJpbmdlbi4=</data>
<key>ID</key>
<string>5012</string>
<key>Name</key>
<string>Danish</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYFU3VvbWkISHl2imtzeW4KRW4gaHl2imtzeQdUdWxvc3RhCVRhbGxlbm5hyW9IeXaKa3N5IGxpc2Vuc3Npc29waW11a3NlbiBlaGRvdCBvc29pdHRhbWFsbGEg1Uh5doprc3nVLiBKb3MgZXQgaHl2imtzeSBzb3BpbXVrc2VuIGVodG9qYSwgb3NvaXRhINVFbiBoeXaKa3N51S4=</data>
<key>ID</key>
<string>5013</string>
<key>Name</key>
<string>Finnish</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYRRnJhbo1haXMgY2FuYWRpZW4IQWNjZXB0ZXIHUmVmdXNlcghJbXByaW1lcg5FbnJlZ2lzdHJlci4uLrpTaSB2b3VzIGFjY2VwdGV6IGxlcyB0ZXJtZXMgZGUgbGEgcHKOc2VudGUgbGljZW5jZSwgY2xpcXVleiBzdXIgIkFjY2VwdGVyIiBhZmluIGQnaW5zdGFsbGVyIGxlIGxvZ2ljaWVsLiBTaSB2b3VzIG4nkHRlcyBwYXMgZCdhY2NvcmQgYXZlYyBsZXMgdGVybWVzIGRlIGxhIGxpY2VuY2UsIGNsaXF1ZXogc3VyICJSZWZ1c2VyIi4=</data>
<key>ID</key>
<string>5014</string>
<key>Name</key>
<string>French Canadian</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYGS29yZWFuBLW/wMcJtb/AxyC+yMfUBsfBuLDGrgfA+sDlLi4ufrvnv+sgsOi+4LytwMcgs7u/67+hILW/wMfHz7jpLCAitb/AxyIgtNzD37imILStt68gvNLHwcauv/6+7rimILyzxKHHz73KvcO/wC4gtb/Ax8fPwfYgvsq0wrTZuOksICK1v8DHIL7Ix9QiILTcw9+4piC0qbijvcq9w7/ALg==</data>
<key>ID</key>
<string>5015</string>
<key>Name</key>
<string>Korean</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAYFTm9yc2sERW5pZwlJa2tlIGVuaWcIU2tyaXYgdXQKQXJraXZlci4uLqNIdmlzIERlIGVyIGVuaWcgaSBiZXN0ZW1tZWxzZW5lIGkgZGVubmUgbGlzZW5zYXZ0YWxlbiwga2xpa2tlciBEZSBwjCAiRW5pZyIta25hcHBlbiBmb3IgjCBpbnN0YWxsZXJlIHByb2dyYW12YXJlbi4gSHZpcyBEZSBpa2tlIGVyIGVuaWcsIGtsaWtrZXIgRGUgcIwgIklra2UgZW5pZyIu</data>
<key>ID</key>
<string>5016</string>
<key>Name</key>
<string>Norwegian</string>
<string>Chinese (Simplified)</string>
</dict>
</array>
<key>TEXT</key>
@ -194,50 +75,49 @@
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>APPLICATION_LICENSE_TEXT</data>
<data>
APPLICATION_LICENSE_TEXT
</data>
<key>ID</key>
<string>5000</string>
<key>Name</key>
<string>English SLA</string>
<string>English (United States) SLA</string>
</dict>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>
APPLICATION_LICENSE_TEXT
</data>
<key>ID</key>
<string>5001</string>
<key>Name</key>
<string>German SLA</string>
</dict>
</array>
<key>TMPL</key>
<array>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>E0RlZmF1bHQgTGFuZ3VhZ2UgSUREV1JEBUNvdW50T0NOVAQqKioqTFNUQwtzeXMgbGFuZyBJRERXUkQebG9jYWwgcmVzIElEIChvZmZzZXQgZnJvbSA1MDAwRFdSRBAyLWJ5dGUgbGFuZ3VhZ2U/RFdSRAQqKioqTFNURQ==</data>
<data>
APPLICATION_LICENSE_TEXT
</data>
<key>ID</key>
<string>128</string>
<string>5002</string>
<key>Name</key>
<string>LPic</string>
<string>Japanese SLA</string>
</dict>
</array>
<key>plst</key>
<array>
<dict>
<key>Attributes</key>
<string>0x0050</string>
<key>Data</key>
<data>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</data>
<key>ID</key>
<string>0</string>
<key>Name</key>
<string></string>
</dict>
</array>
<key>styl</key>
<array>
<dict>
<key>Attributes</key>
<string>0x0000</string>
<key>Data</key>
<data>AAMAAAAAAAwACQAUAAAAAAAAAAAAAAAAACcADAAJABQBAAAAAAAAAAAAAAAAKgAMAAkAFAAAAAAAAAAAAAA=</data>
<data>
APPLICATION_LICENSE_TEXT
</data>
<key>ID</key>
<string>5000</string>
<string>5003</string>
<key>Name</key>
<string>English SLA</string>
<string>Chinese (Simplified) SLA</string>
</dict>
</array>
</dict>

View File

@ -183,12 +183,12 @@ public final class Executor extends CommandArguments<Executor> {
return commandOutputControl.charset();
}
Executor storeOutputInFiles(boolean v) {
public Executor storeOutputInFiles(boolean v) {
commandOutputControl.storeOutputInFiles(v);
return this;
}
Executor storeOutputInFiles() {
public Executor storeOutputInFiles() {
return storeOutputInFiles(true);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, 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
@ -56,6 +56,9 @@ import jdk.jpackage.test.TKit;
*
* Mac:
*
* For DMG license should be displayed on command line when "hdiutil attach"
* is called.
*
* Windows
*
* Installer should display license text matching contents of the license file
@ -96,6 +99,7 @@ public class LicenseTest {
LICENSE_FILE));
});
initMacDmgLicenseVerifier(test.forTypes(PackageType.MAC_DMG));
initLinuxLicenseVerifier(test.forTypes(PackageType.LINUX));
test.run();
@ -131,6 +135,33 @@ public class LicenseTest {
new CustomDebianCopyrightTest().withSubstitution(true).run();
}
private static PackageTest initMacDmgLicenseVerifier(PackageTest test) {
return test
.addBundleVerifier(cmd -> {
verifyLicenseFileInDMGPackage(cmd);
});
}
private static void verifyLicenseFileInDMGPackage(JPackageCommand cmd)
throws IOException {
// DMG should have license, so attach with "no", since we only need license.
// With "no" attach will be canceled.
final var attachExec = Executor.of("sh", "-c", String.join(" ",
"no",
"|",
"/usr/bin/hdiutil",
"attach",
JPackageCommand.escapeAndJoin(cmd.outputBundle().toString())
)).saveOutput().storeOutputInFiles();
// Expected exit code is 1, since we canceling license.
final var attachResult = attachExec.executeAndRepeatUntilExitCode(1, 10, 6);
TKit.assertStringListEquals(Files.readAllLines(LICENSE_FILE),
attachResult.stdout(), String.format(
"Check output of \"hdiutil attach\" has the same license as contents of source license file [%s]",
LICENSE_FILE));
}
private static PackageTest initLinuxLicenseVerifier(PackageTest test) {
return test
.addBundleVerifier(cmd -> {