feat: able to test files

This commit is contained in:
Lin, Hung-Shin authored and wancat committed 2023-10-29 17:41:38 +08:00
1 parent af27780763
commit 625c1a80da
5 files changed
+99 -28

No files matched your search

+46
View File
@@ -1,4 +1,6 @@
import { PassThrough } from 'stream'
import Docker from 'dockerode'
import { buildFileCheckCmd } from '@linux-odyssey/utils'
import config from '../config.js'
const engine = new Docker()
@@ -77,3 +79,47 @@ export async function deleteContainer(id) {
}
await container.remove()
}
// Utility function to convert a stream to a string
function streamToString(stream) {
const chunks = []
return new Promise((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk))
stream.on('error', reject)
stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')))
setTimeout(() => resolve(Buffer.concat(chunks).toString('utf8')), 100)
})
}
export async function checkFiles(id, files) {
const container = engine.getContainer(id)
if (!container) {
throw new Error('Container not found')
}
const cmd = buildFileCheckCmd(files)
console.log(cmd)
const exec = await container.exec({
AttachStdout: true,
AttachStderr: true,
Cmd: ['sh', '-c', cmd],
})
const execStream = await exec.start()
const outStream = new PassThrough()
const errStream = new PassThrough()
console.log('exec started')
exec.modem.demuxStream(execStream, outStream, errStream)
const [output, errorOutput] = await Promise.all([
streamToString(outStream),
streamToString(errStream),
])
console.log('output', output, 'errorOutput', errorOutput)
const execOutput = await exec.inspect()
console.log('exit code', execOutput.ExitCode)
console.log('exit code === 0', execOutput.ExitCode === 0)
return execOutput.ExitCode === 0
}
+37 -11
View File
@@ -3,6 +3,7 @@ import { FileGraph } from '@linux-odyssey/file-graph'
import { Quest } from '@linux-odyssey/models'
import { pushToSession } from '../api/socket.js'
import SessionHandler from './sessionHandler.js'
import { checkFiles } from '../containers/docker.js'
// 檢查 pattern 是否符合 input
const checkMatch = (pattern, input) => {
@@ -53,15 +54,31 @@ export default class CommandHandler extends SessionHandler {
this.session.graph = graph
}
isMatch(condition) {
async isMatch(condition) {
const keys = ['command', 'output', 'error', 'pwd']
console.log('condition', condition)
return (
keys.every((k) => checkMatch(condition[k], this.commandInput[k])) &&
(condition.$or.length === 0 ||
condition.$or.some((c) => this.isMatch(c))) &&
(!condition.$not || !this.isMatch(condition.$not))
)
if (keys.some((k) => !checkMatch(condition[k], this.commandInput[k]))) {
return false
}
if (condition.files.length > 0) {
const match = await this.checkFiles(condition.files)
if (!match) return false
}
if (condition.$not) {
const match = await this.isMatch(condition.$not)
if (match) return false
}
if (condition.$or.length > 0) {
const matches = await Promise.all(
condition.$or.map((c) => this.isMatch(c))
)
if (matches.every((m) => m === false)) return false
}
return true
}
checkFiles(files) {
console.log('checkFiles', files)
return checkFiles(this.session.containerId, files)
}
async run() {
@@ -75,9 +92,18 @@ export default class CommandHandler extends SessionHandler {
this.handleEvent()
this.handleCommand()
const response = stages
.filter((s) => this.isMatch(s.condition))
.reduce((r, s) => ({ ...r, ...this.execute(s) }), {})
const matches = await Promise.all(
stages.map((stage) => this.isMatch(stage.condition))
)
console.log('matches', matches)
const filteredStages = stages.filter((_, i) => matches[i])
console.log('filteredStages', filteredStages)
const response = filteredStages.reduce(
(r, s) => ({ ...r, ...this.execute(s) }),
{}
)
return {
end: this.session.status === 'finished',