pik 0.1.1 → 0.2.0

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 (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