#!/usr/bin/env node "use strict"; var semver = require('semver') var program = require('commander') var path = require('path') var fs = require('fs') var tar = require('tar') var zlib = require('zlib') var fstream = require('fstream') var Packer = require('fstream-npm') var debug = require('debug')('mosaic:publish') var mosaic = require('../lib/mosaic') program.option('-f, --force', 'Force a re-publish') program.parse(process.argv) var args = program.args var cwd = process.cwd() var dpath = cwd if (args[0]) dpath = path.join(cwd, args[0]) var fpath = path.join(dpath, 'package.json') if (!fs.existsSync(fpath)) mosaic.fatal('没找到 package.json') var mo = require(fpath) if (isValid(mo)) { mosaic.log('publish', mo.name) process.stdin.resume() publish(dpath) } function publish(dpath){ new Packer({ path: dpath, type: 'Directory', isDirectory: true }) .pipe(tar.Pack()) .pipe(zlib.Gzip()) .pipe(fstream.Writer('package.tgz')) .on('close', afterTar) } function afterTar(err) { if (err) return mosaic.fatal(err) var url = [mo.name, mo.version].join('\/') var req = mosaic.agent() .get(mosaic.remote(url)) .on('error', function(err) { console.trace(err) cleanup() }) .end(function(res) { if (res.statusCode === 200 && res.text && res.text.indexOf('统一登录中心') >= 0) { // In superagent, res.req is the instance returned by http.request, // which is not an instance of the request wrap by superagent and // does not provide .url property. // // For code brevity, let's simply set it. res.req.url = req.url mosaic.login(res).done(function() { afterTar() }) } else if (res.statusCode === 200) { if (program.force) { postTar(url) } else { mosaic.log('mosaic', url + ' exists. use --force to re-publish') process.exit(0) } } else if (res.statusCode === 404) { postTar(url) } }) } function postTar(url) { var req = mosaic.agent() .put(mosaic.remote(url)) if (program.force) req.query({ force: '' }) req .attach('tarball', 'package.tgz') .buffer(false) .on('response', function(res) { res.text = '' res.on('data', function(chunk) { res.text += chunk process.stdout.write(chunk) }) res.on('end', function() { var status = res.statusCode if (status === 201) { var lines = res.text.split('\n') var data = JSON.parse(lines[lines.length - 1]) process.stdout.write('\n\n') for (var p in data) { mosaic.log(p, data[p]) } } else { mosaic.error('Wrong status code returned ' + res.statusCode) mosaic.error(res.text) } cleanup() }) }) .on('error', function(err) { cleanup() console.trace(err) }) .end() } function isValid(mo){ var name = mo.name var version = mo.version var valid = true function fail(msg) { valid = false mosaic.error(msg) } if (!name) fail('未填写名称') if (!version) fail('未填写版本') if (!/^(mosaics|mo)\/\w+$/.test(name) && !/^\w+(?:\.\w+)+\/\w+$/.test(name)) fail('名称不符合 命名空间/组件名 规范') if (!semver.valid(version)) fail('版本 ' + version + ' 不合规范') return valid } function cleanup() { if (fs.existsSync('package.tgz')) fs.unlinkSync('package.tgz') process.exit() }