1- import * as chalk from 'chalk' ;
2- import { ChildProcess , spawn } from 'child_process' ;
1+ import * as Chalk from 'chalk' ;
2+ import { ChildProcess , spawn as nodeSpawn } from 'child_process' ;
33import * as copyfiles from 'copyfiles' ;
44import * as fs from 'fs' ;
55import { processMillis } from './server/src/util' ;
@@ -13,70 +13,144 @@ const SPIN_DELAY = 100;
1313const MAX_SPIN_DELAY = 100 ;
1414const NO_OP = ( ) => { } ;
1515
16+ const isWindows = ( process . platform === 'win32' ) ;
17+
1618let spinStep = 0 ;
1719let lastSpin = 0 ;
1820let npmInitDone = false ;
1921let doAcu = false ;
2022let doDht = false ;
23+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2124let doGps = false ;
22- let doWwvb = false ;
2325let doI2c = false ;
26+ let doStdDeploy = false ;
27+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
28+ let doWwvb = false ;
29+ let isRaspberryPi = false ;
30+
31+ const chalk = new Chalk . Instance ( ) ;
32+ let canSpin = true ;
33+ let backspace = '\x08' ;
34+ let trailingSpace = ' ' ; // Two spaces
35+
36+ if ( process . platform === 'linux' ) {
37+ try {
38+ if ( fs . existsSync ( '/proc/cpuinfo' ) ) {
39+ const lines = fs . readFileSync ( '/proc/cpuinfo' ) . toString ( ) . split ( '\n' ) ;
40+
41+ for ( const line of lines ) {
42+ if ( / \b M o d e l \s * : \s * R a s p b e r r y P i \b / i. test ( line ) ) {
43+ isRaspberryPi = true ;
44+ break ;
45+ }
46+ }
47+ }
48+ }
49+ catch ( err ) {
50+ console . error ( chalk . red ( 'Raspberry Pi check failed' ) ) ;
51+ }
52+ }
2453
2554// Remove extraneous command line args, if present.
26- if ( / [ / \\ ] t s - n o d e (?: \. c m d ) ? $ / . test ( process . argv [ 0 ] ?? '' ) )
55+ if ( / \b t s - n o d e \b / . test ( process . argv [ 0 ] ?? '' ) )
2756 process . argv . splice ( 0 , 1 ) ;
2857
29- if ( / [ / \\ ] b u i l d \ .t s $ / . test ( process . argv [ 0 ] ?? '' ) )
58+ if ( / \b b u i l d \ .t s \b / . test ( process . argv [ 0 ] ?? '' ) )
3059 process . argv . splice ( 0 , 1 ) ;
3160
61+ if ( process . argv . length === 0 && isRaspberryPi ) {
62+ console . warn ( chalk . yellow ( 'Warning: no build options specified.' ) ) ;
63+ console . warn ( chalk . yellow ( 'This could be OK, or this could mean you forgot the leading ' ) +
64+ chalk . white ( '--' ) + chalk . yellow ( ' before your options.' ) ) ;
65+ }
66+
3267process . argv . forEach ( arg => {
3368 if ( arg === '--acu' )
3469 doAcu = true ;
3570 else if ( arg === '--dht' )
3671 doDht = true ;
3772 else if ( arg === '--gps' )
3873 doGps = doI2c = true ;
74+ else if ( arg === '--pt' ) {
75+ canSpin = false ;
76+ chalk . level = 0 ;
77+ backspace = '' ;
78+ trailingSpace = ' ' ;
79+ }
80+ else if ( arg === '--sd' )
81+ doStdDeploy = true ;
3982 else if ( arg === '--wwvb' )
4083 doWwvb = doI2c = true ;
4184 else {
4285 if ( arg !== '--help' )
4386 console . error ( 'Unrecognized option "' + chalk . red ( arg ) + '"' ) ;
4487
45- console . log ( 'Usage: npm run build [-- [--acu] [--dht] [--gps ] [--help ] [--wwvb ]]' ) ;
88+ console . log ( 'Usage: npm run build [-- [--acu] [--dht] [--help ] [--pt ] [--sd ]]' ) ;
4689 process . exit ( 0 ) ;
4790 }
4891} ) ;
4992
50- process . stdout . write ( ( '' + doAcu + doGps + doWwvb ) . substr ( 0 , 0 ) ) ;
93+ if ( doStdDeploy && ! isRaspberryPi ) {
94+ console . error ( chalk . red ( '--sd option is only valid on Raspberry Pi' ) ) ;
95+ process . exit ( 0 ) ;
96+ }
97+
98+ function spawn ( command : string , args : string [ ] = [ ] , options ?: any ) : ChildProcess {
99+ if ( isWindows ) {
100+ const cmd = process . env . comspec || 'cmd' ;
101+
102+ return nodeSpawn ( cmd , [ '/c' , command , ...args ] , options ) ;
103+ }
104+ else
105+ return nodeSpawn ( command , args , options ) ;
106+ }
51107
52108function spin ( ) : void {
53109 const now = processMillis ( ) ;
54110
55111 if ( lastSpin < now - SPIN_DELAY ) {
56112 lastSpin = now ;
57- process . stdout . write ( '\x08' + SPIN_CHARS . charAt ( spinStep ) ) ;
113+ process . stdout . write ( backspace + SPIN_CHARS . charAt ( spinStep ) ) ;
58114 spinStep = ( spinStep + 1 ) % 4 ;
59115 }
60116}
61117
62118function monitorProcess ( proc : ChildProcess , doSpin = true ) : Promise < string > {
119+ let errors = '' ;
63120 let output = '' ;
64121
122+ doSpin = doSpin && canSpin ;
123+
65124 return new Promise < string > ( ( resolve , reject ) => {
66125 const slowSpin = setInterval ( doSpin ? spin : NO_OP , MAX_SPIN_DELAY ) ;
67126
68- proc . stderr . on ( 'data' , doSpin ? spin : NO_OP ) ;
127+ proc . stderr . on ( 'data' , data => {
128+ ( doSpin ? spin : NO_OP ) ( ) ;
129+ data = data . toString ( ) ;
130+ // This gets confusing, because a lot of non-error progress messaging goes to stderr, and the
131+ // webpack process doesn't exit with an error for compilation errors unless you make it do so.
132+ if ( / \[ w e b p a c k .P r o g r e s s ] / . test ( data ) )
133+ return ;
134+
135+ errors += data ;
136+ } ) ;
69137 proc . stdout . on ( 'data' , data => {
70- output += data . toString ( ) ;
71138 ( doSpin ? spin : NO_OP ) ( ) ;
139+ data = data . toString ( ) ;
140+ output += data ;
141+ errors = '' ;
72142 } ) ;
73143 proc . on ( 'error' , err => {
74144 clearInterval ( slowSpin ) ;
75145 reject ( err ) ;
76146 } ) ;
77147 proc . on ( 'close' , ( ) => {
78148 clearInterval ( slowSpin ) ;
79- resolve ( output ) ;
149+
150+ if ( errors && ( / \b ( e r r o r | e x c e p t i o n ) \b / i. test ( errors ) || / [ _ 0 - 9 a - z ] ( E r r o r | E x c e p t i o n ) \b / . test ( errors ) ) )
151+ reject ( errors ) ;
152+ else
153+ resolve ( output ) ;
80154 } ) ;
81155 } ) ;
82156}
@@ -108,56 +182,67 @@ async function npmInit(): Promise<void> {
108182( async ( ) => {
109183 try {
110184 console . log ( chalk . cyan ( 'Starting build...' ) ) ;
111-
112- process . stdout . write ( 'Updating client ' ) ;
185+ process . stdout . write ( 'Updating client' + trailingSpace ) ;
113186 await monitorProcess ( spawn ( 'npm' , [ '--dev' , 'update' ] ) ) ;
114- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
187+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
115188
116- process . stdout . write ( 'Building client ' ) ;
189+ process . stdout . write ( 'Building client' + trailingSpace ) ;
117190 if ( fs . existsSync ( 'dist' ) )
118191 await monitorProcess ( spawn ( 'rm' , [ '-Rf' , 'dist' ] ) ) ;
119192 let output = await monitorProcess ( spawn ( 'webpack' ) ) ;
120- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
193+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
121194 console . log ( chalk . hex ( '#808080' ) ( getWebpackSummary ( output ) ) ) ;
122195
123- process . stdout . write ( 'Updating server ' ) ;
196+ process . stdout . write ( 'Updating server' + trailingSpace ) ;
124197 await monitorProcess ( spawn ( 'npm' , [ '--dev' , 'update' ] , { cwd : path . join ( __dirname , 'server' ) } ) ) ;
125- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
198+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
126199
127- process . stdout . write ( 'Building server ' ) ;
200+ process . stdout . write ( 'Building server' + trailingSpace ) ;
128201 if ( fs . existsSync ( 'server/dist' ) )
129202 await monitorProcess ( spawn ( 'rm' , [ '-Rf' , 'server/dist' ] ) ) ;
130- output = await monitorProcess ( spawn ( 'npm' , [ 'run' , 'build' ] , { cwd : path . join ( __dirname , 'server' ) } ) ) ;
131- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
203+ output = await monitorProcess ( spawn ( 'npm' , [ 'run' , isWindows ? 'build-win' : 'build' ] , { cwd : path . join ( __dirname , 'server' ) } ) ) ;
204+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
132205 console . log ( chalk . hex ( '#808080' ) ( getWebpackSummary ( output ) ) ) ;
133206
134207 if ( doAcu ) {
135- process . stdout . write ( 'Adding Acu-Rite wireless temperature/humidity sensor support ' ) ;
208+ process . stdout . write ( 'Adding Acu-Rite wireless temperature/humidity sensor support' + trailingSpace ) ;
136209 await npmInit ( ) ;
137- await monitorProcess ( spawn ( 'npm' , [ 'i' , 'rpi-acu-rite-temperature' ] , { cwd : path . join ( __dirname , 'server' , 'dist' ) } ) ) ;
138- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
210+ await monitorProcess ( spawn ( 'npm' , [ 'i' , 'rpi-acu-rite-temperature@2.x ' ] , { cwd : path . join ( __dirname , 'server' , 'dist' ) } ) ) ;
211+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
139212 }
140213
141214 if ( doDht ) {
142- process . stdout . write ( 'Adding DHT wired temperature/humidity sensor support ' ) ;
215+ process . stdout . write ( 'Adding DHT wired temperature/humidity sensor support' + trailingSpace ) ;
143216 await npmInit ( ) ;
144- await monitorProcess ( spawn ( 'npm' , [ 'i' , 'node-dht-sensor' ] , { cwd : path . join ( __dirname , 'server' , 'dist' ) } ) ) ;
145- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
217+ await monitorProcess ( spawn ( 'npm' , [ 'i' , 'node-dht-sensor@0.4.x ' ] , { cwd : path . join ( __dirname , 'server' , 'dist' ) } ) ) ;
218+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
146219 }
147220
148221 if ( doI2c ) {
149- process . stdout . write ( 'Adding I²C serial bus support ' ) ;
222+ process . stdout . write ( 'Adding I²C serial bus support' + trailingSpace ) ;
150223 await npmInit ( ) ;
151224 await monitorProcess ( spawn ( 'npm' , [ 'i' , 'i2c-bus' ] , { cwd : path . join ( __dirname , 'server' , 'dist' ) } ) ) ;
152- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
225+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
153226 }
154227
155- process . stdout . write ( 'Copying server to top-level dist directory ' ) ;
228+ process . stdout . write ( 'Copying server to top-level dist directory' + trailingSpace ) ;
156229 await ( promisify ( copyfiles ) as any ) ( [ 'server/dist/**/*' , 'dist/' ] , { up : 2 } ) ;
157- console . log ( '\x08' + chalk . green ( CHECK_MARK ) ) ;
230+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
231+
232+ if ( doStdDeploy ) {
233+ process . stdout . write ( 'Moving server to ~/weather directory' + trailingSpace ) ;
234+
235+ if ( ! fs . existsSync ( process . env . HOME + '/weather' ) )
236+ fs . mkdirSync ( process . env . HOME + '/weather' ) ;
237+ else
238+ await monitorProcess ( spawn ( 'rm' , [ '-Rf' , '~/weather/*' ] , { shell : true } ) ) ;
239+
240+ await monitorProcess ( spawn ( 'mv' , [ 'dist/*' , '~/weather' ] , { shell : true } ) ) ;
241+ console . log ( backspace + chalk . green ( CHECK_MARK ) ) ;
242+ }
158243 }
159244 catch ( err ) {
160- console . log ( '\x08' + chalk . red ( FAIL_MARK ) ) ;
245+ console . log ( backspace + chalk . red ( FAIL_MARK ) ) ;
161246 console . error ( err ) ;
162247 }
163248} ) ( ) ;
0 commit comments