From c7c34f63f9989b0542ab56f3e6679761a5cd6eca Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Thu, 2 Mar 2023 18:39:40 +0000 Subject: [PATCH 01/11] Update: Use npm for install, update and unstall where required (fixes #175) --- lib/integration/AdaptFramework/npmInstall.js | 7 +- lib/integration/Plugin.js | 13 +- lib/integration/PluginManagement/install.js | 21 ++- lib/integration/PluginManagement/npm.js | 54 ++++++ lib/integration/PluginManagement/register.js | 3 + lib/integration/PluginManagement/rename.js | 1 + lib/integration/PluginManagement/uninstall.js | 19 ++- .../PluginManagement/unregister.js | 1 + lib/integration/PluginManagement/update.js | 16 +- lib/integration/Project.js | 5 + lib/integration/Target.js | 154 +++++++++++------- 11 files changed, 227 insertions(+), 67 deletions(-) create mode 100644 lib/integration/PluginManagement/npm.js diff --git a/lib/integration/AdaptFramework/npmInstall.js b/lib/integration/AdaptFramework/npmInstall.js index d1fd749..5d38737 100644 --- a/lib/integration/AdaptFramework/npmInstall.js +++ b/lib/integration/AdaptFramework/npmInstall.js @@ -4,12 +4,13 @@ import path from 'path' export default async function npmInstall ({ logger, - cwd + cwd, + args = [] } = {}) { cwd = path.resolve(process.cwd(), cwd) await new Promise((resolve, reject) => { - logger?.log(chalk.cyan('installing node dependencies')) - const npm = spawn((process.platform === 'win32' ? 'npm.cmd' : 'npm'), ['--unsafe-perm', 'install'], { + if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) + const npm = spawn((process.platform === 'win32' ? 'npm.cmd' : 'npm'), ['--unsafe-perm', 'install', ...args], { stdio: 'inherit', cwd }) diff --git a/lib/integration/Plugin.js b/lib/integration/Plugin.js index b69ff3b..37b29eb 100644 --- a/lib/integration/Plugin.js +++ b/lib/integration/Plugin.js @@ -79,7 +79,7 @@ export default class Plugin { * @returns {boolean|null} */ get isUpToDate () { - if (!this.hasFrameworkCompatibleVersion) return true; + if (!this.hasFrameworkCompatibleVersion) return true const canCheckSourceAgainstProject = (this.latestSourceVersion && this.projectVersion) if (!canCheckSourceAgainstProject) return null const isLatestVersion = (this.projectVersion === this.latestSourceVersion) @@ -187,6 +187,7 @@ export default class Plugin { if (!this.isLocalSource) throw new Error('Plugin name or version must be a path to the source') if (this.isLocalSourceZip) throw new Error('Cannot install from zip files') this._sourceInfo = await new Promise((resolve, reject) => { + // TODO: npm implementation // get bower.json data const paths = [ path.resolve(this.cwd, `${this.sourcePath}/bower.json`) @@ -211,6 +212,7 @@ export default class Plugin { const perform = async (attemptCount = 0) => { try { return await new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.info(`${this.packageName}`, null, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) @@ -227,12 +229,18 @@ export default class Plugin { this._versionsInfo = info.versions.filter(version => semverOptions.includePrerelease ? true : !semver.prerelease(version)) } + async refetchProjectInfo () { + this._projectInfo = null + return this.fetchProjectInfo() + } + async fetchProjectInfo () { if (this._projectInfo) return this._projectInfo this._projectInfo = null this._projectInfo = await new Promise((resolve, reject) => { // get bower.json data globs([ + // TODO: npm implementation `${this.cwd.replace(/\\/g, '/')}/src/*/${this.packageName}/.bower.json`, `${this.cwd.replace(/\\/g, '/')}/src/*/${this.packageName}/bower.json` ], (err, matches) => { @@ -242,6 +250,7 @@ export default class Plugin { if (!match) { // widen the search globs([ + // TODO: npm implementation `${this.cwd.replace(/\\/g, '/')}/src/**/.bower.json`, `${this.cwd.replace(/\\/g, '/')}/src/**/bower.json` ], (err, matches) => { @@ -268,6 +277,7 @@ export default class Plugin { const perform = async (attemptCount = 0) => { try { return await new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.info(`${this.packageName}@${version}`, null, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) @@ -353,6 +363,7 @@ export default class Plugin { if (this._repositoryUrl) return this._repositoryUrl if (this.isLocalSource) return const url = await new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.lookup(this.packageName, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) diff --git a/lib/integration/PluginManagement/install.js b/lib/integration/PluginManagement/install.js index 1098bfd..2925c0a 100644 --- a/lib/integration/PluginManagement/install.js +++ b/lib/integration/PluginManagement/install.js @@ -8,6 +8,7 @@ import Target from '../Target.js' import bower from 'bower' import { difference } from 'lodash-es' import path from 'path' +import { install as npmInstall } from './npm.js' export default async function install ({ plugins, @@ -20,7 +21,10 @@ export default async function install ({ logger = null }) { cwd = path.resolve(process.cwd(), cwd) - isClean && await new Promise(resolve => bower.commands.cache.clean().on('end', resolve)) + isClean && await new Promise(resolve => { + // TODO: npm implementation + bower.commands.cache.clean().on('end', resolve) + }) const project = new Project({ cwd, logger }) project.tryThrowInvalidPath() @@ -40,8 +44,21 @@ export default async function install ({ await eachOfSeriesProgress( installTargetsToBeInstalled, target => target.install({ clone: dev }), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Installing plugins ${percentage}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Installing plugins ${(percentage / (project.isNPM ? 2 : 1))}% complete`) ) + if (project.isNPM) { + // Batch install npm plugins as it's faster + const installArgs = installTargetsToBeInstalled + .filter(target => target.isNPMInstall) + .map(target => `${target.packageName}@${target.versionToApply}`) + const outputPath = path.join(cwd, 'src') + await npmInstall({ logger, cwd: outputPath, args: installArgs }) + await eachOfSeriesProgress( + installTargetsToBeInstalled, + target => target.postInstall(), + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Installing plugins ${50 + (percentage / 2)}% complete`) + ) + } logger?.log(`${chalk.bold.cyan('')} Installing plugins 100% complete`) const manifestDependencies = await project.getManifestDependencies() await updateManifest({ logger, project, targets, manifestDependencies, isInteractive }) diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js new file mode 100644 index 0000000..46e0991 --- /dev/null +++ b/lib/integration/PluginManagement/npm.js @@ -0,0 +1,54 @@ +import chalk from 'chalk' +import { exec } from 'child_process' +import path from 'path' + +export async function install ({ + logger, + cwd, + args = [] +} = {}) { + cwd = path.resolve(process.cwd(), cwd) + await new Promise((resolve, reject) => { + if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) + exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'install', ...args].join(' '), { + cwd + }, (err, stdout, stderr) => { + if (!err) return resolve() + reject(stderr) + }) + }) +} + +export async function update ({ + logger, + cwd, + args = [] +} = {}) { + cwd = path.resolve(process.cwd(), cwd) + await new Promise((resolve, reject) => { + if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) + exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'update', ...args].join(' '), { + cwd + }, (err, stdout, stderr) => { + if (!err) return resolve() + reject(stderr) + }) + }) +} + +export async function uninstall ({ + logger, + cwd, + args = [] +} = {}) { + cwd = path.resolve(process.cwd(), cwd) + await new Promise((resolve, reject) => { + if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) + exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'uninstall', ...args].join(' '), { + cwd + }, (err, stdout, stderr) => { + if (!err) return resolve() + reject(stderr) + }) + }) +} diff --git a/lib/integration/PluginManagement/register.js b/lib/integration/PluginManagement/register.js index 879e639..adb0760 100644 --- a/lib/integration/PluginManagement/register.js +++ b/lib/integration/PluginManagement/register.js @@ -19,6 +19,7 @@ export default async function register ({ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { + // TODO: npm implementation const bowerJSONPath = path.join(cwd, 'bower.json') const hasBowerJSON = fs.existsSync(bowerJSONPath) @@ -108,6 +109,7 @@ async function confirm (properties) { async function exists (BOWER_REGISTRY_CONFIG, plugin) { const pluginName = plugin.toString().toLowerCase() return new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.search(pluginName, { registry: BOWER_REGISTRY_CONFIG.register }) @@ -121,6 +123,7 @@ async function exists (BOWER_REGISTRY_CONFIG, plugin) { async function registerWithBowerRepo (BOWER_REGISTRY_CONFIG, plugin, repository) { return new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.register(plugin.toString(), repository.url || repository, { registry: BOWER_REGISTRY_CONFIG }) diff --git a/lib/integration/PluginManagement/rename.js b/lib/integration/PluginManagement/rename.js index 1ae33d5..dcde829 100644 --- a/lib/integration/PluginManagement/rename.js +++ b/lib/integration/PluginManagement/rename.js @@ -83,6 +83,7 @@ async function renameInBowerRepo ({ async function exists (BOWER_REGISTRY_CONFIG, plugin) { const pluginName = plugin.toString().toLowerCase() return new Promise((resolve, reject) => { + // TODO: npm implementation bower.commands.search(pluginName, { registry: BOWER_REGISTRY_CONFIG.register }) diff --git a/lib/integration/PluginManagement/uninstall.js b/lib/integration/PluginManagement/uninstall.js index 69a6bb8..e684d56 100644 --- a/lib/integration/PluginManagement/uninstall.js +++ b/lib/integration/PluginManagement/uninstall.js @@ -7,6 +7,7 @@ import { createPromptTask } from '../../util/createPromptTask.js' import { errorPrinter, packageNamePrinter } from './print.js' import { intersection } from 'lodash-es' import path from 'path' +import { uninstall as npmUninstall } from './npm.js' export default async function uninstall ({ plugins, @@ -24,11 +25,25 @@ export default async function uninstall ({ if (!targets?.length) return targets await loadPluginData({ logger, targets }) + const uninstallTargetsToBeUninstalled = targets.filter(target => target.isToBeUninstalled) await eachOfLimitProgress( - targets.filter(target => target.isToBeUninstalled), + uninstallTargetsToBeUninstalled, target => target.uninstall(), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${percentage}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) ) + if (project.isNPM) { + // Batch install npm plugins as it's faster + const installArgs = uninstallTargetsToBeUninstalled + .filter(target => target.isNPMUninstall) + .map(target => `${target.packageName}`) + const outputPath = path.join(cwd, 'src') + await npmUninstall({ logger, cwd: outputPath, args: installArgs }) + await eachOfLimitProgress( + uninstallTargetsToBeUninstalled, + target => target.postUninstall(), + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${50 + (percentage / 2)}% complete`) + ) + } logger?.log(`${chalk.bold.cyan('')} Uninstalling plugins 100% complete`) const installedDependencies = await project.getInstalledDependencies() await updateManifest({ project, targets, installedDependencies, isInteractive }) diff --git a/lib/integration/PluginManagement/unregister.js b/lib/integration/PluginManagement/unregister.js index 3170207..1848157 100644 --- a/lib/integration/PluginManagement/unregister.js +++ b/lib/integration/PluginManagement/unregister.js @@ -17,6 +17,7 @@ export default async function unregister ({ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { + // TODO: npm implementation const bowerJSONPath = path.join(cwd, 'bower.json') const hasBowerJSON = fs.existsSync(bowerJSONPath) const bowerJSON = hasBowerJSON ? await readValidateJSON(bowerJSONPath) : {} diff --git a/lib/integration/PluginManagement/update.js b/lib/integration/PluginManagement/update.js index c89df22..662ecbc 100644 --- a/lib/integration/PluginManagement/update.js +++ b/lib/integration/PluginManagement/update.js @@ -5,6 +5,7 @@ import Project from '../Project.js' import { createPromptTask } from '../../util/createPromptTask.js' import { errorPrinter, packageNamePrinter, versionPrinter, existingVersionPrinter } from './print.js' import { eachOfLimitProgress, eachOfSeriesProgress } from '../../util/promises.js' +import { update as npmUpdate } from './npm.js' /** @typedef {import("../Target.js").default} Target */ export default async function update ({ @@ -35,8 +36,21 @@ export default async function update ({ await eachOfSeriesProgress( updateTargetsToBeUpdated, target => target.update(), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${percentage}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) ) + if (project.isNPM) { + // Batch install npm plugins as it's faster + const installArgs = updateTargetsToBeUpdated + .filter(target => target.isNPMUpdate) + .map(target => `${target.packageName}`) + const outputPath = path.join(cwd, 'src') + await npmUpdate({ logger, cwd: outputPath, args: installArgs }) + await eachOfSeriesProgress( + updateTargetsToBeUpdated, + target => target.postUpdate(), + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${50 + (percentage / 2)}% complete`) + ) + } logger?.log(`${chalk.bold.cyan('')} Updating plugins 100% complete`) } await summariseUpdates({ logger, targets }) diff --git a/lib/integration/Project.js b/lib/integration/Project.js index 528f4e0..2486121 100644 --- a/lib/integration/Project.js +++ b/lib/integration/Project.js @@ -48,6 +48,10 @@ export default class Project { } } + isNPM() { + return fs.existsSync(path.join(cwd, 'src/package.json')) + } + tryThrowInvalidPath () { if (this.containsManifestFile) return this.logger?.error('Fatal error: please run above commands in adapt course directory.') @@ -82,6 +86,7 @@ export default class Project { async getInstalledDependencies () { const getDependencyBowerJSONs = async () => { + // TODO: npm implementation const glob = `${this.cwd.replace(/\\/g, '/')}/src/**/bower.json` const bowerJSONPaths = await new Promise((resolve, reject) => { globs(glob, (err, matches) => { diff --git a/lib/integration/Target.js b/lib/integration/Target.js index 1bea515..6871fae 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -160,6 +160,7 @@ export default class Target extends Plugin { const logger = this.logger const pluginTypeFolder = await this.getTypeFolder() if (this.isLocalSource) { + // TODO: npm implementation await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) const pluginPath = path.resolve(this.cwd, 'src', pluginTypeFolder, this.name) await fs.rm(pluginPath, { recursive: true, force: true }) @@ -168,8 +169,7 @@ export default class Target extends Plugin { bowerJSON._source = this.sourcePath bowerJSON._wasInstalledFromPath = true await fs.writeJSON(path.join(pluginPath, '.bower.json'), bowerJSON, { spaces: 2, replacer: null }) - this._projectInfo = null - await this.fetchProjectInfo() + await this.refetchProjectInfo() return } if (clone) { @@ -200,77 +200,115 @@ export default class Target extends Plugin { throw new Error(chalk.yellow(this.packageName), `could not checkout branch "${this.versionToApply}".`) } } - this._projectInfo = null - await this.fetchProjectInfo() + await this.refetchProjectInfo() return } - // bower install - const outputPath = path.join(this.cwd, 'src', pluginTypeFolder) - const pluginPath = path.join(outputPath, this.name) - try { - await fs.rm(pluginPath, { recursive: true, force: true }) - } catch (err) { - throw new Error(`There was a problem writing to the target directory ${pluginPath}`) - } - await new Promise((resolve, reject) => { - const pluginNameVersion = `${this.packageName}@${this.versionToApply}` - bower.commands.install([pluginNameVersion], null, { - directory: outputPath, - cwd: this.cwd, - registry: this.BOWER_REGISTRY_CONFIG - }) - .on('end', resolve) - .on('error', err => { - err = new Error(`Bower reported ${err}`) - this._error = err - reject(err) + if (!this.project.isNPM) { + // bower install + const outputPath = path.join(this.cwd, 'src', pluginTypeFolder) + const pluginPath = path.join(outputPath, this.name) + try { + await fs.rm(pluginPath, { recursive: true, force: true }) + } catch (err) { + throw new Error(`There was a problem writing to the target directory ${pluginPath}`) + } + await new Promise((resolve, reject) => { + const pluginNameVersion = `${this.packageName}@${this.versionToApply}` + // TODO: npm implementation + bower.commands.install([pluginNameVersion], null, { + directory: outputPath, + cwd: this.cwd, + registry: this.BOWER_REGISTRY_CONFIG }) - }) - const bowerJSON = await fs.readJSON(path.join(pluginPath, 'bower.json')) - bowerJSON.version = bowerJSON.version ?? this.versionToApply; - await fs.writeJSON(path.join(pluginPath, '.bower.json'), bowerJSON, { spaces: 2, replacer: null }) + .on('end', resolve) + .on('error', err => { + err = new Error(`Bower reported ${err}`) + this._error = err + reject(err) + }) + }) + await this.postInstall() + return + } + this.isNPMInstall = true + } + + async postInstall () { + if (!this.project.isNPM) { + const pluginTypeFolder = await this.getTypeFolder() + const outputPath = path.join(this.cwd, 'src', pluginTypeFolder) + const pluginPath = path.join(outputPath, this.name) + const bowerJSON = await fs.readJSON(path.join(pluginPath, 'bower.json')) + bowerJSON.version = bowerJSON.version ?? this.versionToApply + await fs.writeJSON(path.join(pluginPath, '.bower.json'), bowerJSON, { spaces: 2, replacer: null }) + await this.refetchProjectInfo() + return + } + const outputPath = path.join(this.cwd, 'src') + const pluginPath = path.join(outputPath, 'node_modules', this.name) + const bowerJSON = await fs.readJSON(path.join(pluginPath, 'package.json')) + bowerJSON.version = bowerJSON.version ?? this.versionToApply + await fs.writeJSON(path.join(pluginPath, '.package.json'), bowerJSON, { spaces: 2, replacer: null }) this._projectInfo = null await this.fetchProjectInfo() } async update () { if (!this.isToBeUpdated) throw new Error() - const typeFolder = await this.getTypeFolder() - const outputPath = path.join(this.cwd, 'src', typeFolder) - const pluginPath = path.join(outputPath, this.name) - try { - await fs.rm(pluginPath, { recursive: true, force: true }) - } catch (err) { - throw new Error(`There was a problem writing to the target directory ${pluginPath}`) - } - await new Promise((resolve, reject) => { - const pluginNameVersion = `${this.packageName}@${this.matchedVersion}` - bower.commands.install([pluginNameVersion], null, { - directory: outputPath, - cwd: this.cwd, - registry: this.BOWER_REGISTRY_CONFIG - }) - .on('end', resolve) - .on('error', err => { - err = new Error(`Bower reported ${err}`) - this._error = err - reject(err) + if (!this.project.isNPM) { + // bower update + const typeFolder = await this.getTypeFolder() + const outputPath = path.join(this.cwd, 'src', typeFolder) + const pluginPath = path.join(outputPath, this.name) + try { + await fs.rm(pluginPath, { recursive: true, force: true }) + } catch (err) { + throw new Error(`There was a problem writing to the target directory ${pluginPath}`) + } + await new Promise((resolve, reject) => { + const pluginNameVersion = `${this.packageName}@${this.matchedVersion}` + // TODO: npm implementation + bower.commands.install([pluginNameVersion], null, { + directory: outputPath, + cwd: this.cwd, + registry: this.BOWER_REGISTRY_CONFIG }) - }) + .on('end', resolve) + .on('error', err => { + err = new Error(`Bower reported ${err}`) + this._error = err + reject(err) + }) + }) + await this.postUpdate() + return + } + this.isNPMUpdate = true + } + + async postUpdate () { this.preUpdateProjectVersion = this.projectVersion - this._projectInfo = null - await this.fetchProjectInfo() + await this.refetchProjectInfo() } async uninstall () { - try { - if (!this.isToBeUninstalled) throw new Error() - await fs.rm(this.projectPath, { recursive: true, force: true }) - this._wasUninstalled = true - } catch (err) { - this._wasUninstalled = false - throw new Error(`There was a problem writing to the target directory ${this.projectPath}`) + if (!this.project.isNPM) { + // bower uninstall + try { + if (!this.isToBeUninstalled) throw new Error() + await fs.rm(this.projectPath, { recursive: true, force: true }) + this._wasUninstalled = true + } catch (err) { + this._wasUninstalled = false + throw new Error(`There was a problem writing to the target directory ${this.projectPath}`) + } + return } + this.isNPMUninstall = true + } + + async postUninstall () { + this._wasUninstalled = true } isNameMatch (name) { From 408a7d172b9e4cd29baae17e5aac2a1197d27e37 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Thu, 2 Mar 2023 19:32:12 +0000 Subject: [PATCH 02/11] Remove unnecessary changes --- lib/integration/AdaptFramework/npmInstall.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/integration/AdaptFramework/npmInstall.js b/lib/integration/AdaptFramework/npmInstall.js index 5d38737..23944d3 100644 --- a/lib/integration/AdaptFramework/npmInstall.js +++ b/lib/integration/AdaptFramework/npmInstall.js @@ -4,12 +4,11 @@ import path from 'path' export default async function npmInstall ({ logger, - cwd, - args = [] + cwd } = {}) { cwd = path.resolve(process.cwd(), cwd) await new Promise((resolve, reject) => { - if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) + logger?.log(chalk.cyan('installing node dependencies')) const npm = spawn((process.platform === 'win32' ? 'npm.cmd' : 'npm'), ['--unsafe-perm', 'install', ...args], { stdio: 'inherit', cwd From 14a777c5e16ce4cd4e624fcd0bf4df9de88fb60d Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Thu, 2 Mar 2023 19:33:09 +0000 Subject: [PATCH 03/11] Remove unnecessary changes --- lib/integration/AdaptFramework/npmInstall.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/integration/AdaptFramework/npmInstall.js b/lib/integration/AdaptFramework/npmInstall.js index 23944d3..d1fd749 100644 --- a/lib/integration/AdaptFramework/npmInstall.js +++ b/lib/integration/AdaptFramework/npmInstall.js @@ -9,7 +9,7 @@ export default async function npmInstall ({ cwd = path.resolve(process.cwd(), cwd) await new Promise((resolve, reject) => { logger?.log(chalk.cyan('installing node dependencies')) - const npm = spawn((process.platform === 'win32' ? 'npm.cmd' : 'npm'), ['--unsafe-perm', 'install', ...args], { + const npm = spawn((process.platform === 'win32' ? 'npm.cmd' : 'npm'), ['--unsafe-perm', 'install'], { stdio: 'inherit', cwd }) From dd60384fa7b7026a8190fef421e73b1e0cadeda3 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Sat, 4 Mar 2023 08:56:22 +0000 Subject: [PATCH 04/11] Suggestions --- lib/integration/Plugin.js | 16 ++--- lib/integration/PluginManagement/npm.js | 37 ++++------- lib/integration/Project.js | 12 ++-- lib/integration/Target.js | 84 ++++++++++++------------- 4 files changed, 70 insertions(+), 79 deletions(-) diff --git a/lib/integration/Plugin.js b/lib/integration/Plugin.js index 37b29eb..361d630 100644 --- a/lib/integration/Plugin.js +++ b/lib/integration/Plugin.js @@ -187,9 +187,9 @@ export default class Plugin { if (!this.isLocalSource) throw new Error('Plugin name or version must be a path to the source') if (this.isLocalSourceZip) throw new Error('Cannot install from zip files') this._sourceInfo = await new Promise((resolve, reject) => { - // TODO: npm implementation - // get bower.json data + // get package.json or bower.json data const paths = [ + path.resolve(this.cwd, `${this.sourcePath}/package.json`), path.resolve(this.cwd, `${this.sourcePath}/bower.json`) ] const bowerJSON = paths.reduce((bowerJSON, bowerJSONPath) => { @@ -238,9 +238,10 @@ export default class Plugin { if (this._projectInfo) return this._projectInfo this._projectInfo = null this._projectInfo = await new Promise((resolve, reject) => { - // get bower.json data + // get package.json or bower.json data globs([ - // TODO: npm implementation + `${this.cwd.replace(/\\/g, '/')}/src/node_modules/${this.packageName}/.package.json`, + `${this.cwd.replace(/\\/g, '/')}/src/node_modules/${this.packageName}/package.json`, `${this.cwd.replace(/\\/g, '/')}/src/*/${this.packageName}/.bower.json`, `${this.cwd.replace(/\\/g, '/')}/src/*/${this.packageName}/bower.json` ], (err, matches) => { @@ -250,9 +251,10 @@ export default class Plugin { if (!match) { // widen the search globs([ - // TODO: npm implementation - `${this.cwd.replace(/\\/g, '/')}/src/**/.bower.json`, - `${this.cwd.replace(/\\/g, '/')}/src/**/bower.json` + `${this.cwd.replace(/\\/g, '/')}/src/node_modules/adapt-*/.package.json`, + `${this.cwd.replace(/\\/g, '/')}/src/node_modules/adapt-*/package.json`, + `${this.cwd.replace(/\\/g, '/')}/src/*/adapt-*/.bower.json`, + `${this.cwd.replace(/\\/g, '/')}/src/*/adapt-*/bower.json` ], (err, matches) => { if (err) return resolve(null) const tester = new RegExp(`/${this.packageName}/`, 'i') diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js index 46e0991..6906aa1 100644 --- a/lib/integration/PluginManagement/npm.js +++ b/lib/integration/PluginManagement/npm.js @@ -1,16 +1,15 @@ -import chalk from 'chalk' import { exec } from 'child_process' import path from 'path' -export async function install ({ +export async function execute ({ logger, + command, cwd, args = [] } = {}) { cwd = path.resolve(process.cwd(), cwd) await new Promise((resolve, reject) => { - if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) - exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'install', ...args].join(' '), { + exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', command, ...args].join(' '), { cwd }, (err, stdout, stderr) => { if (!err) return resolve() @@ -19,21 +18,20 @@ export async function install ({ }) } +export async function install ({ + logger, + cwd, + args = [] +} = {}) { + await execute({ logger, command: 'install', cwd, args }) +} + export async function update ({ logger, cwd, args = [] } = {}) { - cwd = path.resolve(process.cwd(), cwd) - await new Promise((resolve, reject) => { - if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) - exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'update', ...args].join(' '), { - cwd - }, (err, stdout, stderr) => { - if (!err) return resolve() - reject(stderr) - }) - }) + await execute({ logger, command: 'update', cwd, args }) } export async function uninstall ({ @@ -41,14 +39,5 @@ export async function uninstall ({ cwd, args = [] } = {}) { - cwd = path.resolve(process.cwd(), cwd) - await new Promise((resolve, reject) => { - if (!args.length) logger?.log(chalk.cyan('installing node dependencies')) - exec([(process.platform === 'win32' ? 'npm.cmd' : 'npm'), '--unsafe-perm', 'uninstall', ...args].join(' '), { - cwd - }, (err, stdout, stderr) => { - if (!err) return resolve() - reject(stderr) - }) - }) + await execute({ logger, command: 'uninstall', cwd, args }) } diff --git a/lib/integration/Project.js b/lib/integration/Project.js index 2486121..be770b5 100644 --- a/lib/integration/Project.js +++ b/lib/integration/Project.js @@ -48,8 +48,8 @@ export default class Project { } } - isNPM() { - return fs.existsSync(path.join(cwd, 'src/package.json')) + isNPM () { + return fs.existsSync(path.join(this.cwd, 'src/package.json')) } tryThrowInvalidPath () { @@ -86,10 +86,12 @@ export default class Project { async getInstalledDependencies () { const getDependencyBowerJSONs = async () => { - // TODO: npm implementation - const glob = `${this.cwd.replace(/\\/g, '/')}/src/**/bower.json` + const globs = [ + this.isNPM && `${this.cwd.replace(/\\/g, '/')}/src/node_modules/adapt-*/package.json`, + !this.isNPM && `${this.cwd.replace(/\\/g, '/')}/src/*/adapt-*/bower.json` + ].filter(Boolean) const bowerJSONPaths = await new Promise((resolve, reject) => { - globs(glob, (err, matches) => { + globs(globs, (err, matches) => { if (err) return reject(err) resolve(matches) }) diff --git a/lib/integration/Target.js b/lib/integration/Target.js index 6871fae..2628e47 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -158,52 +158,51 @@ export default class Target extends Plugin { async install ({ clone = false } = {}) { const logger = this.logger - const pluginTypeFolder = await this.getTypeFolder() - if (this.isLocalSource) { - // TODO: npm implementation - await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) - const pluginPath = path.resolve(this.cwd, 'src', pluginTypeFolder, this.name) - await fs.rm(pluginPath, { recursive: true, force: true }) - await fs.copy(this.sourcePath, pluginPath, { recursive: true }) - const bowerJSON = await fs.readJSON(path.join(pluginPath, 'bower.json')) - bowerJSON._source = this.sourcePath - bowerJSON._wasInstalledFromPath = true - await fs.writeJSON(path.join(pluginPath, '.bower.json'), bowerJSON, { spaces: 2, replacer: null }) - await this.refetchProjectInfo() - return - } - if (clone) { - // clone install - const repoDetails = await this.getRepositoryUrl() - if (!repoDetails) throw new Error('Error: Plugin repository url could not be found.') - await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) - const pluginPath = path.resolve(this.cwd, 'src', pluginTypeFolder, this.name) - await fs.rm(pluginPath, { recursive: true, force: true }) - const url = repoDetails.url.replace(/^git:\/\//, 'https://') - try { - const exitCode = await new Promise((resolve, reject) => { + if (!this.project.isNPM) { + const pluginTypeFolder = await this.getTypeFolder() + if (this.isLocalSource) { + await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) + const pluginPath = path.resolve(this.cwd, 'src', pluginTypeFolder, this.name) + await fs.rm(pluginPath, { recursive: true, force: true }) + await fs.copy(this.sourcePath, pluginPath, { recursive: true }) + const bowerJSON = await fs.readJSON(path.join(pluginPath, 'bower.json')) + bowerJSON._source = this.sourcePath + bowerJSON._wasInstalledFromPath = true + await fs.writeJSON(path.join(pluginPath, '.bower.json'), bowerJSON, { spaces: 2, replacer: null }) + await this.refetchProjectInfo() + return + } + if (clone) { + // clone install + const repoDetails = await this.getRepositoryUrl() + if (!repoDetails) throw new Error('Error: Plugin repository url could not be found.') + await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) + const pluginPath = path.resolve(this.cwd, 'src', pluginTypeFolder, this.name) + await fs.rm(pluginPath, { recursive: true, force: true }) + const url = repoDetails.url.replace(/^git:\/\//, 'https://') + try { + const exitCode = await new Promise((resolve, reject) => { + try { + exec(`git clone ${url} "${pluginPath}"`, resolve) + } catch (err) { + reject(err) + } + }) + if (exitCode) throw new Error(`The plugin was found but failed to download and install. Exit code ${exitCode}`) + } catch (error) { + throw new Error(`The plugin was found but failed to download and install. Error ${error}`) + } + if (this.versionToApply !== '*') { try { - exec(`git clone ${url} "${pluginPath}"`, resolve) + await new Promise(resolve => exec(`git -C "${pluginPath}" checkout v${this.versionToApply}`, resolve)) + logger?.log(chalk.green(this.packageName), `is on branch "${this.versionToApply}".`) } catch (err) { - reject(err) + throw new Error(chalk.yellow(this.packageName), `could not checkout branch "${this.versionToApply}".`) } - }) - if (exitCode) throw new Error(`The plugin was found but failed to download and install. Exit code ${exitCode}`) - } catch (error) { - throw new Error(`The plugin was found but failed to download and install. Error ${error}`) - } - if (this.versionToApply !== '*') { - try { - await new Promise(resolve => exec(`git -C "${pluginPath}" checkout v${this.versionToApply}`, resolve)) - logger?.log(chalk.green(this.packageName), `is on branch "${this.versionToApply}".`) - } catch (err) { - throw new Error(chalk.yellow(this.packageName), `could not checkout branch "${this.versionToApply}".`) } + await this.refetchProjectInfo() + return } - await this.refetchProjectInfo() - return - } - if (!this.project.isNPM) { // bower install const outputPath = path.join(this.cwd, 'src', pluginTypeFolder) const pluginPath = path.join(outputPath, this.name) @@ -249,8 +248,7 @@ export default class Target extends Plugin { const bowerJSON = await fs.readJSON(path.join(pluginPath, 'package.json')) bowerJSON.version = bowerJSON.version ?? this.versionToApply await fs.writeJSON(path.join(pluginPath, '.package.json'), bowerJSON, { spaces: 2, replacer: null }) - this._projectInfo = null - await this.fetchProjectInfo() + await this.refetchProjectInfo() } async update () { From 1d454938ff081fedb84cdab6eaf4020131959cce Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Sat, 4 Mar 2023 08:58:35 +0000 Subject: [PATCH 05/11] Typos --- lib/integration/PluginManagement/uninstall.js | 2 +- lib/integration/PluginManagement/update.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/integration/PluginManagement/uninstall.js b/lib/integration/PluginManagement/uninstall.js index e684d56..7dadf96 100644 --- a/lib/integration/PluginManagement/uninstall.js +++ b/lib/integration/PluginManagement/uninstall.js @@ -32,7 +32,7 @@ export default async function uninstall ({ percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) ) if (project.isNPM) { - // Batch install npm plugins as it's faster + // Batch uninstall npm plugins as it's faster const installArgs = uninstallTargetsToBeUninstalled .filter(target => target.isNPMUninstall) .map(target => `${target.packageName}`) diff --git a/lib/integration/PluginManagement/update.js b/lib/integration/PluginManagement/update.js index 662ecbc..3f2a9f1 100644 --- a/lib/integration/PluginManagement/update.js +++ b/lib/integration/PluginManagement/update.js @@ -39,7 +39,7 @@ export default async function update ({ percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) ) if (project.isNPM) { - // Batch install npm plugins as it's faster + // Batch update npm plugins as it's faster const installArgs = updateTargetsToBeUpdated .filter(target => target.isNPMUpdate) .map(target => `${target.packageName}`) From 5b20a10c56d47cb6a5c98de1dc45b0ea23fe95ef Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 8 Mar 2023 12:17:56 +0000 Subject: [PATCH 06/11] Minimise use of bower library --- lib/cli.js | 2 + lib/integration/Plugin.js | 34 +++++- lib/integration/PluginManagement/install.js | 14 ++- lib/integration/PluginManagement/npm.js | 113 ++++++++++++++++++ lib/integration/PluginManagement/register.js | 55 ++++++--- lib/integration/PluginManagement/rename.js | 17 ++- lib/integration/PluginManagement/uninstall.js | 6 +- .../PluginManagement/unregister.js | 18 ++- lib/integration/PluginManagement/update.js | 6 +- lib/integration/Project.js | 11 +- lib/integration/Target.js | 15 ++- lib/logger.js | 7 +- 12 files changed, 248 insertions(+), 50 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index d232ea1..634bf42 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -12,6 +12,7 @@ import unregister from './commands/unregister.js' import update from './commands/update.js' import version from './commands/version.js' import logger from './logger.js' +import { isNPM } from './integration/PluginManagement/npm.js' import './econnreset.js' const commands = { @@ -53,6 +54,7 @@ class CLI { async execute () { try { + logger.info(`using ${await isNPM() ? 'NPM' : 'BOWER'} registry...`) if (!commands[this.command.name]) { const e = new Error(`Unknown command "${this.command.name}", please check the documentation.`) logger?.log(e.message) diff --git a/lib/integration/Plugin.js b/lib/integration/Plugin.js index 361d630..73d2f0b 100644 --- a/lib/integration/Plugin.js +++ b/lib/integration/Plugin.js @@ -5,6 +5,7 @@ import endpointParser from 'bower-endpoint-parser' import semver from 'semver' import fs from 'fs-extra' import path from 'path' +import { fetchAllInfo, fetchVersionInfo, fetchRepoUrl } from './PluginManagement/npm.js' import getBowerRegistryConfig from './getBowerRegistryConfig.js' import { ADAPT_ALLOW_PRERELEASE, PLUGIN_TYPES, PLUGIN_TYPE_FOLDERS, PLUGIN_DEFAULT_TYPE } from '../util/constants.js' /** @typedef {import("./Project.js").default} Project */ @@ -178,7 +179,7 @@ export default class Plugin { async fetchSourceInfo () { if (this.isLocalSource) return await this.fetchLocalSourceInfo() - await this.fetchBowerInfo() + await this.fetchRegistryInfo() } async fetchLocalSourceInfo () { @@ -205,14 +206,21 @@ export default class Plugin { this.packageName = this.name } - async fetchBowerInfo () { + async fetchRegistryInfo () { if (this._sourceInfo) return this._sourceInfo this._sourceInfo = null if (this.isLocalSource) return + const isNPM = await this.project.isNPM() const perform = async (attemptCount = 0) => { try { + if (isNPM) { + return await fetchAllInfo({ + logger: this.logger, + cwd: this.cwd, + packageName: this.packageName + }) + } return await new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.info(`${this.packageName}`, null, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) @@ -275,11 +283,19 @@ export default class Plugin { } async findCompatibleVersion (framework) { + const isNPM = await this.project.isNPM() const getBowerVersionInfo = async (version) => { const perform = async (attemptCount = 0) => { try { + if (isNPM) { + return await fetchVersionInfo({ + logger: this.logger, + cwd: this.cwd, + packageName: this.packageName, + version + }) + } return await new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.info(`${this.packageName}@${version}`, null, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) @@ -364,8 +380,16 @@ export default class Plugin { async getRepositoryUrl () { if (this._repositoryUrl) return this._repositoryUrl if (this.isLocalSource) return + const isNPM = await this.project.isNPM() + if (isNPM) { + const url = await fetchRepoUrl({ + logger: this.logger, + cwd: this.cwd, + packageName: this.packageName + }) + return (this._repositoryUrl = url) + } const url = await new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.lookup(this.packageName, { cwd: this.cwd, registry: this.BOWER_REGISTRY_CONFIG }) .on('end', resolve) .on('error', reject) diff --git a/lib/integration/PluginManagement/install.js b/lib/integration/PluginManagement/install.js index 2925c0a..f9512a7 100644 --- a/lib/integration/PluginManagement/install.js +++ b/lib/integration/PluginManagement/install.js @@ -21,13 +21,15 @@ export default async function install ({ logger = null }) { cwd = path.resolve(process.cwd(), cwd) - isClean && await new Promise(resolve => { - // TODO: npm implementation - bower.commands.cache.clean().on('end', resolve) - }) const project = new Project({ cwd, logger }) project.tryThrowInvalidPath() + const isNPM = await project.isNPM() + + !isNPM && isClean && await new Promise(resolve => { + bower.commands.cache.clean().on('end', resolve) + }) + logger?.log(chalk.cyan(`${dev ? 'cloning' : 'installing'} adapt dependencies...`)) const targets = await getInstallTargets({ logger, project, plugins, isCompatibleEnabled }) @@ -44,9 +46,9 @@ export default async function install ({ await eachOfSeriesProgress( installTargetsToBeInstalled, target => target.install({ clone: dev }), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Installing plugins ${(percentage / (project.isNPM ? 2 : 1))}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Installing plugins ${(percentage / (isNPM ? 2 : 1))}% complete`) ) - if (project.isNPM) { + if (isNPM) { // Batch install npm plugins as it's faster const installArgs = installTargetsToBeInstalled .filter(target => target.isNPMInstall) diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js index 6906aa1..c894cf7 100644 --- a/lib/integration/PluginManagement/npm.js +++ b/lib/integration/PluginManagement/npm.js @@ -1,5 +1,28 @@ import { exec } from 'child_process' import path from 'path' +import nodeFetch from 'node-fetch' +import getBowerRegistryConfig from '../getBowerRegistryConfig.js' +import semver from 'semver' + +const pluginCache = {} +let isNPMCache = null + +export async function isNPM ({ cwd = process.cwd() }) { + if (isNPMCache !== null) return isNPMCache + const packageName = 'adapt-contrib-core' + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + const pluginUrl = `${url}npm/${packageName}` + const req = await nodeFetch(pluginUrl) + const data = await req.json() + isNPMCache = Boolean(typeof data === 'object' && data.name === packageName) + return isNPMCache + } catch (err) { + } + } + return (isNPMCache = false) +} export async function execute ({ logger, @@ -41,3 +64,93 @@ export async function uninstall ({ } = {}) { await execute({ logger, command: 'uninstall', cwd, args }) } + +export async function fetchAllInfo ({ + logger, + cwd, + packageName +}) { + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + let json + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + let data = pluginCache[packageName] + if (!data) { + const pluginUrl = `${url}npm/${packageName}` + const req = await nodeFetch(pluginUrl) + data = await req.json() + } + const versions = Object.values(data.versions).map(item => item.version) + versions.sort((a, b) => semver.compare(a, b) * -1) + json = { + name: data.name, + versions, + latest: data.versions[data['dist-tags'].latest] + } + } catch (err) { + } + } + return json +} + +export async function fetchVersionInfo ({ + logger, + cwd, + packageName, + version +}) { + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + let data = pluginCache[packageName] + if (!data) { + const pluginUrl = `${url}npm/${packageName}` + const req = await nodeFetch(pluginUrl) + data = await req.json() + } + return data.versions[version] + } catch (err) { + } + } + return [] +} + +export async function fetchRepoUrl ({ + logger, + cwd, + packageName, + version +}) { + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + let data = pluginCache[packageName] + if (!data) { + const pluginUrl = `${url}npm/${packageName}` + const req = await nodeFetch(pluginUrl) + data = await req.json() + } + return data.repository?.url ?? data.repository + } catch (err) { + } + } + return null +} + +export async function searchInfo ({ + logger, + cwd, + term +}) { + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + const pluginUrl = `${url}npm/-/v1/search?text=${term}&size=100` + const req = await nodeFetch(pluginUrl) + const data = await req.json() + return data?.objects ?? [] + } catch (err) { + } + } + return [] +} diff --git a/lib/integration/PluginManagement/register.js b/lib/integration/PluginManagement/register.js index adb0760..62e2c1f 100644 --- a/lib/integration/PluginManagement/register.js +++ b/lib/integration/PluginManagement/register.js @@ -3,12 +3,15 @@ import getBowerRegistryConfig from '../getBowerRegistryConfig.js' import fs from 'fs-extra' import path from 'path' import bower from 'bower' +import fetch from 'node-fetch' import chalk from 'chalk' import inquirer from 'inquirer' +import globs from 'globs' import { readValidateJSON } from '../../util/JSONReadValidate.js' import Plugin from '../Plugin.js' import semver from 'semver' import { ADAPT_ALLOW_PRERELEASE } from '../../util/constants.js' +import { searchInfo, isNPM } from '../PluginManagement/npm.js' const semverOptions = { includePrerelease: ADAPT_ALLOW_PRERELEASE } export default async function register ({ @@ -16,21 +19,26 @@ export default async function register ({ cwd = process.cwd() } = {}) { cwd = path.resolve(process.cwd(), cwd) + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { - // TODO: npm implementation - const bowerJSONPath = path.join(cwd, 'bower.json') - const hasBowerJSON = fs.existsSync(bowerJSONPath) + const pluginJSONPath = await Promise((resolve, reject) => { + globs(['package.json', 'bower.json'], { cwd }, (err, matches) => { + if (err) return reject(err) + resolve(matches?.[0]) + }) + }) + const hasPluginJSON = fs.existsSync(pluginJSONPath) - const bowerJSON = { + const pluginJSON = { name: undefined, repository: undefined, framework: undefined, - ...(hasBowerJSON ? await readValidateJSON(bowerJSONPath) : {}) + ...(hasPluginJSON ? await readValidateJSON(pluginJSONPath) : {}) } - const properties = await confirm(bowerJSON) - hasBowerJSON && await fs.writeJSON(bowerJSONPath, properties, { spaces: 2, replacer: null }) + const properties = await confirm(pluginJSON) + hasPluginJSON && await fs.writeJSON(pluginJSONPath, properties, { spaces: 2, replacer: null }) // given a package name, create two Plugin representations // if supplied name is adapt-contrib-myPackageName do a check against this name only @@ -38,8 +46,8 @@ export default async function register ({ // becase we don't want to allow adapt-myPackageName if adapt-contrib-myPackageName exists const plugin = new Plugin({ name: properties.name, logger }) const contribPlugin = new Plugin({ name: properties.name, isContrib: true, logger }) - const contribExists = await exists(BOWER_REGISTRY_CONFIG, contribPlugin) - const pluginExists = await exists(BOWER_REGISTRY_CONFIG, plugin) + const contribExists = await exists({ cwd, BOWER_REGISTRY_CONFIG, pluginName: contribPlugin }) + const pluginExists = await exists({ cwd, BOWER_REGISTRY_CONFIG, pluginName: plugin }) if (contribExists || pluginExists) { logger?.warn(plugin.toString(), 'has been previously registered. Plugin names must be unique. Try again with a different name.') @@ -106,10 +114,16 @@ async function confirm (properties) { * @param {Plugin} plugin * @returns {boolean} */ -async function exists (BOWER_REGISTRY_CONFIG, plugin) { - const pluginName = plugin.toString().toLowerCase() +async function exists ({ cwd, BOWER_REGISTRY_CONFIG, pluginName }) { + pluginName = pluginName.toString().toLowerCase() + if (await isNPM()) { + return await searchInfo({ + cwd, + registry: BOWER_REGISTRY_CONFIG.register, + term: pluginName + }) + } return new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.search(pluginName, { registry: BOWER_REGISTRY_CONFIG.register }) @@ -121,9 +135,22 @@ async function exists (BOWER_REGISTRY_CONFIG, plugin) { }) } -async function registerWithBowerRepo (BOWER_REGISTRY_CONFIG, plugin, repository) { +async function registerWithBowerRepo ({ cwd, BOWER_REGISTRY_CONFIG, plugin, repository }) { + if (await isNPM()) { + const path = 'packages' + const response = await fetch(BOWER_REGISTRY_CONFIG.register + path, { + method: 'POST', + headers: { 'User-Agent': 'adapt-cli' }, + data: { + name: plugin.toString(), + url: repository + }, + followRedirect: false + }) + if (response.status === 201) return true + throw new Error(`The server responded with ${response.status}`) + } return new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.register(plugin.toString(), repository.url || repository, { registry: BOWER_REGISTRY_CONFIG }) diff --git a/lib/integration/PluginManagement/rename.js b/lib/integration/PluginManagement/rename.js index dcde829..ba725fe 100644 --- a/lib/integration/PluginManagement/rename.js +++ b/lib/integration/PluginManagement/rename.js @@ -6,6 +6,7 @@ import inquirer from 'inquirer' import fetch from 'node-fetch' import path from 'path' import Plugin from '../Plugin.js' +import { searchInfo, isNPM } from './npm.js' export default async function rename ({ logger, @@ -25,9 +26,9 @@ export default async function rename ({ logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) logger?.warn(`Plugin will be renamed from ${oldName} to ${newName}`) try { - const oldExists = await exists(BOWER_REGISTRY_CONFIG, oldName) + const oldExists = await exists({ cwd, BOWER_REGISTRY_CONFIG, pluginName: oldName }) if (!oldExists) throw new Error(`Plugin "${oldName}" does not exist`) - const newExists = await exists(BOWER_REGISTRY_CONFIG, newName) + const newExists = await exists({ cwd, BOWER_REGISTRY_CONFIG, pluginName: newName }) if (newExists) throw new Error(`Name "${newName}" already exists`) const { username, token, type } = await authenticate({ pluginName: oldName }) logger?.log(`${username} authenticated as ${type}`) @@ -80,10 +81,16 @@ async function renameInBowerRepo ({ * @param {Plugin} plugin * @returns {boolean} */ -async function exists (BOWER_REGISTRY_CONFIG, plugin) { - const pluginName = plugin.toString().toLowerCase() +async function exists ({ cwd, BOWER_REGISTRY_CONFIG, pluginName }) { + pluginName = pluginName.toString().toLowerCase() + if (await isNPM()) { + return await searchInfo({ + cwd, + registry: BOWER_REGISTRY_CONFIG.register, + term: pluginName + }) + } return new Promise((resolve, reject) => { - // TODO: npm implementation bower.commands.search(pluginName, { registry: BOWER_REGISTRY_CONFIG.register }) diff --git a/lib/integration/PluginManagement/uninstall.js b/lib/integration/PluginManagement/uninstall.js index 7dadf96..c7d3435 100644 --- a/lib/integration/PluginManagement/uninstall.js +++ b/lib/integration/PluginManagement/uninstall.js @@ -19,6 +19,8 @@ export default async function uninstall ({ const project = new Project({ cwd, logger }) project.tryThrowInvalidPath() + const isNPM = await project.isNPM() + logger?.log(chalk.cyan('uninstalling adapt dependencies...')) const targets = await getUninstallTargets({ logger, project, plugins, isInteractive }) @@ -29,9 +31,9 @@ export default async function uninstall ({ await eachOfLimitProgress( uninstallTargetsToBeUninstalled, target => target.uninstall(), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Uninstalling plugins ${percentage / (isNPM ? 2 : 1)}% complete`) ) - if (project.isNPM) { + if (isNPM) { // Batch uninstall npm plugins as it's faster const installArgs = uninstallTargetsToBeUninstalled .filter(target => target.isNPMUninstall) diff --git a/lib/integration/PluginManagement/unregister.js b/lib/integration/PluginManagement/unregister.js index 1848157..47c7f1d 100644 --- a/lib/integration/PluginManagement/unregister.js +++ b/lib/integration/PluginManagement/unregister.js @@ -7,6 +7,7 @@ import inquirer from 'inquirer' import { readValidateJSON } from '../../util/JSONReadValidate.js' import Plugin from '../Plugin.js' import fetch from 'node-fetch' +import globs from 'globs' export default async function unregister ({ logger, @@ -17,12 +18,17 @@ export default async function unregister ({ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { - // TODO: npm implementation - const bowerJSONPath = path.join(cwd, 'bower.json') - const hasBowerJSON = fs.existsSync(bowerJSONPath) - const bowerJSON = hasBowerJSON ? await readValidateJSON(bowerJSONPath) : {} - if (pluginName) bowerJSON.name = pluginName - const props = await confirm(bowerJSON) + const pluginJSONPath = await Promise((resolve, reject) => { + globs(['package.json', 'bower.json'], { cwd }, (err, matches) => { + if (err) return reject(err) + resolve(matches?.[0]) + }) + }) + + const hasPluginJSON = fs.existsSync(pluginJSONPath) + const pluginJSON = hasPluginJSON ? await readValidateJSON(pluginJSONPath) : {} + if (pluginName) pluginJSON.name = pluginName + const props = await confirm(pluginJSON) pluginName = props.pluginName const repository = props.repository const { username, token, type } = await authenticate({ repository, pluginName }) diff --git a/lib/integration/PluginManagement/update.js b/lib/integration/PluginManagement/update.js index 3f2a9f1..332054e 100644 --- a/lib/integration/PluginManagement/update.js +++ b/lib/integration/PluginManagement/update.js @@ -20,6 +20,8 @@ export default async function update ({ const project = new Project({ cwd, logger }) project.tryThrowInvalidPath() + const isNPM = await project.isNPM() + logger?.log(chalk.cyan('update adapt dependencies...')) const targets = await getUpdateTargets({ logger, project, plugins, isDryRun, isInteractive }) @@ -36,9 +38,9 @@ export default async function update ({ await eachOfSeriesProgress( updateTargetsToBeUpdated, target => target.update(), - percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${percentage / (project.isNPM ? 2 : 1)}% complete`) + percentage => logger?.logProgress?.(`${chalk.bold.cyan('')} Updating plugins ${percentage / (isNPM ? 2 : 1)}% complete`) ) - if (project.isNPM) { + if (isNPM) { // Batch update npm plugins as it's faster const installArgs = updateTargetsToBeUpdated .filter(target => target.isNPMUpdate) diff --git a/lib/integration/Project.js b/lib/integration/Project.js index be770b5..68c1355 100644 --- a/lib/integration/Project.js +++ b/lib/integration/Project.js @@ -4,6 +4,7 @@ import globs from 'globs' import { readValidateJSON, readValidateJSONSync } from '../util/JSONReadValidate.js' import Plugin from './Plugin.js' import Target from './Target.js' +import { isNPM } from './PluginManagement/npm.js' export const MANIFEST_FILENAME = 'adapt.json' export const FRAMEWORK_FILENAME = 'package.json' @@ -48,8 +49,14 @@ export default class Project { } } - isNPM () { - return fs.existsSync(path.join(this.cwd, 'src/package.json')) + async isNPM () { + if (this._isNPM !== undefined) return this._isNPM + const isProjectNPM = fs.existsSync(path.join(this.cwd, 'src/package.json')) + const isServerNPM = await isNPM() + if (isProjectNPM && !isServerNPM) { + throw new Error('Project is NPM, registry server is BOWER') + } + return (this._isNPM = isProjectNPM) } tryThrowInvalidPath () { diff --git a/lib/integration/Target.js b/lib/integration/Target.js index 2628e47..d4e1696 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -158,7 +158,8 @@ export default class Target extends Plugin { async install ({ clone = false } = {}) { const logger = this.logger - if (!this.project.isNPM) { + const isNPM = await this.project.isNPM() + if (!isNPM) { const pluginTypeFolder = await this.getTypeFolder() if (this.isLocalSource) { await fs.ensureDir(path.resolve(this.cwd, 'src', pluginTypeFolder)) @@ -213,7 +214,6 @@ export default class Target extends Plugin { } await new Promise((resolve, reject) => { const pluginNameVersion = `${this.packageName}@${this.versionToApply}` - // TODO: npm implementation bower.commands.install([pluginNameVersion], null, { directory: outputPath, cwd: this.cwd, @@ -229,11 +229,13 @@ export default class Target extends Plugin { await this.postInstall() return } + // todo: clone / dev install for npm this.isNPMInstall = true } async postInstall () { - if (!this.project.isNPM) { + const isNPM = await this.project.isNPM() + if (!isNPM) { const pluginTypeFolder = await this.getTypeFolder() const outputPath = path.join(this.cwd, 'src', pluginTypeFolder) const pluginPath = path.join(outputPath, this.name) @@ -253,7 +255,8 @@ export default class Target extends Plugin { async update () { if (!this.isToBeUpdated) throw new Error() - if (!this.project.isNPM) { + const isNPM = await this.project.isNPM() + if (!isNPM) { // bower update const typeFolder = await this.getTypeFolder() const outputPath = path.join(this.cwd, 'src', typeFolder) @@ -265,7 +268,6 @@ export default class Target extends Plugin { } await new Promise((resolve, reject) => { const pluginNameVersion = `${this.packageName}@${this.matchedVersion}` - // TODO: npm implementation bower.commands.install([pluginNameVersion], null, { directory: outputPath, cwd: this.cwd, @@ -290,7 +292,8 @@ export default class Target extends Plugin { } async uninstall () { - if (!this.project.isNPM) { + const isNPM = await this.project.isNPM() + if (!isNPM) { // bower uninstall try { if (!this.isToBeUninstalled) throw new Error() diff --git a/lib/logger.js b/lib/logger.js index ace74ca..1637eb2 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -9,10 +9,13 @@ export default { this.write(args.join(' ')) }, warn (...args) { - chalk.yellow(...args) + console.log(chalk.yellow(...args)) }, error (...args) { - chalk.red(...args) + console.log(chalk.red(...args)) + }, + info (...args) { + console.log(chalk.bold.cyan(...args)) }, log (...args) { if (this.isLoggingProgress) { From 496a132cbbebea8842627113110b8fa4e699fb3d Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 8 Mar 2023 21:32:26 +0000 Subject: [PATCH 07/11] Allow install from local folder --- lib/integration/Plugin.js | 6 +++++- lib/integration/PluginManagement/install.js | 7 ++++++- lib/integration/PluginManagement/npm.js | 2 +- lib/logger.js | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/integration/Plugin.js b/lib/integration/Plugin.js index 73d2f0b..8be1a48 100644 --- a/lib/integration/Plugin.js +++ b/lib/integration/Plugin.js @@ -58,7 +58,7 @@ export default class Plugin { const isLocalPath = (isNameAPath || isVersionAPath) if (isLocalPath) { // wait to name the plugin until the local config file is loaded - this.sourcePath = isNameAPath ? this.name : this.requestedVersion + this.sourcePath = path.resolve(this.cwd, isNameAPath ? this.name : this.requestedVersion) this.name = isVersionAPath ? this.packageName : '' this.packageName = isNameAPath ? '' : this.packageName this.requestedVersion = '*' @@ -198,6 +198,10 @@ export default class Plugin { if (!fs.existsSync(bowerJSONPath)) return null return fs.readJSONSync(bowerJSONPath) }, null) + const hasPackageJSON = fs.existsSync(paths[0]) + if (this.project.isNPM && !hasPackageJSON) { + fs.copySync(paths[1], paths[0]) + } resolve(bowerJSON) }) if (!this._sourceInfo) return diff --git a/lib/integration/PluginManagement/install.js b/lib/integration/PluginManagement/install.js index f9512a7..de21ab2 100644 --- a/lib/integration/PluginManagement/install.js +++ b/lib/integration/PluginManagement/install.js @@ -52,7 +52,12 @@ export default async function install ({ // Batch install npm plugins as it's faster const installArgs = installTargetsToBeInstalled .filter(target => target.isNPMInstall) - .map(target => `${target.packageName}@${target.versionToApply}`) + .map(target => { + if (target.isLocalSource) { + return `${target.sourcePath}` + } + return `${target.packageName}@${target.versionToApply}` + }) const outputPath = path.join(cwd, 'src') await npmInstall({ logger, cwd: outputPath, args: installArgs }) await eachOfSeriesProgress( diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js index c894cf7..db09991 100644 --- a/lib/integration/PluginManagement/npm.js +++ b/lib/integration/PluginManagement/npm.js @@ -7,7 +7,7 @@ import semver from 'semver' const pluginCache = {} let isNPMCache = null -export async function isNPM ({ cwd = process.cwd() }) { +export async function isNPM ({ cwd = process.cwd() } = {}) { if (isNPMCache !== null) return isNPMCache const packageName = 'adapt-contrib-core' const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) diff --git a/lib/logger.js b/lib/logger.js index 1637eb2..150503d 100644 --- a/lib/logger.js +++ b/lib/logger.js @@ -15,7 +15,7 @@ export default { console.log(chalk.red(...args)) }, info (...args) { - console.log(chalk.bold.cyan(...args)) + console.log(chalk.cyan(...args)) }, log (...args) { if (this.isLoggingProgress) { From d5495d81fd75f1a918e52c19f96bff48b2c54166 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 8 Mar 2023 21:42:35 +0000 Subject: [PATCH 08/11] Allow devinstall + npm --- lib/integration/PluginManagement/npm.js | 4 ++-- lib/integration/Target.js | 30 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js index db09991..f03f5b2 100644 --- a/lib/integration/PluginManagement/npm.js +++ b/lib/integration/PluginManagement/npm.js @@ -46,7 +46,7 @@ export async function install ({ cwd, args = [] } = {}) { - await execute({ logger, command: 'install', cwd, args }) + await execute({ logger, command: 'install', cwd, args: ['--omit=dev'].concat(args) }) } export async function update ({ @@ -130,7 +130,7 @@ export async function fetchRepoUrl ({ const req = await nodeFetch(pluginUrl) data = await req.json() } - return data.repository?.url ?? data.repository + return data.repository } catch (err) { } } diff --git a/lib/integration/Target.js b/lib/integration/Target.js index d4e1696..e039094 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -230,6 +230,36 @@ export default class Target extends Plugin { return } // todo: clone / dev install for npm + if (isNPM && clone) { + const repoDetails = await this.getRepositoryUrl() + if (!repoDetails) throw new Error('Error: Plugin repository url could not be found.') + await fs.ensureDir(path.resolve(this.cwd, 'src/dev')) + const pluginPath = path.resolve(this.cwd, 'src/dev', this.name) + await fs.rm(pluginPath, { recursive: true, force: true }) + const url = repoDetails.url.replace(/^git:\/\//, 'https://') + try { + const exitCode = await new Promise((resolve, reject) => { + try { + exec(`git clone ${url} "${pluginPath}"`, resolve) + } catch (err) { + reject(err) + } + }) + if (exitCode) throw new Error(`The plugin was found but failed to download and install. Exit code ${exitCode}`) + } catch (error) { + throw new Error(`The plugin was found but failed to download and install. Error ${error}`) + } + if (this.versionToApply !== '*') { + try { + await new Promise(resolve => exec(`git -C "${pluginPath}" checkout v${this.versionToApply}`, resolve)) + logger?.log(chalk.green(this.packageName), `is on branch "${this.versionToApply}".`) + } catch (err) { + throw new Error(chalk.yellow(this.packageName), `could not checkout branch "${this.versionToApply}".`) + } + } + await this.refetchProjectInfo() + this.sourcePath = pluginPath + } this.isNPMInstall = true } From 1297e4289d68d9322d265cf7b032714cd2cdd441 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Wed, 8 Mar 2023 21:47:52 +0000 Subject: [PATCH 09/11] src/custom folder --- lib/integration/Target.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/integration/Target.js b/lib/integration/Target.js index e039094..4e1960b 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -229,12 +229,12 @@ export default class Target extends Plugin { await this.postInstall() return } - // todo: clone / dev install for npm if (isNPM && clone) { + // npm devinstall const repoDetails = await this.getRepositoryUrl() if (!repoDetails) throw new Error('Error: Plugin repository url could not be found.') - await fs.ensureDir(path.resolve(this.cwd, 'src/dev')) - const pluginPath = path.resolve(this.cwd, 'src/dev', this.name) + await fs.ensureDir(path.resolve(this.cwd, 'src/custom')) + const pluginPath = path.resolve(this.cwd, 'src/custom', this.name) await fs.rm(pluginPath, { recursive: true, force: true }) const url = repoDetails.url.replace(/^git:\/\//, 'https://') try { From 760edaef0fd885105d934ede6fc9d31500782c0d Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Tue, 14 Mar 2023 08:50:03 +0000 Subject: [PATCH 10/11] Fixes to update command --- lib/integration/Plugin.js | 1 + lib/integration/PluginManagement/npm.js | 10 ++++++++++ lib/integration/Project.js | 4 ++-- lib/integration/Target.js | 4 ++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/integration/Plugin.js b/lib/integration/Plugin.js index 8be1a48..15fd554 100644 --- a/lib/integration/Plugin.js +++ b/lib/integration/Plugin.js @@ -187,6 +187,7 @@ export default class Plugin { this._sourceInfo = null if (!this.isLocalSource) throw new Error('Plugin name or version must be a path to the source') if (this.isLocalSourceZip) throw new Error('Cannot install from zip files') + // TODO: sourcePath for adapt devinstall modules this._sourceInfo = await new Promise((resolve, reject) => { // get package.json or bower.json data const paths = [ diff --git a/lib/integration/PluginManagement/npm.js b/lib/integration/PluginManagement/npm.js index f03f5b2..de06ff4 100644 --- a/lib/integration/PluginManagement/npm.js +++ b/lib/integration/PluginManagement/npm.js @@ -7,6 +7,15 @@ import semver from 'semver' const pluginCache = {} let isNPMCache = null +export function correctVersionNumbers (versionObjectHash) { + versionObjectHash = { ...versionObjectHash } + for (const version in versionObjectHash) { + if (semver.valid(version)) continue + delete versionObjectHash[version] + } + return versionObjectHash +} + export async function isNPM ({ cwd = process.cwd() } = {}) { if (isNPMCache !== null) return isNPMCache const packageName = 'adapt-contrib-core' @@ -80,6 +89,7 @@ export async function fetchAllInfo ({ const req = await nodeFetch(pluginUrl) data = await req.json() } + data.versions = correctVersionNumbers(data.versions) const versions = Object.values(data.versions).map(item => item.version) versions.sort((a, b) => semver.compare(a, b) * -1) json = { diff --git a/lib/integration/Project.js b/lib/integration/Project.js index 68c1355..cd111fe 100644 --- a/lib/integration/Project.js +++ b/lib/integration/Project.js @@ -93,12 +93,12 @@ export default class Project { async getInstalledDependencies () { const getDependencyBowerJSONs = async () => { - const globs = [ + const paths = [ this.isNPM && `${this.cwd.replace(/\\/g, '/')}/src/node_modules/adapt-*/package.json`, !this.isNPM && `${this.cwd.replace(/\\/g, '/')}/src/*/adapt-*/bower.json` ].filter(Boolean) const bowerJSONPaths = await new Promise((resolve, reject) => { - globs(globs, (err, matches) => { + globs(paths, (err, matches) => { if (err) return reject(err) resolve(matches) }) diff --git a/lib/integration/Target.js b/lib/integration/Target.js index 4e1960b..f542bff 100644 --- a/lib/integration/Target.js +++ b/lib/integration/Target.js @@ -279,6 +279,10 @@ export default class Target extends Plugin { const pluginPath = path.join(outputPath, 'node_modules', this.name) const bowerJSON = await fs.readJSON(path.join(pluginPath, 'package.json')) bowerJSON.version = bowerJSON.version ?? this.versionToApply + if (this.isLocalSource) { + bowerJSON._source = this.sourcePath + bowerJSON._wasInstalledFromPath = true + } await fs.writeJSON(path.join(pluginPath, '.package.json'), bowerJSON, { spaces: 2, replacer: null }) await this.refetchProjectInfo() } From 39ef92a6c6d6616bdc99ee7c8598e1cac61e7581 Mon Sep 17 00:00:00 2001 From: Oliver Foster Date: Tue, 14 Mar 2023 14:55:10 +0000 Subject: [PATCH 11/11] Fixes register, rename and unregister --- lib/integration/PluginManagement/bower.js | 20 +++++++++++++++ lib/integration/PluginManagement/register.js | 21 +++++++++------- lib/integration/PluginManagement/rename.js | 25 ++++++------------- .../PluginManagement/unregister.js | 6 +++-- 4 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 lib/integration/PluginManagement/bower.js diff --git a/lib/integration/PluginManagement/bower.js b/lib/integration/PluginManagement/bower.js new file mode 100644 index 0000000..6037e45 --- /dev/null +++ b/lib/integration/PluginManagement/bower.js @@ -0,0 +1,20 @@ +import nodeFetch from 'node-fetch' +import getBowerRegistryConfig from '../getBowerRegistryConfig.js' + +export async function searchInfo ({ + logger, + cwd, + term +}) { + const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) + for (const url of BOWER_REGISTRY_CONFIG.search) { + try { + const pluginUrl = `${url}packages/search/${term}` + const req = await nodeFetch(pluginUrl) + const data = await req.json() + return data ?? [] + } catch (err) { + } + } + return [] +} diff --git a/lib/integration/PluginManagement/register.js b/lib/integration/PluginManagement/register.js index 62e2c1f..1a5daa0 100644 --- a/lib/integration/PluginManagement/register.js +++ b/lib/integration/PluginManagement/register.js @@ -23,7 +23,7 @@ export default async function register ({ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { - const pluginJSONPath = await Promise((resolve, reject) => { + const pluginJSONPath = await new Promise((resolve, reject) => { globs(['package.json', 'bower.json'], { cwd }, (err, matches) => { if (err) return reject(err) resolve(matches?.[0]) @@ -54,7 +54,7 @@ export default async function register ({ return } - const result = await registerWithBowerRepo(BOWER_REGISTRY_CONFIG, plugin, properties.repository) + const result = await registerWithBowerRepo({ BOWER_REGISTRY_CONFIG, plugin, repository: properties.repository }) if (!result) throw new Error('The plugin was unable to register.') logger?.log(chalk.green(plugin.packageName), 'has been registered successfully.') } catch (err) { @@ -117,11 +117,11 @@ async function confirm (properties) { async function exists ({ cwd, BOWER_REGISTRY_CONFIG, pluginName }) { pluginName = pluginName.toString().toLowerCase() if (await isNPM()) { - return await searchInfo({ + return Boolean(await searchInfo({ cwd, registry: BOWER_REGISTRY_CONFIG.register, term: pluginName - }) + }).length) } return new Promise((resolve, reject) => { bower.commands.search(pluginName, { @@ -135,16 +135,19 @@ async function exists ({ cwd, BOWER_REGISTRY_CONFIG, pluginName }) { }) } -async function registerWithBowerRepo ({ cwd, BOWER_REGISTRY_CONFIG, plugin, repository }) { +async function registerWithBowerRepo ({ BOWER_REGISTRY_CONFIG, plugin, repository }) { if (await isNPM()) { const path = 'packages' const response = await fetch(BOWER_REGISTRY_CONFIG.register + path, { method: 'POST', - headers: { 'User-Agent': 'adapt-cli' }, - data: { - name: plugin.toString(), - url: repository + headers: { + 'User-Agent': 'adapt-cli', + 'Content-Type': 'application/json' }, + body: JSON.stringify({ + name: plugin.toString(), + url: repository.url + }), followRedirect: false }) if (response.status === 201) return true diff --git a/lib/integration/PluginManagement/rename.js b/lib/integration/PluginManagement/rename.js index ba725fe..9c216d5 100644 --- a/lib/integration/PluginManagement/rename.js +++ b/lib/integration/PluginManagement/rename.js @@ -1,12 +1,11 @@ import getBowerRegistryConfig from '../getBowerRegistryConfig.js' import authenticate from './autenticate.js' -import bower from 'bower' import chalk from 'chalk' import inquirer from 'inquirer' import fetch from 'node-fetch' import path from 'path' import Plugin from '../Plugin.js' -import { searchInfo, isNPM } from './npm.js' +import { searchInfo } from './bower.js' export default async function rename ({ logger, @@ -83,21 +82,11 @@ async function renameInBowerRepo ({ */ async function exists ({ cwd, BOWER_REGISTRY_CONFIG, pluginName }) { pluginName = pluginName.toString().toLowerCase() - if (await isNPM()) { - return await searchInfo({ - cwd, - registry: BOWER_REGISTRY_CONFIG.register, - term: pluginName - }) - } - return new Promise((resolve, reject) => { - bower.commands.search(pluginName, { - registry: BOWER_REGISTRY_CONFIG.register - }) - .on('end', result => { - const matches = result.filter(({ name }) => name.toLowerCase() === pluginName) - resolve(Boolean(matches.length)) - }) - .on('error', reject) + const matches = await searchInfo({ + cwd, + registry: BOWER_REGISTRY_CONFIG.register, + term: pluginName }) + console.log(matches) + return Boolean(matches.length) } diff --git a/lib/integration/PluginManagement/unregister.js b/lib/integration/PluginManagement/unregister.js index 47c7f1d..00234b0 100644 --- a/lib/integration/PluginManagement/unregister.js +++ b/lib/integration/PluginManagement/unregister.js @@ -18,7 +18,7 @@ export default async function unregister ({ const BOWER_REGISTRY_CONFIG = getBowerRegistryConfig({ cwd }) logger?.warn('Using registry at', BOWER_REGISTRY_CONFIG.register) try { - const pluginJSONPath = await Promise((resolve, reject) => { + const pluginJSONPath = await new Promise((resolve, reject) => { globs(['package.json', 'bower.json'], { cwd }, (err, matches) => { if (err) return reject(err) resolve(matches?.[0]) @@ -91,7 +91,9 @@ async function unregisterInBowerRepo ({ const uri = `${BOWER_REGISTRY_CONFIG.register}packages/${username}/${pluginName}?access_token=${token}` const response = await fetch(uri, { method: 'DELETE', - headers: { 'User-Agent': 'adapt-cli' }, + headers: { + 'User-Agent': 'adapt-cli' + }, followRedirect: false }) if (response.status !== 204) throw new Error(`The server responded with ${response.status}`)