import is from "is" ; import path from "path" ; import crc from "crc" ; import URI from "urijs" ; import pathUtil from "./path" ; import Promise from "./promise" ; import command from "./command" ; import fs from "./fs" ; const GIT_PREFIX = "git+" ; function Git ( ) { this . tmpDir ; this . cloned = { } ; } Git . prototype . repoID = function ( host , ref ) { return crc . crc32 ( `${ host }#${ ref || "" }` ) . toString ( 16 ) ; } ; Git . prototype . allocateDir = function ( ) { const that = this ; if ( this . tmpDir ) return Promise ( ) ; return fs . tmpDir ( ) . then ( ( dir ) => { that . tmpDir = dir ; } ) ; } ; Git . prototype . clone = function ( host , ref ) { const that = this ; return ( this . allocateDir ( ) . then ( ( ) => { const repoId = that . repoID ( host , ref ) ; const repoPath = path . join ( that . tmpDir , repoId ) ; if ( that . cloned [ repoId ] ) return repoPath ; return ( command . exec ( `git clone ${ host } ${ repoPath }` ) . then ( ( ) => { that . cloned [ repoId ] = true ; if ( ! ref ) return ; return command . exec ( `git checkout ${ ref }` , { cwd : repoPath } ) ; } ) . thenResolve ( repoPath ) ) ; } ) ) ; } ; Git . prototype . resolve = function ( giturl ) { if ( ! Git . isUrl ( giturl ) ) { if ( this . resolveRoot ( giturl ) ) return Promise ( giturl ) ; return Promise ( null ) ; } if ( is . string ( giturl ) ) giturl = Git . parseUrl ( giturl ) ; if ( ! giturl ) return Promise ( null ) ; return this . clone ( giturl . host , giturl . ref ) . then ( ( repo ) => { return path . resolve ( repo , giturl . filepath ) ; } ) ; } ; Git . prototype . resolveRoot = function ( filepath ) { if ( ! this . tmpDir || ! pathUtil . isInRoot ( this . tmpDir , filepath ) ) return null ; const relativeToGit = path . relative ( this . tmpDir , filepath ) ; const repoId = relativeToGit . split ( path . sep ) [ 0 ] ; if ( ! repoId ) { return ; } return path . resolve ( this . tmpDir , repoId ) ; } ; Git . isUrl = function ( giturl ) { return giturl . indexOf ( GIT_PREFIX ) === 0 ; } ; Git . parseUrl = function ( giturl ) { if ( ! Git . isUrl ( giturl ) ) return null ; giturl = giturl . slice ( GIT_PREFIX . length ) ; const uri = new URI ( giturl ) ; const ref = uri . fragment ( ) || null ; uri . fragment ( null ) ; const fileParts = uri . path ( ) . split ( ".git" ) ; let filepath = fileParts . length > 1 ? fileParts . slice ( 1 ) . join ( ".git" ) : "" ; if ( filepath [ 0 ] == "/" ) { filepath = filepath . slice ( 1 ) ; } uri . path ( `${ fileParts [ 0 ] }.git` ) ; return { host : uri . toString ( ) , ref : ref , filepath : filepath , } ; } ; export default Git ;