99b7e54a06fd4b0054c6f1de12bbc86f5165bdeb
[src/xds/xds-agent.git] / webapp / src / app / pages / 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 { NgbModal } from '@ng-bootstrap/ng-bootstrap';
5
6 import 'rxjs/add/operator/scan';
7 import 'rxjs/add/operator/startWith';
8
9 import { BuildSettingsModalComponent } from './build-settings-modal/build-settings-modal.component';
10
11 import { XDSAgentService, ICmdOutput } from '../../@core-xds/services/xdsagent.service';
12 import { ProjectService, IProject } from '../../@core-xds/services/project.service';
13 import { AlertService, IAlert } from '../../@core-xds/services/alert.service';
14 import { SdkService } from '../../@core-xds/services/sdk.service';
15
16 @Component({
17   selector: 'xds-panel-build',
18   templateUrl: './build.component.html',
19   styleUrls: ['./build.component.scss'],
20   encapsulation: ViewEncapsulation.None,
21 })
22
23 export class BuildComponent implements OnInit, AfterViewChecked {
24   @ViewChild('scrollOutput') private scrollContainer: ElementRef;
25
26   // FIXME workaround of https://github.com/angular/angular-cli/issues/2034
27   // should be removed with angular 5
28   //  @Input() curProject: IProject;
29   @Input() curProject = <IProject>null;
30
31   public buildIsCollapsed = false;
32   public cmdOutput: string;
33   public cmdInfo: string;
34
35   private startTime: Map<string, number> = new Map<string, number>();
36
37   constructor(
38     private prjSvr: ProjectService,
39     private xdsSvr: XDSAgentService,
40     private alertSvr: AlertService,
41     private sdkSvr: SdkService,
42     private modalService: NgbModal,
43   ) {
44     this.cmdOutput = '';
45     this.cmdInfo = '';      // TODO: to be remove (only for debug)
46
47   }
48
49   ngOnInit() {
50     // Command output data tunneling
51     this.xdsSvr.CmdOutput$.subscribe(data => {
52       this.cmdOutput += data.stdout;
53       this.cmdOutput += data.stderr;
54     });
55
56     // Command exit
57     this.xdsSvr.CmdExit$.subscribe(exit => {
58       if (this.startTime.has(exit.cmdID)) {
59         this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID));
60         this.startTime.delete(exit.cmdID);
61       }
62
63       if (exit && exit.code !== 0) {
64         this.cmdOutput += '--- Command exited with code ' + exit.code + ' ---\n\n';
65       }
66     });
67
68     this._scrollToBottom();
69   }
70
71   ngAfterViewChecked() {
72     this._scrollToBottom();
73   }
74
75   resetOutput() {
76     this.cmdOutput = '';
77   }
78
79   settingsShow() {
80     const activeModal = this.modalService.open(BuildSettingsModalComponent, { size: 'lg', container: 'nb-layout' });
81     activeModal.componentInstance.modalHeader = 'Large Modal';
82   }
83
84   clean() {
85     const curPrj = this.prjSvr.getCurrent();
86     this._exec(
87       curPrj.uiSettings.cmdClean,
88       curPrj.uiSettings.subpath,
89       [],
90       curPrj.uiSettings.envVars.join(' '));
91   }
92
93   preBuild() {
94     const curPrj = this.prjSvr.getCurrent();
95     this._exec(
96       curPrj.uiSettings.cmdPrebuild,
97       curPrj.uiSettings.subpath,
98       [],
99       curPrj.uiSettings.envVars.join(' '));
100   }
101
102   build() {
103     const curPrj = this.prjSvr.getCurrent();
104     this._exec(
105       curPrj.uiSettings.cmdBuild,
106       curPrj.uiSettings.subpath,
107       [],
108       curPrj.uiSettings.envVars.join(' '),
109     );
110   }
111
112   populate() {
113     const curPrj = this.prjSvr.getCurrent();
114     this._exec(
115       curPrj.uiSettings.cmdPopulate,
116       curPrj.uiSettings.subpath,
117       [], // args
118       curPrj.uiSettings.envVars.join(' '),
119     );
120   }
121
122   execCmd() {
123     const curPrj = this.prjSvr.getCurrent();
124     this._exec(
125       curPrj.uiSettings.cmdArgs.join(' '),
126       curPrj.uiSettings.subpath,
127       [],
128       curPrj.uiSettings.envVars.join(' '),
129     );
130   }
131
132   private _exec(cmd: string, dir: string, args: string[], env: string) {
133     this.curProject = this.prjSvr.getCurrent();
134     const prjID = this.curProject.id;
135
136     if (!this.curProject) {
137       return this.alertSvr.warning('No active project', true);
138     }
139
140     this.cmdOutput += this._outputHeader();
141
142     const sdkid = this.sdkSvr.getCurrentId();
143
144     // Detect key=value in env string to build array of string
145     const envArr = [];
146     env.split(';').forEach(v => envArr.push(v.trim()));
147
148     const t0 = performance.now();
149     this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
150
151     this.xdsSvr.exec(prjID, dir, cmd, sdkid, args, envArr)
152       .subscribe(res => {
153         this.startTime.set(String(res.cmdID), t0);
154       },
155       err => {
156         this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
157         this.alertSvr.error('ERROR: ' + err);
158       });
159   }
160
161   private _scrollToBottom(): void {
162     try {
163       this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
164     } catch (err) { }
165   }
166
167   private _computeTime(t0: number, t1?: number): string {
168     const enlap = Math.round((t1 || performance.now()) - t0);
169     if (enlap < 1000.0) {
170       return enlap.toFixed(2) + ' ms';
171     } else {
172       return (enlap / 1000.0).toFixed(3) + ' seconds';
173     }
174   }
175
176   private _outputHeader(): string {
177     return '--- ' + new Date().toString() + ' ---\n';
178   }
179
180   private _outputFooter(): string {
181     return '\n';
182   }
183 }