rb.rotate 0.1.0
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/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +32 -0
- data/LICENSE.txt +20 -0
- data/README.md +81 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/bin/rb.rotate +12 -0
- data/lib/rb.rotate.rb +30 -0
- data/lib/rb.rotate/configuration.rb +312 -0
- data/lib/rb.rotate/directory.rb +201 -0
- data/lib/rb.rotate/dispatcher.rb +112 -0
- data/lib/rb.rotate/file.rb +174 -0
- data/lib/rb.rotate/hook.rb +135 -0
- data/lib/rb.rotate/install/defaults.yaml.initial +25 -0
- data/lib/rb.rotate/install/rotate.yaml.initial +349 -0
- data/lib/rb.rotate/log.rb +80 -0
- data/lib/rb.rotate/mail.rb +40 -0
- data/lib/rb.rotate/reader.rb +94 -0
- data/lib/rb.rotate/state.rb +211 -0
- data/lib/rb.rotate/state/archive.rb +109 -0
- data/lib/rb.rotate/state/file.rb +139 -0
- data/lib/rb.rotate/storage.rb +208 -0
- data/lib/rb.rotate/storage/entry.rb +120 -0
- data/lib/rb.rotate/storage/item.rb +415 -0
- data/rb.rotate.gemspec +85 -0
- metadata +153 -0
@@ -0,0 +1,201 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "rb.rotate/configuration"
|
4
|
+
require "rb.rotate/file"
|
5
|
+
require "rb.rotate/reader"
|
6
|
+
require "rb.rotate/storage"
|
7
|
+
|
8
|
+
module RbRotate
|
9
|
+
|
10
|
+
##
|
11
|
+
# Represents one log directory.
|
12
|
+
#
|
13
|
+
|
14
|
+
class Directory
|
15
|
+
|
16
|
+
##
|
17
|
+
# Internal cache of the configuration.
|
18
|
+
#
|
19
|
+
|
20
|
+
@configuration
|
21
|
+
|
22
|
+
##
|
23
|
+
# Parent configuration object.
|
24
|
+
#
|
25
|
+
|
26
|
+
@parent
|
27
|
+
|
28
|
+
##
|
29
|
+
# Indicates, it isn't child directory of configured directory,
|
30
|
+
# but directly the configured directory.
|
31
|
+
#
|
32
|
+
|
33
|
+
@configured
|
34
|
+
|
35
|
+
##
|
36
|
+
# Holds directory identifier.
|
37
|
+
#
|
38
|
+
|
39
|
+
@identifier
|
40
|
+
attr_reader :identifier
|
41
|
+
|
42
|
+
##
|
43
|
+
# Holds directory path.
|
44
|
+
#
|
45
|
+
|
46
|
+
@path
|
47
|
+
attr_reader :path
|
48
|
+
|
49
|
+
##
|
50
|
+
# Constructor.
|
51
|
+
#
|
52
|
+
# Identifier is symbol so identifier in configuration file or
|
53
|
+
# string, so directory path.
|
54
|
+
#
|
55
|
+
|
56
|
+
def initialize(identifier, parent = nil)
|
57
|
+
@parent = parent
|
58
|
+
if identifier.kind_of? Symbol
|
59
|
+
@identifier = identifier
|
60
|
+
else
|
61
|
+
@path = identifier
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Returns the configuration instance.
|
67
|
+
#
|
68
|
+
|
69
|
+
def configuration
|
70
|
+
if @configuration.nil?
|
71
|
+
# If no identifier set, looks for the dir
|
72
|
+
# in configuration.
|
73
|
+
if @identifier.nil?
|
74
|
+
directory = Configuration::find_path(@path)
|
75
|
+
|
76
|
+
if not directory.nil?
|
77
|
+
@identifier = directory.identifier
|
78
|
+
@configured = true
|
79
|
+
elsif not @parent.nil?
|
80
|
+
@identifier = @parent.identifier
|
81
|
+
@configured = false
|
82
|
+
else
|
83
|
+
@identifier = :default
|
84
|
+
@configured = false
|
85
|
+
end
|
86
|
+
else
|
87
|
+
@configured = true
|
88
|
+
end
|
89
|
+
|
90
|
+
@configuration = DirectoryConfiguration::new(@identifier)
|
91
|
+
end
|
92
|
+
|
93
|
+
return @configuration
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Indicates, it isn't child directory of configured directory,
|
98
|
+
# but directly the configured directory.
|
99
|
+
#
|
100
|
+
|
101
|
+
def configured?
|
102
|
+
self.configuration
|
103
|
+
@configured
|
104
|
+
end
|
105
|
+
|
106
|
+
##
|
107
|
+
# Returns path to directory.
|
108
|
+
#
|
109
|
+
# So it get @path or directory from configuration if hasn't
|
110
|
+
# been sete.
|
111
|
+
#
|
112
|
+
|
113
|
+
def path
|
114
|
+
if not @path.nil?
|
115
|
+
@path
|
116
|
+
else
|
117
|
+
self.configuration.directory
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Returns relative path to parent (configured) directory.
|
123
|
+
#
|
124
|
+
|
125
|
+
def relative_path
|
126
|
+
if self.configured?
|
127
|
+
"."
|
128
|
+
else
|
129
|
+
self.path[(self.configured_ancestor.path.length + 1)..-1]
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
##
|
134
|
+
# Returns the "nearest" configured ancestor.
|
135
|
+
#
|
136
|
+
|
137
|
+
def configured_ancestor
|
138
|
+
if self.configured?
|
139
|
+
self
|
140
|
+
elsif not @parent.nil?
|
141
|
+
@parent.configured_ancestor
|
142
|
+
else
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Traverses through all files in directory.
|
149
|
+
#
|
150
|
+
|
151
|
+
def each_file(&block)
|
152
|
+
Reader::read(self, :filter => :files, &block)
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Traverses through all directories in directory.
|
157
|
+
#
|
158
|
+
|
159
|
+
def each_directory(&block)
|
160
|
+
Reader::read(self, :filter => :dirs, &block)
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# Rotates.
|
165
|
+
#
|
166
|
+
|
167
|
+
def rotate!
|
168
|
+
# Cleans old or expired items
|
169
|
+
# self.storage.cleanup! (cleaned up globally by dispatcher call)
|
170
|
+
|
171
|
+
# Rotates
|
172
|
+
if self.configuration[:recursive]
|
173
|
+
self.each_directory do |directory|
|
174
|
+
directory.rotate!
|
175
|
+
end
|
176
|
+
end
|
177
|
+
self.each_file do |file|
|
178
|
+
file.rotate!
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
##
|
183
|
+
# Indicates, directory entries should be compressed
|
184
|
+
# in archive.
|
185
|
+
#
|
186
|
+
|
187
|
+
def compressable?
|
188
|
+
not self.configuration[:compress].nil?
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Returns storage appropriate to directory.
|
193
|
+
#
|
194
|
+
|
195
|
+
def storage
|
196
|
+
Storage::get(self)
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module RbRotate
|
4
|
+
|
5
|
+
##
|
6
|
+
# Dispatches all operations.
|
7
|
+
#
|
8
|
+
|
9
|
+
class Dispatcher
|
10
|
+
|
11
|
+
##
|
12
|
+
# Runs the rotate session.
|
13
|
+
#
|
14
|
+
|
15
|
+
def run!
|
16
|
+
require "rb.rotate/configuration"
|
17
|
+
require "rb.rotate/state"
|
18
|
+
require "rb.rotate/storage"
|
19
|
+
require "rb.rotate/log"
|
20
|
+
|
21
|
+
# Reads configuration file
|
22
|
+
locator = ::File.dirname(::File.dirname(__FILE__)).dup << "/paths.conf"
|
23
|
+
if not ::File.exists? locator
|
24
|
+
STDERR.write("FATAL: rb.rotate unconfigured. Please, run 'rb.rotate install' or eventually create the " << locator << " file with path to configuration file. Aborted.\n")
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
|
28
|
+
path = ::File.read(locator)
|
29
|
+
path.strip!
|
30
|
+
|
31
|
+
Configuration::read(path)
|
32
|
+
log "Configuration file loaded."
|
33
|
+
|
34
|
+
# Process
|
35
|
+
log "Start of processing."
|
36
|
+
Configuration::each_directory do |directory|
|
37
|
+
begin
|
38
|
+
directory.rotate!
|
39
|
+
rescue Exception => e
|
40
|
+
log "Exception: " << e.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Removes orhpans
|
45
|
+
log "Start of orphans removing."
|
46
|
+
Storage::remove_orphans!
|
47
|
+
|
48
|
+
# Saves state file
|
49
|
+
State::save!
|
50
|
+
log "New state saved."
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Installs the application configuration files.
|
55
|
+
#
|
56
|
+
|
57
|
+
def install!
|
58
|
+
require "sys/uname"
|
59
|
+
require "fileutils"
|
60
|
+
|
61
|
+
basedir = ::File.dirname(__FILE__)
|
62
|
+
|
63
|
+
# Loads and creates the configuration dir
|
64
|
+
case Sys::Uname.sysname.downcase.to_sym
|
65
|
+
when :freebsd
|
66
|
+
etc = "/usr/local/etc"
|
67
|
+
when :linux
|
68
|
+
etc = "/etc"
|
69
|
+
else
|
70
|
+
raise Exception::new("You are running on an unknown platform. It cannot be problem, but it's necessary define path to configuration file and define paths in configuration file.")
|
71
|
+
end
|
72
|
+
|
73
|
+
etc << "/rb.rotate"
|
74
|
+
FileUtils.mkdir_p(etc)
|
75
|
+
|
76
|
+
# Creates other important directories
|
77
|
+
FileUtils.mkdir_p("/var/log")
|
78
|
+
FileUtils.mkdir_p("/var/lib")
|
79
|
+
|
80
|
+
# Puts configuration files to configuration directory
|
81
|
+
source = basedir.dup << "/install"
|
82
|
+
replacements = { "%%configuration" => etc }
|
83
|
+
files = ["rotate.yaml", "defaults.yaml"]
|
84
|
+
|
85
|
+
files.each do |file|
|
86
|
+
body = ::File.read(source.dup << "/" << file << ".initial")
|
87
|
+
replacements.each_pair do |key, value|
|
88
|
+
body.gsub! key, value
|
89
|
+
end
|
90
|
+
::File.open(etc.dup << "/" << file, "w") do |io|
|
91
|
+
io.write(body)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Puts to library root path path to configuration directory
|
96
|
+
::File.open(basedir.dup << "/../paths.conf", "w") do |io|
|
97
|
+
io.write(etc.dup << "/rotate.yaml")
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Prints out system name.
|
103
|
+
#
|
104
|
+
|
105
|
+
def sysname!
|
106
|
+
require "sys/uname"
|
107
|
+
puts Sys::Uname.sysname.downcase
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "rb.rotate/storage"
|
5
|
+
require "rb.rotate/directory"
|
6
|
+
require "rb.rotate/configuration"
|
7
|
+
|
8
|
+
module RbRotate
|
9
|
+
|
10
|
+
##
|
11
|
+
# Represents one log file.
|
12
|
+
#
|
13
|
+
|
14
|
+
class File
|
15
|
+
|
16
|
+
##
|
17
|
+
# Holds parent file directory.
|
18
|
+
#
|
19
|
+
|
20
|
+
@directory
|
21
|
+
|
22
|
+
##
|
23
|
+
# Indicates file path.
|
24
|
+
#
|
25
|
+
|
26
|
+
@path
|
27
|
+
attr_reader :path
|
28
|
+
|
29
|
+
##
|
30
|
+
# Holds state for the file.
|
31
|
+
#
|
32
|
+
|
33
|
+
@state
|
34
|
+
|
35
|
+
##
|
36
|
+
# Holds stat informations about the (original) file.
|
37
|
+
#
|
38
|
+
|
39
|
+
@stat
|
40
|
+
|
41
|
+
##
|
42
|
+
# Constructor.
|
43
|
+
#
|
44
|
+
|
45
|
+
def initialize(path, directory = nil)
|
46
|
+
@directory = directory
|
47
|
+
@path = path
|
48
|
+
@stat = ::File.stat(@path.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# Returns the file parent directory object.
|
53
|
+
#
|
54
|
+
|
55
|
+
def directory
|
56
|
+
if @directory.nil?
|
57
|
+
if not self.state.directory.nil?
|
58
|
+
@directory = Directory::new(self.state.directory)
|
59
|
+
else
|
60
|
+
@directory = Configuration::find_path(::File.dirname(@path.to_s))
|
61
|
+
end
|
62
|
+
|
63
|
+
if @directory.nil?
|
64
|
+
raise Exception::new("File from directory which isn't covered by rb.rotate found: " << @path.to_s << ".")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
return @directory
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Removes the file from medium.
|
73
|
+
#
|
74
|
+
|
75
|
+
def remove!
|
76
|
+
FileUtils.remove_file(@path)
|
77
|
+
return @path
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Creates new file.
|
82
|
+
#
|
83
|
+
|
84
|
+
def create!
|
85
|
+
::File.open(@path, "w").close()
|
86
|
+
|
87
|
+
# Sets access rights and ownership according to
|
88
|
+
# stat information
|
89
|
+
if not @stat.nil?
|
90
|
+
::FileUtils.chmod(@stat.mode, @path)
|
91
|
+
::FileUtils.chown(@stat.uid, @stat.gid, @path)
|
92
|
+
end
|
93
|
+
|
94
|
+
return @path
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Truncates file.
|
99
|
+
#
|
100
|
+
|
101
|
+
alias :"truncate!" :"create!"
|
102
|
+
|
103
|
+
##
|
104
|
+
# Rotates the file.
|
105
|
+
#
|
106
|
+
|
107
|
+
def rotate!
|
108
|
+
if self.archivable?
|
109
|
+
self.archive!
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Archives file.
|
115
|
+
#
|
116
|
+
|
117
|
+
def archive!
|
118
|
+
Storage::put(self)
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# Indicates, file is suitable for immediate archiving.
|
123
|
+
#
|
124
|
+
|
125
|
+
def archivable?
|
126
|
+
self.too_big? or self.too_old?
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Indicates, file is bigger than is allowed.
|
131
|
+
#
|
132
|
+
|
133
|
+
def too_big?
|
134
|
+
::File.size(@path) > @directory.configuration[:"max size"].to_bytes
|
135
|
+
end
|
136
|
+
|
137
|
+
##
|
138
|
+
# Indicates, file is too old.
|
139
|
+
#
|
140
|
+
|
141
|
+
def too_old?
|
142
|
+
if self.state.exists?
|
143
|
+
period = @directory.configuration[:period].to_seconds
|
144
|
+
result = Time::at(self.state.date + period) < Time::now
|
145
|
+
else
|
146
|
+
result = false
|
147
|
+
end
|
148
|
+
|
149
|
+
return result
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Returns state.
|
154
|
+
#
|
155
|
+
|
156
|
+
def state
|
157
|
+
if @state.nil?
|
158
|
+
@state = State::get.file(@path)
|
159
|
+
end
|
160
|
+
|
161
|
+
return @state
|
162
|
+
end
|
163
|
+
|
164
|
+
##
|
165
|
+
# Indicates file exists.
|
166
|
+
#
|
167
|
+
|
168
|
+
def exists?
|
169
|
+
::File.exists? @path.to_s
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|