@@ -22,6 +22,7 @@ import { Lockfile, readLockfile, writeLockfile } from './lockfile';
22
22
import { computeDependsOnInstallationOrder } from './containerFeaturesOrder' ;
23
23
import { logFeatureAdvisories } from './featureAdvisories' ;
24
24
import { getEntPasswdShellCommand } from '../spec-common/commonUtils' ;
25
+ import { ContainerError } from '../spec-common/errors' ;
25
26
26
27
// v1
27
28
const V1_ASSET_NAME = 'devcontainer-features.tgz' ;
@@ -116,18 +117,14 @@ export function parseMount(str: string): Mount {
116
117
. reduce ( ( acc , [ key , value ] ) => ( { ...acc , [ ( normalizedMountKeys [ key ] || key ) ] : value } ) , { } ) as Mount ;
117
118
}
118
119
119
- export type SourceInformation = LocalCacheSourceInformation | GithubSourceInformation | DirectTarballSourceInformation | FilePathSourceInformation | OCISourceInformation ;
120
+ export type SourceInformation = GithubSourceInformation | DirectTarballSourceInformation | FilePathSourceInformation | OCISourceInformation ;
120
121
121
122
interface BaseSourceInformation {
122
123
type : string ;
123
124
userFeatureId : string ; // Dictates how a supporting tool will locate and download a given feature. See https://github.com/devcontainers/spec/blob/main/proposals/devcontainer-features.md#referencing-a-feature
124
125
userFeatureIdWithoutVersion ?: string ;
125
126
}
126
127
127
- export interface LocalCacheSourceInformation extends BaseSourceInformation {
128
- type : 'local-cache' ;
129
- }
130
-
131
128
export interface OCISourceInformation extends BaseSourceInformation {
132
129
type : 'oci' ;
133
130
featureRef : OCIRef ;
@@ -215,18 +212,6 @@ export interface ContainerFeatureInternalParams {
215
212
experimentalFrozenLockfile ?: boolean ;
216
213
}
217
214
218
- export const multiStageBuildExploration = false ;
219
-
220
- const isTsnode = path . basename ( process . argv [ 0 ] ) === 'ts-node' || process . argv . indexOf ( 'ts-node/register' ) !== - 1 ;
221
-
222
- export function getContainerFeaturesFolder ( _extensionPath : string | { distFolder : string } ) {
223
- if ( isTsnode ) {
224
- return path . join ( require . resolve ( 'vscode-dev-containers/package.json' ) , '..' , 'container-features' ) ;
225
- }
226
- const distFolder = typeof _extensionPath === 'string' ? path . join ( _extensionPath , 'dist' ) : _extensionPath . distFolder ;
227
- return path . join ( distFolder , 'node_modules' , 'vscode-dev-containers' , 'container-features' ) ;
228
- }
229
-
230
215
// TODO: Move to node layer.
231
216
export function getContainerFeaturesBaseDockerFile ( contentSourceRootPath : string ) {
232
217
return `
@@ -467,29 +452,6 @@ async function askGitHubApiForTarballUri(sourceInformation: GithubSourceInformat
467
452
return undefined ;
468
453
}
469
454
470
- export async function loadFeaturesJson ( jsonBuffer : Buffer , filePath : string , output : Log ) : Promise < FeatureSet | undefined > {
471
- if ( jsonBuffer . length === 0 ) {
472
- output . write ( 'Parsed featureSet is empty.' , LogLevel . Error ) ;
473
- return undefined ;
474
- }
475
-
476
- const featureSet : FeatureSet = jsonc . parse ( jsonBuffer . toString ( ) ) ;
477
- if ( ! featureSet ?. features || featureSet . features . length === 0 ) {
478
- output . write ( 'Parsed featureSet contains no features.' , LogLevel . Error ) ;
479
- return undefined ;
480
- }
481
- output . write ( `Loaded ${ filePath } , which declares ${ featureSet . features . length } features and ${ ( ! ! featureSet . sourceInformation ) ? 'contains' : 'does not contain' } explicit source info.` ,
482
- LogLevel . Trace ) ;
483
-
484
- return updateFromOldProperties ( featureSet ) ;
485
- }
486
-
487
- export async function loadV1FeaturesJsonFromDisk ( pathToDirectory : string , output : Log ) : Promise < FeatureSet | undefined > {
488
- const filePath = path . join ( pathToDirectory , V1_DEVCONTAINER_FEATURES_FILE_NAME ) ;
489
- const jsonBuffer : Buffer = await readLocalFile ( filePath ) ;
490
- return loadFeaturesJson ( jsonBuffer , filePath , output ) ;
491
- }
492
-
493
455
function updateFromOldProperties < T extends { features : ( Feature & { extensions ?: string [ ] ; settings ?: object ; customizations ?: VSCodeCustomizations } ) [ ] } > ( original : T ) : T {
494
456
// https://github.com/microsoft/dev-container-spec/issues/1
495
457
if ( ! original . features . find ( f => f . extensions || f . settings ) ) {
@@ -522,7 +484,7 @@ function updateFromOldProperties<T extends { features: (Feature & { extensions?:
522
484
523
485
// Generate a base featuresConfig object with the set of locally-cached features,
524
486
// as well as downloading and merging in remote feature definitions.
525
- export async function generateFeaturesConfig ( params : ContainerFeatureInternalParams , dstFolder : string , config : DevContainerConfig , getLocalFeaturesFolder : ( d : string ) => string , additionalFeatures : Record < string , string | boolean | Record < string , string | boolean > > ) {
487
+ export async function generateFeaturesConfig ( params : ContainerFeatureInternalParams , dstFolder : string , config : DevContainerConfig , additionalFeatures : Record < string , string | boolean | Record < string , string | boolean > > ) {
526
488
const { output } = params ;
527
489
528
490
const workspaceRoot = params . cwd ;
@@ -533,15 +495,6 @@ export async function generateFeaturesConfig(params: ContainerFeatureInternalPar
533
495
return undefined ;
534
496
}
535
497
536
- // load local cache of features;
537
- // TODO: Update so that cached features are always version 2
538
- const localFeaturesFolder = getLocalFeaturesFolder ( params . extensionPath ) ;
539
- const locallyCachedFeatureSet = await loadV1FeaturesJsonFromDisk ( localFeaturesFolder , output ) ; // TODO: Pass dist folder instead to also work with the devcontainer.json support package.
540
- if ( ! locallyCachedFeatureSet ) {
541
- output . write ( 'Failed to load locally cached features' , LogLevel . Error ) ;
542
- return undefined ;
543
- }
544
-
545
498
let configPath = config . configFilePath && uriToFsPath ( config . configFilePath , params . platform ) ;
546
499
output . write ( `configPath: ${ configPath } ` , LogLevel . Trace ) ;
547
500
@@ -567,7 +520,7 @@ export async function generateFeaturesConfig(params: ContainerFeatureInternalPar
567
520
568
521
// Fetch features, stage into the appropriate build folder, and read the feature's devcontainer-feature.json
569
522
output . write ( '--- Fetching User Features ----' , LogLevel . Trace ) ;
570
- await fetchFeatures ( params , featuresConfig , locallyCachedFeatureSet , dstFolder , localFeaturesFolder , ociCacheDir , lockfile ) ;
523
+ await fetchFeatures ( params , featuresConfig , dstFolder , ociCacheDir , lockfile ) ;
571
524
572
525
await logFeatureAdvisories ( params , featuresConfig ) ;
573
526
await writeLockfile ( params , config , featuresConfig , initLockfile ) ;
@@ -758,9 +711,10 @@ export async function getFeatureIdType(params: CommonParams, userFeatureId: stri
758
711
// (1) A feature backed by a GitHub Release
759
712
// Syntax: <repoOwner>/<repoName>/<featureId>[@version]
760
713
761
- // DEPRECATED: This is a legacy feature-set ID
714
+ // Legacy feature-set ID
762
715
if ( ! userFeatureId . includes ( '/' ) && ! userFeatureId . includes ( '\\' ) ) {
763
- return { type : 'local-cache' , manifest : undefined } ;
716
+ output . write ( `Legacy feature '${ userFeatureId } ' not supported. Please check https://containers.dev/features for replacements.` , LogLevel . Error ) ;
717
+ throw new ContainerError ( { description : `Legacy feature '${ userFeatureId } ' not supported. Please check https://containers.dev/features for replacements.` } ) ;
764
718
}
765
719
766
720
// Direct tarball reference
@@ -797,9 +751,6 @@ export function getBackwardCompatibleFeatureId(output: Log, id: string) {
797
751
deprecatedFeaturesIntoOptions . set ( 'maven' , 'java' ) ;
798
752
deprecatedFeaturesIntoOptions . set ( 'jupyterlab' , 'python' ) ;
799
753
800
- // TODO: add warning logs once we have context on the new location for these Features.
801
- // const deprecatedFeatures = ['fish', 'homebrew'];
802
-
803
754
const newFeaturePath = 'ghcr.io/devcontainers/features' ;
804
755
// Note: Pin the versionBackwardComp to '1' to avoid breaking changes.
805
756
const versionBackwardComp = '1' ;
@@ -840,29 +791,6 @@ export async function processFeatureIdentifier(params: CommonParams, configPath:
840
791
841
792
const { type, manifest } = await getFeatureIdType ( params , userFeature . userFeatureId , lockfile ) ;
842
793
843
- // cached feature
844
- // Resolves deprecated features (fish, maven, gradle, homebrew, jupyterlab)
845
- if ( type === 'local-cache' ) {
846
- output . write ( `Cached feature found.` ) ;
847
-
848
- let feat : Feature = {
849
- id : userFeature . userFeatureId ,
850
- name : userFeature . userFeatureId ,
851
- value : userFeature . options ,
852
- included : true ,
853
- } ;
854
-
855
- let newFeaturesSet : FeatureSet = {
856
- sourceInformation : {
857
- type : 'local-cache' ,
858
- userFeatureId : originalUserFeatureId
859
- } ,
860
- features : [ feat ] ,
861
- } ;
862
-
863
- return newFeaturesSet ;
864
- }
865
-
866
794
// remote tar file
867
795
if ( type === 'direct-tarball' ) {
868
796
output . write ( `Remote tar file found.` ) ;
@@ -1036,7 +964,7 @@ export async function processFeatureIdentifier(params: CommonParams, configPath:
1036
964
// throw new Error(`Unsupported feature source type: ${type}`);
1037
965
}
1038
966
1039
- async function fetchFeatures ( params : { extensionPath : string ; cwd : string ; output : Log ; env : NodeJS . ProcessEnv } , featuresConfig : FeaturesConfig , localFeatures : FeatureSet , dstFolder : string , localFeaturesFolder : string , ociCacheDir : string , lockfile : Lockfile | undefined ) {
967
+ async function fetchFeatures ( params : { extensionPath : string ; cwd : string ; output : Log ; env : NodeJS . ProcessEnv } , featuresConfig : FeaturesConfig , dstFolder : string , ociCacheDir : string , lockfile : Lockfile | undefined ) {
1040
968
const featureSets = featuresConfig . featureSets ;
1041
969
for ( let idx = 0 ; idx < featureSets . length ; idx ++ ) { // Index represents the previously computed installation order.
1042
970
const featureSet = featureSets [ idx ] ;
@@ -1045,10 +973,6 @@ async function fetchFeatures(params: { extensionPath: string; cwd: string; outpu
1045
973
continue ;
1046
974
}
1047
975
1048
- if ( ! localFeatures ) {
1049
- continue ;
1050
- }
1051
-
1052
976
const { output } = params ;
1053
977
1054
978
const feature = featureSet . features [ 0 ] ;
@@ -1086,18 +1010,6 @@ async function fetchFeatures(params: { extensionPath: string; cwd: string; outpu
1086
1010
continue ;
1087
1011
}
1088
1012
1089
- if ( sourceInfoType === 'local-cache' ) {
1090
- // create copy of the local features to set the environment variables for them.
1091
- await mkdirpLocal ( featCachePath ) ;
1092
- await cpDirectoryLocal ( localFeaturesFolder , featCachePath ) ;
1093
-
1094
- if ( ! ( await applyFeatureConfigToFeature ( output , featureSet , feature , featCachePath , undefined ) ) ) {
1095
- const err = `Failed to parse feature '${ featureDebugId } '. Please check your devcontainer.json 'features' attribute.` ;
1096
- throw new Error ( err ) ;
1097
- }
1098
- continue ;
1099
- }
1100
-
1101
1013
if ( sourceInfoType === 'file-path' ) {
1102
1014
output . write ( `Detected local file path` , LogLevel . Trace ) ;
1103
1015
await mkdirpLocal ( featCachePath ) ;
0 commit comments