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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+
5
+ gem "pony", ">= 1.1"
6
+ gem "sys-uname", ">= 0.8.5"
7
+
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "bundler", "~> 1.0.0"
12
+ gem "jeweler", "~> 1.5.2"
13
+ end
@@ -0,0 +1,32 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.3)
5
+ git (1.2.5)
6
+ i18n (0.5.0)
7
+ jeweler (1.5.2)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ mail (2.2.12)
12
+ activesupport (>= 2.3.6)
13
+ i18n (>= 0.4.0)
14
+ mime-types (~> 1.16)
15
+ treetop (~> 1.4.8)
16
+ mime-types (1.16)
17
+ polyglot (0.3.1)
18
+ pony (1.1)
19
+ mail (> 2.0)
20
+ rake (0.8.7)
21
+ sys-uname (0.8.5)
22
+ treetop (1.4.9)
23
+ polyglot (>= 0.3.1)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ bundler (~> 1.0.0)
30
+ jeweler (~> 1.5.2)
31
+ pony (>= 1.1)
32
+ sys-uname (>= 0.8.5)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Martin Kozák
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,81 @@
1
+ rb.rotate
2
+ =========
3
+
4
+ **rb.rotate** is an alternative to classical `logrotate` tool.
5
+ It implements very similar functionallity, features openess and
6
+ flexibility of the scripting environment and removes some most known
7
+ `logrotate` limitations.
8
+
9
+ And of sure, it adds some features and it doesn't implement some
10
+ features of the original for now.
11
+
12
+ ### Removed `logrotate` Limitations
13
+
14
+ * log directory and archive directory can be on **different drives**,
15
+ * it can **follow symbolic links** both for directories and files,
16
+ * it can **respect the subdirectories structure** of the log directory,
17
+ so archive directory can have the same structure as original log
18
+ directory.
19
+
20
+ ### Additional Features
21
+
22
+ * elegant, well documented and easy-to-understand [YAML][2] configuration
23
+ file,
24
+ * flexible and in fact unlimited possibility to define hooks while
25
+ "put file to archive" action and run them in mix with pre-build
26
+ actions in whatever required order.
27
+
28
+ Installation
29
+ ------------
30
+
31
+ After installing the `rb.rotate` gem, simply type following as root and
32
+ then add the `rb.rotate` entry to cron.
33
+
34
+ rb.rotate install
35
+
36
+ Be warn, it works for *Linux* and *FreeBSD* only. On other platforms,
37
+ please:
38
+
39
+ 1. copy initial configuration files in `<gem-path>/lib/rb.rotate/install`
40
+ to appropriate location on your platform (remove the `.initial` extension,
41
+ of sure),
42
+ 2. create the `<gem-path>/lib/paths.conf` file with path to
43
+ `rotate.yaml` file,
44
+ 3. change paths in `rotate.yaml` file to directories appropriate for
45
+ your platfom,
46
+ 4. [report back][1] to the project output of the `rb.rotate sysname`
47
+ command and appropriate configuration locations for including them in
48
+ next release.
49
+
50
+
51
+ Status
52
+ ------
53
+ Currently in **pre-beta** version. All features are implemented, some
54
+ of them such as *hooks* are untested.
55
+
56
+ ### Documentation
57
+
58
+ See the configuration file. It's pretty well documented with possible values
59
+ listed and a lot of explaining.
60
+
61
+
62
+ Contributing
63
+ ------------
64
+
65
+ 1. Fork it.
66
+ 2. Create a branch (`git checkout -b 20101220-my-change`).
67
+ 3. Commit your changes (`git commit -am "Added something"`).
68
+ 4. Push to the branch (`git push origin 20101220-my-change`).
69
+ 5. Create an [Issue][1] with a link to your branch.
70
+ 6. Enjoy a refreshing Diet Coke and wait.
71
+
72
+
73
+ Copyright
74
+ ---------
75
+
76
+ Copyright (c) 2010 [Martin Kozák][3]. See `LICENSE.txt` for
77
+ further details.
78
+
79
+ [1]: http://github.com/martinkozak/rb.rotate/issues
80
+ [2]: http://www.yaml.org/
81
+ [3]: http://www.martinkozak.net/
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'bundler'
4
+ begin
5
+ Bundler.setup(:default, :development)
6
+ rescue Bundler::BundlerError => e
7
+ $stderr.puts e.message
8
+ $stderr.puts "Run `bundle install` to install missing gems"
9
+ exit e.status_code
10
+ end
11
+ require 'rake'
12
+
13
+ require 'jeweler'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "rb.rotate"
17
+ gem.homepage = "http://github.com/martinkozak/rb.rotate"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{More modern alternative to 'logrotate' with more features and less limitations.}
20
+ gem.description = %Q{An alternative to classical 'logrotate' tool. It implements very similar functionallity, features openess and flexibility of the scripting environment and removes some most known 'logrotate' limitations.}
21
+ gem.email = "martinkozak@martinkozak.net"
22
+ gem.authors = ["Martin Kozák"]
23
+ gem.executables = ["rb.rotate"]
24
+ gem.post_install_message = "\nINSTALLATION DONE!\nFor remaining part of installation run 'rb.rotate install'\nand then eventually setup running the 'rb.rotate' by cron.\n\nBe warn, it's still BETA VERSION.\n\n"
25
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
26
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
27
+ # gem.add_runtime_dependency 'sys-uname', '>= 0.8.5'
28
+ # gem.add_runtime_dependency 'pony', '>= 1.1'
29
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
30
+ end
31
+ Jeweler::RubygemsDotOrgTasks.new
32
+
33
+ require 'rake/rdoctask'
34
+ Rake::RDocTask.new do |rdoc|
35
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
+
37
+ rdoc.rdoc_dir = 'rdoc'
38
+ rdoc.title = "rb.rotate #{version}"
39
+ rdoc.rdoc_files.include('README*')
40
+ rdoc.rdoc_files.include('lib/**/*.rb')
41
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require "rb.rotate"
3
+ if ARGV[0]
4
+ case ARGV[0].to_sym
5
+ when :install
6
+ RbRotate::install!
7
+ when :sysname
8
+ RbRotate::sysname!
9
+ end
10
+ else
11
+ RbRotate::run!
12
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ require "rb.rotate/dispatcher"
3
+
4
+ module RbRotate
5
+
6
+ ##
7
+ # Runs the application.
8
+ #
9
+
10
+ def self.run!
11
+ Dispatcher::new::run!
12
+ end
13
+
14
+ ##
15
+ # Installs the application.
16
+ #
17
+
18
+ def self.install!
19
+ Dispatcher::new::install!
20
+ end
21
+
22
+ ##
23
+ # Prints out the system name.
24
+ #
25
+
26
+ def self.sysname!
27
+ Dispatcher::new::sysname!
28
+ end
29
+
30
+ end
@@ -0,0 +1,312 @@
1
+ # encoding: utf-8
2
+
3
+ require "yaml"
4
+ require "rb.rotate/directory"
5
+
6
+ module RbRotate
7
+
8
+ ##
9
+ # Directory configuration.
10
+ #
11
+
12
+ class DirectoryConfiguration
13
+
14
+ ##
15
+ # Holds currently selected directory section.
16
+ #
17
+
18
+ @directory
19
+
20
+ ##
21
+ # Holds configuration data.
22
+ #
23
+
24
+ @data
25
+
26
+ ##
27
+ # Constructor.
28
+ #
29
+ # Expects file path and directory section specification
30
+ # as symbol.
31
+ #
32
+
33
+ def initialize(directory)
34
+ # TODO: this should handle configuration inheritance
35
+ @directory = directory
36
+ end
37
+
38
+ ##
39
+ # Returns configuration file setting.
40
+ #
41
+
42
+ def configuration
43
+ Configuration::get
44
+ end
45
+
46
+ ##
47
+ # Returns configuration data.
48
+ #
49
+
50
+ def data
51
+ if @data.nil?
52
+ data = self.configuration[:dirs][@directory]
53
+ @data = { }
54
+
55
+ # Converts strings to symbols
56
+ data.each_pair do |key, value|
57
+ @data[key.to_sym] = value
58
+ end
59
+
60
+ self.handle_inheritance!
61
+ end
62
+
63
+ return @data
64
+ end
65
+
66
+ ##
67
+ # Handles configuration inheritance.
68
+ #
69
+
70
+ def handle_ihneritance!
71
+ if @data.include? :parent
72
+ @data.merge! self.class::new(@data[:parent]).data
73
+ end
74
+ end
75
+
76
+ ##
77
+ # Returns some item.
78
+ #
79
+
80
+ def [](name)
81
+ self.data[name]
82
+ end
83
+
84
+ ##
85
+ # Handles method calls.
86
+ #
87
+
88
+ def method_missing(name)
89
+ self[name]
90
+ end
91
+
92
+ end
93
+
94
+ ##
95
+ # General configuration file.
96
+ #
97
+
98
+ class Configuration
99
+
100
+ ##
101
+ # Brings self instance. (Class is singletone.)
102
+ #
103
+
104
+ @@self = nil
105
+
106
+ ##
107
+ # Holds data.
108
+ #
109
+
110
+ @data
111
+
112
+ ##
113
+ # Opens the file. (Shortcut for instance call.)
114
+ #
115
+
116
+ def self.read(file)
117
+ self::get.read(file)
118
+ end
119
+
120
+ ##
121
+ # Returns the single instance.
122
+ #
123
+
124
+ def self.get
125
+ if @@self.nil?
126
+ @@self = self::new
127
+ end
128
+
129
+ return @@self
130
+ end
131
+
132
+ ##
133
+ # Traverses through each directory configuration.
134
+ # (Shortcut for instace call.)
135
+
136
+ def self.each_directory(&block)
137
+ self::get.each_directory(&block)
138
+ end
139
+
140
+ ##
141
+ # Alias for #find_path.
142
+ #
143
+
144
+ def self.find_path(path)
145
+ self::get.find_path(path)
146
+ end
147
+
148
+ ##
149
+ # Opens the file.
150
+ #
151
+
152
+ def read(file)
153
+ data = YAML.load(::File.read(file))
154
+ @data = { }
155
+
156
+ # Converts strings to symbols
157
+ data.each_pair do |name, section|
158
+ section_data = { }
159
+ @data[name.to_sym]= section_data
160
+
161
+ if section.kind_of? Hash
162
+ section.each_pair do |key, value|
163
+ section_data[key.to_sym] = value
164
+ end
165
+ end
166
+ end
167
+
168
+ defaults = YAML.load(::File.read(@data[:paths][:"defaults file"]))
169
+
170
+ # Merges with defaults
171
+ defaults.each_pair do |name, section|
172
+ name = name.to_sym
173
+ if not @data.has_key? name
174
+ @data[name] = value
175
+ elsif section.kind_of? Hash
176
+ section.each_pair do |key, value|
177
+ key = key.to_sym
178
+ if not @data[name].has_key? key
179
+ @data[name][key] = value
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
185
+
186
+ ##
187
+ # Returns an item.
188
+ #
189
+
190
+ def [](name)
191
+ @data[name]
192
+ end
193
+
194
+ ##
195
+ # Handles method calls.
196
+ #
197
+
198
+ def method_missing(name)
199
+ self[name]
200
+ end
201
+
202
+ ##
203
+ # Traverses through each directory configuration.
204
+ #
205
+
206
+ def each_directory
207
+ @data[:dirs].each_pair do |name, dir|
208
+ yield Directory::new(name, dir)
209
+ end
210
+ end
211
+
212
+ ##
213
+ # Looks for directory in configuration.
214
+ #
215
+
216
+ def find_path(path)
217
+ @data.each_pair do |name, dir|
218
+ if dir[:directory] == path
219
+ return Directory::new(name, dir)
220
+ end
221
+ end
222
+
223
+ return nil
224
+ end
225
+
226
+ end
227
+
228
+ end
229
+
230
+ # String extensions
231
+
232
+ class String
233
+
234
+ TO_TIME_MATCHER = /(\d+)\s*((?:year|month|week|day|hour|minute|second))s?/i
235
+
236
+ ##
237
+ # Converts number with units to bytes count.
238
+ #
239
+
240
+ def to_bytes
241
+ value = self.to_i
242
+ if value == 0
243
+ raise Exception::new("Invalid size specification: " << self << ".")
244
+ end
245
+
246
+ exponent = nil
247
+ case self[-1]
248
+ when ?M
249
+ exponent = 2
250
+ when ?G
251
+ exponent = 3
252
+ when ?K
253
+ exponent = 1
254
+ when ?0, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9
255
+ exponent = 0
256
+ else
257
+ raise Exception::new("Invalid unit in size specification: " << self << ".")
258
+ end
259
+
260
+ return value * (1024 ** exponent)
261
+ end
262
+
263
+ ##
264
+ # Converts string identifier of time period to seconds.
265
+ #
266
+
267
+ def to_seconds
268
+
269
+ period = nil
270
+ case self.to_sym
271
+ when :yearly
272
+ period = "1 year"
273
+ when :monthly
274
+ period = "1 month"
275
+ when :weekly
276
+ period = "1 week"
277
+ when :daily
278
+ period = "1 day"
279
+ when :hourly
280
+ period = "1 hour"
281
+ else
282
+ period = self
283
+ end
284
+
285
+ matches = period.match(self.class::TO_TIME_MATCHER)
286
+ if matches.nil?
287
+ raise Exception::new("Invalid period specification: " << self << ".")
288
+ end
289
+
290
+ count = matches[1].to_i
291
+ unit = matches[2].to_sym
292
+ seconds = nil
293
+
294
+ case unit
295
+ when :year
296
+ seconds = 365 * 24 * 60 * 60
297
+ when :month
298
+ seconds = 30 * 24 * 60 * 60
299
+ when :week
300
+ seconds = 7 * 24 * 60 * 60
301
+ when :day
302
+ seconds = 24 * 60 * 60
303
+ when :hour
304
+ seconds = 60 * 60
305
+ when :second
306
+ seconds = 1
307
+ end
308
+
309
+ return seconds * count
310
+ end
311
+
312
+ end