@@ -20,55 +20,50 @@ import { Table, Arguments, CodedError, Streamable, Abortable, Watchable, Watcher
20
20
import fqn from '../fqn'
21
21
import { formatOf , KubeOptions , KubeExecOptions } from '../options'
22
22
23
- import { preprocessTable , Pair } from '../../../lib/view/formatTable'
23
+ import { Pair } from '../../../lib/view/formatTable'
24
24
import { getCommandFromArgs } from '../../../lib/util/util'
25
25
26
26
const debug = Debug ( 'plugin-kubectl/controller/watch/watcher' )
27
27
28
- /**
29
- * We might get partial rows back; they will have empty strings in the
30
- * value field.
31
- *
32
- */
33
- function isFullRow ( row : Pair [ ] , nCols : number ) : boolean {
34
- return row . length === nCols && row . every ( _ => _ . value . length > 0 )
35
- }
36
-
37
- /**
38
- * Return the pair of indices that define the extent of "full" rows
39
- * in the given table. Since we are streaming output from kubectl, we
40
- * get back partial rows in any one bundle of bits.
41
- *
42
- */
43
- function findFullRows ( arr : Pair [ ] [ ] , nCols : number ) : { firstFullIdx : number ; lastFullIdx : number } {
44
- if ( arr . length > 0 ) {
45
- // value=NAME means that this is a header column; we know this
46
- // because, below, we are in charge of the schema of the table!
47
- // skip over that here, because we want to find the interval of
48
- // "full" body rows, i.e. excluding the header row
49
- const startIdx = arr . findIndex ( row => row . length === nCols && row [ 0 ] . value !== 'NAME' )
28
+ function preprocessTable ( raw : string , nCols ) : { rows : Pair [ ] [ ] ; leftover : string } {
29
+ const rows = raw . split ( / \n / ) . map ( line => {
30
+ const cells = line . split ( / \| / )
31
+ return cells . slice ( 0 , cells . length - 1 ) // we have a trailing |
32
+ } )
50
33
51
- if ( startIdx >= 0 ) {
52
- for ( let idx = startIdx ; idx < arr . length ; idx ++ ) {
53
- if ( isFullRow ( arr [ idx ] , nCols ) ) {
54
- // then we have found the \lower\ bound
55
- for ( let jdx = arr . length - 1 ; jdx >= idx ; jdx -- ) {
56
- if ( isFullRow ( arr [ jdx ] , nCols ) ) {
57
- // and now we have found the /upper/ bound
58
- return { firstFullIdx : idx , lastFullIdx : jdx }
59
- }
60
- }
34
+ let lastFullRowIdx = rows . length
35
+ while ( -- lastFullRowIdx >= 0 ) {
36
+ if ( rows [ lastFullRowIdx ] . length === nCols ) {
37
+ break
38
+ }
39
+ }
61
40
62
- // hmm, we couldn't find an upper bound, but we did find a
63
- // lower bound
64
- return { firstFullIdx : idx , lastFullIdx : idx }
65
- }
41
+ if ( lastFullRowIdx < 0 ) {
42
+ return {
43
+ leftover : raw ,
44
+ rows : [ ]
45
+ }
46
+ } else if ( lastFullRowIdx === rows . length - 1 ) {
47
+ return {
48
+ leftover : undefined ,
49
+ rows : rows . map ( line => line . map ( value => ( { key : value , value } ) ) ) . filter ( _ => _ . length > 0 )
50
+ }
51
+ } else {
52
+ let lastNewlineIdx = raw . length
53
+ while ( -- lastNewlineIdx >= 0 ) {
54
+ if ( raw . charAt ( lastNewlineIdx ) === '\n' ) {
55
+ break
66
56
}
67
57
}
68
- }
69
58
70
- // hmm, then we couldn't even find a lower bound
71
- return { firstFullIdx : - 1 , lastFullIdx : - 1 }
59
+ return {
60
+ leftover : raw . slice ( lastNewlineIdx ) ,
61
+ rows : rows
62
+ . slice ( 0 , lastFullRowIdx + 1 )
63
+ . map ( line => line . map ( value => ( { key : value , value } ) ) )
64
+ . filter ( _ => _ . length > 0 )
65
+ }
66
+ }
72
67
}
73
68
74
69
class KubectlWatcher implements Abortable , Watcher {
@@ -129,7 +124,7 @@ class KubectlWatcher implements Abortable, Watcher {
129
124
return async ( _ : Streamable ) => {
130
125
if ( typeof _ === 'string' ) {
131
126
// <-- strings flowing out of the PTY
132
- debug ( 'streaming pty output' , _ )
127
+ // debug('streaming pty output', _)
133
128
if ( / n o t f o u n d / . test ( _ ) ) {
134
129
this . pusher . allOffline ( )
135
130
return
@@ -146,26 +141,11 @@ class KubectlWatcher implements Abortable, Watcher {
146
141
this . leftover = undefined
147
142
148
143
// here is where we turn the raw data into tabular data
149
- const allRows = preprocessTable ( [ rawData ] ) [ 0 ]
150
-
151
- // find the interval of "full" rows; we may get back partial
152
- // rows, due to the way output streams back to us from the
153
- // underlying PTY
154
- const { firstFullIdx, lastFullIdx } = findFullRows ( allRows , this . nCols )
155
-
156
- if ( lastFullIdx < 0 ) {
157
- // then we got no full rows
158
- debug ( 'no full rows' , _ )
159
- this . leftover = _
160
- return
161
- } else if ( lastFullIdx < allRows . length - 1 ) {
162
- // the we got some trailing leftover bits
163
- const lastNewlineIdx = _ . lastIndexOf ( '\n' )
164
- this . leftover = _ . slice ( lastNewlineIdx )
165
- }
144
+ const preprocessed = preprocessTable ( rawData , this . nCols )
145
+ this . leftover = preprocessed . leftover === '\n' ? undefined : preprocessed . leftover
146
+ const { rows } = preprocessed
166
147
167
148
// now process the full rows into table view updates
168
- const rows = allRows . slice ( firstFullIdx , lastFullIdx + 1 )
169
149
const tables = await Promise . all (
170
150
rows . map ( async row => {
171
151
try {
@@ -208,8 +188,12 @@ class KubectlWatcher implements Abortable, Watcher {
208
188
if ( table ) {
209
189
table . body . forEach ( row => {
210
190
// push an update to the table model
211
- this . pusher . update ( row )
191
+ // true means we want to do a batch update
192
+ this . pusher . update ( row , true )
212
193
} )
194
+
195
+ // batch update done!
196
+ this . pusher . batchUpdateDone ( )
213
197
}
214
198
} )
215
199
} else {
@@ -238,7 +222,7 @@ class KubectlWatcher implements Abortable, Watcher {
238
222
. replace ( / ^ k ( \s ) / , 'kubectl$1' )
239
223
. replace ( / - - w a t c h = t r u e | - w = t r u e | - - w a t c h - o n l y = t r u e | - - w a t c h | - w | - - w a t c h - o n l y / g, '--watch' ) // force --watch
240
224
. replace ( new RegExp ( `(-o|--output)(\\s+|=)${ this . output } ` ) , '' ) +
241
- ` -o custom-columns=NAME: .metadata.name,KIND: .kind,APIVERSION: .apiVersion,NAMESPACE: .metadata.namespace`
225
+ ` -o jsonpath='{ .metadata.name}{"|"}{ .kind}{"|"}{ .apiVersion}{"|"}{ .metadata.namespace}{"|\\n"}' `
242
226
// ^^^^^ keep these in sync with nCols above !!
243
227
244
228
this . args . REPL . qexec ( `sendtopty ${ command } ` , this . args . block , undefined , {
0 commit comments