es6/Services/Repo.js
import os from 'os'
import path from 'path'
import Promise from 'bluebird'
import cp from '../utils/child_process'
import fs from '../utils/fs'
import Expressive from '../utils/Expressive'
import Ensure from '../utils/Ensure'
import Events from '../utils/Events'
import * as Errors from '../Errors'
import Registry from './Registry'
export default class Repo extends Expressive {
static exec ( dir, cmd ) {
return cp.exec$(cmd, { cwd: dir }).then( result => {
result.unshift(`$ ${cmd}\n`)
return result
}).catch( err => {
if (err.code === "NOENT") {
err = new Errors.Executable_Runtime_Error(`Could not execute cmd ${cmd} in ${dir}`)
err.code = "NOENT"
}
throw err
})
}
static git (dir, args) {
return Repo.exec( dir, [ Repo.bin.git ].concat(args).join(' ') )
}
static npm (dir, args) {
return Repo.exec( dir, [ Repo.bin.npm ].concat(args).join(' ') )
}
static safeDirName (name) {
const delim = "-"
name = name.replace(/\W+/g, delim).split('')
if (name[0] === delim) name.shift()
if (name[name.length-1] === delim) name.pop()
return name.join('')
}
constructor (info) {
super()
this.info = info
this.makeUnavailable()
return this.build()
}
get name () {
return this.info.name
}
get id () {
return this.info.id
}
update (fields) {
Object.assign(this.info, fields)
return Promise.resolve(this)
}
dir (...args) {
args.unshift( Repo.safeDirName(this.name) )
return Registry.appDir.apply(Registry, args)
}
git (...args) {
return Repo.git(this.dir(), args)
}
npm (...args) {
return Repo.npm(this.dir(), args)
}
exists () {
return fs.stat$( this.dir() ).catch( err => {
if ( err.code === "ENOENT" ) return false
throw err
})
}
makeAvailable () {
this.available = true
return this
}
makeUnavailable () {
this.available = false
return this
}
pull () {
return this.git('pull')
}
install () {
return this.npm('install')
}
build () {
this.makeUnavailable()
return this.exists()
.bind(this)
.then( exists => exists ? this.pull() : this.clone() )
.then(this.install)
.then(this.invalidateCache)
.then(this.makeAvailable)
.return(this)
}
clone () {
return Repo.git( Registry.appDir(), [
'clone'
, '--depth=10'
, `--branch=${this.info.branch || 'master'}`
, this.info.repo
, this.info.name
]).then( result => {
this.emitClone(result)
return result
})
}
rm () {
this.removeAllListeners()
return fs.remove$(this.dir()).return(this)
}
get script () {
return this.dir(this.pkg.main)
}
get pkg () {
if (!this._pkg) {
this._pkg = require( this.dir('package.json') )
}
return this._pkg
}
invalidateCache () {
this.emitInvalidate( this.script )
delete require.cache[ require.resolve( this.script ) ]
delete require.cache[ require.resolve( this.dir('package.json') ) ]
return Promise.resolve(this)
}
}
Repo.Event = {
install : "repo:install"
, rm : "repo:rm"
, clone : "repo:clone"
, build : "repo:build"
, pull : "repo:pull"
, invalidate : "cache:invalidate"
}
Events.methodize( Repo, Repo.Event )
Repo.bin = {
git : Ensure.executable('git')
, npm : Ensure.executable('npm')
}