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

Commit 1a41b09

Browse files
author
juvester
committed
Merge branch 'master' of github.com:tmc-cli/tmc-cli into update-dont-dl-completed-juha
2 parents 4b246aa + d2aa5b3 commit 1a41b09

18 files changed

Lines changed: 373 additions & 88 deletions

HACKING.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ public class ExampleCommand extends AbstractCommand {
3131

3232
## Architecture
3333
...
34+
35+
## Debugging
36+
### Logging

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ Now that you've installed tmc-cli, you can view all available commands by runnin
4646
Once installation is complete, you can log in using `tmc login`. This saves your TMC login information to a configuration file in ~/.config/tmc-cli/ (or %LOCALAPPDATA% on Windows) - you will only have to log in once.
4747
```
4848
~ $ tmc login
49-
username: my-username
50-
password:
5149
server address:
50+
username:
51+
password:
5252
Login successful.
5353
```
5454

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>fi.helsinki.cs.tmc.cli</groupId>
55
<artifactId>tmc-cli</artifactId>
6-
<version>0.5.2</version>
6+
<version>0.6.0</version>
77
<packaging>jar</packaging>
88
<properties>
99
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

src/main/java/fi/helsinki/cs/tmc/cli/Application.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,10 @@ public void setWorkdir(WorkDir workDir) {
246246
this.workDir = workDir;
247247
}
248248

249+
public void setTmcProjectDirectory(Path path) {
250+
this.settings.setTmcProjectDirectory(path);
251+
}
252+
249253
public HashMap<String, String> getProperties() {
250254
// Loads properties from the global configuration file in .config/tmc-cli/
251255
return this.properties;

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

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package fi.helsinki.cs.tmc.cli.command;
22

3+
import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_BLUE;
4+
import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_GREEN;
5+
import static fi.helsinki.cs.tmc.cli.io.Color.AnsiColor.ANSI_RED;
6+
37
import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand;
48
import fi.helsinki.cs.tmc.cli.command.core.Command;
9+
import fi.helsinki.cs.tmc.cli.io.Color;
510
import fi.helsinki.cs.tmc.cli.io.Io;
611
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo;
712
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo;
@@ -53,13 +58,13 @@ public void run(CommandLine args, Io io) {
5358
if (workDir.getExerciseNames().size() == 1 && stringArgs.length == 0) {
5459
String currentExercise = workDir.getExerciseNames().get(0);
5560
exercise = info.getExercise(currentExercise);
56-
printExerciseDetails();
61+
printOneExercise(args.hasOption("a"));
5762
return;
5863

5964
} else if (stringArgs.length != 0) {
6065
if (info.getExercise(stringArgs[0]) != null) {
6166
exercise = info.getExercise(stringArgs[0]);
62-
printExerciseDetails();
67+
printOneExercise(args.hasOption("a"));
6368
return;
6469

6570
} else {
@@ -109,11 +114,32 @@ private void printCourseDetails() {
109114
io.println("CometUrl: " + course.getCometUrl());
110115
}
111116

112-
private void printExerciseDetails() {
113-
io.println(exercise.getName());
114-
io.println("Completed: " + exercise.isCompleted());
115-
io.println("Attempted: " + exercise.isAttempted());
116-
io.println("Deadline: " + exercise.getDeadline());
117+
private void printOneExercise(boolean showAll) {
118+
if (showAll) {
119+
printExercise(exercise);
120+
} else {
121+
printExerciseShort();
122+
}
123+
}
124+
125+
private void printExerciseShort() {
126+
io.println("Exercise: " + exercise.getName());
127+
io.println("Deadline: " + getDeadline(exercise));
128+
io.println(formatString("completed", exercise.isCompleted()));
129+
if (!exercise.isCompleted() && exercise.isAttempted()) {
130+
io.println(Color.colorString("attempted", ANSI_BLUE));
131+
}
132+
if (exercise.requiresReview()) {
133+
io.println(formatString("reviewed", exercise.isReviewed()));
134+
}
135+
}
136+
137+
private String formatString(String string, boolean color) {
138+
if (color) {
139+
return Color.colorString(string, ANSI_GREEN);
140+
} else {
141+
return Color.colorString("not " + string, ANSI_RED);
142+
}
117143
}
118144

119145
private void printExercises(boolean showAll) {
@@ -169,4 +195,13 @@ private void printExercise(Exercise exercise) {
169195
io.println(" Checksum: " + exercise.getChecksum());
170196
io.println("");
171197
}
198+
199+
private String getDeadline(Exercise exercise) {
200+
String deadline = exercise.getDeadline();
201+
if (deadline == null) {
202+
return "not available";
203+
}
204+
deadline = deadline.substring(0, 19);
205+
return deadline.replace("T", " at ");
206+
}
172207
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ public void getOptions(Options options) {
3636
@Override
3737
public void run(CommandLine args, Io io) {
3838
this.io = io;
39+
String serverAddress = getLoginInfo(args, "s", "server address: ");
3940
String username = getLoginInfo(args, "u", "username: ");
4041
String password = getLoginInfo(args, "p", "password: ");
41-
String serverAddress = getLoginInfo(args, "s", "server address: ");
42-
42+
4343
Settings settings = new Settings(serverAddress, username, password);
4444
if (loginPossible(settings) && saveLoginSettings(settings)) {
4545
io.println("Login successful.");

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

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package fi.helsinki.cs.tmc.cli.command;
22

3+
import static fi.helsinki.cs.tmc.langs.domain.RunResult.Status.PASSED;
4+
35
import fi.helsinki.cs.tmc.cli.Application;
46
import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand;
57
import fi.helsinki.cs.tmc.cli.command.core.Command;
68
import fi.helsinki.cs.tmc.cli.io.Color;
79
import fi.helsinki.cs.tmc.cli.io.Io;
810
import fi.helsinki.cs.tmc.cli.io.ResultPrinter;
911
import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver;
12+
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo;
1013
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfoIo;
1114
import fi.helsinki.cs.tmc.cli.tmcstuff.Settings;
1215
import fi.helsinki.cs.tmc.cli.tmcstuff.WorkDir;
@@ -25,6 +28,7 @@
2528
import java.nio.file.Path;
2629
import java.util.List;
2730

31+
2832
@Command(name = "test", desc = "Run local exercise tests")
2933
public class RunTestsCommand extends AbstractCommand {
3034

@@ -58,13 +62,13 @@ public void run(CommandLine args, Io io) {
5862
return;
5963
}
6064
}
61-
String courseName = getCourseName(workDir);
6265
List<String> exerciseNames = workDir.getExerciseNames();
6366

6467
if (exerciseNames.isEmpty()) {
6568
io.println("You have to be in a course directory to run tests");
6669
return;
6770
}
71+
CourseInfo info = CourseInfoIo.load(workDir.getConfigFile());
6872

6973
// Local tests don't require login so make sure tmcCore is never null.
7074
app.createTmcCore(new Settings());
@@ -90,16 +94,30 @@ public void run(CommandLine args, Io io) {
9094

9195
io.println(Color.colorString("Testing: " + name, Color.AnsiColor.ANSI_YELLOW));
9296
//name = name.replace("-", File.separator);
93-
Exercise exercise = new Exercise(name, courseName);
97+
Exercise exercise = info.getExercise(name);
98+
// Exercise exercise = new Exercise(name, courseName);
9499

95100
// TmcCliProgressObserver progobs = new TmcCliProgressObserver(io);
96101
runResult = core.runTests(ProgressObserver.NULL_OBSERVER, exercise).call();
97102
// progobs.end(0);
98103

99-
resultPrinter.printRunResult(runResult, isOnlyExercise, color1, color2);
104+
resultPrinter.printRunResult(runResult, exercise.isCompleted(),
105+
isOnlyExercise, color1, color2);
100106
total += runResult.testResults.size();
101107
passed += ResultPrinter.passedTests(runResult.testResults);
108+
exercise.setAttempted(true);
109+
if (runResult.status == PASSED && !exercise.isCompleted()) {
110+
// add exercise to locally tested exercises
111+
if (!info.getLocalCompletedExercises().contains(exercise.getName())) {
112+
info.getLocalCompletedExercises().add(exercise.getName());
113+
}
114+
} else {
115+
if (info.getLocalCompletedExercises().contains(exercise.getName())) {
116+
info.getLocalCompletedExercises().remove(exercise.getName());
117+
}
118+
}
102119
}
120+
CourseInfoIo.save(info, workDir.getConfigFile());
103121
if (total > 0 && !isOnlyExercise) {
104122
// Print a progress bar showing how the ratio of passed exercises
105123
// But only if more than one exercise was tested
@@ -115,15 +133,6 @@ public void run(CommandLine args, Io io) {
115133
}
116134
}
117135

118-
private String getCourseName(WorkDir dirUtil) {
119-
Path courseDir = dirUtil.getCourseDirectory();
120-
try {
121-
return courseDir.getName(courseDir.getNameCount() - 1).toString();
122-
} catch (Exception e) {
123-
}
124-
return null;
125-
}
126-
127136
private String[] parseArgs(CommandLine args) {
128137
this.showPassed = args.hasOption("a");
129138
this.showDetails = args.hasOption("d");

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

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fi.helsinki.cs.tmc.cli.command;
22

3+
import static fi.helsinki.cs.tmc.core.domain.submission.SubmissionResult.TestResultStatus.NONE_FAILED;
4+
35
import fi.helsinki.cs.tmc.cli.Application;
46
import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand;
57
import fi.helsinki.cs.tmc.cli.command.core.Command;
@@ -38,6 +40,8 @@ public class SubmitCommand extends AbstractCommand {
3840
public void getOptions(Options options) {
3941
options.addOption("a", "all", false, "Show all test results");
4042
options.addOption("d", "details", false, "Show detailed error message");
43+
options.addOption("c", "completed", false,
44+
"Filter out exercises that haven't been locally tested");
4145
}
4246

4347
@Override
@@ -58,14 +62,25 @@ public void run(CommandLine args, Io io) {
5862
WorkDir workDir = app.getWorkDir();
5963
for (String exercise : exercisesFromArgs) {
6064
if (!workDir.addPath(exercise)) {
61-
io.println("Error: '" + exercise + "' is not a valid exercise.");
65+
io.println("Error: " + exercise + " is not a valid exercise.");
6266
return;
6367
}
6468
}
6569

66-
List<String> exerciseNames = workDir.getExerciseNames();
70+
List<String> exerciseNames;
71+
if (args.hasOption("c")) {
72+
workDir.addPath(workDir.getCourseDirectory());
73+
exerciseNames = workDir.getExerciseNames(true, true, false);
74+
} else {
75+
exerciseNames = workDir.getExerciseNames();
76+
}
77+
6778
if (exerciseNames.isEmpty()) {
68-
io.println("You have to be in a course directory to submit");
79+
if (args.hasOption("c") && workDir.getCourseDirectory() != null) {
80+
io.println("No locally tested exercises.");
81+
return;
82+
}
83+
io.println("No exercises specified.");
6984
return;
7085
}
7186

@@ -95,8 +110,17 @@ public void run(CommandLine args, Io io) {
95110
resultPrinter.printSubmissionResult(result, isOnlyExercise, color1, color2);
96111
total += result.getTestCases().size();
97112
passed += ResultPrinter.passedTests(result.getTestCases());
113+
114+
exercise.setAttempted(true);
115+
if (result.getTestResultStatus() == NONE_FAILED) {
116+
if (info.getLocalCompletedExercises().contains(exercise.getName())) {
117+
info.getLocalCompletedExercises().remove(exercise.getName());
118+
}
119+
exercise.setCompleted(true);
120+
}
98121
}
99122
}
123+
CourseInfoIo.save(info, workDir.getConfigFile());
100124
if (total > 0 && !isOnlyExercise) {
101125
// Print a progress bar showing how the ratio of passed exercises
102126
io.println("");

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import fi.helsinki.cs.tmc.cli.command.core.AbstractCommand;
44
import fi.helsinki.cs.tmc.cli.command.core.Command;
5+
import fi.helsinki.cs.tmc.cli.io.Color;
56
import fi.helsinki.cs.tmc.cli.io.Io;
67
import fi.helsinki.cs.tmc.cli.io.TmcCliProgressObserver;
78
import fi.helsinki.cs.tmc.cli.tmcstuff.CourseInfo;
@@ -65,8 +66,10 @@ public void updateExercises(TmcCore core, CourseInfo info, Path configFile) {
6566
printExercises(exerciseUpdater.getUpdatedExercises(), "Modified exercises:");
6667
io.println("");
6768

69+
Color.AnsiColor color1 = getApp().getColor("progressbar-left");
70+
Color.AnsiColor color2 = getApp().getColor("progressbar-right");
6871
List<Exercise> downloaded = exerciseUpdater.downloadUpdates(
69-
new TmcCliProgressObserver(io));
72+
new TmcCliProgressObserver(io, color1, color2));
7073
if (downloaded.isEmpty()) {
7174
io.println("Failed to download exercises");
7275
return;

src/main/java/fi/helsinki/cs/tmc/cli/command/core/CommandAnnotationProcessor.java

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,38 +30,32 @@ public class CommandAnnotationProcessor extends AbstractProcessor {
3030
private static final Logger logger = LoggerFactory.getLogger(CommandAnnotationProcessor.class);
3131

3232
private static final String CLASS_NAME = "CommandList";
33-
private static final String PACKAGE_NAME = "fi.helsinki.cs.tmc.cli.command";
33+
private static final String PACKAGE_NAME = "fi.helsinki.cs.tmc.cli.command.core";
3434
private static final String TAB = " ";
3535

36-
private ProcessingEnvironment processingEnv;
37-
38-
@Override
39-
public void init(ProcessingEnvironment processingEnv) {
40-
this.processingEnv = processingEnv;
41-
}
42-
4336
private void generateSourceFile(Map<String, String> map) throws IOException {
4437
JavaFileObject jfo = processingEnv.getFiler().createSourceFile(
45-
PACKAGE_NAME + ".core." + CLASS_NAME);
38+
PACKAGE_NAME + "." + CLASS_NAME);
4639

4740
try (Writer writer = jfo.openWriter()) {
4841
BufferedWriter bwriter = new BufferedWriter(writer);
49-
bwriter.append("package ");
50-
bwriter.append(PACKAGE_NAME);
51-
bwriter.append(".core;\n\n");
42+
bwriter.append("package " + PACKAGE_NAME + ";\n\n");
43+
44+
// import the command classes
5245
bwriter.append("//CHECKSTYLE:OFF\n");
53-
bwriter.append("import " + PACKAGE_NAME + ".core.CommandFactory;\n\n");
5446
for (Entry<String, String> entry : map.entrySet()) {
5547
bwriter.append("import " + entry.getValue() + ";\n");
5648
}
5749
bwriter.append("//CHECKSTYLE:ON\n");
50+
5851
bwriter.append("\npublic class " + CLASS_NAME + " {\n");
5952
bwriter.append(TAB + "static {\n");
6053
for (Entry<String, String> entry : map.entrySet()) {
6154
String[] parts = entry.getValue().split("\\.");
6255
if (parts.length == 0) {
6356
continue;
6457
}
58+
// print out the lines that add the commands to the command factory.
6559
String className = parts[parts.length - 1];
6660
bwriter.append(TAB + TAB + "CommandFactory.addCommand(\""
6761
+ entry.getKey() + "\", "
@@ -76,15 +70,15 @@ private void generateSourceFile(Map<String, String> map) throws IOException {
7670
@Override
7771
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
7872
Map<String, String> map = new HashMap<>();
79-
Messager messager = processingEnv.getMessager();
8073

8174
for (Element elem : roundEnv.getElementsAnnotatedWith(Command.class)) {
8275
if (elem.getKind() != ElementKind.CLASS) {
83-
continue;
76+
logger.warn("Element with command annotation is not class: " + elem.toString());
77+
return false;
8478
}
8579
Command command = elem.getAnnotation(Command.class);
86-
messager.printMessage(Diagnostic.Kind.NOTE, elem.toString());
87-
messager.printMessage(Diagnostic.Kind.NOTE, elem.getClass().getCanonicalName());
80+
logger.info("element with annotation: " + elem.toString());
81+
logger.info("element name with annotation: " + elem.getClass().getCanonicalName());
8882

8983
TypeElement classElement = (TypeElement) elem;
9084
map.put(command.name(), processingEnv.getElementUtils()
@@ -94,7 +88,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
9488
try {
9589
generateSourceFile(map);
9690
} catch (IOException ex) {
97-
messager.printMessage(Diagnostic.Kind.NOTE, "Failed to create source file." + ex);
91+
logger.warn("Failed to create source file." + ex);
9892
}
9993
return true;
10094
}

0 commit comments

Comments
 (0)