2022-06-14 14:37:10 +08:00
/ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Copyright ( c ) Microsoft Corporation . All rights reserved .
* Licensed under the MIT License . See License . txt in the project root for license information .
* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- * /
import * as fs from 'fs' ;
import * as path from 'path' ;
import * as os from 'os' ;
import * as rimraf from 'rimraf' ;
import * as es from 'event-stream' ;
import * as rename from 'gulp-rename' ;
import * as vfs from 'vinyl-fs' ;
import * as ext from './extensions' ;
import * as fancyLog from 'fancy-log' ;
import * as ansiColors from 'ansi-colors' ;
import { Stream } from 'stream' ;
const mkdirp = require ( 'mkdirp' ) ;
export interface IExtensionDefinition {
name : string ;
version : string ;
repo : string ;
platforms? : string [ ] ;
metadata : {
id : string ;
publisherId : {
publisherId : string ;
publisherName : string ;
displayName : string ;
flags : string ;
} ;
publisherDisplayName : string ;
} ;
}
const root = path . dirname ( path . dirname ( __dirname ) ) ;
const productjson = JSON . parse ( fs . readFileSync ( path . join ( __dirname , '../../product.json' ) , 'utf8' ) ) ;
const builtInExtensions = < IExtensionDefinition [ ] > productjson . builtInExtensions || [ ] ;
const webBuiltInExtensions = < IExtensionDefinition [ ] > productjson . webBuiltInExtensions || [ ] ;
2023-05-30 16:24:14 +08:00
const controlFilePath = path . join ( os . homedir ( ) , '.kylin-code-dev' , 'extensions' , 'control.json' ) ;
2022-06-14 14:37:10 +08:00
const ENABLE_LOGGING = ! process . env [ 'VSCODE_BUILD_BUILTIN_EXTENSIONS_SILENCE_PLEASE' ] ;
function log ( . . . messages : string [ ] ) : void {
if ( ENABLE_LOGGING ) {
fancyLog ( . . . messages ) ;
}
}
function getExtensionPath ( extension : IExtensionDefinition ) : string {
return path . join ( root , '.build' , 'builtInExtensions' , extension . name ) ;
}
function isUpToDate ( extension : IExtensionDefinition ) : boolean {
const packagePath = path . join ( getExtensionPath ( extension ) , 'package.json' ) ;
if ( ! fs . existsSync ( packagePath ) ) {
return false ;
}
const packageContents = fs . readFileSync ( packagePath , { encoding : 'utf8' } ) ;
try {
const diskVersion = JSON . parse ( packageContents ) . version ;
return ( diskVersion === extension . version ) ;
} catch ( err ) {
return false ;
}
}
function syncMarketplaceExtension ( extension : IExtensionDefinition ) : Stream {
const galleryServiceUrl = productjson . extensionsGallery ? . serviceUrl ;
const source = ansiColors . blue ( galleryServiceUrl ? '[marketplace]' : '[github]' ) ;
if ( isUpToDate ( extension ) ) {
log ( source , ` ${ extension . name } @ ${ extension . version } ` , ansiColors . green ( '✔︎' ) ) ;
return es . readArray ( [ ] ) ;
}
rimraf . sync ( getExtensionPath ( extension ) ) ;
return ( galleryServiceUrl ? ext . fromMarketplace ( galleryServiceUrl , extension ) : ext . fromGithub ( extension ) )
. pipe ( rename ( p = > p . dirname = ` ${ extension . name } / ${ p . dirname } ` ) )
. pipe ( vfs . dest ( '.build/builtInExtensions' ) )
. on ( 'end' , ( ) = > log ( source , extension . name , ansiColors . green ( '✔︎' ) ) ) ;
}
function syncExtension ( extension : IExtensionDefinition , controlState : 'disabled' | 'marketplace' ) : Stream {
if ( extension . platforms ) {
const platforms = new Set ( extension . platforms ) ;
if ( ! platforms . has ( process . platform ) ) {
log ( ansiColors . gray ( '[skip]' ) , ` ${ extension . name } @ ${ extension . version } : Platform ' ${ process . platform } ' not supported: [ ${ extension . platforms } ] ` , ansiColors . green ( '✔︎' ) ) ;
return es . readArray ( [ ] ) ;
}
}
switch ( controlState ) {
case 'disabled' :
log ( ansiColors . blue ( '[disabled]' ) , ansiColors . gray ( extension . name ) ) ;
return es . readArray ( [ ] ) ;
case 'marketplace' :
return syncMarketplaceExtension ( extension ) ;
default :
if ( ! fs . existsSync ( controlState ) ) {
log ( ansiColors . red ( ` Error: Built-in extension ' ${ extension . name } ' is configured to run from ' ${ controlState } ' but that path does not exist. ` ) ) ;
return es . readArray ( [ ] ) ;
} else if ( ! fs . existsSync ( path . join ( controlState , 'package.json' ) ) ) {
log ( ansiColors . red ( ` Error: Built-in extension ' ${ extension . name } ' is configured to run from ' ${ controlState } ' but there is no 'package.json' file in that directory. ` ) ) ;
return es . readArray ( [ ] ) ;
}
log ( ansiColors . blue ( '[local]' ) , ` ${ extension . name } : ${ ansiColors . cyan ( controlState ) } ` , ansiColors . green ( '✔︎' ) ) ;
return es . readArray ( [ ] ) ;
}
}
interface IControlFile {
[ name : string ] : 'disabled' | 'marketplace' ;
}
function readControlFile ( ) : IControlFile {
try {
return JSON . parse ( fs . readFileSync ( controlFilePath , 'utf8' ) ) ;
} catch ( err ) {
return { } ;
}
}
function writeControlFile ( control : IControlFile ) : void {
mkdirp . sync ( path . dirname ( controlFilePath ) ) ;
fs . writeFileSync ( controlFilePath , JSON . stringify ( control , null , 2 ) ) ;
}
export function getBuiltInExtensions ( ) : Promise < void > {
log ( 'Synchronizing built-in extensions...' ) ;
log ( ` You can manage built-in extensions with the ${ ansiColors . cyan ( '--builtin' ) } flag ` ) ;
const control = readControlFile ( ) ;
const streams : Stream [ ] = [ ] ;
for ( const extension of [ . . . builtInExtensions , . . . webBuiltInExtensions ] ) {
let controlState = control [ extension . name ] || 'marketplace' ;
control [ extension . name ] = controlState ;
streams . push ( syncExtension ( extension , controlState ) ) ;
}
writeControlFile ( control ) ;
return new Promise ( ( resolve , reject ) = > {
es . merge ( streams )
. on ( 'error' , reject )
. on ( 'end' , resolve ) ;
} ) ;
}
if ( require . main === module ) {
getBuiltInExtensions ( ) . then ( ( ) = > process . exit ( 0 ) ) . catch ( err = > {
console . error ( err ) ;
process . exit ( 1 ) ;
} ) ;
}