From 7e242c36074d73386042a69b838efb2376c6e003 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Mon, 27 Feb 2023 16:51:21 +0000 Subject: [PATCH 1/7] automatic lookup for workspace folder --- src/spec-node/devContainersSpecCLI.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 16e316cb4..9199f0dfa 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -3,6 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import fs from 'fs'; import * as path from 'path'; import yargs, { Argv } from 'yargs'; @@ -127,6 +128,14 @@ function provisionOptions(y: Argv) { if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } + if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { + const cwd_content = fs.readdirSync(path.resolve(process.cwd())); + if (cwd_content.includes('.devcontainer')) { + argv['workspace-folder'] = path.resolve(process.cwd()); + } else { + throw new Error('Missing required argument: workspace-folder or id-label or override-config'); + } + } if (!(argv['workspace-folder'] || argv['id-label'])) { throw new Error('Missing required argument: workspace-folder or id-label'); } @@ -188,7 +197,6 @@ async function provision({ 'dotfiles-target-path': dotfilesTargetPath, 'container-session-data-folder': containerSessionDataFolder, }: ProvisionArgs) { - const workspaceFolder = workspaceFolderArg ? path.resolve(process.cwd(), workspaceFolderArg) : undefined; const addRemoteEnvs = addRemoteEnv ? (Array.isArray(addRemoteEnv) ? addRemoteEnv as string[] : [addRemoteEnv]) : []; const addCacheFroms = addCacheFrom ? (Array.isArray(addCacheFrom) ? addCacheFrom as string[] : [addCacheFrom]) : []; From 5c7077c67832614f0ec56bd5f3d76543e52c44f1 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Mon, 27 Feb 2023 17:55:04 +0000 Subject: [PATCH 2/7] removing duplicate update --- src/spec-node/devContainersSpecCLI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 9199f0dfa..fd5574336 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -131,7 +131,7 @@ function provisionOptions(y: Argv) { if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { const cwd_content = fs.readdirSync(path.resolve(process.cwd())); if (cwd_content.includes('.devcontainer')) { - argv['workspace-folder'] = path.resolve(process.cwd()); + argv['workspace-folder'] = '.'; } else { throw new Error('Missing required argument: workspace-folder or id-label or override-config'); } From c99c04f99004f716b6224cf1383b3c843d4bfc6d Mon Sep 17 00:00:00 2001 From: MunsMan Date: Tue, 28 Feb 2023 11:07:20 +0000 Subject: [PATCH 3/7] switching to findWorkspaceFolder Function like in issue #387 --- src/spec-node/devContainersSpecCLI.ts | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index fd5574336..6a4d8d388 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -83,6 +83,16 @@ const mountRegex = /^type=(bind|volume),source=([^,]+),target=([^,]+)(?:,externa })().catch(console.error); +function findWorkspaceFolder(): string | undefined { + const workspacePath = path.join(process.cwd(), '.devcontainer'); + if (fs.existsSync(workspacePath)) { + if (fs.lstatSync(workspacePath).isDirectory()) { + return process.cwd(); + } + } + return undefined; +} + export type UnpackArgv = T extends Argv ? U : T; function provisionOptions(y: Argv) { @@ -125,22 +135,13 @@ function provisionOptions(y: Argv) { }) .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; + const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); + console.debug(isWorkspaceFound) if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } - if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { - const cwd_content = fs.readdirSync(path.resolve(process.cwd())); - if (cwd_content.includes('.devcontainer')) { - argv['workspace-folder'] = '.'; - } else { - throw new Error('Missing required argument: workspace-folder or id-label or override-config'); - } - } - if (!(argv['workspace-folder'] || argv['id-label'])) { - throw new Error('Missing required argument: workspace-folder or id-label'); - } - if (!(argv['workspace-folder'] || argv['override-config'])) { - throw new Error('Missing required argument: workspace-folder or override-config'); + if (!(argv['id-label'] || argv['override-config'] || isWorkspaceFound)) { + throw new Error('Missing required argument: workspace-folder or id-label or override-config'); } const mounts = (argv.mount && (Array.isArray(argv.mount) ? argv.mount : [argv.mount])) as string[] | undefined; if (mounts?.some(mount => !mountRegex.test(mount))) { @@ -151,6 +152,10 @@ function provisionOptions(y: Argv) { throw new Error('Unmatched argument format: remote-env must match ='); } return true; + }).middleware((argv) => { + if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { + argv['workspace-folder'] = findWorkspaceFolder(); + } }); } From bac5de8ed226c1e7d398159fb1f7a5860c93c897 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Tue, 28 Feb 2023 11:30:04 +0000 Subject: [PATCH 4/7] Adding support for the `run-user-command` --- src/spec-node/devContainersSpecCLI.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 6a4d8d388..890ade8bb 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -136,7 +136,6 @@ function provisionOptions(y: Argv) { .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); - console.debug(isWorkspaceFound) if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } @@ -709,6 +708,8 @@ function runUserCommandsOptions(y: Argv) { }) .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; + const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); + console.debug(isWorkspaceFound) if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } @@ -716,10 +717,14 @@ function runUserCommandsOptions(y: Argv) { if (remoteEnvs?.some(remoteEnv => !/.+=.+/.test(remoteEnv))) { throw new Error('Unmatched argument format: remote-env must match ='); } - if (!argv['container-id'] && !idLabels?.length && !argv['workspace-folder']) { + if (!(argv['container-id'] || idLabels?.length || isWorkspaceFound)) { throw new Error('Missing required argument: One of --container-id, --id-label or --workspace-folder is required.'); } return true; + }).middleware((argv) => { + if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { + argv['workspace-folder'] = findWorkspaceFolder(); + } }); } From 2051fa16f4a6c1401113e68da3436c7400525da3 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Tue, 28 Feb 2023 11:33:59 +0000 Subject: [PATCH 5/7] Adding Support for `read-configuration` --- src/spec-node/devContainersSpecCLI.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 890ade8bb..54f4bd130 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -900,13 +900,18 @@ function readConfigurationOptions(y: Argv) { }) .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; + const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } - if (!argv['container-id'] && !idLabels?.length && !argv['workspace-folder']) { + if (!(argv['container-id'] || idLabels?.length || isWorkspaceFound)) { throw new Error('Missing required argument: One of --container-id, --id-label or --workspace-folder is required.'); } return true; + }).middleware((argv) => { + if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { + argv['workspace-folder'] = findWorkspaceFolder(); + } }); } From 06d690573f32ae71b414b93fa2aa72077a5e19eb Mon Sep 17 00:00:00 2001 From: MunsMan Date: Tue, 28 Feb 2023 11:37:45 +0000 Subject: [PATCH 6/7] adding support for `exec` --- src/spec-node/devContainersSpecCLI.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 54f4bd130..7ed829afc 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -1076,6 +1076,7 @@ function execOptions(y: Argv) { }) .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; + const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); } @@ -1083,10 +1084,14 @@ function execOptions(y: Argv) { if (remoteEnvs?.some(remoteEnv => !/.+=.+/.test(remoteEnv))) { throw new Error('Unmatched argument format: remote-env must match ='); } - if (!argv['container-id'] && !idLabels?.length && !argv['workspace-folder']) { + if (!(argv['container-id'] || idLabels?.length || isWorkspaceFound)) { throw new Error('Missing required argument: One of --container-id, --id-label or --workspace-folder is required.'); } return true; + }).middleware((argv) => { + if (!(argv['id-label'] || argv['override-config'] || argv['workspace-folder'])) { + argv['workspace-folder'] = findWorkspaceFolder(); + } }); } From bc7b16c9faf8ee0e2889f6292a4e7819261b2c37 Mon Sep 17 00:00:00 2001 From: MunsMan Date: Tue, 28 Feb 2023 13:57:40 +0000 Subject: [PATCH 7/7] adding feature to the `build` command. Had to add default to ensure that `workspace-folder` can't be undefined --- src/spec-node/devContainersSpecCLI.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/spec-node/devContainersSpecCLI.ts b/src/spec-node/devContainersSpecCLI.ts index 7ed829afc..05a664b8a 100644 --- a/src/spec-node/devContainersSpecCLI.ts +++ b/src/spec-node/devContainersSpecCLI.ts @@ -463,7 +463,7 @@ function buildOptions(y: Argv) { 'user-data-folder': { type: 'string', description: 'Host path to a directory that is intended to be persisted and share state between sessions.' }, 'docker-path': { type: 'string', description: 'Docker CLI path.' }, 'docker-compose-path': { type: 'string', description: 'Docker Compose CLI path.' }, - 'workspace-folder': { type: 'string', required: true, description: 'Workspace folder path. The devcontainer.json will be looked up relative to this path.' }, + 'workspace-folder': { type: 'string', default: '.', description: 'Workspace folder path. The devcontainer.json will be looked up relative to this path.' }, 'log-level': { choices: ['info' as 'info', 'debug' as 'debug', 'trace' as 'trace'], default: 'info' as 'info', description: 'Log level.' }, 'log-format': { choices: ['text' as 'text', 'json' as 'json'], default: 'text' as 'text', description: 'Log format.' }, 'no-cache': { type: 'boolean', default: false, description: 'Builds the image with `--no-cache`.' }, @@ -477,6 +477,14 @@ function buildOptions(y: Argv) { 'skip-feature-auto-mapping': { type: 'boolean', default: false, hidden: true, description: 'Temporary option for testing.' }, 'experimental-image-metadata': { type: 'boolean', default: experimentalImageMetadataDefault, hidden: true, description: 'Temporary option for testing.' }, 'skip-persisting-customizations-from-features': { type: 'boolean', default: false, hidden: true, description: 'Do not save customizations from referenced Features as image metadata' }, + }).check(argv => { + if (argv['workspace-folder'] === '.') { + const workspaceFolder = findWorkspaceFolder(); + if (!workspaceFolder) { + throw new Error('Unable to find Configuration File, provide workspace-folder argument'); + } + } + return true; }); } @@ -709,7 +717,7 @@ function runUserCommandsOptions(y: Argv) { .check(argv => { const idLabels = (argv['id-label'] && (Array.isArray(argv['id-label']) ? argv['id-label'] : [argv['id-label']])) as string[] | undefined; const isWorkspaceFound = argv['workspace-folder'] || findWorkspaceFolder(); - console.debug(isWorkspaceFound) + console.debug(isWorkspaceFound); if (idLabels?.some(idLabel => !/.+=.+/.test(idLabel))) { throw new Error('Unmatched argument format: id-label must match ='); }