Skip to content

Commit

Permalink
Merge pull request #28 from axelpale/release-3.2
Browse files Browse the repository at this point in the history
Release candidate 3.2.0
  • Loading branch information
axelpale authored Jan 8, 2024
2 parents 751d9d0 + 912d216 commit de0dd6a
Show file tree
Hide file tree
Showing 29 changed files with 1,242 additions and 436 deletions.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2021 Akseli Palén
Copyright (c) 2024 Akseli Palén

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
206 changes: 158 additions & 48 deletions README.md

Large diffs are not rendered by default.

98 changes: 75 additions & 23 deletions bin/genversion.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,79 @@
#!/usr/bin/env node

const gv = require('../lib/genversion')
const v = require('../lib/version')
const gv = require('../index')
const csvToArray = require('../lib/csvToArray')
const commander = require('commander')
const path = require('path')

// Setup
const program = commander.program

program
.version(v, '-V, --version', 'output genversion\'s own version')
.arguments('<target>')
.description('Generates a version module at the target filepath.')
.option('-v, --verbose', 'increased output verbosity')
.option('-s, --semi', 'use semicolons in generated code')
.option('-d, --double', 'use double quotes in generated code')
.option('-b, --backtick', 'use backticks in generated code')
.option('-e, --es6', 'use es6 syntax in generated code')
.option('-e, --esm', 'use ESM exports in generated code')
.option(' --es6', 'alias for --esm flag')
.option('-u, --strict', 'add "use strict" in generated code')
.option('-c, --check-only', 'check if target is up to date')
.option('-f, --force', 'force file rewrite upon generation')
.option('-p, --source <path>', 'search for package.json along a custom path')
.option('-c, --check-only', 'check if the version module is up to date')
.option('-P, --property <key>', 'select properties; default is "version"')
.option('-t, --template <path>', 'generate with a custom template')
.option(' --template-engine <name>',
'select template engine; default is "ejs"')
.option('-v, --verbose', 'increased output verbosity')
.version(gv.version, '-V, --version', 'output genversion\'s own version')
.action((target, cliOpts) => {
if (typeof target !== 'string' || target === '') {
console.error('Missing argument: target')
return process.exit(1)
process.exitCode = 1
return
}
// Short alias for basename used a lot in log output
const targetBase = path.basename(target)

// Short alias for verbosity as we use it a lot
const verbose = cliOpts.verbose

// Read properties. Open comma separated list
if (cliOpts.property && cliOpts.property.startsWith('-')) {
// Detect forgotten property list (argument becomes the next flag)
console.error('error: property cannot be empty.')
process.exitCode = 1
return
}
cliOpts.properties = csvToArray(cliOpts.property)
if (cliOpts.properties.length === 0) {
cliOpts.properties = ['version']
}

// Options for check and generate
const opts = {
properties: cliOpts.properties,
source: cliOpts.source,
template: cliOpts.template,
templateEngine: cliOpts.templateEngine || 'ejs',
useSemicolon: cliOpts.semi,
useDoubleQuotes: cliOpts.double,
useBackticks: cliOpts.backtick,
useEs6Syntax: cliOpts.es6,
useStrict: cliOpts.strict,
source: cliOpts.source
useEs6Syntax: cliOpts.es6 || cliOpts.esm,
useStrict: cliOpts.strict
}

// A source path along to search for the package.json
// Default source path from which to search for the package.json.
if (typeof cliOpts.source !== 'string' || cliOpts.source === '') {
cliOpts.source = target
}

if (cliOpts.checkOnly) {
return gv.check(target, opts, (err, doesExist, isByGv, isUpToDate) => {
gv.check(target, opts, (err, doesExist, isByGv, isUpToDate) => {
if (err) {
console.error(err.toString())
return process.exit(1)
process.exitCode = 1
return
}

let exitCode = 1
Expand All @@ -66,63 +92,89 @@ program
if (verbose) {
switch (exitCode) {
case 0:
console.log('The version module ' + path.basename(target) +
console.log('The version module ' + targetBase +
' is up to date.')
break
case 1:
console.error('The version module ' + path.basename(target) +
console.error('The version module ' + targetBase +
' could not be found.')
break
case 2:
console.error('The version module ' + path.basename(target) +
console.error('The version module ' + targetBase +
' has outdated or unknown content.')
break
default:
throw new Error('Unknown exitCode: ' + exitCode)
}
}

return process.exit(exitCode)
process.exitCode = exitCode
})
// check completed, exit without generation
return
}

gv.check(target, opts, (err, doesExist, isByGenversion) => {
if (err) {
console.error(err.toString())
return process.exit(1)
process.exitCode = 1
return
}

if (doesExist) {
if (isByGenversion) {
gv.generate(target, opts, (errg, version) => {
if (errg) {
console.error(errg)
process.exitCode = 1
return
}

if (verbose) {
console.log('Version module ' + path.basename(target) +
console.log('Version module ' + targetBase +
' was successfully updated to ' + version)
}
})
} else if (cliOpts.force) {
// Forcefully rewrite unknown file.
if (verbose) {
console.warn('File ' + targetBase +
' will be forcefully overwritten.')
}

gv.generate(target, opts, (errg, version) => {
if (errg) {
console.error(errg)
process.exitCode = 1
return
}

if (verbose) {
console.log('Version module ' + targetBase +
' was successfully generated with version ' + version)
}
})
} else {
// FAIL, unknown file, do not replace
console.error(
'ERROR: File ' + target + ' is not generated by genversion and ' +
'therefore will not be replaced. Please ensure that the file can ' +
'be destroyed and remove it manually before retry.'
'ERROR: Target file ' + target + ' exists and it has unexpected ' +
'content. To be safe, the file will not be replaced. ' +
'Please ensure that the file is not important and ' +
'remove it manually before retry.'
)
process.exitCode = 1
}
} else {
// OK, file does not exist.
gv.generate(target, opts, (errg, version) => {
if (errg) {
console.error(errg)
process.exitCode = 1
return
}

if (verbose) {
console.log('Version module ' + path.basename(target) +
console.log('Version module ' + targetBase +
' was successfully generated with version ' + version)
}
})
Expand Down
Binary file added doc/genversion-logo-2k-halo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Binary file added doc/genversion-logo-halo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
2 changes: 1 addition & 1 deletion doc/logo-rain.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ <h3>Emojitracker OpenMoji Visualization</h3>
const s = sprinkler.create(c)

var images = [
'logo.png'
'genversion-logo.png'
]

var stop = s.start(images, {
Expand Down
10 changes: 3 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@

const gv = require('./lib/genversion')
const v = require('./lib/version')

exports.check = gv.check
exports.generate = gv.generate
exports.version = v
exports.check = require('./lib/check')
exports.generate = require('./lib/generate')
exports.version = require('./lib/version')
79 changes: 79 additions & 0 deletions lib/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const dryRun = require('./dryRun')
const fs = require('fs')

module.exports = (targetPath, opts, callback) => {
// Check if a version file can be generated.
//
// Parameters
// targetPath
// relative or absolute filepath to version file.
// opts
// optional options object. See dryRun docs for details.
// callback
// function (err, doesExist, isByGenversion, isUpToDate)
// err
// non-null on file system error
// doesExist
// boolean, if the version file exists
// isByGenversion
// boolean, true if file exists and is generated by genversion.
// The check is done by comparing the SIGNATURE on the first line.
// isUpToDate
// boolean, true if contents of the file are exactly as
// freshly generated.
//
if (typeof callback !== 'function') {
if (typeof opts !== 'function') {
throw new Error('Unexpected callback argument')
} else {
callback = opts
opts = {}
}
}

dryRun(targetPath, opts, (err, result) => {
if (err) {
return callback(err)
}

const absTarget = result.absoluteTargetPath
const referenceContent = result.generatedContent

fs.readFile(absTarget, 'utf8', (errf, fileContent) => {
if (errf) {
if (errf.code === 'ENOENT') {
// OK, file does not exist.
return callback(null, false, false, false)
}
// Real error.
return callback(errf, false, false, false)
}

// Issue axelpale/genversion#15
// Remove all the CR characters inserted by git on clone/checkout
// when git configuration has core.autocrlf=true
while (fileContent.indexOf('\r') >= 0) {
fileContent = fileContent.replace(/\r/, '')
}

// Get first line to test if we can touch the file.
// We should not touch the file if it does not resemble
// the content with which we are about to rewrite it.
const fingerprint = fileContent.trim().substring(0, 5).toLowerCase()
const refprint = referenceContent.trim().substring(0, 5).toLowerCase()
// Find the file begins like the generated content.
if (fingerprint !== refprint) {
// The file exists but is not created by genversion
return callback(null, true, false, false)
}

if (fileContent !== referenceContent) {
// The file is created by genversion but has outdated content
return callback(null, true, true, false)
}

// OK, the existing file was generated by genversion and is up to date.
return callback(null, true, true, true)
})
})
}
2 changes: 2 additions & 0 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// The signature is the first line of the generated file.
exports.SIGNATURE = '// Generated by genversion.'
20 changes: 20 additions & 0 deletions lib/csvToArray.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = (csv) => {
if (!csv) {
return []
}

if (Array.isArray(csv)) {
// Spread comma-separated values and flatten
const flat = csv.reduce((acc, str) => {
return acc.concat(str.split(','))
}, []).map(str => str.trim())

return flat
}

if (typeof csv === 'string') {
return csv.split(',').map(str => str.trim())
}

return []
}
Loading

0 comments on commit de0dd6a

Please sign in to comment.