wycats-textmate 0.9.2 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/Rakefile +1 -1
  2. data/bin/textmate +108 -62
  3. metadata +7 -5
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require 'rake/gempackagetask'
3
3
  require 'date'
4
4
 
5
5
  GEM = "textmate"
6
- GEM_VERSION = "0.9.2"
6
+ GEM_VERSION = "0.9.6"
7
7
  AUTHOR = "Yehuda Katz"
8
8
  EMAIL = "wycats@gmail.com"
9
9
  HOMEPAGE = "http://yehudakatz.com"
data/bin/textmate CHANGED
@@ -5,17 +5,18 @@ require "rubygems"
5
5
  require "thor"
6
6
  require "open-uri"
7
7
  require "yaml"
8
+ require "cgi"
8
9
 
9
10
  class TextmateInstaller < Thor
10
-
11
+
11
12
  # CHANGED: renamed list to remote. Could there be a better name?
12
- desc "remote [SEARCH]", "Lists all the matching remote bundles"
13
- def remote(search_term = "")
13
+ desc "search [SEARCH]", "Lists all the matching remote bundles"
14
+ def search(search_term = "")
14
15
  search_term = Regexp.new(".*#{search_term}.*", "i")
15
-
16
- remote_bundle_locations.each do |name,location|
16
+
17
+ REMOTE_LOCATIONS.each do |name,location|
17
18
  puts "\n" << name.to_s << " Remote Bundles\n" << name.to_s.gsub(/./,'-') << '---------------'
18
-
19
+
19
20
  results = case location[:scm]
20
21
  when :svn
21
22
  %x[svn list #{e_sh location[:url]}].map {|x| x.split(".")[0]}.select {|x| x =~ search_term}.join("\n")
@@ -26,50 +27,53 @@ class TextmateInstaller < Thor
26
27
  "%s (by %s)" %
27
28
  [
28
29
  normalize_github_repo_name(result['name']).split('.').first,
29
- result['url'][/github\.com\/([a-zA-Z0-9]+)\//, 1] # Extract the username out of the repo URL
30
+ result['username']
30
31
  ]
31
32
  }
32
33
  end
33
-
34
+
34
35
  puts results
35
36
  end
36
37
  end
37
-
38
+
38
39
  desc "list [SEARCH]", "lists all the bundles installed locally"
39
40
  def list(search_term = "")
40
41
  search_term = Regexp.new(".*#{search_term}.*", "i")
41
-
42
+
42
43
  local_bundle_paths.each do |name,bundles_path|
43
44
  puts "\n" << name.to_s << " Bundles\n" << name.to_s.gsub(/./,'-') << '--------'
44
45
  puts Dir["#{e_sh bundles_path}/*.tmbundle"].map {|x| x.split("/").last.split(".").first}.
45
46
  select {|x| x =~ search_term}.join("\n")
46
47
  end
47
48
  end
48
-
49
- desc "install NAME [SOURCE]", "install a bundle"
50
- def install(bundle_name, remote_bundle_location_name=nil)
49
+
50
+ desc "install NAME", "Install a bundle. Source must be one of trunk, review, or github. \n" \
51
+ "If multiple gems with the same name exist, you will be prompted to \n" \
52
+ "choose from the available list."
53
+ method_option :source
54
+ def install(bundle_name)
51
55
  FileUtils.mkdir_p install_bundles_path
52
56
  puts "Checking out #{bundle_name}..."
53
-
57
+
54
58
  # CHANGED: It's faster to just try and fail for each repo than to search them all first
55
59
  installed=false
56
- remote_bundle_locations.each do |remote_name,location|
57
- next unless remote_name.to_s.downcase.include? remote_bundle_location_name.to_s.downcase if remote_bundle_location_name
58
-
60
+ REMOTE_LOCATIONS.each do |remote_name,location|
61
+ next unless remote_bundle(options["source"]) == location if options.key?("source")
62
+
59
63
  cmd = case location[:scm]
60
64
  when :git
61
65
  'echo "git remotes not implemented yet"'
62
66
  when :svn
63
- %[svn co #{e_sh location[:url]}/#{e_sh bundle_name}.tmbundle #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
67
+ %[svn co "#{location[:url]}/#{url_escape bundle_name}.tmbundle" #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
64
68
  when :github
65
69
  repos = find_github_bundles(denormalize_github_repo_name(bundle_name))
66
-
70
+
67
71
  # Handle possible multiple Repos with the same name
68
72
  case repos.size
69
73
  when 0
70
74
  'echo "Sorry, no such bundle found"'
71
75
  when 1
72
- %[git clone #{e_sh repos.first['url'].sub('http', 'git') + '.git'} #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
76
+ git_clone(repos.first["username"], repos.first["name"])
73
77
  else
74
78
  puts "Multiple bundles with that name found. Please choose which one you want to install:"
75
79
  repos.each_with_index {|repo, idx|
@@ -77,49 +81,57 @@ class TextmateInstaller < Thor
77
81
  [
78
82
  idx + 1,
79
83
  normalize_github_repo_name(repo['name']),
80
- repo['url'][/github\.com\/([a-zA-Z0-9]+)\//, 1]
84
+ repo['username']
81
85
  ]
82
86
  }
83
87
  print "Your choice: "
84
-
88
+
85
89
  # Since to_i defaults to 0, we have to use Integer
86
90
  choice = Integer(STDIN.gets.chomp) rescue nil
87
91
  until choice && (0...repos.size).include?( choice - 1 ) do
88
92
  print "Sorry, invalid choice. Please enter a valid number or Ctrl+C to stop: "
89
93
  choice = Integer(STDIN.gets.chomp) rescue nil
90
94
  end
91
-
92
- %[git clone #{e_sh repos[choice - 1]['url'].sub('http', 'git') + '.git'} #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
95
+
96
+ git_clone(repos[choice - 1]["username"], repos[choice - 1]["name"])
93
97
  end
94
98
  end
95
-
99
+
96
100
  res = %x{#{cmd}}
97
-
101
+
98
102
  puts cmd, res.gsub(/^/,' ')
99
-
103
+
100
104
  installed=true and break if res =~ /Checked out revision|Initialized empty Git repository/
101
105
  end
102
106
  abort 'Not Installed' unless installed
103
-
107
+
104
108
  reload :verbose => true
105
109
  end
106
110
 
107
111
  desc "uninstall NAME", "uninstall a bundle"
108
112
  def uninstall(bundle_name)
113
+ removed = false
114
+
109
115
  puts "Removing bundle..."
110
- # When moving to the trash, maybe move the bundle into a trash/disabled_bundles subfolder
111
- # named as the bundles_path key. Just in case there are multiple versions of
116
+ # When moving to the trash, maybe move the bundle into a trash/disabled_bundles subfolder
117
+ # named as the bundles_path key. Just in case there are multiple versions of
112
118
  # the same bundle in multiple bundle paths
113
119
  local_bundle_paths.each do |name,bundles_path|
114
120
  bundle_path = "#{bundles_path}/#{bundle_name}.tmbundle"
115
121
  if File.exist? bundle_path
122
+ removed = true
116
123
  %x[osascript -e 'tell application "Finder" to move the POSIX file "#{bundle_path}" to trash']
117
124
  end
118
125
  end
119
-
120
- reload :verbose => true
126
+
127
+ unless removed
128
+ say "There is no bundle by that name in the system", :red
129
+ exit
130
+ else
131
+ reload :verbose => true
132
+ end
121
133
  end
122
-
134
+
123
135
  desc "reload", "Reloads TextMate Bundles"
124
136
  method_options :verbose => :boolean
125
137
  def reload(opts = {})
@@ -127,18 +139,24 @@ class TextmateInstaller < Thor
127
139
  %x[osascript -e 'tell app "TextMate" to reload bundles']
128
140
  puts "Done." if opts[:verbose]
129
141
  end
130
-
142
+
131
143
  private
132
- def remote_bundle_locations
133
- { :'Macromates Trunk' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Bundles'},
134
- :'Macromates Review' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Review/Bundles'},
135
-
144
+ REMOTE_LOCATIONS =
145
+ { :'Macromates Trunk' => {:scm => :svn, :url => 'http://svn.textmate.org/trunk/Bundles'},
146
+ :'Macromates Review' => {:scm => :svn, :url => 'http://svn.textmate.org/trunk/Review/Bundles'},
147
+
136
148
  # :'Bunch of Git Bundles' => {:scm => :git, :url => 'git://NotImplemented'},
137
-
149
+
138
150
  :'GitHub' => {:scm => :github, :url => 'http://github.com/search?q=tmbundle'},
139
151
  }
152
+
153
+ SHORT_LOCATIONS = {:trunk => :"Macromates Trunk", :review => :"Macromates Review", :github => :"GitHub"}
154
+
155
+ def remote_bundle(name)
156
+ name = name.to_sym
157
+ REMOTE_LOCATIONS[name] || REMOTE_LOCATIONS[SHORT_LOCATIONS[name]]
140
158
  end
141
-
159
+
142
160
  def local_bundle_paths
143
161
  { :Application => '/Applications/TextMate.app/Contents/SharedSupport/Bundles',
144
162
  :User => "#{ENV["HOME"]}/Library/Application Support/TextMate/Bundles",
@@ -147,48 +165,76 @@ class TextmateInstaller < Thor
147
165
  :'System Pristine' => '/Library/Application Support/TextMate/Pristine Copy/Bundles',
148
166
  }
149
167
  end
150
-
168
+
151
169
  def install_bundles_path
152
170
  local_bundle_paths[:'User Pristine']
153
171
  end
154
-
172
+
155
173
  # Copied from http://macromates.com/svn/Bundles/trunk/Support/lib/escape.rb
156
174
  # escape text to make it useable in a shell script as one “word” (string)
157
175
  def e_sh(str)
158
176
  str.to_s.gsub(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/, '\\').gsub(/\n/, "'\n'").sub(/^$/, "''")
159
177
  end
160
-
178
+
179
+ def url_escape(str)
180
+ chars = ((33...47).to_a + (94...96).to_a + (123...126).to_a).map {|c| c.chr }.join + "\\[\\]\\\\"
181
+ str = str.to_s.gsub(%r{[#{chars}]}) {|m| CGI.escape(m) }
182
+ end
183
+
161
184
  CAPITALIZATION_EXCEPTIONS = %w[tmbundle on]
162
185
  # Convert a GitHub repo name into a "normal" TM bundle name
163
186
  # e.g. ruby-on-rails-tmbundle => Ruby on Rails.tmbundle
164
187
  def normalize_github_repo_name(name)
165
- name = name.gsub("-", " ").split.each{|part| part.capitalize! unless CAPITALIZATION_EXCEPTIONS.include? part}.join(" ")
188
+ name = name.gsub(/[\-\.]/, " ").split.each{|part| part.capitalize! unless CAPITALIZATION_EXCEPTIONS.include? part}.join(" ")
166
189
  name[-9] = ?. if name =~ / tmbundle$/
167
190
  name
168
191
  end
169
-
192
+
170
193
  # Does the opposite of normalize_github_repo_name
171
194
  def denormalize_github_repo_name(name)
172
- name += " tmbundle" unless name =~ / tmbundle$/
173
- name.split(' ').each{|part| part.downcase!}.join(' ').gsub(' ', '-')
195
+ name = name.split(' ').each{|part| part.downcase!}.join(' ').gsub(' ', '-')
196
+ name += ".tmbundle" unless name =~ /.tmbundle$/
197
+ name
174
198
  end
175
-
199
+
176
200
  def find_github_bundles(search_term)
177
- YAML.load(open('http://github.com/api/v1/yaml/search/tmbundle'))['repositories'].
178
- find_all{|result| result['name'].match(search_term)}.
179
- sort{|a,b| a['name'] <=> b['name']}
201
+ # Until GitHub fixes http://support.github.com/discussions/feature-requests/11-api-search-results,
202
+ # we need to account for multiple pages of results:
203
+ page = 1
204
+ repositories = YAML.load(open("http://github.com/api/v1/yaml/search/tmbundle?start_value=#{page}"))['repositories']
205
+ results = []
206
+ until repositories.empty?
207
+ results += repositories.find_all{|result| result['name'].match(search_term)}
208
+ page += 1
209
+ repositories = YAML.load(open("http://github.com/api/v1/yaml/search/tmbundle?start_value=#{page}"))['repositories']
210
+ end
211
+ results.sort{|a,b| a['name'] <=> b['name']}
212
+ end
213
+
214
+ def git_clone(repo, name)
215
+ bundle_name = normalize_github_repo_name(name)
216
+
217
+ path = "#{install_bundles_path}/#{bundle_name}"
218
+ escaped_path = "#{e_sh(install_bundles_path)}/#{e_sh(bundle_name)}"
219
+
220
+ if File.directory?(path)
221
+ say "Sorry, that bundle is already installed. Please uninstall it first.", :red
222
+ exit
223
+ end
224
+
225
+ %[git clone "git://github.com/#{url_escape(repo)}/#{url_escape(name)}.git" #{escaped_path} 2>&1]
180
226
  end
181
-
227
+
182
228
  end
183
229
 
184
230
  # TODO: create a "monument to personal cleverness" by class-izing everything?
185
231
  # class TextMateBundle
186
232
  # def self.find_local(bundle_name)
187
- #
233
+ #
188
234
  # end
189
- #
235
+ #
190
236
  # def self.find_remote(bundle_name)
191
- #
237
+ #
192
238
  # end
193
239
  # attr_reader :name
194
240
  # attr_reader :location
@@ -198,20 +244,20 @@ end
198
244
  # @location = location
199
245
  # @scm = scm
200
246
  # end
201
- #
247
+ #
202
248
  # def install!
203
- #
249
+ #
204
250
  # end
205
- #
251
+ #
206
252
  # def uninstall!
207
- #
253
+ #
208
254
  # end
209
- #
210
- #
255
+ #
256
+ #
211
257
  # def installed?
212
258
  # # List all the installed versions, and where they're at
213
259
  # end
214
- #
260
+ #
215
261
  # # TODO: dirty? method to show if there are any deltas
216
262
  # end
217
263
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wycats-textmate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,11 +9,12 @@ autorequire: textmate
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-28 00:00:00 -07:00
12
+ date: 2009-08-03 00:00:00 -07:00
13
13
  default_executable: textmate
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: thor
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements:
@@ -35,8 +36,9 @@ files:
35
36
  - README.markdown
36
37
  - Rakefile
37
38
  - bin/textmate
38
- has_rdoc: true
39
+ has_rdoc: false
39
40
  homepage: http://yehudakatz.com
41
+ licenses:
40
42
  post_install_message:
41
43
  rdoc_options: []
42
44
 
@@ -57,9 +59,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
57
59
  requirements: []
58
60
 
59
61
  rubyforge_project:
60
- rubygems_version: 1.0.1
62
+ rubygems_version: 1.3.5
61
63
  signing_key:
62
- specification_version: 2
64
+ specification_version: 3
63
65
  summary: Command-line textmate package manager
64
66
  test_files: []
65
67