GitHub Sale: sign up for any paid plan this week and pay nothing until January 1, 2009!  [ hide ]

public
Description: a tiny graphical app kit for ruby
Homepage: http://code.whytheluckystiff.net/shoes
Clone URL: git://github.com/why/shoes.git
shoes / lib / shoes / cache.rb
100644 359 lines (331 sloc) 12.599 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
require 'fileutils'
include FileUtils
 
# locate ~/.shoes
require 'tmpdir'
 
lib_dir = nil
homes = []
homes << [ENV['HOME'], File.join( ENV['HOME'], '.shoes' )] if ENV['HOME']
homes << [ENV['APPDATA'], File.join( ENV['APPDATA'], 'Shoes' )] if ENV['APPDATA']
homes.each do |home_top, home_dir|
  next unless home_top
  if File.exists? home_top
    lib_dir = home_dir
    break
  end
end
LIB_DIR = lib_dir || File.join(Dir::tmpdir, "shoes")
SITE_LIB_DIR = File.join(LIB_DIR, '+lib')
GEM_DIR = File.join(LIB_DIR, '+gem')
CACHE_DIR = File.join(LIB_DIR, '+cache')
GEM_CENTRAL_DIR = File.join(DIR, "ruby/gems")
 
mkdir_p(CACHE_DIR)
$:.unshift SITE_LIB_DIR
$:.unshift GEM_DIR
 
require 'rbconfig'
config = {
  'prefix' => "#{DIR}",
  'rubylibdir' => "#{DIR}/ruby/lib",
  'datarootdir' => "#{DIR}/share",
  'dvidir' => "#{DIR}/doc/${PACKAGE}",
  'psdir' => "#{DIR}/doc/${PACKAGE}",
  'htmldir' => "#{DIR}/doc/${PACKAGE}",
  'docdir' => "#{DIR}/doc/${PACKAGE}",
  'archdir' => "#{DIR}/ruby/lib/#{PLATFORM}",
  'sitedir' => SITE_LIB_DIR,
  'sitelibdir' => SITE_LIB_DIR,
  'sitearchdir' => "#{SITE_LIB_DIR}/#{PLATFORM}",
  'LIBRUBYARG_STATIC' => "",
  'libdir' => "#{DIR}",
  'LDFLAGS' => "-L. -L#{DIR}"
}
Config::CONFIG.merge! config
Config::MAKEFILE_CONFIG.merge! config
 
require 'rubygems'
require 'rubygems/dependency_installer'
class << Gem::Ext::ExtConfBuilder
  def build(extension, directory, dest_path, results)
    Kernel.eval(File.read(File.basename(extension)))
    make(dest_path, results) rescue nil
    results
  end
  # alias_method :make__, :make
  # def make(dest_path, results)
  # raise unless File.exist?('Makefile')
  # mf = File.read('Makefile')
  # mf = mf.gsub(/^INSTALL\s*=\s*\$[^$]*/, "INSTALL = '@$(RUBY) -run -e install -- -vp'")
  # mf = mf.gsub(/^INSTALL_PROG\s*=\s*\$[^$]*/, "INSTALL_PROG = '$(INSTALL) -m 0755'")
  # mf = mf.gsub(/^INSTALL_DATA\s*=\s*\$[^$]*/, "INSTALL_DATA = '$(INSTALL) -m 0644'")
  # File.open('Makefile', 'wb') {|f| f.print mf}
  # make__(dest_path, results)
  # end
end
class << Gem; attr_accessor :loaded_specs end
 
# STDIN.reopen("/dev/tty") if STDIN.eof?
class NotSupportedByShoes < Exception; end
 
class Shoes::Setup
 
  def self.init
    gem_reset
    install_sources if Gem.source_index.find_name('sources').empty?
  end
 
  def self.gem_reset
    Gem.use_paths(GEM_DIR, [GEM_DIR])
    Gem.source_index.refresh!
  end
 
  def self.setup_app(setup)
    appt = "Setting up for #{setup.script}"
    Shoes.app :width => 370, :height => 158, :resizable => false, :title => appt do
      background "#EEC".."#AA9"
      image :top => 0, :left => 0 do
        stroke "#FFF"; strokewidth 0.1
        (0..158).step(3) { |i| line 0, i, 370, i }
        mask { rect 4, 4, 362, 150, 6 }
      end
      @pulse = stack :top => 0, :left => 0
      @logo = image "#{DIR}/static/shoes-icon.png", :top => -20, :right => -20
      stack :margin => 18 do
        title "Shoes Setup", :size => 12, :weight => "bold", :margin => 0
        para "Preparing #{setup.script}", :size => 8, :margin => 0, :margin_top => 8, :width => 220
        progress :width => 1.0, :top => 70, :height => 20
        button "Cancel", :top => 98, :left => 0.4 do
          self.close
        end
 
        start do
          Thread.start(self) do |app|
            begin
              setup.start(app)
            rescue => e
              puts e.message
            end
          end
        end
      end
 
      animate 10 do |i|
        i %= 10
@pulse.clear do
fill black(0.2 - (i * 0.02))
strokewidth(3.0 - (i * 0.2))
stroke red(1.0 - (i * 0.1))
oval(@logo.left - i, @logo.top - i, @logo.width + (i * 2))
end
end
end
end
 
attr_accessor :steps, :script
 
def initialize(script, &blk)
@steps = []
    @script = script
    instance_eval &blk
    unless no_steps?
      app = self.class.setup_app(self)
    end
  end
 
  def no_steps?
    (@steps.map { |s| s[0] }.uniq - [:source]).empty?
  end
 
  def gem name, version = nil
    arg = "#{name} #{version}".strip
    name, version = arg.split(/\s+/, 2)
    if ['hpricot', 'sqlite3-ruby'].include? name
      warn "#{name} is included with Shoes and cannot be installed as a gem."
    else
      if Gem.source_index.find_name(name, version).empty?
        @steps << [:gem, arg]
      end
    end
  end
 
  def source uri
    @steps << [:source, uri]
  end
 
  def start(app)
    old_ui = Gem::DefaultUserInteraction.ui
    ui = Gem::DefaultUserInteraction.ui = Gem::ShoesFace.new(app)
    count, total = 0, @steps.length
    ui.progress count, total
 
    steps.each do |act, arg|
      case act
      when :gem
        name, version = arg.split(/\s+/, 2)
        count += 1
        ui.say "Looking for #{name}"
        if Gem.source_index.find_name(name, version).empty?
          ui.title "Installing #{name}"
          installer = Gem::DependencyInstaller.new
          installer.install(name, version || Gem::Requirement.default)
          self.class.gem_reset
        end
        gem = Gem.source_index.find_name(name, version).first
        Gem.activate(gem.name, "= #{gem.version}")
        ui.say "Finished installing #{name}"
      when :source
        ui.title "Switching Gem servers"
        ui.say "Pulling from #{arg}"
        Gem.sources.clear << arg
        self.class.gem_reset
      end
      ui.progress count, total
    end
    Gem::DefaultUserInteraction.ui = old_ui
 
    Shoes.load(@script)
    app.close
  end
 
  def svn(dir, save_as = nil, &blk)
    dir.gsub! /(.)\/*$/, '\1/'
    if save_as.nil? or save_as.empty?
      save_as = File.join(GEM_DIR, 'svn', '1')
      save_as.succ! while File.exists? save_as
    elsif save_as.index(GEM_DIR) != 0
      save_as = File.join(GEM_DIR, 'svn', save_as)
    end
    mkdir_p(save_as)
    puts "** Pulling down #{dir}..."
    svnuri = URI.parse(dir)
    case svnuri.scheme
    when "http", "https"
      REXML::Document.new(svnuri.open { |f| f.read }).
        each_element("/svn/index/*") do |ele|
          fname, href = ele.attributes['name'], ele.attributes['href']
          case ele.name
          when "file"
            puts "- #{dir}#{href}"
            URI.parse("#{dir}#{href}").open do |f|
              File.open(File.join(save_as, fname), 'wb') do |f2|
                f2 << f.read(16384) until f.eof?
              end
            end
          when "dir"
            svn("#{dir}#{href}", File.join(save_as, fname))
          end
        end
    else
      raise NotSupportedByShoes, "Only HTTP addresses are supported by Shoes's Subversion module."
    end
    if blk
      Dir.chdir(save_as, &blk)
    end
  end
 
  def self.install_sources
    require 'base64'
    sources_gem = File.join(LIB_DIR, "sources-0.0.1.gem")
    File.open(sources_gem, "wb") do |f|
      f << Base64.decode64( <<-GEM.gsub(/^ +/, '') )
ZGF0YS50YXIuZ3oAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADAwMDA2NDQAMDAwMDAwMAAwMDAwMDAwADAwMDAwMDAwMjYw
ADAwMDAwMDAwMDAwADAxMzMxNQAgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB1c3RhcgAwMHdoZWVs
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd2hlZWwAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAwMDAwMDAwADAwMDAwMDAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAfiwgAAKBzRAADyslM0i/OLy1KTi3WK0pioAkw
AAIzMxMwDQTotIGhCYINFgcKGBsxKBjQxjmooLS4JLEIaH15RmpqDh51hOTR
PTdEQG5+SmlOqoJ7ai6XgoIDNCUo2CpEK2WUlBRY6eunp+YCU0ZpUmVaflF6
qh6QUIoFKk1JTVMoTs1J04NqAQoh9AM5qXkpXCA80P4bBaNgFIyCUYAdAAAA
AP//AwBOIUx0AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1ldGFkYXRhLmd6
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAw
MDAwNjQ0ADAwMDAwMDAAMDAwMDAwMAAwMDAwMDAwMDYzMAAwMDAwMDAwMDAw
MAAwMTM0MDAAIDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAdXN0YXIAMDB3aGVlbAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAHdoZWVsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAMDAwMDAwMAAwMDAwMDAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAH4sIAACgc0QAA4SRyW7cMAyG73wKNndPNCkaFDrkmntb9FIEgizR
thItLiVneftKHk88QYHWMqCF5E/yY9d1+ImX/u069Y9kirynIOX3mYwbnNHF
pYjQ7COFrJ6Jc32RKA5fD8cj5Eu/3XqEqANJzGlhQxneDX9n+nkyISBeiIvD
EawuVeJGiNtOfOluPqMQcv2xE7d1g7yEoPlN4o/JZZy1edIj4czp2VnKaNNL
9EnbcxU4JEamkAphbQZdzEV7v5YOTL8Xx6RmXaYsETr0rgcK2vl6m1KguYrL
E4oqNFZXTmsbCDWbYTeXtXjQS0mb3E7A0qAXXxS9klmK7n3T6l20jiXWHSad
FdtkJA7aZzoXZFVLqP4PUMpvp4hAsTSavF9bQ4hdXVd3V/XUzv+cRPs+TENc
jgfmCq0yCBKbCGQ3RhdH9UR1FmCIizKTdhuLKXHN/+sBYHCe3tleb2QO3EOh
XNRmbY6Ng0orz+2FXgvrlc+l3w5zd6OY97CPDNqLpZmipWjcOeYPAAAA//8D
ADLcAkIBAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAA
GEM
    end
    Gem::Installer.new(sources_gem).install()
  end
end
 
class Gem::ShoesFace
  class ProgressReporter
    attr_reader :count
 
    def initialize(prog, status, size, initial_message,
                   terminal_message = "complete")
      @prog = prog
      (@status = status).replace initial_message
      @total = size
      @count = 0.0
    end
 
    def updated(message)
      @count += 1.0
      @prog.fraction = (@count / @total.to_f) * 0.5
    end
 
    def done
    end
  end
 
  def initialize app
    @title, @status, @prog, = app.contents[-1].contents
  end
  def title msg
    @title.replace msg
  end
  def progress count, total
    @prog.fraction = count.to_f / total.to_f
  end
  def ask_yes_no msg
    Kernel.confirm(msg)
  end
  def ask msg
    Kernel.ask(msg)
  end
  def say msg
    @status.replace msg
  end
  def alert msg, quiz=nil
    say(msg)
    ask(quiz) if quiz
  end
  def progress_reporter(*args)
    ProgressReporter.new(@prog, @status, *args)
  end
  def method_missing(*args)
    p args
    nil
  end
end