-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCreateNativeImage.groovy
More file actions
154 lines (131 loc) · 5.15 KB
/
CreateNativeImage.groovy
File metadata and controls
154 lines (131 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
@Grab(group = 'org.yaml', module = 'snakeyaml', version = '2.0')
@Grab(group = 'org.codehaus.groovy', module = 'groovy-cli-commons', version = '3.0.9')
import java.nio.file.Files
import java.nio.file.Paths
import java.util.logging.Level
import java.util.logging.Logger
import groovy.cli.commons.CliBuilder
import groovy.transform.Field
import org.yaml.snakeyaml.Yaml
@Field static final String CONFIG_AGENT_ARGS = 'native-image.agent.args'
@Field static final String CONFIG_BUILD_ADDITIONAL_ARGS = 'native-image.build.additional-args'
@Field static final String CONFIG_BUILD_OVERRIDE_ARGS = 'native-image.build.override-args'
@Field static final String ARG_GRAPE_DISABLE = '-Dgroovy.grape.enable=false'
@Field static final String REGEX_ENV_VARIABLE = '\\$\\{([A-Z_]+)\\}'
System.setProperty('java.util.logging.SimpleFormatter.format',
'%1$tY-%1$tm-%1$tdT%1$tH:%1$tM:%1$tS.%1$tL%1$tz %4$s %5$s%6$s%n')
@Field Logger logger = Logger.getLogger('CreateNativeImage.log')
def cli = new CliBuilder(usage: 'groovy CreateNativeImage.groovy [options]')
cli.m(longOpt: 'main-class-name', args: 1, argName: 'main-class-name', 'The name of the main class')
cli.j(longOpt: 'jar-name', args: 1, argName: 'jar-name', 'The jar containing the main class')
cli.c(longOpt: 'config', args: 1, argName: 'config', 'File containing configuration for the native image build')
cli.cp(longOpt: 'classpath', args: 1, argName: 'classpath', 'Classpath for the native image build')
cli.rp(longOpt: 'reflection-config-path', args: 1, argName: 'reflection-config-path', 'Path in which to generate the reflection config')
cli.d(longOpt: 'debug', args: 0, argName: 'debug', 'Enable debug logs')
def options = cli.parse(args)
if (!(options.m || options.j)) {
cli.usage()
System.exit(1)
}
// Enable debug logs
if (options.d) {
Logger root = Logger.getLogger('')
root.setLevel(Level.FINE)
root.getHandlers().each { it.setLevel(Level.FINE) }
}
// Read config file
def config = [:]
if (options.c) {
Yaml yaml = new Yaml()
config.putAll(getFlattenedMap('', yaml.load(new File(options.c).text)))
}
logger.fine({ String.valueOf(config) })
// Generate reflection config
String classPath = options.cp ?: 'build/native/libs/*:build/native/classes'
String reflectConfigPath = options.rp ?: 'build/native/graal-config/'
Files.createDirectories(Paths.get(reflectConfigPath))
def firstCommand = ['java', "-agentlib:native-image-agent=config-output-dir=${reflectConfigPath}",
'-cp', classPath, ARG_GRAPE_DISABLE]
def baseCommand = ['java', "-agentlib:native-image-agent=config-merge-dir=${reflectConfigPath}",
'-cp', classPath, ARG_GRAPE_DISABLE]
def executable = []
if (options.m) {
executable.add(options.m)
} else {
executable.add('-jar')
executable.add(options.j)
}
firstCommand.addAll(executable)
baseCommand.addAll(executable)
if (config[CONFIG_AGENT_ARGS]) {
boolean first = true
def commandWithArgs = []
config[CONFIG_AGENT_ARGS].each { arguments ->
commandWithArgs.clear()
if (first) {
commandWithArgs.addAll(firstCommand)
first = false
} else {
commandWithArgs.addAll(baseCommand)
}
arguments.each { argument ->
// If argument is an environment variable, replace it with its value if present
if (argument =~ REGEX_ENV_VARIABLE) {
String envVariableName = argument.find(REGEX_ENV_VARIABLE) { matchedText, group ->
return group
}
String envVariableValue = System.getenv(envVariableName)
commandWithArgs.add(envVariableValue ?: argument)
} else {
commandWithArgs.add(argument)
}
}
executeCommand(commandWithArgs)
}
} else {
executeCommand(firstCommand)
}
/** Build native image **/
def nativeImageCommand = ['native-image', '-cp', classPath]
// If override arguments are specified, add only those
if (config[CONFIG_BUILD_OVERRIDE_ARGS]) {
nativeImageCommand.addAll(config[CONFIG_BUILD_OVERRIDE_ARGS])
} else {
nativeImageCommand.addAll([ARG_GRAPE_DISABLE, '--static',
'--no-fallback', '--report-unsupported-elements-at-runtime',
'--enable-url-protocols=http,https', "-H:ConfigurationFileDirectories=${reflectConfigPath}"])
if (config[CONFIG_BUILD_ADDITIONAL_ARGS]) {
nativeImageCommand.addAll(config[CONFIG_BUILD_ADDITIONAL_ARGS])
}
}
nativeImageCommand.addAll(executable)
executeCommand(nativeImageCommand)
/**
* Executes a command
*
* @param command
*/
void executeCommand(def command) {
logger.fine({ String.valueOf(command) })
Process process = command.execute()
process.consumeProcessOutput(System.out, System.err)
process.waitFor()
}
/**
* Converts the YAML configuration into a flat map
*
* @param prefix
* @param map
* @return
*/
Map getFlattenedMap(String prefix, Map map) {
Map flatMap = [:]
map.each { key, value ->
if (value instanceof Map) {
flatMap.putAll(getFlattenedMap(prefix + key + '.', value))
} else {
flatMap[(prefix + key)] = value
}
}
return flatMap
}