@@ -5,6 +5,8 @@ import endpointParser from 'bower-endpoint-parser'
55import semver from 'semver'
66import fs from 'fs-extra'
77import path from 'path'
8+ import os from 'os'
9+ import { exec } from 'child_process'
810import getBowerRegistryConfig from './getBowerRegistryConfig.js'
911import { ADAPT_ALLOW_PRERELEASE , PLUGIN_TYPES , PLUGIN_TYPE_FOLDERS , PLUGIN_DEFAULT_TYPE } from '../util/constants.js'
1012/** @typedef {import("./Project.js").default } Project */
@@ -38,13 +40,23 @@ export default class Plugin {
3840 this . project = project
3941 this . cwd = cwd
4042 this . BOWER_REGISTRY_CONFIG = getBowerRegistryConfig ( { cwd : this . cwd } )
41- const endpoint = name + '#' + ( isCompatibleEnabled ? '*' : requestedVersion )
42- const ep = endpointParser . decompose ( endpoint )
4343 this . sourcePath = null
44- this . name = ep . name || ep . source
45- this . packageName = ( / ^ a d a p t - / i. test ( this . name ) ? '' : 'adapt-' ) + ( ! isContrib ? '' : 'contrib-' ) + slug ( this . name , { maintainCase : true } )
46- // the constraint given by the user
47- this . requestedVersion = requestedVersion
44+
45+ const isGitUrl = / ^ h t t p s ? : \/ \/ / . test ( name )
46+ if ( isGitUrl ) {
47+ this . gitUrl = name
48+ this . gitRef = ( requestedVersion && requestedVersion !== '*' ) ? requestedVersion : null
49+ this . name = ''
50+ this . packageName = ''
51+ this . requestedVersion = '*'
52+ } else {
53+ const endpoint = name + '#' + ( isCompatibleEnabled ? '*' : requestedVersion )
54+ const ep = endpointParser . decompose ( endpoint )
55+ this . name = ep . name || ep . source
56+ this . packageName = ( / ^ a d a p t - / i. test ( this . name ) ? '' : 'adapt-' ) + ( ! isContrib ? '' : 'contrib-' ) + slug ( this . name , { maintainCase : true } )
57+ this . requestedVersion = requestedVersion
58+ }
59+
4860 // the most recent version of the plugin compatible with the given framework
4961 this . latestCompatibleSourceVersion = null
5062 // a non-wildcard constraint resolved to the highest version of the plugin that satisfies the requestedVersion and is compatible with the framework
@@ -128,6 +140,14 @@ export default class Plugin {
128140 return Boolean ( this . sourcePath || this ?. _projectInfo ?. _wasInstalledFromPath )
129141 }
130142
143+ /**
144+ * plugin will be or was installed from a git URL
145+ * @returns {boolean }
146+ */
147+ get isGitSource ( ) {
148+ return Boolean ( this . gitUrl || this . _projectInfo ?. _wasInstalledFromGitRepo )
149+ }
150+
131151 /**
132152 * check if source path is a zip
133153 * @returns {boolean }
@@ -185,10 +205,34 @@ export default class Plugin {
185205 }
186206
187207 async fetchSourceInfo ( ) {
208+ if ( this . isGitSource ) return await this . fetchGitSourceInfo ( )
188209 if ( this . isLocalSource ) return await this . fetchLocalSourceInfo ( )
189210 await this . fetchBowerInfo ( )
190211 }
191212
213+ async fetchGitSourceInfo ( ) {
214+ if ( this . _sourceInfo ) return this . _sourceInfo
215+ this . _sourceInfo = null
216+ const tmpDir = path . join ( os . tmpdir ( ) , `adapt-git-${ Date . now ( ) } ` )
217+ try {
218+ const branchFlag = this . gitRef ? ` --branch ${ this . gitRef } ` : ''
219+ await new Promise ( ( resolve , reject ) => {
220+ exec ( `git clone --depth 1${ branchFlag } ${ this . gitUrl } "${ tmpDir } "` , ( err ) => {
221+ if ( err ) return reject ( err )
222+ resolve ( )
223+ } )
224+ } )
225+ const bowerJSONPath = path . join ( tmpDir , 'bower.json' )
226+ if ( ! fs . existsSync ( bowerJSONPath ) ) return
227+ this . _sourceInfo = await fs . readJSON ( bowerJSONPath )
228+ this . name = this . _sourceInfo . name
229+ this . packageName = this . name
230+ this . matchedVersion = this . _sourceInfo . version
231+ } finally {
232+ await fs . rm ( tmpDir , { recursive : true , force : true } )
233+ }
234+ }
235+
192236 async fetchLocalSourceInfo ( ) {
193237 if ( this . _sourceInfo ) return this . _sourceInfo
194238 this . _sourceInfo = null
@@ -269,6 +313,10 @@ export default class Plugin {
269313 if ( ! this . _projectInfo ) return
270314 this . name = this . _projectInfo . name
271315 this . packageName = this . name
316+ if ( this . _projectInfo . _wasInstalledFromGitRepo ) {
317+ this . gitUrl = this . _projectInfo . _gitUrl
318+ this . gitRef = this . _projectInfo . _gitRef || null
319+ }
272320 }
273321
274322 async findCompatibleVersion ( framework ) {
@@ -291,7 +339,7 @@ export default class Plugin {
291339 const getMatchingVersion = async ( ) => {
292340 if ( ! this . isPresent ) return null
293341
294- if ( this . isLocalSource ) {
342+ if ( this . isLocalSource || this . isGitSource ) {
295343 const info = this . projectVersion ? this . _projectInfo : this . _sourceInfo
296344 const satisfiesConstraint = ! this . hasValidRequestVersion || semver . satisfies ( info . version , this . requestedVersion , semverOptions )
297345 const satisfiesFramework = semver . satisfies ( framework , info . framework )
@@ -360,7 +408,7 @@ export default class Plugin {
360408
361409 async getRepositoryUrl ( ) {
362410 if ( this . _repositoryUrl ) return this . _repositoryUrl
363- if ( this . isLocalSource ) return
411+ if ( this . isLocalSource || this . isGitSource ) return
364412 const url = await new Promise ( ( resolve , reject ) => {
365413 bower . commands . lookup ( this . packageName , { cwd : this . cwd , registry : this . BOWER_REGISTRY_CONFIG } )
366414 . on ( 'end' , resolve )
0 commit comments