UNPKG

mlpm

Version:

the client for mlpm, a MarkLogic package manager

309 lines (256 loc) 6.96 kB
'use strict' var fs = require('fs') , vfs = require('vinyl-fs') , JSZip = require('jszip') , concat = require('concat-stream') , toposort = require('toposort') , async = require('async') , _ = require('lodash') , path = require('path') , slash = require('slash') , git = require('gulp-git') , util = require('./util.js') var include = [ '*', 'docs/**/*', 'src/**/*', 'lib/**/*', 'rest-api/ext/**/*', 'rest-api/transform/**/*', 'rest-api/service/**/*' ] , ignore = [ 'mlpm.json', 'mlpm_modules', '.*.swp', '._*', '.DS_Store', '.git', '.hg', '.lock-wscript', '.svn', '.wafpickle-*', 'CVS', 'npm-debug.log', 'test', 'src/test', 'xray', 'src/xray' ] , symbols = { pkg: '├── ', pipe: '│ ', last: '└── ' } function getConfig(cb) { util.readJson('mlpm.json', cb) } function saveConfig(data, cb) { util.writeJson('mlpm.json', data, cb) } function getRepository(cb) { git.exec({ args: 'config --get remote.origin.url', quiet: true }, function(err, stdout) { if (err) return cb(err) var origin = stdout.toString().trim() if ( origin && /^git@github.com:/.test( origin ) ) { origin = origin.replace(/^git@github.com:/, 'https://github.com/') } cb(null, origin) }) } function getHeadCommit(cb) { git.revParse({ args: 'HEAD', quiet: true }, function(err, stdout) { if (err) return cb(err) cb( null, stdout.toString().trim() ) }) } function getRepoStatus(cb) { git.status({ args: '--porcelain', quiet: true }, function (err, stdout) { if (err) return cb(err) var changes = _.chain( stdout.trim().split('\n') ) .filter(function (line) { return line.trim() && !line.match(/^\?\? /) }).map(function (line) { return line.trim() }) .value() cb(null, changes) }) } function commitConfig(msg, cb) { vfs.src('mlpm.json') .pipe(git.add({ quiet: true })) .pipe(git.commit( msg, { quiet: true } )) .on('error', function(err) { cb(err) }) .on('end', function() { cb(null) }) } function tagRepo(tag, cb) { if ( !/^v/.test(tag) ) { tag = 'v' + tag } git.tag(tag, tag, { quiet: true }, function (err) { cb(err) }) } function getDefaultConfig(pkgConfig, cb) { if (pkgConfig) { // cthulu cb(null, _.pick(pkgConfig, 'name', 'version', 'description', 'repository')) } else { getRepository(function(err, repository) { // ignore err cb(null, { name: path.basename( process.cwd() ), version: '1.0.0', repository: repository }) }) } } function saveDependency(pkgConfig, name, version, cb) { pkgConfig.dependencies = pkgConfig.dependencies || {} // save semver any patch version version = /^\d+\.\d+\.\d+$/.test( version ) ? version.replace(/\d+$/, '*') : version pkgConfig.dependencies[ name ] = version saveConfig(pkgConfig, cb) } function deleteDependency(pkgConfig, name, cb) { // TODO: check if exists? delete pkgConfig.dependencies[name] saveConfig(pkgConfig, cb) } /* inverse topological sort */ function sortPackages(packages) { var sortedNames = _.chain(packages) .filter(function(pkg) { return pkg.dependencies }) .map(function(pkg) { return _.map(pkg.dependencies, function(_, dep) { return [dep, pkg.name] }) }) .flatten(false) .thru(toposort) .value() return _.sortBy(packages, function(pkg) { return sortedNames.indexOf(pkg.name) }) } function getPackages(cb) { var src = vfs.src('./mlpm_modules/*/mlpm.json') src.on('error', cb) src.pipe(concat(function(files) { cb(null, sortPackages( _.map(files, function(file) { // TODO try/catch? return JSON.parse(file.contents) }) ) ) })) } //TODO: replace with byline and concat function getIgnoreGlobs(cb) { async.map(['.mlpmignore', '.gitignore'], function(file, cb) { fs.readFile(file, function(err, data) { if (err) return cb(null, []) cb( null, data.toString().split(/\r?\n/) ) }) }, function(err, globs) { var ignoreGlobs = _.chain([ignore, globs]) .flatten(true) .compact() .uniq() .map(function(line) { return '!' + line; }) .value() cb( null, ignoreGlobs ) }) } function getGlobs(pkgConfig, cb) { getIgnoreGlobs(function(__, ignoreGlobs) { if ( !(pkgConfig.files && pkgConfig.files.length) ) { return cb( null, include.concat(ignoreGlobs) ) } // TODO: sync with defaultExcludes in package.getFiles() var globs = [ 'README', 'README.{md,mdown}', 'LICENSE', 'license.txt' ] async.map(pkgConfig.files, fs.stat, function(err, stats) { if (err) return cb(err) _.each(stats, function(file, index) { var path = pkgConfig.files[ index ].replace(/\/$/, '') if ( file.isDirectory() ) { path += '/**/*' } globs.push(path) }) cb( null, globs.concat(ignoreGlobs) ) }) }) } function getFiles(pkgConfig, readContents, cb) { if ( !cb ) { cb = readContents readContents = true } getGlobs(pkgConfig, function(err, globs) { if (err) return cb(err) var src = vfs.src(globs, { read: readContents }) src.on('error', cb) src.pipe(concat(function(files) { cb(null, _.filter(files, function(file) { return file.stat.isFile() })) })) }) } function createZip(pkgConfig, cb) { getFiles(pkgConfig, function(err, files) { if (err) return cb(err) getHeadCommit(function(err, gitHead) { var zip = new JSZip() function normalizePath(file) { var relative = file.path.replace( process.cwd(), '' ) return slash( relative ).replace(/^\//, '') } if ( !err ) pkgConfig.gitHead = gitHead zip.file( 'mlpm.json', util.formatJson(pkgConfig) ) _.each(files, function(file) { var filePath = normalizePath(file) // in case it was explicitly included in files array, or otherwise snuck through ... if ( filePath === 'mlpm.json' ) return zip.file( filePath, file.contents ) }) if ( _.keys( zip.files ).length === 0 ) { return cb(new Error('aborting, empty zip')) } cb( null, zip ) }) }) } module.exports = { getConfig: getConfig, saveConfig: saveConfig, getRepository: getRepository, getHeadCommit: getHeadCommit, getRepoStatus: getRepoStatus, commitConfig: commitConfig, tagRepo: tagRepo, getDefaultConfig: getDefaultConfig, saveDependency: saveDependency, deleteDependency: deleteDependency, sortPackages: sortPackages, getPackages: getPackages, getIgnoreGlobs: getIgnoreGlobs, getGlobs: getGlobs, getFiles: getFiles, createZip: createZip, symbols: symbols }