Skip to content

Commit 567174f

Browse files
authored
[improve][cli] PIP-343: Use picocli instead of jcommander in pulsar-function (#22331)
Signed-off-by: Zixuan Liu <nodeces@gmail.com>
1 parent afe4261 commit 567174f

6 files changed

Lines changed: 98 additions & 115 deletions

File tree

pulsar-functions/instance/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,8 @@
153153
</dependency>
154154

155155
<dependency>
156-
<groupId>com.beust</groupId>
157-
<artifactId>jcommander</artifactId>
156+
<groupId>info.picocli</groupId>
157+
<artifactId>picocli</artifactId>
158158
</dependency>
159159

160160
<dependency>

pulsar-functions/localrun-shaded/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
<include>org.rocksdb:*</include>
134134
<include>org.eclipse.jetty*:*</include>
135135
<include>org.apache.avro:avro</include>
136-
<include>com.beust:*</include>
136+
<include>info.picocli:*</include>
137137
<include>net.jodah:*</include>
138138
<include>io.airlift:*</include>
139139
<include>com.yahoo.datasketches:*</include>
@@ -385,8 +385,8 @@
385385
<shadedPattern>org.apache.pulsar.shaded.com.yahoo.sketches</shadedPattern>
386386
</relocation>
387387
<relocation>
388-
<pattern>com.beust</pattern>
389-
<shadedPattern>org.apache.pulsar.functions.runtime.shaded.com.beust</shadedPattern>
388+
<pattern>info.picocli</pattern>
389+
<shadedPattern>org.apache.pulsar.functions.runtime.shaded.info.picocli</shadedPattern>
390390
</relocation>
391391
<!-- Netty cannot be shaded, this is causing java.lang.NoSuchMethodError -->
392392
<relocation>

pulsar-functions/localrun/src/main/java/org/apache/pulsar/functions/LocalRunner.java

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020

2121
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
2222
import static org.apache.pulsar.common.functions.Utils.inferMissingArguments;
23-
import com.beust.jcommander.IStringConverter;
24-
import com.beust.jcommander.JCommander;
25-
import com.beust.jcommander.Parameter;
2623
import com.google.gson.Gson;
2724
import com.google.gson.GsonBuilder;
2825
import com.google.gson.JsonParser;
@@ -87,6 +84,10 @@
8784
import org.apache.pulsar.functions.utils.functions.FunctionUtils;
8885
import org.apache.pulsar.functions.utils.io.Connector;
8986
import org.apache.pulsar.functions.utils.io.ConnectorUtils;
87+
import picocli.CommandLine;
88+
import picocli.CommandLine.ITypeConverter;
89+
import picocli.CommandLine.Option;
90+
import picocli.CommandLine.TypeConversionException;
9091

9192
@Slf4j
9293
public class LocalRunner implements AutoCloseable {
@@ -115,95 +116,95 @@ private static class UserCodeClassLoader {
115116
boolean classLoaderCreated;
116117
}
117118

118-
public static class FunctionConfigConverter implements IStringConverter<FunctionConfig> {
119+
public static class FunctionConfigConverter implements ITypeConverter<FunctionConfig> {
119120
@Override
120121
public FunctionConfig convert(String value) {
121122
try {
122123
return ObjectMapperFactory.getMapper().reader().readValue(value, FunctionConfig.class);
123124
} catch (IOException e) {
124-
throw new RuntimeException("Failed to parse function config:", e);
125+
throw new TypeConversionException(e.getMessage());
125126
}
126127
}
127128
}
128129

129-
public static class SourceConfigConverter implements IStringConverter<SourceConfig> {
130+
public static class SourceConfigConverter implements ITypeConverter<SourceConfig> {
130131
@Override
131132
public SourceConfig convert(String value) {
132133
try {
133134
return ObjectMapperFactory.getMapper().reader().readValue(value, SourceConfig.class);
134135
} catch (IOException e) {
135-
throw new RuntimeException("Failed to parse source config:", e);
136+
throw new TypeConversionException(e.getMessage());
136137
}
137138
}
138139
}
139140

140-
public static class SinkConfigConverter implements IStringConverter<SinkConfig> {
141+
public static class SinkConfigConverter implements ITypeConverter<SinkConfig> {
141142
@Override
142143
public SinkConfig convert(String value) {
143144
try {
144145
return ObjectMapperFactory.getMapper().reader().readValue(value, SinkConfig.class);
145146
} catch (IOException e) {
146-
throw new RuntimeException("Failed to parse sink config:", e);
147+
throw new TypeConversionException(e.getMessage());
147148
}
148149
}
149150
}
150151

151-
public static class RuntimeConverter implements IStringConverter<RuntimeEnv> {
152+
public static class RuntimeConverter implements ITypeConverter<RuntimeEnv> {
152153
@Override
153154
public RuntimeEnv convert(String value) {
154155
return RuntimeEnv.valueOf(value);
155156
}
156157
}
157158

158-
@Parameter(names = "--functionConfig", description = "The json representation of FunctionConfig",
159+
@Option(names = "--functionConfig", description = "The json representation of FunctionConfig",
159160
hidden = true, converter = FunctionConfigConverter.class)
160161
protected FunctionConfig functionConfig;
161-
@Parameter(names = "--sourceConfig", description = "The json representation of SourceConfig",
162+
@Option(names = "--sourceConfig", description = "The json representation of SourceConfig",
162163
hidden = true, converter = SourceConfigConverter.class)
163164
protected SourceConfig sourceConfig;
164-
@Parameter(names = "--sinkConfig", description = "The json representation of SinkConfig",
165+
@Option(names = "--sinkConfig", description = "The json representation of SinkConfig",
165166
hidden = true, converter = SinkConfigConverter.class)
166167
protected SinkConfig sinkConfig;
167-
@Parameter(names = "--stateStorageImplClass", description = "The implemenatation class "
168+
@Option(names = "--stateStorageImplClass", description = "The implemenatation class "
168169
+ "state storage service (by default Apache BookKeeper)", hidden = true, required = false)
169170
protected String stateStorageImplClass;
170-
@Parameter(names = "--stateStorageServiceUrl", description = "The URL for the state storage service "
171+
@Option(names = "--stateStorageServiceUrl", description = "The URL for the state storage service "
171172
+ "(by default Apache BookKeeper)", hidden = true)
172173
protected String stateStorageServiceUrl;
173-
@Parameter(names = "--brokerServiceUrl", description = "The URL for the Pulsar broker", hidden = true)
174+
@Option(names = "--brokerServiceUrl", description = "The URL for the Pulsar broker", hidden = true)
174175
protected String brokerServiceUrl;
175-
@Parameter(names = "--webServiceUrl", description = "The URL for the Pulsar web service", hidden = true)
176+
@Option(names = "--webServiceUrl", description = "The URL for the Pulsar web service", hidden = true)
176177
protected String webServiceUrl = null;
177-
@Parameter(names = "--clientAuthPlugin", description = "Client authentication plugin using which "
178+
@Option(names = "--clientAuthPlugin", description = "Client authentication plugin using which "
178179
+ "function-process can connect to broker", hidden = true)
179180
protected String clientAuthPlugin;
180-
@Parameter(names = "--clientAuthParams", description = "Client authentication param", hidden = true)
181+
@Option(names = "--clientAuthParams", description = "Client authentication param", hidden = true)
181182
protected String clientAuthParams;
182-
@Parameter(names = "--useTls", description = "Use tls connection\n", hidden = true, arity = 1)
183+
@Option(names = "--useTls", description = "Use tls connection\n", hidden = true, arity = "1")
183184
protected boolean useTls;
184-
@Parameter(names = "--tlsAllowInsecureConnection", description = "Allow insecure tls connection\n",
185-
hidden = true, arity = 1)
185+
@Option(names = "--tlsAllowInsecureConnection", description = "Allow insecure tls connection\n",
186+
hidden = true, arity = "1")
186187
protected boolean tlsAllowInsecureConnection;
187-
@Parameter(names = "--tlsHostNameVerificationEnabled", description = "Enable hostname verification", hidden = true
188-
, arity = 1)
188+
@Option(names = "--tlsHostNameVerificationEnabled", description = "Enable hostname verification", hidden = true
189+
, arity = "1")
189190
protected boolean tlsHostNameVerificationEnabled;
190-
@Parameter(names = "--tlsTrustCertFilePath", description = "tls trust cert file path", hidden = true)
191+
@Option(names = "--tlsTrustCertFilePath", description = "tls trust cert file path", hidden = true)
191192
protected String tlsTrustCertFilePath;
192-
@Parameter(names = "--instanceIdOffset", description = "Start the instanceIds from this offset", hidden = true)
193+
@Option(names = "--instanceIdOffset", description = "Start the instanceIds from this offset", hidden = true)
193194
protected int instanceIdOffset = 0;
194-
@Parameter(names = "--runtime", description = "Function runtime to use (Thread/Process)", hidden = true,
195+
@Option(names = "--runtime", description = "Function runtime to use (Thread/Process)", hidden = true,
195196
converter = RuntimeConverter.class)
196197
protected RuntimeEnv runtimeEnv;
197-
@Parameter(names = "--secretsProviderClassName",
198+
@Option(names = "--secretsProviderClassName",
198199
description = "Whats the classname of secrets provider", hidden = true)
199200
protected String secretsProviderClassName;
200-
@Parameter(names = "--secretsProviderConfig",
201+
@Option(names = "--secretsProviderConfig",
201202
description = "Whats the config for the secrets provider", hidden = true)
202203
protected String secretsProviderConfig;
203-
@Parameter(names = "--metricsPortStart", description = "The starting port range for metrics server. When running "
204+
@Option(names = "--metricsPortStart", description = "The starting port range for metrics server. When running "
204205
+ "instances as threads, one metrics server is used to host the stats for all instances.", hidden = true)
205206
protected Integer metricsPortStart;
206-
@Parameter(names = "--exitOnError", description = "The starting port range for metrics server. When running "
207+
@Option(names = "--exitOnError", description = "The starting port range for metrics server. When running "
207208
+ "instances as threads, one metrics server is used to host the stats for all instances.", hidden = true)
208209
protected boolean exitOnError;
209210

@@ -212,11 +213,10 @@ public RuntimeEnv convert(String value) {
212213

213214
public static void main(String[] args) throws Exception {
214215
LocalRunner localRunner = LocalRunner.builder().build();
215-
JCommander jcommander = new JCommander(localRunner);
216-
jcommander.setProgramName("LocalRunner");
216+
CommandLine jcommander = new CommandLine(localRunner);
217+
jcommander.setCommandName("LocalRunner");
217218

218-
// parse args by JCommander
219-
jcommander.parse(args);
219+
jcommander.parseArgs(args);
220220
try {
221221
localRunner.start(true);
222222
} catch (Exception e) {

pulsar-functions/runtime/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
</dependency>
4747

4848
<dependency>
49-
<groupId>com.beust</groupId>
50-
<artifactId>jcommander</artifactId>
49+
<groupId>info.picocli</groupId>
50+
<artifactId>picocli</artifactId>
5151
</dependency>
5252

5353
<dependency>

pulsar-functions/runtime/src/main/java/org/apache/pulsar/functions/runtime/JavaInstanceStarter.java

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@
2020

2121
import static org.apache.pulsar.functions.utils.FunctionCommon.getSinkType;
2222
import static org.apache.pulsar.functions.utils.FunctionCommon.getSourceType;
23-
import com.beust.jcommander.JCommander;
24-
import com.beust.jcommander.Parameter;
25-
import com.beust.jcommander.converters.StringConverter;
2623
import com.google.gson.Gson;
2724
import com.google.gson.reflect.TypeToken;
2825
import com.google.protobuf.Empty;
@@ -59,104 +56,104 @@
5956
import org.apache.pulsar.functions.utils.FunctionCommon;
6057
import org.apache.pulsar.functions.utils.functioncache.FunctionCacheManager;
6158
import org.apache.pulsar.functions.utils.functioncache.FunctionCacheManagerImpl;
59+
import picocli.CommandLine;
60+
import picocli.CommandLine.Option;
6261

6362

6463
@Slf4j
6564
public class JavaInstanceStarter implements AutoCloseable {
66-
@Parameter(names = "--function_details", description = "Function details json\n", required = true)
65+
@Option(names = "--function_details", description = "Function details json\n", required = true)
6766
public String functionDetailsJsonString;
68-
@Parameter(
67+
@Option(
6968
names = "--jar",
70-
description = "Path to Jar\n",
71-
listConverter = StringConverter.class)
69+
description = "Path to Jar\n")
7270
public String jarFile;
7371

74-
@Parameter(
72+
@Option(
7573
names = "--transform_function_jar",
76-
description = "Path to Transform Function Jar\n",
77-
listConverter = StringConverter.class)
74+
description = "Path to Transform Function Jar\n")
7875
public String transformFunctionJarFile;
7976

80-
@Parameter(names = "--instance_id", description = "Instance Id\n", required = true)
77+
@Option(names = "--instance_id", description = "Instance Id\n", required = true)
8178
public int instanceId;
8279

83-
@Parameter(names = "--function_id", description = "Function Id\n", required = true)
80+
@Option(names = "--function_id", description = "Function Id\n", required = true)
8481
public String functionId;
8582

86-
@Parameter(names = "--function_version", description = "Function Version\n", required = true)
83+
@Option(names = "--function_version", description = "Function Version\n", required = true)
8784
public String functionVersion;
8885

89-
@Parameter(names = "--pulsar_serviceurl", description = "Pulsar Service Url\n", required = true)
86+
@Option(names = "--pulsar_serviceurl", description = "Pulsar Service Url\n", required = true)
9087
public String pulsarServiceUrl;
9188

92-
@Parameter(names = "--transform_function_id", description = "Transform Function Id\n")
89+
@Option(names = "--transform_function_id", description = "Transform Function Id\n")
9390
public String transformFunctionId;
9491

95-
@Parameter(names = "--client_auth_plugin", description = "Client auth plugin name\n")
92+
@Option(names = "--client_auth_plugin", description = "Client auth plugin name\n")
9693
public String clientAuthenticationPlugin;
9794

98-
@Parameter(names = "--client_auth_params", description = "Client auth param\n")
95+
@Option(names = "--client_auth_params", description = "Client auth param\n")
9996
public String clientAuthenticationParameters;
10097

101-
@Parameter(names = "--use_tls", description = "Use tls connection\n")
98+
@Option(names = "--use_tls", description = "Use tls connection\n")
10299
public String useTls = Boolean.FALSE.toString();
103100

104-
@Parameter(names = "--tls_allow_insecure", description = "Allow insecure tls connection\n")
101+
@Option(names = "--tls_allow_insecure", description = "Allow insecure tls connection\n")
105102
public String tlsAllowInsecureConnection = Boolean.FALSE.toString();
106103

107-
@Parameter(names = "--hostname_verification_enabled", description = "Enable hostname verification")
104+
@Option(names = "--hostname_verification_enabled", description = "Enable hostname verification")
108105
public String tlsHostNameVerificationEnabled = Boolean.FALSE.toString();
109106

110-
@Parameter(names = "--tls_trust_cert_path", description = "tls trust cert file path")
107+
@Option(names = "--tls_trust_cert_path", description = "tls trust cert file path")
111108
public String tlsTrustCertFilePath;
112109

113-
@Parameter(names = "--state_storage_impl_class", description = "State Storage Service "
110+
@Option(names = "--state_storage_impl_class", description = "State Storage Service "
114111
+ "Implementation class\n", required = false)
115112
public String stateStorageImplClass;
116113

117-
@Parameter(names = "--state_storage_serviceurl", description = "State Storage Service Url\n", required = false)
114+
@Option(names = "--state_storage_serviceurl", description = "State Storage Service Url\n", required = false)
118115
public String stateStorageServiceUrl;
119116

120-
@Parameter(names = "--port", description = "Port to listen on\n", required = true)
117+
@Option(names = "--port", description = "Port to listen on\n", required = true)
121118
public int port;
122119

123-
@Parameter(names = "--metrics_port", description = "Port metrics will be exposed on\n", required = true)
120+
@Option(names = "--metrics_port", description = "Port metrics will be exposed on\n", required = true)
124121
public int metricsPort;
125122

126-
@Parameter(names = "--max_buffered_tuples", description = "Maximum number of tuples to buffer\n", required = true)
123+
@Option(names = "--max_buffered_tuples", description = "Maximum number of tuples to buffer\n", required = true)
127124
public int maxBufferedTuples;
128125

129-
@Parameter(names = "--expected_healthcheck_interval", description = "Expected interval in "
126+
@Option(names = "--expected_healthcheck_interval", description = "Expected interval in "
130127
+ "seconds between healtchecks", required = true)
131128
public int expectedHealthCheckInterval;
132129

133-
@Parameter(names = "--secrets_provider", description = "The classname of the secrets provider", required = false)
130+
@Option(names = "--secrets_provider", description = "The classname of the secrets provider", required = false)
134131
public String secretsProviderClassName;
135132

136-
@Parameter(names = "--secrets_provider_config", description = "The config that needs to be "
133+
@Option(names = "--secrets_provider_config", description = "The config that needs to be "
137134
+ "passed to secrets provider", required = false)
138135
public String secretsProviderConfig;
139136

140-
@Parameter(names = "--cluster_name", description = "The name of the cluster this "
137+
@Option(names = "--cluster_name", description = "The name of the cluster this "
141138
+ "instance is running on", required = true)
142139
public String clusterName;
143140

144-
@Parameter(names = "--nar_extraction_directory", description = "The directory where "
141+
@Option(names = "--nar_extraction_directory", description = "The directory where "
145142
+ "extraction of nar packages happen", required = false)
146143
public String narExtractionDirectory = NarClassLoader.DEFAULT_NAR_EXTRACTION_DIR;
147144

148-
@Parameter(names = "--pending_async_requests", description = "Max pending async requests per instance",
145+
@Option(names = "--pending_async_requests", description = "Max pending async requests per instance",
149146
required = false)
150147
public int maxPendingAsyncRequests = 1000;
151148

152-
@Parameter(names = "--web_serviceurl", description = "Pulsar Web Service Url", required = false)
149+
@Option(names = "--web_serviceurl", description = "Pulsar Web Service Url", required = false)
153150
public String webServiceUrl = null;
154151

155-
@Parameter(names = "--expose_pulsaradmin", description = "Whether the pulsar admin client "
152+
@Option(names = "--expose_pulsaradmin", description = "Whether the pulsar admin client "
156153
+ "exposed to function context, default is disabled.", required = false)
157154
public Boolean exposePulsarAdminClientEnabled = false;
158155

159-
@Parameter(names = "--ignore_unknown_config_fields",
156+
@Option(names = "--ignore_unknown_config_fields",
160157
description = "Whether to ignore unknown properties when deserializing the connector configuration.",
161158
required = false)
162159
public Boolean ignoreUnknownConfigFields = false;
@@ -176,9 +173,8 @@ public void start(String[] args, ClassLoader functionInstanceClassLoader, ClassL
176173
throws Exception {
177174
Thread.currentThread().setContextClassLoader(functionInstanceClassLoader);
178175

179-
JCommander jcommander = new JCommander(this);
180-
// parse args by JCommander
181-
jcommander.parse(args);
176+
CommandLine jcommander = new CommandLine(this);
177+
jcommander.parseArgs(args);
182178

183179
InstanceConfig instanceConfig = new InstanceConfig();
184180
instanceConfig.setFunctionId(functionId);

0 commit comments

Comments
 (0)