Skip to content

Commit 22fef0a

Browse files
committed
8347300: Don't exclude the "PATH" var from the environment when running app launchers in jpackage tests
Reviewed-by: mbaesken Backport-of: 8374d1f6fff541bef426b668978c31186405089b
1 parent c9f4ceb commit 22fef0a

File tree

10 files changed

+295
-82
lines changed

10 files changed

+295
-82
lines changed
Lines changed: 92 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,53 +25,109 @@
2525
import java.io.IOException;
2626
import java.nio.file.Files;
2727
import java.nio.file.Path;
28+
import java.util.ArrayList;
2829
import java.util.Collections;
29-
import java.util.HashMap;
30+
import java.util.List;
3031
import java.util.Map;
3132
import java.util.Objects;
3233
import java.util.Optional;
3334
import java.util.regex.Matcher;
3435
import java.util.regex.Pattern;
36+
import java.util.stream.Stream;
3537

3638

3739
public final class CfgFile {
38-
public String getValue(String section, String key) {
39-
Objects.requireNonNull(section);
40-
Objects.requireNonNull(key);
40+
public String getValue(String sectionName, String key) {
41+
var section = getSection(sectionName);
42+
TKit.assertTrue(section != null, String.format(
43+
"Check section [%s] is found in [%s] cfg file", sectionName, id));
4144

42-
Map<String, String> entries = data.get(section);
43-
TKit.assertTrue(entries != null, String.format(
44-
"Check section [%s] is found in [%s] cfg file", section, id));
45-
46-
String value = entries.get(key);
45+
String value = section.getValue(key);
4746
TKit.assertNotNull(value, String.format(
4847
"Check key [%s] is found in [%s] section of [%s] cfg file", key,
49-
section, id));
48+
sectionName, id));
5049

5150
return value;
5251
}
5352

54-
private CfgFile(Map<String, Map<String, String>> data, String id) {
53+
public String getValueUnchecked(String sectionName, String key) {
54+
var section = getSection(sectionName);
55+
if (section != null) {
56+
return section.getValue(key);
57+
} else {
58+
return null;
59+
}
60+
}
61+
62+
public void addValue(String sectionName, String key, String value) {
63+
var section = getSection(sectionName);
64+
if (section == null) {
65+
section = new Section(sectionName, new ArrayList<>());
66+
data.add(section);
67+
}
68+
section.data.add(Map.entry(key, value));
69+
}
70+
71+
public CfgFile() {
72+
this(new ArrayList<>(), "*");
73+
}
74+
75+
public static CfgFile combine(CfgFile base, CfgFile mods) {
76+
var cfgFile = new CfgFile(new ArrayList<>(), "*");
77+
for (var src : List.of(base, mods)) {
78+
for (var section : src.data) {
79+
for (var kvp : section.data) {
80+
cfgFile.addValue(section.name, kvp.getKey(), kvp.getValue());
81+
}
82+
}
83+
}
84+
return cfgFile;
85+
}
86+
87+
private CfgFile(List<Section> data, String id) {
5588
this.data = data;
5689
this.id = id;
5790
}
5891

59-
public static CfgFile readFromFile(Path path) throws IOException {
92+
public void save(Path path) {
93+
var lines = data.stream().flatMap(section -> {
94+
return Stream.concat(
95+
Stream.of(String.format("[%s]", section.name)),
96+
section.data.stream().map(kvp -> {
97+
return String.format("%s=%s", kvp.getKey(), kvp.getValue());
98+
}));
99+
});
100+
TKit.createTextFile(path, lines);
101+
}
102+
103+
private Section getSection(String name) {
104+
Objects.requireNonNull(name);
105+
for (int i = data.size()-1; i >=0; i--) {
106+
var section = data.get(i);
107+
if (name.equals(section.name)) {
108+
return section;
109+
}
110+
}
111+
return null;
112+
}
113+
114+
public static CfgFile load(Path path) throws IOException {
60115
TKit.trace(String.format("Read [%s] jpackage cfg file", path));
61116

62117
final Pattern sectionBeginRegex = Pattern.compile( "\\s*\\[([^]]*)\\]\\s*");
63118
final Pattern keyRegex = Pattern.compile( "\\s*([^=]*)=(.*)" );
64119

65-
Map<String, Map<String, String>> result = new HashMap<>();
120+
List<Section> sections = new ArrayList<>();
66121

67122
String currentSectionName = null;
68-
Map<String, String> currentSection = new HashMap<>();
123+
List<Map.Entry<String, String>> currentSection = new ArrayList<>();
69124
for (String line : Files.readAllLines(path)) {
70125
Matcher matcher = sectionBeginRegex.matcher(line);
71126
if (matcher.find()) {
72127
if (currentSectionName != null) {
73-
result.put(currentSectionName, Collections.unmodifiableMap(
74-
new HashMap<>(currentSection)));
128+
sections.add(new Section(currentSectionName,
129+
Collections.unmodifiableList(new ArrayList<>(
130+
currentSection))));
75131
}
76132
currentSectionName = matcher.group(1);
77133
currentSection.clear();
@@ -80,19 +136,32 @@ public static CfgFile readFromFile(Path path) throws IOException {
80136

81137
matcher = keyRegex.matcher(line);
82138
if (matcher.find()) {
83-
currentSection.put(matcher.group(1), matcher.group(2));
84-
continue;
139+
currentSection.add(Map.entry(matcher.group(1), matcher.group(2)));
85140
}
86141
}
87142

88143
if (!currentSection.isEmpty()) {
89-
result.put(Optional.ofNullable(currentSectionName).orElse(""),
90-
Collections.unmodifiableMap(currentSection));
144+
sections.add(new Section(
145+
Optional.ofNullable(currentSectionName).orElse(""),
146+
Collections.unmodifiableList(currentSection)));
91147
}
92148

93-
return new CfgFile(Collections.unmodifiableMap(result), path.toString());
149+
return new CfgFile(sections, path.toString());
150+
}
151+
152+
private static record Section(String name, List<Map.Entry<String, String>> data) {
153+
String getValue(String key) {
154+
Objects.requireNonNull(key);
155+
for (int i = data.size()-1; i >= 0; i--) {
156+
var kvp = data.get(i);
157+
if (key.equals(kvp.getKey())) {
158+
return kvp.getValue();
159+
}
160+
}
161+
return null;
162+
}
94163
}
95164

96-
private final Map<String, Map<String, String>> data;
165+
private final List<Section> data;
97166
private final String id;
98167
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright (c) 2024, 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.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
package jdk.jpackage.test;
24+
25+
import java.util.HashSet;
26+
import java.util.Set;
27+
28+
record Comm<T>(Set<T> common, Set<T> unique1, Set<T> unique2) {
29+
30+
static <T> Comm<T> compare(Set<T> a, Set<T> b) {
31+
Set<T> common = new HashSet<>(a);
32+
common.retainAll(b);
33+
Set<T> unique1 = new HashSet<>(a);
34+
unique1.removeAll(common);
35+
Set<T> unique2 = new HashSet<>(b);
36+
unique2.removeAll(common);
37+
return new Comm(common, unique1, unique2);
38+
}
39+
}

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -54,7 +54,6 @@ public static Executor of(String... cmdline) {
5454

5555
public Executor() {
5656
saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE));
57-
removePath = false;
5857
winEnglishOutput = false;
5958
}
6059

@@ -91,8 +90,8 @@ public Executor setExecutable(JavaTool v) {
9190
return setExecutable(v.getPath());
9291
}
9392

94-
public Executor setRemovePath(boolean value) {
95-
removePath = value;
93+
public Executor removeEnvVar(String envVarName) {
94+
removeEnvVars.add(Objects.requireNonNull(envVarName));
9695
return this;
9796
}
9897

@@ -370,10 +369,12 @@ private Result runExecutable() throws IOException, InterruptedException {
370369
builder.directory(directory.toFile());
371370
sb.append(String.format("; in directory [%s]", directory));
372371
}
373-
if (removePath) {
374-
// run this with cleared Path in Environment
375-
TKit.trace("Clearing PATH in environment");
376-
builder.environment().remove("PATH");
372+
if (!removeEnvVars.isEmpty()) {
373+
final var envComm = Comm.compare(builder.environment().keySet(), removeEnvVars);
374+
builder.environment().keySet().removeAll(envComm.common());
375+
envComm.common().forEach(envVar -> {
376+
TKit.trace(String.format("Clearing %s in environment", envVar));
377+
});
377378
}
378379

379380
trace("Execute " + sb.toString() + "...");
@@ -512,7 +513,7 @@ private static void trace(String msg) {
512513
private Path executable;
513514
private Set<SaveOutputType> saveOutputType;
514515
private Path directory;
515-
private boolean removePath;
516+
private Set<String> removeEnvVars = new HashSet<>();
516517
private boolean winEnglishOutput;
517518
private String winTmpDir = null;
518519

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -464,13 +464,14 @@ private Executor getExecutor(String...args) {
464464
}
465465

466466
final List<String> launcherArgs = List.of(args);
467-
return new Executor()
467+
final var executor = new Executor()
468468
.setDirectory(outputFile.getParent())
469469
.saveOutput(saveOutput)
470470
.dumpOutput()
471-
.setRemovePath(removePath)
472471
.setExecutable(executablePath)
473-
.addArguments(launcherArgs);
472+
.addArguments(List.of(args));
473+
474+
return configureEnvironment(executor);
474475
}
475476

476477
private boolean launcherNoExit;
@@ -487,6 +488,14 @@ public static AppOutputVerifier assertApp(Path helloAppLauncher) {
487488
return new AppOutputVerifier(helloAppLauncher);
488489
}
489490

491+
public static Executor configureEnvironment(Executor executor) {
492+
if (CLEAR_JAVA_ENV_VARS) {
493+
executor.removeEnvVar("JAVA_TOOL_OPTIONS");
494+
executor.removeEnvVar("_JAVA_OPTIONS");
495+
}
496+
return executor;
497+
}
498+
490499
static final String OUTPUT_FILENAME = "appOutput.txt";
491500

492501
private final JavaAppDesc appDesc;
@@ -496,4 +505,7 @@ public static AppOutputVerifier assertApp(Path helloAppLauncher) {
496505

497506
private static final String CLASS_NAME = HELLO_JAVA.getFileName().toString().split(
498507
"\\.", 2)[0];
508+
509+
private static final boolean CLEAR_JAVA_ENV_VARS = Optional.ofNullable(
510+
TKit.getConfigProperty("clear-app-launcher-java-env-vars")).map(Boolean::parseBoolean).orElse(false);
499511
}

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,18 @@ public Path appLauncherCfgPath(String launcherName) {
570570
}
571571

572572
public boolean isFakeRuntime(String msg) {
573-
Path runtimeDir = appRuntimeDirectory();
573+
if (isFakeRuntime()) {
574+
// Fake runtime
575+
Path runtimeDir = appRuntimeDirectory();
576+
TKit.trace(String.format(
577+
"%s because application runtime directory [%s] is incomplete",
578+
msg, runtimeDir));
579+
return true;
580+
}
581+
return false;
582+
}
574583

584+
private boolean isFakeRuntime() {
575585
final Collection<Path> criticalRuntimeFiles;
576586
if (TKit.isWindows()) {
577587
criticalRuntimeFiles = WindowsHelper.CRITICAL_RUNTIME_FILES;
@@ -583,16 +593,9 @@ public boolean isFakeRuntime(String msg) {
583593
throw TKit.throwUnknownPlatformError();
584594
}
585595

586-
if (!criticalRuntimeFiles.stream().anyMatch(v -> {
587-
return runtimeDir.resolve(v).toFile().exists();
588-
})) {
589-
// Fake runtime
590-
TKit.trace(String.format(
591-
"%s because application runtime directory [%s] is incomplete",
592-
msg, runtimeDir));
593-
return true;
594-
}
595-
return false;
596+
Path runtimeDir = appRuntimeDirectory();
597+
return !criticalRuntimeFiles.stream().map(runtimeDir::resolve).allMatch(
598+
Files::exists);
596599
}
597600

598601
public boolean canRunLauncher(String msg) {
@@ -657,6 +660,13 @@ public JPackageCommand ignoreDefaultRuntime(boolean v) {
657660
return this;
658661
}
659662

663+
public JPackageCommand ignoreFakeRuntime() {
664+
if (isFakeRuntime()) {
665+
ignoreDefaultRuntime(true);
666+
}
667+
return this;
668+
}
669+
660670
public JPackageCommand ignoreDefaultVerbose(boolean v) {
661671
verifyMutable();
662672
ignoreDefaultVerbose = v;
@@ -876,7 +886,7 @@ public CfgFile readLauncherCfgFile(String launcherName) {
876886
if (isRuntime()) {
877887
return null;
878888
}
879-
return ThrowingFunction.toFunction(CfgFile::readFromFile).apply(
889+
return ThrowingFunction.toFunction(CfgFile::load).apply(
880890
appLauncherCfgPath(launcherName));
881891
}
882892

0 commit comments

Comments
 (0)