rip 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.gitignore +4 -0
  2. data/LICENSE +20 -0
  3. data/README.markdown +306 -0
  4. data/Rakefile +51 -0
  5. data/bin/rip +6 -0
  6. data/examples/debug.rb +13 -0
  7. data/examples/reverse.rb +21 -0
  8. data/ext/extconf.rb +11 -0
  9. data/lib/rip.rb +53 -0
  10. data/lib/rip/commands.rb +113 -0
  11. data/lib/rip/commands/build.rb +23 -0
  12. data/lib/rip/commands/core.rb +82 -0
  13. data/lib/rip/commands/install.rb +37 -0
  14. data/lib/rip/commands/uninstall.rb +43 -0
  15. data/lib/rip/env.rb +128 -0
  16. data/lib/rip/installer.rb +130 -0
  17. data/lib/rip/memoize.rb +111 -0
  18. data/lib/rip/package.rb +126 -0
  19. data/lib/rip/package_api.rb +94 -0
  20. data/lib/rip/package_manager.rb +175 -0
  21. data/lib/rip/packages/dir_package.rb +34 -0
  22. data/lib/rip/packages/file_package.rb +60 -0
  23. data/lib/rip/packages/gem_package.rb +44 -0
  24. data/lib/rip/packages/git_package.rb +62 -0
  25. data/lib/rip/packages/http_package.rb +46 -0
  26. data/lib/rip/packages/remote_gem_package.rb +64 -0
  27. data/lib/rip/packages/ripfile_package.rb +46 -0
  28. data/lib/rip/setup.rb +205 -0
  29. data/lib/rip/sh/git.rb +35 -0
  30. data/lib/rip/ui.rb +24 -0
  31. data/lib/rip/version.rb +9 -0
  32. data/setup.rb +27 -0
  33. data/test/commands_test.rb +15 -0
  34. data/test/dev.rip +2 -0
  35. data/test/dir_test.rb +25 -0
  36. data/test/env_test.rb +173 -0
  37. data/test/git_test.rb +36 -0
  38. data/test/mock_git.rb +51 -0
  39. data/test/repos/simple_c/dot_git/HEAD +1 -0
  40. data/test/repos/simple_c/dot_git/config +6 -0
  41. data/test/repos/simple_c/dot_git/description +1 -0
  42. data/test/repos/simple_c/dot_git/hooks/applypatch-msg.sample +15 -0
  43. data/test/repos/simple_c/dot_git/hooks/commit-msg.sample +24 -0
  44. data/test/repos/simple_c/dot_git/hooks/post-commit.sample +8 -0
  45. data/test/repos/simple_c/dot_git/hooks/post-receive.sample +15 -0
  46. data/test/repos/simple_c/dot_git/hooks/post-update.sample +8 -0
  47. data/test/repos/simple_c/dot_git/hooks/pre-applypatch.sample +14 -0
  48. data/test/repos/simple_c/dot_git/hooks/pre-commit.sample +18 -0
  49. data/test/repos/simple_c/dot_git/hooks/pre-rebase.sample +169 -0
  50. data/test/repos/simple_c/dot_git/hooks/prepare-commit-msg.sample +36 -0
  51. data/test/repos/simple_c/dot_git/hooks/update.sample +107 -0
  52. data/test/repos/simple_c/dot_git/index +0 -0
  53. data/test/repos/simple_c/dot_git/info/exclude +6 -0
  54. data/test/repos/simple_c/dot_git/logs/HEAD +1 -0
  55. data/test/repos/simple_c/dot_git/logs/refs/heads/master +1 -0
  56. data/test/repos/simple_c/dot_git/objects/2d/94227280db3ac66875f52592c6a736b4526084 +0 -0
  57. data/test/repos/simple_c/dot_git/objects/3f/1d6dacdedf75058e9edf23f48de03fa451f7ce +1 -0
  58. data/test/repos/simple_c/dot_git/objects/53/23e9a7ff897fe7bfc3357d9274775b67f9ade4 +0 -0
  59. data/test/repos/simple_c/dot_git/objects/55/31db58bd71148661c400dc48815bf06b366128 +0 -0
  60. data/test/repos/simple_c/dot_git/objects/d7/55c6f119520808609a8d79bac1a8dbe0c57424 +0 -0
  61. data/test/repos/simple_c/dot_git/objects/d7/58739ea968ac8e8fe0cbbf1f6451af47f04964 +0 -0
  62. data/test/repos/simple_c/dot_git/objects/e6/7b81a24f0ce4bff84c3599b5c9ba7093f554d8 +0 -0
  63. data/test/repos/simple_c/dot_git/objects/ec/be0a80dc841c16beb2c733bbdd320b45565d89 +0 -0
  64. data/test/repos/simple_c/dot_git/refs/heads/master +1 -0
  65. data/test/repos/simple_c/ext/simp/extconf.rb +6 -0
  66. data/test/repos/simple_c/ext/simp/simp.c +17 -0
  67. data/test/repos/simple_c/lib/simple_c.rb +1 -0
  68. data/test/repos/simple_d-1.2.3/lib/simple_d.rb +1 -0
  69. data/test/rip_test.rb +8 -0
  70. data/test/test_helper.rb +79 -0
  71. data/test/ui_test.rb +36 -0
  72. metadata +149 -0
@@ -0,0 +1,34 @@
1
+ module Rip
2
+ class DirPackage < Package
3
+ handles do |source|
4
+ File.directory? source
5
+ end
6
+
7
+ def initialize(source, *args)
8
+ super
9
+ @source = File.expand_path(source)
10
+ end
11
+
12
+ def exists?
13
+ File.directory? source
14
+ end
15
+
16
+ memoize :name
17
+ def name
18
+ File.basename(source)
19
+ end
20
+
21
+ def version
22
+ if name.match(/-((?:\d+\.?)+\d+)$/)
23
+ $1
24
+ else
25
+ "unversioned"
26
+ end
27
+ end
28
+
29
+ def fetch!
30
+ FileUtils.rm_rf cache_path
31
+ FileUtils.cp_r "#{source}/.", cache_path
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ require 'date'
2
+
3
+ module Rip
4
+ class FilePackage < Package
5
+ handles do |source|
6
+ File.file?(source)
7
+ end
8
+
9
+ def initialize(source, *args)
10
+ super
11
+ @source = File.expand_path(source)
12
+ end
13
+
14
+ def exists?
15
+ File.file? source
16
+ end
17
+
18
+ memoize :name
19
+ def name
20
+ source.split('/').last
21
+ end
22
+
23
+ def version
24
+ Date.today.to_s
25
+ end
26
+
27
+ def fetch!
28
+ FileUtils.rm_rf cache_path
29
+ FileUtils.mkdir_p cache_path
30
+ FileUtils.cp source, cache_path
31
+ end
32
+
33
+ def files!
34
+ fetch
35
+
36
+ Dir.chdir cache_path do
37
+ file = File.readlines(source)[0...5].detect do |line|
38
+ line =~ /^# ?file:(.+)/
39
+ end
40
+
41
+ if file
42
+ dir = File.dirname($1)
43
+ file = File.basename($1)
44
+ [ File.join(Rip::Env.active_dir, dir, file) ]
45
+ else
46
+ [ File.join(Rip::Env.active_dir, 'lib', name) ]
47
+ end
48
+ end
49
+ end
50
+
51
+ def unpack!
52
+ Dir.chdir cache_path do
53
+ files.each do |file|
54
+ FileUtils.mkdir_p File.dirname(file)
55
+ FileUtils.cp File.join(cache_path, name), file
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,44 @@
1
+ module Rip
2
+ class GemPackage < Package
3
+ handles '.gem'
4
+
5
+ def initialize(source, *args)
6
+ super
7
+ @source = File.expand_path(source.strip.chomp)
8
+ end
9
+
10
+ def name
11
+ metadata[:name]
12
+ end
13
+
14
+ def version
15
+ metadata[:version]
16
+ end
17
+
18
+ def cache_file
19
+ "#{cache_path}.gem"
20
+ end
21
+
22
+ def exists?
23
+ if `which gem`.strip.empty?
24
+ ui.abort "you don't have rubygems installed"
25
+ end
26
+
27
+ File.exists?(source)
28
+ end
29
+
30
+ def fetch!
31
+ FileUtils.cp File.expand_path(source), cache_file
32
+ end
33
+
34
+ def unpack!
35
+ system "gem unpack #{cache_file} --target=#{packages_path} > /dev/null"
36
+ end
37
+
38
+ memoize :metadata
39
+ def metadata
40
+ parts = source.split('/').last.chomp('.gem').split('-')
41
+ { :name => parts[0...-1].join('-'), :version => parts[-1] }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,62 @@
1
+ module Rip
2
+ class GitPackage < Package
3
+ include Sh::Git
4
+
5
+ handles "file://", "git://", '.git'
6
+
7
+ memoize :name
8
+ def name
9
+ source.split('/').last.chomp('.git')
10
+ end
11
+
12
+ def version
13
+ return @version if @version
14
+
15
+ fetch!
16
+ Dir.chdir cache_path do
17
+ @version = git_revparse('origin/master')[0,7]
18
+ end
19
+ end
20
+
21
+ def exists?
22
+ case source
23
+ when /^file:/
24
+ file_exists?
25
+ when /^git:/
26
+ remote_exists?
27
+ when /\.git$/
28
+ file_exists? || remote_exists?
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def fetch!
35
+ if File.exists? cache_path
36
+ Dir.chdir cache_path do
37
+ git_fetch('origin')
38
+ end
39
+ else
40
+ git_clone(source, cache_name)
41
+ end
42
+ end
43
+
44
+ def unpack!
45
+ Dir.chdir cache_path do
46
+ git_reset_hard(version)
47
+ git_submodule_init
48
+ git_submodule_update
49
+ end
50
+ end
51
+
52
+ private
53
+ def file_exists?
54
+ File.exists? File.join(source.sub('file://', ''), '.git')
55
+ end
56
+
57
+ def remote_exists?
58
+ out = git_ls_remote(source, @version)
59
+ out.include? @version || 'HEAD'
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,46 @@
1
+ require 'net/http'
2
+ require 'date'
3
+
4
+ module Rip
5
+ class HTTPPackage < Package
6
+ handles 'http://'
7
+
8
+ def exists?
9
+ code = Net::HTTP.get_response(URI.parse(source)).code
10
+ code.to_i == 200
11
+ end
12
+
13
+ memoize :name
14
+ def name
15
+ source.split('/').last
16
+ end
17
+
18
+ def meta_package?
19
+ true
20
+ end
21
+
22
+ def fetch!
23
+ FileUtils.rm_rf cache_path
24
+ FileUtils.mkdir_p cache_path
25
+ File.open(File.join(cache_path, name), 'w') do |f|
26
+ f.puts Net::HTTP.get(URI.parse(source))
27
+ end
28
+ end
29
+
30
+ def unpack!
31
+ installer = Installer.new
32
+ installer.install actual_package
33
+ installer.manager.sources[actual_package.name] = source
34
+ installer.manager.save
35
+ end
36
+
37
+ def version
38
+ actual_package ? actual_package.version : super
39
+ end
40
+
41
+ memoize :actual_package
42
+ def actual_package
43
+ Package.for(File.join(cache_path, name))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,64 @@
1
+ require 'timeout'
2
+
3
+ module Rip
4
+ class RemoteGemPackage < Package
5
+ handles do |source|
6
+ RemoteGemPackage.new(source).exists?
7
+ end
8
+
9
+ @@remotes = %w( gems.github.com gems.rubyforge.org )
10
+ @@exists_cache = {}
11
+
12
+ def exists?
13
+ return false unless source =~ /^[\w-]+$/
14
+ return true if @@exists_cache[source] || File.exists?(cache_path)
15
+
16
+ FileUtils.mkdir_p cache_path
17
+
18
+ Dir.chdir cache_path do
19
+ @@remotes.each do |remote|
20
+ ui.puts "Searching %s for %s..." % [ remote, source ]
21
+
22
+ source_flag = "--source=http://#{remote}/"
23
+ if rgem("fetch #{source} #{source_flag}") =~ /Downloaded (.+)/
24
+ @@exists_cache[source] = $1
25
+ return true
26
+ end
27
+ end
28
+ end
29
+
30
+ false
31
+ end
32
+
33
+ def rgem(command)
34
+ Timeout.timeout(5) do
35
+ `gem #{command}`
36
+ end
37
+ rescue Timeout::Error
38
+ ''
39
+ end
40
+
41
+ def meta_package?
42
+ true
43
+ end
44
+
45
+ def fetch!
46
+ end
47
+
48
+ def unpack!
49
+ installer = Installer.new
50
+ installer.install actual_package
51
+ installer.manager.sources[actual_package.name] = source
52
+ installer.manager.save
53
+ end
54
+
55
+ def version
56
+ actual_package ? actual_package.version : super
57
+ end
58
+
59
+ memoize :actual_package
60
+ def actual_package
61
+ Package.for(Dir[cache_path + '/*'].first)
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,46 @@
1
+ module Rip
2
+ class RipfilePackage < Package
3
+ handles '.rip'
4
+
5
+ def initialize(source, *args)
6
+ super
7
+ @source = File.expand_path(source)
8
+ end
9
+
10
+ def exists?
11
+ File.exists? source
12
+ end
13
+
14
+ def name
15
+ source.split('/').last
16
+ end
17
+
18
+ def meta_package?
19
+ true
20
+ end
21
+
22
+ def cached?
23
+ false
24
+ end
25
+
26
+ def fetch!
27
+ end
28
+
29
+ def unpack!
30
+ FileUtils.rm_rf cache_path
31
+ FileUtils.mkdir_p cache_path
32
+ FileUtils.cp source, cache_path
33
+ end
34
+
35
+ def dependencies!
36
+ if File.exists? deps = File.join(cache_path, name)
37
+ File.readlines(deps).map do |line|
38
+ source, version, *extra = line.split(' ')
39
+ Package.for(source, version)
40
+ end
41
+ else
42
+ []
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,205 @@
1
+ require 'rbconfig'
2
+ require 'fileutils'
3
+
4
+ module Rip
5
+ module Setup
6
+ extend self
7
+
8
+
9
+ #
10
+ # config
11
+ #
12
+
13
+ WEBSITE = "http://hellorip.com/"
14
+ STARTUP_SCRIPTS = %w( .bash_profile .bash_login .bashrc .zshrc .profile )
15
+
16
+ __DIR__ = File.expand_path(File.dirname(__FILE__))
17
+
18
+ HOME = File.expand_path('~')
19
+ USER = HOME.split('/')[-1]
20
+ LIBDIR = RbConfig::CONFIG['sitelibdir']
21
+ RIPDIR = File.expand_path(ENV['RIPDIR'] || File.join(HOME, '.rip'))
22
+ RIPROOT = File.expand_path(File.join(__DIR__, '..', '..'))
23
+ RIPINSTALLDIR = File.join(LIBDIR, 'rip')
24
+
25
+ # caution: RbConfig::CONFIG['bindir'] does NOT work for me
26
+ # on OS X
27
+ BINDIR = File.join('/', 'usr', 'local', 'bin')
28
+
29
+
30
+ #
31
+ # setup steps
32
+ #
33
+
34
+ def install
35
+ install_libs
36
+ install_binary
37
+ setup_ripenv
38
+ setup_startup_script
39
+ finish_setup
40
+ end
41
+
42
+ def uninstall(verbose = false)
43
+ FileUtils.rm_rf RIPINSTALLDIR, :verbose => verbose
44
+ FileUtils.rm_rf File.join(LIBDIR, 'rip.rb'), :verbose => verbose
45
+ FileUtils.rm_rf RIPDIR, :verbose => verbose
46
+ FileUtils.rm File.join(BINDIR, 'rip'), :verbose => verbose
47
+
48
+ # just in case...
49
+ `gem uninstall rip 2&> /dev/null`
50
+
51
+ ui.abort "rip uninstalled" if verbose
52
+ rescue Errno::EACCES
53
+ ui.abort "rip: uninstall failed. please try again with `sudo`" if verbose
54
+ rescue Errno::ENOENT
55
+ nil
56
+ rescue => e
57
+ raise e if verbose
58
+ end
59
+
60
+ def install_libs(verbose = false)
61
+ transaction "installing library files" do
62
+ riprb = File.join(RIPROOT, 'lib', 'rip.rb')
63
+ ripdr = File.join(RIPROOT, 'lib', 'rip')
64
+ FileUtils.cp_r riprb, LIBDIR, :verbose => verbose
65
+ FileUtils.cp_r ripdr, LIBDIR, :verbose => verbose
66
+ end
67
+ end
68
+
69
+ def install_binary(verbose = false)
70
+ transaction "installing rip binary" do
71
+ src = File.join(RIPROOT, 'bin', 'rip')
72
+ dst = File.join(BINDIR, 'rip')
73
+ FileUtils.cp src, dst, :verbose => verbose
74
+ end
75
+ end
76
+
77
+ def setup_ripenv(ripdir=RIPDIR, verbose = false)
78
+ transaction "setting up ripenv" do
79
+ FileUtils.mkdir_p File.join(ripdir, 'rip-packages')
80
+ Rip.dir = ripdir
81
+ Rip::Env.create 'base'
82
+ FileUtils.chown_R USER, nil, ripdir, :verbose => verbose
83
+ end
84
+ end
85
+
86
+ def setup_startup_script
87
+ script = startup_script
88
+
89
+ if script.empty?
90
+ ui.puts "rip: please create one of these startup scripts in $HOME:"
91
+ ui.puts startup_scripts.map { |s| ' ' + s }
92
+ exit
93
+ end
94
+
95
+ if File.read(script).include? 'RIPDIR='
96
+ ui.puts "rip: env variables already present in startup script"
97
+ else
98
+ ui.puts "rip: adding env variables to #{script}"
99
+ File.open(script, 'a+') do |f|
100
+ f.puts startup_script_template
101
+ end
102
+ end
103
+ end
104
+
105
+ def finish_setup
106
+ ui.puts finish_setup_banner(startup_script)
107
+ end
108
+
109
+ def finish_setup_banner(script = "~/.bashrc")
110
+ <<-EOI.gsub(/^ +/, "")
111
+ ****************************************************
112
+ So far so good...
113
+
114
+ Run `rip check` to be sure Rip installed successfully
115
+
116
+ NOTE: You may need to source your #{script}
117
+ or start a new shell session.
118
+
119
+ Get started: `rip -h` or #{WEBSITE}
120
+
121
+ ****************************************************
122
+ EOI
123
+ end
124
+
125
+ #
126
+ # helper methods
127
+ #
128
+
129
+ def transaction(message, &block)
130
+ ui.puts 'rip: ' + message
131
+ block.call
132
+ rescue Errno::EACCES
133
+ uninstall
134
+ ui.abort "access denied. please try running again with `sudo`"
135
+ rescue => e
136
+ ui.puts "rip: something failed, rolling back..."
137
+ uninstall
138
+ raise e
139
+ end
140
+
141
+ def startup_script_template
142
+ STARTUP_SCRIPT_TEMPLATE % RIPDIR
143
+ end
144
+
145
+ def startup_script
146
+ script = STARTUP_SCRIPTS.detect do |script|
147
+ File.exists? file = File.join(HOME, script)
148
+ end
149
+
150
+ script ? File.join(HOME, script) : ''
151
+ end
152
+
153
+ def installed?
154
+ check_installation
155
+ true
156
+ rescue
157
+ false
158
+ end
159
+
160
+ def check_installation
161
+ script = startup_script
162
+
163
+ if !File.read(script).include? 'RIPDIR='
164
+ raise "no env variables in startup script"
165
+ end
166
+
167
+ if ENV['RIPDIR'].to_s.empty?
168
+ if startup_script.empty?
169
+ raise "no $RIPDIR."
170
+ else
171
+ raise "no $RIPDIR. you may need to run `source #{startup_script}`"
172
+ end
173
+ end
174
+
175
+ if !File.exists? File.join(BINDIR, 'rip')
176
+ raise "no rip in #{BINDIR}"
177
+ end
178
+
179
+ if !File.exists? File.join(LIBDIR, 'rip')
180
+ raise "no rip in #{LIBDIR}"
181
+ end
182
+
183
+ if !File.exists? File.join(LIBDIR, 'rip')
184
+ raise "no rip.rb in #{LIBDIR}"
185
+ end
186
+
187
+ true
188
+ end
189
+
190
+ def ui
191
+ Rip.ui
192
+ end
193
+ end
194
+
195
+ STARTUP_SCRIPT_TEMPLATE = <<-end_template
196
+
197
+ # -- start rip config -- #
198
+ RIPDIR=%s
199
+ RUBYLIB="$RUBYLIB:$RIPDIR/active/lib"
200
+ PATH="$PATH:$RIPDIR/active/bin"
201
+ export RIPDIR RUBYLIB PATH
202
+ # -- end rip config -- #
203
+ end_template
204
+
205
+ end