Skip to content

Commit

Permalink
feat(console): console command exec times
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuri committed Sep 5, 2017
1 parent dcffee0 commit 2611e4f
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 142 deletions.
3 changes: 1 addition & 2 deletions .abstruse.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ before_script:
- sudo /etc/init.d/docker start
- sudo /etc/init.d/xvfb start
- export DISPLAY=:99
- sudo su abstruse

script:
- if [[ "$SCRIPT" ]]; then newgrp docker && npm run-script $SCRIPT; fi
- if [[ "$SCRIPT" ]]; then npm run-script $SCRIPT; fi
4 changes: 2 additions & 2 deletions src/api/process-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobEvents
.subscribe(event => {
let msg = [
yellow('['),
blue('abstruse_' + event.build_id + '_' + event.job_id),
cyan('abstruse_' + event.build_id + '_' + event.job_id),
yellow(']'),
' --- ',
yellow(event.data)
Expand Down Expand Up @@ -200,7 +200,7 @@ export function startJob(proc: JobProcess): Promise<void> {
} else if (event.type === 'container') {
let msg = [
yellow('['),
blue('abstruse_' + proc.build_id + '_' + proc.job_id),
cyan('abstruse_' + proc.build_id + '_' + proc.job_id),
yellow(']'),
' --- ',
yellow(event.data)
Expand Down
106 changes: 65 additions & 41 deletions src/api/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as child_process from 'child_process';
import { generateRandomId } from './utils';
import { getRepositoryByBuildId } from './db/repository';
import { Observable } from 'rxjs';
import { green, red, bold, yellow, blue } from 'chalk';
import { green, red, bold, yellow, blue, cyan } from 'chalk';
import { CommandType, Command } from './config';
import { JobProcess } from './process-manager';
const nodePty = require('node-pty');
Expand Down Expand Up @@ -90,52 +90,76 @@ export function startBuildProcess(

function executeInContainer(name: string, cmd: Command): Observable<ProcessOutput> {
return new Observable(observer => {
let executed = false;
let attach = null;
let detachKey = 'D';
let success = false;

attach = nodePty.spawn('docker', ['attach', `--detach-keys=${detachKey}`, name]);

attach.on('data', data => {
if (!executed) {
const exec = `/usr/bin/abstruse '${cmd.command}'\r`;
attach.write(exec);
observer.next({ type: 'data', data: yellow('==> ' + cmd.command) + '\r' });
executed = true;
} else {
if (data.includes('[success]')) {
if (cmd.type === CommandType.script) {
observer.next({ type: 'data', data: green(data.replace(/\n\r/g, '')) });
}

success = true;
attach.write(detachKey);
} else if (data.includes('[error]')) {
attach.kill();
observer.error(red(data.replace(/\n\r/g, '')));
} else if (!data.includes('/usr/bin/abstruse') &&
!data.includes('exit $?') && !data.includes('logout') &&
!data.includes('read escape sequence')) {
observer.next({ type: 'data', data: data.replace('> ', '') });
}
}
});
const startTime = new Date().getTime();
const start = nodePty.spawn('docker', ['start', name], { name: 'xterm-color' });

attach.on('exit', code => {
if (code !== 0 && !success) {
start.on('exit', startCode => {
if (startCode !== 0) {
const msg = [
yellow('['),
blue(name),
yellow(']'),
' --- ',
`Executed command returned exit code ${red(code.toString())}`
yellow('['), cyan(name), yellow(']'), ' --- ',
'Container errored with exit code ' + red(startCode)
].join('');
observer.error(msg);
}

let executed = false;
let success = false;
let dk = null;
let attach = null;

if (cmd.command.includes('init.d') && cmd.command.includes('start')) {
dk = 'Q';
attach = nodePty.spawn('docker', ['attach', `--detach-keys=${dk}`, name]);
} else {
observer.next({ type: 'exit', data: '0' });
observer.complete();
attach = nodePty.spawn('docker', ['exec', `-it`, name, 'bash', '-l']);
}

attach.on('data', data => {
if (!executed) {
const exec = `/usr/bin/abstruse '${cmd.command}'\r`;
attach.write(exec);
observer.next({ type: 'data', data: yellow('==> ' + cmd.command) + '\r' });
executed = true;
} else {
if (data.includes('[success]')) {
if (cmd.type === CommandType.script) {
observer.next({ type: 'data', data: green(data.replace(/\n\r/g, '')) });
}

success = true;
if (dk) {
attach.write(dk);
} else {
attach.write('pkill -9 sleep && exit 100\r');
}
} else if (data.includes('[error]')) {
attach.kill();
observer.error(red(data.replace(/\n\r/g, '')));
} else if (!data.includes('/usr/bin/abstruse') &&
!data.includes('exit 100') && !data.includes('logout') &&
!data.includes('read escape sequence')) {
observer.next({ type: 'data', data: data.replace('> ', '') });
}
}
});

attach.on('exit', code => {
const endTime = new Date().getTime();
const totalTime = endTime - startTime;

if (code !== 0 && !success) {
const msg = [
yellow('['), cyan(name), yellow(']'), ' --- ',
`Executed command returned exit code ${red(code.toString())}`
].join('');
observer.next({ type: 'data', data: `[exectime]: ${totalTime}` });
observer.error(msg);
} else {
observer.next({ type: 'data', data: `[exectime]: ${totalTime}` });
observer.next({ type: 'exit', data: '0' });
observer.complete();
}
});
});
});
}
Expand Down
52 changes: 9 additions & 43 deletions src/app/assets/public/images/icons/collapse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 9 additions & 43 deletions src/app/assets/public/images/icons/expand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/app/components/app-terminal/app-terminal.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<div class="window-terminal-container dracula-ansi-theme" *ngIf="!noData">
<div class="terminal" *ngFor="let cmd of commands; let i = index;" [id]="i">
<div class="command-line" (click)="toogleCommand(i)">
<div class="command-line" (click)="toogleCommand(i)" [class.is-opened]="cmd.visible">
<span class="icon">
<img *ngIf="cmd.visible" src="images/icons/collapse.svg">
<img *ngIf="!cmd.visible" src="images/icons/expand.svg">
</span>
<span class="command" [innerHTML]="cmd.command"></span>
<span class="time" *ngIf="cmd.time">{{ cmd.time }}</span>
</div>
<pre class="output" [class.is-hidden]="!cmd.visible" [innerHTML]="cmd.output"></pre>
</div>
Expand Down
48 changes: 44 additions & 4 deletions src/app/components/app-terminal/app-terminal.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export class AppTerminalComponent implements OnInit {
@Input() data: any;
@Input() options: { size: 'normal' | 'large' };
au: any;
commands: { command: string, visible: boolean, output: string }[];
commands: { command: string, visible: boolean, output: string, time: string }[];
noData: boolean;

constructor(private elementRef: ElementRef) {
Expand Down Expand Up @@ -39,12 +39,21 @@ export class AppTerminalComponent implements OnInit {
let commands: string[] = [];

if (output.match(regex)) {
while (match = regex.exec(output)) { commands.push(match[0]); }
while (match = regex.exec(output)) {
commands.push(match[0]);
}

if (commands.length > 1) {
this.commands = [];
}

let retime = new RegExp('exectime.*(\\d)', 'igm');
let times = [];
while (match = retime.exec(output)) {
let t = match[0].replace('exectime]: ', '').replace(/<span.*/, '');
times.push(t);
}

this.commands = commands.reduce((acc, curr, i) => {
let next = commands[i + 1] || '';
next = next.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
Expand All @@ -53,15 +62,24 @@ export class AppTerminalComponent implements OnInit {
if (!output.match(re)) {
re = new RegExp('(' + c + ')' + '[\\s\\S]+');
}
let retime = new RegExp('exectime.*(\\d)', 'igm');
let t = times[i] ? parseFloat(<any>(times[i] / 10)).toFixed(0) : null;
let time = t && parseInt(<any>t, 10);

return acc.concat({
command: curr.trim(),
visible: i === commands.length - 1 ? true : false,
output: output.match(re) && output.match(re)[2] ? output.match(re)[2].trim() : ''
output: output.match(re) && output.match(re)[2] ? output.match(re)[2].trim() : '',
time: times[i] ? this.getDuration(time) : null
});
}, this.commands);
} else {
this.commands[this.commands.length - 1].output += output;
if (output.includes('[exectime]')) {
const time = parseInt(output.replace('[exectime]', ''), 10);
console.log(time);
} else {
this.commands[this.commands.length - 1].output += output;
}
}

this.commands = this.commands.map((cmd, i) => {
Expand All @@ -84,4 +102,26 @@ export class AppTerminalComponent implements OnInit {
toogleCommand(index: number) {
this.commands[index].visible = !this.commands[index].visible;
}

getDuration(millis: number): string {
const dur = {};
const units = [
{label: 'millis', mod: 100 }, // millis
{label: 'seconds', mod: 60 },
{label: 'minutes', mod: 60 },
{label: 'hours', mod: 24 },
{label: 'days', mod: 31 }
];
units.forEach(u => millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod);
const nonZero = (u) => { return dur[u.label]; };
dur.toString = () => {
return units
.reverse()
.filter(nonZero)
.map(u => dur[u.label] + ' ' + (dur[u.label] === 1 ? u.label.slice(0, -1) : u.label))
.join(', ');
};

return dur.toString();
}
}
20 changes: 14 additions & 6 deletions src/app/styles/terminal.sass
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@
.command-line
display: flex
align-items: center
background: #000000
margin: 2px 5px
padding: 0px
border-radius: 2px
cursor: pointer
line-height: 10px
position: relative

&.is-opened
background: lighten(#000000, 5)

.icon
margin-top: 6px

img
width: 24px
height: 24px
width: 12px
height: 12px

.command
font-size: 12px
Expand All @@ -50,6 +50,14 @@
color: $white
font-weight: $weight-semibold

.time
position: absolute
display: block
font-size: 12px
color: $white
right: 5px
top: 8px

.output
display: inline-block
width: 100%
Expand Down

0 comments on commit 2611e4f

Please sign in to comment.