1 | #!/usr/bin/env node
|
2 |
|
3 | "use strict";
|
4 |
|
5 | var semver = require('semver')
|
6 | var program = require('commander')
|
7 | var path = require('path')
|
8 | var fs = require('fs')
|
9 | var tar = require('tar')
|
10 | var zlib = require('zlib')
|
11 | var fstream = require('fstream')
|
12 | var Packer = require('fstream-npm')
|
13 | var debug = require('debug')('mosaic:publish')
|
14 | var mosaic = require('../lib/mosaic')
|
15 |
|
16 |
|
17 | program.option('-f, --force', 'Force a re-publish')
|
18 | program.parse(process.argv)
|
19 |
|
20 |
|
21 | var args = program.args
|
22 | var cwd = process.cwd()
|
23 | var dpath = cwd
|
24 |
|
25 | if (args[0]) dpath = path.join(cwd, args[0])
|
26 |
|
27 | var fpath = path.join(dpath, 'package.json')
|
28 |
|
29 | if (!fs.existsSync(fpath)) mosaic.fatal('没找到 package.json')
|
30 |
|
31 | var mo = require(fpath)
|
32 |
|
33 |
|
34 | if (isValid(mo)) {
|
35 | mosaic.log('publish', mo.name)
|
36 | process.stdin.resume()
|
37 | publish(dpath)
|
38 | }
|
39 |
|
40 |
|
41 | function publish(dpath){
|
42 | new Packer({ path: dpath, type: 'Directory', isDirectory: true })
|
43 | .pipe(tar.Pack())
|
44 | .pipe(zlib.Gzip())
|
45 | .pipe(fstream.Writer('package.tgz'))
|
46 | .on('close', afterTar)
|
47 | }
|
48 |
|
49 | function afterTar(err) {
|
50 | if (err) return mosaic.fatal(err)
|
51 |
|
52 | var url = [mo.name, mo.version].join('\/')
|
53 | var req = mosaic.agent()
|
54 | .get(mosaic.remote(url))
|
55 | .on('error', function(err) {
|
56 | console.trace(err)
|
57 | cleanup()
|
58 | })
|
59 | .end(function(res) {
|
60 | if (res.statusCode === 200 && res.text && res.text.indexOf('统一登录中心') >= 0) {
|
61 | // In superagent, res.req is the instance returned by http.request,
|
62 | // which is not an instance of the request wrap by superagent and
|
63 | // does not provide .url property.
|
64 | //
|
65 | // For code brevity, let's simply set it.
|
66 | res.req.url = req.url
|
67 | mosaic.login(res).done(function() { afterTar() })
|
68 | }
|
69 | else if (res.statusCode === 200) {
|
70 | if (program.force) {
|
71 | postTar(url)
|
72 | }
|
73 | else {
|
74 | mosaic.log('mosaic', url + ' exists. use --force to re-publish')
|
75 | process.exit(0)
|
76 | }
|
77 | }
|
78 | else if (res.statusCode === 404) {
|
79 | postTar(url)
|
80 | }
|
81 | })
|
82 | }
|
83 |
|
84 | function postTar(url) {
|
85 | var req = mosaic.agent()
|
86 | .put(mosaic.remote(url))
|
87 |
|
88 | if (program.force) req.query({ force: '' })
|
89 |
|
90 | req
|
91 | .attach('tarball', 'package.tgz')
|
92 | .buffer(false)
|
93 | .on('response', function(res) {
|
94 | res.text = ''
|
95 | res.on('data', function(chunk) {
|
96 | res.text += chunk
|
97 | process.stdout.write(chunk)
|
98 | })
|
99 | res.on('end', function() {
|
100 | var status = res.statusCode
|
101 |
|
102 | if (status === 201) {
|
103 | var lines = res.text.split('\n')
|
104 | var data = JSON.parse(lines[lines.length - 1])
|
105 |
|
106 | process.stdout.write('\n\n')
|
107 | for (var p in data) {
|
108 | mosaic.log(p, data[p])
|
109 | }
|
110 | }
|
111 | else {
|
112 | mosaic.error('Wrong status code returned ' + res.statusCode)
|
113 | mosaic.error(res.text)
|
114 | }
|
115 | cleanup()
|
116 | })
|
117 | })
|
118 | .on('error', function(err) {
|
119 | cleanup()
|
120 | console.trace(err)
|
121 | })
|
122 | .end()
|
123 | }
|
124 |
|
125 | function isValid(mo){
|
126 | var name = mo.name
|
127 | var version = mo.version
|
128 | var valid = true
|
129 |
|
130 | function fail(msg) {
|
131 | valid = false
|
132 | mosaic.error(msg)
|
133 | }
|
134 |
|
135 | if (!name) fail('未填写名称')
|
136 | if (!version) fail('未填写版本')
|
137 |
|
138 | if (!/^(mosaics|mo)\/\w+$/.test(name) && !/^\w+(?:\.\w+)+\/\w+$/.test(name)) fail('名称不符合 命名空间/组件名 规范')
|
139 | if (!semver.valid(version)) fail('版本 ' + version + ' 不合规范')
|
140 |
|
141 | return valid
|
142 | }
|
143 |
|
144 | function cleanup() {
|
145 | if (fs.existsSync('package.tgz')) fs.unlinkSync('package.tgz')
|
146 | process.exit()
|
147 | }
|