b7003b18dc4d1887fbbd967f775b5c1c3367475b
[src/xds/xds-server.git] / webapp / src / app / devel / build / build.component.ts
1 import { Component, AfterViewChecked, ElementRef, ViewChild, OnInit, Input } from '@angular/core';
2 import { Observable } from 'rxjs';
3 import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
4 import { CookieService } from 'ngx-cookie';
5
6 import 'rxjs/add/operator/scan';
7 import 'rxjs/add/operator/startWith';
8
9 import { XDSServerService, ICmdOutput } from "../../services/xdsserver.service";
10 import { ConfigService, IConfig, IProject } from "../../services/config.service";
11 import { AlertService, IAlert } from "../../services/alert.service";
12 import { SdkService } from "../../services/sdk.service";
13
14 @Component({
15     selector: 'panel-build',
16     moduleId: module.id,
17     templateUrl: './build.component.html',
18     styleUrls: ['./build.component.css']
19 })
20
21 export class BuildComponent implements OnInit, AfterViewChecked {
22     @ViewChild('scrollOutput') private scrollContainer: ElementRef;
23
24     @Input() curProject: IProject;
25
26     buildForm: FormGroup;
27     subpathCtrl = new FormControl("", Validators.required);
28     debugEnable: boolean = false;
29
30     public cmdOutput: string;
31     public cmdInfo: string;
32
33     private startTime: Map<string, number> = new Map<string, number>();
34
35     constructor(private configSvr: ConfigService,
36         private xdsSvr: XDSServerService,
37         private fb: FormBuilder,
38         private alertSvr: AlertService,
39         private sdkSvr: SdkService,
40         private cookie: CookieService,
41     ) {
42         this.cmdOutput = "";
43         this.cmdInfo = "";      // TODO: to be remove (only for debug)
44         this.buildForm = fb.group({
45             subpath: this.subpathCtrl,
46             cmdArgs: ["", Validators.nullValidator],
47             envVars: ["", Validators.nullValidator],
48         });
49     }
50
51     ngOnInit() {
52         // Command output data tunneling
53         this.xdsSvr.CmdOutput$.subscribe(data => {
54             this.cmdOutput += data.stdout + "\n";
55         });
56
57         // Command exit
58         this.xdsSvr.CmdExit$.subscribe(exit => {
59             if (this.startTime.has(exit.cmdID)) {
60                 this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID));
61                 this.startTime.delete(exit.cmdID);
62             }
63
64             if (exit && exit.code !== 0) {
65                 this.cmdOutput += "--- Command exited with code " + exit.code + " ---\n\n";
66             }
67         });
68
69         this._scrollToBottom();
70
71         // only use for debug
72         this.debugEnable = (this.cookie.get("debug_build") !== "");
73     }
74
75     ngAfterViewChecked() {
76         this._scrollToBottom();
77     }
78
79     reset() {
80         this.cmdOutput = '';
81     }
82
83     preBuild() {
84         this._exec(
85             "mkdir -p build && cd build && cmake ..",
86             this.buildForm.value.subpath,
87             [],
88             this.buildForm.value.envVars);
89     }
90
91     build() {
92         this._exec(
93             "cd build && make",
94             this.buildForm.value.subpath,
95             this.buildForm.value.cmdArgs,
96             this.buildForm.value.envVars
97         );
98     }
99
100     populate() {
101         this._exec(
102             "SEB_TODO_script_populate",
103             this.buildForm.value.subpath,
104             [], // args
105             this.buildForm.value.envVars
106         );
107     }
108
109     execCmd() {
110         this._exec(
111             this.buildForm.value.cmdArgs,
112             this.buildForm.value.subpath,
113             [],
114             this.buildForm.value.envVars
115         );
116     }
117
118     private _exec(cmd: string, dir: string, args: string[], env: string) {
119         if (!this.curProject) {
120             this.alertSvr.warning('No active project', true);
121         }
122
123         let prjID = this.curProject.id;
124
125         this.cmdOutput += this._outputHeader();
126
127         let sdkid = this.sdkSvr.getCurrentId();
128
129         // Detect key=value in env string to build array of string
130         let envArr = [];
131         env.split(';').forEach(v => envArr.push(v.trim()));
132
133         let t0 = performance.now();
134         this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
135
136         this.xdsSvr.exec(prjID, dir, cmd, sdkid, args, envArr)
137             .subscribe(res => {
138                 this.startTime.set(String(res.cmdID), t0);
139             },
140             err => {
141                 this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
142                 this.alertSvr.error('ERROR: ' + err);
143             });
144     }
145
146     make(args: string) {
147         if (!this.curProject) {
148             this.alertSvr.warning('No active project', true);
149         }
150
151         let prjID = this.curProject.id;
152
153         this.cmdOutput += this._outputHeader();
154
155         let sdkid = this.sdkSvr.getCurrentId();
156
157         let argsArr = args ? args.split(' ') : this.buildForm.value.cmdArgs.split(' ');
158
159         // Detect key=value in env string to build array of string
160         let envArr = [];
161         this.buildForm.value.envVars.split(';').forEach(v => envArr.push(v.trim()));
162
163         let t0 = performance.now();
164         this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
165
166         this.xdsSvr.make(prjID, this.buildForm.value.subpath, sdkid, argsArr, envArr)
167             .subscribe(res => {
168                 this.startTime.set(String(res.cmdID), t0);
169             },
170             err => {
171                 this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
172                 this.alertSvr.error('ERROR: ' + err);
173             });
174     }
175
176     private _scrollToBottom(): void {
177         try {
178             this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
179         } catch (err) { }
180     }
181
182     private _computeTime(t0: number, t1?: number): string {
183         let enlap = Math.round((t1 || performance.now()) - t0);
184         if (enlap < 1000.0) {
185             return enlap.toFixed(2) + ' ms';
186         } else {
187             return (enlap / 1000.0).toFixed(3) + ' seconds';
188         }
189     }
190
191     private _outputHeader(): string {
192         return "--- " + new Date().toString() + " ---\n";
193     }
194
195     private _outputFooter(): string {
196         return "\n";
197     }
198 }