From 2f30d17feb45f24cbc13698fb69ef42bb9921aa1 Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Tue, 16 May 2017 19:16:53 -0700 Subject: [PATCH 1/6] make create command much nicer --- src/commands/create.js | 68 ++++++++++++++++++++++++++++++++++---- src/lib/import-progress.js | 1 + src/ui/archive.js | 6 +++- src/ui/create.js | 48 +++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 src/ui/create.js diff --git a/src/commands/create.js b/src/commands/create.js index 91289c04..468026ec 100644 --- a/src/commands/create.js +++ b/src/commands/create.js @@ -1,9 +1,13 @@ +var path = require('path') +var fs = require('fs') var Dat = require('dat-node') var neatLog = require('neat-log') -var archiveUI = require('../ui/archive') +var DatJson = require('dat-json') +var prompt = require('prompt') +var chalk = require('chalk') +var createUI = require('../ui/create') var trackArchive = require('../lib/archive') var onExit = require('../lib/exit') -// var datJson = require('../dat-json') TODO: dat-node/use module var debug = require('debug')('dat') module.exports = { @@ -19,7 +23,7 @@ module.exports = { name: 'import', boolean: true, default: false, - help: 'Import files in the given directory' + help: 'Import files from the directory' }, { name: 'ignoreHidden', @@ -41,7 +45,7 @@ function create (opts) { // Todo // debug('Creating Dat archive in', opts.dir) - var neat = neatLog(archiveUI, { logspeed: opts.logspeed, quiet: opts.quiet }) + var neat = neatLog(createUI, { logspeed: opts.logspeed, quiet: opts.quiet }) neat.use(trackArchive) neat.use(onExit) neat.use(function (state, bus) { @@ -52,9 +56,59 @@ function create (opts) { if (err && err.name === 'ExistsError') return bus.emit('exit:warn', 'Archive already exists.') if (err) return bus.emit('exit:error', err) - // TODO: dat.json creation/write key - state.dat = dat - bus.emit('dat') + + // create before import + datjson = DatJson(dat.archive, { file: path.join(opts.dir, 'dat.json') }) + fs.readFile(path.join(opts.dir, 'dat.json'), 'utf-8', function (err, data) { + if (err) return doPrompt() + data = JSON.parse(data) + debug('read existing dat.json data', data) + doPrompt(data) + }) + + function doPrompt(data) { + if (!data) data = {} + + var schema = { + properties: { + title: { + description: chalk.magenta('Dat Title'), + default: data.title || '', + pattern: /^[a-zA-Z\s\-]+$/, + message: 'Name must be only letters, spaces, or dashes', + required: false + }, + description: { + description: chalk.magenta('Dat Description'), + default: data.description || '' + }, + doImport: { + description: chalk.magenta('Would you like to import your files?'), + default: 'yes' + } + } + } + prompt.message = chalk.green('> ') + prompt.delimiter = '' //chalk.cyan('') + prompt.start() + prompt.get(schema, writeDatJson) + + function writeDatJson (err, results) { + if (err) return console.log(err.message) // prompt error + if (results.doImport[0] === 'y') state.opts.import = true + if (!results.title && !results.description) return done() + delete results.doImport // don't want this in dat.json + datjson.create(results, done) + } + + function done (err) { + if (err) return bus.emit('exit:error', err) + state.title = 'Creating a new dat' + state.dat = dat + bus.emit('dat') + bus.emit('render') + } + } bus.emit('render') }) }) diff --git a/src/lib/import-progress.js b/src/lib/import-progress.js index 78ff2153..5503e4dc 100644 --- a/src/lib/import-progress.js +++ b/src/lib/import-progress.js @@ -10,6 +10,7 @@ function trackImport (state, bus) { var progress = state.dat.importFiles(state.opts, function (err) { if (err) return bus.emit('exit:error', err) state.importer.fileImport = null + state.exiting = true bus.emit('render') }) state.importer = xtend({ diff --git a/src/ui/archive.js b/src/ui/archive.js index 0b505642..bf524a70 100644 --- a/src/ui/archive.js +++ b/src/ui/archive.js @@ -24,7 +24,7 @@ function archiveUI (state) { if (state.title) title += state.title else if (state.writable) title += 'Sharing dat' else title += 'Downloading dat' - if (stats.version > 0) title += `: ${stats.files} files (${pretty(stats.byteLength)})` + if (stats.version > 0) title += `: ${stats.files} ${pluralize('file', stats.file)} (${pretty(stats.byteLength)})` else if (stats.version === 0) title += ': (empty archive)' if (state.http && state.http.listening) title += `\nServing files over http at http://localhost:${state.http.port}` @@ -46,4 +46,8 @@ function archiveUI (state) { ${state.opts.sources ? sourcesUI(state) : ''} ${state.exiting ? 'Exiting the Dat program...' : chalk.dim('Ctrl+C to Exit')} ` + + function pluralize (str, val) { + return `${str}${val === 1 ? '' : 's'}` + } } diff --git a/src/ui/create.js b/src/ui/create.js new file mode 100644 index 00000000..f40b7ef8 --- /dev/null +++ b/src/ui/create.js @@ -0,0 +1,48 @@ +var output = require('neat-log/output') +var stringKey = require('dat-encoding').toStr +var pretty = require('prettier-bytes') +var chalk = require('chalk') +var importUI = require('./components/import-progress') + +module.exports = createUI + +function createUI (state) { + if (!state.dat) return output` + Creating a Dat! Add information to your dat.json file: + ` + + var dat = state.dat + var stats = dat.stats.get() + var title = '' + var progressView + var exitMsg = ` + Your dat is created! Run ${chalk.green('dat sync')} to share: + ${chalk.blue('dat://' + stringKey(dat.key))} + ` + + if (state.writable || state.opts.showKey) { + title = `${chalk.blue('dat://' + stringKey(dat.key))}\n` + } + if (state.title) title += state.title + + if (stats.version > 0) title += `: ${stats.files} ${pluralize('file', stats.files)} (${pretty(stats.byteLength)})` + else if (stats.version === 0) title += ': (empty archive)' + + if (state.opts.import) { + progressView = importUI(state) + } else { + state.exiting = true + progressView = 'Not importing files.' + } + return output` + ${title} + + ${progressView} + + ${state.exiting ? exitMsg : chalk.dim('Ctrl+C to Exit')} + ` + + function pluralize (str, val) { + return `${str}${val === 1 ? '' : 's'}` + } +} From fb8e16fb2c6e4108bab7214cdc38c2bddd91caf2 Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Tue, 16 May 2017 19:19:18 -0700 Subject: [PATCH 2/6] add dat-json package + standard --- package.json | 1 + src/commands/create.js | 11 +++++------ src/ui/create.js | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 02606a0f..96a68031 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "cli-truncate": "^1.0.0", "dat-doctor": "^1.2.5", "dat-encoding": "^4.0.2", + "dat-json": "^1.0.0", "dat-link-resolve": "^1.0.0", "dat-node": "^3.3.0", "dat-registry": "^2.1.2", diff --git a/src/commands/create.js b/src/commands/create.js index 468026ec..e699d9ad 100644 --- a/src/commands/create.js +++ b/src/commands/create.js @@ -56,9 +56,8 @@ function create (opts) { if (err && err.name === 'ExistsError') return bus.emit('exit:warn', 'Archive already exists.') if (err) return bus.emit('exit:error', err) - // create before import - datjson = DatJson(dat.archive, { file: path.join(opts.dir, 'dat.json') }) + var datjson = DatJson(dat.archive, { file: path.join(opts.dir, 'dat.json') }) fs.readFile(path.join(opts.dir, 'dat.json'), 'utf-8', function (err, data) { if (err) return doPrompt() data = JSON.parse(data) @@ -66,7 +65,7 @@ function create (opts) { doPrompt(data) }) - function doPrompt(data) { + function doPrompt (data) { if (!data) data = {} var schema = { @@ -74,8 +73,8 @@ function create (opts) { title: { description: chalk.magenta('Dat Title'), default: data.title || '', - pattern: /^[a-zA-Z\s\-]+$/, - message: 'Name must be only letters, spaces, or dashes', + // pattern: /^[a-zA-Z\s\-]+$/, + // message: 'Name must be only letters, spaces, or dashes', required: false }, description: { @@ -89,7 +88,7 @@ function create (opts) { } } prompt.message = chalk.green('> ') - prompt.delimiter = '' //chalk.cyan('') + prompt.delimiter = '' // chalk.cyan('') prompt.start() prompt.get(schema, writeDatJson) diff --git a/src/ui/create.js b/src/ui/create.js index f40b7ef8..790a1e6d 100644 --- a/src/ui/create.js +++ b/src/ui/create.js @@ -7,9 +7,11 @@ var importUI = require('./components/import-progress') module.exports = createUI function createUI (state) { - if (!state.dat) return output` + if (!state.dat) { + return output` Creating a Dat! Add information to your dat.json file: ` + } var dat = state.dat var stats = dat.stats.get() From 553d899de177d7e2023f14baed355c567b2c7843 Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Tue, 16 May 2017 19:27:58 -0700 Subject: [PATCH 3/6] a bit of cleanup --- src/ui/create.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/ui/create.js b/src/ui/create.js index 790a1e6d..9e3fb3cf 100644 --- a/src/ui/create.js +++ b/src/ui/create.js @@ -15,14 +15,19 @@ function createUI (state) { var dat = state.dat var stats = dat.stats.get() - var title = '' + var title = '\n' var progressView var exitMsg = ` Your dat is created! Run ${chalk.green('dat sync')} to share: ${chalk.blue('dat://' + stringKey(dat.key))} ` + if (!state.opts.import) { + // set exiting right away + state.exiting = true + } - if (state.writable || state.opts.showKey) { + if (!state.exiting) { + // Only show key if not about to exit title = `${chalk.blue('dat://' + stringKey(dat.key))}\n` } if (state.title) title += state.title @@ -31,16 +36,15 @@ function createUI (state) { else if (stats.version === 0) title += ': (empty archive)' if (state.opts.import) { - progressView = importUI(state) + progressView = importUI(state) + '\n' } else { - state.exiting = true progressView = 'Not importing files.' } + return output` ${title} ${progressView} - ${state.exiting ? exitMsg : chalk.dim('Ctrl+C to Exit')} ` From 01fd64efdfacd26f6bf13d8184d044809e1b32ea Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Wed, 17 May 2017 10:44:54 -0700 Subject: [PATCH 4/6] move key + plural to elements --- src/ui/archive.js | 9 +++------ src/ui/components/network.js | 5 +---- src/ui/create.js | 11 ++++------- src/ui/elements/key.js | 6 ++++++ src/ui/elements/pluralize.js | 3 +++ 5 files changed, 17 insertions(+), 17 deletions(-) create mode 100644 src/ui/elements/key.js create mode 100644 src/ui/elements/pluralize.js diff --git a/src/ui/archive.js b/src/ui/archive.js index bf524a70..a887e4be 100644 --- a/src/ui/archive.js +++ b/src/ui/archive.js @@ -1,11 +1,12 @@ var output = require('neat-log/output') -var stringKey = require('dat-encoding').toStr var pretty = require('prettier-bytes') var chalk = require('chalk') var downloadUI = require('./components/download') var importUI = require('./components/import-progress') var networkUI = require('./components/network') var sourcesUI = require('./components/sources') +var keyEl = require('./elements/key') +var pluralize = require('./elements/pluralize') module.exports = archiveUI @@ -19,7 +20,7 @@ function archiveUI (state) { var progressView if (state.writable || state.opts.showKey) { - title = `${chalk.blue('dat://' + stringKey(dat.key))}\n` + title = `${keyEl(dat.key)}\n` } if (state.title) title += state.title else if (state.writable) title += 'Sharing dat' @@ -46,8 +47,4 @@ function archiveUI (state) { ${state.opts.sources ? sourcesUI(state) : ''} ${state.exiting ? 'Exiting the Dat program...' : chalk.dim('Ctrl+C to Exit')} ` - - function pluralize (str, val) { - return `${str}${val === 1 ? '' : 's'}` - } } diff --git a/src/ui/components/network.js b/src/ui/components/network.js index 68c4c828..2db0a4ea 100644 --- a/src/ui/components/network.js +++ b/src/ui/components/network.js @@ -1,5 +1,6 @@ var output = require('neat-log/output') var pretty = require('prettier-bytes') +var pluralize = require('../elements/pluralize') module.exports = networkUI @@ -23,8 +24,4 @@ function networkUI (state) { output += ` Upload ${pretty(upSpeed)}/s ` return output } - - function pluralize (str, val) { - return `${str}${val === 1 ? '' : 's'}` - } } diff --git a/src/ui/create.js b/src/ui/create.js index 9e3fb3cf..542a1429 100644 --- a/src/ui/create.js +++ b/src/ui/create.js @@ -1,8 +1,9 @@ var output = require('neat-log/output') -var stringKey = require('dat-encoding').toStr var pretty = require('prettier-bytes') var chalk = require('chalk') var importUI = require('./components/import-progress') +var keyEl = require('./elements/key') +var pluralize = require('./elements/pluralize') module.exports = createUI @@ -19,7 +20,7 @@ function createUI (state) { var progressView var exitMsg = ` Your dat is created! Run ${chalk.green('dat sync')} to share: - ${chalk.blue('dat://' + stringKey(dat.key))} + ${keyEl(dat.key)} ` if (!state.opts.import) { // set exiting right away @@ -28,7 +29,7 @@ function createUI (state) { if (!state.exiting) { // Only show key if not about to exit - title = `${chalk.blue('dat://' + stringKey(dat.key))}\n` + title = `${keyEl(dat.key)}\n` } if (state.title) title += state.title @@ -47,8 +48,4 @@ function createUI (state) { ${progressView} ${state.exiting ? exitMsg : chalk.dim('Ctrl+C to Exit')} ` - - function pluralize (str, val) { - return `${str}${val === 1 ? '' : 's'}` - } } diff --git a/src/ui/elements/key.js b/src/ui/elements/key.js new file mode 100644 index 00000000..94e36069 --- /dev/null +++ b/src/ui/elements/key.js @@ -0,0 +1,6 @@ +var stringKey = require('dat-encoding').toStr +var chalk = require('chalk') + +module.exports = function (key) { + return `${chalk.blue(`dat://${stringKey(key)}`)}` +} diff --git a/src/ui/elements/pluralize.js b/src/ui/elements/pluralize.js new file mode 100644 index 00000000..0a885791 --- /dev/null +++ b/src/ui/elements/pluralize.js @@ -0,0 +1,3 @@ +module.exports = function pluralize (str, val) { + return `${str}${val === 1 ? '' : 's'}` +} From c260de651ae4b8008524015afbb3268c8734bb34 Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Wed, 17 May 2017 10:46:15 -0700 Subject: [PATCH 5/6] exit on prompt error --- src/commands/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/create.js b/src/commands/create.js index e699d9ad..89d0dc2e 100644 --- a/src/commands/create.js +++ b/src/commands/create.js @@ -93,7 +93,7 @@ function create (opts) { prompt.get(schema, writeDatJson) function writeDatJson (err, results) { - if (err) return console.log(err.message) // prompt error + if (err) return bus.emit('exit:error', err) // prompt error if (results.doImport[0] === 'y') state.opts.import = true if (!results.title && !results.description) return done() delete results.doImport // don't want this in dat.json From 28ecc8bb11608ccd1e831d1a8ef59f5c03755d65 Mon Sep 17 00:00:00 2001 From: Joe Hand Date: Fri, 19 May 2017 16:57:40 -0700 Subject: [PATCH 6/6] fix prompt for tests --- src/commands/create.js | 7 ++++++- test/create.js | 12 ++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/commands/create.js b/src/commands/create.js index 89d0dc2e..9dc9fde8 100644 --- a/src/commands/create.js +++ b/src/commands/create.js @@ -59,7 +59,7 @@ function create (opts) { // create before import var datjson = DatJson(dat.archive, { file: path.join(opts.dir, 'dat.json') }) fs.readFile(path.join(opts.dir, 'dat.json'), 'utf-8', function (err, data) { - if (err) return doPrompt() + if (err || !data) return doPrompt() data = JSON.parse(data) debug('read existing dat.json data', data) doPrompt(data) @@ -87,6 +87,11 @@ function create (opts) { } } } + if (opts.title || opts.description) { + // avoid setting import unless these title/desc are set + var doImport = opts.import ? 'yes' : 'no' + prompt.override = { title: opts.title, description: opts.description, doImport: doImport } + } prompt.message = chalk.green('> ') prompt.delimiter = '' // chalk.cyan('') prompt.start() diff --git a/test/create.js b/test/create.js index a0c2a6b2..ac982f81 100644 --- a/test/create.js +++ b/test/create.js @@ -17,7 +17,7 @@ try { fs.unlinkSync(path.join(fixtures, 'dat.json')) } catch (e) { /* ignore err test('create - default opts no import', function (t) { tempDir(function (_, dir, cleanup) { - var cmd = dat + ' create' + var cmd = dat + ' create --title data --description thing' var st = spawn(t, cmd, {cwd: dir}) st.stdout.match(function (output) { @@ -37,7 +37,7 @@ test('create - default opts no import', function (t) { test('create - default opts with import', function (t) { tempDir(function (_, dir, cleanup) { - var cmd = dat + ' create --import' + var cmd = dat + ' create --title data --description thing --import' var st = spawn(t, cmd, {cwd: dir}) st.stdout.match(function (output) { @@ -62,7 +62,7 @@ test('create - errors on existing archive', function (t) { Dat(dir, function (err, dat) { t.error(err, 'no error') dat.close(function () { - var cmd = dat + ' create' + var cmd = dat + ' create --title data --description thing' var st = spawn(t, cmd, {cwd: dir}) st.stderr.match(function (output) { t.ok(output, 'errors') @@ -77,7 +77,7 @@ test('create - errors on existing archive', function (t) { test('create - sync after create ok', function (t) { tempDir(function (_, dir, cleanup) { - var cmd = dat + ' create' + var cmd = dat + ' create --title data --description thing' var st = spawn(t, cmd, {cwd: dir, end: false}) st.stdout.match(function (output) { var connected = output.indexOf('Not importing files') > -1 @@ -104,7 +104,7 @@ test('create - sync after create ok', function (t) { test('create - init alias', function (t) { tempDir(function (_, dir, cleanup) { - var cmd = dat + ' init' + var cmd = dat + ' init --title data --description thing' var st = spawn(t, cmd, {cwd: dir}) st.stdout.match(function (output) { @@ -124,7 +124,7 @@ test('create - init alias', function (t) { test('create - with path', function (t) { tempDir(function (_, dir, cleanup) { - var cmd = dat + ' init ' + dir + var cmd = dat + ' init ' + dir + ' --title data --description thing' var st = spawn(t, cmd) st.stdout.match(function (output) { var datCreated = output.indexOf('Not importing files') > -1