Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Massive rewrite / now with module

  • Loading branch information...
commit 2e9e016773de6677cab9b242b89a17ea86a6837d 1 parent 70ebb49
Jacob Chapel authored February 16, 2011
127  README.markdown
Source Rendered
... ...
@@ -0,0 +1,127 @@
  1
+ngist
  2
+=====
  3
+
  4
+ngist is a node.js module and CLI tool for easy posting of [gists](http://gist.github.com).
  5
+
  6
+
  7
+Installation
  8
+------------
  9
+
  10
+With [npm](http://github.com/isaacs/npm):
  11
+
  12
+	npm install ngist
  13
+	
  14
+Clone this project:
  15
+
  16
+	git clone http://github.com/chapel/ngist.git
  17
+
  18
+
  19
+CLI
  20
+---
  21
+
  22
+	Usage: ngist [file.js file2.js ...] [options]
  23
+
  24
+	[Options]
  25
+	-h, --help         Display this help page
  26
+	-c, --clip         Use clipboard content
  27
+	                     ex: ngist [file.js] -c file.js
  28
+	-d, --desc         Set description of gist
  29
+	                     ex: ngist file.js -d 'Description'
  30
+	-u, --user         Github username
  31
+	-t, --token        Github API token
  32
+	                     ex: ngist file.js -u username -t token
  33
+	-p, --private      Make gist private
  34
+	-o, --out          Copy gist url to clipboard
  35
+
  36
+How to set user/token with git config
  37
+-------------------------------------
  38
+
  39
+Once you get your Github API token from your [Github Account](https://github.com/account#admin_bucket)
  40
+If you set your Github username and API token using these steps, ngist will
  41
+automatically gather them and authenticate for you.
  42
+
  43
+Run these two commands:
  44
+
  45
+	git config --add github.user [github_username]
  46
+	git config --add github.token [github_api_token]
  47
+
  48
+To verify that they have been set, use:
  49
+
  50
+	git config --get github.user
  51
+	git config --get github.token
  52
+	
  53
+
  54
+Module
  55
+------
  56
+
  57
+The ngist module is simple and easy to use.
  58
+
  59
+**Example**
  60
+
  61
+ngist_text.js
  62
+
  63
+	var ngist = require('ngist');
  64
+	
  65
+	var files = [{name: 'file1.js', content: "function(){ console.log('x'); };"}, 
  66
+				{name: 'file2.js', content: "function(){ test.x; };"}];
  67
+	var options = {
  68
+		user: chapel, // Your username!
  69
+		token: asa09fjew0f, // [Github Account](https://github.com/account#admin_bucket)
  70
+		description: 'This is an example gist', // Set for whole gist and is optional.
  71
+		private: true; // Set to true if you want the gist to be private, otherwise omit.
  72
+	};
  73
+	
  74
+	ngist.send(files, options, function(err, url) {
  75
+		console.log(url); // Example: https://gist.github.com/830022
  76
+	});
  77
+
  78
+ngist_files.js
  79
+
  80
+	var ngist = require('ngist');
  81
+	
  82
+	var files = ['file1.js', 'file2.js'];
  83
+	var options = {
  84
+		user: chapel, 
  85
+		token: asa09fjew0f, 
  86
+		description: 'This is an example gist', 
  87
+		private: true; 
  88
+	};
  89
+	
  90
+	ngist.files(files, function(err, processed_files) {
  91
+		ngist.send(processed_files, options, function(err, url) {
  92
+			console.log(url); 
  93
+		});
  94
+	});
  95
+	
  96
+ngist_files.coffee
  97
+	
  98
+	ngist = require 'ngist'
  99
+	
  100
+	files = ['file1.js', 'file2.js']
  101
+	options = 
  102
+		user: chapel
  103
+		token: pajsdfjoafe
  104
+		description: 'This is an example gist'
  105
+		private: true;
  106
+		
  107
+	ngist.files files, (err, processed_files) ->
  108
+		ngist.send processed_files, options, (err, url) ->
  109
+			console.log url
  110
+			
  111
+
  112
+Functions
  113
+---------
  114
+
  115
+**ngist.files**
  116
+
  117
+Takes an array of file names, fetches the files, while sending an error if a file is not found. If all files are found, then it returns an array of objects that have the files extension, name, and contents ready to be sent.
  118
+
  119
+**ngist.send**
  120
+
  121
+Takes an array of objects, as well as an object that has optional parameters like user/token, description and private. If there are no errors, it will return a gist url.
  122
+			
  123
+
  124
+Inspired By
  125
+-----------
  126
+
  127
+The original CLI tool was inspired by [defunkt's gist](https://github.com/defunkt/gist) as well as those on [#node.js](irc://freenode.net) that gave advice and criticism. It is always welcome.
165  lib/cli.js
... ...
@@ -0,0 +1,165 @@
  1
+#!/usr/bin/env node
  2
+
  3
+var exec, finish, get_clip, get_creds, next, ngist, opt, os, run, serial, set_clip, spit_error;
  4
+os = require('os');
  5
+ngist = require('./ngist');
  6
+exec = require('child_process').exec;
  7
+opt = require('optimist').argv;
  8
+run = function() {
  9
+  if (opt._.length === 0) {
  10
+    opt._ = null;
  11
+  }
  12
+  opt.help = opt.help || opt.h;
  13
+  opt.clip = opt.clip || opt.c;
  14
+  opt.desc = opt.desc || opt.d;
  15
+  opt.private = opt.private || opt.p;
  16
+  opt.user = opt.user || opt.u;
  17
+  opt.token = opt.token || opt.t;
  18
+  opt.out = opt.out || opt.o;
  19
+  if (opt.help) {
  20
+    return console.log('  \nUsage: ngist [file.js file2.js ...] [options]\n\n[Options]\n-h, --help         Display this help page\n-c, --clip         Use clipboard content\n                       ex: ngist [file.js] -c file.js\n-d, --desc         Set description of gist\n                       ex: ngist file.js -d \'Description\'\n-u, --user         Github username\n-t, --token        Github API token | https://github.com/account#admin_bucket\n                       ex: ngist file.js -u username -t token\n-p, --private      Make gist private\n-o, --out          Copy gist url to clipboard\n\n[How to set user/token with git config]\nOnce you get your Github API token from https://github.com/account#admin_bucket\nIf you set your Github username and API token using these steps, ngist will\nautomatically gather them and authenticate for you.\n\nRun these two commands:\n  git config --add github.user [github_username]\n  git config --add github.token [github_api_token]\n\nTo verify that they have been set, use:\n  git config --get github.[user/token]');
  21
+  }
  22
+  if (opt._ && opt.clip) {
  23
+    return ngist.files(opt._, function(err, files) {
  24
+      if (err) {
  25
+        spit_error(err);
  26
+      }
  27
+      return get_clip(function(clip) {
  28
+        files = files.concat(clip);
  29
+        return next(files);
  30
+      });
  31
+    });
  32
+  } else if (opt._) {
  33
+    return ngist.files(opt._, function(err, files) {
  34
+      if (err) {
  35
+        spit_error(err);
  36
+      }
  37
+      return next(files);
  38
+    });
  39
+  } else if (opt.clip) {
  40
+    return get_clip(function(clip) {
  41
+      return next(clip);
  42
+    });
  43
+  } else {
  44
+    return spit_error('You must set file(s) and/or a clip from the clipboard (-c)');
  45
+  }
  46
+};
  47
+next = function(files) {
  48
+  if (opt.user && opt.token) {
  49
+    return finish(files, opt.user, opt.token);
  50
+  } else if ((opt.user && !opt.token) || (opt.token && !opt.user)) {
  51
+    return spit_error('Both user (-u) and token (-t) must be set if you wish to login');
  52
+  } else {
  53
+    return get_creds(files);
  54
+  }
  55
+};
  56
+finish = function(files, user, token) {
  57
+  var options;
  58
+  if (opt.desc || opt.private || (user && token)) {
  59
+    options = {};
  60
+  } else {
  61
+    options = null;
  62
+  }
  63
+  if (opt.private) {
  64
+    options.private = true;
  65
+  }
  66
+  if (opt.desc) {
  67
+    options.description = opt.desc;
  68
+  }
  69
+  if (user) {
  70
+    options.user = user;
  71
+  }
  72
+  if (token) {
  73
+    options.token = token;
  74
+  }
  75
+  return ngist.send(files, options, function(err, url) {
  76
+    if (err) {
  77
+      spit_error(err);
  78
+    }
  79
+    if (opt.out) {
  80
+      set_clip(url);
  81
+    }
  82
+    return console.log("Gist: " + url);
  83
+  });
  84
+};
  85
+get_creds = function(files) {
  86
+  var keys;
  87
+  keys = ['get', 'system', 'global', 'simple'];
  88
+  return serial(keys, function(key, i, _next) {
  89
+    return exec("git config --" + key + " github.user", function(err, stdout, stderr) {
  90
+      var user;
  91
+      if (!err) {
  92
+        user = stdout.replace("\n", "");
  93
+        return exec("git config --" + key + " github.token", function(err, stdout, stderr) {
  94
+          var token;
  95
+          if (!err) {
  96
+            token = stdout.replace("\n", "");
  97
+            return finish(files, user, token);
  98
+          }
  99
+        });
  100
+      } else {
  101
+        return _next();
  102
+      }
  103
+    });
  104
+  }, function() {
  105
+    console.log("For instructions on how to authenticate your gists: ngist -h");
  106
+    return finish(files, null, null);
  107
+  });
  108
+};
  109
+set_clip = function(url) {
  110
+  var clipboard;
  111
+  switch (os.type()) {
  112
+    case 'Darwin':
  113
+      clipboard = "echo " + url + " | pbcopy";
  114
+      break;
  115
+    case 'Linux':
  116
+      clipboard = "echo " + url + " | xclip";
  117
+  }
  118
+  return exec(clipboard, function(err, stdout) {
  119
+    if (err) {
  120
+      return spit_error('Problem sending url to clipboard');
  121
+    }
  122
+  });
  123
+};
  124
+get_clip = function(callback) {
  125
+  var clip, clipboard;
  126
+  clip = [];
  127
+  switch (os.type()) {
  128
+    case 'Darwin':
  129
+      clipboard = 'pbpaste';
  130
+      break;
  131
+    case 'Linux':
  132
+      clipboard = 'xclip -out -selection clipboard';
  133
+  }
  134
+  return exec(clipboard, function(err, stdout) {
  135
+    if (stdout === '') {
  136
+      spit_error('Nothing in clipboard');
  137
+    }
  138
+    if (err) {
  139
+      spit_error('Problem getting contents of clipboard');
  140
+    }
  141
+    clip.push({
  142
+      name: opt.clip,
  143
+      contents: stdout
  144
+    });
  145
+    return callback(clip);
  146
+  });
  147
+};
  148
+spit_error = function(err) {
  149
+  console.error("" + err + "\nFor more help see: ngist -h");
  150
+  return process.exit(1);
  151
+};
  152
+serial = function(array, iterator, next) {
  153
+  var cycle;
  154
+  cycle = function(i) {
  155
+    if (i < array.length) {
  156
+      return iterator(array[i], i, function() {
  157
+        return cycle(i + 1);
  158
+      });
  159
+    } else {
  160
+      return next();
  161
+    }
  162
+  };
  163
+  return cycle(0);
  164
+};
  165
+run();
260  lib/ngist.js 100755 → 100644
... ...
@@ -1,191 +1,95 @@
1  
-(function() {
2  
-  var EventEmitter, anError, emitter, exec, fs, getClip, getCredentials, getFiles, https, opt, os, path, post, querystring, run, setClipboard, setCredentials, usage;
3  
-  fs = require('fs');
4  
-  os = require('os');
5  
-  path = require('path');
6  
-  https = require('https');
7  
-  querystring = require('querystring');
8  
-  exec = require('child_process').exec;
9  
-  EventEmitter = require('events').EventEmitter;
10  
-  opt = require('optimist').usage('Usage: ngist [options] [file.ext] [file...]').argv;
11  
-  emitter = new EventEmitter;
12  
-  run = function() {
13  
-    if (opt.h || opt.help) {
14  
-      return usage();
  1
+var fs, https, path, post, querystring, serial;
  2
+fs = require('fs');
  3
+path = require('path');
  4
+https = require('https');
  5
+querystring = require('querystring');
  6
+exports.send = function(files, options, callback) {
  7
+  var gist;
  8
+  gist = {};
  9
+  if (typeof options === 'function') {
  10
+    callback = options;
  11
+    options = null;
  12
+  }
  13
+  if (files.length > 10) {
  14
+    return callback(new Error("" + files.length + " files is more than the maximum of 10 files"));
  15
+  }
  16
+  files.forEach(function(file, i) {
  17
+    gist["file_ext[gistfile" + (i + 1) + "]"] = path.extname(file.name);
  18
+    gist["file_name[gistfile" + (i + 1) + "]"] = file.name;
  19
+    return gist["file_contents[gistfile" + (i + 1) + "]"] = file.contents;
  20
+  });
  21
+  if (options !== null) {
  22
+    if ((options.user && !options.token) || (options.token && !options.user)) {
  23
+      return callback(new Error('To login both options.user and options.token must be given'));
15 24
     }
16  
-    if ((opt.f || opt.file) && !(opt.c || opt.clip)) {
17  
-      return getFiles();
  25
+    if (options.user) {
  26
+      gist['login'] = options.user;
18 27
     }
19  
-    if ((opt.c || opt.clip) && !(opt.f || opt.file)) {
20  
-      return getClip();
  28
+    if (options.token) {
  29
+      gist['token'] = options.token;
21 30
     }
22  
-    if ((opt.c || opt.clip) && (opt.f || opt.file)) {
23  
-      anError('You cannot use files and clipboard together.');
  31
+    if (options.description) {
  32
+      gist['description'] = options.description;
24 33
     }
25  
-    if (!((opt.f || opt.file) || (opt.c || opt.f))) {
26  
-      return anError('File or clipboard not specified. For help: ngist -h');
  34
+    if (options.private === true) {
  35
+      gist['action_button'] = 'private';
27 36
     }
28  
-  };
29  
-  getCredentials = function() {
30  
-    if ((opt.u || opt.user) && (opt.t || opt.token)) {
31  
-      return setCredentials();
32  
-    } else {
33  
-      return exec("git config --global github.user", function(err, stdout, stderr) {
34  
-        var user;
35  
-        if (!err) {
36  
-          user = stdout.replace("\n", "");
37  
-          return exec("git config --global github.token", function(err, stdout, stderr) {
38  
-            var token;
39  
-            if (!err) {
40  
-              token = stdout.replace("\n", "");
41  
-              return emitter.emit('credentials', user, token);
42  
-            } else {
43  
-              return anError('No token set with git.\nFor help: ngist -h');
44  
-            }
45  
-          });
46  
-        } else {
47  
-          return anError('No username or token set with git.\nFor help: ngist -h');
48  
-        }
49  
-      });
50  
-    }
51  
-  };
52  
-  setCredentials = function() {
53  
-    return exec("git config --global github.user " + (opt.u || opt.user), function(err, stdout, stderr) {
54  
-      if (!err) {
55  
-        return exec("git config --global github.token " + (opt.t || opt.token), function(err, stdout, stderr) {
56  
-          return emitter.emit('credentials', opt.u || opt.user, opt.t || opt.token);
57  
-        });
  37
+  }
  38
+  return post(gist, callback);
  39
+};
  40
+exports.files = function(files, callback) {
  41
+  var tmp;
  42
+  tmp = [];
  43
+  return serial(files, function(file, i, next) {
  44
+    return path.exists(file, function(exists) {
  45
+      if (!exists) {
  46
+        return callback(new Error("File not found: " + file));
58 47
       }
59  
-    });
60  
-  };
61  
-  setClipboard = function(url) {
62  
-    var clipboard;
63  
-    switch (os.type()) {
64  
-      case 'Darwin':
65  
-        clipboard = "echo " + url + " | pbcopy";
66  
-        break;
67  
-      case 'Linux':
68  
-        clipboard = "echo " + url + " | xclip";
69  
-    }
70  
-    return exec(clipboard, function(err, stdout) {
71  
-      if (err) {
72  
-        return anError('Problem sending url to clipboard');
73  
-      }
74  
-    });
75  
-  };
76  
-  post = function(gist) {
77  
-    var gistData, options, req;
78  
-    gistData = querystring.stringify(gist);
79  
-    options = {
80  
-      host: 'gist.github.com',
81  
-      port: 443,
82  
-      path: '/gists',
83  
-      method: 'POST',
84  
-      headers: {
85  
-        'Content-Type': 'application/x-www-form-urlencoded',
86  
-        'Content-Length': gistData.length
87  
-      }
88  
-    };
89  
-    req = https.request(options, function(res) {
90  
-      if (res.statusCode === 401) {
91  
-        anError("Github.com username or token are not valid.\n      username: " + gist.login + "      token: " + gist.token + "\n      For help: gist -h");
92  
-        process.exit(1);
93  
-      }
94  
-      return res.on('end', function() {
95  
-        if (opt.o || opt.out) {
96  
-          setClipboard(res.headers.location);
97  
-        }
98  
-        return console.log('Gist URL: ' + res.headers.location);
  48
+      return fs.readFile(file, 'utf8', function(err, data) {
  49
+        tmp.push({
  50
+          'name': path.basename(file),
  51
+          'contents': data
  52
+        });
  53
+        return next();
99 54
       });
100 55
     });
101  
-    return req.end(gistData);
102  
-  };
103  
-  getFiles = function() {
104  
-    var files, gist, i;
105  
-    gist = {};
106  
-    files = [];
107  
-    files.push(opt.f || opt.file);
108  
-    if (opt._) {
109  
-      for (i in opt._) {
110  
-        files.push(opt._[i]);
111  
-      }
  56
+  }, function() {
  57
+    return callback(null, tmp);
  58
+  });
  59
+};
  60
+post = function(gist, callback) {
  61
+  var gistData, options, req;
  62
+  gistData = querystring.stringify(gist);
  63
+  options = {
  64
+    host: 'gist.github.com',
  65
+    port: 443,
  66
+    path: '/gists',
  67
+    method: 'POST',
  68
+    headers: {
  69
+      'Content-Type': 'application/x-www-form-urlencoded',
  70
+      'Content-Length': gistData.length
112 71
     }
113  
-    files.forEach(function(file, i, arr) {
114  
-      return path.exists(file, function(exists) {
115  
-        if (!exists) {
116  
-          anError("File not found: " + file);
117  
-        }
118  
-        gist["file_ext[gistfile" + (i + 1) + "]"] = path.extname(file);
119  
-        gist["file_name[gistfile" + (i + 1) + "]"] = path.basename(file);
120  
-        if (opt.d || opt.description) {
121  
-          gist['description'] = opt.d || opt.description;
122  
-        }
123  
-        gist["file_contents[gistfile" + (i + 1) + "]"] = fs.readFileSync(file, 'utf8');
124  
-        if (opt.p || opt.private) {
125  
-          gist['action_button'] = 'private';
126  
-        }
127  
-        if (i === arr.length - 1) {
128  
-          return emitter.emit('filesDone');
129  
-        }
130  
-      });
131  
-    });
132  
-    return emitter.on('filesDone', function() {
133  
-      if (opt.l || opt.login) {
134  
-        getCredentials();
135  
-        return emitter.on('credentials', function(user, token) {
136  
-          gist['login'] = user;
137  
-          gist['token'] = token;
138  
-          return post(gist);
139  
-        });
140  
-      } else {
141  
-        return post(gist);
142  
-      }
143  
-    });
144 72
   };
145  
-  getClip = function() {
146  
-    var clipboard, gist;
147  
-    gist = {};
148  
-    switch (os.type()) {
149  
-      case 'Darwin':
150  
-        clipboard = 'pbpaste';
151  
-        break;
152  
-      case 'Linux':
153  
-        clipboard = 'xclip -out -selection clipboard';
  73
+  req = https.request(options, function(res) {
  74
+    if (res.statusCode === 401) {
  75
+      return callback(new Error('Username or token not authorized on Github.com'));
154 76
     }
155  
-    return exec(clipboard, function(err, stdout) {
156  
-      if (stdout === '') {
157  
-        anError('Nothing in clipboard');
158  
-      }
159  
-      if (err) {
160  
-        anError('Problem getting contents of clipboard');
161  
-      }
162  
-      gist['file_ext[gistfile1]'] = path.extname(opt.c || opt.clip);
163  
-      gist['file_name[gistfile1]'] = opt.c || opt.clip;
164  
-      if (opt.d || opt.description) {
165  
-        gist['description'] = opt.d || opt.description;
166  
-      }
167  
-      gist['file_contents[gistfile1]'] = stdout;
168  
-      if (opt.p || opt.private) {
169  
-        gist['action_button'] = 'private';
170  
-      }
171  
-      if (opt.l || opt.login) {
172  
-        getCredentials();
173  
-        return emitter.on('credentials', function(user, token) {
174  
-          gist['login'] = user;
175  
-          gist['token'] = token;
176  
-          return post(gist);
177  
-        });
178  
-      } else {
179  
-        return post(gist);
180  
-      }
  77
+    return res.on('end', function() {
  78
+      return callback(null, res.headers.location);
181 79
     });
  80
+  });
  81
+  return req.end(gistData);
  82
+};
  83
+serial = function(array, iterator, next) {
  84
+  var cycle;
  85
+  cycle = function(i) {
  86
+    if (i < array.length) {
  87
+      return iterator(array[i], i, function() {
  88
+        return cycle(i + 1);
  89
+      });
  90
+    } else {
  91
+      return next();
  92
+    }
182 93
   };
183  
-  anError = function(text) {
184  
-    console.error(text);
185  
-    return process.exit(1);
186  
-  };
187  
-  usage = function() {
188  
-    return console.log('\n            Usage: ngist [options] [-f file.ext] [files...]\n            \n            -f, --file         use file(s) for gist\n            -c, --clip         use clipboard for gist\n            -d, --description  set description for gist\n            -p, --private      make private gist\n            -l, --login        use github.com credentials\n            -u, --username     github.com username\n            -t, --token        github.com API token\n            -o, --out          copy new gist url to clipboard\n            -h, --help         display this help message\n            \n            \n            Examples\n            \n            Single File\n              ngist -f file.js\n            \n            Multiple Files\n              ngist -f file.js file2.js file3.js\n            \n            Use clipboard\n              ngist -c file.js\n              \n            Set description\n              ngist -f file.js -d \'This is a description\'\n            \n            Login and set user and token\n              ngist -f file.js -l -u user -t fj920df\n              \n            Login after user and token are set\n              ngist -f file.js -l\n            \n            Private gist\n              ngist -p -f file.js\n              ');
189  
-  };
190  
-  run();
191  
-}).call(this);
  94
+  return cycle(0);
  95
+};
6  package.json
... ...
@@ -1,9 +1,9 @@
1 1
 {
2 2
     "name":         "ngist",
3  
-    "description":  "Gist CLI tool using node.js",
  3
+    "description":  "Gist module and CLI tool using node.js",
4 4
     "keywords":     ["gist", "cli", "github", "tools"],
5 5
     "author":       "Jacob Chapel <jacob.chapel@gmail.com>",
6  
-    "version":      "0.1.1",
  6
+    "version":      "0.2.0",
7 7
     "licenses":     [{
8 8
       "type":       "MIT",
9 9
       "url":        "http://github.com/chapel/ngist/raw/master/LICENSE"
@@ -20,6 +20,6 @@
20 20
     },
21 21
     "main" : "./lib/ngist",
22 22
     "bin":          {
23  
-      "ngist":       "./lib/ngist.js"
  23
+      "ngist":       "./lib/cli.js"
24 24
     }
25 25
 }
138  src/cli.coffee
... ...
@@ -0,0 +1,138 @@
  1
+os             = require 'os'
  2
+ngist          = require './ngist'
  3
+{exec}         = require 'child_process'
  4
+opt            = require('optimist').argv
  5
+
  6
+run = ->
  7
+  # Set args to the appropriate values
  8
+  opt._ = null if opt._.length is 0
  9
+  opt.help = opt.help or opt.h
  10
+  opt.clip = opt.clip or opt.c
  11
+  opt.desc = opt.desc or opt.d
  12
+  opt.private = opt.private or opt.p
  13
+  opt.user = opt.user or opt.u
  14
+  opt.token = opt.token or opt.t
  15
+  opt.out = opt.out or opt.o
  16
+  
  17
+  # Return help message if -h or --help is set
  18
+  if opt.help
  19
+    return console.log '''
  20
+    
  21
+Usage: ngist [file.js file2.js ...] [options]
  22
+
  23
+[Options]
  24
+-h, --help         Display this help page
  25
+-c, --clip         Use clipboard content
  26
+                         ex: ngist [file.js] -c file.js
  27
+-d, --desc         Set description of gist
  28
+                         ex: ngist file.js -d 'Description'
  29
+-u, --user         Github username
  30
+-t, --token        Github API token | https://github.com/account#admin_bucket
  31
+                         ex: ngist file.js -u username -t token
  32
+-p, --private      Make gist private
  33
+-o, --out          Copy gist url to clipboard
  34
+
  35
+[How to set user/token with git config]
  36
+Once you get your Github API token from https://github.com/account#admin_bucket
  37
+If you set your Github username and API token using these steps, ngist will
  38
+automatically gather them and authenticate for you.
  39
+
  40
+Run these two commands:
  41
+    git config --add github.user [github_username]
  42
+    git config --add github.token [github_api_token]
  43
+  
  44
+To verify that they have been set, use:
  45
+    git config --get github.[user/token]
  46
+'''
  47
+  
  48
+  if opt._ and opt.clip
  49
+    ngist.files opt._, (err, files) ->
  50
+      spit_error err if err
  51
+      get_clip (clip) ->
  52
+        files = files.concat clip
  53
+        next(files)
  54
+  else if opt._
  55
+    ngist.files opt._, (err, files) ->
  56
+      spit_error err if err
  57
+      next(files)
  58
+  else if opt.clip
  59
+    get_clip (clip) ->
  60
+      next clip
  61
+  else
  62
+    spit_error 'You must set file(s) and/or a clip from the clipboard (-c)'
  63
+    
  64
+
  65
+next = (files) ->
  66
+  if opt.user and opt.token
  67
+    finish files, opt.user, opt.token
  68
+  else if (opt.user and not opt.token) or (opt.token and not opt.user)
  69
+    spit_error 'Both user (-u) and token (-t) must be set if you wish to login'
  70
+  else
  71
+    get_creds files
  72
+
  73
+finish = (files, user, token) ->
  74
+  if opt.desc or opt.private or (user and token)
  75
+    options = {}
  76
+  else
  77
+    options = null
  78
+  options.private = true if opt.private
  79
+  options.description = opt.desc if opt.desc
  80
+  options.user = user if user
  81
+  options.token = token if token
  82
+  ngist.send files, options, (err, url) ->
  83
+    spit_error err if err
  84
+    set_clip url if opt.out
  85
+    console.log "Gist: #{url}"
  86
+  
  87
+get_creds = (files) ->
  88
+  keys = ['get', 'system', 'global', 'simple']
  89
+  serial keys, (key, i, _next) ->
  90
+    exec "git config --#{key} github.user", (err, stdout, stderr) ->
  91
+      unless err
  92
+        user = stdout.replace("\n", "")
  93
+        exec "git config --#{key} github.token", (err, stdout, stderr) ->
  94
+          unless err
  95
+            token = stdout.replace("\n", "")
  96
+            return finish files, user, token
  97
+      else
  98
+        _next()
  99
+  , ->
  100
+    console.log "For instructions on how to authenticate your gists: ngist -h"
  101
+    return finish files, null, null
  102
+        
  103
+set_clip = (url) ->
  104
+  switch os.type()
  105
+     when 'Darwin' then clipboard = "echo #{url} | pbcopy"
  106
+     when 'Linux' then clipboard = "echo #{url} | xclip"
  107
+ 
  108
+  exec clipboard, (err, stdout) ->
  109
+    spit_error 'Problem sending url to clipboard' if err
  110
+            
  111
+get_clip = (callback) ->
  112
+  clip = []
  113
+  switch os.type()
  114
+     when 'Darwin' then clipboard = 'pbpaste'
  115
+     when 'Linux' then clipboard = 'xclip -out -selection clipboard'
  116
+ 
  117
+  exec clipboard, (err, stdout) ->
  118
+    spit_error 'Nothing in clipboard' if stdout == ''
  119
+    spit_error 'Problem getting contents of clipboard' if err
  120
+    clip.push
  121
+      name: opt.clip
  122
+      contents: stdout
  123
+    callback clip
  124
+
  125
+spit_error = (err) ->
  126
+  console.error "#{err}\nFor more help see: ngist -h"
  127
+  process.exit 1
  128
+  
  129
+serial = (array, iterator, next) ->
  130
+  cycle = (i) ->
  131
+    if i < array.length
  132
+      iterator array[i], i, ->
  133
+        cycle i+1
  134
+    else
  135
+      next()
  136
+  cycle 0
  137
+
  138
+run()
202  src/ngist.coffee
... ...
@@ -1,58 +1,42 @@
1 1
 fs             = require 'fs'
2  
-os             = require 'os'
3 2
 path           = require 'path'
4 3
 https          = require 'https'
5 4
 querystring    = require 'querystring'
6  
-{exec}         = require 'child_process'
7  
-{EventEmitter} = require 'events'
8  
-opt            = require('optimist')
9  
-               .usage('Usage: ngist [options] [file.ext] [file...]')
10  
-               .argv
11  
-  
12  
-  
13  
-emitter = new EventEmitter
14 5
 
15  
-run = ->
16  
-  return usage() if opt.h or opt.help
17  
-  return getFiles() if (opt.f or opt.file) and not (opt.c or opt.clip)
18  
-  return getClip() if (opt.c or opt.clip) and not (opt.f or opt.file)
19  
-  
20  
-  
21  
-  anError 'You cannot use files and clipboard together.' if (opt.c or opt.clip) and (opt.f or opt.file)
22  
-  anError 'File or clipboard not specified. For help: ngist -h' unless (opt.f or opt.file) or (opt.c or opt.f)
23 6
 
24  
-    
25  
-getCredentials = ->
26  
-  if (opt.u or opt.user) and (opt.t or opt.token)
27  
-    setCredentials()
28  
-  else
29  
-    exec "git config --global github.user", (err, stdout, stderr) ->
30  
-      unless err
31  
-        user = stdout.replace("\n", "")
32  
-        exec "git config --global github.token", (err, stdout, stderr) ->
33  
-          unless err
34  
-            token = stdout.replace("\n", "")
35  
-            emitter.emit 'credentials', user, token
36  
-          else
37  
-            anError 'No token set with git.\nFor help: ngist -h'
38  
-      else
39  
-        anError 'No username or token set with git.\nFor help: ngist -h'
40  
-      
41  
-setCredentials = ->
42  
-  exec "git config --global github.user #{opt.u or opt.user}", (err, stdout, stderr) ->
43  
-    unless err
44  
-      exec "git config --global github.token #{opt.t or opt.token}", (err, stdout, stderr) ->
45  
-        emitter.emit 'credentials', (opt.u or opt.user), (opt.t or opt.token)
46  
-        
47  
-setClipboard = (url) ->
48  
-  switch os.type()
49  
-     when 'Darwin' then clipboard = "echo #{url} | pbcopy"
50  
-     when 'Linux' then clipboard = "echo #{url} | xclip"
51  
- 
52  
-  exec clipboard, (err, stdout) ->
53  
-    anError 'Problem sending url to clipboard' if err
54  
-    
55  
-post = (gist) ->
  7
+exports.send = (files, options, callback) ->
  8
+  gist = {}
  9
+  if typeof options is 'function'
  10
+    callback = options
  11
+    options = null
  12
+  return callback new Error "#{files.length} files is more than the maximum of 10 files" if files.length > 10
  13
+  files.forEach (file, i) ->
  14
+    gist["file_ext[gistfile#{i+1}]"] = path.extname file.name
  15
+    gist["file_name[gistfile#{i+1}]"] = file.name
  16
+    gist["file_contents[gistfile#{i+1}]"] = file.contents
  17
+  unless options is null
  18
+    if (options.user and not options.token) or (options.token and not options.user)
  19
+      return callback new Error 'To login both options.user and options.token must be given'
  20
+    gist['login'] = options.user if options.user
  21
+    gist['token'] = options.token if options.token
  22
+    gist['description'] = options.description if options.description
  23
+    gist['action_button'] = 'private' if options.private is true
  24
+  return post gist, callback
  25
+
  26
+exports.files = (files, callback) ->
  27
+  tmp = []
  28
+  serial files, (file, i, next) ->
  29
+    path.exists file, (exists) ->
  30
+      return callback new Error "File not found: #{file}" unless exists
  31
+      fs.readFile file, 'utf8', (err, data) ->
  32
+        tmp.push
  33
+          'name': path.basename file
  34
+          'contents': data
  35
+        next()
  36
+  , ->
  37
+    callback null, tmp
  38
+                
  39
+post = (gist, callback) ->
56 40
   gistData = querystring.stringify gist
57 41
   options = 
58 42
     host: 'gist.github.com'
@@ -62,117 +46,21 @@ post = (gist) ->
62 46
     headers:
63 47
       'Content-Type': 'application/x-www-form-urlencoded'
64 48
       'Content-Length': gistData.length
65  
-  
  49
+
66 50
   req = https.request options, (res) ->
67 51
     if res.statusCode == 401
68  
-      anError "Github.com username or token are not valid.\n
69  
-      username: #{gist.login}
70  
-      token: #{gist.token}\n
71  
-      For help: gist -h"
72  
-      process.exit 1
73  
-    
  52
+      return callback new Error 'Username or token not authorized on Github.com'
  53
+
74 54
     res.on 'end', ->
75  
-      setClipboard(res.headers.location) if opt.o or opt.out
76  
-      console.log 'Gist URL: ' + res.headers.location
77  
-    
  55
+      callback null, res.headers.location
  56
+
78 57
   req.end gistData
79 58
   
80  
-getFiles = ->
81  
-  gist = {}
82  
-  files = []
83  
-  files.push opt.f or opt.file
84  
-  if opt._
85  
-    for i of opt._
86  
-      files.push opt._[i]
87  
-  
88  
-  files.forEach (file, i, arr) ->
89  
-    path.exists file, (exists) ->
90  
-      unless exists
91  
-        anError "File not found: #{file}"
92  
-      gist["file_ext[gistfile#{i+1}]"] = path.extname file
93  
-      gist["file_name[gistfile#{i+1}]"] = path.basename file
94  
-      gist['description'] = opt.d or opt.description if opt.d or opt.description
95  
-      gist["file_contents[gistfile#{i+1}]"] = fs.readFileSync file, 'utf8'
96  
-      gist['action_button'] = 'private' if (opt.p or opt.private)
97  
-      if i == arr.length - 1 then emitter.emit 'filesDone'
98  
-  
99  
-  emitter.on 'filesDone', ->
100  
-    if opt.l or opt.login
101  
-      getCredentials()
102  
-      emitter.on 'credentials', (user, token) ->
103  
-        gist['login'] = user
104  
-        gist['token'] = token
105  
-        post gist
  59
+serial = (array, iterator, next) ->
  60
+  cycle = (i) ->
  61
+    if i < array.length
  62
+      iterator array[i], i, ->
  63
+        cycle i+1
106 64
     else
107  
-      post gist
108  
-        
109  
-getClip = ->
110  
-  gist = {}
111  
-  switch os.type()
112  
-     when 'Darwin' then clipboard = 'pbpaste'
113  
-     when 'Linux' then clipboard = 'xclip -out -selection clipboard'
114  
- 
115  
-  exec clipboard, (err, stdout) ->
116  
-    anError 'Nothing in clipboard' if stdout == ''
117  
-    anError 'Problem getting contents of clipboard' if err
118  
-    gist['file_ext[gistfile1]'] = path.extname opt.c or opt.clip
119  
-    gist['file_name[gistfile1]'] = opt.c or opt.clip
120  
-    gist['description'] = opt.d or opt.description if opt.d or opt.description
121  
-    gist['file_contents[gistfile1]'] = stdout
122  
-    gist['action_button'] = 'private' if (opt.p or opt.private)
123  
-    if opt.l or opt.login
124  
-      getCredentials()
125  
-      emitter.on 'credentials', (user, token) ->
126  
-        gist['login'] = user
127  
-        gist['token'] = token
128  
-        post gist
129  
-    else
130  
-      post gist
131  
-      
132  
-anError = (text) ->
133  
-  console.error text
134  
-  process.exit 1
135  
-
136  
-
137  
-usage = ->
138  
-  console.log '''
139  
-  
140  
-              Usage: ngist [options] [-f file.ext] [files...]
141  
-              
142  
-              -f, --file         use file(s) for gist
143  
-              -c, --clip         use clipboard for gist
144  
-              -d, --description  set description for gist
145  
-              -p, --private      make private gist
146  
-              -l, --login        use github.com credentials
147  
-              -u, --username     github.com username
148  
-              -t, --token        github.com API token
149  
-              -o, --out          copy new gist url to clipboard
150  
-              -h, --help         display this help message
151  
-              
152  
-              
153  
-              Examples
154  
-              
155  
-              Single File
156  
-                ngist -f file.js
157  
-              
158  
-              Multiple Files
159  
-                ngist -f file.js file2.js file3.js
160  
-              
161  
-              Use clipboard
162  
-                ngist -c file.js
163  
-                
164  
-              Set description
165  
-                ngist -f file.js -d 'This is a description'
166  
-              
167  
-              Login and set user and token
168  
-                ngist -f file.js -l -u user -t fj920df
169  
-                
170  
-              Login after user and token are set
171  
-                ngist -f file.js -l
172  
-              
173  
-              Private gist
174  
-                ngist -p -f file.js
175  
-                
176  
-              '''
177  
-
178  
-run()
  65
+      next()
  66
+  cycle 0

0 notes on commit 2e9e016

Please sign in to comment.
Something went wrong with that request. Please try again.