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.
@@ -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
@@ -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(/(&amp;)?(login|token)=\w+(&amp;)?/, '') }
116
+ end
117
+ end
118
+ end
@@ -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
+
@@ -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