Permalink
Please sign in to comment.
Browse files
Merge pull request #49 from legien/master
Head command, plus fix for cat
- Loading branch information...
Showing
with
404 additions
and 29 deletions.
- +2 −0 bin/head.js
- +2 −1 commands.json
- +5 −1 dist/commands/cat.js
- +90 −0 dist/commands/head.js
- +3 −0 dist/help/head.js
- +4 −1 packages/cat/dist/commands/cat.js
- +32 −0 packages/head/README.md/template.README.md
- +2 −0 packages/head/bin/head.js
- +50 −0 packages/head/bin/parser.js
- +44 −0 packages/head/package.json
- +30 −26 src/commands/cat.js
- +94 −0 src/commands/head.js
- +1 −0 src/help.js
- +7 −0 src/help/head.js
- +38 −0 test/head.js
2
bin/head.js
@@ -0,0 +1,2 @@ | ||
+#!/usr/bin/env node | ||
+require('./parser')(process.argv, 'head'); |
3
commands.json
6
dist/commands/cat.js
90
dist/commands/head.js
@@ -0,0 +1,90 @@ | ||
+'use strict'; | ||
+ | ||
+var interfacer = require('./../util/interfacer'); | ||
+var fs = require('fs'); | ||
+var fsAutocomplete = require('vorpal-autocomplete-fs'); | ||
+ | ||
+var head = { | ||
+ exec: function exec(args, options) { | ||
+ var self = this; | ||
+ options = options || {}; | ||
+ | ||
+ options.argsType = args.stdin === undefined ? 'files' : 'stdin'; | ||
+ options.n = options.n === undefined ? 10 : options.n; | ||
+ | ||
+ if (options.n < 1) { | ||
+ self.log('Option n must be a positive integer.'); | ||
+ return 1; | ||
+ } | ||
+ | ||
+ if (options.argsType === 'stdin') { | ||
+ self.log(head.readLines(args.stdin[0], options.n)); | ||
+ return 0; | ||
+ } | ||
+ | ||
+ var files = args.files || args; | ||
+ files = files === undefined ? [] : files; | ||
+ files = typeof files === 'string' ? String(files).split(' ') : files; | ||
+ files = files.filter(function (arg) { | ||
+ return String(arg).trim() !== ''; | ||
+ }); | ||
+ | ||
+ var stdout = ''; | ||
+ var writeHeaders = false; | ||
+ if (files.length > 1) { | ||
+ writeHeaders = true; | ||
+ } | ||
+ | ||
+ var content = []; | ||
+ for (var i = 0; i < files.length; i++) { | ||
+ try { | ||
+ content[i] = fs.readFileSync(files[i]).toString(); | ||
+ } catch (e) { | ||
+ self.log('head: ' + files[i] + ': No such file or directory'); | ||
+ return 1; | ||
+ } | ||
+ } | ||
+ | ||
+ for (var i = 0; i < files.length; i++) { | ||
+ if (writeHeaders) { | ||
+ stdout += (i > 0 ? '\n\n' : '') + '==> ' + files[i] + ' <==\n'; | ||
+ } | ||
+ | ||
+ stdout += head.readLines(content[i], options.n); | ||
+ } | ||
+ | ||
+ self.log(stdout); | ||
+ return 0; | ||
+ }, | ||
+ readLines: function readLines(content, numberOfLines) { | ||
+ var stdout = ''; | ||
+ var contentArray = content.split('\n'); | ||
+ var linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines; | ||
+ for (var i = 0; i < linesToRead; i++) { | ||
+ if (stdout === '') { | ||
+ stdout = contentArray[i]; | ||
+ continue; | ||
+ } | ||
+ | ||
+ stdout += '\n' + contentArray[i]; | ||
+ } | ||
+ | ||
+ return stdout; | ||
+ } | ||
+}; | ||
+ | ||
+module.exports = function (vorpal) { | ||
+ if (vorpal === undefined) { | ||
+ return head; | ||
+ } | ||
+ vorpal.api.head = head; | ||
+ vorpal.command('head [files...]').option('-n [number]', 'The first number of lines will be copied to stdout.').autocomplete(fsAutocomplete()).action(function (args, callback) { | ||
+ args.options = args.options || {}; | ||
+ return interfacer.call(this, { | ||
+ command: head, | ||
+ args: args, | ||
+ options: args.options, | ||
+ callback: callback | ||
+ }); | ||
+ }); | ||
+}; |
3
dist/help/head.js
@@ -0,0 +1,3 @@ | ||
+"use strict"; | ||
+ | ||
+module.exports = "\nUsage: head [OPTION] [files ...]\nShow first lines of file(s).\n\nReport head bugs to <https://github.com/dthree/cash>\nCash home page: <http://cash.js.org/>\n"; |
5
packages/cat/dist/commands/cat.js
32
packages/head/README.md/template.README.md
@@ -0,0 +1,32 @@ | ||
+# {package-name} | ||
+ | ||
+--- | ||
+ | ||
+ | ||
+This is a cross-platform, 100% ES6 implementation of the Unix `{command-name}` command. | ||
+ | ||
+```bash | ||
+npm install {package-name} -g | ||
+``` | ||
+ | ||
+This will install `{command-name}` globally in your system path. | ||
+ | ||
+For help on the command, type: | ||
+ | ||
+```bash | ||
+> {command-name} --help | ||
+``` | ||
+ | ||
+## More | ||
+ | ||
+This module is part of [Cash](https://github.com/dthree/cash), a project providing cross-platform implementations of all major Unix-based commands in pure Javascript. | ||
+ | ||
+ | ||
+## Related | ||
+ | ||
+{related} | ||
+ | ||
+ | ||
+## License | ||
+ | ||
+MIT © [David Caccavella](https://github.com/dthree) |
2
packages/head/bin/head.js
@@ -0,0 +1,2 @@ | ||
+#!/usr/bin/env node | ||
+require('./parser')(process.argv, 'head'); |
50
packages/head/bin/parser.js
@@ -0,0 +1,50 @@ | ||
+'use strict'; | ||
+ | ||
+module.exports = function (args, command) { | ||
+ args.splice(0, 2); | ||
+ var pipes = (args.indexOf('|') > -1); | ||
+ if (args.length === 0) { | ||
+ // If we don't have to parse arguments, do | ||
+ // the quickest load: just the raw js file | ||
+ // of the command and nothing else. | ||
+ var cmd = require('./../dist/commands/' + command)(); | ||
+ cmd.exec.call(console, {options: {}}, {}); | ||
+ } else if (pipes === false) { | ||
+ // If we need to parse args for this | ||
+ // command only, pull up vorpal and just load | ||
+ // that one command. | ||
+ var vorpal = require('vorpal')(); | ||
+ vorpal.api = {}; | ||
+ require('./../dist/commands/' + command)(vorpal); | ||
+ args = args.join(' '); | ||
+ | ||
+ // If we passed in a help request, load in | ||
+ // the help file. | ||
+ if (args.indexOf('help') > -1 || args.indexOf('?') > -1) { | ||
+ let help; | ||
+ try { | ||
+ help = require('./../dist/help/' + command + '.js'); | ||
+ help = String(help).replace(/^\n|\n$/g, ''); | ||
+ } catch (e) {} | ||
+ let cmdObj = vorpal.find(command); | ||
+ if (cmdObj && help) { | ||
+ cmdObj.help(function (argus, cb) { | ||
+ cb(help); | ||
+ }) | ||
+ } | ||
+ } | ||
+ vorpal.exec(command + ' ' + args); | ||
+ } else { | ||
+ // If we get into piping other commands, | ||
+ // we need to go full bore and load the | ||
+ // entire cash library. | ||
+ // I guess we could technically parse all | ||
+ // of the passed args, look for applicable | ||
+ // commands and only load those, but that's | ||
+ // some messy work for something that might | ||
+ // not matter. If you're reading this and | ||
+ // have deemed it matters, do a PR. | ||
+ var cash = require('./../dist/index'); | ||
+ cash.vorpal.exec(command + ' ' + args.join(' ')); | ||
+ } | ||
+}; |
44
packages/head/package.json
@@ -0,0 +1,44 @@ | ||
+{ | ||
+ "name": "", | ||
+ "version": "0.0.1", | ||
+ "description": "", | ||
+ "main": "", | ||
+ "scripts": {}, | ||
+ "repository": { | ||
+ "type": "git", | ||
+ "url": "git+https://github.com/dthree/cash.git" | ||
+ }, | ||
+ "keywords": [ | ||
+ "cash", | ||
+ "terminal", | ||
+ "emulator", | ||
+ "cygwin", | ||
+ "cli", | ||
+ "windows", | ||
+ "linux", | ||
+ "unix", | ||
+ "posix", | ||
+ "bash", | ||
+ "tty", | ||
+ "util", | ||
+ "vorpal", | ||
+ "vorpal.js" | ||
+ ], | ||
+ "author": "dthree", | ||
+ "license": "MIT", | ||
+ "bugs": { | ||
+ "url": "https://github.com/dthree/cash/issues" | ||
+ }, | ||
+ "homepage": "https://github.com/dthree/cash#readme", | ||
+ "devDependencies": {}, | ||
+ "bin": {}, | ||
+ "dependencies": {}, | ||
+ "engines": { | ||
+ "node": ">= 4", | ||
+ "iojs": ">= 1.0.0" | ||
+ }, | ||
+ "files": [ | ||
+ "dist", | ||
+ "bin" | ||
+ ] | ||
+} |
56
src/commands/cat.js
94
src/commands/head.js
@@ -0,0 +1,94 @@ | ||
+'use strict'; | ||
+ | ||
+const interfacer = require('./../util/interfacer'); | ||
+const fs = require('fs'); | ||
+const fsAutocomplete = require('vorpal-autocomplete-fs'); | ||
+ | ||
+const head = { | ||
+ | ||
+ exec(args, options) { | ||
+ const self = this; | ||
+ options = options || {}; | ||
+ | ||
+ options.argsType = args.stdin === undefined ? 'files' : 'stdin'; | ||
+ options.n = options.n === undefined ? 10 : options.n; | ||
+ | ||
+ if (options.n < 1) { | ||
+ self.log('Option n must be a positive integer.'); | ||
+ return 1; | ||
+ } | ||
+ | ||
+ if (options.argsType === 'stdin') { | ||
+ self.log(head.readLines(args.stdin[0], options.n)); | ||
+ return 0; | ||
+ } | ||
+ | ||
+ let files = args.files || args; | ||
+ files = (files === undefined) ? [] : files; | ||
+ files = (typeof files === 'string') ? String(files).split(' ') : files; | ||
+ files = files.filter(arg => String(arg).trim() !== ''); | ||
+ | ||
+ let stdout = ''; | ||
+ let writeHeaders = false; | ||
+ if (files.length > 1) { | ||
+ writeHeaders = true; | ||
+ } | ||
+ | ||
+ const content = []; | ||
+ for (let i = 0; i < files.length; i++) { | ||
+ try { | ||
+ content[i] = fs.readFileSync(files[i]).toString(); | ||
+ } catch (e) { | ||
+ self.log(`head: ${files[i]}: No such file or directory`); | ||
+ return 1; | ||
+ } | ||
+ } | ||
+ | ||
+ for (let i = 0; i < files.length; i++) { | ||
+ if (writeHeaders) { | ||
+ stdout += `${i > 0 ? '\n\n' : ''}==> ${files[i]} <==\n`; | ||
+ } | ||
+ | ||
+ stdout += head.readLines(content[i], options.n); | ||
+ } | ||
+ | ||
+ self.log(stdout); | ||
+ return 0; | ||
+ }, | ||
+ | ||
+ readLines(content, numberOfLines) { | ||
+ let stdout = ''; | ||
+ const contentArray = content.split('\n'); | ||
+ const linesToRead = numberOfLines >= contentArray.length ? contentArray.length : numberOfLines; | ||
+ for (let i = 0; i < linesToRead; i++) { | ||
+ if (stdout === '') { | ||
+ stdout = contentArray[i]; | ||
+ continue; | ||
+ } | ||
+ | ||
+ stdout += `\n${contentArray[i]}`; | ||
+ } | ||
+ | ||
+ return stdout; | ||
+ } | ||
+}; | ||
+ | ||
+module.exports = function (vorpal) { | ||
+ if (vorpal === undefined) { | ||
+ return head; | ||
+ } | ||
+ vorpal.api.head = head; | ||
+ vorpal | ||
+ .command('head [files...]') | ||
+ .option('-n [number]', 'The first number of lines will be copied to stdout.') | ||
+ .autocomplete(fsAutocomplete()) | ||
+ .action(function (args, callback) { | ||
+ args.options = args.options || {}; | ||
+ return interfacer.call(this, { | ||
+ command: head, | ||
+ args, | ||
+ options: args.options, | ||
+ callback | ||
+ }); | ||
+ }); | ||
+}; |
1
src/help.js
7
src/help/head.js
@@ -0,0 +1,7 @@ | ||
+module.exports = ` | ||
+Usage: head [OPTION] [files ...] | ||
+Show first lines of file(s). | ||
+ | ||
+Report head bugs to <https://github.com/dthree/cash> | ||
+Cash home page: <http://cash.js.org/> | ||
+`; |
38
test/head.js
@@ -0,0 +1,38 @@ | ||
+'use strict'; | ||
+ | ||
+require('assert'); | ||
+require('mocha'); | ||
+const should = require('should'); | ||
+const cash = require('../dist/index.js'); | ||
+const $ = require('shelljs'); | ||
+require('shelljs/global'); | ||
+ | ||
+describe('head', function () { | ||
+ before(function () { | ||
+ 'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\nline11'.to('eleven.test'); | ||
+ 'line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10'.to('ten.test'); | ||
+ }); | ||
+ | ||
+ after(function () { | ||
+ $.rm(['eleven.test', 'ten.test']); | ||
+ }); | ||
+ | ||
+ it('should exist and be a function', function () { | ||
+ should.exist(cash.head); | ||
+ }); | ||
+ | ||
+ it('should give back ten lines when called without options', function () { | ||
+ const result = cash.head('eleven.test'); | ||
+ result.should.be.equal('line1\nline2\nline3\nline4\nline5\nline6\nline7\nline8\nline9\nline10\n'); | ||
+ }); | ||
+ | ||
+ it('should give back five lines when called with option n set to 5', function () { | ||
+ const result = cash.head('eleven.test', {n: 5}); | ||
+ result.should.be.equal('line1\nline2\nline3\nline4\nline5\n'); | ||
+ }); | ||
+ | ||
+ it('should write header when used with more than one file', function () { | ||
+ const result = cash.head(['eleven.test', 'ten.test'], {n: 2}); | ||
+ result.should.be.equal('==> eleven.test <==\nline1\nline2\n\n==> ten.test <==\nline1\nline2\n'); | ||
+ }); | ||
+}); |
0 comments on commit
b9f9ee9