]> gerrit.simantics Code Review - simantics/district.git/blob - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/npm-registry-client/lib/publish.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / npm-registry-client / lib / publish.js
1 module.exports = publish
2
3 var url = require('url')
4 var semver = require('semver')
5 var crypto = require('crypto')
6 var Stream = require('stream').Stream
7 var assert = require('assert')
8 var fixer = require('normalize-package-data').fixer
9 var concat = require('concat-stream')
10
11 function escaped (name) {
12   return name.replace('/', '%2f')
13 }
14
15 function publish (uri, params, cb) {
16   assert(typeof uri === 'string', 'must pass registry URI to publish')
17   assert(params && typeof params === 'object', 'must pass params to publish')
18   assert(typeof cb === 'function', 'must pass callback to publish')
19
20   var access = params.access
21   assert(
22     (!access) || ['public', 'restricted'].indexOf(access) !== -1,
23     "if present, access level must be either 'public' or 'restricted'"
24   )
25
26   var auth = params.auth
27   assert(auth && typeof auth === 'object', 'must pass auth to publish')
28   if (!(auth.token ||
29         (auth.password && auth.username && auth.email))) {
30     var er = new Error('auth required for publishing')
31     er.code = 'ENEEDAUTH'
32     return cb(er)
33   }
34
35   var metadata = params.metadata
36   assert(
37     metadata && typeof metadata === 'object',
38     'must pass package metadata to publish'
39   )
40   try {
41     fixer.fixNameField(metadata, {strict: true, allowLegacyCase: true})
42   } catch (er) {
43     return cb(er)
44   }
45   var version = semver.clean(metadata.version)
46   if (!version) return cb(new Error('invalid semver: ' + metadata.version))
47   metadata.version = version
48
49   var body = params.body
50   assert(body, 'must pass package body to publish')
51   assert(body instanceof Stream, 'package body passed to publish must be a stream')
52   var client = this
53   var sink = concat(function (tarbuffer) {
54     putFirst.call(client, uri, metadata, tarbuffer, access, auth, cb)
55   })
56   sink.on('error', cb)
57   body.pipe(sink)
58 }
59
60 function putFirst (registry, data, tarbuffer, access, auth, cb) {
61   // optimistically try to PUT all in one single atomic thing.
62   // If 409, then GET and merge, try again.
63   // If other error, then fail.
64
65   var root = {
66     _id: data.name,
67     name: data.name,
68     description: data.description,
69     'dist-tags': {},
70     versions: {},
71     readme: data.readme || ''
72   }
73
74   if (access) root.access = access
75
76   if (!auth.token) {
77     root.maintainers = [{ name: auth.username, email: auth.email }]
78     data.maintainers = JSON.parse(JSON.stringify(root.maintainers))
79   }
80
81   root.versions[ data.version ] = data
82   var tag = data.tag || this.config.defaultTag
83   root['dist-tags'][tag] = data.version
84
85   var tbName = data.name + '-' + data.version + '.tgz'
86   var tbURI = data.name + '/-/' + tbName
87
88   data._id = data.name + '@' + data.version
89   data.dist = data.dist || {}
90   data.dist.shasum = crypto.createHash('sha1').update(tarbuffer).digest('hex')
91   data.dist.tarball = url.resolve(registry, tbURI)
92                          .replace(/^https:\/\//, 'http://')
93
94   root._attachments = {}
95   root._attachments[ tbName ] = {
96     'content_type': 'application/octet-stream',
97     'data': tarbuffer.toString('base64'),
98     'length': tarbuffer.length
99   }
100
101   var fixed = url.resolve(registry, escaped(data.name))
102   var client = this
103   var options = {
104     method: 'PUT',
105     body: root,
106     auth: auth
107   }
108   this.request(fixed, options, function (er, parsed, json, res) {
109     var r409 = 'must supply latest _rev to update existing package'
110     var r409b = 'Document update conflict.'
111     var conflict = res && res.statusCode === 409
112     if (parsed && (parsed.reason === r409 || parsed.reason === r409b)) {
113       conflict = true
114     }
115
116     // a 409 is typical here.  GET the data and merge in.
117     if (er && !conflict) {
118       client.log.error('publish', 'Failed PUT ' + (res && res.statusCode))
119       return cb(er)
120     }
121
122     if (!er && !conflict) return cb(er, parsed, json, res)
123
124     // let's see what versions are already published.
125     client.request(fixed + '?write=true', { auth: auth }, function (er, current) {
126       if (er) return cb(er)
127
128       putNext.call(client, registry, data.version, root, current, auth, cb)
129     })
130   })
131 }
132
133 function putNext (registry, newVersion, root, current, auth, cb) {
134   // already have the tardata on the root object
135   // just merge in existing stuff
136   var curVers = Object.keys(current.versions || {}).map(function (v) {
137     return semver.clean(v, true)
138   }).concat(Object.keys(current.time || {}).map(function (v) {
139     if (semver.valid(v, true)) return semver.clean(v, true)
140   }).filter(function (v) {
141     return v
142   }))
143
144   if (curVers.indexOf(newVersion) !== -1) {
145     return cb(conflictError(root.name, newVersion))
146   }
147
148   current.versions[newVersion] = root.versions[newVersion]
149   current._attachments = current._attachments || {}
150   for (var i in root) {
151     switch (i) {
152       // objects that copy over the new stuffs
153       case 'dist-tags':
154       case 'versions':
155       case '_attachments':
156         for (var j in root[i]) {
157           current[i][j] = root[i][j]
158         }
159         break
160
161       // ignore these
162       case 'maintainers':
163         break
164
165       // copy
166       default:
167         current[i] = root[i]
168     }
169   }
170   var maint = JSON.parse(JSON.stringify(root.maintainers))
171   root.versions[newVersion].maintainers = maint
172
173   var uri = url.resolve(registry, escaped(root.name))
174   var options = {
175     method: 'PUT',
176     body: current,
177     auth: auth
178   }
179   this.request(uri, options, cb)
180 }
181
182 function conflictError (pkgid, version) {
183   var e = new Error('cannot modify pre-existing version')
184   e.code = 'EPUBLISHCONFLICT'
185   e.pkgid = pkgid
186   e.version = version
187   return e
188 }