3
3
const BB = require ( 'bluebird' )
4
4
5
5
const cacache = require ( 'cacache' )
6
- const createReadStream = require ( 'graceful-fs' ) . createReadStream
7
- const getPublishConfig = require ( './utils/get-publish-config.js' )
6
+ const figgyPudding = require ( 'figgy-pudding' )
7
+ const libpub = require ( 'libnpm/publish' )
8
+ const libunpub = require ( 'libnpm/unpublish' )
8
9
const lifecycle = BB . promisify ( require ( './utils/lifecycle.js' ) )
9
10
const log = require ( 'npmlog' )
10
- const mapToRegistry = require ( './utils/map-to-registry.js' )
11
- const npa = require ( 'npm-package-arg' )
12
- const npm = require ( './npm.js' )
11
+ const npa = require ( 'libnpm/parse-arg' )
12
+ const npmConfig = require ( './config/figgy-config.js' )
13
13
const output = require ( './utils/output.js' )
14
+ const otplease = require ( './utils/otplease.js' )
14
15
const pack = require ( './pack' )
15
- const pacote = require ( 'pacote ' )
16
+ const { tarball , extract } = require ( 'libnpm ' )
16
17
const pacoteOpts = require ( './config/pacote' )
17
18
const path = require ( 'path' )
19
+ const readFileAsync = BB . promisify ( require ( 'graceful-fs' ) . readFile )
18
20
const readJson = BB . promisify ( require ( 'read-package-json' ) )
19
- const readUserInfo = require ( './utils/read-user-info.js' )
20
21
const semver = require ( 'semver' )
21
22
const statAsync = BB . promisify ( require ( 'graceful-fs' ) . stat )
22
23
@@ -31,6 +32,16 @@ publish.completion = function (opts, cb) {
31
32
return cb ( )
32
33
}
33
34
35
+ const PublishConfig = figgyPudding ( {
36
+ dryRun : 'dry-run' ,
37
+ 'dry-run' : { default : false } ,
38
+ force : { default : false } ,
39
+ json : { default : false } ,
40
+ Promise : { default : ( ) => Promise } ,
41
+ tag : { default : 'latest' } ,
42
+ tmp : { }
43
+ } )
44
+
34
45
module . exports = publish
35
46
function publish ( args , isRetry , cb ) {
36
47
if ( typeof cb !== 'function' ) {
@@ -42,15 +53,16 @@ function publish (args, isRetry, cb) {
42
53
43
54
log . verbose ( 'publish' , args )
44
55
45
- const t = npm . config . get ( 'tag' ) . trim ( )
56
+ const opts = PublishConfig ( npmConfig ( ) )
57
+ const t = opts . tag . trim ( )
46
58
if ( semver . validRange ( t ) ) {
47
59
return cb ( new Error ( 'Tag name must not be a valid SemVer range: ' + t ) )
48
60
}
49
61
50
- return publish_ ( args [ 0 ] )
62
+ return publish_ ( args [ 0 ] , opts )
51
63
. then ( ( tarball ) => {
52
64
const silent = log . level === 'silent'
53
- if ( ! silent && npm . config . get ( ' json' ) ) {
65
+ if ( ! silent && opts . json ) {
54
66
output ( JSON . stringify ( tarball , null , 2 ) )
55
67
} else if ( ! silent ) {
56
68
output ( `+ ${ tarball . id } ` )
@@ -59,7 +71,7 @@ function publish (args, isRetry, cb) {
59
71
. nodeify ( cb )
60
72
}
61
73
62
- function publish_ ( arg ) {
74
+ function publish_ ( arg , opts ) {
63
75
return statAsync ( arg ) . then ( ( stat ) => {
64
76
if ( stat . isDirectory ( ) ) {
65
77
return stat
@@ -69,17 +81,17 @@ function publish_ (arg) {
69
81
throw err
70
82
}
71
83
} ) . then ( ( ) => {
72
- return publishFromDirectory ( arg )
84
+ return publishFromDirectory ( arg , opts )
73
85
} , ( err ) => {
74
86
if ( err . code !== 'ENOENT' && err . code !== 'ENOTDIR' ) {
75
87
throw err
76
88
} else {
77
- return publishFromPackage ( arg )
89
+ return publishFromPackage ( arg , opts )
78
90
}
79
91
} )
80
92
}
81
93
82
- function publishFromDirectory ( arg ) {
94
+ function publishFromDirectory ( arg , opts ) {
83
95
// All this readJson is because any of the given scripts might modify the
84
96
// package.json in question, so we need to refresh after every step.
85
97
let contents
@@ -90,12 +102,12 @@ function publishFromDirectory (arg) {
90
102
} ) . then ( ( ) => {
91
103
return readJson ( path . join ( arg , 'package.json' ) )
92
104
} ) . then ( ( pkg ) => {
93
- return cacache . tmp . withTmp ( npm . tmp , { tmpPrefix : 'fromDir' } , ( tmpDir ) => {
105
+ return cacache . tmp . withTmp ( opts . tmp , { tmpPrefix : 'fromDir' } , ( tmpDir ) => {
94
106
const target = path . join ( tmpDir , 'package.tgz' )
95
107
return pack . packDirectory ( pkg , arg , target , null , true )
96
108
. tap ( ( c ) => { contents = c } )
97
- . then ( ( c ) => ! npm . config . get ( ' json' ) && pack . logContents ( c ) )
98
- . then ( ( ) => upload ( arg , pkg , false , target ) )
109
+ . then ( ( c ) => ! opts . json && pack . logContents ( c ) )
110
+ . then ( ( ) => upload ( pkg , false , target , opts ) )
99
111
} )
100
112
} ) . then ( ( ) => {
101
113
return readJson ( path . join ( arg , 'package.json' ) )
@@ -107,121 +119,51 @@ function publishFromDirectory (arg) {
107
119
. then ( ( ) => contents )
108
120
}
109
121
110
- function publishFromPackage ( arg ) {
111
- return cacache . tmp . withTmp ( npm . tmp , { tmpPrefix : 'fromPackage' } , ( tmp ) => {
122
+ function publishFromPackage ( arg , opts ) {
123
+ return cacache . tmp . withTmp ( opts . tmp , { tmpPrefix : 'fromPackage' } , tmp => {
112
124
const extracted = path . join ( tmp , 'package' )
113
125
const target = path . join ( tmp , 'package.json' )
114
- const opts = pacoteOpts ( )
115
- return pacote . tarball . toFile ( arg , target , opts )
116
- . then ( ( ) => pacote . extract ( arg , extracted , opts ) )
126
+ const pacOpts = pacoteOpts ( )
127
+ return tarball . toFile ( arg , target , pacOpts )
128
+ . then ( ( ) => extract ( arg , extracted , pacOpts ) )
117
129
. then ( ( ) => readJson ( path . join ( extracted , 'package.json' ) ) )
118
130
. then ( ( pkg ) => {
119
131
return BB . resolve ( pack . getContents ( pkg , target ) )
120
- . tap ( ( c ) => ! npm . config . get ( ' json' ) && pack . logContents ( c ) )
121
- . tap ( ( ) => upload ( arg , pkg , false , target ) )
132
+ . tap ( ( c ) => ! opts . json && pack . logContents ( c ) )
133
+ . tap ( ( ) => upload ( pkg , false , target , opts ) )
122
134
} )
123
135
} )
124
136
}
125
137
126
- function upload ( arg , pkg , isRetry , cached ) {
127
- if ( ! pkg ) {
128
- return BB . reject ( new Error ( 'no package.json file found' ) )
129
- }
130
- if ( pkg . private ) {
131
- return BB . reject ( new Error (
132
- 'This package has been marked as private\n' +
133
- "Remove the 'private' field from the package.json to publish it."
134
- ) )
135
- }
136
- const mappedConfig = getPublishConfig (
137
- pkg . publishConfig ,
138
- npm . config ,
139
- npm . registry
140
- )
141
- const config = mappedConfig . config
142
- const registry = mappedConfig . client
143
-
144
- pkg . _npmVersion = npm . version
145
- pkg . _nodeVersion = process . versions . node
146
-
147
- delete pkg . modules
148
-
149
- return BB . fromNode ( ( cb ) => {
150
- mapToRegistry ( pkg . name , config , ( err , registryURI , auth , registryBase ) => {
151
- if ( err ) { return cb ( err ) }
152
- cb ( null , [ registryURI , auth , registryBase ] )
153
- } )
154
- } ) . spread ( ( registryURI , auth , registryBase ) => {
155
- // we just want the base registry URL in this case
156
- log . verbose ( 'publish' , 'registryBase' , registryBase )
157
- log . silly ( 'publish' , 'uploading' , cached )
158
-
159
- pkg . _npmUser = {
160
- name : auth . username ,
161
- email : auth . email
162
- }
163
-
164
- const params = {
165
- metadata : pkg ,
166
- body : ! npm . config . get ( 'dry-run' ) && createReadStream ( cached ) ,
167
- auth : auth
168
- }
169
-
170
- function closeFile ( ) {
171
- if ( ! npm . config . get ( 'dry-run' ) ) {
172
- params . body . close ( )
173
- }
174
- }
175
-
176
- // registry-frontdoor cares about the access level, which is only
177
- // configurable for scoped packages
178
- if ( config . get ( 'access' ) ) {
179
- if ( ! npa ( pkg . name ) . scope && config . get ( 'access' ) === 'restricted' ) {
180
- throw new Error ( "Can't restrict access to unscoped packages." )
181
- }
182
-
183
- params . access = config . get ( 'access' )
184
- }
185
-
186
- if ( npm . config . get ( 'dry-run' ) ) {
187
- log . verbose ( 'publish' , '--dry-run mode enabled. Skipping upload.' )
188
- return BB . resolve ( )
189
- }
190
-
191
- log . showProgress ( 'publish:' + pkg . _id )
192
- return BB . fromNode ( ( cb ) => {
193
- registry . publish ( registryBase , params , cb )
194
- } ) . catch ( ( err ) => {
195
- if (
196
- err . code === 'EPUBLISHCONFLICT' &&
197
- npm . config . get ( 'force' ) &&
198
- ! isRetry
199
- ) {
200
- log . warn ( 'publish' , 'Forced publish over ' + pkg . _id )
201
- return BB . fromNode ( ( cb ) => {
202
- npm . commands . unpublish ( [ pkg . _id ] , cb )
203
- } ) . finally ( ( ) => {
204
- // close the file we are trying to upload, we will open it again.
205
- closeFile ( )
206
- // ignore errors. Use the force. Reach out with your feelings.
207
- return upload ( arg , pkg , true , cached ) . catch ( ( ) => {
208
- // but if it fails again, then report the first error.
209
- throw err
138
+ function upload ( pkg , isRetry , cached , opts ) {
139
+ if ( ! opts . dryRun ) {
140
+ return readFileAsync ( cached ) . then ( tarball => {
141
+ return otplease ( opts , opts => {
142
+ return libpub ( pkg , tarball , opts )
143
+ } ) . catch ( err => {
144
+ if (
145
+ err . code === 'EPUBLISHCONFLICT' &&
146
+ opts . force &&
147
+ ! isRetry
148
+ ) {
149
+ log . warn ( 'publish' , 'Forced publish over ' + pkg . _id )
150
+ return otplease ( opts , opts => libunpub (
151
+ npa . resolve ( pkg . name , pkg . version ) , opts
152
+ ) ) . finally ( ( ) => {
153
+ // ignore errors. Use the force. Reach out with your feelings.
154
+ return otplease ( opts , opts => {
155
+ return upload ( pkg , true , tarball , opts )
156
+ } ) . catch ( ( ) => {
157
+ // but if it fails again, then report the first error.
158
+ throw err
159
+ } )
210
160
} )
211
- } )
212
- } else {
213
- // close the file we are trying to upload, all attempts to resume will open it again
214
- closeFile ( )
215
- throw err
216
- }
217
- } )
218
- } ) . catch ( ( err ) => {
219
- if ( err . code !== 'EOTP' && ! ( err . code === 'E401' && / o n e - t i m e p a s s / . test ( err . message ) ) ) throw err
220
- // we prompt on stdout and read answers from stdin, so they need to be ttys.
221
- if ( ! process . stdin . isTTY || ! process . stdout . isTTY ) throw err
222
- return readUserInfo . otp ( ) . then ( ( otp ) => {
223
- npm . config . set ( 'otp' , otp )
224
- return upload ( arg , pkg , isRetry , cached )
161
+ } else {
162
+ throw err
163
+ }
164
+ } )
225
165
} )
226
- } )
166
+ } else {
167
+ return opts . Promise . resolve ( true )
168
+ }
227
169
}
0 commit comments