UNPKG

@gobstones/gobstones-scripts

Version:

Scripts to abstract away build configuration of Gobstones Project's libraries and modules.

204 lines (168 loc) 8.25 kB
/* * ***************************************************************************** * Copyright (C) National University of Quilmes 2018-2024 * Gobstones (TM) is a trademark of the National University of Quilmes. * * This program is free software distributed under the terms of the * GNU Affero General Public License version 3. * Additional terms added in compliance to section 7 of such license apply. * * You may read the full license at https://gobstones.github.io/gobstones-guidelines/LICENSE. * ***************************************************************************** */ /** * ---------------------------------------------------- * @module Helpers * @author Alan Rodas Bonjour <alanrodas@gmail.com> * * @internal * ---------------------------------------------------- */ import fs from 'fs'; import path from 'path'; import { isWindows } from './isWindows'; import { logger } from './Logger'; import { PackageJsonReader } from './PackageJsonReader'; import { ExecutableScriptDefinition, PackageManagerDefinition } from '../Config/config'; /** * Get the path to one of the bin scripts exported by a package. * If the bin name is different from the package name, it should * be given, if not given, the name of the binary is assumed to be the same * of that of the package. * * @param projectRootPath - The currently identified project's root path. * @param packageManagerDefinition - The definition to all available package managers. * @param packageName - The name of the package holding the binary. * @param binName - The name of the binary that it's intended to be retrieved. * * @returns The information for the binary execution, or undefined if no binary was found. */ export const getBin = ( projectRootPath: string, packageManagerDefinition: PackageManagerDefinition, packageName: string, binName?: string ): ExecutableScriptDefinition | undefined => { if (!binName) { binName = packageName; } // Hold the result of the file found for caching it at the end. let result: Partial<ExecutableScriptDefinition> = {}; logger.debug(`[getBin]: Attempting to find binary file "${binName}" for the package "${packageName}"`, 'magenta'); try { logger.debug(`[getBin]: Trying to retrieve the package.json information through require.resolve`, 'magenta'); // Attempt to get the bin by resolving the package.json const packageJsonPath = require.resolve(`${packageName}/package.json`); const packageRootDir = path.dirname(packageJsonPath); const binFile = getBinFile(packageJsonPath, packageRootDir, binName); result = { scriptFile: binFile, command: `node --experimental-vm-modules ${binFile}`, mode: 'node' }; } catch { logger.debug(`[getBin]: Could not detect through require.resolve`, 'magenta'); logger.debug(`[getBin]: Attempting to find binary in binary folders of current package manager`, 'magenta'); for (const modulesFolder of packageManagerDefinition.modulesFolders) { logger.debug(`[getBin]: Verifying at: ${modulesFolder}`); const packageNamePath = path.join(projectRootPath, modulesFolder, packageName, 'package.json'); if (fs.existsSync(packageNamePath)) { logger.debug(`[getBin]: Found a package.json file at: ${packageNamePath}`, 'magenta'); const packageRootDir = path.dirname(packageNamePath); const binFile = getBinFile(packageNamePath, packageRootDir, binName); result = { scriptFile: binFile, command: `node --experimental-vm-modules ${binFile}`, mode: 'node' }; break; } else { logger.debug(`[getBin]: No package with name found. Attempting to find native binary.`, 'magenta'); const binFile = path.join(projectRootPath, modulesFolder, '.bin', binName || packageName); if (fs.existsSync(binFile)) { // We found a possible binary, but in some cases // this are actually node files that were not reported. // We need to check the heading to see that. const contents = fs.readFileSync(binFile).toString(); const heading = contents.length > 0 ? contents.split('\n')[0] : ''; if (heading.includes('node')) { // If the heading mentions node, it's a javascript file. logger.debug(`[getBin]: Found a javascript executable at: ${binFile}`, 'magenta'); result = { scriptFile: binFile, command: `node --experimental-vm-modules ${binFile}`, mode: 'node' }; break; } // If not, it's a binary file, but there may be // many depending on the OS. Verify to see if we have // a powershell, command, or sh. if (isWindows()) { if (fs.existsSync(`${binFile}.ps1`)) { logger.debug(`[getBin]: Found a powershell executable at: ${binFile}.ps1`, 'magenta'); result = { scriptFile: `${binFile}.ps1`, command: `powershell ${binFile}.ps1`, mode: 'pwsh' }; break; } if (fs.existsSync(`${binFile}.cmd`)) { logger.debug( `[getBin]: Found a windows command line executable at: ${binFile}.cmd`, 'magenta' ); result = { scriptFile: `${binFile}.cmd`, command: `${binFile}.cmd`, mode: 'cmd' }; break; } } // Default to shell script logger.debug(`[getBin]: Found a shell script at: ${binFile}`, 'magenta'); result = { scriptFile: binFile, command: `sh ${binFile}`, mode: 'sh' }; break; } } } } if (Object.keys(result).length === 0) { logger.debug(`[getBin]: Could not find a binary file`, 'magenta'); return undefined; } return Object.assign(result, { packageName, binName }) as ExecutableScriptDefinition; }; /** * Returns the bin file for a given package and binary file. * * @param packageJsonPath - The path of the requested package's package.json * @param packageRootDir - The path to root of the package that contains the binary directory * @param binName - The name of the binary that we want the path of. * * @returns The path to the binary file. * * @internal */ const getBinFile = (packageJsonPath: string, packageRootDir: string, binName: string): string => { logger.debug(`[getBin] Attempting to find the binary file: ${binName} using root: ${packageJsonPath}`, 'magenta'); const pkgJsonReader = new PackageJsonReader(packageJsonPath); let pkgBinDefinition = pkgJsonReader.getValueAt('bin') as string | Record<string, string>; const binRelativeToPackgeInJson: string = pkgBinDefinition && typeof pkgBinDefinition === 'object' ? (pkgBinDefinition = pkgBinDefinition[binName]) : pkgBinDefinition; logger.debug(`[getBin] Found a package.json with bin file declared as: ${binRelativeToPackgeInJson}`, 'magenta'); const fullBinPath = path.join(packageRootDir, binRelativeToPackgeInJson); logger.debug(`[getBin] Path for binary found as: ${fullBinPath}`, 'magenta'); return fullBinPath; };