Skip to content
This repository was archived by the owner on Jun 3, 2025. It is now read-only.

Commit df89b33

Browse files
author
Aleksi Salmela
committed
Implement config command.
This is replacement for the prop command with bit more conventional syntax. I will remove the old prop comamnd completely at some point.
1 parent cfa6c2a commit df89b33

File tree

3 files changed

+299
-0
lines changed

3 files changed

+299
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
package fi.helsinki.cs.tmc.cli.command;
2+
3+
import fi.helsinki.cs.tmc.cli.core.AbstractCommand;
4+
import fi.helsinki.cs.tmc.cli.core.CliContext;
5+
import fi.helsinki.cs.tmc.cli.core.Command;
6+
import fi.helsinki.cs.tmc.cli.io.Io;
7+
8+
import org.apache.commons.cli.CommandLine;
9+
import org.apache.commons.cli.Options;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import java.util.ArrayList;
14+
import java.util.Collections;
15+
import java.util.HashMap;
16+
17+
@Command(name = "config", desc = "Set/unset TMC-CLI properties")
18+
public class ConfigCommand extends AbstractCommand {
19+
20+
private static final Logger logger = LoggerFactory.getLogger(ConfigCommand.class);
21+
private CliContext context;
22+
private Io io;
23+
24+
private HashMap<String, String> properties;
25+
private boolean quiet;
26+
27+
@Override
28+
public String[] getUsages() {
29+
return new String[] {"[-q|--quiet] KEY=\"VALUE\"...", "-d [-q|--quiet] KEY...", "-l"};
30+
}
31+
32+
@Override
33+
public void getOptions(Options options) {
34+
options.addOption("g", "get", false, "Get value of a key");
35+
options.addOption("d", "delete", false, "Unset given property keys");
36+
options.addOption("q", "quiet", false, "Don't ask confirmations");
37+
options.addOption("l", "list", false, "List all properties");
38+
}
39+
40+
@Override
41+
public void run(CliContext context, CommandLine args) {
42+
this.context = context;
43+
this.io = context.getIo();
44+
45+
boolean get = args.hasOption("g");
46+
boolean listing = args.hasOption("l");
47+
boolean delete = args.hasOption("d");
48+
this.quiet = args.hasOption("q");
49+
50+
String[] arguments = args.getArgs();
51+
this.properties = context.getProperties();
52+
53+
if ((get ? 1 : 0) + (listing ? 1 : 0) + (delete ? 1 : 0) > 1) {
54+
io.errorln("Only one of the --get or --list or --delete options can "
55+
+ "be used at same time.");
56+
printUsage(context);
57+
return;
58+
}
59+
60+
if (listing) {
61+
if (arguments.length != 0) {
62+
io.errorln("Listing option doesn't take any arguments.");
63+
return;
64+
}
65+
printAllProperties();
66+
return;
67+
}
68+
69+
if (delete) {
70+
deleteProperties(arguments);
71+
} else {
72+
setProperties(arguments);
73+
}
74+
context.saveProperties();
75+
}
76+
77+
private void printAllProperties() {
78+
ArrayList<String> array = new ArrayList<>(properties.keySet());
79+
Collections.sort(array);
80+
81+
for (String key : array) {
82+
io.println(key + "=" + properties.get(key));
83+
}
84+
}
85+
86+
private void deleteProperties(String[] keys) {
87+
if (this.quiet) {
88+
for (String key : keys) {
89+
if (properties.containsKey(key)) {
90+
properties.remove(key);
91+
}
92+
}
93+
return;
94+
}
95+
96+
if (keys.length == 0) {
97+
io.errorln("Expected at least one property as argument.");
98+
printUsage(context);
99+
return;
100+
}
101+
102+
for (String key : keys) {
103+
if (!properties.containsKey(key)) {
104+
io.error("Key " + key + " doesn't exist.");
105+
return;
106+
}
107+
}
108+
109+
io.println("Deleting " + keys.length + " properties.");
110+
111+
if (!io.readConfirmation("Are you sure?", true)) {
112+
return;
113+
}
114+
for (String key : keys) {
115+
String oldValue = properties.remove(key);
116+
io.println("Unset key " + key + ", was " + oldValue);
117+
}
118+
}
119+
120+
private void setProperties(String[] arguments) {
121+
if (arguments.length == 0) {
122+
io.errorln("Expected at least one key-value pair.");
123+
printUsage(context);
124+
return;
125+
}
126+
127+
if (this.quiet) {
128+
setPropertiesQuietly(arguments);
129+
return;
130+
}
131+
132+
io.print("Setting property keys:");
133+
for (String argument : arguments) {
134+
String[] parts = argument.split("=", 2);
135+
String oldValue = properties.get(parts[0]);
136+
io.print(" " + parts[0] + " set to \"" + parts[1] + "\"");
137+
138+
if (oldValue != null) {
139+
io.println(", it was \"" + oldValue + "\".");
140+
} else {
141+
io.println(".");
142+
}
143+
}
144+
io.println();
145+
if (!io.readConfirmation("Are you sure?", true)) {
146+
return;
147+
}
148+
149+
setPropertiesQuietly(arguments);
150+
}
151+
152+
private void setPropertiesQuietly(String[] arguments) {
153+
for (String argument : arguments) {
154+
String[] parts = argument.split("=", 2);
155+
properties.put(parts[0], parts[1]);
156+
}
157+
}
158+
}

src/main/java/fi/helsinki/cs/tmc/cli/command/PropertiesCommand.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ public void run(CliContext context, CommandLine args) {
3737
boolean unset = args.hasOption("u");
3838
String[] arguments = args.getArgs();
3939
HashMap<String, String> props = context.getProperties();
40+
41+
io.errorln("This is deprecated command; use config command instead.");
42+
4043
if (arguments.length == 0) {
4144
printAllProps(props);
4245
return;
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package fi.helsinki.cs.tmc.cli.command;
2+
3+
import static org.junit.Assert.assertEquals;
4+
import static org.junit.Assert.assertTrue;
5+
import static org.mockito.Mockito.when;
6+
7+
import fi.helsinki.cs.tmc.cli.Application;
8+
import fi.helsinki.cs.tmc.cli.core.CliContext;
9+
import fi.helsinki.cs.tmc.cli.io.TestIo;
10+
11+
import org.junit.Before;
12+
import org.junit.Test;
13+
import org.mockito.Mockito;
14+
15+
import java.util.HashMap;
16+
17+
public class ConfigCommandTest {
18+
19+
private Application app;
20+
private TestIo io;
21+
private HashMap<String, String> props;
22+
23+
@Before
24+
public void setup() {
25+
io = new TestIo();
26+
CliContext ctx = Mockito.spy(new CliContext(io));
27+
app = new Application(ctx);
28+
29+
when(ctx.saveProperties()).thenReturn(true);
30+
props = new HashMap<>();
31+
when(ctx.getProperties()).thenReturn(props);
32+
}
33+
34+
@Test
35+
public void printsErrorIfNoArgumentsGiven() {
36+
app.run(new String[] {"config"});
37+
io.assertContains("Expected at least one key-value pair.");
38+
}
39+
40+
@Test
41+
public void printsErrorIfTwoConflictingOptionsGiven() {
42+
app.run(new String[] {"config", "--get", "--list"});
43+
io.assertContains("Only one of the");
44+
}
45+
46+
@Test
47+
public void printsErrorIfThreeConflictingOptionsGiven() {
48+
app.run(new String[] {"config", "--get", "--list", "--delete"});
49+
io.assertContains("Only one of the");
50+
}
51+
52+
@Test
53+
public void listsAllProperties() {
54+
props.put("hello", "world");
55+
props.put("toilet", "wonderland");
56+
app.run(new String[] {"config", "--list"});
57+
io.assertContains("hello=world");
58+
io.assertContains("toilet=wonderland");
59+
}
60+
61+
@Test
62+
public void setsOnePropertyWhenNoOptionsGiven() {
63+
io.addConfirmationPrompt(true);
64+
app.run(new String[] {"config", "cool=yeah"});
65+
assertTrue(props.containsKey("cool"));
66+
assertTrue(props.containsValue("yeah"));
67+
io.assertContains(" cool set to \"yeah\".");
68+
io.assertAllPromptsUsed();
69+
}
70+
71+
@Test
72+
public void setsOnePropertyQuietly() {
73+
app.run(new String[] {"config", "-q", "cool=yeah"});
74+
assertTrue(props.containsKey("cool"));
75+
assertTrue(props.containsValue("yeah"));
76+
io.assertNotContains(" cool set to \"yeah\".");
77+
io.assertAllPromptsUsed();
78+
}
79+
80+
@Test
81+
public void setsOneExistingProperty() {
82+
io.addConfirmationPrompt(true);
83+
props.put("cool", "old");
84+
app.run(new String[] {"config", "cool=yeah"});
85+
assertTrue(props.containsKey("cool"));
86+
assertTrue(props.containsValue("yeah"));
87+
io.assertContains(" cool set to \"yeah\", it was \"old\".");
88+
io.assertAllPromptsUsed();
89+
}
90+
91+
@Test
92+
public void setsMultiplePropertiesCorrectly() {
93+
io.addConfirmationPrompt(true);
94+
app.run(new String[] {"config", "cool=yeah", "hello=world"});
95+
assertEquals("yeah", props.get("cool"));
96+
assertEquals("world", props.get("hello"));
97+
io.assertAllPromptsUsed();
98+
}
99+
100+
@Test
101+
public void deletesZeroProperties() {
102+
app.run(new String[] {"config", "-d"});
103+
io.assertContains("Expected at least one property as argument.");
104+
io.assertAllPromptsUsed();
105+
}
106+
107+
@Test
108+
public void deletesOneProperty() {
109+
io.addConfirmationPrompt(true);
110+
props.put("no", "e");
111+
app.run(new String[] {"config", "-d", "no"});
112+
assertTrue(!props.containsKey("no"));
113+
io.assertContains("Deleting 1 properties.");
114+
io.assertAllPromptsUsed();
115+
}
116+
117+
@Test
118+
public void deletesOnePropertyQuietly() {
119+
props.put("no", "e");
120+
app.run(new String[] {"config", "-d", "-q", "no"});
121+
assertTrue(!props.containsKey("no"));
122+
io.assertAllPromptsUsed();
123+
}
124+
125+
@Test
126+
public void deletesMultiplePropertiesCorrectly() {
127+
io.addConfirmationPrompt(true);
128+
props.put("biggie", "smalls");
129+
props.put("snoop", "dogg");
130+
props.put("some", "thing");
131+
app.run(new String[] {"config", "-d", "biggie", "snoop"});
132+
assertTrue(!props.containsKey("biggie"));
133+
assertTrue(!props.containsKey("snoop"));
134+
assertTrue(props.containsKey("some"));
135+
assertEquals("thing", props.get("some"));
136+
io.assertAllPromptsUsed();
137+
}
138+
}

0 commit comments

Comments
 (0)