1 module rest.apiv1; 2 3 import vibe.d; 4 import rest.iapiv1; 5 import exec.iexecprovider; 6 import contentprovider; 7 8 class ApiV1: IApiV1 9 { 10 private IExecProvider execProvider_; 11 private ContentProvider contentProvider_; 12 13 this(IExecProvider execProvider, ContentProvider contentProvider) 14 { 15 this.execProvider_ = execProvider; 16 this.contentProvider_ = contentProvider; 17 } 18 19 /++ 20 Parses the message contained in $(D output) 21 and fills the appropriate errors and warnings 22 arrays. 23 Note: parsing s just done when $(D output.success) 24 is false. 25 +/ 26 private static void parseErrorsAndWarnings(ref RunOutput output) 27 { 28 import std.regex; 29 import std.algorithm: splitter; 30 import std.conv: to; 31 32 static ctr = ctRegex! 33 `^[^(]+\(([0-9]+)(,[0-9]+)?\): ([a-zA-Z]+): (.*)$`; 34 35 foreach(line; splitter(output.output, '\n')) { 36 auto m = line.matchFirst(ctr); 37 if (m.empty) 38 continue; 39 auto lineNumber = to!int(m[1]); 40 string type = m[3]; 41 string message = m[4]; 42 43 switch (type) { 44 case "Warning": 45 case "Deprecation": 46 output.warnings ~= RunOutput.Message(lineNumber, 47 message); 48 break; 49 default: 50 output.errors ~= RunOutput.Message(lineNumber, 51 message); 52 } 53 } 54 } 55 56 RunOutput run(string source) 57 { 58 if (source.length > 4 * 1024) { 59 return RunOutput("ERROR: source code size is above limit.", false); 60 } 61 62 auto result = execProvider_.compileAndExecute(source); 63 auto output = RunOutput(result.output, result.success); 64 parseErrorsAndWarnings(output); 65 return output; 66 } 67 68 SourceOutput getSource(string _language, string _chapter, string _section) 69 { 70 auto tourData = contentProvider_.getContent(_language, _chapter, _section); 71 if (tourData.content == null) { 72 throw new HTTPStatusException(404, 73 "Couldn't find tour data for chapter '%s', section %d".format(_language, _chapter, _section)); 74 } 75 76 return SourceOutput(tourData.content.sourceCode); 77 } 78 } 79 80 unittest { 81 string run1 = `onlineapp.d(6): Error: found '}' when expecting ';' following statement 82 onlineapp.d(6): Error: found 'EOF' when expecting '}' following compound statement 83 Failed: ["dmd", "-v", "-o-", "onlineapp.d", "-I."]`; 84 85 auto test2 = ApiV1.RunOutput(run1, false); 86 ApiV1.parseErrorsAndWarnings(test2); 87 assert(test2.errors.length == 2); 88 assert(test2.errors[0].line == 6); 89 assert(test2.errors[0].message[0 .. 9] == "found '}'"); 90 assert(test2.errors[1].line == 6); 91 assert(test2.errors[1].message[0 .. 11] == "found 'EOF'"); 92 93 string run2 = `dlang-tour ~master: building configuration "executable"... 94 ../.dub/packages/dyaml-0.5.2/source/dyaml/dumper.d(15,8): Deprecation: module std.stream is deprecated - It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD 95 ../.dub/packages/dyaml-0.5.2/source/dyaml/emitter.d(21,8): Deprecation: module std.stream is deprecated - It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD 96 ../.dub/packages/dyaml-0.5.2/source/dyaml/representer.d(679,8): Deprecation: module std.stream is deprecated - It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD 97 ../.dub/packages/dyaml-0.5.2/source/dyaml/loader.d(171,16): Deprecation: module std.stream is deprecated - It will be removed from Phobos in October 2016. If you still need it, go to https://github.com/DigitalMars/undeaD`; 98 auto test3 = ApiV1.RunOutput(run2, false); 99 ApiV1.parseErrorsAndWarnings(test3); 100 assert(test3.warnings.length == 4); 101 import std.algorithm: all; 102 assert(test3.warnings.all!(x => x.message[0 .. 31] == "module std.stream is deprecated")); 103 assert(test3.warnings[0].line == 15); 104 assert(test3.warnings[1].line == 21); 105 assert(test3.warnings[2].line == 679); 106 assert(test3.warnings[3].line == 171); 107 }