Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

Commit d9579e1

Browse files
committed
#247 New CLI and executable jar
1 parent 36a4ef4 commit d9579e1

File tree

7 files changed

+304
-1
lines changed

7 files changed

+304
-1
lines changed

build.gradle

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ dependencies {
2121
compile 'org.apache.httpcomponents:httpclient:4.3.5'
2222
compile 'org.springframework:spring-web:4.3.5.RELEASE'
2323

24+
// Don't want to include this in the published jar, just the executable jar
25+
compileOnly "com.beust:jcommander:1.72"
26+
2427
testCompile 'com.marklogic:ml-junit:' + mlJunitVersion
2528
testCompile 'commons-io:commons-io:2.5'
2629

2730
// Forcing Spring to use logback instead of commons-logging
28-
runtime "ch.qos.logback:logback-classic:1.1.8"
31+
compile "ch.qos.logback:logback-classic:1.1.8" // Needs to be compile for CLI
2932
runtime group: "org.slf4j", name: "jcl-over-slf4j", version: "1.7.22"
3033
runtime group: "org.slf4j", name: "slf4j-api", version: "1.7.22"
3134
}
@@ -77,3 +80,23 @@ test {
7780
exceptionFormat 'full'
7881
}
7982
}
83+
84+
task executableJar(type: Jar) {
85+
baseName = "deployer"
86+
manifest {
87+
attributes("Main-Class": "com.marklogic.appdeployer.cli.Main")
88+
}
89+
// Include this project's class files
90+
from sourceSets.main.output
91+
// Include all project dependencies
92+
from {
93+
configurations.runtime.collect {
94+
it.isDirectory() ? it : zipTree(it)
95+
}
96+
}
97+
from {
98+
configurations.compileOnly.collect {
99+
it.isDirectory() ? it : zipTree(it)
100+
}
101+
}
102+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
import com.marklogic.appdeployer.command.Command;
4+
5+
public interface CommandArray {
6+
7+
Command[] getCommands();
8+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
import com.beust.jcommander.Parameters;
4+
import com.marklogic.appdeployer.command.Command;
5+
6+
/**
7+
* Using this wrapper solely to make "null" go away as the description of a command when calling JCommander's "usage()".
8+
* <p>
9+
* Ideally, each Command object can provide a description, but not ready to make every command depend on
10+
* JCommander annotations.
11+
*/
12+
@Parameters(commandDescription = "")
13+
public class CommandWrapper implements CommandArray {
14+
15+
private Command command;
16+
17+
public CommandWrapper(Command command) {
18+
this.command = command;
19+
}
20+
21+
@Override
22+
public Command[] getCommands() {
23+
return new Command[]{command};
24+
}
25+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
import com.marklogic.appdeployer.command.Command;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Map;
8+
9+
public class DeployCommand implements CommandArray {
10+
11+
private Map<String, List<Command>> commandMap;
12+
13+
public DeployCommand(Map<String, List<Command>> commandMap) {
14+
this.commandMap = commandMap;
15+
}
16+
17+
@Override
18+
public Command[] getCommands() {
19+
List<Command> list = new ArrayList<>();
20+
for (String group : commandMap.keySet()) {
21+
list.addAll(commandMap.get(group));
22+
}
23+
return list.toArray(new Command[]{});
24+
}
25+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
import ch.qos.logback.classic.Level;
4+
import com.beust.jcommander.JCommander;
5+
import com.marklogic.appdeployer.AppConfig;
6+
import com.marklogic.appdeployer.DefaultAppConfigFactory;
7+
import com.marklogic.appdeployer.command.Command;
8+
import com.marklogic.appdeployer.command.CommandMapBuilder;
9+
import com.marklogic.appdeployer.impl.SimpleAppDeployer;
10+
import com.marklogic.mgmt.DefaultManageConfigFactory;
11+
import com.marklogic.mgmt.ManageClient;
12+
import com.marklogic.mgmt.ManageConfig;
13+
import com.marklogic.mgmt.admin.AdminConfig;
14+
import com.marklogic.mgmt.admin.AdminManager;
15+
import com.marklogic.mgmt.admin.DefaultAdminConfigFactory;
16+
import com.marklogic.mgmt.util.PropertySource;
17+
import com.marklogic.mgmt.util.SimplePropertySource;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
import java.io.FileInputStream;
22+
import java.io.IOException;
23+
import java.util.List;
24+
import java.util.Map;
25+
import java.util.Properties;
26+
import java.util.TreeMap;
27+
28+
public class Main {
29+
30+
private final static Logger logger = LoggerFactory.getLogger(Main.class);
31+
32+
/**
33+
* @param args
34+
*/
35+
public static void main(String[] args) throws IOException {
36+
Options options = new Options();
37+
JCommander.Builder builder = JCommander
38+
.newBuilder()
39+
.addObject(options);
40+
41+
addCommandsToBuilder(builder);
42+
43+
JCommander commander = builder.build();
44+
commander.setProgramName("java -jar <name of jar>");
45+
commander.parse(args);
46+
47+
String parsedCommand = commander.getParsedCommand();
48+
if (parsedCommand == null) {
49+
commander.usage();
50+
} else {
51+
ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
52+
root.setLevel(Level.toLevel(options.getLogLevel()));
53+
54+
JCommander parsedCommander = commander.getCommands().get(parsedCommand);
55+
CommandArray commandArray = (CommandArray) parsedCommander.getObjects().get(0);
56+
PropertySource propertySource = buildPropertySource(options);
57+
runCommand(commandArray, propertySource, options);
58+
}
59+
}
60+
61+
/**
62+
* Use CommandMapBuilder to construct the list of all known commands. Each will then be added to JCommander.
63+
*
64+
* @param builder
65+
*/
66+
private static void addCommandsToBuilder(JCommander.Builder builder) {
67+
CommandMapBuilder commandMapBuilder = new CommandMapBuilder();
68+
Map<String, List<Command>> commandMap = commandMapBuilder.buildCommandMap();
69+
70+
// Combine all commands into an ordered map so that usage() lists them in alphabetical order
71+
Map<String, CommandArray> orderedCommandMap = new TreeMap<>();
72+
orderedCommandMap.put("mlDeploy", new DeployCommand(commandMap));
73+
74+
for (String commandGroup : commandMap.keySet()) {
75+
for (Command command : commandMap.get(commandGroup)) {
76+
String className = command.getClass().getSimpleName();
77+
if (className.endsWith("Command")) {
78+
className = className.substring(0, className.length() - "Command".length());
79+
}
80+
orderedCommandMap.put("ml" + className, new CommandWrapper(command));
81+
}
82+
}
83+
84+
for (String commandName : orderedCommandMap.keySet()) {
85+
builder.addCommand(commandName, orderedCommandMap.get(commandName));
86+
}
87+
}
88+
89+
/**
90+
* Properties can be read from a properties file, and/or specified via the -P flag. If a file is specified, any
91+
* properties specified via -P will override what's in the properties file.
92+
*
93+
* @param options
94+
* @return
95+
* @throws IOException
96+
*/
97+
private static PropertySource buildPropertySource(Options options) throws IOException {
98+
final String propertiesFilePath = options.getPropertiesFilePath();
99+
if (propertiesFilePath != null) {
100+
Properties props = new Properties();
101+
if (logger.isInfoEnabled()) {
102+
logger.info("Reading properties from file path: " + propertiesFilePath);
103+
}
104+
FileInputStream fis = new FileInputStream(propertiesFilePath);
105+
try {
106+
props.load(fis);
107+
} finally {
108+
fis.close();
109+
}
110+
111+
// Dynamic params override what's in the properties file
112+
Map<String, String> params = options.getParams();
113+
if (params != null) {
114+
for (String key : params.keySet()) {
115+
props.setProperty(key, params.get(key));
116+
}
117+
}
118+
return new SimplePropertySource(props);
119+
} else {
120+
return (name) -> options.getParams().get(name);
121+
}
122+
}
123+
124+
/**
125+
* @param commandArray
126+
* @param propertySource
127+
* @param options
128+
*/
129+
private static void runCommand(CommandArray commandArray, PropertySource propertySource, Options options) {
130+
AppConfig appConfig = new DefaultAppConfigFactory(propertySource).newAppConfig();
131+
ManageConfig manageConfig = new DefaultManageConfigFactory(propertySource).newManageConfig();
132+
ManageClient manageClient = new ManageClient(manageConfig);
133+
AdminConfig adminConfig = new DefaultAdminConfigFactory(propertySource).newAdminConfig();
134+
AdminManager adminManager = new AdminManager(adminConfig);
135+
136+
SimpleAppDeployer deployer = new SimpleAppDeployer(manageClient, adminManager, commandArray.getCommands());
137+
if (options.isUndo()) {
138+
deployer.undeploy(appConfig);
139+
} else {
140+
deployer.deploy(appConfig);
141+
}
142+
}
143+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
import ch.qos.logback.classic.Level;
4+
import com.beust.jcommander.DynamicParameter;
5+
import com.beust.jcommander.Parameter;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
public class Options {
11+
12+
@Parameter(names = {"-f"}, description = "Path to properties file")
13+
private String propertiesFilePath;
14+
15+
@Parameter(names = {"-u"}, description = "Undo the given command (i.e. undeploy instead of deploy)")
16+
private boolean undo;
17+
18+
@Parameter(names = {"-l"}, description = "Log level, as defined by Logback")
19+
private String logLevel = Level.INFO.levelStr;
20+
21+
@DynamicParameter(names = "-P", description = "Use this argument to include any property defined by the ml-gradle Property Reference; e.g. -PmlAppName=example")
22+
private Map<String, String> params = new HashMap<>();
23+
24+
public Map<String, String> getParams() {
25+
return params;
26+
}
27+
28+
public void setParams(Map<String, String> params) {
29+
this.params = params;
30+
}
31+
32+
public String getPropertiesFilePath() {
33+
return propertiesFilePath;
34+
}
35+
36+
public void setPropertiesFilePath(String propertiesFilePath) {
37+
this.propertiesFilePath = propertiesFilePath;
38+
}
39+
40+
public boolean isUndo() {
41+
return undo;
42+
}
43+
44+
public void setUndo(boolean undo) {
45+
this.undo = undo;
46+
}
47+
48+
public String getLogLevel() {
49+
return logLevel;
50+
}
51+
52+
public void setLogLevel(String logLevel) {
53+
this.logLevel = logLevel;
54+
}
55+
}
56+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.marklogic.appdeployer.cli;
2+
3+
public class DeployerDebug {
4+
5+
public static void main(String[] args) throws Exception {
6+
args = new String[]{
7+
"-l", "info",
8+
"-PmlAppName=cli",
9+
"-PmlContentForestsPerHost=1",
10+
"-PmlConfigPath=src/test/resources/sample-app/db-only-config",
11+
"mlDeployContentDatabases"
12+
};
13+
14+
// args = new String[]{
15+
// "-f", "build/deployer.properties",
16+
// "-u",
17+
// "-l", "INFO",
18+
// "mlDeployContentDatabases"
19+
// };
20+
//args = new String[]{};
21+
Main.main(args);
22+
}
23+
}

0 commit comments

Comments
 (0)