gisty 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +49 -0
- data/Rakefile +118 -0
- data/bin/gisty +119 -0
- data/lib/gisty.rb +194 -0
- data/test/fixtures/24835 +241 -0
- data/test/fixtures/30119 +376 -0
- data/test/fixtures/bar.user.js +1 -0
- data/test/fixtures/foo.user.js +1 -0
- data/test/fixtures/mine_login_foo_token_bar +494 -0
- data/test/fixtures/mine_page_1_login_foo_token_bar +518 -0
- data/test/fixtures/mine_page_2_login_foo_token_bar +511 -0
- data/test/fixtures/mine_page_3_login_foo_token_bar +190 -0
- data/test/fixtures/swdyh +302 -0
- data/test/fixtures/swdyh_page_4 +178 -0
- data/test/gisty_test.rb +175 -0
- data/test/test_helper.rb +3 -0
- metadata +88 -0
data/README.rdoc
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
= gisty
|
3
|
+
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
yet another command line client for gist
|
8
|
+
|
9
|
+
== Installation
|
10
|
+
|
11
|
+
=== Gem Installation
|
12
|
+
|
13
|
+
gem sources -a http://gems.github.com (you only have to do this once)
|
14
|
+
sudo gem install swdyh-gisty
|
15
|
+
|
16
|
+
set environment variable GISTY_DIR.
|
17
|
+
example .zshrc
|
18
|
+
|
19
|
+
export GISTY_DIR="$HOME/dev/gists"
|
20
|
+
|
21
|
+
set global git config. see "Global Git Config" at https://github.com/account
|
22
|
+
|
23
|
+
git config --global github.user your_id
|
24
|
+
git config --global github.token your_token
|
25
|
+
|
26
|
+
if you use zsh command completion, download this file to $fpath directory.
|
27
|
+
http://github.com/swdyh/gisty/raw/master/_gisty
|
28
|
+
|
29
|
+
|
30
|
+
== Features/Problems
|
31
|
+
|
32
|
+
use API token with HTTP. at your own risk.
|
33
|
+
|
34
|
+
== Synopsis
|
35
|
+
|
36
|
+
gisty list show local list.
|
37
|
+
gisty post file1 file2 ... post new gist.
|
38
|
+
gisty private_post file1 file2 ... post new private gist.
|
39
|
+
gisty sync sync remote gist. (clone all remote gist)
|
40
|
+
gisty sync_delete sync remote gist. delete local gist if remote gist was deleted.
|
41
|
+
gisty pull_all pull all gist.
|
42
|
+
gisty about show about gisty
|
43
|
+
gisty help show help
|
44
|
+
|
45
|
+
== Copyright
|
46
|
+
|
47
|
+
Author:: swdyh <http://mailhide.recaptcha.net/d?k=01AhB7crgrlHptVaYRD0oPwA==&c=L_iqOZrGmo6hcGpPTFg1QYnjr-WpAStyQ4Y8ShfgOHs=>
|
48
|
+
Copyright:: Copyright (c) 2008 swdyh
|
49
|
+
License:: MIT
|
data/Rakefile
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/rdoctask'
|
8
|
+
require 'rake/contrib/rubyforgepublisher'
|
9
|
+
require 'rake/contrib/sshpublisher'
|
10
|
+
require 'fileutils'
|
11
|
+
require 'lib/gisty'
|
12
|
+
include FileUtils
|
13
|
+
|
14
|
+
NAME = "gisty"
|
15
|
+
AUTHOR = "swdyh"
|
16
|
+
EMAIL = "http://mailhide.recaptcha.net/d?k=01AhB7crgrlHptVaYRD0oPwA==&c=L_iqOZrGmo6hcGpPTFg1QYnjr-WpAStyQ4Y8ShfgOHs="
|
17
|
+
DESCRIPTION = "yet another command line client for gist"
|
18
|
+
RUBYFORGE_PROJECT = "gisty"
|
19
|
+
HOMEPATH = "http://github.com/swdyh/gisty/tree/master"
|
20
|
+
BIN_FILES = %w( gisty )
|
21
|
+
|
22
|
+
VERS = Gisty::VERSION
|
23
|
+
REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
|
24
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config', '*.gemspec']
|
25
|
+
RDOC_OPTS = [
|
26
|
+
'--title', "#{NAME} documentation",
|
27
|
+
"--charset", "utf-8",
|
28
|
+
"--line-numbers",
|
29
|
+
"--main", "README.rdoc",
|
30
|
+
"--inline-source",
|
31
|
+
]
|
32
|
+
|
33
|
+
task :default => [:test]
|
34
|
+
task :package => [:clean]
|
35
|
+
|
36
|
+
Rake::TestTask.new("test") do |t|
|
37
|
+
t.libs << "test"
|
38
|
+
t.pattern = "test/**/*_test.rb"
|
39
|
+
t.verbose = true
|
40
|
+
end
|
41
|
+
|
42
|
+
spec = Gem::Specification.new do |s|
|
43
|
+
s.name = NAME
|
44
|
+
s.version = VERS
|
45
|
+
s.platform = Gem::Platform::RUBY
|
46
|
+
s.has_rdoc = true
|
47
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
48
|
+
s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
|
49
|
+
s.summary = DESCRIPTION
|
50
|
+
s.description = DESCRIPTION
|
51
|
+
s.author = AUTHOR
|
52
|
+
s.email = EMAIL
|
53
|
+
s.homepage = HOMEPATH
|
54
|
+
s.executables = BIN_FILES
|
55
|
+
s.rubyforge_project = RUBYFORGE_PROJECT
|
56
|
+
s.bindir = "bin"
|
57
|
+
s.require_path = "lib"
|
58
|
+
#s.autorequire = ""
|
59
|
+
s.test_files = Dir["test/*_test.rb"]
|
60
|
+
|
61
|
+
#s.add_dependency('activesupport', '>=1.3.1')
|
62
|
+
s.add_dependency('nokogiri', '>=1.0.0')
|
63
|
+
#s.required_ruby_version = '>= 1.8.2'
|
64
|
+
|
65
|
+
s.files = %w(README.rdoc Rakefile) +
|
66
|
+
Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
|
67
|
+
Dir.glob("ext/**/*.{h,c,rb}") +
|
68
|
+
Dir.glob("examples/**/*.rb") +
|
69
|
+
Dir.glob("tools/*.rb") +
|
70
|
+
Dir.glob("rails/*.rb")
|
71
|
+
|
72
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
Rake::GemPackageTask.new(spec) do |p|
|
77
|
+
p.need_tar = true
|
78
|
+
p.gem_spec = spec
|
79
|
+
end
|
80
|
+
|
81
|
+
Rake::RDocTask.new do |rdoc|
|
82
|
+
rdoc.rdoc_dir = 'html'
|
83
|
+
rdoc.options += RDOC_OPTS
|
84
|
+
rdoc.template = "resh"
|
85
|
+
#rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
86
|
+
if ENV['DOC_FILES']
|
87
|
+
rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
|
88
|
+
else
|
89
|
+
rdoc.rdoc_files.include('README.rdoc')
|
90
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
91
|
+
rdoc.rdoc_files.include('ext/**/*.c')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
desc 'Update gem spec'
|
96
|
+
task :gemspec do
|
97
|
+
open("#{NAME}.gemspec", 'w') { |f| f.puts spec.to_ruby }
|
98
|
+
end
|
99
|
+
|
100
|
+
desc 'gem build'
|
101
|
+
task :build_gem => [:gemspec] do
|
102
|
+
sh "gem build #{NAME}.gemspec"
|
103
|
+
end
|
104
|
+
|
105
|
+
desc 'refresh fixtures'
|
106
|
+
task :reflresh_fixtures do
|
107
|
+
g = Gisty.new 'tmp'
|
108
|
+
re = /page=\d+/
|
109
|
+
urls = g.map_pages do |url, page|
|
110
|
+
m = url.match re
|
111
|
+
if m
|
112
|
+
fn = 'mine_' + m.to_a.first.sub('=', '_') + '_login_foo_token_bar'
|
113
|
+
path = File.join 'test', 'fixtures', fn
|
114
|
+
puts "write #{path}"
|
115
|
+
open(path, 'w') { |f| f.write page.gsub(/(&)?(login|token)=\w+(&)?/, '') }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/bin/gisty
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'gisty'
|
5
|
+
|
6
|
+
@cmds = {}
|
7
|
+
|
8
|
+
def cmd name
|
9
|
+
@cmds[name.to_s] = Proc.new { |i| yield i }
|
10
|
+
end
|
11
|
+
|
12
|
+
cmd :about do
|
13
|
+
puts Gisty::AA
|
14
|
+
puts
|
15
|
+
puts 'version: ' + Gisty::VERSION
|
16
|
+
puts 'url: ' + Gisty::GISTY_URL
|
17
|
+
end
|
18
|
+
|
19
|
+
cmd :help do
|
20
|
+
puts <<-EOS
|
21
|
+
usage:
|
22
|
+
gisty commands
|
23
|
+
commands:
|
24
|
+
gisty list show local list.
|
25
|
+
gisty post file1 file2 ... post new gist.
|
26
|
+
gisty private_post file1 file2 ... post new private gist.
|
27
|
+
gisty sync sync remote gist. (clone all remote gist)
|
28
|
+
gisty sync_delete sync remote gist. delete local gist if remote gist was deleted.
|
29
|
+
gisty pull_all pull all gist.
|
30
|
+
gisty about show about gisty
|
31
|
+
gisty help show help
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
|
35
|
+
cmd :list do
|
36
|
+
list = @g.list
|
37
|
+
puts '- public gist -'
|
38
|
+
list[:public].each do |i|
|
39
|
+
puts "#{i[0]}: #{i[1].join(' ')}"
|
40
|
+
end
|
41
|
+
puts '- private gist -'
|
42
|
+
list[:private].each do |i|
|
43
|
+
puts "#{i[0]}: #{i[1].join(' ')}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
cmd :sync do
|
48
|
+
@g.sync
|
49
|
+
puts '---'
|
50
|
+
puts 'sync finished.'
|
51
|
+
end
|
52
|
+
|
53
|
+
cmd :sync_delete do
|
54
|
+
@g.sync true
|
55
|
+
puts '---'
|
56
|
+
puts 'sync finished.'
|
57
|
+
end
|
58
|
+
|
59
|
+
cmd :pull_all do
|
60
|
+
@g.pull_all
|
61
|
+
puts '---'
|
62
|
+
puts 'pull_all finished.'
|
63
|
+
end
|
64
|
+
|
65
|
+
cmd :post do |fs|
|
66
|
+
if fs.size > 0
|
67
|
+
begin
|
68
|
+
url = @g.create fs
|
69
|
+
rescue Gisty::InvalidFileException => e
|
70
|
+
puts "Error: invalid file"
|
71
|
+
rescue Exception => e
|
72
|
+
puts "Error: #{e}"
|
73
|
+
else
|
74
|
+
id = url.split('/').last
|
75
|
+
@g.clone id
|
76
|
+
system "open #{url}" if /darwin/ === RUBY_PLATFORM
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
cmd :private_post do |fs|
|
82
|
+
if fs.size > 0
|
83
|
+
begin
|
84
|
+
url = @g.create fs, :private => true
|
85
|
+
rescue Exception => e
|
86
|
+
puts "Error: #{e}"
|
87
|
+
else
|
88
|
+
system "open #{url}" if /darwin/ === RUBY_PLATFORM
|
89
|
+
id = url.split('/').last
|
90
|
+
@g.clone id
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
if ENV['GISTY_DIR']
|
97
|
+
begin
|
98
|
+
@g = Gisty.new ENV['GISTY_DIR']
|
99
|
+
rescue Gisty::UnsetAuthInfoException => e
|
100
|
+
puts 'Error: set your api token.'
|
101
|
+
puts 'see Global Git Config at https://github.com/account'
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
else
|
105
|
+
puts "Error: please set ENV['GISTY_DIR']"
|
106
|
+
exit
|
107
|
+
end
|
108
|
+
|
109
|
+
if ARGV.size == 0
|
110
|
+
@cmds['help'].call []
|
111
|
+
else
|
112
|
+
c = @cmds[ARGV.first]
|
113
|
+
if c
|
114
|
+
c.call ARGV.last(ARGV.size - 1)
|
115
|
+
else
|
116
|
+
puts 'unknown commands.'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
data/lib/gisty.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'net/http'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'nokogiri'
|
7
|
+
|
8
|
+
class Gisty
|
9
|
+
VERSION = '0.0.15'
|
10
|
+
GIST_URL = 'http://gist.github.com/'
|
11
|
+
GISTY_URL = 'http://github.com/swdyh/gisty/tree/master'
|
12
|
+
|
13
|
+
class UnsetAuthInfoException < Exception
|
14
|
+
end
|
15
|
+
|
16
|
+
class InvalidFileException < Exception
|
17
|
+
end
|
18
|
+
|
19
|
+
class PostFailureException < Exception
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.extract_ids str
|
23
|
+
doc = Nokogiri::HTML str
|
24
|
+
doc.css('.file .info a').map { |i| i['href'].sub('/', '') }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.extract url
|
28
|
+
doc = Nokogiri::HTML open(url)
|
29
|
+
{
|
30
|
+
:id => url.split('/').last,
|
31
|
+
:author => doc.css('#owner a').inner_text,
|
32
|
+
:files => doc.css('.meta .info').map { |i| i.inner_text.strip },
|
33
|
+
:clone => doc.css('a[rel="#git-clone"]').inner_text,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize path, login = nil, token = nil
|
38
|
+
@auth = (login && token) ? { 'login' => login, 'token' => token } : auth
|
39
|
+
raise UnsetAuthInfoException if @auth['login'].nil? || @auth['token'].nil?
|
40
|
+
@auth_query = "login=#{@auth['login']}&token=#{@auth['token']}"
|
41
|
+
@dir = Pathname.pwd.realpath.join path
|
42
|
+
FileUtils.mkdir_p @dir unless @dir.exist?
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_link str
|
46
|
+
doc = Nokogiri::HTML str
|
47
|
+
a = doc.at('.pagination a[hotkey="l"]')
|
48
|
+
a ? a['href'] : nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def map_pages
|
52
|
+
result = []
|
53
|
+
base_url = GIST_URL.sub(/\/$/, '')
|
54
|
+
path = "/mine?page=1"
|
55
|
+
loop do
|
56
|
+
url = base_url + path + "&#{@auth_query}"
|
57
|
+
page = open(url).read
|
58
|
+
result << yield(url, page)
|
59
|
+
path = next_link page
|
60
|
+
break unless path
|
61
|
+
end
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
def remote_ids
|
66
|
+
map_pages { |url, page| Gisty.extract_ids page }.flatten.uniq.sort
|
67
|
+
end
|
68
|
+
|
69
|
+
def clone id
|
70
|
+
FileUtils.cd @dir do
|
71
|
+
c = "git clone git@gist.github.com:#{id}.git"
|
72
|
+
Kernel.system c
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def list
|
77
|
+
dirs = Pathname.glob(@dir.to_s + '/*').map do |i|
|
78
|
+
[i.basename.to_s,
|
79
|
+
Pathname.glob(i.to_s + '/*').map { |i| i.basename.to_s }]
|
80
|
+
end
|
81
|
+
re_pub = /^\d+$/
|
82
|
+
pub = dirs.select { |i| re_pub.match(i.first) }.sort_by { |i| i.first.to_i }.reverse
|
83
|
+
pri = dirs.select { |i| !re_pub.match(i.first) }.sort_by { |i| i.first }
|
84
|
+
{ :public => pub, :private => pri }
|
85
|
+
end
|
86
|
+
|
87
|
+
def local_ids
|
88
|
+
dirs = Pathname.glob(@dir.to_s + '/*')
|
89
|
+
dirs.map { |i| i.basename.to_s }
|
90
|
+
end
|
91
|
+
|
92
|
+
def delete id
|
93
|
+
FileUtils.rm_rf @dir.join(id) if @dir.join(id).exist?
|
94
|
+
end
|
95
|
+
|
96
|
+
def sync delete = false
|
97
|
+
remote = remote_ids
|
98
|
+
local = local_ids
|
99
|
+
|
100
|
+
if delete
|
101
|
+
(local - remote).each do |id|
|
102
|
+
print "delete #{id}? [y/n]"
|
103
|
+
confirm = $stdin.gets.strip
|
104
|
+
if confirm == 'y' || confirm == 'yes'
|
105
|
+
puts "delete #{id}"
|
106
|
+
delete id
|
107
|
+
else
|
108
|
+
puts "skip #{id}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
ids = remote
|
112
|
+
else
|
113
|
+
ids = (remote + local).uniq
|
114
|
+
end
|
115
|
+
|
116
|
+
FileUtils.cd @dir do
|
117
|
+
ids.each do |id|
|
118
|
+
if File.exist? id
|
119
|
+
# FileUtils.cd id do
|
120
|
+
# c = "git pull"
|
121
|
+
# Kernel.system c
|
122
|
+
# end
|
123
|
+
else
|
124
|
+
c = "git clone git@gist.github.com:#{id}.git"
|
125
|
+
Kernel.system c
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def pull_all
|
132
|
+
ids = local_ids
|
133
|
+
FileUtils.cd @dir do
|
134
|
+
ids.each do |id|
|
135
|
+
if File.exist? id
|
136
|
+
FileUtils.cd id do
|
137
|
+
c = "git pull"
|
138
|
+
Kernel.system c
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def auth
|
146
|
+
user = `git config --global github.user`.strip
|
147
|
+
token = `git config --global github.token`.strip
|
148
|
+
user.empty? ? {} : { 'login' => user, 'token' => token }
|
149
|
+
end
|
150
|
+
|
151
|
+
def post params
|
152
|
+
url = URI.parse('http://gist.github.com/gists')
|
153
|
+
res = Net::HTTP.post_form(url, params)
|
154
|
+
if res['Location']
|
155
|
+
res['Location']
|
156
|
+
else
|
157
|
+
raise PostFailureException, res.inspect
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def build_params paths
|
162
|
+
list = (Array === paths ? paths : [paths]).map { |i| Pathname.new i }
|
163
|
+
raise InvalidFileException if list.any?{ |i| !i.file? }
|
164
|
+
|
165
|
+
params = {}
|
166
|
+
list.each_with_index do |i, index|
|
167
|
+
params["file_ext[gistfile#{index + 1}]"] = i.extname
|
168
|
+
params["file_name[gistfile#{index + 1}]"] = i.basename.to_s
|
169
|
+
params["file_contents[gistfile#{index + 1}]"] = IO.read(i)
|
170
|
+
end
|
171
|
+
params
|
172
|
+
end
|
173
|
+
|
174
|
+
def create paths, opt = { :private => false }
|
175
|
+
params = build_params paths
|
176
|
+
if opt[:private]
|
177
|
+
params['private'] = 'on'
|
178
|
+
params['action_button'] = 'private'
|
179
|
+
end
|
180
|
+
post params.merge(auth)
|
181
|
+
end
|
182
|
+
|
183
|
+
# `figlet -f contributed/bdffonts/clb8x8.flf gisty`.gsub('#', 'm')
|
184
|
+
AA = <<-EOS
|
185
|
+
mm mm
|
186
|
+
mm
|
187
|
+
mmmmmm mmmm mmmmm mmmmmm mm mm
|
188
|
+
mm mm mm mm mm mm mm
|
189
|
+
mm mm mm mmmm mm mm mm
|
190
|
+
mmmmmm mm mm mm mmmmm
|
191
|
+
mm mmmmmm mmmmm mmm mm
|
192
|
+
mmmmm mmmm
|
193
|
+
EOS
|
194
|
+
end
|