nogara-resque-loner 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/CHANGELOG.markdown +27 -0
- data/Gemfile +8 -0
- data/LICENSE +19 -0
- data/README.markdown +103 -0
- data/Rakefile +83 -0
- data/init.rb +1 -0
- data/lib/resque-ext/job.rb +57 -0
- data/lib/resque-ext/resque.rb +26 -0
- data/lib/resque-loner.rb +6 -0
- data/lib/resque-loner/helpers.rb +73 -0
- data/lib/resque-loner/unique_job.rb +75 -0
- data/lib/resque-loner/version.rb +7 -0
- data/rails/init.rb +1 -0
- data/resque-loner.gemspec +50 -0
- data/spec/loner_spec.rb +165 -0
- data/spec/redis-test.conf +115 -0
- data/spec/spec_helper.rb +14 -0
- data/tasks/redis.rake +159 -0
- data/tasks/resque.rake +2 -0
- data/test/hoptoad_test.rb +25 -0
- data/test/job_hooks_test.rb +323 -0
- data/test/job_plugins_test.rb +230 -0
- data/test/plugin_test.rb +116 -0
- data/test/redis-test.conf +115 -0
- data/test/resque-web_test.rb +53 -0
- data/test/resque_test.rb +259 -0
- data/test/test_helper.rb +148 -0
- data/test/worker_test.rb +332 -0
- metadata +185 -0
data/rails/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'resque-loner'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib/', __FILE__)
|
3
|
+
$:.unshift lib unless $:.include?(lib)
|
4
|
+
|
5
|
+
require 'resque-loner/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = 'nogara-resque-loner'
|
9
|
+
s.version = Resque::Plugins::Loner::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = ['Jannis Hermanns']
|
12
|
+
s.email = ['jannis@moviepilot.com']
|
13
|
+
s.homepage = 'http://github.com/jayniz/resque-loner'
|
14
|
+
s.summary = 'Adds unique jobs to resque'
|
15
|
+
s.has_rdoc = false
|
16
|
+
|
17
|
+
s.rubyforge_project = 'resque-loner'
|
18
|
+
|
19
|
+
s.add_dependency 'resque', '~>1.0'
|
20
|
+
{
|
21
|
+
'rake' => '> 0.8.7',
|
22
|
+
'rack-test' => '~> 0.5.7',
|
23
|
+
'rspec' => '~> 2.5.0',
|
24
|
+
'mock_redis' => '~> 0.2.0',
|
25
|
+
'yajl-ruby' => '~> 0.8.2'
|
26
|
+
}.each do |lib, version|
|
27
|
+
s.add_development_dependency lib, version
|
28
|
+
end
|
29
|
+
|
30
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
31
|
+
s.files = `git ls-files`.split("\n")
|
32
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
|
35
|
+
s.description = <<desc
|
36
|
+
Makes sure that for special jobs, there can be only one job with the same workload in one queue.
|
37
|
+
|
38
|
+
Example:
|
39
|
+
class CacheSweeper
|
40
|
+
|
41
|
+
include Resque::Plugins::UniqueJob
|
42
|
+
|
43
|
+
@queue = :cache_sweeps
|
44
|
+
|
45
|
+
def self.perform(article_id)
|
46
|
+
# Cache Me If You Can...
|
47
|
+
end
|
48
|
+
end
|
49
|
+
desc
|
50
|
+
end
|
data/spec/loner_spec.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
#
|
5
|
+
# Resque-loner specific specs. I'm shooting right through the stack here and just
|
6
|
+
# test the outcomes, because the implementation will change soon and the tests run
|
7
|
+
# quite quickly.
|
8
|
+
#
|
9
|
+
|
10
|
+
class SomeJob
|
11
|
+
@queue = :some_queue
|
12
|
+
end
|
13
|
+
|
14
|
+
class SomeUniqueJob
|
15
|
+
|
16
|
+
include Resque::Plugins::UniqueJob
|
17
|
+
|
18
|
+
@queue = :other_queue
|
19
|
+
def self.perform(foo); end
|
20
|
+
end
|
21
|
+
|
22
|
+
class FailingUniqueJob
|
23
|
+
include Resque::Plugins::UniqueJob
|
24
|
+
@queue = :other_queue
|
25
|
+
def self.perform(foo)
|
26
|
+
raise "I beg to differ"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class DeprecatedUniqueJob < Resque::Plugins::Loner::UniqueJob
|
31
|
+
|
32
|
+
@queue = :other_queue
|
33
|
+
def self.perform(foo); end
|
34
|
+
end
|
35
|
+
|
36
|
+
class UniqueJobWithTtl
|
37
|
+
include Resque::Plugins::UniqueJob
|
38
|
+
@queue = :unique_with_ttl
|
39
|
+
@loner_ttl = 300
|
40
|
+
|
41
|
+
def self.perform(*args); end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "Resque" do
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
Resque.redis.flushall
|
48
|
+
Resque.size(:other_queue).should == 0
|
49
|
+
Resque.size(:some_queue).should == 0
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "Jobs" do
|
53
|
+
it "can put multiple normal jobs on a queue" do
|
54
|
+
Resque.enqueue SomeJob, "foo"
|
55
|
+
Resque.enqueue SomeJob, "foo"
|
56
|
+
Resque.size(:some_queue).should == 2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should allow only one of the same job to sit in a queue" do
|
60
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
61
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
62
|
+
Resque.size(:other_queue).should == 1
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should support deprecated Resque::Plugins::Loner::UniqueJob class" do
|
66
|
+
Resque.enqueue DeprecatedUniqueJob, "foo"
|
67
|
+
Resque.enqueue DeprecatedUniqueJob, "foo"
|
68
|
+
Resque.size(:other_queue).should == 1
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should allow the same jobs to be executed one after the other" do
|
72
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
73
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
74
|
+
Resque.size(:other_queue).should == 1
|
75
|
+
|
76
|
+
Resque.reserve(:other_queue)
|
77
|
+
Resque.size(:other_queue).should == 0
|
78
|
+
|
79
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
80
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
81
|
+
Resque.size(:other_queue).should == 1
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should be robust regarding hash attributes" do
|
85
|
+
Resque.enqueue SomeUniqueJob, :bar => 1, :foo => 2
|
86
|
+
Resque.enqueue SomeUniqueJob, :foo => 2, :bar => 1
|
87
|
+
Resque.size(:other_queue).should == 1
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should be robust regarding hash attributes (JSON does not distinguish between string and symbol)" do
|
91
|
+
Resque.enqueue SomeUniqueJob, :bar => 1, :foo => 1
|
92
|
+
Resque.enqueue SomeUniqueJob, :bar => 1, "foo" => 1
|
93
|
+
Resque.size(:other_queue).should == 1
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should mark jobs as unqueued, when Job.destroy is killing them" do
|
97
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
98
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
99
|
+
Resque.size(:other_queue).should == 1
|
100
|
+
|
101
|
+
Resque::Job.destroy(:other_queue, SomeUniqueJob)
|
102
|
+
Resque.size(:other_queue).should == 0
|
103
|
+
|
104
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
105
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
106
|
+
Resque.size(:other_queue).should == 1
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should mark jobs as unqueued, when they raise an exception during #perform" do
|
110
|
+
2.times { Resque.enqueue( FailingUniqueJob, "foo" ) }
|
111
|
+
Resque.size(:other_queue).should == 1
|
112
|
+
|
113
|
+
worker = Resque::Worker.new(:other_queue)
|
114
|
+
worker.work 0
|
115
|
+
Resque.size(:other_queue).should == 0
|
116
|
+
|
117
|
+
2.times { Resque.enqueue( FailingUniqueJob, "foo" ) }
|
118
|
+
Resque.size(:other_queue).should == 1
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should report if a job is queued or not" do
|
122
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
123
|
+
Resque.enqueued?(SomeUniqueJob, "foo").should be_true
|
124
|
+
Resque.enqueued?(SomeUniqueJob, "bar").should be_false
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should report if a job is in a special queue or not" do
|
128
|
+
default_queue = SomeUniqueJob.instance_variable_get(:@queue)
|
129
|
+
SomeUniqueJob.instance_variable_set(:@queue, :special_queue)
|
130
|
+
|
131
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
132
|
+
Resque.enqueued_in?( :special_queue, SomeUniqueJob, "foo").should be_true
|
133
|
+
|
134
|
+
SomeUniqueJob.instance_variable_set(:@queue, default_queue)
|
135
|
+
|
136
|
+
Resque.enqueued?( SomeUniqueJob, "foo").should be_false
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should not be able to report if a non-unique job was enqueued" do
|
140
|
+
Resque.enqueued?(SomeJob).should be_nil
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should cleanup all loners when a queue is destroyed" do
|
144
|
+
Resque.enqueue SomeUniqueJob, "foo"
|
145
|
+
Resque.enqueue FailingUniqueJob, "foo"
|
146
|
+
|
147
|
+
Resque.remove_queue(:other_queue)
|
148
|
+
|
149
|
+
Resque.enqueue(SomeUniqueJob, "foo")
|
150
|
+
Resque.size(:other_queue).should == 1
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should not raise an error when deleting an already empty queue' do
|
154
|
+
expect { Resque.remove_queue(:other_queue) }.to_not raise_error
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should honor loner_ttl in the redis key' do
|
158
|
+
Resque.enqueue UniqueJobWithTtl
|
159
|
+
Resque.enqueued?(UniqueJobWithTtl).should be_true
|
160
|
+
k=Resque.redis.keys "loners:queue:unique_with_ttl:job:*"
|
161
|
+
k.length.should == 1
|
162
|
+
Resque.redis.ttl(k[0]).should be_within(2).of(UniqueJobWithTtl.loner_ttl)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Redis configuration file example
|
2
|
+
|
3
|
+
# By default Redis does not run as a daemon. Use 'yes' if you need it.
|
4
|
+
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
|
5
|
+
daemonize yes
|
6
|
+
|
7
|
+
# When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
|
8
|
+
# You can specify a custom pid file location here.
|
9
|
+
pidfile ./spec/redis-test.pid
|
10
|
+
|
11
|
+
# Accept connections on the specified port, default is 6379
|
12
|
+
port 9736
|
13
|
+
|
14
|
+
# If you want you can bind a single interface, if the bind option is not
|
15
|
+
# specified all the interfaces will listen for connections.
|
16
|
+
#
|
17
|
+
# bind 127.0.0.1
|
18
|
+
|
19
|
+
# Close the connection after a client is idle for N seconds (0 to disable)
|
20
|
+
timeout 300
|
21
|
+
|
22
|
+
# Save the DB on disk:
|
23
|
+
#
|
24
|
+
# save <seconds> <changes>
|
25
|
+
#
|
26
|
+
# Will save the DB if both the given number of seconds and the given
|
27
|
+
# number of write operations against the DB occurred.
|
28
|
+
#
|
29
|
+
# In the example below the behaviour will be to save:
|
30
|
+
# after 900 sec (15 min) if at least 1 key changed
|
31
|
+
# after 300 sec (5 min) if at least 10 keys changed
|
32
|
+
# after 60 sec if at least 10000 keys changed
|
33
|
+
save 900 1
|
34
|
+
save 300 10
|
35
|
+
save 60 10000
|
36
|
+
|
37
|
+
# The filename where to dump the DB
|
38
|
+
dbfilename dump.rdb
|
39
|
+
|
40
|
+
# For default save/load DB in/from the working directory
|
41
|
+
# Note that you must specify a directory not a file name.
|
42
|
+
dir ./spec/
|
43
|
+
|
44
|
+
# Set server verbosity to 'debug'
|
45
|
+
# it can be one of:
|
46
|
+
# debug (a lot of information, useful for development/testing)
|
47
|
+
# notice (moderately verbose, what you want in production probably)
|
48
|
+
# warning (only very important / critical messages are logged)
|
49
|
+
loglevel debug
|
50
|
+
|
51
|
+
# Specify the log file name. Also 'stdout' can be used to force
|
52
|
+
# the demon to log on the standard output. Note that if you use standard
|
53
|
+
# output for logging but daemonize, logs will be sent to /dev/null
|
54
|
+
logfile stdout
|
55
|
+
|
56
|
+
# Set the number of databases. The default database is DB 0, you can select
|
57
|
+
# a different one on a per-connection basis using SELECT <dbid> where
|
58
|
+
# dbid is a number between 0 and 'databases'-1
|
59
|
+
databases 16
|
60
|
+
|
61
|
+
################################# REPLICATION #################################
|
62
|
+
|
63
|
+
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
|
64
|
+
# another Redis server. Note that the configuration is local to the slave
|
65
|
+
# so for example it is possible to configure the slave to save the DB with a
|
66
|
+
# different interval, or to listen to another port, and so on.
|
67
|
+
|
68
|
+
# slaveof <masterip> <masterport>
|
69
|
+
|
70
|
+
################################## SECURITY ###################################
|
71
|
+
|
72
|
+
# Require clients to issue AUTH <PASSWORD> before processing any other
|
73
|
+
# commands. This might be useful in environments in which you do not trust
|
74
|
+
# others with access to the host running redis-server.
|
75
|
+
#
|
76
|
+
# This should stay commented out for backward compatibility and because most
|
77
|
+
# people do not need auth (e.g. they run their own servers).
|
78
|
+
|
79
|
+
# requirepass foobared
|
80
|
+
|
81
|
+
################################### LIMITS ####################################
|
82
|
+
|
83
|
+
# Set the max number of connected clients at the same time. By default there
|
84
|
+
# is no limit, and it's up to the number of file descriptors the Redis process
|
85
|
+
# is able to open. The special value '0' means no limts.
|
86
|
+
# Once the limit is reached Redis will close all the new connections sending
|
87
|
+
# an error 'max number of clients reached'.
|
88
|
+
|
89
|
+
# maxclients 128
|
90
|
+
|
91
|
+
# Don't use more memory than the specified amount of bytes.
|
92
|
+
# When the memory limit is reached Redis will try to remove keys with an
|
93
|
+
# EXPIRE set. It will try to start freeing keys that are going to expire
|
94
|
+
# in little time and preserve keys with a longer time to live.
|
95
|
+
# Redis will also try to remove objects from free lists if possible.
|
96
|
+
#
|
97
|
+
# If all this fails, Redis will start to reply with errors to commands
|
98
|
+
# that will use more memory, like SET, LPUSH, and so on, and will continue
|
99
|
+
# to reply to most read-only commands like GET.
|
100
|
+
#
|
101
|
+
# WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
|
102
|
+
# 'state' server or cache, not as a real DB. When Redis is used as a real
|
103
|
+
# database the memory usage will grow over the weeks, it will be obvious if
|
104
|
+
# it is going to use too much memory in the long run, and you'll have the time
|
105
|
+
# to upgrade. With maxmemory after the limit is reached you'll start to get
|
106
|
+
# errors for write operations, and this may even lead to DB inconsistency.
|
107
|
+
|
108
|
+
# maxmemory <bytes>
|
109
|
+
|
110
|
+
############################### ADVANCED CONFIG ###############################
|
111
|
+
|
112
|
+
# Glue small output buffers together in order to send small replies in a
|
113
|
+
# single TCP packet. Uses a bit more CPU but most of the times it is a win
|
114
|
+
# in terms of number of queries per second. Use 'yes' if unsure.
|
115
|
+
glueoutputbuf yes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec'
|
4
|
+
|
5
|
+
require 'ruby-debug'
|
6
|
+
require 'mock_redis'
|
7
|
+
require 'resque'
|
8
|
+
require 'resque-loner'
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.before(:suite) do
|
12
|
+
Resque.redis = MockRedis.new
|
13
|
+
end
|
14
|
+
end
|
data/tasks/redis.rake
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# Inspired by rabbitmq.rake the Redbox project at http://github.com/rick/redbox/tree/master
|
2
|
+
require 'fileutils'
|
3
|
+
require 'open-uri'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
class RedisRunner
|
7
|
+
|
8
|
+
def self.redis_dir
|
9
|
+
@redis_dir ||= if ENV['PREFIX']
|
10
|
+
Pathname.new(ENV['PREFIX'])
|
11
|
+
else
|
12
|
+
Pathname.new(`which redis-server`) + '..' + '..'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.bin_dir
|
17
|
+
redis_dir + 'bin'
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.config
|
21
|
+
@config ||= if File.exists?(redis_dir + 'etc/redis.conf')
|
22
|
+
redis_dir + 'etc/redis.conf'
|
23
|
+
else
|
24
|
+
redis_dir + '../etc/redis.conf'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.dtach_socket
|
29
|
+
'/tmp/redis.dtach'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Just check for existance of dtach socket
|
33
|
+
def self.running?
|
34
|
+
File.exists? dtach_socket
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.start
|
38
|
+
puts 'Detach with Ctrl+\ Re-attach with rake redis:attach'
|
39
|
+
sleep 1
|
40
|
+
command = "#{bin_dir}/dtach -A #{dtach_socket} #{bin_dir}/redis-server #{config}"
|
41
|
+
sh command
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.attach
|
45
|
+
exec "#{bin_dir}/dtach -a #{dtach_socket}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.stop
|
49
|
+
sh 'echo "SHUTDOWN" | nc localhost 6379'
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
namespace :redis do
|
55
|
+
|
56
|
+
desc 'About redis'
|
57
|
+
task :about do
|
58
|
+
puts "\nSee http://code.google.com/p/redis/ for information about redis.\n\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
desc 'Start redis'
|
62
|
+
task :start do
|
63
|
+
RedisRunner.start
|
64
|
+
end
|
65
|
+
|
66
|
+
desc 'Stop redis'
|
67
|
+
task :stop do
|
68
|
+
RedisRunner.stop
|
69
|
+
end
|
70
|
+
|
71
|
+
desc 'Restart redis'
|
72
|
+
task :restart do
|
73
|
+
RedisRunner.stop
|
74
|
+
RedisRunner.start
|
75
|
+
end
|
76
|
+
|
77
|
+
desc 'Attach to redis dtach socket'
|
78
|
+
task :attach do
|
79
|
+
RedisRunner.attach
|
80
|
+
end
|
81
|
+
|
82
|
+
desc 'Install the latest verison of Redis from Github (requires git, duh)'
|
83
|
+
task :install => [:about, :download, :make] do
|
84
|
+
bin_dir = '/usr/bin'
|
85
|
+
conf_dir = '/etc'
|
86
|
+
|
87
|
+
if ENV['PREFIX']
|
88
|
+
bin_dir = "#{ENV['PREFIX']}/bin"
|
89
|
+
sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
|
90
|
+
|
91
|
+
conf_dir = "#{ENV['PREFIX']}/etc"
|
92
|
+
sh "mkdir -p #{conf_dir}" unless File.exists?("#{conf_dir}")
|
93
|
+
end
|
94
|
+
|
95
|
+
%w(redis-benchmark redis-cli redis-server).each do |bin|
|
96
|
+
sh "cp /tmp/redis/#{bin} #{bin_dir}"
|
97
|
+
end
|
98
|
+
|
99
|
+
puts "Installed redis-benchmark, redis-cli and redis-server to #{bin_dir}"
|
100
|
+
|
101
|
+
unless File.exists?("#{conf_dir}/redis.conf")
|
102
|
+
sh "cp /tmp/redis/redis.conf #{conf_dir}/redis.conf"
|
103
|
+
puts "Installed redis.conf to #{conf_dir} \n You should look at this file!"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
task :make do
|
108
|
+
sh "cd /tmp/redis && make clean"
|
109
|
+
sh "cd /tmp/redis && make"
|
110
|
+
end
|
111
|
+
|
112
|
+
desc "Download package"
|
113
|
+
task :download do
|
114
|
+
sh 'rm -rf /tmp/redis/' if File.exists?("/tmp/redis/.svn")
|
115
|
+
sh 'git clone git://github.com/antirez/redis.git /tmp/redis' unless File.exists?('/tmp/redis')
|
116
|
+
sh "cd /tmp/redis && git pull" if File.exists?("/tmp/redis/.git")
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
namespace :dtach do
|
122
|
+
|
123
|
+
desc 'About dtach'
|
124
|
+
task :about do
|
125
|
+
puts "\nSee http://dtach.sourceforge.net/ for information about dtach.\n\n"
|
126
|
+
end
|
127
|
+
|
128
|
+
desc 'Install dtach 0.8 from source'
|
129
|
+
task :install => [:about, :download, :make] do
|
130
|
+
|
131
|
+
bin_dir = "/usr/bin"
|
132
|
+
|
133
|
+
if ENV['PREFIX']
|
134
|
+
bin_dir = "#{ENV['PREFIX']}/bin"
|
135
|
+
sh "mkdir -p #{bin_dir}" unless File.exists?("#{bin_dir}")
|
136
|
+
end
|
137
|
+
|
138
|
+
sh "cp /tmp/dtach-0.8/dtach #{bin_dir}"
|
139
|
+
end
|
140
|
+
|
141
|
+
task :make do
|
142
|
+
sh 'cd /tmp/dtach-0.8/ && ./configure && make'
|
143
|
+
end
|
144
|
+
|
145
|
+
desc "Download package"
|
146
|
+
task :download do
|
147
|
+
unless File.exists?('/tmp/dtach-0.8.tar.gz')
|
148
|
+
require 'net/http'
|
149
|
+
|
150
|
+
url = 'http://downloads.sourceforge.net/project/dtach/dtach/0.8/dtach-0.8.tar.gz'
|
151
|
+
open('/tmp/dtach-0.8.tar.gz', 'wb') do |file| file.write(open(url).read) end
|
152
|
+
end
|
153
|
+
|
154
|
+
unless File.directory?('/tmp/dtach-0.8')
|
155
|
+
sh 'cd /tmp && tar xzf dtach-0.8.tar.gz'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|