pik 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/History.txt +13 -0
  2. data/Manifest.txt +35 -1
  3. data/README.rdoc +99 -39
  4. data/Rakefile +49 -8
  5. data/bin/pik_install +23 -0
  6. data/features/add_command.feature +28 -0
  7. data/features/checkup_command.feature +0 -0
  8. data/features/config_command.feature +12 -0
  9. data/features/default_command.feature +12 -0
  10. data/features/env.rb +52 -0
  11. data/features/gemsync_command.feature +0 -0
  12. data/features/help_command.feature +13 -0
  13. data/features/implode_command.feature +12 -0
  14. data/features/install_command.feature +13 -0
  15. data/features/list_command.feature +18 -0
  16. data/features/remove_command.feature +18 -0
  17. data/features/run_command.feature +22 -0
  18. data/features/step_definitions/pik_commands.rb +140 -0
  19. data/features/switch_command.feature +35 -0
  20. data/features/tag_command.feature +18 -0
  21. data/features/version.feature +9 -0
  22. data/lib/pik.rb +17 -3
  23. data/lib/pik/commands/add_command.rb +6 -6
  24. data/lib/pik/commands/batch_file_editor.rb +22 -8
  25. data/lib/pik/commands/checkup_command.rb +5 -2
  26. data/lib/pik/commands/command.rb +30 -26
  27. data/lib/pik/commands/config_command.rb +54 -2
  28. data/lib/pik/commands/default_command.rb +19 -5
  29. data/lib/pik/commands/help_command.rb +1 -1
  30. data/lib/pik/commands/implode_command.rb +12 -1
  31. data/lib/pik/commands/install_command.rb +182 -0
  32. data/lib/pik/commands/list_command.rb +3 -2
  33. data/lib/pik/commands/remove_command.rb +6 -6
  34. data/lib/pik/commands/run_command.rb +70 -10
  35. data/lib/pik/commands/switch_command.rb +10 -10
  36. data/lib/pik/commands/tag_command.rb +56 -0
  37. data/lib/pik/config_file.rb +26 -2
  38. data/lib/pik/contrib/progressbar.rb +237 -0
  39. data/lib/pik/contrib/unzip.rb +14 -0
  40. data/lib/pik/contrib/uri_ext.rb +296 -0
  41. data/lib/pik/contrib/zip/ioextras.rb +155 -0
  42. data/lib/pik/contrib/zip/stdrubyext.rb +111 -0
  43. data/lib/pik/contrib/zip/tempfile_bugfixed.rb +195 -0
  44. data/lib/pik/contrib/zip/zip.rb +1846 -0
  45. data/lib/pik/contrib/zip/zipfilesystem.rb +609 -0
  46. data/lib/pik/contrib/zip/ziprequire.rb +90 -0
  47. data/lib/pik/core_ext/pathname.rb +20 -7
  48. data/lib/pik/search_path.rb +21 -13
  49. data/lib/pik/which.rb +52 -0
  50. data/lib/pik/windows_env.rb +64 -25
  51. data/spec/add_command_spec.rb +0 -2
  52. data/spec/batch_file_spec.rb +3 -3
  53. data/spec/command_spec.rb +0 -7
  54. data/spec/gemsync_command_spec.rb +1 -1
  55. data/spec/help_command_spec.rb +1 -1
  56. data/spec/list_command_spec.rb +1 -1
  57. data/spec/pathname_spec.rb +30 -0
  58. data/spec/remove_command_spec.rb +6 -6
  59. data/spec/run_command_spec.rb +2 -30
  60. data/spec/search_path_spec.rb +9 -0
  61. data/spec/switch_command_spec.rb +14 -2
  62. data/spec/which_spec.rb +7 -0
  63. data/tools/pik.bat +2 -0
  64. data/tools/pik/pik +45 -0
  65. data/tools/pik/pik.exe +0 -0
  66. data/tools/pik/pik.exy +198 -0
  67. metadata +50 -21
  68. data/bin/pik +0 -33
@@ -6,24 +6,24 @@ module Pik
6
6
  it "Removes a ruby location from pik."
7
7
  include ConfigFileEditor
8
8
 
9
- attr_reader :quiet
9
+ attr_reader :force
10
10
 
11
11
  def execute
12
12
  to_remove = self.class.choose_from(@args, @config)
13
13
  raise QuitError unless to_remove
14
- if quiet || @hl.agree("Are you sure you'd like to remove '#{to_remove}'? [Yn] ")
14
+ if force || @hl.agree("Are you sure you'd like to remove '#{to_remove}'? [Yn] ")
15
15
  @config.delete(to_remove)
16
- @hl.say("#{to_remove} removed") unless quiet
16
+ @hl.say("#{to_remove} removed")
17
17
  end
18
18
  end
19
19
 
20
20
  def command_options
21
21
  super
22
- options.on("--quiet", "-q", "Remove without prompting") do |value|
23
- @quiet = value
22
+ options.on("--force", "-f", "Remove without prompting") do |value|
23
+ @force = value
24
24
  end
25
25
  end
26
26
 
27
27
  end
28
28
 
29
- end
29
+ end
@@ -2,21 +2,21 @@ module Pik
2
2
 
3
3
  class Run < Command
4
4
 
5
- it "Runs command with all version of ruby that pik is aware of."
6
- include BatchFileEditor
5
+ it "Runs command with all versions of ruby that pik is aware of."
7
6
 
8
7
  def execute
9
- command = @args.join(' ')
10
- current_ruby = @config[get_version]
11
8
  @config.sort.each do |version,hash|
12
9
  switch_path_to(hash)
13
10
  switch_gem_home_to(hash[:gem_home])
14
- echo_running_with_ruby_version
15
- @batch.call command
16
- @batch.echo "."
11
+ echo_ruby_version(hash[:path])
12
+ puts `#{command}`
13
+ puts
17
14
  end
18
- switch_path_to(current_ruby)
19
- switch_gem_home_to(current_ruby[:gem_home])
15
+ end
16
+
17
+ def command(cmd='CALL')
18
+ args = @args.map{|a| a.sub(/.*\s.*/m, '"\&"')}.join(' ')
19
+ "#{cmd} #{args}"
20
20
  end
21
21
 
22
22
  def command_options
@@ -31,7 +31,67 @@ module Pik
31
31
  SEP
32
32
  options.separator sep
33
33
  end
34
+
35
+ def parse_options
36
+ end
37
+
38
+ def switch_path_to(new_ver)
39
+ dir = Which::Ruby.find
40
+ current_config = config[ find_config_from_path(dir) ]
41
+
42
+ new_path = SearchPath.new(ENV['PATH']).replace_or_add(dir, new_ver[:path])
43
+ if new_gem_home = new_ver[:gem_home]
44
+
45
+ new_gem_bin = Pathname.new(new_gem_home) + 'bin'
46
+
47
+ if current_config && (current_gem_home = current_config[:gem_home])
48
+ current_gem_bin = Pathname.new(current_gem_home) + 'bin'
49
+ new_path.replace(current_gem_bin, new_gem_bin)
50
+ else
51
+ new_path.add(new_gem_bin)
52
+ end
53
+ else
54
+ if current_config && (current_gem_home = current_config[:gem_home])
55
+ current_gem_bin = Pathname.new(current_gem_home) + 'bin'
56
+ new_path.remove(current_gem_bin)
57
+ end
58
+ end
59
+ ENV['PATH'] = new_path.join
60
+ end
61
+
62
+ def switch_gem_home_to(gem_home)
63
+ gem_home = Pathname(gem_home).to_windows rescue nil
64
+ ENV['GEM_PATH'] = gem_home
65
+ ENV['GEM_HOME'] = gem_home
66
+ end
67
+
68
+ def echo_ruby_version(path)
69
+ rb = Which::Ruby.exe(path)
70
+ puts `#{rb} -v `
71
+ end
34
72
 
35
73
  end
74
+
75
+ class Ruby < Run
36
76
 
37
- end
77
+ aka :rb
78
+ it "Runs ruby with all versions that pik is aware of."
79
+
80
+ def command(cmd=Which::Ruby.exe.basename)
81
+ super(cmd)
82
+ end
83
+
84
+ end
85
+
86
+ class Gem < Run
87
+
88
+ it "Runs the gem command with all versions that pik is aware of."
89
+
90
+ def command(cmd=Which::Gem.bat.basename)
91
+ super(cmd)
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+
@@ -8,24 +8,24 @@ module Pik
8
8
 
9
9
  attr_accessor :global
10
10
  attr_accessor :gem_home
11
+ attr_accessor :verbose
11
12
 
12
13
  def execute
13
14
  abort('Nothing matches:') unless new_ver = self.class.choose_from(@args, @config)
14
15
  switch_path_to(@config[new_ver])
15
- switch_gem_home_to(@config[new_ver][:gem_home])
16
- echo_ruby_version
16
+ switch_gem_home_to(@config[new_ver][:gem_home])
17
+ echo_ruby_version(@config[new_ver][:path]) if verbose
17
18
  end
18
19
 
19
20
  def command_options
20
- # options.on("--global", "-g", "Make changes globally") do |value|
21
- # @global = value
22
- # end
23
-
24
- # options.on("-m name", "specify gem_home (Named gem sets)") do |value|
25
- # @gem_home = value
26
- # end
27
-
28
21
  super
22
+
23
+ options.on("--verbose", "-v",
24
+ "Display verbose output"
25
+ ) do |value|
26
+ @verbose = true
27
+ end
28
+
29
29
  sep =<<SEP
30
30
  Examples:
31
31
 
@@ -0,0 +1,56 @@
1
+ module Pik
2
+
3
+ class Tags < Command
4
+
5
+ it 'Runs the pik command against the given tags.'
6
+
7
+ def execute
8
+ config.global[:tags] ||= Hash.new{|h,k| h[k] = [] }
9
+ @tag_config = config.dup
10
+ @tag_config.clear
11
+ tags = @args.shift.split(',')
12
+ tags.each do |tag|
13
+ versions = config.global[:tags][tag]
14
+ raise "Tag '#{tag}' unknown" unless versions
15
+ versions.each{|version| @tag_config[version] = config[version] }
16
+ end
17
+ command = Commands.find(@args.shift)
18
+ raise "The command '#{args.join(' ')}' is unknown." unless command
19
+
20
+ cmd = command.new(@args, @tag_config)
21
+ cmd.execute
22
+
23
+ rescue QuitError
24
+ puts "\nQuitting..."
25
+ rescue => e
26
+ puts "\nThere was an error"
27
+ puts " Error: #{e.message}\n\n"
28
+ puts e.backtrace.map{|m| " in: #{m}" }
29
+ ensure
30
+ cmd.close if cmd
31
+ end
32
+
33
+ def parse_options
34
+ end
35
+
36
+ end
37
+
38
+ class Tag < Command
39
+
40
+ it 'Adds the given tag to the current version.'
41
+
42
+ include ConfigFileEditor
43
+
44
+ def execute
45
+ config.global[:tags] ||= Hash.new
46
+ @args.each do |arg|
47
+ tags = config.global[:tags]
48
+ tags[arg] ||= []
49
+ tags[arg] << find_config_from_path
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
@@ -3,19 +3,43 @@ require 'yaml'
3
3
  module Pik
4
4
 
5
5
  class ConfigFile < Hash
6
+
7
+ attr_reader :global
6
8
 
7
9
  def initialize
8
10
  @file = File.join(PIK_HOME, 'config.yml')
9
11
  super
10
12
  if File.exists? @file
11
- self.update( YAML.load( File.read( @file ) ) )
13
+ contents = File.read( @file )
14
+ unless contents.empty?
15
+ documents = YAML.load_stream( contents )
16
+ self.update( documents[0] )
17
+ @global = documents[1] || {}
18
+ end
12
19
  end
13
20
  end
14
21
 
15
22
  def write
16
- File.open(@file, 'w'){|f| f.puts YAML::dump(Hash[self]) }
23
+ File.open(@file, 'w')do |f|
24
+ f.puts YAML::dump_stream( Hash[self]), YAML.dump(global)
25
+ end
17
26
  end
18
27
 
19
28
  end
20
29
 
21
30
  end
31
+
32
+ class Hash
33
+ # Replacing the to_yaml function so it'll serialize hashes sorted (by their keys)
34
+ #
35
+ # Original function is in /usr/lib/ruby/1.8/yaml/rubytypes.rb
36
+ def to_yaml( opts = {} )
37
+ YAML::quick_emit( object_id, opts ) do |out|
38
+ out.map( taguri, to_yaml_style ) do |map|
39
+ sort_by{|s| s[0].to_s}.each do |k, v| # <-- here's my addition (the 'sort')
40
+ map.add( k, v )
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,237 @@
1
+ # = progressbar.rb
2
+ #
3
+ # == Copyright (C) 2001 Satoru Takabayashi
4
+ #
5
+ # Ruby License
6
+ #
7
+ # This module is free software. You may use, modify, and/or redistribute this
8
+ # software under the same terms as Ruby.
9
+ #
10
+ # This program is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12
+ # FOR A PARTICULAR PURPOSE.
13
+ #
14
+ # == Author(s)
15
+ #
16
+ # * Satoru Takabayashi
17
+
18
+ # Author:: Satoru Takabayashi
19
+ # Copyright:: Copyright (c) 2001 Satoru Takabayashi
20
+ # License:: Ruby License
21
+
22
+ # = Console Progress Bar
23
+ #
24
+ # Console::ProgressBar is a terminal-based progress bar library.
25
+ #
26
+ # == Usage
27
+ #
28
+ # pbar = ConsoleProgressBar.new( "Demo", 100 )
29
+ # 100.times { pbar.inc }
30
+ # pbar.finish
31
+ #
32
+
33
+ module Console; end
34
+
35
+ class Console::ProgressBar
36
+
37
+ def initialize(title, total, out = STDERR)
38
+ @title = title
39
+ @total = total
40
+ @out = out
41
+ @bar_length = 80
42
+ @bar_mark = "o"
43
+ @total_overflow = true
44
+ @current = 0
45
+ @previous = 0
46
+ @is_finished = false
47
+ @start_time = Time.now
48
+ @format = "%-14s %3d%% %s %s"
49
+ @format_arguments = [:title, :percentage, :bar, :stat]
50
+ show_progress
51
+ end
52
+
53
+ private
54
+ def convert_bytes (bytes)
55
+ if bytes < 1024
56
+ sprintf("%6dB", bytes)
57
+ elsif bytes < 1024 * 1000 # 1000kb
58
+ sprintf("%5.1fKB", bytes.to_f / 1024)
59
+ elsif bytes < 1024 * 1024 * 1000 # 1000mb
60
+ sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
61
+ else
62
+ sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
63
+ end
64
+ end
65
+
66
+ def transfer_rate
67
+ bytes_per_second = @current.to_f / (Time.now - @start_time)
68
+ sprintf("%s/s", convert_bytes(bytes_per_second))
69
+ end
70
+
71
+ def bytes
72
+ convert_bytes(@current)
73
+ end
74
+
75
+ def format_time (t)
76
+ t = t.to_i
77
+ sec = t % 60
78
+ min = (t / 60) % 60
79
+ hour = t / 3600
80
+ sprintf("%02d:%02d:%02d", hour, min, sec);
81
+ end
82
+
83
+ # ETA stands for Estimated Time of Arrival.
84
+ def eta
85
+ if @current == 0
86
+ "ETA: --:--:--"
87
+ else
88
+ elapsed = Time.now - @start_time
89
+ eta = elapsed * @total / @current - elapsed;
90
+ sprintf("ETA: %s", format_time(eta))
91
+ end
92
+ end
93
+
94
+ def elapsed
95
+ elapsed = Time.now - @start_time
96
+ sprintf("Time: %s", format_time(elapsed))
97
+ end
98
+
99
+ def stat
100
+ if @is_finished then elapsed else eta end
101
+ end
102
+
103
+ def stat_for_file_transfer
104
+ if @is_finished then
105
+ sprintf("%s %s %s", bytes, transfer_rate, elapsed)
106
+ else
107
+ sprintf("%s %s %s", bytes, transfer_rate, eta)
108
+ end
109
+ end
110
+
111
+ def eol
112
+ if @is_finished then "\n" else "\r" end
113
+ end
114
+
115
+ def bar
116
+ len = percentage * @bar_length / 100
117
+ sprintf("|%s%s|", @bar_mark * len, " " * (@bar_length - len))
118
+ end
119
+
120
+ def percentage
121
+ if @total.zero?
122
+ 100
123
+ else
124
+ @current * 100 / @total
125
+ end
126
+ end
127
+
128
+ def title
129
+ @title[0,13] + ":"
130
+ end
131
+
132
+ def get_width
133
+ # FIXME: I don't know how portable it is.
134
+ default_width = 80
135
+ begin
136
+ tiocgwinsz = 0x5413
137
+ data = [0, 0, 0, 0].pack("SSSS")
138
+ if @out.ioctl(tiocgwinsz, data) >= 0 then
139
+ rows, cols, xpixels, ypixels = data.unpack("SSSS")
140
+ if cols >= 0 then cols else default_width end
141
+ else
142
+ default_width
143
+ end
144
+ rescue Exception
145
+ default_width
146
+ end
147
+ end
148
+
149
+ def show
150
+ arguments = @format_arguments.map {|method| send(method) }
151
+ line = sprintf(@format, *arguments)
152
+
153
+ width = get_width
154
+ if line.length == width - 1
155
+ @out.print(line + eol)
156
+ elsif line.length >= width
157
+ @bar_length = [@bar_length - (line.length - width + 1), 0].max
158
+ if @bar_length == 0 then @out.print(line + eol) else show end
159
+ else #line.length < width - 1
160
+ @bar_length += width - line.length + 1
161
+ show
162
+ end
163
+ end
164
+
165
+ def show_progress
166
+ if @total.zero?
167
+ cur_percentage = 100
168
+ prev_percentage = 0
169
+ else
170
+ cur_percentage = (@current * 100 / @total).to_i
171
+ prev_percentage = (@previous * 100 / @total).to_i
172
+ end
173
+
174
+ if cur_percentage > prev_percentage || @is_finished
175
+ show
176
+ end
177
+ end
178
+
179
+ public
180
+ def file_transfer_mode
181
+ @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
182
+ end
183
+
184
+ def bar_mark= (mark)
185
+ @bar_mark = String(mark)[0..0]
186
+ end
187
+
188
+ def total_overflow= (boolv)
189
+ @total_overflow = boolv ? true : false
190
+ end
191
+
192
+ def format= (format)
193
+ @format = format
194
+ end
195
+
196
+ def format_arguments= (arguments)
197
+ @format_arguments = arguments
198
+ end
199
+
200
+ def finish
201
+ @current = @total
202
+ @is_finished = true
203
+ show_progress
204
+ end
205
+
206
+ def halt
207
+ @is_finished = true
208
+ show_progress
209
+ end
210
+
211
+ def set (count)
212
+ if count < 0
213
+ raise "invalid count less than zero: #{count}"
214
+ elsif count > @total
215
+ if @total_overflow
216
+ @total = count + 1
217
+ else
218
+ raise "invalid count greater than total: #{count}"
219
+ end
220
+ end
221
+ @current = count
222
+ show_progress
223
+ @previous = @current
224
+ end
225
+
226
+ def inc (step = 1)
227
+ @current += step
228
+ @current = @total if @current > @total
229
+ show_progress
230
+ @previous = @current
231
+ end
232
+
233
+ def inspect
234
+ "(ProgressBar: #{@current}/#{@total})"
235
+ end
236
+
237
+ end