logging 0.7.0 → 0.7.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.
- 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
|