1 |
|
2 | module.exports = owner
|
3 |
|
4 | var npm = require('./npm.js')
|
5 | var log = require('npmlog')
|
6 | var mapToRegistry = require('./utils/map-to-registry.js')
|
7 | var readLocalPkg = require('./utils/read-local-package.js')
|
8 | var usage = require('./utils/usage')
|
9 | var output = require('./utils/output.js')
|
10 |
|
11 | owner.usage = usage(
|
12 | 'owner',
|
13 | 'npm owner add <user> [<@scope>/]<pkg>' +
|
14 | '\nnpm owner rm <user> [<@scope>/]<pkg>' +
|
15 | '\nnpm owner ls [<@scope>/]<pkg>'
|
16 | )
|
17 | owner.completion = function (opts, cb) {
|
18 | var argv = opts.conf.argv.remain
|
19 | if (argv.length > 4) return cb()
|
20 | if (argv.length <= 2) {
|
21 | var subs = ['add', 'rm']
|
22 | if (opts.partialWord === 'l') subs.push('ls')
|
23 | else subs.push('ls', 'list')
|
24 | return cb(null, subs)
|
25 | }
|
26 |
|
27 | npm.commands.whoami([], true, function (er, username) {
|
28 | if (er) return cb()
|
29 |
|
30 | var un = encodeURIComponent(username)
|
31 | var byUser, theUser
|
32 | switch (argv[2]) {
|
33 | case 'ls':
|
34 |
|
35 |
|
36 | return cb()
|
37 |
|
38 | case 'rm':
|
39 | if (argv.length > 3) {
|
40 | theUser = encodeURIComponent(argv[3])
|
41 | byUser = '-/by-user/' + theUser + '|' + un
|
42 | return mapToRegistry(byUser, npm.config, function (er, uri, auth) {
|
43 | if (er) return cb(er)
|
44 |
|
45 | console.error(uri)
|
46 | npm.registry.get(uri, { auth: auth }, function (er, d) {
|
47 | if (er) return cb(er)
|
48 |
|
49 | return cb(null, d[theUser].filter(function (p) {
|
50 |
|
51 | return un === 'isaacs' || d[un].indexOf(p) === -1
|
52 | }))
|
53 | })
|
54 | })
|
55 | }
|
56 |
|
57 |
|
58 | case 'add':
|
59 | if (argv.length > 3) {
|
60 | theUser = encodeURIComponent(argv[3])
|
61 | byUser = '-/by-user/' + theUser + '|' + un
|
62 | return mapToRegistry(byUser, npm.config, function (er, uri, auth) {
|
63 | if (er) return cb(er)
|
64 |
|
65 | console.error(uri)
|
66 | npm.registry.get(uri, { auth: auth }, function (er, d) {
|
67 | console.error(uri, er || d)
|
68 |
|
69 | if (er) return cb(er)
|
70 | var mine = d[un] || []
|
71 | var theirs = d[theUser] || []
|
72 | return cb(null, mine.filter(function (p) {
|
73 | return theirs.indexOf(p) === -1
|
74 | }))
|
75 | })
|
76 | })
|
77 | }
|
78 |
|
79 | return mapToRegistry('-/users', npm.config, function (er, uri, auth) {
|
80 | if (er) return cb(er)
|
81 |
|
82 | npm.registry.get(uri, { auth: auth }, function (er, list) {
|
83 | if (er) return cb()
|
84 | return cb(null, Object.keys(list).filter(function (n) {
|
85 | return n !== un
|
86 | }))
|
87 | })
|
88 | })
|
89 |
|
90 | default:
|
91 | return cb()
|
92 | }
|
93 | })
|
94 | }
|
95 |
|
96 | function owner (args, cb) {
|
97 | var action = args.shift()
|
98 | switch (action) {
|
99 | case 'ls': case 'list': return ls(args[0], cb)
|
100 | case 'add': return add(args[0], args[1], cb)
|
101 | case 'rm': case 'remove': return rm(args[0], args[1], cb)
|
102 | default: return unknown(action, cb)
|
103 | }
|
104 | }
|
105 |
|
106 | function ls (pkg, cb) {
|
107 | if (!pkg) {
|
108 | return readLocalPkg(function (er, pkg) {
|
109 | if (er) return cb(er)
|
110 | if (!pkg) return cb(owner.usage)
|
111 | ls(pkg, cb)
|
112 | })
|
113 | }
|
114 |
|
115 | mapToRegistry(pkg, npm.config, function (er, uri, auth) {
|
116 | if (er) return cb(er)
|
117 |
|
118 | npm.registry.get(uri, { auth: auth }, function (er, data) {
|
119 | var msg = ''
|
120 | if (er) {
|
121 | log.error('owner ls', "Couldn't get owner data", pkg)
|
122 | return cb(er)
|
123 | }
|
124 | var owners = data.maintainers
|
125 | if (!owners || !owners.length) {
|
126 | msg = 'admin party!'
|
127 | } else {
|
128 | msg = owners.map(function (o) {
|
129 | return o.name + ' <' + o.email + '>'
|
130 | }).join('\n')
|
131 | }
|
132 | output(msg)
|
133 | cb(er, owners)
|
134 | })
|
135 | })
|
136 | }
|
137 |
|
138 | function add (user, pkg, cb) {
|
139 | if (!user) return cb(owner.usage)
|
140 | if (!pkg) {
|
141 | return readLocalPkg(function (er, pkg) {
|
142 | if (er) return cb(er)
|
143 | if (!pkg) return cb(new Error(owner.usage))
|
144 | add(user, pkg, cb)
|
145 | })
|
146 | }
|
147 |
|
148 | log.verbose('owner add', '%s to %s', user, pkg)
|
149 | mutate(pkg, user, function (u, owners) {
|
150 | if (!owners) owners = []
|
151 | for (var i = 0, l = owners.length; i < l; i++) {
|
152 | var o = owners[i]
|
153 | if (o.name === u.name) {
|
154 | log.info(
|
155 | 'owner add',
|
156 | 'Already a package owner: ' + o.name + ' <' + o.email + '>'
|
157 | )
|
158 | return false
|
159 | }
|
160 | }
|
161 | owners.push(u)
|
162 | return owners
|
163 | }, cb)
|
164 | }
|
165 |
|
166 | function rm (user, pkg, cb) {
|
167 | if (!pkg) {
|
168 | return readLocalPkg(function (er, pkg) {
|
169 | if (er) return cb(er)
|
170 | if (!pkg) return cb(new Error(owner.usage))
|
171 | rm(user, pkg, cb)
|
172 | })
|
173 | }
|
174 |
|
175 | log.verbose('owner rm', '%s from %s', user, pkg)
|
176 | mutate(pkg, user, function (u, owners) {
|
177 | var found = false
|
178 | var m = owners.filter(function (o) {
|
179 | var match = (o.name === user)
|
180 | found = found || match
|
181 | return !match
|
182 | })
|
183 |
|
184 | if (!found) {
|
185 | log.info('owner rm', 'Not a package owner: ' + user)
|
186 | return false
|
187 | }
|
188 |
|
189 | if (!m.length) {
|
190 | return new Error(
|
191 | 'Cannot remove all owners of a package. Add someone else first.'
|
192 | )
|
193 | }
|
194 |
|
195 | return m
|
196 | }, cb)
|
197 | }
|
198 |
|
199 | function mutate (pkg, user, mutation, cb) {
|
200 | if (user) {
|
201 | var byUser = '-/user/org.couchdb.user:' + user
|
202 | mapToRegistry(byUser, npm.config, function (er, uri, auth) {
|
203 | if (er) return cb(er)
|
204 |
|
205 | npm.registry.get(uri, { auth: auth }, mutate_)
|
206 | })
|
207 | } else {
|
208 | mutate_(null, null)
|
209 | }
|
210 |
|
211 | function mutate_ (er, u) {
|
212 | if (!er && user && (!u || u.error)) {
|
213 | er = new Error(
|
214 | "Couldn't get user data for " + user + ': ' + JSON.stringify(u)
|
215 | )
|
216 | }
|
217 |
|
218 | if (er) {
|
219 | log.error('owner mutate', 'Error getting user data for %s', user)
|
220 | return cb(er)
|
221 | }
|
222 |
|
223 | if (u) u = { name: u.name, email: u.email }
|
224 | mapToRegistry(pkg, npm.config, function (er, uri, auth) {
|
225 | if (er) return cb(er)
|
226 |
|
227 | npm.registry.get(uri, { auth: auth }, function (er, data) {
|
228 | if (er) {
|
229 | log.error('owner mutate', 'Error getting package data for %s', pkg)
|
230 | return cb(er)
|
231 | }
|
232 |
|
233 |
|
234 |
|
235 | var beforeMutation = data.maintainers.length
|
236 |
|
237 | var m = mutation(u, data.maintainers)
|
238 | if (!m) return cb()
|
239 | if (m instanceof Error) return cb(m)
|
240 |
|
241 | data = {
|
242 | _id: data._id,
|
243 | _rev: data._rev,
|
244 | maintainers: m
|
245 | }
|
246 | var dataPath = pkg.replace('/', '%2f') + '/-rev/' + data._rev
|
247 | mapToRegistry(dataPath, npm.config, function (er, uri, auth) {
|
248 | if (er) return cb(er)
|
249 |
|
250 | var params = {
|
251 | method: 'PUT',
|
252 | body: data,
|
253 | auth: auth
|
254 | }
|
255 | npm.registry.request(uri, params, function (er, data) {
|
256 | if (!er && data.error) {
|
257 | er = new Error('Failed to update package metadata: ' + JSON.stringify(data))
|
258 | }
|
259 |
|
260 | if (er) {
|
261 | log.error('owner mutate', 'Failed to update package metadata')
|
262 | } else if (m.length > beforeMutation) {
|
263 | output('+ %s (%s)', user, pkg)
|
264 | } else if (m.length < beforeMutation) {
|
265 | output('- %s (%s)', user, pkg)
|
266 | }
|
267 |
|
268 | cb(er, data)
|
269 | })
|
270 | })
|
271 | })
|
272 | })
|
273 | }
|
274 | }
|
275 |
|
276 | function unknown (action, cb) {
|
277 | cb('Usage: \n' + owner.usage)
|
278 | }
|