textmate 0.9.0 → 0.9.2

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/README.markdown +23 -13
  2. data/Rakefile +12 -5
  3. data/bin/textmate +160 -48
  4. metadata +4 -5
  5. data/lib/class_cli.rb +0 -77
@@ -1,31 +1,41 @@
1
- textmate
2
- ========
1
+ # textmate
3
2
 
4
3
  A binary that provides package management for TextMate.
5
4
 
6
- Usage
7
- =====
5
+ # Usage
8
6
 
9
7
  `textmate [COMMAND] [*PARAMS]`
10
8
 
11
9
  Textmate bundles are automatically reloaded after install or uninstall operations.
12
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
+
13
19
  `textmate list [SEARCH]`
14
- ------------------------
15
20
 
16
- List all of the available bundles in the remote repository that have a substring `search`. By default, list all bundles.
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]`
17
26
 
18
- `textmate installed`
19
- --------------------
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:
20
29
 
21
- List all of the bundles that are installed on the local system.
30
+ `textmate install "Ruby on Rails" GitHub`
22
31
 
23
- `textmate install NAME`
24
- -----------------------
32
+ Available remote bundle locations are:
33
+ * Macromates Trunk
34
+ * Macromates Review
35
+ * GitHub
25
36
 
26
- Installs a bundle from the remote repository.
37
+ ## Uninstalling bundles
27
38
 
28
39
  `textmate uninstall NAME`
29
- -------------------------
30
40
 
31
41
  Uninstalls a bundle from the local repository.
data/Rakefile CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'rubygems'
2
2
  require 'rake/gempackagetask'
3
+ require 'date'
3
4
 
4
5
  GEM = "textmate"
5
- GEM_VERSION = "0.9.0"
6
+ GEM_VERSION = "0.9.2"
6
7
  AUTHOR = "Yehuda Katz"
7
8
  EMAIL = "wycats@gmail.com"
8
9
  HOMEPAGE = "http://yehudakatz.com"
@@ -20,11 +21,10 @@ spec = Gem::Specification.new do |s|
20
21
  s.email = EMAIL
21
22
  s.homepage = HOMEPAGE
22
23
 
23
- s.add_dependency "thor", ">= 0.9.1"
24
-
25
- s.require_path = 'lib'
24
+ s.add_dependency "thor", ">= 0.9.2"
25
+
26
26
  s.autorequire = GEM
27
- s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{bin,lib,specs}/**/*")
27
+ s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("{bin,specs}/**/*")
28
28
  s.bindir = "bin"
29
29
  s.executables = %w( textmate )
30
30
  end
@@ -33,6 +33,13 @@ Rake::GemPackageTask.new(spec) do |pkg|
33
33
  pkg.gem_spec = spec
34
34
  end
35
35
 
36
+ desc "make a gemspec file"
37
+ task :make_spec do
38
+ File.open("#{GEM}.gemspec", "w") do |file|
39
+ file.puts spec.to_ruby
40
+ end
41
+ end
42
+
36
43
  task :install => [:package] do
37
44
  sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION} --no-rdoc --no-ri}
38
45
  end
@@ -1,71 +1,183 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "fileutils"
4
+ require "rubygems"
4
5
  require "thor"
6
+ require "open-uri"
7
+ require "yaml"
5
8
 
6
9
  class TextmateInstaller < Thor
7
10
 
8
- desc "list [SEARCH]", "Lists all the matching remote bundles"
9
- def list(limit = "")
10
- limit = Regexp.new(".*#{limit}.*", "i")
11
- puts "\nBundles\n-------\n"
12
- results = %x[svn list #{svn_for("bundles")}]
13
- puts results.map {|x| x.split(".")[0]}.select {|x| x =~ limit}.join("\n")
14
- puts "\nReview\n------\n"
15
- results = %x[svn list #{svn_for("review")}]
16
- puts results.map {|x| x.split(".")[0]}.select {|x| x =~ limit}.join("\n")
11
+ # 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 = "")
14
+ search_term = Regexp.new(".*#{search_term}.*", "i")
15
+
16
+ remote_bundle_locations.each do |name,location|
17
+ puts "\n" << name.to_s << " Remote Bundles\n" << name.to_s.gsub(/./,'-') << '---------------'
18
+
19
+ results = case location[:scm]
20
+ when :svn
21
+ %x[svn list #{e_sh location[:url]}].map {|x| x.split(".")[0]}.select {|x| x =~ search_term}.join("\n")
22
+ when :git
23
+ 'git remotes not implemented yet'
24
+ when :github
25
+ find_github_bundles(search_term).map{|result| normalize_github_repo_name(result['name']).split('.').first}
26
+ end
27
+
28
+ puts results
29
+ end
17
30
  end
18
-
19
- desc "installed", "lists all the bundles installed locally"
20
- def installed()
21
- puts "\nSystem\n------\n"
22
- puts Dir["/Library/Application Support/TextMate/Bundles/*.tmbundle"].map {|x| x.split("/").last.split(".").first}.join("\n")
23
- puts "\nUser\n----\n"
24
- puts Dir["#{ENV["HOME"]}/Library/Application Support/TextMate/Bundles/*.tmbundle"].map {|x| x.split("/").last.split(".").first}.join("\n")
31
+
32
+ desc "list [SEARCH]", "lists all the bundles installed locally"
33
+ def list(search_term = "")
34
+ search_term = Regexp.new(".*#{search_term}.*", "i")
35
+
36
+ local_bundle_paths.each do |name,bundles_path|
37
+ puts "\n" << name.to_s << " Bundles\n" << name.to_s.gsub(/./,'-') << '--------'
38
+ puts Dir["#{e_sh bundles_path}/*.tmbundle"].map {|x| x.split("/").last.split(".").first}.
39
+ select {|x| x =~ search_term}.join("\n")
40
+ end
25
41
  end
26
42
 
27
- desc "install NAME", "install a bundle"
28
- def install(name)
29
- FileUtils.mkdir_p "/Library/Application Support/TextMate/Bundles"
30
- quoted_name = name.gsub(" ", "\\ ")
31
- type = where(name)
32
- puts "Checking out #{name}..."
33
- res = %x[svn co #{svn_for(type)}/#{quoted_name}.tmbundle /Library/Application\\ Support/TextMate/Bundles/#{quoted_name}.tmbundle]
34
- puts "Reloading Bundles..."
35
- reload_textmate!
36
- puts "Done."
43
+ desc "install NAME [SOURCE]", "install a bundle"
44
+ def install(bundle_name, remote_bundle_location_name=nil)
45
+ FileUtils.mkdir_p install_bundles_path
46
+ puts "Checking out #{bundle_name}..."
47
+
48
+ # CHANGED: It's faster to just try and fail for each repo than to search them all first
49
+ installed=false
50
+ remote_bundle_locations.each do |remote_name,location|
51
+ next unless remote_name.to_s.downcase.include? remote_bundle_location_name.to_s.downcase if remote_bundle_location_name
52
+
53
+ cmd = case location[:scm]
54
+ when :git
55
+ 'echo "git remotes not implemented yet"'
56
+ when :svn
57
+ %[svn co #{e_sh location[:url]}/#{e_sh bundle_name}.tmbundle #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
58
+ when :github
59
+ repo = find_github_bundles(denormalize_github_repo_name(bundle_name)).first
60
+ %[git clone #{e_sh repo['url'].sub('http', 'git') + '.git'} #{e_sh install_bundles_path}/#{e_sh bundle_name}.tmbundle 2>&1]
61
+ end
62
+
63
+ res = %x{#{cmd}}
64
+
65
+ puts cmd, res.gsub(/^/,' ')
66
+
67
+ installed=true and break if res =~ /Checked out revision|Initialized empty Git repository/
68
+ end
69
+ abort 'Not Installed' unless installed
70
+
71
+ reload :verbose => true
37
72
  end
38
73
 
39
74
  desc "uninstall NAME", "uninstall a bundle"
40
- def uninstall(name)
75
+ def uninstall(bundle_name)
41
76
  puts "Removing bundle..."
42
- FileUtils.rm_rf("/Library/Application Support/TextMate/Bundles/#{name}.tmbundle")
43
- FileUtils.rm_rf("#{ENV["HOME"]}/Library/Application Support/TextMate/Bundles/#{name}.tmbundle")
44
- puts "Reloading bundles..."
45
- reload_textmate!
46
- puts "Done."
77
+ # When moving to the trash, maybe move the bundle into a trash/disabled_bundles subfolder
78
+ # named as the bundles_path key. Just in case there are multiple versions of
79
+ # the same bundle in multiple bundle paths
80
+ local_bundle_paths.each do |name,bundles_path|
81
+ bundle_path = "#{bundles_path}/#{bundle_name}.tmbundle"
82
+ if File.exist? bundle_path
83
+ %x[osascript -e 'tell application "Finder" to move the POSIX file "#{bundle_path}" to trash']
84
+ end
85
+ end
86
+
87
+ reload :verbose => true
47
88
  end
48
89
 
49
- private
50
- def reload_textmate!
90
+ desc "reload", "Reloads TextMate Bundles"
91
+ method_options :verbose => :boolean
92
+ def reload(opts = {})
93
+ puts "Reloading bundles..." if opts[:verbose]
51
94
  %x[osascript -e 'tell app "TextMate" to reload bundles']
95
+ puts "Done." if opts[:verbose]
52
96
  end
53
-
54
- def where(bundle)
55
- bundles = %x[svn list #{svn_for("bundles")}].map {|x| x.split(".")[0]}
56
- review = %x[svn list #{svn_for("review")}].map {|x| x.split(".")[0]}
57
- return "bundles" if bundles.include?(bundle)
58
- return "review" if review.include?(bundle)
97
+
98
+ private
99
+ def remote_bundle_locations
100
+ { :'Macromates Trunk' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Bundles'},
101
+ :'Macromates Review' => {:scm => :svn, :url => 'http://macromates.com/svn/Bundles/trunk/Review/Bundles'},
102
+
103
+ # :'Bunch of Git Bundles' => {:scm => :git, :url => 'git://NotImplemented'},
104
+
105
+ :'GitHub' => {:scm => :github, :url => 'http://github.com/search?q=tmbundle'},
106
+ }
59
107
  end
60
-
61
- def svn_for(type)
62
- if type =~ /bundles/i
63
- "http://macromates.com/svn/Bundles/trunk/Bundles"
64
- elsif type =~ /review/i
65
- "http://macromates.com/svn/Bundles/trunk/Review/Bundles"
66
- end
108
+
109
+ def local_bundle_paths
110
+ { :Application => '/Applications/TextMate.app/Contents/SharedSupport/Bundles',
111
+ :User => "#{ENV["HOME"]}/Library/Application Support/TextMate/Bundles",
112
+ :System => '/Library/Application Support/TextMate/Bundles',
113
+ :'User Pristine' => "#{ENV["HOME"]}/Library/Application Support/TextMate/Pristine Copy/Bundles",
114
+ :'System Pristine' => '/Library/Application Support/TextMate/Pristine Copy/Bundles',
115
+ }
116
+ end
117
+
118
+ def install_bundles_path
119
+ local_bundle_paths[:'User Pristine']
120
+ end
121
+
122
+ # Copied from http://macromates.com/svn/Bundles/trunk/Support/lib/escape.rb
123
+ # escape text to make it useable in a shell script as one “word” (string)
124
+ def e_sh(str)
125
+ str.to_s.gsub(/(?=[^a-zA-Z0-9_.\/\-\x7F-\xFF\n])/, '\\').gsub(/\n/, "'\n'").sub(/^$/, "''")
126
+ end
127
+
128
+ CAPITALIZATION_EXCEPTIONS = %w[tmbundle on]
129
+ # Convert a GitHub repo name into a "normal" TM bundle name
130
+ # e.g. ruby-on-rails-tmbundle => Ruby on Rails.tmbundle
131
+ def normalize_github_repo_name(name)
132
+ name = name.gsub("-", " ").split.each{|part| part.capitalize! unless CAPITALIZATION_EXCEPTIONS.include? part}.join(" ")
133
+ name[-9] = ?. if name =~ / tmbundle$/
134
+ name
135
+ end
136
+
137
+ # Does the opposite of normalize_github_repo_name
138
+ def denormalize_github_repo_name(name)
139
+ name += " tmbundle" unless name =~ / tmbundle$/
140
+ name.split(' ').each{|part| part.downcase!}.join(' ').gsub(' ', '-')
141
+ end
142
+
143
+ def find_github_bundles(search_term)
144
+ YAML.load(open('http://github.com/api/v1/yaml/search/tmbundle'))['repositories'].find_all{|result| result['name'].match(search_term)}
67
145
  end
68
146
 
69
147
  end
70
148
 
71
- TextmateInstaller.start
149
+ # TODO: create a "monument to personal cleverness" by class-izing everything?
150
+ # class TextMateBundle
151
+ # def self.find_local(bundle_name)
152
+ #
153
+ # end
154
+ #
155
+ # def self.find_remote(bundle_name)
156
+ #
157
+ # end
158
+ # attr_reader :name
159
+ # attr_reader :location
160
+ # attr_reader :scm
161
+ # def initialize(name, location, scm)
162
+ # @name = name
163
+ # @location = location
164
+ # @scm = scm
165
+ # end
166
+ #
167
+ # def install!
168
+ #
169
+ # end
170
+ #
171
+ # def uninstall!
172
+ #
173
+ # end
174
+ #
175
+ #
176
+ # def installed?
177
+ # # List all the installed versions, and where they're at
178
+ # end
179
+ #
180
+ # # TODO: dirty? method to show if there are any deltas
181
+ # end
182
+
183
+ TextmateInstaller.start
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: textmate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yehuda Katz
@@ -9,7 +9,7 @@ autorequire: textmate
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-05-12 00:00:00 -07:00
12
+ date: 2008-05-28 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -19,7 +19,7 @@ dependencies:
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.9.1
22
+ version: 0.9.2
23
23
  version:
24
24
  description: Command-line textmate package manager
25
25
  email: wycats@gmail.com
@@ -35,7 +35,6 @@ files:
35
35
  - README.markdown
36
36
  - Rakefile
37
37
  - bin/textmate
38
- - lib/class_cli.rb
39
38
  has_rdoc: true
40
39
  homepage: http://yehudakatz.com
41
40
  post_install_message:
@@ -58,7 +57,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
57
  requirements: []
59
58
 
60
59
  rubyforge_project:
61
- rubygems_version: 1.0.1
60
+ rubygems_version: 1.1.1
62
61
  signing_key:
63
62
  specification_version: 2
64
63
  summary: Command-line textmate package manager
@@ -1,77 +0,0 @@
1
- require "getopt/long"
2
-
3
- module Hermes
4
- def self.extended(klass)
5
- klass.class_eval <<-RUBY, "class_cli.rb", 6
6
-
7
- def self.method_added(meth)
8
- return if !public_instance_methods.include?(meth.to_s) || !@@usage
9
- @@descriptions = defined?(@@descriptions) ? @@descriptions : []
10
- @@usages = defined?(@@usages) ? @@usages : []
11
- @@opts = defined?(@@opts) ? @@opts : []
12
- @@descriptions << [meth.to_s, @@desc]
13
- @@usages << [meth.to_s, @@usage]
14
- if defined?(@@method_options) && @@method_options
15
- @@opts << [meth.to_s, @@method_options]
16
- end
17
- @@usage, @@desc, @@method_options = nil
18
- end
19
-
20
- def self.desc(usage, description)
21
- @@usage, @@desc = usage, description
22
- end
23
-
24
- def self.method_options(opts)
25
- @@method_options = opts
26
- end
27
-
28
- def self.start
29
- meth = ARGV.shift
30
- params = ARGV.inject([]) do |accum, arg|
31
- accum << ARGV.delete(arg) unless arg =~ /^\-/
32
- accum
33
- end
34
- if @@opts.assoc(meth)
35
- opts = @@opts.assoc(meth).last.map {|opt, val| [opt, val == true ? Getopt::BOOLEAN : Getopt.const_get(val)].flatten}
36
- options = Getopt::Long.getopts(*opts)
37
- params << options
38
- end
39
- new(meth, params)
40
- end
41
-
42
- def initialize(op, params)
43
- send(op.to_sym, *params) if public_methods.include?(op)
44
- end
45
-
46
- private
47
- def format_opts(opts)
48
- return "" unless opts
49
- opts.map do |opt, val|
50
- if val == true || val == "BOOLEAN"
51
- opt
52
- elsif val == "REQUIRED"
53
- opt + "=" + opt.gsub(/\-/, "").upcase
54
- elsif val == "OPTIONAL"
55
- "[" + opt + "=" + opt.gsub(/\-/, "").upcase + "]"
56
- end
57
- end.join(" ")
58
- end
59
-
60
- public
61
- desc "help", "show this screen"
62
- def help
63
- puts "Options"
64
- puts "-------"
65
- max_usage = @@usages.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
66
- max_opts = @@opts.empty? ? 0 : format_opts(@@opts.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last).size
67
- max_desc = @@descriptions.max {|x,y| x.last.to_s.size <=> y.last.to_s.size}.last.size
68
- @@usages.each do |meth, usage|
69
- format = "%-" + (max_usage + max_opts + 4).to_s + "s"
70
- print format % (@@usages.assoc(meth)[1] + (@@opts.assoc(meth) ? " " + format_opts(@@opts.assoc(meth)[1]) : ""))
71
- # print format % (@@usages.assoc(meth)[1] + @@opts.assoc(meth) ? format_opts(@@opts.assoc(meth)[1]) : ""))
72
- puts @@descriptions.assoc(meth)[1]
73
- end
74
- end
75
- RUBY
76
- end
77
- end