Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Fix rust language support #102

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,10 @@
<module>build-tools</module>
<module>tmc-langs-framework</module>
<module>tmc-langs-java</module>
<module>tmc-langs-make</module>
<!-- <module>tmc-langs-make</module> -->
<module>tmc-langs-python3</module>
<module>tmc-langs-notests</module>
<!--module>tmc-langs-rust</module-->
<module>tmc-langs-rust</module>
<module>tmc-langs-qmake</module>
<!-- TODO: add plugins and support libraries here -->

Expand Down
8 changes: 7 additions & 1 deletion tmc-langs-rust/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>fi.helsinki.cs.tmc</groupId>
<artifactId>tmc-langs</artifactId>
<version>0.7.15-SNAPSHOT</version>
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<tmc.basedir>../target</tmc.basedir>
Expand All @@ -29,7 +35,7 @@
<dependency>
<groupId>fi.helsinki.cs.tmc</groupId>
<artifactId>tmc-langs-framework</artifactId>
<version>0.1.3-SNAPSHOT</version>
<version>${project.version}</version>
<type>jar</type>
</dependency>
</dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,21 @@ public class CargoPlugin extends AbstractLanguagePlugin {
private static final Logger log = LoggerFactory.getLogger(CargoPlugin.class);
private static final RunResult EMPTY_FAILURE =
new RunResult(
Status.COMPILE_FAILED,
ImmutableList.<TestResult>of(),
new ImmutableMap.Builder<String, byte[]>().build());
Status.COMPILE_FAILED,
ImmutableList.<TestResult>of(),
new ImmutableMap.Builder<String, byte[]>().build()
);

/**
* Creates new plugin for cargo with all default stuff set.
*/
public CargoPlugin() {
super(
new ExerciseBuilder(),
new StudentFileAwareSubmissionProcessor(),
new StudentFileAwareZipper(),
new StudentFileAwareUnzipper());
new ExerciseBuilder(),
new StudentFileAwareSubmissionProcessor(),
new StudentFileAwareZipper(),
new StudentFileAwareUnzipper()
);
}

@Override
Expand All @@ -64,19 +66,32 @@ protected StudentFilePolicy getStudentFilePolicy(Path projectPath) {
@Override
public ValidationResult checkCodeStyle(Path path, Locale locale) {
if (run(new String[] {"cargo", "clean"}, path).isPresent()) {
String[] command = {"cargo", "rustc", "--", "--forbid", "warnings"};
String[] command = {
"cargo" , "rustc", "--message-format", "json"
};
log.info("Building for lints with command {}", Arrays.deepToString(command));
Optional<ProcessResult> result = run(command, path);
if (result.isPresent()) {
return parseLints(result.get());
ValidationResult validationResult = parseLints(result.get());
if (validationResult.getValidationErrors().isEmpty()) {
String[] command2 = {
"cargo" , "rustc", "--message-format", "json", "--", "--forbid", "warnings"
};
log.info("Ensuring that lints are not being dissabled {}", Arrays.deepToString(command2));
Optional<ProcessResult> result2 = run(command, path);
if (result2.isPresent()) {
return parseLints(result2.get());
}
}
return validationResult;
}
}
log.error("Build for lints failed.");
return null;
}

public String getLanguageName() {
return "cargo";
return "Rust";
}

public String getPluginName() {
Expand Down Expand Up @@ -152,9 +167,9 @@ private Optional<ProcessResult> run(String[] command, Path dir) {
private RunResult filledFailure(ProcessResult processResult) {
byte[] errorOutput = processResult.errorOutput.getBytes(StandardCharsets.UTF_8);
ImmutableMap<String, byte[]> logs =
new ImmutableMap.Builder()
new ImmutableMap.Builder<String, byte[]>()
.put(SpecialLogs.COMPILER_OUTPUT, errorOutput)
.<String, byte[]>build();
.build();
return new RunResult(Status.COMPILE_FAILED, ImmutableList.<TestResult>of(), logs);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public CargoStudentFilePolicy(Path configFileParent) {
* decision to move them is made by {@link ConfigurableStudentFilePolicy}.
*/
@Override
public boolean isStudentSourceFile(Path path) {
public boolean isStudentSourceFile(Path path, Path projectRootPath) {
return !path.endsWith(Constants.CARGO_TOML) && path.startsWith(Constants.SOURCE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,31 @@

import fi.helsinki.cs.tmc.langs.abstraction.ValidationError;

import java.util.List;

public class LintError implements ValidationError {

private final List<String> code;
private final int startLine;
private final int startColumn;
private final String description;
private final String message;
private final String file;
private final int endLine;
private final int endColumn;

/**
* Creates new error that failing lints generate.
*
* @param file file that the error is in
* @param description describes what is wrong
* @param code list of code lines the error is in
* @param message describes what is wrong
* @param startLine from what line error start
* @param startColumn from what column in that line error starts
* @param endLine in what line error ends
* @param endColumn in what column in that line error ends
*/
public LintError(
String file,
String description,
List<String> code,
String message,
int startLine,
int startColumn,
int endLine,
int endColumn) {
this.code = code;
int startColumn
) {
this.file = file;
this.description = description;
this.message = message;
this.startLine = startLine;
this.startColumn = startColumn;
this.endLine = endLine;
this.endColumn = endColumn;
}

@Override
Expand All @@ -52,26 +39,14 @@ public int getLine() {
return startLine;
}

public int getEndColumn() {
return endColumn;
}

public int getEndLine() {
return endLine;
}

@Override
public String getMessage() {
return description;
return message;
}

@Override
public String getSourceName() {
return file;
}

public List<String> getCode() {
return code;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
import fi.helsinki.cs.tmc.langs.abstraction.ValidationResult;

import java.io.File;
import java.util.HashMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public class LinterResult implements ValidationResult {
private Strategy strategy;
private final Map<File, List<ValidationError>> errors;

public LinterResult() {
errors = new HashMap<>();
public LinterResult(Map<File, List<ValidationError>> errors) {
this.errors = errors;
strategy = Strategy.DISABLED;
}

Expand All @@ -25,6 +25,6 @@ public Strategy getStrategy() {

@Override
public Map<File, List<ValidationError>> getValidationErrors() {
return errors;
return Collections.unmodifiableMap(errors);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,66 @@
import fi.helsinki.cs.tmc.langs.abstraction.ValidationResult;
import fi.helsinki.cs.tmc.langs.utils.ProcessResult;

import java.io.File;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class LinterResultParser {
//src\lib.rs:3:9:
private static final String START_INFO
= "(?<file>.+):(?<startLine>\\d+):(?<startColumn>\\d+):";
//3:14
private static final String END_INFO = "(?<endLine>\\d+):(?<endColumn>\\d+)";
//error: variable does not need to be mutable, #[forbid(unused_mut)] on by default
private static final Pattern ERROR_START
= Pattern.compile(START_INFO + " " + END_INFO + " error: (?<description>.*), .*");
//src\lib.rs:3 let mut x = a * b;
private static final Pattern ERROR_CONTINUE
= Pattern.compile("(?<before>(?<file>.+):(?<line>\\d+) )(?<code>.*)");
// ^~~~~
private static final Pattern ARROW = Pattern.compile("(?<before> *)\\^(?<stem>~*)");

private static final ObjectMapper mapper = new ObjectMapper();

/**
* Parses given process result to a validation result.
*/
public ValidationResult parse(ProcessResult processResult) {
String output = processResult.errorOutput;
String output = processResult.output;
String[] lines = output.split("\\r?\\n");
LinterResult result = new LinterResult();
List<String> code = new ArrayList<>();
for (String line : lines) {
Matcher matcher = ERROR_START.matcher(line);
if (matcher.matches()) {
code = new ArrayList<>();
addLintError(matcher, code, result);
} else {
matcher = ERROR_CONTINUE.matcher(line);
if (matcher.matches()) {
code.add(line);
} else {
matcher = ARROW.matcher(line);
if (!matcher.matches()) {
break;
return new LinterResult(Arrays
.stream(lines)
.filter(line -> line.startsWith("{"))
.flatMap(line -> {
try {
return Stream.of(mapper.readTree(line));
} catch (IOException e) {
// TODO: When does IOException happen? Or does it?
throw new RuntimeException(e);
}
})
.filter(parseTree -> parseTree
.get("reason")
.asText()
.equals("compiler-message")
)
.map(parseTree -> parseTree.get("message"))
.flatMap(parseTree -> {
for (JsonNode node : parseTree.get("spans")) {
if (node.get("is_primary").asBoolean()) {
return Stream.of(createLintError(
node,
parseTree.get("rendered").asText()
));
}
}
}
}
return result;
return Stream.empty();
})
.collect(Collectors.groupingBy(error ->
Paths.get(error.getSourceName()).toFile()
))
);
}

private void addLintError(Matcher matcher, List<String> code, LinterResult result) {
String fileName = matcher.group("file");
LintError current = new LintError(
fileName,
matcher.group("description"),
code,
Integer.parseInt(matcher.group("startLine")),
Integer.parseInt(matcher.group("startColumn")),
Integer.parseInt(matcher.group("endLine")),
Integer.parseInt(matcher.group("endColumn")));
File file = Paths.get(fileName).toFile();
List<ValidationError> errors = result.getValidationErrors().get(file);
if (errors == null) {
errors = new ArrayList<>();
result.getValidationErrors().put(file, errors);
}
errors.add(current);
private ValidationError createLintError(JsonNode node, String message) {
return new LintError(
node.get("file_name").asText(),
message,
node.get("line_start").asInt(),
node.get("column_start").asInt()
);
}
}
Loading