ddollar-textmate 0.9.4

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.
Files changed (5) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +41 -0
  3. data/Rakefile +46 -0
  4. data/bin/textmate +236 -0
  5. metadata +66 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Yehuda Katz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,41 @@
1
+ # textmate
2
+
3
+ A binary that provides package management for TextMate.
4
+
5
+ # Usage
6
+
7
+ `textmate [COMMAND] [*PARAMS]`
8
+
9
+ Textmate bundles are automatically reloaded after install or uninstall operations.
10
+
11
+ ## List available remote bundles
12
+
13
+ `textmate remote [SEARCH]`
14
+
15
+ List all of the available bundles in the remote repository, optionally filtering by `search`.
16
+
17
+ ## List installed bundles
18
+
19
+ `textmate list [SEARCH]`
20
+
21
+ List all of the bundles that are installed on the local system, optionally filtering by `search`.
22
+
23
+ ## Installing new bundles
24
+
25
+ `textmate install NAME [SOURCE]`
26
+
27
+ Installs a bundle from the remote repository. SOURCE filters known remote bundle locations.
28
+ For example, if you want to install the "Ruby on Rails" bundle off GitHub, you'd type the following:
29
+
30
+ `textmate install "Ruby on Rails" GitHub`
31
+
32
+ Available remote bundle locations are:
33
+ * Macromates Trunk
34
+ * Macromates Review
35
+ * GitHub
36
+
37
+ ## Uninstalling bundles
38
+
39
+ `textmate uninstall NAME`
40
+
41
+ Uninstalls a bundle from the local repository.
data/Rakefile ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'date'
4
+
5
+ GEM = "textmate"
6
+ GEM_VERSION = "0.9.4"
7
+ AUTHOR = "Yehuda Katz"
8
+ EMAIL = "wycats@gmail.com"
9
+ HOMEPAGE = "http://yehudakatz.com"
10
+ SUMMARY = "Command-line textmate package manager (minor additions by ddollar)"
11
+
12
+ spec = Gem::Specification.new do |s|
13
+ s.name = GEM
14
+ s.version = GEM_VERSION
15
+ s.platform = Gem::Platform::RUBY
16
+ s.has_rdoc = true
17
+ s.extra_rdoc_files = ["README.markdown", "LICENSE"]
18
+ s.summary = SUMMARY
19
+ s.description = s.summary
20
+ s.author = AUTHOR
21
+ s.email = EMAIL
22
+ s.homepage = HOMEPAGE
23
+
24
+ s.add_dependency "thor", ">= 0.9.2"
25
+
26
+ s.require_path = 'bin' # Yes, it's a hack, but otherwise gem complains on install
27
+ s.autorequire = GEM
28
+ s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{bin,specs}/**/*")
29
+ s.bindir = "bin"
30
+ s.executables = %w( textmate )
31
+ end
32
+
33
+ Rake::GemPackageTask.new(spec) do |pkg|
34
+ pkg.gem_spec = spec
35
+ end
36
+
37
+ desc "make a gemspec file"
38
+ task :make_spec do
39
+ File.open("#{GEM}.gemspec", "w") do |file|
40
+ file.puts spec.to_ruby
41
+ end
42
+ end
43
+
44
+ task :install => [:package] do
45
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION} --no-rdoc --no-ri}
46
+ end
data/bin/textmate ADDED
@@ -0,0 +1,236 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "fileutils"
4
+ require "rubygems"
5
+ require "thor"
6
+ require "open-uri"
7
+ require "yaml"
8
+
9
+ class TextmateInstaller < Thor
10
+
11
+ # CHANGED: renamed list to remote. Could there be a better name?
12
+ desc "search [SEARCH]", "Lists all the matching remote bundles"
13
+ def search(search_term = "")
14
+ search_term = Regexp.new(".*#{search_term}.*", "i")
15
+
16
+ remote_bundle_locations.keys.map { |key| key.to_s }.sort.each do |name|
17
+ location = remote_bundle_locations[name.to_sym]
18
+ puts "\n" << name.to_s << " Remote Bundles\n" << name.to_s.gsub(/./,'-') << '---------------'
19
+
20
+ results = case location[:scm]
21
+ when :svn
22
+ %x[svn list #{e_sh location[:url]}].select {|x| x =~ search_term}.map do |result|
23
+ "%s - %s" % [
24
+ result.split('.').first,
25
+ "#{location[:url]}/#{result}"
26
+ ]
27
+ end.join("\n")
28
+ when :git
29
+ 'git remotes not implemented yet'
30
+ when :github
31
+ find_github_bundles(search_term).map {|result|
32
+ "%s - %s" %
33
+ [
34
+ normalize_github_repo_name(result['name']).split('.').first,
35
+ git_url_from_github_result(result)
36
+ ]
37
+ }
38
+ end
39
+
40
+ puts results
41
+ end
42
+ end
43
+
44
+ desc "list [SEARCH]", "lists all the bundles installed locally"
45
+ def list(search_term = "")
46
+ search_term = Regexp.new(".*#{search_term}.*", "i")
47
+
48
+ local_bundle_paths.each do |name,bundles_path|
49
+ puts "\n" << name.to_s << " Bundles\n" << name.to_s.gsub(/./,'-') << '--------'
50
+ puts Dir["#{e_sh bundles_path}/*.tmbundle"].map {|x| x.split("/").last.split(".").first}.
51
+ select {|x| x =~ search_term}.join("\n")
52
+ end
53
+ end
54
+
55
+ desc "install NAME [SOURCE]", "install a bundle"
56
+ def install(bundle_name, remote_bundle_location_name=nil)
57
+ FileUtils.mkdir_p install_bundles_path
58
+ puts "Checking out #{bundle_name}..."
59
+
60
+ # CHANGED: It's faster to just try and fail for each repo than to search them all first
61
+ installed=false
62
+ remote_bundle_locations.each do |remote_name,location|
63
+ next unless remote_name.to_s.downcase.include? remote_bundle_location_name.to_s.downcase if remote_bundle_location_name
64
+
65
+ cmd = case location[:scm]
66
+ when :git
67
+ 'echo "git remotes not implemented yet"'
68
+ when :svn
69
+ %[svn co #{e_sh location[:url]}/#{e_sh bundle_name}.tmbundle #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
70
+ when :github
71
+ repos = find_github_bundles(denormalize_github_repo_name(bundle_name))
72
+
73
+ # Handle possible multiple Repos with the same name
74
+ case repos.size
75
+ when 0
76
+ 'echo "Sorry, no such bundle found"'
77
+ when 1
78
+ %[git clone git://github.com/#{repos.first['username']}/#{repos.first['name']}.git #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
79
+ else
80
+ puts "Multiple bundles with that name found. Please choose which one you want to install:"
81
+ repos.each_with_index {|repo, idx|
82
+ puts "%d: %s by %s" %
83
+ [
84
+ idx + 1,
85
+ normalize_github_repo_name(repo['name']),
86
+ repo['username']
87
+ ]
88
+ }
89
+ print "Your choice: "
90
+
91
+ # Since to_i defaults to 0, we have to use Integer
92
+ choice = Integer(STDIN.gets.chomp) rescue nil
93
+ until choice && (0...repos.size).include?( choice - 1 ) do
94
+ print "Sorry, invalid choice. Please enter a valid number or Ctrl+C to stop: "
95
+ choice = Integer(STDIN.gets.chomp) rescue nil
96
+ end
97
+
98
+ %[git clone git://github.com/#{repos[choice - 1]['username']}/#{repos.first['name']}.git #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
99
+ end
100
+ end
101
+
102
+ res = %x{#{cmd}}
103
+
104
+ puts cmd, res.gsub(/^/,' ')
105
+
106
+ installed=true and break if res =~ /Checked out revision|Initialized empty Git repository/
107
+ end
108
+ abort 'Not Installed' unless installed
109
+
110
+ reload :verbose => true
111
+ end
112
+
113
+ desc "uninstall NAME", "uninstall a bundle"
114
+ def uninstall(bundle_name)
115
+ puts "Removing bundle..."
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
118
+ # the same bundle in multiple bundle paths
119
+ local_bundle_paths.each do |name,bundles_path|
120
+ bundle_path = "#{bundles_path}/#{bundle_name}.tmbundle"
121
+ if File.exist? bundle_path
122
+ %x[osascript -e 'tell application "Finder" to move the POSIX file "#{bundle_path}" to trash']
123
+ end
124
+ end
125
+
126
+ reload :verbose => true
127
+ end
128
+
129
+ desc "reload", "Reloads TextMate Bundles"
130
+ method_options :verbose => :boolean
131
+ def reload(opts = {})
132
+ puts "Reloading bundles..." if opts[:verbose]
133
+ %x[osascript -e 'tell app "TextMate" to reload bundles']
134
+ puts "Done." if opts[:verbose]
135
+ end
136
+
137
+ private
138
+ def remote_bundle_locations
139
+ { :'Macromates Trunk' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Bundles'},
140
+ :'Macromates Review' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Review/Bundles'},
141
+
142
+ # :'Bunch of Git Bundles' => {:scm => :git, :url => 'git://NotImplemented'},
143
+
144
+ :'GitHub' => {:scm => :github, :url => 'http://github.com/search?q=tmbundle'},
145
+ }
146
+ end
147
+
148
+ def local_bundle_paths
149
+ { :Application => '/Applications/TextMate.app/Contents/SharedSupport/Bundles',
150
+ :User => "#{ENV["HOME"]}/Library/Application Support/TextMate/Bundles",
151
+ :System => '/Library/Application Support/TextMate/Bundles',
152
+ :'User Pristine' => "#{ENV["HOME"]}/Library/Application Support/TextMate/Pristine Copy/Bundles",
153
+ :'System Pristine' => '/Library/Application Support/TextMate/Pristine Copy/Bundles',
154
+ }
155
+ end
156
+
157
+ def install_bundles_path
158
+ local_bundle_paths[:'User Pristine']
159
+ end
160
+
161
+ # Copied from http://macromates.com/svn/Bundles/trunk/Support/lib/escape.rb
162
+ # escape text to make it useable in a shell script as one “word” (string)
163
+ def e_sh(str)
164
+ str.to_s.gsub(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/, '\\').gsub(/\n/, "'\n'").sub(/^$/, "''")
165
+ end
166
+
167
+ CAPITALIZATION_EXCEPTIONS = %w[tmbundle on]
168
+ # Convert a GitHub repo name into a "normal" TM bundle name
169
+ # e.g. ruby-on-rails-tmbundle => Ruby on Rails.tmbundle
170
+ def normalize_github_repo_name(name)
171
+ name = name.gsub("-", " ").split.each{|part| part.capitalize! unless CAPITALIZATION_EXCEPTIONS.include? part}.join(" ")
172
+ name[-9] = ?. if name =~ / tmbundle$/
173
+ name
174
+ end
175
+
176
+ # Does the opposite of normalize_github_repo_name
177
+ def denormalize_github_repo_name(name)
178
+ name += " tmbundle" unless name =~ / tmbundle$/
179
+ name.split(' ').each{|part| part.downcase!}.join(' ').gsub(' ', '-')
180
+ end
181
+
182
+ def find_github_bundles(search_term)
183
+ # Until GitHub fixes http://support.github.com/discussions/feature-requests/11-api-search-results,
184
+ # we need to account for multiple pages of results:
185
+ page = 1
186
+ repositories = YAML.load(open("http://github.com/api/v1/yaml/search/tmbundle?start_value=#{page}"))['repositories']
187
+ results = []
188
+ until repositories.empty?
189
+ results += repositories.find_all{|result| result['name'].match(search_term)}
190
+ page += 1
191
+ repositories = YAML.load(open("http://github.com/api/v1/yaml/search/tmbundle?start_value=#{page}"))['repositories']
192
+ end
193
+ results.sort{|a,b| a['name'] <=> b['name']}
194
+ end
195
+
196
+ def git_url_from_github_result(result)
197
+ "git://github.com/#{result['username']}/#{result['name']}.git"
198
+ end
199
+
200
+ end
201
+
202
+ # TODO: create a "monument to personal cleverness" by class-izing everything?
203
+ # class TextMateBundle
204
+ # def self.find_local(bundle_name)
205
+ #
206
+ # end
207
+ #
208
+ # def self.find_remote(bundle_name)
209
+ #
210
+ # end
211
+ # attr_reader :name
212
+ # attr_reader :location
213
+ # attr_reader :scm
214
+ # def initialize(name, location, scm)
215
+ # @name = name
216
+ # @location = location
217
+ # @scm = scm
218
+ # end
219
+ #
220
+ # def install!
221
+ #
222
+ # end
223
+ #
224
+ # def uninstall!
225
+ #
226
+ # end
227
+ #
228
+ #
229
+ # def installed?
230
+ # # List all the installed versions, and where they're at
231
+ # end
232
+ #
233
+ # # TODO: dirty? method to show if there are any deltas
234
+ # end
235
+
236
+ TextmateInstaller.start
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ddollar-textmate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.4
5
+ platform: ruby
6
+ authors:
7
+ - Yehuda Katz
8
+ autorequire: textmate
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-15 00:00:00 -07:00
13
+ default_executable: textmate
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: thor
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.2
24
+ version:
25
+ description: Command-line textmate package manager (minor additions by ddollar)
26
+ email: wycats@gmail.com
27
+ executables:
28
+ - textmate
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.markdown
33
+ - LICENSE
34
+ files:
35
+ - LICENSE
36
+ - README.markdown
37
+ - Rakefile
38
+ - bin/textmate
39
+ has_rdoc: false
40
+ homepage: http://yehudakatz.com
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - bin
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.2.0
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Command-line textmate package manager (minor additions by ddollar)
65
+ test_files: []
66
+