logging 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +8 -0
- data/Manifest.txt +3 -0
- data/README.txt +11 -8
- data/Rakefile +1 -2
- data/lib/logging.rb +2 -2
- data/lib/logging/appenders/rolling_file.rb +18 -31
- data/lib/logging/stelan/lockfile.rb +530 -0
- data/tasks/ann.rake +76 -0
- data/tasks/annotations.rake +1 -1
- data/tasks/bones.rake +40 -0
- data/tasks/doc.rake +1 -2
- data/tasks/gem.rake +26 -2
- data/tasks/manifest.rake +15 -21
- data/tasks/post_load.rake +22 -10
- data/tasks/setup.rb +50 -13
- data/tasks/test.rake +4 -6
- data/test/appenders/test_rolling_file.rb +9 -7
- metadata +5 -11
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.7.1 / 2008-
|
2
|
+
|
3
|
+
1 minor enhancement
|
4
|
+
- Removed dependency on the Lockfile gem (brought the ruby
|
5
|
+
file into the logging/stelan directory)
|
6
|
+
1 bug fix
|
7
|
+
- Fixed bug with age based rolling: was not multi-process safe
|
8
|
+
|
1
9
|
== 0.7.0 / 2008-02-12
|
2
10
|
|
3
11
|
1 major enhancement
|
data/Manifest.txt
CHANGED
@@ -20,8 +20,11 @@ lib/logging/log_event.rb
|
|
20
20
|
lib/logging/logger.rb
|
21
21
|
lib/logging/repository.rb
|
22
22
|
lib/logging/root_logger.rb
|
23
|
+
lib/logging/stelan/lockfile.rb
|
23
24
|
lib/logging/utils.rb
|
25
|
+
tasks/ann.rake
|
24
26
|
tasks/annotations.rake
|
27
|
+
tasks/bones.rake
|
25
28
|
tasks/doc.rake
|
26
29
|
tasks/gem.rake
|
27
30
|
tasks/manifest.rake
|
data/README.txt
CHANGED
@@ -1,21 +1,22 @@
|
|
1
1
|
Logging
|
2
|
+
by Tim Pease
|
2
3
|
|
3
4
|
* {Homepage}[http://logging.rubyforge.org/]
|
4
5
|
* {Rubyforge Project}[http://rubyforge.org/projects/logging]
|
5
6
|
* email tim dot pease at gmail dot com
|
6
7
|
|
7
|
-
== DESCRIPTION
|
8
|
+
== DESCRIPTION
|
8
9
|
|
9
10
|
Logging is a flexible logging library for use in Ruby programs based on the
|
10
11
|
design of Java's log4j library. It features a hierarchical logging system,
|
11
12
|
custom level names, multiple output destinations per log event, custom
|
12
13
|
formatting, and more.
|
13
14
|
|
14
|
-
== INSTALL
|
15
|
+
== INSTALL
|
15
16
|
|
16
17
|
sudo gem install logging
|
17
18
|
|
18
|
-
== EXAMPLE
|
19
|
+
== EXAMPLE
|
19
20
|
|
20
21
|
This example configures a logger to output messages in a format similar to the
|
21
22
|
core ruby Logger class. Only log messages that are warnings or higher will be
|
@@ -35,8 +36,10 @@ file. Only log messages that are informational or higher will be logged.
|
|
35
36
|
require 'logging'
|
36
37
|
|
37
38
|
logger = Logging::Logger['example_logger']
|
38
|
-
logger.
|
39
|
-
|
39
|
+
logger.add_appenders(
|
40
|
+
Logging::Appender.stdout,
|
41
|
+
Logging::Appenders::File.new('example.log')
|
42
|
+
)
|
40
43
|
logger.level = :info
|
41
44
|
|
42
45
|
logger.debug "this debug message will not be output by the logger"
|
@@ -72,7 +75,7 @@ the recommended way of accomplishing this.
|
|
72
75
|
end
|
73
76
|
end
|
74
77
|
|
75
|
-
== NOTES
|
78
|
+
== NOTES
|
76
79
|
|
77
80
|
Although Logging is intended to supersede Log4r, it is not a one-to-one
|
78
81
|
replacement for the Log4r library. Most notably is the difference in namespaces
|
@@ -81,10 +84,10 @@ Logging::Appender and renaming Log4r::Formatter to Logging::Layout. These
|
|
81
84
|
changes were meant to bring the Logging class names more in line with the Log4j
|
82
85
|
class names.
|
83
86
|
|
84
|
-
== REQUIREMENTS
|
87
|
+
== REQUIREMENTS
|
85
88
|
|
86
89
|
Logging does not depend on any other installed libraries or gems.
|
87
90
|
|
88
|
-
== LICENSE
|
91
|
+
== LICENSE
|
89
92
|
|
90
93
|
Ruby
|
data/Rakefile
CHANGED
@@ -18,11 +18,10 @@ PROJ.rdoc_dir = 'doc/rdoc'
|
|
18
18
|
PROJ.rdoc_remote_dir = ''
|
19
19
|
PROJ.version = Logging::VERSION
|
20
20
|
|
21
|
-
PROJ.exclude
|
21
|
+
PROJ.exclude += %w[^tags$ ^tasks/archive ^coverage]
|
22
22
|
PROJ.rdoc_exclude << '^data'
|
23
23
|
PROJ.svn = true
|
24
24
|
|
25
25
|
depend_on 'flexmock'
|
26
|
-
depend_on 'lockfile'
|
27
26
|
|
28
27
|
# EOF
|
data/lib/logging.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: logging.rb
|
1
|
+
# $Id: logging.rb 105 2008-02-26 04:43:21Z tim_pease $
|
2
2
|
|
3
3
|
# Equivalent to a header guard in C/C++
|
4
4
|
# Used to prevent the class/module from being loaded more than once
|
@@ -12,7 +12,7 @@ unless defined? Logging
|
|
12
12
|
module Logging
|
13
13
|
|
14
14
|
# :stopdoc:
|
15
|
-
VERSION = '0.7.
|
15
|
+
VERSION = '0.7.1'
|
16
16
|
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
17
17
|
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
18
18
|
WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM
|
@@ -1,19 +1,6 @@
|
|
1
|
-
# $Id: rolling_file.rb
|
2
|
-
|
3
|
-
|
4
|
-
require 'lockfile'
|
5
|
-
rescue LoadError
|
6
|
-
require 'rubygems'
|
7
|
-
require 'lockfile'
|
8
|
-
end
|
9
|
-
|
10
|
-
# FIXME: bug when truncating a rolling file on create
|
11
|
-
# If there is not log file in existence, it is created and then
|
12
|
-
# immediately rolld resulting in two log files
|
13
|
-
#
|
14
|
-
# This appears to be because of rails -- creating the logfile and
|
15
|
-
# then we replace the default logger with a rolling file appender. It
|
16
|
-
# sees the already existing log file and happily rolls it right over.
|
1
|
+
# $Id: rolling_file.rb 106 2008-02-26 04:52:42Z tim_pease $
|
2
|
+
|
3
|
+
require Logging.libpath(*%w[logging stelan lockfile])
|
17
4
|
|
18
5
|
module Logging::Appenders
|
19
6
|
|
@@ -88,7 +75,7 @@ module Logging::Appenders
|
|
88
75
|
@size = opts.getopt(:size, :as => Integer)
|
89
76
|
|
90
77
|
@lockfile = if opts.getopt(:safe, false) and !::Logging::WIN32
|
91
|
-
Lockfile.new(
|
78
|
+
::Logging::Lockfile.new(
|
92
79
|
@fn + '.lck',
|
93
80
|
:retries => 1,
|
94
81
|
:timeout => 2
|
@@ -96,39 +83,38 @@ module Logging::Appenders
|
|
96
83
|
end
|
97
84
|
|
98
85
|
code = 'def sufficiently_aged?() false end'
|
86
|
+
@age_fn = @fn + '.age'
|
99
87
|
|
100
88
|
case @age = opts.getopt(:age)
|
101
89
|
when 'daily'
|
102
|
-
@
|
90
|
+
FileUtils.touch(@age_fn) unless test(?f, @age_fn)
|
103
91
|
code = <<-CODE
|
104
92
|
def sufficiently_aged?
|
105
93
|
now = Time.now
|
106
|
-
|
107
|
-
|
94
|
+
start = ::File.mtime(@age_fn)
|
95
|
+
if (now.day != start.day) or (now - start) > 86400
|
108
96
|
return true
|
109
97
|
end
|
110
98
|
false
|
111
99
|
end
|
112
100
|
CODE
|
113
101
|
when 'weekly'
|
114
|
-
@
|
102
|
+
FileUtils.touch(@age_fn) unless test(?f, @age_fn)
|
115
103
|
code = <<-CODE
|
116
104
|
def sufficiently_aged?
|
117
|
-
now
|
118
|
-
if (now - @start_time) > 604800
|
119
|
-
@start_time = now
|
105
|
+
if (Time.now - ::File.mtime(@age_fn)) > 604800
|
120
106
|
return true
|
121
107
|
end
|
122
108
|
false
|
123
109
|
end
|
124
110
|
CODE
|
125
111
|
when 'monthly'
|
126
|
-
@
|
112
|
+
FileUtils.touch(@age_fn) unless test(?f, @age_fn)
|
127
113
|
code = <<-CODE
|
128
114
|
def sufficiently_aged?
|
129
115
|
now = Time.now
|
130
|
-
|
131
|
-
|
116
|
+
start = ::File.mtime(@age_fn)
|
117
|
+
if (now.month != start.month) or (now - start) > 2678400
|
132
118
|
return true
|
133
119
|
end
|
134
120
|
false
|
@@ -136,12 +122,10 @@ module Logging::Appenders
|
|
136
122
|
CODE
|
137
123
|
when Integer, String
|
138
124
|
@age = Integer(@age)
|
139
|
-
@
|
125
|
+
FileUtils.touch(@age_fn) unless test(?f, @age_fn)
|
140
126
|
code = <<-CODE
|
141
127
|
def sufficiently_aged?
|
142
|
-
now
|
143
|
-
if (now - @start_time) > @age
|
144
|
-
@start_time = now
|
128
|
+
if (Time.now - ::File.mtime(@age_fn)) > @age
|
145
129
|
return true
|
146
130
|
end
|
147
131
|
false
|
@@ -264,6 +248,9 @@ module Logging::Appenders
|
|
264
248
|
|
265
249
|
# finally reanme the base log file
|
266
250
|
::File.rename(@fn, sprintf(@logname_fmt, 1))
|
251
|
+
|
252
|
+
# touch the age file if needed
|
253
|
+
FileUtils.touch(@age_fn) if @age
|
267
254
|
end
|
268
255
|
|
269
256
|
# call-seq:
|
@@ -0,0 +1,530 @@
|
|
1
|
+
# $Id: lockfile.rb 101 2008-02-13 17:10:47Z tim_pease $
|
2
|
+
|
3
|
+
# This file was stolen with permission from Ara T. Howrad's gem of the same
|
4
|
+
# name. The only difference is the removal of Ara's vim folding turds and
|
5
|
+
# making the code work with Ruby1.9
|
6
|
+
|
7
|
+
unless(defined?($__logging_lockfile__) or defined?(Logging::Lockfile))
|
8
|
+
|
9
|
+
require 'socket'
|
10
|
+
require 'timeout'
|
11
|
+
require 'fileutils'
|
12
|
+
|
13
|
+
module Logging
|
14
|
+
class Lockfile
|
15
|
+
|
16
|
+
VERSION = '1.4.3'
|
17
|
+
def version() VERSION end
|
18
|
+
|
19
|
+
class LockError < StandardError; end
|
20
|
+
class StolenLockError < LockError; end
|
21
|
+
class StackingLockError < LockError; end
|
22
|
+
class StatLockError < LockError; end
|
23
|
+
class MaxTriesLockError < LockError; end
|
24
|
+
class TimeoutLockError < LockError; end
|
25
|
+
class NFSLockError < LockError; end
|
26
|
+
class UnLockError < LockError; end
|
27
|
+
|
28
|
+
class SleepCycle < Array
|
29
|
+
attr :min
|
30
|
+
attr :max
|
31
|
+
attr :range
|
32
|
+
attr :inc
|
33
|
+
|
34
|
+
def initialize( min, max, inc )
|
35
|
+
@min, @max, @inc = Float(min), Float(max), Float(inc)
|
36
|
+
@range = @max - @min
|
37
|
+
raise RangeError, "max(#{ @max }) <= min(#{ @min })" if @max <= @min
|
38
|
+
raise RangeError, "inc(#{ @inc }) > range(#{ @range })" if @inc > @range
|
39
|
+
raise RangeError, "inc(#{ @inc }) <= 0" if @inc <= 0
|
40
|
+
raise RangeError, "range(#{ @range }) <= 0" if @range <= 0
|
41
|
+
s = @min
|
42
|
+
push(s) and s += @inc while(s <= @max)
|
43
|
+
self[-1] = @max if self[-1] < @max
|
44
|
+
reset
|
45
|
+
end
|
46
|
+
|
47
|
+
def next
|
48
|
+
ret = self[@idx]
|
49
|
+
@idx = ((@idx + 1) % self.size)
|
50
|
+
ret
|
51
|
+
end
|
52
|
+
|
53
|
+
def reset
|
54
|
+
@idx = 0
|
55
|
+
end
|
56
|
+
end # class SleepCycle
|
57
|
+
|
58
|
+
HOSTNAME = Socket::gethostname
|
59
|
+
|
60
|
+
DEFAULT_RETRIES = nil # maximum number of attempts
|
61
|
+
DEFAULT_TIMEOUT = nil # the longest we will try
|
62
|
+
DEFAULT_MAX_AGE = 3600 # lockfiles older than this are stale
|
63
|
+
DEFAULT_SLEEP_INC = 2 # sleep cycle is this much longer each time
|
64
|
+
DEFAULT_MIN_SLEEP = 2 # shortest sleep time
|
65
|
+
DEFAULT_MAX_SLEEP = 32 # longest sleep time
|
66
|
+
DEFAULT_SUSPEND = 1800 # iff we steal a lock wait this long before we go on
|
67
|
+
DEFAULT_REFRESH = 8 # how often we touch/validate the lock
|
68
|
+
DEFAULT_DONT_CLEAN = false # iff we leave lock files lying around
|
69
|
+
DEFAULT_POLL_RETRIES = 16 # this many polls makes one 'try'
|
70
|
+
DEFAULT_POLL_MAX_SLEEP = 0.08 # the longest we'll sleep between polls
|
71
|
+
DEFAULT_DONT_SWEEP = false # if we cleanup after other process on our host
|
72
|
+
DEFAULT_DONT_USE_LOCK_ID = false # if we dump lock info into lockfile
|
73
|
+
|
74
|
+
DEFAULT_DEBUG = ENV['LOCKFILE_DEBUG'] || false
|
75
|
+
|
76
|
+
class << self
|
77
|
+
attr_accessor :retries
|
78
|
+
attr_accessor :max_age
|
79
|
+
attr_accessor :sleep_inc
|
80
|
+
attr_accessor :min_sleep
|
81
|
+
attr_accessor :max_sleep
|
82
|
+
attr_accessor :suspend
|
83
|
+
attr_accessor :timeout
|
84
|
+
attr_accessor :refresh
|
85
|
+
attr_accessor :debug
|
86
|
+
attr_accessor :dont_clean
|
87
|
+
attr_accessor :poll_retries
|
88
|
+
attr_accessor :poll_max_sleep
|
89
|
+
attr_accessor :dont_sweep
|
90
|
+
attr_accessor :dont_use_lock_id
|
91
|
+
|
92
|
+
def init
|
93
|
+
@retries = DEFAULT_RETRIES
|
94
|
+
@max_age = DEFAULT_MAX_AGE
|
95
|
+
@sleep_inc = DEFAULT_SLEEP_INC
|
96
|
+
@min_sleep = DEFAULT_MIN_SLEEP
|
97
|
+
@max_sleep = DEFAULT_MAX_SLEEP
|
98
|
+
@suspend = DEFAULT_SUSPEND
|
99
|
+
@timeout = DEFAULT_TIMEOUT
|
100
|
+
@refresh = DEFAULT_REFRESH
|
101
|
+
@dont_clean = DEFAULT_DONT_CLEAN
|
102
|
+
@poll_retries = DEFAULT_POLL_RETRIES
|
103
|
+
@poll_max_sleep = DEFAULT_POLL_MAX_SLEEP
|
104
|
+
@dont_sweep = DEFAULT_DONT_SWEEP
|
105
|
+
@dont_use_lock_id = DEFAULT_DONT_USE_LOCK_ID
|
106
|
+
|
107
|
+
@debug = DEFAULT_DEBUG
|
108
|
+
|
109
|
+
STDOUT.sync = true if @debug
|
110
|
+
STDERR.sync = true if @debug
|
111
|
+
end
|
112
|
+
end
|
113
|
+
self.init
|
114
|
+
|
115
|
+
attr :klass
|
116
|
+
attr :path
|
117
|
+
attr :opts
|
118
|
+
attr :locked
|
119
|
+
attr :thief
|
120
|
+
attr :dirname
|
121
|
+
attr :basename
|
122
|
+
attr :clean
|
123
|
+
attr :retries
|
124
|
+
attr :max_age
|
125
|
+
attr :sleep_inc
|
126
|
+
attr :min_sleep
|
127
|
+
attr :max_sleep
|
128
|
+
attr :suspend
|
129
|
+
attr :refresh
|
130
|
+
attr :timeout
|
131
|
+
attr :dont_clean
|
132
|
+
attr :poll_retries
|
133
|
+
attr :poll_max_sleep
|
134
|
+
attr :dont_sweep
|
135
|
+
attr :dont_use_lock_id
|
136
|
+
|
137
|
+
attr_accessor :debug
|
138
|
+
|
139
|
+
alias thief? thief
|
140
|
+
alias locked? locked
|
141
|
+
alias debug? debug
|
142
|
+
|
143
|
+
def self::create( path, *a, &b )
|
144
|
+
opts = {
|
145
|
+
'retries' => 0,
|
146
|
+
'min_sleep' => 0,
|
147
|
+
'max_sleep' => 1,
|
148
|
+
'sleep_inc' => 1,
|
149
|
+
'max_age' => nil,
|
150
|
+
'suspend' => 0,
|
151
|
+
'refresh' => nil,
|
152
|
+
'timeout' => nil,
|
153
|
+
'poll_retries' => 0,
|
154
|
+
'dont_clean' => true,
|
155
|
+
'dont_sweep' => false,
|
156
|
+
'dont_use_lock_id' => true
|
157
|
+
}
|
158
|
+
begin
|
159
|
+
new(path, opts).lock
|
160
|
+
rescue LockError
|
161
|
+
raise Errno::EEXIST, path
|
162
|
+
end
|
163
|
+
open(path, *a, &b)
|
164
|
+
end
|
165
|
+
|
166
|
+
def initialize( path, opts = {}, &block )
|
167
|
+
@klass = self.class
|
168
|
+
@path = path
|
169
|
+
@opts = opts
|
170
|
+
|
171
|
+
@retries = getopt 'retries' , @klass.retries
|
172
|
+
@max_age = getopt 'max_age' , @klass.max_age
|
173
|
+
@sleep_inc = getopt 'sleep_inc' , @klass.sleep_inc
|
174
|
+
@min_sleep = getopt 'min_sleep' , @klass.min_sleep
|
175
|
+
@max_sleep = getopt 'max_sleep' , @klass.max_sleep
|
176
|
+
@suspend = getopt 'suspend' , @klass.suspend
|
177
|
+
@timeout = getopt 'timeout' , @klass.timeout
|
178
|
+
@refresh = getopt 'refresh' , @klass.refresh
|
179
|
+
@dont_clean = getopt 'dont_clean' , @klass.dont_clean
|
180
|
+
@poll_retries = getopt 'poll_retries' , @klass.poll_retries
|
181
|
+
@poll_max_sleep = getopt 'poll_max_sleep' , @klass.poll_max_sleep
|
182
|
+
@dont_sweep = getopt 'dont_sweep' , @klass.dont_sweep
|
183
|
+
@dont_use_lock_id = getopt 'dont_use_lock_id' , @klass.dont_use_lock_id
|
184
|
+
@debug = getopt 'debug' , @klass.debug
|
185
|
+
|
186
|
+
@sleep_cycle = SleepCycle::new @min_sleep, @max_sleep, @sleep_inc
|
187
|
+
|
188
|
+
@clean = @dont_clean ? nil : lambda{ File::unlink @path rescue nil }
|
189
|
+
@dirname = File::dirname @path
|
190
|
+
@basename = File::basename @path
|
191
|
+
@thief = false
|
192
|
+
@locked = false
|
193
|
+
|
194
|
+
lock(&block) if block
|
195
|
+
end
|
196
|
+
|
197
|
+
def lock
|
198
|
+
raise StackingLockError, "<#{ @path }> is locked!" if @locked
|
199
|
+
|
200
|
+
sweep unless @dont_sweep
|
201
|
+
|
202
|
+
ret = nil
|
203
|
+
|
204
|
+
attempt do
|
205
|
+
begin
|
206
|
+
@sleep_cycle.reset
|
207
|
+
create_tmplock do |f|
|
208
|
+
begin
|
209
|
+
Timeout::timeout(@timeout) do
|
210
|
+
tmp_path = f.path
|
211
|
+
tmp_stat = f.lstat
|
212
|
+
n_retries = 0
|
213
|
+
trace{ "attempting to lock <#{ @path }>..." }
|
214
|
+
begin
|
215
|
+
i = 0
|
216
|
+
begin
|
217
|
+
trace{ "polling attempt <#{ i }>..." }
|
218
|
+
begin
|
219
|
+
File::link tmp_path, @path
|
220
|
+
rescue Errno::ENOENT
|
221
|
+
try_again!
|
222
|
+
end
|
223
|
+
lock_stat = File::lstat @path
|
224
|
+
raise StatLockError, "stat's do not agree" unless
|
225
|
+
tmp_stat.rdev == lock_stat.rdev and tmp_stat.ino == lock_stat.ino
|
226
|
+
trace{ "aquired lock <#{ @path }>" }
|
227
|
+
@locked = true
|
228
|
+
rescue => e
|
229
|
+
i += 1
|
230
|
+
unless i >= @poll_retries
|
231
|
+
t = [rand(@poll_max_sleep), @poll_max_sleep].min
|
232
|
+
trace{ "poll sleep <#{ t }>..." }
|
233
|
+
sleep t
|
234
|
+
retry
|
235
|
+
end
|
236
|
+
raise
|
237
|
+
end
|
238
|
+
|
239
|
+
rescue => e
|
240
|
+
n_retries += 1
|
241
|
+
trace{ "n_retries <#{ n_retries }>" }
|
242
|
+
case validlock?
|
243
|
+
when true
|
244
|
+
raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
|
245
|
+
@retries and n_retries >= @retries
|
246
|
+
trace{ "found valid lock" }
|
247
|
+
sleeptime = @sleep_cycle.next
|
248
|
+
trace{ "sleep <#{ sleeptime }>..." }
|
249
|
+
sleep sleeptime
|
250
|
+
when false
|
251
|
+
trace{ "found invalid lock and removing" }
|
252
|
+
begin
|
253
|
+
File::unlink @path
|
254
|
+
@thief = true
|
255
|
+
warn "<#{ @path }> stolen by <#{ Process.pid }> at <#{ timestamp }>"
|
256
|
+
trace{ "i am a thief!" }
|
257
|
+
rescue Errno::ENOENT
|
258
|
+
end
|
259
|
+
trace{ "suspending <#{ @suspend }>" }
|
260
|
+
sleep @suspend
|
261
|
+
when nil
|
262
|
+
raise MaxTriesLockError, "surpased retries <#{ @retries }>" if
|
263
|
+
@retries and n_retries >= @retries
|
264
|
+
end
|
265
|
+
retry
|
266
|
+
end # begin
|
267
|
+
end # timeout
|
268
|
+
rescue Timeout::Error
|
269
|
+
raise TimeoutLockError, "surpassed timeout <#{ @timeout }>"
|
270
|
+
end # begin
|
271
|
+
end # create_tmplock
|
272
|
+
|
273
|
+
if block_given?
|
274
|
+
stolen = false
|
275
|
+
refresher = (@refresh ? new_refresher : nil)
|
276
|
+
begin
|
277
|
+
begin
|
278
|
+
ret = yield @path
|
279
|
+
rescue StolenLockError
|
280
|
+
stolen = true
|
281
|
+
raise
|
282
|
+
end
|
283
|
+
ensure
|
284
|
+
begin
|
285
|
+
refresher.kill if refresher and refresher.status
|
286
|
+
ensure
|
287
|
+
unlock unless stolen
|
288
|
+
end
|
289
|
+
end
|
290
|
+
else
|
291
|
+
ObjectSpace.define_finalizer self, @clean if @clean
|
292
|
+
ret = self
|
293
|
+
end
|
294
|
+
rescue Errno::ESTALE, Errno::EIO => e
|
295
|
+
raise(NFSLockError, errmsg(e))
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
return ret
|
300
|
+
end
|
301
|
+
|
302
|
+
def sweep
|
303
|
+
begin
|
304
|
+
glob = File::join(@dirname, ".*lck")
|
305
|
+
paths = Dir[glob]
|
306
|
+
paths.each do |path|
|
307
|
+
begin
|
308
|
+
basename = File::basename path
|
309
|
+
pat = %r/^\s*\.([^_]+)_([^_]+)/o
|
310
|
+
if pat.match(basename)
|
311
|
+
host, pid = $1, $2
|
312
|
+
else
|
313
|
+
next
|
314
|
+
end
|
315
|
+
host.gsub!(%r/^\.+|\.+$/,'')
|
316
|
+
quad = host.split %r/\./
|
317
|
+
host = quad.first
|
318
|
+
pat = %r/^\s*#{ host }/i
|
319
|
+
if pat.match(HOSTNAME) and %r/^\s*\d+\s*$/.match(pid)
|
320
|
+
unless alive?(pid)
|
321
|
+
trace{ "process <#{ pid }> on <#{ host }> is no longer alive" }
|
322
|
+
trace{ "sweeping <#{ path }>" }
|
323
|
+
FileUtils::rm_f path
|
324
|
+
else
|
325
|
+
trace{ "process <#{ pid }> on <#{ host }> is still alive" }
|
326
|
+
trace{ "ignoring <#{ path }>" }
|
327
|
+
end
|
328
|
+
else
|
329
|
+
trace{ "ignoring <#{ path }> generated by <#{ host }>" }
|
330
|
+
end
|
331
|
+
rescue
|
332
|
+
next
|
333
|
+
end
|
334
|
+
end
|
335
|
+
rescue => e
|
336
|
+
warn(errmsg(e))
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
def alive?( pid )
|
341
|
+
pid = Integer("#{ pid }")
|
342
|
+
begin
|
343
|
+
Process::kill 0, pid
|
344
|
+
true
|
345
|
+
rescue Errno::ESRCH
|
346
|
+
false
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def unlock
|
351
|
+
raise UnLockError, "<#{ @path }> is not locked!" unless @locked
|
352
|
+
begin
|
353
|
+
File::unlink @path
|
354
|
+
rescue Errno::ENOENT
|
355
|
+
raise StolenLockError, @path
|
356
|
+
ensure
|
357
|
+
@thief = false
|
358
|
+
@locked = false
|
359
|
+
ObjectSpace.undefine_finalizer self if @clean
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def new_refresher
|
364
|
+
Thread::new(Thread::current, @path, @refresh, @dont_use_lock_id) do |thread, path, refresh, dont_use_lock_id|
|
365
|
+
loop do
|
366
|
+
begin
|
367
|
+
touch path
|
368
|
+
trace{"touched <#{ path }> @ <#{ Time.now.to_f }>"}
|
369
|
+
unless dont_use_lock_id
|
370
|
+
loaded = load_lock_id(IO.read(path))
|
371
|
+
trace{"loaded <\n#{ loaded.inspect }\n>"}
|
372
|
+
raise unless loaded == @lock_id
|
373
|
+
end
|
374
|
+
sleep refresh
|
375
|
+
rescue Exception => e
|
376
|
+
trace{errmsg e}
|
377
|
+
thread.raise StolenLockError
|
378
|
+
Thread::exit
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def validlock?
|
385
|
+
if @max_age
|
386
|
+
uncache @path rescue nil
|
387
|
+
begin
|
388
|
+
return((Time.now - File::stat(@path).mtime) < @max_age)
|
389
|
+
rescue Errno::ENOENT
|
390
|
+
return nil
|
391
|
+
end
|
392
|
+
else
|
393
|
+
exist = File::exist?(@path)
|
394
|
+
return(exist ? true : nil)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
def uncache( file )
|
399
|
+
refresh = nil
|
400
|
+
begin
|
401
|
+
is_a_file = File === file
|
402
|
+
path = (is_a_file ? file.path : file.to_s)
|
403
|
+
stat = (is_a_file ? file.stat : File::stat(file.to_s))
|
404
|
+
refresh = tmpnam(File::dirname(path))
|
405
|
+
File::link path, refresh
|
406
|
+
File::chmod stat.mode, path
|
407
|
+
File::utime stat.atime, stat.mtime, path
|
408
|
+
ensure
|
409
|
+
begin
|
410
|
+
File::unlink refresh if refresh
|
411
|
+
rescue Errno::ENOENT
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
def create_tmplock
|
417
|
+
tmplock = tmpnam @dirname
|
418
|
+
begin
|
419
|
+
create(tmplock) do |f|
|
420
|
+
unless dont_use_lock_id
|
421
|
+
@lock_id = gen_lock_id
|
422
|
+
dumped = dump_lock_id
|
423
|
+
trace{"lock_id <\n#{ @lock_id.inspect }\n>"}
|
424
|
+
f.write dumped
|
425
|
+
f.flush
|
426
|
+
end
|
427
|
+
yield f
|
428
|
+
end
|
429
|
+
ensure
|
430
|
+
begin; File::unlink tmplock; rescue Errno::ENOENT; end if tmplock
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def gen_lock_id
|
435
|
+
Hash[
|
436
|
+
'host' => "#{ HOSTNAME }",
|
437
|
+
'pid' => "#{ Process.pid }",
|
438
|
+
'ppid' => "#{ Process.ppid }",
|
439
|
+
'time' => timestamp
|
440
|
+
]
|
441
|
+
end
|
442
|
+
|
443
|
+
def timestamp
|
444
|
+
time = Time.now
|
445
|
+
usec = time.usec.to_s
|
446
|
+
usec << '0' while usec.size < 6
|
447
|
+
"#{ time.strftime('%Y-%m-%d %H:%M:%S') }.#{ usec }"
|
448
|
+
end
|
449
|
+
|
450
|
+
def dump_lock_id lock_id = @lock_id
|
451
|
+
"host: %s\npid: %s\nppid: %s\ntime: %s\n" %
|
452
|
+
lock_id.values_at('host','pid','ppid','time')
|
453
|
+
end
|
454
|
+
|
455
|
+
def load_lock_id( buf )
|
456
|
+
lock_id = {}
|
457
|
+
kv = %r/([^:]+):(.*)/o
|
458
|
+
buf.each do |line|
|
459
|
+
m = kv.match line
|
460
|
+
k, v = m[1], m[2]
|
461
|
+
next unless m and k and v
|
462
|
+
lock_id[k.strip] = v.strip
|
463
|
+
end
|
464
|
+
lock_id
|
465
|
+
end
|
466
|
+
|
467
|
+
def tmpnam( dir, seed = File::basename($0) )
|
468
|
+
pid = Process.pid
|
469
|
+
time = Time.now
|
470
|
+
sec = time.to_i
|
471
|
+
usec = time.usec
|
472
|
+
"%s%s.%s_%d_%s_%d_%d_%d.lck" %
|
473
|
+
[dir, File::SEPARATOR, HOSTNAME, pid, seed, sec, usec, rand(sec)]
|
474
|
+
end
|
475
|
+
|
476
|
+
def create( path )
|
477
|
+
umask = nil
|
478
|
+
f = nil
|
479
|
+
begin
|
480
|
+
umask = File::umask 022
|
481
|
+
f = open path, File::WRONLY|File::CREAT|File::EXCL, 0644
|
482
|
+
ensure
|
483
|
+
File::umask umask if umask
|
484
|
+
end
|
485
|
+
return(block_given? ? begin; yield f; ensure; f.close; end : f)
|
486
|
+
end
|
487
|
+
|
488
|
+
def touch( path )
|
489
|
+
FileUtils.touch path
|
490
|
+
end
|
491
|
+
|
492
|
+
def getopt( key, default = nil )
|
493
|
+
[ key, key.to_s, key.to_s.intern ].each do |k|
|
494
|
+
return @opts[k] if @opts.has_key?(k)
|
495
|
+
end
|
496
|
+
return default
|
497
|
+
end
|
498
|
+
|
499
|
+
def to_str
|
500
|
+
@path
|
501
|
+
end
|
502
|
+
alias to_s to_str
|
503
|
+
|
504
|
+
def trace( s = nil )
|
505
|
+
STDERR.puts((s ? s : yield)) if @debug
|
506
|
+
end
|
507
|
+
|
508
|
+
def errmsg( e )
|
509
|
+
"%s (%s)\n%s\n" % [e.class, e.message, e.backtrace.join("\n")]
|
510
|
+
end
|
511
|
+
|
512
|
+
def attempt
|
513
|
+
ret = nil
|
514
|
+
loop{ break unless catch('attempt'){ ret = yield } == 'try_again' }
|
515
|
+
ret
|
516
|
+
end
|
517
|
+
|
518
|
+
def try_again!
|
519
|
+
throw 'attempt', 'try_again'
|
520
|
+
end
|
521
|
+
alias again! try_again!
|
522
|
+
|
523
|
+
def give_up!
|
524
|
+
throw 'attempt', 'give_up'
|
525
|
+
end
|
526
|
+
end # class Lockfile
|
527
|
+
end # module Logging
|
528
|
+
|
529
|
+
$__logging_lockfile__ = __FILE__
|
530
|
+
end
|
data/tasks/ann.rake
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# $Id: ann.rake 105 2008-02-26 04:43:21Z tim_pease $
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bones/smtp_tls'
|
5
|
+
rescue LoadError
|
6
|
+
require 'net/smtp'
|
7
|
+
end
|
8
|
+
require 'time'
|
9
|
+
|
10
|
+
namespace :ann do
|
11
|
+
|
12
|
+
file PROJ.ann_file do
|
13
|
+
puts "Generating #{PROJ.ann_file}"
|
14
|
+
File.open(PROJ.ann_file,'w') do |fd|
|
15
|
+
fd.puts("#{PROJ.name} version #{PROJ.version}")
|
16
|
+
fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
|
17
|
+
fd.puts(" #{PROJ.url}") if PROJ.url
|
18
|
+
fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
|
19
|
+
fd.puts
|
20
|
+
fd.puts("== DESCRIPTION")
|
21
|
+
fd.puts
|
22
|
+
fd.puts(PROJ.description)
|
23
|
+
fd.puts
|
24
|
+
fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
|
25
|
+
fd.puts
|
26
|
+
PROJ.ann_paragraphs.each do |p|
|
27
|
+
fd.puts "== #{p.upcase}"
|
28
|
+
fd.puts
|
29
|
+
fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
|
30
|
+
fd.puts
|
31
|
+
end
|
32
|
+
fd.puts PROJ.ann_text if PROJ.ann_text
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "Create an announcement file"
|
37
|
+
task :announcement => PROJ.ann_file
|
38
|
+
|
39
|
+
desc "Send an email announcement"
|
40
|
+
task :email => PROJ.ann_file do
|
41
|
+
from = PROJ.ann_email[:from] || PROJ.email
|
42
|
+
to = Array(PROJ.ann_email[:to])
|
43
|
+
|
44
|
+
### build a mail header for RFC 822
|
45
|
+
rfc822msg = "From: #{from}\n"
|
46
|
+
rfc822msg << "To: #{to.join(',')}\n"
|
47
|
+
rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
|
48
|
+
rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
|
49
|
+
rfc822msg << "\n"
|
50
|
+
rfc822msg << "Date: #{Time.new.rfc822}\n"
|
51
|
+
rfc822msg << "Message-Id: "
|
52
|
+
rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{PROJ.ann_email[:domain]}>\n\n"
|
53
|
+
rfc822msg << File.read(PROJ.ann_file)
|
54
|
+
|
55
|
+
params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
|
56
|
+
PROJ.ann_email[key]
|
57
|
+
end
|
58
|
+
|
59
|
+
params[3] = PROJ.email if params[3].nil?
|
60
|
+
|
61
|
+
if params[4].nil?
|
62
|
+
STDOUT.write "Please enter your e-mail password (#{params[3]}): "
|
63
|
+
params[4] = STDIN.gets.chomp
|
64
|
+
end
|
65
|
+
|
66
|
+
### send email
|
67
|
+
Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
|
68
|
+
end
|
69
|
+
end # namespace :ann
|
70
|
+
|
71
|
+
desc 'Alias to ann:announcement'
|
72
|
+
task :ann => 'ann:announcement'
|
73
|
+
|
74
|
+
CLOBBER << PROJ.ann_file
|
75
|
+
|
76
|
+
# EOF
|
data/tasks/annotations.rake
CHANGED
data/tasks/bones.rake
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# $Id: bones.rake 105 2008-02-26 04:43:21Z tim_pease $
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
namespace :bones do
|
7
|
+
|
8
|
+
desc 'Show the PROJ open struct'
|
9
|
+
task :debug do |t|
|
10
|
+
atr = if ARGV.length == 2
|
11
|
+
t.application.top_level_tasks.pop
|
12
|
+
end
|
13
|
+
sio = StringIO.new
|
14
|
+
sep = "\n" + ' '*27
|
15
|
+
fmt = "%23s => %s"
|
16
|
+
|
17
|
+
if atr
|
18
|
+
PP.pp(PROJ.send(atr.to_sym), sio, 49)
|
19
|
+
sio.seek 0
|
20
|
+
val = sio.read
|
21
|
+
val = val.split("\n").join(sep)
|
22
|
+
|
23
|
+
puts fmt % [atr, val]
|
24
|
+
else
|
25
|
+
h = PROJ.instance_variable_get(:@table)
|
26
|
+
h.keys.map {|k| k.to_s}.sort.each do |k|
|
27
|
+
sio.truncate 0
|
28
|
+
PP.pp(h[k.to_sym], sio, 49)
|
29
|
+
sio.seek 0
|
30
|
+
val = sio.read
|
31
|
+
val = val.split("\n").join(sep)
|
32
|
+
|
33
|
+
puts fmt % [k, val]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end # namespace :bones
|
39
|
+
|
40
|
+
# EOF
|
data/tasks/doc.rake
CHANGED
@@ -31,7 +31,6 @@ namespace :doc do
|
|
31
31
|
sh "#{RDOC} --ri -o ri ."
|
32
32
|
end
|
33
33
|
|
34
|
-
desc 'Remove ri products'
|
35
34
|
task :clobber_ri do
|
36
35
|
rm_r 'ri' rescue nil
|
37
36
|
end
|
@@ -44,6 +43,6 @@ task :doc => 'doc:rdoc'
|
|
44
43
|
desc 'Remove all build products'
|
45
44
|
task :clobber => %w(doc:clobber_rdoc doc:clobber_ri)
|
46
45
|
|
47
|
-
remove_desc_for_task %w(doc:clobber_rdoc
|
46
|
+
remove_desc_for_task %w(doc:clobber_rdoc)
|
48
47
|
|
49
48
|
# EOF
|
data/tasks/gem.rake
CHANGED
@@ -12,6 +12,7 @@ namespace :gem do
|
|
12
12
|
s.email = PROJ.email
|
13
13
|
s.homepage = Array(PROJ.url).first
|
14
14
|
s.rubyforge_project = PROJ.rubyforge_name
|
15
|
+
s.post_install_message = PROJ.post_install_message
|
15
16
|
|
16
17
|
s.description = PROJ.description
|
17
18
|
|
@@ -62,9 +63,29 @@ namespace :gem do
|
|
62
63
|
puts PROJ.spec.to_ruby
|
63
64
|
end
|
64
65
|
|
65
|
-
Rake::
|
66
|
+
pkg = Rake::PackageTask.new(PROJ.name, PROJ.version) do |pkg|
|
66
67
|
pkg.need_tar = PROJ.need_tar
|
67
68
|
pkg.need_zip = PROJ.need_zip
|
69
|
+
pkg.package_files += PROJ.spec.files
|
70
|
+
end
|
71
|
+
Rake::Task['gem:package'].instance_variable_set(:@full_comment, nil)
|
72
|
+
|
73
|
+
gem_file = if PROJ.spec.platform == Gem::Platform::RUBY
|
74
|
+
"#{pkg.package_name}.gem"
|
75
|
+
else
|
76
|
+
"#{pkg.package_name}-#{PROJ.spec.platform}.gem"
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Build the gem file #{gem_file}"
|
80
|
+
task :package => "#{pkg.package_dir}/#{gem_file}"
|
81
|
+
|
82
|
+
file "#{pkg.package_dir}/#{gem_file}" => [pkg.package_dir] + PROJ.spec.files do
|
83
|
+
when_writing("Creating GEM") {
|
84
|
+
Gem::Builder.new(PROJ.spec).build
|
85
|
+
verbose(true) {
|
86
|
+
mv gem_file, "#{pkg.package_dir}/#{gem_file}"
|
87
|
+
}
|
88
|
+
}
|
68
89
|
end
|
69
90
|
|
70
91
|
desc 'Install the gem'
|
@@ -74,9 +95,12 @@ namespace :gem do
|
|
74
95
|
|
75
96
|
desc 'Uninstall the gem'
|
76
97
|
task :uninstall do
|
77
|
-
sh "#{SUDO} #{GEM} uninstall -v '#{PROJ.version}' -x #{PROJ.name}"
|
98
|
+
sh "#{SUDO} #{GEM} uninstall -v '#{PROJ.version}' -i -x #{PROJ.name}"
|
78
99
|
end
|
79
100
|
|
101
|
+
desc 'Reinstall the gem'
|
102
|
+
task :reinstall => [:uninstall, :install]
|
103
|
+
|
80
104
|
end # namespace :gem
|
81
105
|
|
82
106
|
desc 'Alias to gem:package'
|
data/tasks/manifest.rake
CHANGED
@@ -6,18 +6,11 @@ namespace :manifest do
|
|
6
6
|
|
7
7
|
desc 'Verify the manifest'
|
8
8
|
task :check do
|
9
|
-
fn = '
|
10
|
-
files =
|
11
|
-
exclude = Regexp.new(PROJ.exclude.join('|'))
|
12
|
-
Find.find '.' do |path|
|
13
|
-
path.sub! %r/^(\.\/|\/)/o, ''
|
14
|
-
next unless test ?f, path
|
15
|
-
next if path =~ exclude
|
16
|
-
files << path
|
17
|
-
end
|
9
|
+
fn = PROJ.manifest_file + '.tmp'
|
10
|
+
files = manifest_files
|
18
11
|
|
19
|
-
File.open(fn, 'w') {|fp| fp.puts files
|
20
|
-
lines = %x(#{DIFF} -du
|
12
|
+
File.open(fn, 'w') {|fp| fp.puts files}
|
13
|
+
lines = %x(#{DIFF} -du #{PROJ.manifest_file} #{fn}).split("\n")
|
21
14
|
if HAVE_FACETS_ANSICODE and ENV.has_key?('TERM')
|
22
15
|
lines.map! do |line|
|
23
16
|
case line
|
@@ -34,19 +27,20 @@ namespace :manifest do
|
|
34
27
|
|
35
28
|
desc 'Create a new manifest'
|
36
29
|
task :create do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
path.sub! %r/^(\.\/|\/)/o, ''
|
42
|
-
next unless test ?f, path
|
43
|
-
next if path =~ exclude
|
44
|
-
files << path
|
30
|
+
files = manifest_files
|
31
|
+
unless test(?f, PROJ.manifest_file)
|
32
|
+
files << PROJ.manifest_file
|
33
|
+
files.sort!
|
45
34
|
end
|
35
|
+
File.open(PROJ.manifest_file, 'w') {|fp| fp.puts files}
|
36
|
+
end
|
46
37
|
|
47
|
-
|
48
|
-
|
38
|
+
task :assert do
|
39
|
+
files = manifest_files
|
40
|
+
manifest = File.read(PROJ.manifest_file).split($/)
|
41
|
+
raise "ERROR: #{PROJ.manifest_file} is out of date" unless files == manifest
|
49
42
|
end
|
43
|
+
|
50
44
|
end # namespace :manifest
|
51
45
|
|
52
46
|
desc 'Alias to manifest:check'
|
data/tasks/post_load.rake
CHANGED
@@ -1,18 +1,30 @@
|
|
1
|
-
# $Id$
|
1
|
+
# $Id: post_load.rake 105 2008-02-26 04:43:21Z tim_pease $
|
2
2
|
|
3
3
|
# This file does not define any rake tasks. It is used to load some project
|
4
4
|
# settings if they are not defined by the user.
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
end
|
6
|
+
PROJ.rdoc_exclude << "^#{Regexp.escape(PROJ.manifest_file)}$"
|
7
|
+
PROJ.exclude << "^#{Regexp.escape(PROJ.ann_file)}$"
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
PROJ.exclude.flatten!
|
10
|
+
PROJ.rdoc_exclude.flatten!
|
11
|
+
PROJ.annotation_exclude.flatten!
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
PROJ.changes ||= paragraphs_of(PROJ.history_file, 0..1).join("\n\n")
|
14
|
+
|
15
|
+
PROJ.description ||= paragraphs_of(PROJ.readme_file, 'description').join("\n\n")
|
16
|
+
|
17
|
+
PROJ.summary ||= PROJ.description.split('.').first
|
18
|
+
|
19
|
+
PROJ.files ||=
|
20
|
+
if test(?f, PROJ.manifest_file)
|
21
|
+
files = File.readlines(PROJ.manifest_file).map {|fn| fn.chomp.strip}
|
22
|
+
files.delete ''
|
23
|
+
files
|
24
|
+
else [] end
|
25
|
+
|
26
|
+
PROJ.executables ||= PROJ.files.find_all {|fn| fn =~ %r/^bin/}
|
27
|
+
|
28
|
+
PROJ.rdoc_main ||= PROJ.readme_file
|
17
29
|
|
18
30
|
# EOF
|
data/tasks/setup.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
# $Id: setup.rb
|
1
|
+
# $Id: setup.rb 105 2008-02-26 04:43:21Z tim_pease $
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
4
|
require 'rake'
|
5
|
+
require 'rake/clean'
|
5
6
|
require 'fileutils'
|
6
7
|
require 'ostruct'
|
7
8
|
|
@@ -17,6 +18,10 @@ PROJ.url = nil
|
|
17
18
|
PROJ.version = ENV['VERSION'] || '0.0.0'
|
18
19
|
PROJ.rubyforge_name = nil
|
19
20
|
PROJ.exclude = %w(tmp$ bak$ ~$ CVS .svn/ ^pkg/ ^doc/)
|
21
|
+
PROJ.release_name = ENV['RELEASE']
|
22
|
+
PROJ.history_file = 'History.txt'
|
23
|
+
PROJ.manifest_file = 'Manifest.txt'
|
24
|
+
PROJ.readme_file = 'README.txt'
|
20
25
|
|
21
26
|
# Rspec
|
22
27
|
PROJ.specs = FileList['spec/**/*_spec.rb']
|
@@ -28,13 +33,16 @@ PROJ.test_file = 'test/all.rb'
|
|
28
33
|
PROJ.test_opts = []
|
29
34
|
|
30
35
|
# Rcov
|
36
|
+
PROJ.rcov_dir = 'coverage'
|
31
37
|
PROJ.rcov_opts = ['--sort', 'coverage', '-T']
|
38
|
+
PROJ.rcov_threshold = 90.0
|
39
|
+
PROJ.rcov_threshold_exact = false
|
32
40
|
|
33
41
|
# Rdoc
|
34
42
|
PROJ.rdoc_opts = []
|
35
43
|
PROJ.rdoc_include = %w(^lib/ ^bin/ ^ext/ .txt$)
|
36
|
-
PROJ.rdoc_exclude = %w(extconf.rb$
|
37
|
-
PROJ.rdoc_main =
|
44
|
+
PROJ.rdoc_exclude = %w(extconf.rb$)
|
45
|
+
PROJ.rdoc_main = nil
|
38
46
|
PROJ.rdoc_dir = 'doc'
|
39
47
|
PROJ.rdoc_remote_dir = nil
|
40
48
|
|
@@ -45,16 +53,12 @@ PROJ.libs = []
|
|
45
53
|
%w(lib ext).each {|dir| PROJ.libs << dir if test ?d, dir}
|
46
54
|
|
47
55
|
# Gem Packaging
|
48
|
-
PROJ.files =
|
49
|
-
|
50
|
-
files = File.readlines('Manifest.txt').map {|fn| fn.chomp.strip}
|
51
|
-
files.delete ''
|
52
|
-
files
|
53
|
-
else [] end
|
54
|
-
PROJ.executables = PROJ.files.find_all {|fn| fn =~ %r/^bin/}
|
56
|
+
PROJ.files = nil
|
57
|
+
PROJ.executables = nil
|
55
58
|
PROJ.dependencies = []
|
56
59
|
PROJ.need_tar = true
|
57
60
|
PROJ.need_zip = false
|
61
|
+
PROJ.post_install_message = nil
|
58
62
|
|
59
63
|
# File Annotations
|
60
64
|
PROJ.annotation_exclude = %w(^tasks/setup.rb$)
|
@@ -68,6 +72,21 @@ PROJ.svn_trunk = 'trunk'
|
|
68
72
|
PROJ.svn_tags = 'tags'
|
69
73
|
PROJ.svn_branches = 'branches'
|
70
74
|
|
75
|
+
# Announce
|
76
|
+
PROJ.ann_file = 'announcement.txt'
|
77
|
+
PROJ.ann_text = nil
|
78
|
+
PROJ.ann_paragraphs = []
|
79
|
+
PROJ.ann_email = {
|
80
|
+
:from => nil,
|
81
|
+
:to => %w(ruby-talk@ruby-lang.org),
|
82
|
+
:server => 'localhost',
|
83
|
+
:port => 25,
|
84
|
+
:domain => ENV['HOSTNAME'],
|
85
|
+
:acct => nil,
|
86
|
+
:passwd => nil,
|
87
|
+
:authtype => :plain
|
88
|
+
}
|
89
|
+
|
71
90
|
# Load the other rake files in the tasks folder
|
72
91
|
rakefiles = Dir.glob('tasks/*.rake').sort
|
73
92
|
rakefiles.unshift(rakefiles.delete('tasks/post_load.rake')).compact!
|
@@ -100,8 +119,8 @@ SUDO = if WIN32 then ''
|
|
100
119
|
else '' end
|
101
120
|
end
|
102
121
|
|
103
|
-
RCOV = WIN32 ? 'rcov.
|
104
|
-
GEM = WIN32 ? 'gem.
|
122
|
+
RCOV = WIN32 ? 'rcov.bat' : 'rcov'
|
123
|
+
GEM = WIN32 ? 'gem.bat' : 'gem'
|
105
124
|
|
106
125
|
%w(rcov spec/rake/spectask rubyforge bones facets/ansicode).each do |lib|
|
107
126
|
begin
|
@@ -150,7 +169,10 @@ def depend_on( name, version = nil )
|
|
150
169
|
spec = Gem.source_index.find_name(name).last
|
151
170
|
version = spec.version.to_s if version.nil? and !spec.nil?
|
152
171
|
|
153
|
-
PROJ.dependencies <<
|
172
|
+
PROJ.dependencies << case version
|
173
|
+
when nil; [name]
|
174
|
+
when %r/^\d/; [name, ">= #{version}"]
|
175
|
+
else [name, version] end
|
154
176
|
end
|
155
177
|
|
156
178
|
# Adds the given arguments to the include path if they are not already there
|
@@ -187,4 +209,19 @@ def in_directory( dir, &block )
|
|
187
209
|
end
|
188
210
|
end
|
189
211
|
|
212
|
+
# Scans the current working directory and creates a list of files that are
|
213
|
+
# candidates to be in the manifest.
|
214
|
+
#
|
215
|
+
def manifest_files
|
216
|
+
files = []
|
217
|
+
exclude = Regexp.new(PROJ.exclude.join('|'))
|
218
|
+
Find.find '.' do |path|
|
219
|
+
path.sub! %r/^(\.\/|\/)/o, ''
|
220
|
+
next unless test ?f, path
|
221
|
+
next if path =~ exclude
|
222
|
+
files << path
|
223
|
+
end
|
224
|
+
files.sort!
|
225
|
+
end
|
226
|
+
|
190
227
|
# EOF
|
data/tasks/test.rake
CHANGED
@@ -6,7 +6,7 @@ namespace :test do
|
|
6
6
|
|
7
7
|
Rake::TestTask.new(:run) do |t|
|
8
8
|
t.libs = PROJ.libs
|
9
|
-
t.test_files = if test
|
9
|
+
t.test_files = if test(?f, PROJ.test_file) then [PROJ.test_file]
|
10
10
|
else PROJ.tests end
|
11
11
|
t.ruby_opts += PROJ.ruby_opts
|
12
12
|
t.ruby_opts += PROJ.test_opts
|
@@ -15,14 +15,14 @@ namespace :test do
|
|
15
15
|
if HAVE_RCOV
|
16
16
|
desc 'Run rcov on the unit tests'
|
17
17
|
task :rcov => :clobber_rcov do
|
18
|
-
opts = PROJ.rcov_opts.
|
19
|
-
|
18
|
+
opts = PROJ.rcov_opts.dup << '-o' << PROJ.rcov_dir
|
19
|
+
opts = opts.join(' ')
|
20
|
+
files = if test(?f, PROJ.test_file) then [PROJ.test_file]
|
20
21
|
else PROJ.tests end
|
21
22
|
files = files.join(' ')
|
22
23
|
sh "#{RCOV} #{files} #{opts}"
|
23
24
|
end
|
24
25
|
|
25
|
-
desc 'Remove rcov products'
|
26
26
|
task :clobber_rcov do
|
27
27
|
rm_r 'coverage' rescue nil
|
28
28
|
end
|
@@ -35,6 +35,4 @@ task :test => 'test:run'
|
|
35
35
|
|
36
36
|
task :clobber => 'test:clobber_rcov' if HAVE_RCOV
|
37
37
|
|
38
|
-
remove_desc_for_task %w(test:clobber_rcov)
|
39
|
-
|
40
38
|
# EOF
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_rolling_file.rb
|
1
|
+
# $Id: test_rolling_file.rb 105 2008-02-26 04:43:21Z tim_pease $
|
2
2
|
|
3
3
|
require File.join(File.dirname(__FILE__), %w[.. setup])
|
4
4
|
|
@@ -109,8 +109,10 @@ module TestAppenders
|
|
109
109
|
ap << "random message\n"
|
110
110
|
assert_equal 2, Dir.glob(@glob).length
|
111
111
|
|
112
|
-
|
113
|
-
|
112
|
+
age_fn = @fn + '.age'
|
113
|
+
now = ::File.mtime(age_fn)
|
114
|
+
start = now - 3600 * 24
|
115
|
+
::File.utime(start, start, age_fn)
|
114
116
|
|
115
117
|
sleep 0.250
|
116
118
|
ap << "yet another random message\n"
|
@@ -122,8 +124,8 @@ module TestAppenders
|
|
122
124
|
ap << "random message\n"
|
123
125
|
assert_equal 3, Dir.glob(@glob).length
|
124
126
|
|
125
|
-
|
126
|
-
|
127
|
+
start = now - 3600 * 24 * 7
|
128
|
+
::File.utime(start, start, age_fn)
|
127
129
|
|
128
130
|
sleep 0.250
|
129
131
|
ap << "yet another random message\n"
|
@@ -135,8 +137,8 @@ module TestAppenders
|
|
135
137
|
ap << "random message\n"
|
136
138
|
assert_equal 4, Dir.glob(@glob).length
|
137
139
|
|
138
|
-
|
139
|
-
|
140
|
+
start = now - 3600 * 24 * 31
|
141
|
+
::File.utime(start, start, age_fn)
|
140
142
|
|
141
143
|
sleep 0.250
|
142
144
|
ap << "yet another random message\n"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logging
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Pease
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-02-
|
12
|
+
date: 2008-02-25 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -21,15 +21,6 @@ dependencies:
|
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 0.8.0
|
23
23
|
version:
|
24
|
-
- !ruby/object:Gem::Dependency
|
25
|
-
name: lockfile
|
26
|
-
version_requirement:
|
27
|
-
version_requirements: !ruby/object:Gem::Requirement
|
28
|
-
requirements:
|
29
|
-
- - ">="
|
30
|
-
- !ruby/object:Gem::Version
|
31
|
-
version: 1.4.3
|
32
|
-
version:
|
33
24
|
description: Logging is a flexible logging library for use in Ruby programs based on the design of Java's log4j library. It features a hierarchical logging system, custom level names, multiple output destinations per log event, custom formatting, and more.
|
34
25
|
email: tim.pease@gmail.com
|
35
26
|
executables: []
|
@@ -62,8 +53,11 @@ files:
|
|
62
53
|
- lib/logging/logger.rb
|
63
54
|
- lib/logging/repository.rb
|
64
55
|
- lib/logging/root_logger.rb
|
56
|
+
- lib/logging/stelan/lockfile.rb
|
65
57
|
- lib/logging/utils.rb
|
58
|
+
- tasks/ann.rake
|
66
59
|
- tasks/annotations.rake
|
60
|
+
- tasks/bones.rake
|
67
61
|
- tasks/doc.rake
|
68
62
|
- tasks/gem.rake
|
69
63
|
- tasks/manifest.rake
|