diff --git a/Dockerfile b/Dockerfile index 28671db2a9c107d923e81fc80b885bcd59ef1ec4..13b0fd15e8ea7ca09740c659da483134b8cb9c73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,7 @@ USER root RUN apt update RUN apt upgrade -y RUN apt install rsync -y +RUN apt install vim -y COPY plugins /home/plugins COPY theia/plugin-storage/global-state.json /home/theia/.theia/plugin-storage/global-state.json @@ -13,12 +14,14 @@ RUN chown theia /home/plugins -R COPY server.js /home/theia/src-gen/backend/server.js -COPY start.sh . - COPY recorder-out/dist/main.js deadlock/recorder.js COPY recorder-out/dist/preStop.js deadlock/preStop.js COPY .gitignore_recorder deadlock/.gitignore +COPY setup_trace.py . +RUN chmod 700 setup_trace.py +RUN chown theia setup_trace.py +COPY start.sh . RUN chmod 504 deadlock/ -R RUN chmod 500 start.sh diff --git a/plugins/deadlock-extension/src/recorder/command-recorder.ts b/plugins/deadlock-extension/src/recorder/command-recorder.ts index 6ec8d4de2dcd945ae60f86f2d8ef26b2296d8cab..62132a3bd5120ea1a4658e01a3ebbdaa23591819 100644 --- a/plugins/deadlock-extension/src/recorder/command-recorder.ts +++ b/plugins/deadlock-extension/src/recorder/command-recorder.ts @@ -1,8 +1,8 @@ import GitMission from '../core/gitMission'; -import { error, commitAndPushCode, CommitFrom } from './utils'; -const async = require("async"); +import { error, commitAndPushCode, CommitFrom, log } from './utils'; +const async = require('async'); -// regex to match command line in ps aux +// regex to match command line in ps aux /** * group 0: Full match * group 1: USER (theia) @@ -13,98 +13,85 @@ const async = require("async"); */ const child = require('child_process'); +const fs = require('fs'); -const regexPsCommand = /(theia).+?([\d]+).+?([\d]+\:[\d]+).+?([\d+]\:[\d+]+) (.+)/ +const regexPsCommand = + /(theia).+?([\d]+).+?([\d]+\:[\d]+).+?([\d+]\:[\d+]+) (.+)/; class Command { + public still: boolean; - public still: boolean; + constructor(public pid: number, private command: string) { + this.pid = pid; + this.command = command; - constructor(public pid: number, private command: string) { - this.pid = pid; - this.command = command; - - this.still = true; - } + this.still = true; + } } export default class CommandRecorder { - - private commandsInProgress = new Map<number, Command>(); - private readonly queue: any; - - constructor(private gitMission: GitMission) { - // create a queue object with concurrency 1 - this.queue = async.queue(async function (task) { - await task.apply(); - }, 1); - - this.queue.error((err, _task) => { - error(`Error on task: `, err); - }); - + private commandsInProgress = new Map<number, Command>(); + private readonly queue: any; + + constructor(private gitMission: GitMission) { + // create a queue object with concurrency 1 + this.queue = async.queue(async function (task) { + await task.apply(); + }, 1); + + this.queue.error((err, _task) => { + error('Error on task: ', err); + }); + } + + somethingExecuted(pid, command) { + if (!this.commandsInProgress.has(pid)) { + this.commandsInProgress.set(pid, new Command(pid, command)); + try { + this.queue.push( + async () => await commitAndPushCode(this.gitMission, CommitFrom.Run) + ); + } catch (e) { + console.error('Cannot send user code to git'); + console.error(e); + } + } else { + this.commandsInProgress.get(pid)!.still = true; } - - somethingExecuted(pid, command) { - if (!this.commandsInProgress.has(pid)) { - - this.commandsInProgress.set(pid, new Command(pid, command)); - try { - this.queue.push(async () => await commitAndPushCode(this.gitMission, CommitFrom.Run)); - } catch (e) { - console.error('Cannot send user code to git'); - console.error(e); - } - - } else { - this.commandsInProgress.get(pid)!.still = true; + } + + run() { + let lastLineIndexWatched = 0; + setInterval(() => { + try { + const trace = fs.readFileSync('/tmp/.trace', 'utf8'); + const lines = trace.split(/\r?\n/); + this.commandsInProgress.forEach((command) => (command.still = false)); + for (let index = lastLineIndexWatched; index < lines.length; index++) { + const line = lines[index]; + log('line ', line); + if ( + line.indexOf('java') !== -1 || + line.indexOf('yarn serve') !== -1 || + line.indexOf('yarn start') !== -1 || + line.indexOf('npm run') !== -1 || + line.indexOf('npm start') !== -1 + ) { + log('smth executed'); + this.somethingExecuted(index, line); + } } - } - - run() { - setInterval(() => { - try { - const spawn = child.spawn('ps', ['aux']); - - this.commandsInProgress.forEach(command => command.still = false); - - spawn.stdout.setEncoding('utf8'); - spawn.stdout.on('data', (data) => { - const lines = data.toString().split('\n'); - for (const line of lines) { - const lineMatcher = line.match(regexPsCommand); - if (lineMatcher && lineMatcher.length > 4) { - - const pid = lineMatcher[2]; - const command = lineMatcher[5]; + lastLineIndexWatched = lines.length; - if (line.indexOf('/opt/ibm/java/bin/java ') !== -1 && - line.indexOf('org.eclipse.jdt.ls.core') === -1 && - line.indexOf('-version') === -1 - ) { - // java program - this.somethingExecuted(pid, command); - } else if (line.indexOf('npm run start') !== -1 || - line.indexOf('yarn serve') !== -1 || - line.indexOf('yarn start') !== -1) { - // npm/yarn program - this.somethingExecuted(pid, command); - } - } - } - // clear command down (means still = false) - this.commandsInProgress.forEach(command => { - if (!command.still) { - this.commandsInProgress.delete(command.pid); - } - }) - }); - } catch (e) { - console.error(e); - } - }, 350); - } + // clear command down (means still = false) + this.commandsInProgress.forEach((command) => { + if (!command.still) { + this.commandsInProgress.delete(command.pid); + } + }); + } catch (e) { + console.error(e); + } + }, 500); + } } - - - diff --git a/plugins/deadlock-extension/src/recorder/index.ts b/plugins/deadlock-extension/src/recorder/index.ts index 9246d7c917a75cf455f0c6f4505e4e796c377015..fc876d2bd433bd08f17dff4afca352dc23d49eeb 100644 --- a/plugins/deadlock-extension/src/recorder/index.ts +++ b/plugins/deadlock-extension/src/recorder/index.ts @@ -11,8 +11,11 @@ export default class Recorder { const userConfig = new UserConfigNode(); try { + log('Init User config'); await userConfig.init(); + log('Init GitMission'); const gitMission = await new GitMission(userConfig).init(); + log('Check if remote repo exist'); const isRemoteRepoExist = await gitMission.isRemoteRepoExist(); if (isRemoteRepoExist) { // rm all except git directory pull remote code and setup diff --git a/plugins/deadlock-extension/src/recorder/utils.ts b/plugins/deadlock-extension/src/recorder/utils.ts index f37d234b6cccf6cec42573655141764780f3c52c..88e8e126a48cc3809638aa6c73ef2bad62a306e6 100644 --- a/plugins/deadlock-extension/src/recorder/utils.ts +++ b/plugins/deadlock-extension/src/recorder/utils.ts @@ -10,7 +10,7 @@ const fs = require('fs'); const readdirSync = require('fs').readdirSync; const Path = require('path'); -const PREFIX = '[DEADLOCK-RECORDER]' +const PREFIX = '[DEADLOCK-RECORDER]'; export const log = (message, args?) => { if (args) { @@ -56,7 +56,7 @@ export enum CommitFrom { export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom) { try { - log(`Commit & push`); + log('Commit & push'); await clearFilesExceptGit(PROJECT_SRC_PATH); execSync(`rsync -r --exclude .git --exclude npm --exclude target ${PROJECT_THEIA_PATH}/* ${PROJECT_SRC_PATH} && cp ${Path.join(__dirname, '.gitignore')} ${PROJECT_SRC_PATH} && chown -R root:root /project`); @@ -65,7 +65,7 @@ export async function commitAndPushCode(gitMission: GitMission, from: CommitFrom await gitMission.addAll(); await gitMission.commit(currentDate); await gitMission.push(); - log(`Commit & push done.`) + log('Commit & push done.'); } catch (e) { error(`[${e.status}] cannot commitAndPush code: ${e.stderr}`); error(e.message); diff --git a/setup_trace.py b/setup_trace.py new file mode 100644 index 0000000000000000000000000000000000000000..84c9cd26efcfbe6800c98b7bda0068b548726fb6 --- /dev/null +++ b/setup_trace.py @@ -0,0 +1,15 @@ + +open('/tmp/.trace', 'a').close() + +bashrc = open('/home/theia/.bashrc', 'a') +bashrc.write('\n') +bashrc.write('''PS4='$(echo $(date) $(history 1) >> /tmp/.trace) TRACE: \'''') + +bashrc.write('\n') +bashrc.write('export PS4') +bashrc.write('\n') +bashrc.write('set -x') +bashrc.write('\n') + +# Close the file +bashrc.close() \ No newline at end of file diff --git a/start.sh b/start.sh index e6e2ad0d5e8f4adb17f3f3f14fc5ebd439be1cd5..da50c742626a49bffd35bed93cdb84ca482ac985 100755 --- a/start.sh +++ b/start.sh @@ -8,5 +8,12 @@ cp /tmp/.ssh/* ~/.ssh/ # start command recorder node deadlock/recorder.js & + +#trap 'if [[ "$BASH_COMMAND" == "java "* ]]; then printf "[%s]\n" ${BASH_COMMAND#echo}; false; fi' DEBUG +#set -T +#shopt -s extdebug + +su theia --command "python setup_trace.py" + # starting theia as THEIA su theia --command "node /home/theia/src-gen/backend/main.js /home/project --hostname=0.0.0.0 --plugins=local-dir:/home/plugins" \ No newline at end of file