forked from koajs/kick-off-koa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
exercise.js
118 lines (100 loc) · 3.62 KB
/
exercise.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
var through2 = require('through2');
var exercise = require('workshopper-exercise')();
var filecheck = require('workshopper-exercise/filecheck');
var execute = require('workshopper-exercise/execute');
var comparestdout = require('workshopper-exercise/comparestdout');
var urllib = require('urllib');
var pedding = require('pedding');
var fmt = require('util').format;
var freeport = require('freeport');
var fs = require('fs');
var path = require('path');
var argv = [];
exports.argv = function () {
var args = [].slice.call(arguments);
argv = argv.concat(args);
return exports;
};
var tasks = [];
exports.push = function (path, options, verify) {
if (arguments.length === 1) {
tasks.push(['/', {}, path]);
} else if (arguments.length === 2) {
tasks.push([path, {}, options]);
} else {
tasks.push([path, options, verify]);
}
return exports;
};
function query(mode) {
var exercise = this;
var task = tasks.shift();
// end stream when task list empty
if (!task) {
exercise.submissionStdout.end();
return;
}
// query submisstion server
var submissionUrl = 'http://localhost:' + exercise.submissionPort + task[0];
urllib.request(submissionUrl, task[1], function (err, data, res) {
if (err) return error(err, exercise.__('server_type.submission'));
var verify = task[2];
verify.call(exercise, data, res, exercise.submissionStdout);
query.call(exercise, mode);
});
function error (err, type) {
var port = type === 'solution'
? exercise.solutionPort
: exercise.submissionPort;
var msg = fmt(exercise.__('fail.cannot_connect'), type, port, task[0], task[1], err.stack);
exercise.emit('fail', msg);
};
}
exports.generate = function () {
// the output will be long lines so make the comparison take that into account
exercise.longCompareOutput = true;
// checks that the submission file actually exists
// execute the solution and submission in parallel with spawn()
exercise = execute(filecheck(exercise));
// set up the data file to be passed to the submission
exercise.addSetup(function (mode, callback) {
var self = this;
freeport(function (err, port) {
if (err) throw err;
self.submissionPort = port;
self.submissionArgs = self.submissionArgs.concat([self.submissionPort]).concat(argv);
if (!self.submissionCommand) {
self.submissionCommand = [ self.submission ].concat(self.submissionArgs);
}
self.submissionCommand.unshift('--harmony');
setImmediate(callback);
});
});
// add a processor for both run and verify calls, added *before*
// the comparestdout processor so we can mess with the stdouts
exercise.addProcessor(function (mode, callback) {
this.submissionStdout.pipe(process.stdout);
// replace stdout with our own streams
this.submissionStdout = through2();
if (mode === 'verify') {
var solutionFile = path.join(this.dir, 'solution_' + this.lang + '/solution.txt');
if (!fs.existsSync(solutionFile)) {
solutionFile = path.join(this.dir, 'solution/solution.txt');
}
this.solutionStdout = fs.createReadStream(solutionFile);
// this.solutionStdout = fs.createReadStream();
}
setTimeout(query.bind(this, mode), 500);
process.nextTick(callback.bind(null, null, true));
});
exercise.strOut = function strOut(stream, key) {
var args = Array.prototype.slice.call(arguments, 2);
args.unshift(this.__(key));
var result = fmt.apply(null, args);
if ("\n" !== result.slice(-1)) result += "\n";
stream.write(result);
};
// compare stdout of solution and submission
exercise = comparestdout(exercise)
return exercise;
};