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