1
- const log = require ( 'npmlog' )
2
1
const os = require ( 'os' )
3
2
const path = require ( 'path' )
4
3
const writeFileAtomic = require ( 'write-file-atomic' )
@@ -13,8 +12,6 @@ let logFileName
13
12
let npm // set by the cli
14
13
let wroteLogFile = false
15
14
16
- const timings = { }
17
-
18
15
const getLogFile = ( ) => {
19
16
// we call this multiple times, so we need to treat it as a singleton because
20
17
// the date is part of the name
@@ -24,20 +21,13 @@ const getLogFile = () => {
24
21
return logFileName
25
22
}
26
23
27
- process . on ( 'timing' , ( name , value ) => {
28
- if ( timings [ name ] )
29
- timings [ name ] += value
30
- else
31
- timings [ name ] = value
32
- } )
33
-
34
24
process . on ( 'exit' , code => {
35
25
// process.emit is synchronous, so the timeEnd handler will run before the
36
26
// unfinished timer check below
37
27
process . emit ( 'timeEnd' , 'npm' )
38
- log . disableProgress ( )
28
+ npm . log . disableProgress ( )
39
29
for ( const [ name , timers ] of npm . timers )
40
- log . verbose ( 'unfinished npm timer' , name , timers )
30
+ npm . log . verbose ( 'unfinished npm timer' , name , timers )
41
31
42
32
if ( npm . config . loaded && npm . config . get ( 'timing' ) ) {
43
33
try {
@@ -49,7 +39,7 @@ process.on('exit', code => {
49
39
command : process . argv . slice ( 2 ) ,
50
40
logfile : getLogFile ( ) ,
51
41
version : npm . version ,
52
- ...timings ,
42
+ ...npm . timings ,
53
43
} ) + '\n' )
54
44
55
45
const st = fs . lstatSync ( path . dirname ( npm . config . get ( 'cache' ) ) )
@@ -61,14 +51,14 @@ process.on('exit', code => {
61
51
}
62
52
63
53
if ( ! code )
64
- log . info ( 'ok' )
54
+ npm . log . info ( 'ok' )
65
55
else {
66
- log . verbose ( 'code' , code )
56
+ npm . log . verbose ( 'code' , code )
67
57
if ( ! exitHandlerCalled ) {
68
- log . error ( '' , 'Exit handler never called!' )
58
+ npm . log . error ( '' , 'Exit handler never called!' )
69
59
console . error ( '' )
70
- log . error ( '' , 'This is an error with npm itself. Please report this error at:' )
71
- log . error ( '' , ' <https://github.com/npm/cli/issues>' )
60
+ npm . log . error ( '' , 'This is an error with npm itself. Please report this error at:' )
61
+ npm . log . error ( '' , ' <https://github.com/npm/cli/issues>' )
72
62
// TODO this doesn't have an npm.config.loaded guard
73
63
writeLogFile ( )
74
64
}
@@ -78,10 +68,10 @@ process.on('exit', code => {
78
68
writeLogFile ( )
79
69
if ( wroteLogFile ) {
80
70
// just a line break
81
- if ( log . levels [ log . level ] <= log . levels . error )
71
+ if ( npm . log . levels [ npm . log . level ] <= npm . log . levels . error )
82
72
console . error ( '' )
83
73
84
- log . error (
74
+ npm . log . error (
85
75
'' ,
86
76
[
87
77
'A complete log of this run can be found in:' ,
@@ -93,121 +83,114 @@ process.on('exit', code => {
93
83
// these are needed for the tests to have a clean slate in each test case
94
84
exitHandlerCalled = false
95
85
wroteLogFile = false
96
-
97
- // actually exit.
98
- process . exit ( code )
99
86
} )
100
87
101
- const exit = ( code , noLog ) => {
102
- log . verbose ( 'exit' , code || 0 )
103
- if ( log . level === 'silent' )
104
- noLog = true
105
-
106
- // noLog is true if there was an error, including if config wasn't loaded, so
107
- // this doesn't need a config.loaded guard
108
- if ( code && ! noLog )
109
- writeLogFile ( )
110
-
111
- // Exit directly -- nothing in the CLI should still be running in the
112
- // background at this point, and this makes sure anything left dangling
113
- // for whatever reason gets thrown away, instead of leaving the CLI open
114
- process . stdout . write ( '' , ( ) => {
115
- process . exit ( code )
116
- } )
117
- }
118
-
119
88
const exitHandler = ( err ) => {
120
- log . disableProgress ( )
89
+ npm . log . disableProgress ( )
121
90
if ( ! npm . config . loaded ) {
122
- // logging won't work unless we pretend that it's ready
123
91
err = err || new Error ( 'Exit prior to config file resolving.' )
124
92
console . error ( err . stack || err . message )
125
93
}
126
94
127
- if ( exitHandlerCalled )
128
- err = err || new Error ( 'Exit handler called more than once.' )
129
-
130
- // only show the notification if it finished before the other stuff we
131
- // were doing. no need to hang on `npm -v` or something.
95
+ // only show the notification if it finished.
132
96
if ( typeof npm . updateNotification === 'string' ) {
133
- const { level } = log
134
- log . level = log . levels . notice
135
- log . notice ( '' , npm . updateNotification )
136
- log . level = level
97
+ const { level } = npm . log
98
+ npm . log . level = ' notice'
99
+ npm . log . notice ( '' , npm . updateNotification )
100
+ npm . log . level = level
137
101
}
138
102
139
103
exitHandlerCalled = true
140
- if ( ! err )
141
- return exit ( )
142
-
143
- // if we got a command that just shells out to something else, then it
144
- // will presumably print its own errors and exit with a proper status
145
- // code if there's a problem. If we got an error with a code=0, then...
146
- // something else went wrong along the way, so maybe an npm problem?
147
- const isShellout = npm . shelloutCommands . includes ( npm . command )
148
- const quietShellout = isShellout && typeof err . code === 'number' && err . code
149
- if ( quietShellout )
150
- return exit ( err . code , true )
151
- else if ( typeof err === 'string' ) {
152
- log . error ( '' , err )
153
- return exit ( 1 , true )
154
- } else if ( ! ( err instanceof Error ) ) {
155
- log . error ( 'weird error' , err )
156
- return exit ( 1 , true )
157
- }
158
104
159
- if ( ! err . code ) {
160
- const matchErrorCode = err . message . match ( / ^ (?: E r r o r : ) ? ( E [ A - Z ] + ) / )
161
- err . code = matchErrorCode && matchErrorCode [ 1 ]
162
- }
163
-
164
- for ( const k of [ 'type' , 'stack' , 'statusCode' , 'pkgid' ] ) {
165
- const v = err [ k ]
166
- if ( v )
167
- log . verbose ( k , replaceInfo ( v ) )
105
+ let exitCode
106
+ let noLog
107
+
108
+ if ( err ) {
109
+ exitCode = 1
110
+ // if we got a command that just shells out to something else, then it
111
+ // will presumably print its own errors and exit with a proper status
112
+ // code if there's a problem. If we got an error with a code=0, then...
113
+ // something else went wrong along the way, so maybe an npm problem?
114
+ const isShellout = npm . shelloutCommands . includes ( npm . command )
115
+ const quietShellout = isShellout && typeof err . code === 'number' && err . code
116
+ if ( quietShellout ) {
117
+ exitCode = err . code
118
+ noLog = true
119
+ } else if ( typeof err === 'string' ) {
120
+ noLog = true
121
+ npm . log . error ( '' , err )
122
+ } else if ( ! ( err instanceof Error ) ) {
123
+ noLog = true
124
+ npm . log . error ( 'weird error' , err )
125
+ } else {
126
+ if ( ! err . code ) {
127
+ const matchErrorCode = err . message . match ( / ^ (?: E r r o r : ) ? ( E [ A - Z ] + ) / )
128
+ err . code = matchErrorCode && matchErrorCode [ 1 ]
129
+ }
130
+
131
+ for ( const k of [ 'type' , 'stack' , 'statusCode' , 'pkgid' ] ) {
132
+ const v = err [ k ]
133
+ if ( v )
134
+ npm . log . verbose ( k , replaceInfo ( v ) )
135
+ }
136
+
137
+ npm . log . verbose ( 'cwd' , process . cwd ( ) )
138
+
139
+ const args = replaceInfo ( process . argv )
140
+ npm . log . verbose ( '' , os . type ( ) + ' ' + os . release ( ) )
141
+ npm . log . verbose ( 'argv' , args . map ( JSON . stringify ) . join ( ' ' ) )
142
+ npm . log . verbose ( 'node' , process . version )
143
+ npm . log . verbose ( 'npm ' , 'v' + npm . version )
144
+
145
+ for ( const k of [ 'code' , 'syscall' , 'file' , 'path' , 'dest' , 'errno' ] ) {
146
+ const v = err [ k ]
147
+ if ( v )
148
+ npm . log . error ( k , v )
149
+ }
150
+
151
+ const msg = errorMessage ( err , npm )
152
+ for ( const errline of [ ...msg . summary , ...msg . detail ] )
153
+ npm . log . error ( ...errline )
154
+
155
+ if ( npm . config . loaded && npm . config . get ( 'json' ) ) {
156
+ const error = {
157
+ error : {
158
+ code : err . code ,
159
+ summary : messageText ( msg . summary ) ,
160
+ detail : messageText ( msg . detail ) ,
161
+ } ,
162
+ }
163
+ console . error ( JSON . stringify ( error , null , 2 ) )
164
+ }
165
+
166
+ if ( typeof err . errno === 'number' )
167
+ exitCode = err . errno
168
+ else if ( typeof err . code === 'number' )
169
+ exitCode = err . code
170
+ }
168
171
}
172
+ npm . log . verbose ( 'exit' , exitCode || 0 )
169
173
170
- log . verbose ( 'cwd' , process . cwd ( ) )
171
-
172
- const args = replaceInfo ( process . argv )
173
- log . verbose ( '' , os . type ( ) + ' ' + os . release ( ) )
174
- log . verbose ( 'argv' , args . map ( JSON . stringify ) . join ( ' ' ) )
175
- log . verbose ( 'node' , process . version )
176
- log . verbose ( 'npm ' , 'v' + npm . version )
177
-
178
- for ( const k of [ 'code' , 'syscall' , 'file' , 'path' , 'dest' , 'errno' ] ) {
179
- const v = err [ k ]
180
- if ( v )
181
- log . error ( k , v )
182
- }
174
+ if ( npm . log . level === 'silent' )
175
+ noLog = true
183
176
184
- const msg = errorMessage ( err , npm )
185
- for ( const errline of [ ...msg . summary , ...msg . detail ] )
186
- log . error ( ...errline )
187
-
188
- if ( npm . config . loaded && npm . config . get ( 'json' ) ) {
189
- const error = {
190
- error : {
191
- code : err . code ,
192
- summary : messageText ( msg . summary ) ,
193
- detail : messageText ( msg . detail ) ,
194
- } ,
195
- }
196
- console . error ( JSON . stringify ( error , null , 2 ) )
197
- }
177
+ // noLog is true if there was an error, including if config wasn't loaded, so
178
+ // this doesn't need a config.loaded guard
179
+ if ( exitCode && ! noLog )
180
+ writeLogFile ( )
198
181
199
- exit ( typeof err . errno === 'number' ? err . errno : typeof err . code === 'number' ? err . code : 1 )
182
+ // explicitly call process.exit now so we don't hang on things like the
183
+ // update notifier, also flush stdout beforehand because process.exit doesn't
184
+ // wait for that to happen.
185
+ process . stdout . write ( '' , ( ) => process . exit ( exitCode ) )
200
186
}
201
187
202
188
const messageText = msg => msg . map ( line => line . slice ( 1 ) . join ( ' ' ) ) . join ( '\n' )
203
189
204
190
const writeLogFile = ( ) => {
205
- if ( wroteLogFile )
206
- return
207
-
208
191
try {
209
192
let logOutput = ''
210
- log . record . forEach ( m => {
193
+ npm . log . record . forEach ( m => {
211
194
const p = [ m . id , m . level ]
212
195
if ( m . prefix )
213
196
p . push ( m . prefix )
@@ -230,7 +213,7 @@ const writeLogFile = () => {
230
213
fs . chownSync ( file , st . uid , st . gid )
231
214
232
215
// truncate once it's been written.
233
- log . record . length = 0
216
+ npm . log . record . length = 0
234
217
wroteLogFile = true
235
218
} catch ( ex ) {
236
219
0 commit comments