Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions scripts/initializr/build.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
#!/bin/bash
set -e
MVNW="./mvnw"
RUN_TESTS_DEFAULT="true"

function should_run_tests {
if [ "$INITIALIZR_RUN_TESTS" == "" ]; then
[ "$RUN_TESTS_DEFAULT" == "true" ]
return
fi
[ "$INITIALIZR_RUN_TESTS" == "true" ]
}

function run_common_tests {
if should_run_tests; then
"$MVNW" "-pl" "common" "-am" "test" "-DskipTests=false" "-DfailIfNoTests=false" "-Dtest=GeneratorModelMatrixTest,GeneratorModelLocalizationPackagingTest" "-U" "-e"
fi
}

function mac_desktop {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=javase" "-Dcodename1.buildTarget=mac-os-x-desktop" "-U" "-e"
}
function windows_desktop {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=javase" "-Dcodename1.buildTarget=windows-desktop" "-U" "-e"
}
function windows_device {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=win" "-Dcodename1.buildTarget=windows-device" "-U" "-e"
}
Expand All @@ -19,33 +40,47 @@ function uwp {
"windows_device"
}
function javascript {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=javascript" "-Dcodename1.buildTarget=javascript" "-U" "-e"
}
function android {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=android" "-Dcodename1.buildTarget=android-device" "-U" "-e"
}
function xcode {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=ios" "-Dcodename1.buildTarget=ios-source" "-U" "-e"
}
function ios_source {
"xcode"
}
function android_source {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=android" "-Dcodename1.buildTarget=android-source" "-U" "-e"
}
function ios {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=ios" "-Dcodename1.buildTarget=ios-device" "-U" "-e"
}
function ios_release {
run_common_tests


"$MVNW" "package" "-DskipTests" "-Dcodename1.platform=ios" "-Dcodename1.buildTarget=ios-device-release" "-U" "-e"
}
function jar {
run_common_tests


"$MVNW" "-Pexecutable-jar" "package" "-Dcodename1.platform=javase" "-DskipTests" "-U" "-e"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,25 +90,30 @@ private void addLocalizationEntries(Map<String, byte[]> mergedEntries) throws IO
if (!isBareTemplate() || !options.includeLocalizationBundles) {
return;
}
addLocalizationEntry(mergedEntries, "messages.properties");
copySingleTextEntryToMap(
"common/src/main/resources/messages.properties",
readResourceToString("/messages.properties"),
"common/src/main/resources/messages_en.properties",
readRequiredResourceToString("/messages.properties"),
mergedEntries,
ZipEntryType.COMMON
);
for (ProjectOptions.PreviewLanguage language : ProjectOptions.PreviewLanguage.values()) {
if (language == ProjectOptions.PreviewLanguage.ENGLISH) {
continue;
}
copySingleTextEntryToMap(
"common/src/main/resources/messages_" + language.bundleSuffix + ".properties",
readResourceToString("/messages_" + language.bundleSuffix + ".properties"),
mergedEntries,
ZipEntryType.COMMON
);
addLocalizationEntry(mergedEntries, "messages_" + language.bundleSuffix + ".properties");
}
}

private void addLocalizationEntry(Map<String, byte[]> mergedEntries, String fileName) throws IOException {
copySingleTextEntryToMap(
"common/src/main/resources/" + fileName,
readRequiredResourceToString("/" + fileName),
mergedEntries,
ZipEntryType.COMMON
);
}

private void copyZipEntriesToMap(String zipResource, Map<String, byte[]> mergedEntries, ZipEntryType zipType) throws IOException {
try(ZipInputStream zis = new ZipInputStream(getResourceAsStream(zipResource))) {
ZipEntry entry = zis.getNextEntry();
Expand Down Expand Up @@ -216,7 +221,16 @@ private String injectJavaLocalizationBootstrap(String content) {
String method = "\n @Override\n"
+ " public void init(Object context) {\n"
+ " String language = L10NManager.getInstance().getLanguage();\n"
+ " if (language == null || language.length() == 0) {\n"
+ " language = \"en\";\n"
+ " }\n"
+ " Hashtable<String, String> bundle = Resources.getGlobalResources().getL10N(\"messages\", language);\n"
+ " if (bundle == null && language != null && language.indexOf('_') > 0) {\n"
+ " bundle = Resources.getGlobalResources().getL10N(\"messages\", language.substring(0, language.indexOf('_')));\n"
+ " }\n"
+ " if (bundle == null) {\n"
+ " bundle = Resources.getGlobalResources().getL10N(\"messages\", \"en\");\n"
+ " }\n"
+ " UIManager.getInstance().setBundle(bundle);\n"
+ " }\n\n";
int firstBrace = content.indexOf('{');
Expand All @@ -232,8 +246,17 @@ private String injectKotlinLocalizationBootstrap(String content) {
}
content = StringUtil.replaceAll(content, "import com.codename1.system.Lifecycle\n", "import com.codename1.system.Lifecycle\nimport com.codename1.l10n.L10NManager\nimport com.codename1.ui.plaf.UIManager\nimport com.codename1.ui.util.Resources\nimport java.util.Hashtable\n");
String method = "\n override fun init(context: Any?) {\n"
+ " val language = L10NManager.getInstance().language\n"
+ " val bundle: Hashtable<String, String>? = Resources.getGlobalResources().getL10N(\"messages\", language)\n"
+ " var language = L10NManager.getInstance().language\n"
+ " if (language == null || language.length == 0) {\n"
+ " language = \"en\"\n"
+ " }\n"
+ " var bundle: Hashtable<String, String>? = Resources.getGlobalResources().getL10N(\"messages\", language)\n"
+ " if (bundle == null && language != null && language.indexOf('_') > 0) {\n"
+ " bundle = Resources.getGlobalResources().getL10N(\"messages\", language.substring(0, language.indexOf('_')))\n"
+ " }\n"
+ " if (bundle == null) {\n"
+ " bundle = Resources.getGlobalResources().getL10N(\"messages\", \"en\")\n"
+ " }\n"
+ " UIManager.getInstance().setBundle(bundle)\n"
+ " }\n\n";
int firstBrace = content.indexOf('{');
Expand Down Expand Up @@ -462,6 +485,18 @@ private static String readResourceToString(String resourcePath) throws IOExcepti
}
}

static String readRequiredResourceToString(String resourcePath) throws IOException {
InputStream inputStream = getResourceAsStream(resourcePath);
if (inputStream == null) {
throw new IOException("Missing required resource " + resourcePath);
}
try {
return readToStringNoClose(inputStream);
} finally {
inputStream.close();
}
}

private static String readToStringNoClose(InputStream is) throws IOException {
return StringUtil.newString(readToBytesNoClose(is));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.codename1.components.ImageViewer;
import com.codename1.initializr.model.ProjectOptions;
import com.codename1.initializr.model.Template;
import com.codename1.io.Log;
import com.codename1.io.Properties;
import com.codename1.ui.Button;
import com.codename1.ui.Component;
Expand Down Expand Up @@ -100,28 +99,18 @@ private Hashtable<String, String> findBundle(ProjectOptions.PreviewLanguage lang
if (language == null) {
return null;
}
Resources resources = Resources.getGlobalResources();
if (resources != null) {
try {
Hashtable<String, String> exact = resources.getL10N("messages", language.bundleSuffix);
if (exact != null) {
return exact;
}
int split = language.bundleSuffix.indexOf('_');
if (split > 0) {
Hashtable<String, String> languageOnly = resources.getL10N("messages", language.bundleSuffix.substring(0, split));
if (languageOnly != null) {
return languageOnly;
}
}
} catch (RuntimeException err) {
Log.e(err);
}
}

String[] candidates = language.bundleSuffix.indexOf('_') > 0
? new String[]{"/messages_" + language.bundleSuffix + ".properties", "/messages_" + language.bundleSuffix.substring(0, language.bundleSuffix.indexOf('_')) + ".properties", "/messages.properties"}
: new String[]{"/messages_" + language.bundleSuffix + ".properties", "/messages.properties"};
? new String[]{
"/messages_" + language.bundleSuffix + ".properties",
"/messages_" + language.bundleSuffix.substring(0, language.bundleSuffix.indexOf('_')) + ".properties",
"/messages_en.properties",
"/messages.properties"
}
: new String[]{
"/messages_" + language.bundleSuffix + ".properties",
"/messages_en.properties",
"/messages.properties"
};

for (String path : candidates) {
Hashtable<String, String> loaded = loadBundleProperties(path);
Expand All @@ -146,8 +135,7 @@ private Hashtable<String, String> loadBundleProperties(String resourcePath) {
}
return out;
} catch (Exception err) {
Log.e(err);
return null;
throw new RuntimeException("Failed to load localization bundle " + resourcePath, err);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Hi\ World=Hi World
Hello\ World=Hello World
Hello\ Command=Hello Command
Hello\ Codename\ One=Hello Codename One
Welcome\ to\ Codename\ One=Welcome to Codename One
OK=OK
Side\ menu\ is\ not\ available\ in\ embedded\ preview\ mode.=Side menu is not available in embedded preview mode.
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package com.codename1.initializr.model;

import com.codename1.io.Util;
import com.codename1.testing.AbstractTest;
import net.sf.zipme.ZipEntry;
import net.sf.zipme.ZipInputStream;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;

public class GeneratorModelLocalizationPackagingTest extends AbstractTest {
@Override
public boolean runTest() throws Exception {
byte[] zip = createProjectZip();
Map<String, byte[]> entries = readZipEntries(zip);

File classesRoot = Files.createTempDirectory("cn1-localization-packaging").toFile();
try {
compileDisplayClass(classesRoot);
writeGeneratedLocalizationResources(entries, classesRoot);
assertResourcesLoadFromDisplayClass(classesRoot);
} finally {
Util.cleanup(classesRoot.getAbsolutePath());
}
return true;
}

private static byte[] createProjectZip() throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
GeneratorModel.create(
IDE.INTELLIJ,
Template.BAREBONES,
"PackagingProbeApp",
"com.example.packaging"
).writeProjectZip(output);
return output.toByteArray();
}

private static Map<String, byte[]> readZipEntries(byte[] zipData) throws IOException {
Map<String, byte[]> entries = new HashMap<String, byte[]>();
ByteArrayInputStream input = new ByteArrayInputStream(zipData);
ZipInputStream zis = new ZipInputStream(input);
try {
ZipEntry entry = zis.getNextEntry();
while (entry != null) {
if (!entry.isDirectory()) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Util.copyNoClose(zis, bos, 8192);
entries.put(entry.getName(), bos.toByteArray());
bos.close();
}
zis.closeEntry();
entry = zis.getNextEntry();
}
} finally {
zis.close();
input.close();
}
return entries;
}

private static void compileDisplayClass(File classesRoot) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
if (compiler == null) {
throw new IOException("JDK compiler is required to run packaging test");
}
File sourceRoot = new File(classesRoot, "src");
File packageDir = new File(sourceRoot, "com/example/packaging");
packageDir.mkdirs();

File javaFile = new File(packageDir, "DisplayClass.java");
String source = "package com.example.packaging; public class DisplayClass {}";
Files.write(javaFile.toPath(), source.getBytes(StandardCharsets.UTF_8));

StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
try {
fileManager.setLocation(StandardLocation.CLASS_OUTPUT, java.util.Collections.singletonList(classesRoot));
Boolean ok = compiler.getTask(null, fileManager, null, null, null,
fileManager.getJavaFileObjectsFromFiles(java.util.Collections.singletonList(javaFile))).call();
if (!Boolean.TRUE.equals(ok)) {
throw new IOException("Failed to compile display class for packaging test");
}
} finally {
fileManager.close();
Util.cleanup(sourceRoot.getAbsolutePath());
}
}

private static void writeGeneratedLocalizationResources(Map<String, byte[]> entries, File classesRoot) throws IOException {
writeResource(entries, classesRoot, "messages.properties");
writeResource(entries, classesRoot, "messages_en.properties");
for (ProjectOptions.PreviewLanguage language : ProjectOptions.PreviewLanguage.values()) {
if (language == ProjectOptions.PreviewLanguage.ENGLISH) {
continue;
}
writeResource(entries, classesRoot, "messages_" + language.bundleSuffix + ".properties");
}
}

private static void writeResource(Map<String, byte[]> entries, File classesRoot, String resourceName) throws IOException {
byte[] data = entries.get("common/src/main/resources/" + resourceName);
if (data == null) {
throw new IOException("Generated project is missing localization resource " + resourceName);
}
try (FileOutputStream fos = new FileOutputStream(new File(classesRoot, resourceName))) {
fos.write(data);
}
}

private void assertResourcesLoadFromDisplayClass(File classesRoot) throws Exception {
URLClassLoader loader = new URLClassLoader(new URL[]{classesRoot.toURI().toURL()}, null);
try {
Class<?> displayClass = Class.forName("com.example.packaging.DisplayClass", true, loader);
assertNotNull(displayClass.getResourceAsStream("/messages.properties"), "Default bundle should resolve from display class");
assertNotNull(displayClass.getResourceAsStream("/messages_en.properties"), "English bundle alias should resolve from display class");
for (ProjectOptions.PreviewLanguage language : ProjectOptions.PreviewLanguage.values()) {
if (language == ProjectOptions.PreviewLanguage.ENGLISH) {
continue;
}
String resource = "/messages_" + language.bundleSuffix + ".properties";
InputStream in = displayClass.getResourceAsStream(resource);
assertNotNull(in, "Bundle should resolve from display class: " + resource);
if (in != null) {
in.close();
}
}
} finally {
loader.close();
}
}
}
Loading
Loading