diff --git a/packages/plugin-dlx/sources/commands/dlx.ts b/packages/plugin-dlx/sources/commands/dlx.ts index 2cc22c1c627c..20262564adab 100644 --- a/packages/plugin-dlx/sources/commands/dlx.ts +++ b/packages/plugin-dlx/sources/commands/dlx.ts @@ -1,6 +1,7 @@ import {BaseCommand, WorkspaceRequiredError} from '@yarnpkg/cli'; import {Configuration, Project, ThrowReport} from '@yarnpkg/core'; import {scriptUtils, structUtils} from '@yarnpkg/core'; +import {DEFAULT_LOCK_FILENAME, DEFAULT_RC_FILENAME} from '@yarnpkg/core'; import {Filename, PortablePath, npath, ppath, toFilename, xfs} from '@yarnpkg/fslib'; import {Command} from 'clipanion'; import tmp from 'tmp'; diff --git a/packages/plugin-init/package.json b/packages/plugin-init/package.json index ec667ea22646..8ee7d89a977c 100644 --- a/packages/plugin-init/package.json +++ b/packages/plugin-init/package.json @@ -3,7 +3,7 @@ "version": "2.0.0-rc.7", "nextVersion": { "semver": "2.0.0-rc.8", - "nonce": "279316411436635" + "nonce": "4149448387893945" }, "main": "./sources/index.ts", "dependencies": { diff --git a/packages/plugin-init/sources/commands/init.ts b/packages/plugin-init/sources/commands/init.ts index 6c6c939d2fc9..91270f0efde2 100644 --- a/packages/plugin-init/sources/commands/init.ts +++ b/packages/plugin-init/sources/commands/init.ts @@ -1,9 +1,10 @@ -import {BaseCommand} from '@yarnpkg/cli'; -import {Configuration, Manifest} from '@yarnpkg/core'; -import {structUtils} from '@yarnpkg/core'; -import {xfs, ppath, toFilename} from '@yarnpkg/fslib'; -import {updateAndSave} from '@yarnpkg/json-proxy'; -import {Command, UsageError} from 'clipanion'; +import {BaseCommand} from '@yarnpkg/cli'; +import {Configuration, Manifest} from '@yarnpkg/core'; +import {execUtils, scriptUtils, structUtils} from '@yarnpkg/core'; +import {xfs, ppath, toFilename, Filename} from '@yarnpkg/fslib'; +import {updateAndSave} from '@yarnpkg/json-proxy'; +import {Command, UsageError} from 'clipanion'; +import {inspect} from 'util'; // eslint-disable-next-line arca/no-default-export export default class InitCommand extends BaseCommand { @@ -13,6 +14,9 @@ export default class InitCommand extends BaseCommand { @Command.Boolean(`-p,--private`) private: boolean = false; + @Command.String(`-i,--install`) + install?: string; + static usage = Command.Usage({ description: `create a new package`, details: ` @@ -20,6 +24,8 @@ export default class InitCommand extends BaseCommand { If the \`-p,--private\` option is set, the package will be private by default. + If the \`-i,--install\` option is given a value, Yarn will first download it using \`yarn set version\` and only then forward the init call to the newly downloaded bundle. + The following settings can be used in order to affect what the generated package.json will look like: - \`initLicense\` @@ -32,18 +38,66 @@ export default class InitCommand extends BaseCommand { ], [ `Create a new private package in the local directory`, `yarn init -p`, + ], [ + `Create a new package and store the Yarn release inside`, + `yarn init -i berry`, ]], }); @Command.Path(`init`) async execute() { - if (xfs.existsSync(ppath.join(this.context.cwd, toFilename(`package.json`)))) + if (xfs.existsSync(ppath.join(this.context.cwd, Manifest.fileName))) throw new UsageError(`A package.json already exists in the specified directory`); + const configuration = await Configuration.find(this.context.cwd, this.context.plugins); + + if (typeof this.install !== `undefined`) { + return await this.executeProxy(configuration); + } else { + return await this.executeRegular(configuration); + } + } + + async executeProxy(configuration: Configuration) { + if (configuration.get(`yarnPath`) !== null) + throw new UsageError(`Cannot use the --install flag when the current directory already uses yarnPath (from ${configuration.sources.get(`yarnPath`)})`); + + if (configuration.projectCwd !== null) + throw new UsageError(`Cannot use the --install flag when the current directory is already part of a project`); + if (!xfs.existsSync(this.context.cwd)) await xfs.mkdirpPromise(this.context.cwd); - const configuration = await Configuration.find(this.context.cwd, this.context.plugins); + const lockfilePath = ppath.join(this.context.cwd, configuration.get(`lockfileFilename`)); + if (!xfs.existsSync(lockfilePath)) + await xfs.writeFilePromise(lockfilePath, ``); + + const versionExitCode = await this.cli.run([`set`, `version`, this.install!]); + if (versionExitCode !== 0) + return versionExitCode; + + this.context.stdout.write(`\n`); + + const args: Array = []; + if (this.private) + args.push(`-p`); + if (this.yes) + args.push(`-y`); + + const {code} = await execUtils.pipevp(`yarn`, [`init`, ...args], { + cwd: this.context.cwd, + stdin: this.context.stdin, + stdout: this.context.stdout, + stderr: this.context.stderr, + env: await scriptUtils.makeScriptEnv(), + }); + + return code; + } + + async executeRegular(configuration: Configuration) { + if (!xfs.existsSync(this.context.cwd)) + await xfs.mkdirpPromise(this.context.cwd); const manifest = new Manifest(); manifest.name = structUtils.makeIdent(configuration.get(`initScope`), ppath.basename(this.context.cwd)); @@ -51,8 +105,15 @@ export default class InitCommand extends BaseCommand { manifest.private = this.private; manifest.license = configuration.get(`initLicense`); - await updateAndSave(ppath.join(this.context.cwd, toFilename(`package.json`)), (tracker: Object) => { + await updateAndSave(ppath.join(this.context.cwd, Manifest.fileName), (tracker: Object) => { manifest.exportTo(tracker); }); + + const inspectable: any = {}; + manifest.exportTo(inspectable); + + this.context.stdout.write(`${inspect(inspectable, { + depth: Infinity, + })}\n`); } } diff --git a/packages/yarnpkg-cli/package.json b/packages/yarnpkg-cli/package.json index 6fbb439f571c..ad4b8037c2c3 100644 --- a/packages/yarnpkg-cli/package.json +++ b/packages/yarnpkg-cli/package.json @@ -3,7 +3,7 @@ "version": "2.0.0-rc.18", "nextVersion": { "semver": "2.0.0-rc.19", - "nonce": "8682259403650061" + "nonce": "6173145748735661" }, "main": "./sources/index.ts", "dependencies": { diff --git a/packages/yarnpkg-core/sources/Configuration.ts b/packages/yarnpkg-core/sources/Configuration.ts index 99ab6f750cd8..0f76a3e584b4 100644 --- a/packages/yarnpkg-core/sources/Configuration.ts +++ b/packages/yarnpkg-core/sources/Configuration.ts @@ -706,12 +706,16 @@ export class Configuration { if (xfs.existsSync(ppath.join(currentCwd, toFilename(`package.json`)))) projectCwd = currentCwd; - const topLevelFound = lockfileFilename !== null - ? xfs.existsSync(ppath.join(currentCwd, lockfileFilename)) - : projectCwd !== null; - - if (topLevelFound) - break; + if (lockfileFilename !== null) { + if (xfs.existsSync(ppath.join(currentCwd, lockfileFilename))) { + projectCwd = currentCwd; + break; + } + } else { + if (projectCwd !== null) { + break; + } + } nextCwd = ppath.dirname(currentCwd); } diff --git a/packages/yarnpkg-core/sources/Project.ts b/packages/yarnpkg-core/sources/Project.ts index 2ab2b8944a40..e03d50a39b2a 100644 --- a/packages/yarnpkg-core/sources/Project.ts +++ b/packages/yarnpkg-core/sources/Project.ts @@ -82,7 +82,7 @@ export class Project { if (!configuration.projectCwd) throw new Error(`No project found in the initial directory`); - let packageCwd = null; + let packageCwd = configuration.projectCwd; let nextCwd = startingCwd; let currentCwd = null; @@ -90,16 +90,14 @@ export class Project { while (currentCwd !== configuration.projectCwd) { currentCwd = nextCwd; - if (xfs.existsSync(ppath.join(currentCwd, toFilename(`package.json`)))) - if (!packageCwd) - packageCwd = currentCwd; + if (xfs.existsSync(ppath.join(currentCwd, toFilename(`package.json`)))) { + packageCwd = currentCwd; + break; + } nextCwd = ppath.dirname(currentCwd); } - if (!packageCwd) - throw new Error(`Assertion failed: No manifest found in the project`); - const project = new Project(configuration.projectCwd, {configuration}); await project.setupResolutions(); @@ -200,7 +198,7 @@ export class Project { } } - private async setupWorkspaces({force = false}: {force?: boolean} = {}) { + private async setupWorkspaces() { this.workspaces = []; this.workspacesByCwd = new Map(); diff --git a/packages/yarnpkg-core/sources/Workspace.ts b/packages/yarnpkg-core/sources/Workspace.ts index f8090a71a03b..d6ffeb3fe555 100644 --- a/packages/yarnpkg-core/sources/Workspace.ts +++ b/packages/yarnpkg-core/sources/Workspace.ts @@ -42,7 +42,9 @@ export class Workspace { async setup() { // @ts-ignore: It's ok to initialize it now - this.manifest = await Manifest.find(this.cwd); + this.manifest = xfs.existsSync(ppath.join(this.cwd, Manifest.fileName)) + ? await Manifest.find(this.cwd) + : new Manifest(); // We use ppath.relative to guarantee that the default hash will be consistent even if the project is installed on different OS / path // @ts-ignore: It's ok to initialize it now, even if it's readonly (setup is called right after construction) diff --git a/packages/yarnpkg-core/sources/index.ts b/packages/yarnpkg-core/sources/index.ts index 4ccb6f5ffa62..cc3c7287a906 100644 --- a/packages/yarnpkg-core/sources/index.ts +++ b/packages/yarnpkg-core/sources/index.ts @@ -8,6 +8,7 @@ import * as structUtils from './structUtils'; import * as tgzUtils from './tgzUtils'; export {Cache} from './Cache'; +export {DEFAULT_RC_FILENAME, DEFAULT_LOCK_FILENAME} from './Configuration'; export {Configuration, FormatType, PluginConfiguration, ProjectLookup, SettingsDefinition, SettingsType} from './Configuration'; export {Fetcher, FetchOptions, FetchResult, MinimalFetchOptions} from './Fetcher'; export {Installer, BuildDirective, BuildType} from './Installer'; @@ -28,7 +29,6 @@ export {YarnVersion} export {IdentHash, DescriptorHash, LocatorHash} from './types'; export {Ident, Descriptor, Locator, Package} from './types'; export {LinkType} from './types'; - export {hashUtils}; export {httpUtils}; export {execUtils};