textmate 0.9.0 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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