31
31
import java .nio .charset .StandardCharsets ;
32
32
import java .nio .file .FileVisitResult ;
33
33
import java .nio .file .Files ;
34
+ import java .nio .file .LinkOption ;
34
35
import java .nio .file .Path ;
35
36
import java .nio .file .Paths ;
36
37
import java .nio .file .SimpleFileVisitor ;
@@ -49,9 +50,9 @@ public final class QmakePlugin extends AbstractLanguagePlugin {
49
50
50
51
private static final Path TMC_TEST_RESULTS = Paths .get ("tmc_test_results.xml" );
51
52
52
- // Finds pattern 'POINT(exercise_name, 1)'
53
+ // Finds pattern 'POINT(exercise_name, 1.1 )'
53
54
private static final Pattern POINT_PATTERN
54
- = Pattern .compile ("POINT\\ (\\ s*(\\ w+),\\ s*(\\ w +)\\ s*\\ )\\ s*;" );
55
+ = Pattern .compile ("POINT\\ (\\ s*(\\ w+),\\ s*([^ \\ s| \\ )] +)\\ s*\\ )\\ s*;" );
55
56
// Pattern to find comments
56
57
private static final Pattern COMMENT_PATTERN
57
58
= Pattern .compile ("(^[^\" \\ r\\ n]*\\ /\\ *{1,2}.*?\\ *\\ /"
@@ -79,8 +80,9 @@ public String getPluginName() {
79
80
* Resolve the exercise .pro file from exercise directory. The file should
80
81
* be named after the directory.
81
82
*/
82
- private Path getProFile (Path basePath ) {
83
- return Paths .get (basePath .toString () + "/" + basePath .getFileName () + ".pro" );
83
+ private Path getProFile (Path basePath ) throws IOException {
84
+ Path fullPath = basePath .toRealPath (LinkOption .NOFOLLOW_LINKS );
85
+ return fullPath .resolve (fullPath .getFileName () + ".pro" );
84
86
}
85
87
86
88
@ Override
@@ -101,7 +103,11 @@ public Optional<ExerciseDesc> scanExercise(Path path, String exerciseName) {
101
103
102
104
@ Override
103
105
public boolean isExerciseTypeCorrect (Path path ) {
104
- return Files .isRegularFile (getProFile (path ));
106
+ try {
107
+ return Files .isRegularFile (getProFile (path ));
108
+ } catch (IOException e ) {
109
+ return false ;
110
+ }
105
111
}
106
112
107
113
/**
@@ -121,31 +127,45 @@ protected StudentFilePolicy getStudentFilePolicy(Path projectPath) {
121
127
122
128
@ Override
123
129
public RunResult runTests (Path path ) {
124
- Path shadowDir = makeShadowBuildDir (path );
130
+ Path fullPath ;
131
+ try {
132
+ fullPath = path .toRealPath (LinkOption .NOFOLLOW_LINKS );
133
+ } catch (IOException e ) {
134
+ log .error ("Exercise directory not found" , e );
135
+ return filledFailure (Status .GENERIC_ERROR , "Exercise directory not found" );
136
+ }
137
+
138
+ Path shadowDir ;
139
+ try {
140
+ shadowDir = makeShadowBuildDir (fullPath );
141
+ } catch (IOException e ) {
142
+ log .error ("Preparing exercise failed" , e );
143
+ return filledFailure (Status .GENERIC_ERROR , "Could not create build directory" );
144
+ }
125
145
126
146
try {
127
147
ProcessResult qmakeBuild = buildWithQmake (shadowDir );
128
148
if (qmakeBuild .statusCode != 0 ) {
129
149
log .error ("Building project with qmake failed: {}" , qmakeBuild .errorOutput );
130
- return filledFailure (qmakeBuild .errorOutput );
150
+ return filledFailure (Status . COMPILE_FAILED , qmakeBuild .errorOutput );
131
151
}
132
152
} catch (IOException | InterruptedException e ) {
133
153
log .error ("Building project with qmake failed" , e );
134
- throw new QmakeBuildException ( e );
154
+ return filledFailure ( Status . GENERIC_ERROR , "Building project with qmake failed" );
135
155
}
136
156
137
157
try {
138
158
ProcessResult makeBuild = buildWithMake (shadowDir );
139
159
if (makeBuild .statusCode != 0 ) {
140
160
log .error ("Building project with make failed: {}" , makeBuild .errorOutput );
141
- return filledFailure (makeBuild .errorOutput );
161
+ return filledFailure (Status . COMPILE_FAILED , makeBuild .errorOutput );
142
162
}
143
163
} catch (IOException | InterruptedException e ) {
144
164
log .error ("Building project with make failed" , e );
145
- throw new QmakeBuildException ( e );
165
+ return filledFailure ( Status . GENERIC_ERROR , "Building project with make failed" );
146
166
}
147
167
148
- Path testResults = path .resolve (TMC_TEST_RESULTS );
168
+ Path testResults = shadowDir .resolve (TMC_TEST_RESULTS );
149
169
150
170
String target = "check" ;
151
171
String config = "TESTARGS=-o " + testResults .toString () + ",xml" ;
@@ -158,11 +178,11 @@ public RunResult runTests(Path path) {
158
178
159
179
if (!Files .exists (testResults )) {
160
180
log .error ("Failed to get test output at {}" , testResults );
161
- return filledFailure (testRun .output );
181
+ return filledFailure (Status . GENERIC_ERROR , testRun .output );
162
182
}
163
183
} catch (IOException | InterruptedException e ) {
164
184
log .error ("Testing with make check failed" , e );
165
- throw new QmakeBuildException ( e );
185
+ return filledFailure ( Status . GENERIC_ERROR , "Testing with make check failed" );
166
186
}
167
187
168
188
QTestResultParser parser = new QTestResultParser ();
@@ -185,11 +205,18 @@ public Map<File, List<ValidationError>> getValidationErrors() {
185
205
};
186
206
}
187
207
188
- private Path makeShadowBuildDir (Path dir ) {
189
- File buildDir = dir .resolve ("build" ).toFile ();
208
+ private Path makeShadowBuildDir (Path dir ) throws IOException {
209
+ Path shadowPath = dir .resolve ("build" );
210
+ if (Files .exists (shadowPath )) {
211
+ log .info ("Shadow dir already exists at {}" , shadowPath );
212
+ return shadowPath ;
213
+ }
214
+
215
+ File buildDir = shadowPath .toFile ();
216
+
190
217
log .info ("Making shadow build dir to {}" , buildDir .toPath ());
191
218
if (!buildDir .mkdirs ()) {
192
- throw new RuntimeException (
219
+ throw new IOException (
193
220
"Unable to create shadow build directory: "
194
221
+ buildDir .toPath ());
195
222
}
@@ -231,13 +258,13 @@ private ProcessResult run(String[] command, Path dir) throws IOException, Interr
231
258
return runner .call ();
232
259
}
233
260
234
- private RunResult filledFailure (String output ) {
261
+ private RunResult filledFailure (Status status , String output ) {
235
262
byte [] errorOutput = output .getBytes (StandardCharsets .UTF_8 );
236
263
ImmutableMap <String , byte []> logs
237
264
= new ImmutableMap .Builder ()
238
265
.put (SpecialLogs .COMPILER_OUTPUT , errorOutput )
239
266
.<String , byte []>build ();
240
- return new RunResult (Status . COMPILE_FAILED , ImmutableList .<TestResult >of (), logs );
267
+ return new RunResult (status , ImmutableList .<TestResult >of (), logs );
241
268
}
242
269
243
270
/**
0 commit comments