@sap/cds-dk
Version:
Command line client and development toolkit for the SAP Cloud Application Programming Model
161 lines (133 loc) • 5.55 kB
JavaScript
const { join, resolve } = require ('path')
const { execSync, spawnSync } = require('child_process')
module.exports = Object.assign(list_versions, {
flags: [ '--info', '--markdown', '--all', '--npm-list', '--npm-tree', '--no-colors'],
shortcuts: [ '-i', '-m','-a', '-ls', '-ll' ],
info,
help: `
# SYNOPSIS
*cds version* <options>
*cds -v* <option>
Prints the versions of all @sap/cds packages in your package dependencies.
# OPTIONS
*-i | --info*
Prints version information in a tabular markdown format, which you
can embed into your bug reports.
*-a | --all*
Also lists sub-packages and optional dependencies.
*-ls | --npm-list* <pattern>
*-ll | --npm-tree* <pattern>
Prints an npm ls tree filtered to the specified pattern.
(default: '@sap/cds')
`})
const MISSING = '-- missing --'
function list_versions(args, options) {
const {colors} = require('../lib/util/term')
if (options['npm-list'] || options['npm-tree']) {
let [pattern] = args, re = pattern ? RegExp(pattern) : /@sap\/cd[rs]|@sap\/eslint-plugin-cds/
let cmd = 'npm ls --depth ' + (options['npm-tree'] ? 11 : 0)
console.log (cmd,'| grep', re.source)
return require('child_process').exec(cmd, (e,stdout)=>{
// if (e) console.error(e)
const replacement = (!colors ? '$1 $2$3$4' : '\x1b[91m$1 \x1b[32m$2\x1b[0m\x1b[2m$3\x1b[32m$4\x1b[0m');
for (let line of stdout.split(/\n/)) if (line.match(re)) console.log(
line.replace(/(@sap[^@]*)@([\S]+)( -> [\S]+)?(deduped)?/,replacement)
)
})
}
const versions = info (options)
process.stdout.isTTY && console.log()
if (options.markdown || options.info) {
_markdown (versions)
} else {
const mark = !colors ? s => s : require('../lib/util/term').info
for (let each of Object.keys(versions)) console.log(`${mark(each)}: ${versions[each]}`)
}
process.stdout.isTTY && console.log()
}
function info({ root:cwd=process.cwd() }) {
const cds = require('../lib')
const env = cds.env.for('cds', cwd)
env.cli ??= {}; env.cli.version ??= {}
const javaInfo = !env.cli.version.skipjava && env['project-nature'] === 'java'
if (javaInfo && process.stderr.isTTY) {
console.error('\x1b[2m'+'This takes a while. Collecting Java versions...', '\x1b[0m')
}
const npmRoot = execSync('npm root -g').toString().trim()
let versions = {
..._versions_from(_pkg_path('@sap/cds-dk', npmRoot), '@sap/cds-dk (global)'), // linked in cap/dev or installed globally
..._versions_from(_pkg_path('@sap/cds-dk', cwd)), // local dk, important for Java projects
..._versions_from(_pkg_path('@sap/cds', __dirname)), // @sap/cds from here
..._versions_from(_pkg_path('@sap/cds', cds.home)), // ... or local @sap/cds
..._versions_from(_pkg_path('@cap-js/db-service', cwd)), // only required transitively
..._versions_from(cwd), // ... more from local app dependencies
'@sap/cds-compiler': cds.compiler.version(),
'Node.js': process.version,
'home': cds.home, // effective cds home
}
// sort Node entries
versions = Object.keys(versions).sort().reduce((all, key) => { all[key] = versions[key]; return all }, {})
if (javaInfo) {
Object.assign(versions, capJavaVersion(cwd))
}
return versions
}
function _versions_from(pkg_path, pkg_label) {
let pkg; try { pkg = require(join(pkg_path, 'package.json')) } catch { return {} }
let versions = {}
if (pkg.name) versions[pkg_label || pkg.name] = pkg.version
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
for (let dep in deps) {
if (!dep.match(/@sap\/.*cds.*/) && !dep.startsWith('@cap-js/')) continue
try {
const dep_path = require.resolve(join(dep, 'package.json'), {paths:[pkg_path]})
const dep_pkg = require(dep_path)
versions[dep_pkg.name] = dep_pkg.version
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') console.error(e)
}
}
return versions
}
function _markdown (versions) {
const pkg = { name:'', repository:'', version:'' }; try {
Object.assign (pkg, require (resolve('package.json')))
} catch (e) {/* ignored */}
const repo = pkg.repository.url || pkg.repository || 'https://github.com/<your/repo>'
const valLength = Math.max(repo.length, versions.home.length)
console.log ('|', $(pkg.name, repo), '|')
console.log ('|', $('----------------------', '-'.repeat(valLength)), '|')
Object.keys(versions)
.filter(mod => mod != pkg.name)
.sort()
.forEach(id => console.log ('|', $(id, versions[id]), '|'))
function $ (key, val=MISSING) {
return ( key + ' '.repeat(22)).slice(0,22)
+' | '+ (val + ' '.repeat(valLength)).slice(0,valLength)
}
}
function _pkg_path(id, ...paths) {
try {
const pk_path = require.resolve(join(id, 'package.json'), { paths })
return resolve(pk_path, '..')
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND') throw e
}
}
function capJavaVersion(cwd) {
const cmd = 'mvn com.sap.cds:cds-maven-plugin:version -B -Dcds.version.excludeCds -Dcds.version.json'
let out = ''
try {
out = spawnSync(cmd, {cwd, shell: true}).stdout.toString().trim()
} catch (e) { /* ignored */ }
const match = out.match(/===\n(.*)\n===/ms)
if (match?.[1]) {
const res = {}
Object.entries(JSON.parse(match[1])).forEach(([k,v]) => {
const entries = Object.entries(v)
res[k] = entries.map(([k,v]) => (k === 'version' || k === 'name') ? v : `${k}: ${v}`).join(', ')
})
return res
}
return { 'CAP Java SDK': MISSING }
}