2015-12-31 07:00:18 +03:00
|
|
|
/**********************************************************************
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
**********************************************************************/
|
2016-08-21 02:19:24 +03:00
|
|
|
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
|
|
|
|
|
(function(require){ var module={} // make module AMD/node compatible...
|
2016-08-20 22:49:36 +03:00
|
|
|
/*********************************************************************/
|
2015-12-31 07:00:18 +03:00
|
|
|
|
2020-12-10 06:44:47 +03:00
|
|
|
var object = require('lib/object')
|
2016-05-29 23:49:01 +03:00
|
|
|
var util = require('lib/util')
|
2015-12-31 07:00:18 +03:00
|
|
|
var actions = require('lib/actions')
|
|
|
|
|
var features = require('lib/features')
|
|
|
|
|
|
2016-06-01 16:12:10 +03:00
|
|
|
var data = require('imagegrid/data')
|
|
|
|
|
var images = require('imagegrid/images')
|
2015-12-31 07:00:18 +03:00
|
|
|
|
|
|
|
|
var core = require('features/core')
|
|
|
|
|
var base = require('features/base')
|
|
|
|
|
|
|
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
//require('features/all')
|
|
|
|
|
|
|
|
|
|
|
2016-05-29 23:49:01 +03:00
|
|
|
if(typeof(process) != 'undefined'){
|
|
|
|
|
var pathlib = requirejs('path')
|
2020-12-08 18:35:50 +03:00
|
|
|
var argv = requirejs('lib/argv')
|
2020-12-09 06:27:11 +03:00
|
|
|
var progress = requirejs('cli-progress')
|
2023-01-17 18:39:44 +03:00
|
|
|
var colors = requirejs('colors')
|
|
|
|
|
|
|
|
|
|
var file = require('imagegrid/file') }
|
2016-05-29 23:49:01 +03:00
|
|
|
|
|
|
|
|
|
2019-01-17 17:51:26 +03:00
|
|
|
|
2015-12-31 07:00:18 +03:00
|
|
|
/*********************************************************************/
|
2016-05-23 03:42:53 +03:00
|
|
|
|
|
|
|
|
var CLIActions = actions.Actions({
|
2020-12-10 19:13:48 +03:00
|
|
|
config: {
|
|
|
|
|
// XXX do we care that something is not "ready" here???
|
|
|
|
|
'declare-ready-timeout': 0,
|
|
|
|
|
},
|
2018-12-20 15:28:24 +03:00
|
|
|
|
2020-12-10 06:05:02 +03:00
|
|
|
help: ['- System/Show action help',
|
|
|
|
|
function(...actions){
|
|
|
|
|
Object.entries(this.getDoc(actions))
|
|
|
|
|
.forEach(function([action, [s, l]]){
|
|
|
|
|
console.log(l)
|
|
|
|
|
console.log('')
|
|
|
|
|
}) }],
|
|
|
|
|
|
|
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
get cliActions(){
|
2018-12-20 15:28:24 +03:00
|
|
|
return this.actions
|
|
|
|
|
.filter(function(action){
|
|
|
|
|
return this.getActionAttr(action, 'cli') }.bind(this)) },
|
|
|
|
|
|
2020-12-10 06:05:02 +03:00
|
|
|
|
2018-12-20 04:40:30 +03:00
|
|
|
// XXX should this be here???
|
|
|
|
|
// ...move this to progress...
|
2020-12-09 06:27:11 +03:00
|
|
|
// XXX we are missing some beats, is this because we do not let the
|
|
|
|
|
// bar update before closing???
|
2018-12-20 04:40:30 +03:00
|
|
|
__progress: null,
|
|
|
|
|
showProgress: ['- System/',
|
|
|
|
|
function(text, value, max){
|
2020-12-09 19:02:31 +03:00
|
|
|
// progress display is disabled...
|
|
|
|
|
if(this.__progress === false){
|
|
|
|
|
return }
|
|
|
|
|
|
2020-12-09 03:53:57 +03:00
|
|
|
var msg = text instanceof Array ?
|
|
|
|
|
text.slice(1).join(': ')
|
|
|
|
|
: null
|
|
|
|
|
text = text instanceof Array ?
|
|
|
|
|
text[0]
|
|
|
|
|
: text
|
2018-12-20 04:40:30 +03:00
|
|
|
|
2020-12-09 06:27:11 +03:00
|
|
|
var settings = this.__progress = this.__progress || {}
|
|
|
|
|
var state = settings[text] = settings[text] || {}
|
|
|
|
|
|
|
|
|
|
var l = Math.max(text.length, settings.__text_length || 0)
|
|
|
|
|
// length changed -> update the bars...
|
|
|
|
|
l != settings.__text_length
|
|
|
|
|
&& Object.entries(settings)
|
|
|
|
|
.forEach(function([key, value]){
|
|
|
|
|
value instanceof Object
|
|
|
|
|
&& 'bar' in value
|
|
|
|
|
&& value.bar.update({text: key.padEnd(l)}) })
|
|
|
|
|
settings.__text_length = l
|
2018-12-20 04:40:30 +03:00
|
|
|
|
|
|
|
|
// normalize max and value...
|
2020-12-09 06:27:11 +03:00
|
|
|
value = state.value =
|
|
|
|
|
value != null ?
|
2018-12-20 04:40:30 +03:00
|
|
|
(typeof(value) == typeof('str') && /[+-][0-9]+/.test(value) ?
|
|
|
|
|
(state.value || 0) + parseInt(value)
|
2020-12-09 06:27:11 +03:00
|
|
|
: value)
|
|
|
|
|
: state.value
|
|
|
|
|
max = state.max =
|
|
|
|
|
max != null ?
|
|
|
|
|
(typeof(max) == typeof('str') && /[+-][0-9]+/.test(max) ?
|
|
|
|
|
(state.max || 0) + parseInt(max)
|
|
|
|
|
: max)
|
|
|
|
|
: state.max
|
|
|
|
|
|
|
|
|
|
var container = settings.__multi_bar =
|
|
|
|
|
settings.__multi_bar
|
2020-12-09 18:17:23 +03:00
|
|
|
|| (new progress.MultiBar({
|
|
|
|
|
// XXX make this simpler...
|
|
|
|
|
format: '{text} {bar} {percentage}% '
|
|
|
|
|
+'| ETA: {eta_formatted} | {value}/{total}',
|
|
|
|
|
autopadding: true,
|
|
|
|
|
stopOnComplete: true,
|
|
|
|
|
forceRedraw: true,
|
|
|
|
|
},
|
|
|
|
|
progress.Presets.rect)
|
|
|
|
|
// prepare for printing stuff...
|
|
|
|
|
.run(function(){
|
|
|
|
|
this.on('redraw-pre', function(){
|
|
|
|
|
// XXX need to clear the line -- need to get term-width....
|
|
|
|
|
// XXX this requires a full draw (forceRedraw: true)...
|
2020-12-09 19:02:31 +03:00
|
|
|
//console.log('moo'.padEnd(process.stdout.columns))
|
2020-12-09 18:17:23 +03:00
|
|
|
}) }))
|
2020-12-09 06:27:11 +03:00
|
|
|
var bar = state.bar =
|
|
|
|
|
state.bar || container.create(0, 0, {text: text.padEnd(l)})
|
|
|
|
|
|
2020-12-13 04:12:12 +03:00
|
|
|
// XXX for some reason this does not work under electron...
|
2020-12-09 06:27:11 +03:00
|
|
|
bar.setTotal(Math.max(max, value))
|
|
|
|
|
bar.update(value)
|
|
|
|
|
}],
|
|
|
|
|
|
|
|
|
|
// handle logger progress...
|
2020-12-11 06:24:22 +03:00
|
|
|
// XXX this is a copy from ui-progress -- need to reuse if possible...
|
2020-12-09 06:27:11 +03:00
|
|
|
handleLogItem: ['- System/',
|
|
|
|
|
function(logger, path, status, ...rest){
|
|
|
|
|
var msg = path.join(': ')
|
|
|
|
|
var l = (rest.length == 1 && rest[0] instanceof Array) ?
|
|
|
|
|
rest[0].length
|
|
|
|
|
: rest.length
|
|
|
|
|
|
|
|
|
|
// only pass the relevant stuff...
|
|
|
|
|
var attrs = {}
|
|
|
|
|
logger.ondone
|
|
|
|
|
&& (attrs.ondone = logger.ondone)
|
|
|
|
|
logger.onclose
|
|
|
|
|
&& (attrs.onclose = logger.onclose)
|
|
|
|
|
|
|
|
|
|
// get keywords...
|
|
|
|
|
var {add, done, skip, reset, close, error} =
|
|
|
|
|
this.config['progress-logger-keywords']
|
|
|
|
|
|| {}
|
|
|
|
|
// setup default aliases...
|
|
|
|
|
add = new Set([...(add || []), 'added'])
|
|
|
|
|
done = new Set([...(done || [])])
|
|
|
|
|
skip = new Set([...(skip || []), 'skipped'])
|
|
|
|
|
reset = new Set([...(reset || [])])
|
|
|
|
|
close = new Set([...(close || []), 'closed'])
|
|
|
|
|
error = new Set([...(error || [])])
|
|
|
|
|
|
|
|
|
|
// close...
|
|
|
|
|
if(status == 'close' || close.has(status)){
|
|
|
|
|
//this.showProgress(path, 'close')
|
|
|
|
|
// reset...
|
|
|
|
|
} else if(status == 'reset' || reset.has(status)){
|
|
|
|
|
//this.showProgress(path, 'reset')
|
|
|
|
|
// added new item -- increase max...
|
|
|
|
|
// XXX show msg in the progress bar???
|
|
|
|
|
} else if(status == 'add' || add.has(status)){
|
|
|
|
|
this.showProgress(path, '+0', '+'+l)
|
|
|
|
|
// resolved item -- increase done...
|
|
|
|
|
} else if(status == 'done' || done.has(status)){
|
|
|
|
|
this.showProgress(path, '+'+l)
|
|
|
|
|
// skipped item -- increase done...
|
|
|
|
|
// XXX should we instead decrease max here???
|
|
|
|
|
// ...if not this is the same as done -- merge...
|
|
|
|
|
} else if(status == 'skip' || skip.has(status)){
|
|
|
|
|
this.showProgress(path, '+'+l)
|
|
|
|
|
// error...
|
|
|
|
|
// XXX STUB...
|
|
|
|
|
} else if(status == 'error' || error.has(status)){
|
|
|
|
|
this.showProgress(['Error'].concat(msg), '+0', '+'+l) }
|
2018-12-20 04:40:30 +03:00
|
|
|
}],
|
|
|
|
|
|
2020-12-09 03:53:57 +03:00
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
// XXX SETUP revise default...
|
|
|
|
|
setupFeatures: ['- System/',
|
|
|
|
|
function(...tags){
|
|
|
|
|
var features = this.features.FeatureSet
|
|
|
|
|
requirejs('features/all')
|
|
|
|
|
features.setup(this, tags.length == 0 ?
|
|
|
|
|
[
|
|
|
|
|
'imagegrid-testing',
|
|
|
|
|
...this.features.input,
|
|
|
|
|
]
|
|
|
|
|
: tags) }],
|
|
|
|
|
|
2020-12-09 06:27:11 +03:00
|
|
|
|
2020-12-09 18:17:23 +03:00
|
|
|
// Startup commands...
|
|
|
|
|
//
|
2020-12-08 18:35:50 +03:00
|
|
|
startREPL: ['- System/Start CLI interpreter',
|
2020-12-13 04:12:12 +03:00
|
|
|
{cli: {
|
|
|
|
|
name: '@repl',
|
2020-12-20 06:12:47 +03:00
|
|
|
//interactive: true,
|
2020-12-13 04:12:12 +03:00
|
|
|
}},
|
2020-12-08 18:35:50 +03:00
|
|
|
function(){
|
2020-12-10 19:13:48 +03:00
|
|
|
var that = this
|
2020-12-08 18:35:50 +03:00
|
|
|
var repl = nodeRequire('repl')
|
2018-12-20 04:40:30 +03:00
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
// XXX SETUP
|
|
|
|
|
this.setupFeatures()
|
|
|
|
|
|
2020-12-09 18:17:23 +03:00
|
|
|
this.__keep_running = true
|
2020-12-08 18:35:50 +03:00
|
|
|
|
|
|
|
|
// setup the global ns...
|
|
|
|
|
global.ig =
|
|
|
|
|
global.ImageGrid =
|
|
|
|
|
this
|
|
|
|
|
|
2020-12-10 06:05:02 +03:00
|
|
|
global.help = function(...actions){
|
|
|
|
|
global.ig.help(...actions) }
|
|
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
var features = global.ImageGridFeatures = core.ImageGridFeatures
|
2020-12-08 18:35:50 +03:00
|
|
|
|
|
|
|
|
//var ig = core.ImageGridFeatures
|
2020-12-23 20:02:37 +03:00
|
|
|
|
|
|
|
|
// print banner...
|
|
|
|
|
//XXX
|
2020-12-08 18:35:50 +03:00
|
|
|
|
|
|
|
|
repl
|
|
|
|
|
.start({
|
|
|
|
|
prompt: 'ig> ',
|
2016-05-23 03:42:53 +03:00
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
useGlobal: true,
|
2016-05-27 18:41:28 +03:00
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
input: process.stdin,
|
|
|
|
|
output: process.stdout,
|
|
|
|
|
|
|
|
|
|
//ignoreUndefined: true,
|
|
|
|
|
})
|
|
|
|
|
.on('exit', function(){
|
2020-12-10 19:13:48 +03:00
|
|
|
that.stop() }) }],
|
2020-12-09 18:17:23 +03:00
|
|
|
// XXX move this to a feature that requires electron...
|
|
|
|
|
// ...and move electron to an optional dependency...
|
2020-12-12 09:29:57 +03:00
|
|
|
// XXX should we require electron or npx electron???
|
2020-12-13 04:12:12 +03:00
|
|
|
// XXX add --dev-tools flag...
|
2020-12-08 18:35:50 +03:00
|
|
|
startGUI: ['- System/Start viewer GUI',
|
2020-12-12 09:29:57 +03:00
|
|
|
core.doc`
|
|
|
|
|
|
|
|
|
|
NOTE: this will not wait for the viewer to exit.`,
|
2020-12-08 18:35:50 +03:00
|
|
|
{cli: '@gui'},
|
|
|
|
|
function(){
|
2020-12-12 09:29:57 +03:00
|
|
|
// already in electron...
|
|
|
|
|
if(process.versions.electron){
|
|
|
|
|
// XXX this feels hackish...
|
|
|
|
|
global.START_GUI = true
|
|
|
|
|
|
|
|
|
|
// launch gui...
|
|
|
|
|
} else {
|
|
|
|
|
requirejs('child_process')
|
|
|
|
|
.spawn(requirejs('electron'),
|
|
|
|
|
[ pathlib.join(
|
2020-12-09 18:17:23 +03:00
|
|
|
pathlib.dirname(nodeRequire.main.filename),
|
2020-12-12 09:29:57 +03:00
|
|
|
'e.js') ],
|
|
|
|
|
{ detached: true, }) } }],
|
2023-01-17 18:39:44 +03:00
|
|
|
|
|
|
|
|
// Introspection...
|
|
|
|
|
//
|
|
|
|
|
/* XXX
|
|
|
|
|
cliInfo: ['- System/Show information about index in PATH',
|
|
|
|
|
{cli: {
|
|
|
|
|
name: '@info',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
default: '.',
|
|
|
|
|
}},
|
|
|
|
|
function(path, options={}){
|
|
|
|
|
// XXX
|
|
|
|
|
}],
|
|
|
|
|
//*/
|
|
|
|
|
// XXX revise naming...
|
|
|
|
|
// XXX how do we handle errors???
|
|
|
|
|
cliListCollections: ['- System/List collections in index',
|
|
|
|
|
{cli: argv && argv.Parser({
|
|
|
|
|
key: '@collections',
|
|
|
|
|
doc: 'List collection in index at PATH',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
|
|
|
|
|
'-version': undefined,
|
|
|
|
|
'-quiet': undefined,
|
|
|
|
|
|
|
|
|
|
'-f': '-full',
|
|
|
|
|
'-full': {
|
|
|
|
|
doc: 'show full collection information',
|
|
|
|
|
type: 'bool',
|
|
|
|
|
},
|
|
|
|
|
})},
|
|
|
|
|
function(path, options={}){
|
|
|
|
|
var that = this
|
|
|
|
|
|
|
|
|
|
this.setupFeatures()
|
|
|
|
|
|
|
|
|
|
path = path || options.value
|
|
|
|
|
path = util.normalizePath(
|
|
|
|
|
path ?
|
|
|
|
|
pathlib.resolve(process.cwd(), path)
|
|
|
|
|
: process.cwd())
|
|
|
|
|
return this.loadIndex(path)
|
|
|
|
|
.then(
|
|
|
|
|
function(){
|
|
|
|
|
for(var name of that.collection_order || []){
|
|
|
|
|
// XXX revise output formatting...
|
|
|
|
|
options.full ?
|
|
|
|
|
console.log(that.collections[name].gid, name)
|
|
|
|
|
: console.log(name) } },
|
|
|
|
|
function(err){
|
|
|
|
|
// XXX how do we handle rejection???
|
|
|
|
|
console.error('Can\'t find or load index at:', path) }) }],
|
|
|
|
|
// XXX handle errors...
|
|
|
|
|
cliListIndexes: ['- System/List indexes in PATH',
|
|
|
|
|
{cli: argv && argv.Parser({
|
|
|
|
|
key: '@ls',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
default: '.',
|
|
|
|
|
|
|
|
|
|
'-version': undefined,
|
|
|
|
|
'-quiet': undefined,
|
|
|
|
|
|
|
|
|
|
'-r': '-recursive',
|
|
|
|
|
'-recursive': {
|
|
|
|
|
doc: 'List nested/recursive indexes',
|
|
|
|
|
type: 'bool',
|
|
|
|
|
},
|
2023-01-17 19:26:46 +03:00
|
|
|
|
|
|
|
|
'-n': '-nested-only',
|
|
|
|
|
'-nested-only': {
|
|
|
|
|
doc: 'Ignore the top-level index and only list the indexes below',
|
|
|
|
|
type: 'bool',
|
|
|
|
|
},
|
|
|
|
|
|
2023-01-17 18:39:44 +03:00
|
|
|
})},
|
|
|
|
|
function(path, options={}){
|
2023-01-17 19:26:46 +03:00
|
|
|
var that = this
|
|
|
|
|
this.setupFeatures()
|
2023-01-17 18:39:44 +03:00
|
|
|
file.listIndexes(path)
|
|
|
|
|
.on('end', function(paths){
|
2023-01-17 19:26:46 +03:00
|
|
|
paths = paths
|
|
|
|
|
.map(function(p){
|
|
|
|
|
return p
|
|
|
|
|
.split(that.config['index-dir'])
|
|
|
|
|
.shift() })
|
|
|
|
|
// normalize path...
|
|
|
|
|
path.at(-1) != '/'
|
|
|
|
|
&& (path += '/')
|
|
|
|
|
// handle --nested-only
|
|
|
|
|
options['nested-only']
|
|
|
|
|
&& paths.splice(paths.indexOf(path), 1)
|
|
|
|
|
paths = options.recursive ?
|
|
|
|
|
paths
|
|
|
|
|
: file.skipNested(paths)
|
|
|
|
|
.sortAs(paths)
|
2023-01-17 18:39:44 +03:00
|
|
|
for(var p of paths){
|
2023-01-17 19:26:46 +03:00
|
|
|
console.log(p) } }) }],
|
2023-01-17 18:39:44 +03:00
|
|
|
|
|
|
|
|
/* XXX
|
2020-12-09 06:55:42 +03:00
|
|
|
startWorker: ['- System/Start as worker',
|
|
|
|
|
{cli: '-worker'},
|
|
|
|
|
function(){
|
|
|
|
|
// XXX
|
|
|
|
|
}],
|
2020-12-08 18:35:50 +03:00
|
|
|
|
2020-12-09 18:17:23 +03:00
|
|
|
// Actions...
|
|
|
|
|
//
|
2020-12-11 06:24:22 +03:00
|
|
|
// XXX
|
2020-12-09 18:17:23 +03:00
|
|
|
// XXX this should be a nested parser...
|
|
|
|
|
// args:
|
|
|
|
|
// from=PATH
|
|
|
|
|
// to=PATH
|
|
|
|
|
// ...
|
|
|
|
|
cliExportIindex: ['- System/Clone index',
|
|
|
|
|
{cli: {
|
|
|
|
|
name: '@clone',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
valueRequired: true,
|
|
|
|
|
}},
|
|
|
|
|
function(){
|
|
|
|
|
// XXX
|
|
|
|
|
}],
|
|
|
|
|
cliPullChanges: ['- System/Pull changes',
|
|
|
|
|
{cli: {
|
|
|
|
|
name: '@pull',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
valueRequired: true,
|
|
|
|
|
}},
|
|
|
|
|
function(){
|
|
|
|
|
// XXX
|
|
|
|
|
}],
|
|
|
|
|
cliPushChanges: ['- System/Push changes',
|
|
|
|
|
{cli: {
|
|
|
|
|
name: '@push',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
valueRequired: true,
|
|
|
|
|
}},
|
|
|
|
|
function(){
|
|
|
|
|
// XXX
|
|
|
|
|
}],
|
|
|
|
|
//*/
|
|
|
|
|
|
2020-12-10 06:44:47 +03:00
|
|
|
// XXX report that can't find an index...
|
2020-12-10 19:13:48 +03:00
|
|
|
// XXX move options to generic object for re-use...
|
2023-01-17 17:57:29 +03:00
|
|
|
// XXX how do we handle errors???
|
2020-12-09 18:17:23 +03:00
|
|
|
cliExportImages: ['- System/Export images',
|
2020-12-10 06:44:47 +03:00
|
|
|
{cli: argv && argv.Parser({
|
2020-12-09 18:17:23 +03:00
|
|
|
key: '@export',
|
2020-12-10 06:44:47 +03:00
|
|
|
// help...
|
2020-12-10 06:05:02 +03:00
|
|
|
'-help-pattern': {
|
|
|
|
|
doc: 'Show image filename pattern info and exit',
|
|
|
|
|
priority: 89,
|
|
|
|
|
handler: function(){
|
2020-12-23 20:02:37 +03:00
|
|
|
this.parent.context
|
|
|
|
|
// XXX SETUP
|
|
|
|
|
//.setupFeatures('fs', 'commandline')
|
|
|
|
|
.setupFeatures()
|
|
|
|
|
.help('formatImageName')
|
2020-12-10 06:05:02 +03:00
|
|
|
return argv.STOP } },
|
|
|
|
|
'-version': undefined,
|
|
|
|
|
'-quiet': undefined,
|
2020-12-10 06:44:47 +03:00
|
|
|
// commands...
|
2020-12-09 19:02:31 +03:00
|
|
|
'@from': {
|
|
|
|
|
doc: 'Source path',
|
2020-12-10 06:44:47 +03:00
|
|
|
arg: 'PATH | from',
|
2020-12-10 21:59:15 +03:00
|
|
|
default: '.',
|
|
|
|
|
valueRequired: true, },
|
2023-01-17 17:57:29 +03:00
|
|
|
// XXX
|
|
|
|
|
'@collection': {
|
|
|
|
|
doc: 'Source collection (name/gid)',
|
|
|
|
|
arg: 'COLLECTION | collection',
|
|
|
|
|
//default: 'ALL',
|
|
|
|
|
valueRequired: false, },
|
|
|
|
|
//*/
|
2020-12-09 19:02:31 +03:00
|
|
|
'@to': {
|
|
|
|
|
doc: 'Destination path',
|
2020-12-10 06:44:47 +03:00
|
|
|
arg: 'PATH | path',
|
2020-12-10 06:05:02 +03:00
|
|
|
required: true,
|
|
|
|
|
valueRequired: true, },
|
2020-12-10 21:59:15 +03:00
|
|
|
// bool options...
|
2020-12-10 06:05:02 +03:00
|
|
|
// XXX these should get defaults from .config
|
|
|
|
|
'-include-virtual': {
|
|
|
|
|
doc: 'Include virtual blocks',
|
2020-12-10 21:59:15 +03:00
|
|
|
arg: '| include-virtual',
|
2020-12-10 06:05:02 +03:00
|
|
|
type: 'bool',
|
2020-12-11 06:24:22 +03:00
|
|
|
//value: true,
|
2020-12-10 06:05:02 +03:00
|
|
|
default: true, },
|
|
|
|
|
'-clean-target': {
|
|
|
|
|
doc: 'Cleanup target before export (backup)',
|
2020-12-10 21:59:15 +03:00
|
|
|
arg: '| clean-target',
|
2020-12-10 06:05:02 +03:00
|
|
|
type: 'bool',
|
2020-12-11 06:24:22 +03:00
|
|
|
//value: true,
|
2020-12-10 06:05:02 +03:00
|
|
|
default: true, },
|
2020-12-10 21:59:15 +03:00
|
|
|
'-no-*': {
|
|
|
|
|
doc: 'Negate boolean option value',
|
|
|
|
|
handler: function(rest, key, value, ...args){
|
|
|
|
|
rest.unshift(key.replace(/^-?-no/, '') +'=false') } },
|
|
|
|
|
// options...
|
2020-12-10 06:05:02 +03:00
|
|
|
'-image-name': {
|
|
|
|
|
doc: 'Image name pattern',
|
|
|
|
|
arg: 'PATTERN | preview-name-pattern',
|
2020-12-10 21:59:15 +03:00
|
|
|
default: '%(fav)l%n%(-%c)c',
|
|
|
|
|
valueRequired: true, },
|
2020-12-10 06:05:02 +03:00
|
|
|
'-mode': {
|
2020-12-10 23:55:56 +03:00
|
|
|
// XXX get doc values from system...
|
2020-12-10 06:44:47 +03:00
|
|
|
doc: 'Export mode, can be "resize" or "copy best match"',
|
2020-12-10 06:05:02 +03:00
|
|
|
arg: 'MODE | export-mode',
|
|
|
|
|
//default: 'copy best match',
|
2020-12-10 21:59:15 +03:00
|
|
|
default: 'resize',
|
|
|
|
|
valueRequired: true, },
|
2020-12-10 06:05:02 +03:00
|
|
|
'-image-size': {
|
|
|
|
|
doc: 'Output image size',
|
|
|
|
|
arg: 'SIZE | preview-size',
|
2020-12-10 21:59:15 +03:00
|
|
|
default: 1000,
|
|
|
|
|
valueRequired: true, },
|
2020-12-09 18:17:23 +03:00
|
|
|
})},
|
2020-12-10 06:44:47 +03:00
|
|
|
function(path, options={}){
|
|
|
|
|
var that = this
|
2020-12-10 19:13:48 +03:00
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
// XXX SETUP
|
|
|
|
|
this.setupFeatures()
|
|
|
|
|
|
2020-12-10 19:13:48 +03:00
|
|
|
path = path || options.from
|
|
|
|
|
path = util.normalizePath(
|
|
|
|
|
path ?
|
|
|
|
|
pathlib.resolve(process.cwd(), path)
|
|
|
|
|
: process.cwd())
|
|
|
|
|
|
2023-01-17 17:57:29 +03:00
|
|
|
var collection = options.collection
|
|
|
|
|
|
2020-12-10 19:13:48 +03:00
|
|
|
return this.loadIndex(path)
|
|
|
|
|
.then(
|
|
|
|
|
function(){
|
2023-01-17 17:57:29 +03:00
|
|
|
// export collection...
|
|
|
|
|
if(collection){
|
|
|
|
|
if(!that.collections[collection]){
|
|
|
|
|
console.error(
|
|
|
|
|
'Can\'t find collection "'+collection+'" in index at:', path)
|
|
|
|
|
// XXX how do we handle rejection???
|
|
|
|
|
//return Promise.reject('moo')
|
|
|
|
|
return }
|
|
|
|
|
var resolve
|
|
|
|
|
var reject
|
|
|
|
|
// XXX add a timeout???
|
|
|
|
|
that.one('collectionLoading.post',
|
|
|
|
|
function(){
|
|
|
|
|
resolve(that.exportImages(options)) })
|
|
|
|
|
that.loadCollection(collection)
|
|
|
|
|
return new Promise(function(res, rej){
|
|
|
|
|
resolve = res
|
|
|
|
|
reject = rej }) }
|
|
|
|
|
// export root...
|
2020-12-10 19:13:48 +03:00
|
|
|
return that.exportImages(options) },
|
|
|
|
|
function(err){
|
2023-01-17 17:57:29 +03:00
|
|
|
// XXX how do we handle rejection???
|
|
|
|
|
console.error('Can\'t find or load index at:', path) }) }],
|
|
|
|
|
|
2020-12-09 18:17:23 +03:00
|
|
|
// Utility... (EXPERIMENTAL)
|
|
|
|
|
//
|
2020-12-09 06:27:11 +03:00
|
|
|
// XXX metadata caching and preview creation are not in sync, can
|
|
|
|
|
// this be a problem???
|
|
|
|
|
// ...if not, add a note...
|
|
|
|
|
// XXX should we support creating multiple indexes at the same time???
|
2020-12-08 18:35:50 +03:00
|
|
|
// XXX this is reletively generic, might be useful globally...
|
2020-12-09 03:53:57 +03:00
|
|
|
// XXX should we use a clean index or do this in-place???
|
2020-12-10 06:05:02 +03:00
|
|
|
// XXX add ability to disable sort...
|
|
|
|
|
initIndex: ['- System/Make index',
|
|
|
|
|
core.doc`
|
|
|
|
|
|
|
|
|
|
Create index in current directory
|
|
|
|
|
.initIndex()
|
|
|
|
|
.initIndex('create')
|
|
|
|
|
-> promise
|
|
|
|
|
|
|
|
|
|
Create index in path...
|
|
|
|
|
,initIndex(path)
|
|
|
|
|
.initIndex('create', path)
|
|
|
|
|
-> promise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Update index in current directory
|
|
|
|
|
.initIndex('update')
|
|
|
|
|
-> promise
|
|
|
|
|
|
|
|
|
|
Update index in path...
|
|
|
|
|
.initIndex('update', path)
|
|
|
|
|
-> promise
|
|
|
|
|
|
|
|
|
|
`,
|
2020-12-08 18:35:50 +03:00
|
|
|
{cli: {
|
2020-12-10 06:05:02 +03:00
|
|
|
name: '@init',
|
2020-12-08 18:35:50 +03:00
|
|
|
arg: 'PATH',
|
2020-12-10 06:05:02 +03:00
|
|
|
//valueRequired: true,
|
2020-12-08 18:35:50 +03:00
|
|
|
}},
|
2020-12-10 06:05:02 +03:00
|
|
|
function(path, options){
|
2020-12-23 20:02:37 +03:00
|
|
|
// XXX SETUP
|
|
|
|
|
this.setupFeatures()
|
|
|
|
|
|
2020-12-10 06:05:02 +03:00
|
|
|
// get mode...
|
|
|
|
|
if(path == 'create' || path == 'update'){
|
|
|
|
|
var [mode, path, options] = arguments }
|
|
|
|
|
mode = mode || 'create'
|
|
|
|
|
// normalize path...
|
2020-12-09 06:55:42 +03:00
|
|
|
path = util.normalizePath(
|
2020-12-10 06:05:02 +03:00
|
|
|
path ?
|
|
|
|
|
pathlib.resolve(process.cwd(), path)
|
|
|
|
|
: process.cwd())
|
|
|
|
|
options = options || {}
|
2016-05-29 23:49:01 +03:00
|
|
|
|
2020-12-09 03:53:57 +03:00
|
|
|
// XXX should we use a clean index or do this in-place???
|
2020-12-09 06:27:11 +03:00
|
|
|
//var index = this.constructor(..)
|
2020-12-08 18:35:50 +03:00
|
|
|
var index = this
|
2020-12-10 06:05:02 +03:00
|
|
|
return (mode == 'create' ?
|
|
|
|
|
index.loadImages(path)
|
|
|
|
|
: index.loadNewImages(path))
|
2016-06-03 04:46:51 +03:00
|
|
|
// save base index...
|
2016-05-28 02:47:52 +03:00
|
|
|
.then(function(){
|
2020-12-08 18:35:50 +03:00
|
|
|
return index.saveIndex() })
|
|
|
|
|
// sharp stuff...
|
2016-06-03 04:46:51 +03:00
|
|
|
.then(function(){
|
2020-12-08 18:35:50 +03:00
|
|
|
if(index.makePreviews){
|
|
|
|
|
return Promise.all([
|
2020-12-10 06:44:47 +03:00
|
|
|
// NOTE: no need to call .cacheMetadata(..) as
|
|
|
|
|
// it is already running after .loadImages(..)
|
2020-12-08 18:35:50 +03:00
|
|
|
index.makePreviews('all') ])} })
|
2016-06-03 04:46:51 +03:00
|
|
|
.then(function(){
|
2020-12-08 18:35:50 +03:00
|
|
|
return index
|
2016-05-28 02:47:52 +03:00
|
|
|
.sortImages()
|
2020-12-08 18:35:50 +03:00
|
|
|
.saveIndex() }) }],
|
2020-12-20 06:12:47 +03:00
|
|
|
|
|
|
|
|
// XXX this is still wrong...
|
|
|
|
|
_makeIndex: ['- System/',
|
2020-12-21 03:41:11 +03:00
|
|
|
`chain: [
|
|
|
|
|
"loadImages: $1",
|
|
|
|
|
"saveIndex",
|
|
|
|
|
"makePreviews: 'all'",
|
|
|
|
|
"sortImages",
|
|
|
|
|
"saveIndex", ]`],
|
2020-12-20 06:12:47 +03:00
|
|
|
|
2020-12-10 06:05:02 +03:00
|
|
|
// XXX does not work yet...
|
|
|
|
|
updateIndex: ['- System/Update index',
|
|
|
|
|
{cli: {
|
|
|
|
|
name: '@update',
|
|
|
|
|
arg: 'PATH',
|
|
|
|
|
}},
|
|
|
|
|
'initIndex: "update" ...'],
|
|
|
|
|
cleanIndex: ['- System/',
|
|
|
|
|
{},
|
|
|
|
|
function(path, options){}],
|
2016-05-23 03:42:53 +03:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
2020-06-23 22:54:40 +03:00
|
|
|
// XXX revise architecture....
|
2020-06-09 16:48:23 +03:00
|
|
|
// XXX move this to the argv parser used in object.js
|
2015-12-31 07:00:18 +03:00
|
|
|
var CLI =
|
|
|
|
|
module.CLI = core.ImageGridFeatures.Feature({
|
|
|
|
|
title: '',
|
|
|
|
|
doc: '',
|
|
|
|
|
|
|
|
|
|
tag: 'commandline',
|
2016-05-23 03:42:53 +03:00
|
|
|
depends: [
|
2020-06-09 16:48:23 +03:00
|
|
|
'lifecycle',
|
|
|
|
|
'logger',
|
2016-05-23 03:42:53 +03:00
|
|
|
],
|
2015-12-31 07:00:18 +03:00
|
|
|
|
2017-10-04 08:08:40 +03:00
|
|
|
// XXX should this be ONLY node???
|
2015-12-31 07:00:18 +03:00
|
|
|
isApplicable: function(){
|
2017-10-04 08:08:40 +03:00
|
|
|
return this.runtime.node && !this.runtime.browser },
|
2015-12-31 07:00:18 +03:00
|
|
|
|
2016-05-23 03:42:53 +03:00
|
|
|
actions: CLIActions,
|
|
|
|
|
|
2015-12-31 07:00:18 +03:00
|
|
|
handlers: [
|
2020-12-09 03:53:57 +03:00
|
|
|
// supress logging by default...
|
|
|
|
|
['start.pre',
|
|
|
|
|
function(){
|
|
|
|
|
this.logger
|
|
|
|
|
&& (this.logger.quiet = true) }],
|
|
|
|
|
|
|
|
|
|
// handle args...
|
2020-12-09 18:17:23 +03:00
|
|
|
// XXX
|
2018-12-12 00:53:17 +03:00
|
|
|
['ready',
|
2015-12-31 07:00:18 +03:00
|
|
|
function(){
|
2016-01-03 04:49:00 +03:00
|
|
|
var that = this
|
2018-12-20 15:07:42 +03:00
|
|
|
|
2020-12-13 04:12:12 +03:00
|
|
|
//var pkg = require('package.json')
|
2020-12-08 18:35:50 +03:00
|
|
|
var pkg = nodeRequire('./package.json')
|
2020-12-10 19:13:48 +03:00
|
|
|
var wait_for = []
|
2020-12-13 04:12:12 +03:00
|
|
|
// XXX
|
|
|
|
|
var interactive = false
|
2020-12-08 18:35:50 +03:00
|
|
|
|
2020-12-23 20:02:37 +03:00
|
|
|
// XXX SETUP need to setup everything that has command-line features...
|
|
|
|
|
//this.setupFeatures()
|
|
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
argv.Parser({
|
2020-12-10 06:05:02 +03:00
|
|
|
context: this,
|
|
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
// XXX argv.js is not picking these up because
|
|
|
|
|
// of the require(..) mixup...
|
|
|
|
|
author: pkg.author,
|
|
|
|
|
version: pkg.version,
|
|
|
|
|
license: pkg.license,
|
|
|
|
|
|
2020-12-09 03:53:57 +03:00
|
|
|
'-verbose': {
|
2020-12-09 06:27:11 +03:00
|
|
|
doc: 'Enable verbose (very) output',
|
2020-12-09 03:53:57 +03:00
|
|
|
handler: function(){
|
|
|
|
|
that.logger
|
|
|
|
|
&& (that.logger.quiet = false) } },
|
2020-12-09 19:02:31 +03:00
|
|
|
// XXX merge this with -quiet...
|
|
|
|
|
'-no-progress': {
|
|
|
|
|
doc: 'Disable progress bar display',
|
|
|
|
|
handler: function(){
|
|
|
|
|
that.__progress = false } },
|
2020-12-09 03:53:57 +03:00
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
// XXX setup presets...
|
|
|
|
|
// ...load sets of features and allow user
|
|
|
|
|
// to block/add specific features...
|
|
|
|
|
|
2020-12-10 19:13:48 +03:00
|
|
|
// XXX config editor...
|
2020-12-08 18:35:50 +03:00
|
|
|
// ...get/set persistent config values...
|
|
|
|
|
|
|
|
|
|
// build the action command list...
|
|
|
|
|
...this.cliActions
|
|
|
|
|
.reduce(function(res, action){
|
|
|
|
|
var cmd = that.getActionAttr(action, 'cli')
|
|
|
|
|
if(typeof(cmd) == typeof('str') || cmd === true){
|
|
|
|
|
var name = cmd
|
|
|
|
|
var cmd = {name} }
|
|
|
|
|
var name = name === true ?
|
|
|
|
|
action
|
2020-12-09 18:17:23 +03:00
|
|
|
: (cmd.key || cmd.name)
|
|
|
|
|
|
2020-12-13 04:12:12 +03:00
|
|
|
// skip interactive commands in non-interactive
|
|
|
|
|
// contexts...
|
|
|
|
|
if(!interactive && cmd.interactive){
|
|
|
|
|
return res }
|
|
|
|
|
|
2020-12-09 18:17:23 +03:00
|
|
|
res[name] = cmd instanceof argv.Parser ?
|
2020-12-10 19:13:48 +03:00
|
|
|
// parser...
|
2020-12-09 18:17:23 +03:00
|
|
|
cmd
|
2020-12-10 06:05:02 +03:00
|
|
|
.then(function(unhandled, value, rest){
|
2020-12-10 19:13:48 +03:00
|
|
|
wait_for.push(that[action](value, this)) })
|
|
|
|
|
// single option definition...
|
2020-12-09 18:17:23 +03:00
|
|
|
: {
|
|
|
|
|
doc: (that.getActionAttr(action, 'doc') || '')
|
|
|
|
|
.split(/[\\\/]/g).pop(),
|
|
|
|
|
handler: function(rest, key, value){
|
2020-12-10 19:13:48 +03:00
|
|
|
var res = that[action](value)
|
|
|
|
|
wait_for.push(res)
|
|
|
|
|
return res },
|
2020-12-09 18:17:23 +03:00
|
|
|
...cmd,
|
|
|
|
|
}
|
2020-12-08 18:35:50 +03:00
|
|
|
|
|
|
|
|
return res }, {}),
|
2016-01-02 23:27:50 +03:00
|
|
|
})
|
2020-12-08 18:35:50 +03:00
|
|
|
.onNoArgs(function(args){
|
|
|
|
|
console.log('No args.')
|
2015-12-31 22:23:32 +03:00
|
|
|
|
2020-12-08 18:35:50 +03:00
|
|
|
// XXX we should either start the GUI here or print help...
|
|
|
|
|
args.push('--help')
|
|
|
|
|
//args.push('gui')
|
2016-05-23 03:42:53 +03:00
|
|
|
})
|
2020-12-10 19:13:48 +03:00
|
|
|
.stop(function(){ process.exit() })
|
|
|
|
|
.error(function(){ process.exit() })
|
2020-12-08 18:35:50 +03:00
|
|
|
.then(function(){
|
2016-01-01 01:58:55 +03:00
|
|
|
// XXX
|
2020-12-08 18:35:50 +03:00
|
|
|
})()
|
2018-12-11 17:18:02 +03:00
|
|
|
|
2020-12-10 19:13:48 +03:00
|
|
|
// XXX not all promises in the system resolve strictly
|
|
|
|
|
// after all the work is done, some resolve before that
|
|
|
|
|
// point and this calling process.exit() will interrupt
|
|
|
|
|
// them...
|
|
|
|
|
this.__keep_running
|
|
|
|
|
|| this.afterAction(function(){ this.stop() }) }],
|
2015-12-31 07:00:18 +03:00
|
|
|
],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
|
* vim:set ts=4 sw=4 : */
|
|
|
|
|
return module })
|