rip 0.0.1

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