/**********************************************************************
 * Copyright (c) 2020-2021 Red Hat, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 ***********************************************************************/ import * as path from 'path' ; import { VsixCategory , VsixInfo } from '../extensions/vsix-info' ; import { inject , injectable } from 'inversify' ; import { CheTheiaPluginMetaInfo } from '../build' ; import { MetaYamlPluginInfo } from '../meta-yaml/meta-yaml-plugin-info' ; import { Sidecar } from '../sidecar/sidecar' ; @ injectable ( ) export class CheTheiaPluginsMetaYamlGenerator { static readonly CHE_THEIA_SIDECAR_PREFERENCES = 'CHE_THEIA_SIDECAR_PREFERENCES' ; @ inject ( Sidecar ) private sidecar : Sidecar ; readI18nProperty ( propertyName , vsixInfo ) { if ( propertyName && propertyName . startsWith ( '%' ) && propertyName . endsWith ( '%' ) ) { const propertyWithoutPrefixSuffix = propertyName . substring ( 1 , propertyName . length - 1 ) ; const nls = vsixInfo . packageNlsJson ; if ( nls ) { return nls [ propertyWithoutPrefixSuffix ] ; } } return propertyName ; } async compute ( cheTheiaPlugins ) { const metaYamlPluginInfos = await Promise . all ( cheTheiaPlugins . map ( async ( chePlugin ) => { const type = 'VS Code extension' ; const vsixData = Array . from ( chePlugin . vsixInfos . values ( ) ) ; const firstVsix = vsixData [ 0 ] ; const packageJson = firstVsix . packageJson ; const chePluginOutput = JSON . stringify ( chePlugin ) ; if ( ! packageJson ) { throw new Error ( `No package.json found for ${ chePluginOutput }` ) ; } if ( ! packageJson . publisher ) { throw new Error ( `No publisher field in package.json found for ${ chePluginOutput }` ) ; } const publisher = packageJson . publisher . toLowerCase ( ) ; if ( ! packageJson . name ) { throw new Error ( `No name field in package.json found for ${ chePluginOutput }` ) ; } const name = packageJson . name . toLowerCase ( ) ; if ( ! packageJson . version ) { throw new Error ( `No version field in package.json found for ${ chePluginOutput }` ) ; } const version = packageJson . version ; let displayName ; if ( packageJson . displayName ) { displayName = this . readI18nProperty ( packageJson . displayName , firstVsix ) ; } else if ( packageJson . description ) { displayName = this . readI18nProperty ( packageJson . description , firstVsix ) ; } else { displayName = name ; } const title = displayName ; let description ; if ( ! packageJson . description ) { description = name ; console . error ( `No description field in package.json found for ${ chePluginOutput }` ) ; } else { description = this . readI18nProperty ( packageJson . description , firstVsix ) ; } let category ; if ( ! packageJson . categories || packageJson . categories . length === 0 ) { console . error ( `No categories field in package.json found for ${ chePluginOutput }. Using Other type` ) ; category = 'Other' ; } else { category = packageJson . categories [ 0 ] ; } if ( ! packageJson . icon ) { console . warn ( `No icon field in package.json found for ${ chePluginOutput }` ) ; } let iconFile ; if ( packageJson . icon && firstVsix . unpackedExtensionRootDir ) { iconFile = path . resolve ( firstVsix . unpackedExtensionRootDir , packageJson . icon ) ; } let repository ; if ( packageJson . repository && typeof packageJson . repository === 'string' ) { repository = packageJson . repository ; } else if ( packageJson . repository && packageJson . repository . url && typeof packageJson . repository . url === 'string' ) { repository = packageJson . repository . url ; } else { repository = chePlugin . repository . url ; console . warn ( `repository field is not a string or repository.url missing in package.json found, using the one from yaml content for ${ chePluginOutput }` ) ; } let firstPublicationDate ; if ( firstVsix . creationDate ) { firstPublicationDate = firstVsix . creationDate ; } else { console . error ( 'No creation date' ) ; throw new Error ( `No creation date found for vsix ${ chePluginOutput }` ) ; } const id = chePlugin . id ; const latestUpdateDate = new Date ( ) . toISOString ( ) . slice ( 0 , 10 ) ; const spec = { } ; if ( chePlugin . sidecar ) { const sidecarImage = await this . sidecar . getDockerImageFor ( chePlugin ) ; const container = { image : sidecarImage } ; let endpoints ; if ( chePlugin . sidecar . name ) { container . name = chePlugin . sidecar . name ; } if ( chePlugin . sidecar . volumeMounts ) { container . volumes = chePlugin . sidecar . volumeMounts . map ( volume => ( { name : volume . name , mountPath : volume . path , } ) ) ; } if ( chePlugin . sidecar . memoryLimit ) { container . memoryLimit = chePlugin . sidecar . memoryLimit ; } if ( chePlugin . sidecar . memoryRequest ) { container . memoryRequest = chePlugin . sidecar . memoryRequest ; } if ( chePlugin . sidecar . cpuRequest ) { container . cpuRequest = chePlugin . sidecar . cpuRequest ; } if ( chePlugin . sidecar . cpuLimit ) { container . cpuLimit = chePlugin . sidecar . cpuLimit ; } if ( chePlugin . sidecar . env ) { container . env = chePlugin . sidecar . env ; } if ( chePlugin . preferences ) { if ( ! container . env ) { container . env = [ ] ; } container . env . push ( { name : CheTheiaPluginsMetaYamlGenerator . CHE_THEIA_SIDECAR_PREFERENCES , value : JSON . stringify ( chePlugin . preferences ) , } ) ; } if ( chePlugin . sidecar . mountSources ) { container . mountSources = chePlugin . sidecar . mountSources ; } if ( chePlugin . sidecar . args ) { container . args = chePlugin . sidecar . args ; } if ( chePlugin . sidecar . command ) { container . command = chePlugin . sidecar . command ; } if ( chePlugin . sidecar . endpoints ) { container . ports = chePlugin . sidecar . endpoints . map ( endpoint => ( { exposedPort : endpoint . targetPort } ) ) ; endpoints = chePlugin . sidecar . endpoints ; } spec . containers = [ container ] ; if ( endpoints ) { spec . endpoints = endpoints ; } } const resolvedExtensions = [ chePlugin . extension ] ; let dependenciesToInline = [ ] ; const packageJsonDependencies = packageJson . extensionDependencies ; if ( packageJsonDependencies && packageJsonDependencies . length > 0 ) { dependenciesToInline . push ( ... packageJsonDependencies . map ( dependency => dependency . replace ( '.' , '/' ) . toLocaleLowerCase ( ) ) ) ; } const skipDependencies = chePlugin . skipDependencies || [ ] ; const extraDependencies = chePlugin . extraDependencies || [ ] ; let skipIndex = false ; const vsixInfos = new Map ( chePlugin . vsixInfos ) ; if ( chePlugin . metaYaml ) { const metaYamlExtraDependencies = chePlugin . metaYaml . extraDependencies || [ ] ; extraDependencies . push ( ... metaYamlExtraDependencies ) ; dependenciesToInline . push ( ... extraDependencies ) ; const metaYamlSkipDependencies = chePlugin . metaYaml . skipDependencies || [ ] ; skipDependencies . push ( ... metaYamlSkipDependencies ) ; dependenciesToInline = dependenciesToInline . filter ( dependency => ! skipDependencies . includes ( dependency ) ) ; skipIndex = chePlugin . metaYaml . skipIndex || false ; } if ( dependenciesToInline . length > 0 ) { dependenciesToInline = dependenciesToInline . filter ( dependency => dependency === 'vscode/typescript-language-features' || ! dependency . startsWith ( 'vscode/' ) ) ; dependenciesToInline = [ ... new Set ( dependenciesToInline ) ] ; dependenciesToInline . map ( dependency => { const dependencyMeta = cheTheiaPlugins . find ( plugin => plugin . id === dependency ) ; if ( ! dependencyMeta ) { throw new Error ( `Unable to find the dependency id ${ dependency } required by plug-in ${ id }` ) ; } resolvedExtensions . push ( dependencyMeta . extension ) ; dependencyMeta . vsixInfos . forEach ( ( value , key ) => { if ( ! vsixInfos . has ( key ) ) { vsixInfos . set ( key , value ) ; } } ) ; } ) ; } spec . extensions = resolvedExtensions ; const aliases = chePlugin . aliases ; return { id , vsixInfos , skipIndex , publisher , name , version , type , displayName , title , description , iconFile , repository , category , firstPublicationDate , latestUpdateDate , spec , aliases , } as MetaYamlPluginInfo ; } ) ) ; return metaYamlPluginInfos ; } }