Skip to content

Commit 45b7c74

Browse files
author
Alexey Semenyuk
committed
8341641: Make %APPDATA% and %LOCALAPPDATA% env variables available in *.cfg files
Reviewed-by: almatvee
1 parent 5c438c5 commit 45b7c74

File tree

10 files changed

+659
-48
lines changed

10 files changed

+659
-48
lines changed

src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
import java.util.stream.IntStream;
4343
import java.util.stream.Stream;
4444

45+
/**
46+
* Class to replace tokens in strings.
47+
* <p>
48+
* Single instance holds a list of tokens. Tokens can be substrings of each other.
49+
* The implementation performs greedy replacement: longer tokens are replaced first.
50+
*/
4551
public final class TokenReplace {
4652

4753
private record TokenCut(String[] main, String[] sub) {
@@ -103,7 +109,7 @@ public TokenReplace(String... tokens) {
103109
this.tokens = tokens;
104110
regexps = new ArrayList<>();
105111

106-
for(;;) {
112+
for (;;) {
107113
final var tokenCut = TokenCut.createFromOrderedTokens(tokens);
108114
regexps.add(Pattern.compile(Stream.of(tokenCut.main()).map(Pattern::quote).collect(joining("|", "(", ")"))));
109115

@@ -153,12 +159,12 @@ public int hashCode() {
153159
@Override
154160
public boolean equals(Object obj) {
155161
// Auto generated code
156-
if (this == obj)
162+
if (this == obj) {
157163
return true;
158-
if (obj == null)
159-
return false;
160-
if (getClass() != obj.getClass())
164+
}
165+
if ((obj == null) || (getClass() != obj.getClass())) {
161166
return false;
167+
}
162168
TokenReplace other = (TokenReplace) obj;
163169
return Arrays.equals(tokens, other.tokens);
164170
}

src/jdk.jpackage/share/man/jpackage.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,35 @@ The `jpackage` tool will take as input a Java application and a Java run-time im
219219

220220
This option can be used multiple times.
221221

222+
Value can contain substrings that will be expanded at runtime.
223+
Two types of such substrings are supported: environment variables
224+
and "APPDIR", "BINDIR", and "ROOTDIR" tokens.
225+
226+
An expandable substring should be enclosed between the dollar
227+
sign character ($) and the first following non-alphanumeric
228+
character. Alternatively, it can be enclosed between "${" and "}"
229+
substrings.
230+
231+
Expandable substrings are case-sensitive on Unix and
232+
case-insensitive on Windows. No string expansion occurs if the
233+
referenced environment variable is undefined.
234+
235+
Environment variables with names "APPDIR", "BINDIR", and "ROOTDIR"
236+
will be ignored, and these expandable substrings will be
237+
replaced by values calculated by the app launcher.
238+
239+
Prefix the dollar sign character with the backslash character (\)
240+
to prevent substring expansion.
241+
222242
<a id="option-java-options">`--java-options` *options*</a>
223243

224244
: Options to pass to the Java runtime
225245

226246
This option can be used multiple times.
227247

248+
Value can contain substrings that will be substituted at runtime,
249+
such as for the --arguments option.
250+
228251
<a id="option-main-class">`--main-class` *class-name*</a>
229252

230253
: Qualified name of the application main class to execute

src/jdk.jpackage/share/native/applauncher/AppLauncher.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 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
@@ -164,9 +164,9 @@ CfgFile* AppLauncher::createCfgFile() const {
164164
<< cfgFilePath << "\"");
165165

166166
CfgFile::Macros macros;
167-
macros[_T("$APPDIR")] = appDirPath;
168-
macros[_T("$BINDIR")] = FileUtils::dirname(launcherPath);
169-
macros[_T("$ROOTDIR")] = imageRoot;
167+
macros[_T("APPDIR")] = appDirPath;
168+
macros[_T("BINDIR")] = FileUtils::dirname(launcherPath);
169+
macros[_T("ROOTDIR")] = imageRoot;
170170
std::unique_ptr<CfgFile> dummy(new CfgFile());
171171
CfgFile::load(cfgFilePath).expandMacros(macros).swap(*dummy);
172172
return dummy.release();

src/jdk.jpackage/share/native/applauncher/CfgFile.cpp

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 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
@@ -25,13 +25,16 @@
2525

2626
#include "kludge_c++11.h"
2727

28+
#include <set>
2829
#include <fstream>
2930
#include <algorithm>
3031
#include "CfgFile.h"
32+
#include "SysInfo.h"
3133
#include "Log.h"
3234
#include "Toolbox.h"
3335
#include "FileUtils.h"
3436
#include "ErrorHandling.h"
37+
#include "StringProcessing.h"
3538

3639

3740
const CfgFile::Properties& CfgFile::getProperties(
@@ -60,38 +63,82 @@ CfgFile& CfgFile::setPropertyValue(const SectionName& sectionName,
6063

6164
namespace {
6265

63-
tstring expandMacros(const tstring& str, const CfgFile::Macros& macros) {
64-
tstring reply = str;
65-
CfgFile::Macros::const_iterator it = macros.begin();
66-
const CfgFile::Macros::const_iterator end = macros.end();
67-
for (; it != end; ++it) {
68-
reply = tstrings::replace(reply, it->first, it->second);
66+
template <typename CfgFileType, typename OpType>
67+
void iterateProperties(CfgFileType& cfgFile, OpType& op) {
68+
for (auto mapIt = cfgFile.begin(), mapEnd = cfgFile.end(); mapIt != mapEnd; ++mapIt) {
69+
for (auto propertyIt = mapIt->second.begin(), propertyEnd = mapIt->second.end(); propertyIt != propertyEnd; ++propertyIt) {
70+
for (auto strIt = propertyIt->second.begin(), strEnd = propertyIt->second.end(); strIt != strEnd; ++strIt) {
71+
op(strIt);
72+
}
73+
}
6974
}
70-
return reply;
7175
}
7276

77+
struct tokenize_strings {
78+
void operator () (tstring_array::const_iterator& strIt) {
79+
const auto tokens = StringProcessing::tokenize(*strIt);
80+
values.push_back(tokens);
81+
}
82+
83+
std::set<tstring> variableNames() const {
84+
std::set<tstring> allVariableNames;
85+
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
86+
const auto variableNames = StringProcessing::extractVariableNames(*it);
87+
allVariableNames.insert(variableNames.begin(), variableNames.end());
88+
}
89+
90+
return allVariableNames;
91+
}
92+
93+
std::vector<StringProcessing::TokenizedString> values;
94+
};
95+
96+
class expand_macros {
97+
public:
98+
expand_macros(const CfgFile::Macros& m,
99+
std::vector<StringProcessing::TokenizedString>::iterator iter) : macros(m), curTokenizedString(iter) {
100+
}
101+
102+
void operator () (tstring_array::iterator& strIt) {
103+
StringProcessing::expandVariables(*curTokenizedString, macros);
104+
auto newStr = StringProcessing::stringify(*curTokenizedString);
105+
++curTokenizedString;
106+
if (*strIt != newStr) {
107+
LOG_TRACE(tstrings::any() << "Map [" << *strIt << "] into [" << newStr << "]");
108+
}
109+
strIt->swap(newStr);
110+
}
111+
112+
private:
113+
const CfgFile::Macros& macros;
114+
std::vector<StringProcessing::TokenizedString>::iterator curTokenizedString;
115+
};
116+
73117
} // namespace
74118

75119
CfgFile CfgFile::expandMacros(const Macros& macros) const {
76120
CfgFile copyCfgFile = *this;
77121

78-
PropertyMap::iterator mapIt = copyCfgFile.data.begin();
79-
const PropertyMap::iterator mapEnd = copyCfgFile.data.end();
80-
for (; mapIt != mapEnd; ++mapIt) {
81-
Properties::iterator propertyIt = mapIt->second.begin();
82-
const Properties::iterator propertyEnd = mapIt->second.end();
83-
for (; propertyIt != propertyEnd; ++propertyIt) {
84-
tstring_array::iterator strIt = propertyIt->second.begin();
85-
const tstring_array::iterator strEnd = propertyIt->second.end();
86-
for (; strIt != strEnd; ++strIt) {
87-
tstring newValue;
88-
while ((newValue = ::expandMacros(*strIt, macros)) != *strIt) {
89-
strIt->swap(newValue);
90-
}
122+
tokenize_strings tokenizedStrings;
123+
iterateProperties(static_cast<const CfgFile::PropertyMap&>(copyCfgFile.data), tokenizedStrings);
124+
125+
Macros allMacros(macros);
126+
127+
const auto variableNames = tokenizedStrings.variableNames();
128+
for (auto it = variableNames.begin(), end = variableNames.end(); it != end; ++it) {
129+
if (macros.find(*it) == macros.end()) {
130+
// Not one of the reserved macro names. Assuming an environment variable.
131+
const auto envVarName = *it;
132+
if (SysInfo::isEnvVariableSet(envVarName)) {
133+
const auto envVarValue = SysInfo::getEnvVariable(envVarName);
134+
allMacros[envVarName] = envVarValue;
91135
}
92136
}
93137
}
94138

139+
expand_macros expandMacros(allMacros, tokenizedStrings.values.begin());
140+
iterateProperties(copyCfgFile.data, expandMacros);
141+
95142
return copyCfgFile;
96143
}
97144

src/jdk.jpackage/share/native/applauncher/CfgFile.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 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
@@ -27,8 +27,7 @@
2727
#ifndef CfgFile_h
2828
#define CfgFile_h
2929

30-
#include <map>
31-
#include "tstrings.h"
30+
#include "StringProcessing.h"
3231

3332

3433
class CfgFile {
@@ -90,10 +89,10 @@ class CfgFile {
9089
std::swap(empty, other.empty);
9190
}
9291

93-
typedef std::map<tstring, tstring> Macros;
92+
typedef StringProcessing::VariableValues Macros;
9493

9594
/**
96-
* Returns copy of this instance with the given macros expanded.
95+
* Returns copy of this instance with the given macros and environment variables expanded.
9796
*/
9897
CfgFile expandMacros(const Macros& macros) const;
9998

0 commit comments

Comments
 (0)