17e545f0c38dc1d5cebe765979f21e88a5fd09cd
[src/xds/xds-server.git] / webapp / src / app / build / build.component.ts
1 import { Component, AfterViewChecked, ElementRef, ViewChild, OnInit } from '@angular/core';
2 import { Observable } from 'rxjs';
3 import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
4
5 import 'rxjs/add/operator/scan';
6 import 'rxjs/add/operator/startWith';
7
8 import { XDSServerService, ICmdOutput } from "../common/xdsserver.service";
9 import { ConfigService, IConfig, IProject } from "../common/config.service";
10 import { AlertService, IAlert } from "../common/alert.service";
11 import { SdkService } from "../common/sdk.service";
12
13 @Component({
14     selector: 'build',
15     moduleId: module.id,
16     templateUrl: './build.component.html',
17     styleUrls: ['./build.component.css']
18 })
19
20 export class BuildComponent implements OnInit, AfterViewChecked {
21     @ViewChild('scrollOutput') private scrollContainer: ElementRef;
22
23     config$: Observable<IConfig>;
24
25     buildForm: FormGroup;
26     subpathCtrl = new FormControl("", Validators.required);
27
28     public cmdOutput: string;
29     public confValid: boolean;
30     public curProject: IProject;
31     public cmdInfo: string;
32
33     private startTime: Map<string, number> = new Map<string, number>();
34
35     // I initialize the app component.
36     constructor(private configSvr: ConfigService,
37         private xdsSvr: XDSServerService,
38         private fb: FormBuilder,
39         private alertSvr: AlertService,
40         private sdkSvr: SdkService
41     ) {
42         this.cmdOutput = "";
43         this.confValid = false;
44         this.cmdInfo = "";      // TODO: to be remove (only for debug)
45         this.buildForm = fb.group({
46             subpath: this.subpathCtrl,
47             makeArgs: ["", Validators.nullValidator],
48         });
49     }
50
51     ngOnInit() {
52         this.config$ = this.configSvr.conf;
53         this.config$.subscribe((cfg) => {
54             if ("projects" in cfg) {
55                 this.curProject = cfg.projects[0];
56                 this.confValid = (cfg.projects.length && this.curProject.id != null);
57             } else {
58                 this.curProject = null;
59                 this.confValid = false;
60             }
61         });
62
63         // Command output data tunneling
64         this.xdsSvr.CmdOutput$.subscribe(data => {
65             this.cmdOutput += data.stdout + "\n";
66         });
67
68         // Command exit
69         this.xdsSvr.CmdExit$.subscribe(exit => {
70             if (this.startTime.has(exit.cmdID)) {
71                 this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID));
72                 this.startTime.delete(exit.cmdID);
73             }
74
75             if (exit && exit.code !== 0) {
76                 this.cmdOutput += "--- Command exited with code " + exit.code + " ---\n\n";
77             }
78         });
79
80         this._scrollToBottom();
81     }
82
83     ngAfterViewChecked() {
84         this._scrollToBottom();
85     }
86
87     reset() {
88         this.cmdOutput = '';
89     }
90
91     make(args: string) {
92         if (!this.curProject) {
93             this.alertSvr.warning('No active project', true);
94         }
95
96         let prjID = this.curProject.id;
97
98         this.cmdOutput += this._outputHeader();
99
100         let sdkid = this.sdkSvr.getCurrentId();
101
102         let cmdArgs = args ? args : this.buildForm.value.makeArgs;
103
104         let t0 = performance.now();
105         this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
106
107         this.xdsSvr.make(prjID, this.buildForm.value.subpath, cmdArgs, sdkid)
108             .subscribe(res => {
109                 this.startTime.set(String(res.cmdID), t0);
110             },
111             err => {
112                 this.cmdInfo = 'Last command duration: ' + this._computeTime(t0);
113                 this.alertSvr.error('ERROR: ' + err);
114             });
115     }
116
117     private _scrollToBottom(): void {
118         try {
119             this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
120         } catch (err) { }
121     }
122
123     private _computeTime(t0: number, t1?: number): string {
124         let enlap = Math.round((t1 || performance.now()) - t0);
125         if (enlap < 1000.0) {
126             return enlap.toFixed(2) + ' ms';
127         } else {
128             return (enlap / 1000.0).toFixed(3) + ' seconds';
129         }
130     }
131
132     private _outputHeader(): string {
133         return "--- " + new Date().toString() + " ---\n";
134     }
135
136     private _outputFooter(): string {
137         return "\n";
138     }
139 }