rb.rotate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+ require "rb.rotate/state"
3
+
4
+ module RbRotate
5
+ module StateModule
6
+
7
+ ##
8
+ # Represents file state record.
9
+ #
10
+
11
+ class File
12
+
13
+ ##
14
+ # Holds the file data.
15
+ #
16
+
17
+ @data
18
+
19
+ ##
20
+ # Holds path of the appropriate file.
21
+ #
22
+
23
+ @path
24
+
25
+ ##
26
+ # Constructor.
27
+ #
28
+
29
+ def initialize(path, data)
30
+ @path = path
31
+ @data = data
32
+ end
33
+
34
+ ##
35
+ # Indicates tate record for file exists.
36
+ #
37
+
38
+ def exists?
39
+ not @data.empty?
40
+ end
41
+
42
+ ##
43
+ # Returns last archival date.
44
+ #
45
+
46
+ def date
47
+ @data[:date]
48
+ end
49
+
50
+ ##
51
+ # Touches date to current date.
52
+ #
53
+
54
+ def touch!
55
+ @data[:date] = Time::now
56
+ end
57
+
58
+ ##
59
+ # Returns extension.
60
+ #
61
+
62
+ def extension
63
+ @data[:filename][:extension]
64
+ end
65
+
66
+ ##
67
+ # Returns basename.
68
+ #
69
+
70
+ def name
71
+ @data[:filename][:name]
72
+ end
73
+
74
+ ##
75
+ # Returns items list.
76
+ #
77
+
78
+ def items
79
+ @data[:items]
80
+ end
81
+
82
+ ##
83
+ # Returns directory specification.
84
+ #
85
+
86
+ def directory
87
+ if @data.has_key? :directory
88
+ @data[:directory].to_sym
89
+ else
90
+ nil
91
+ end
92
+ end
93
+
94
+ ##
95
+ # Sets items list.
96
+ #
97
+
98
+ def items=(value)
99
+ @data[:items].replace(value)
100
+ end
101
+
102
+ ##
103
+ # Creates the state record.
104
+ #
105
+
106
+ def create(file)
107
+ extension = ::File.extname(file.path)[1..-1]
108
+ if extension.nil?
109
+ extension = nil
110
+ cut = 0..-1
111
+ else
112
+ cut = 0..-2
113
+ end
114
+
115
+ new = {
116
+ :date => Time::now,
117
+ :items => { },
118
+ :directory => file.directory.identifier,
119
+ :filename => {
120
+ :name => ::File.basename(file.path, extension.to_s)[cut],
121
+ :extension => extension
122
+ }
123
+ }
124
+
125
+ @data.replace(new)
126
+ end
127
+
128
+ ##
129
+ # Destroys the state record.
130
+ #
131
+
132
+ def destroy!
133
+ State::files.delete(@path.to_sym)
134
+ @data = nil
135
+ end
136
+
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,208 @@
1
+ # encoding: utf-8
2
+
3
+ require "rb.rotate/storage/entry"
4
+ require "rb.rotate/file"
5
+ require "rb.rotate/configuration"
6
+
7
+ module RbRotate
8
+
9
+ ##
10
+ # Represents storage for archived files.
11
+ #
12
+
13
+ class Storage
14
+
15
+ ##
16
+ # Directory for which storage is aimed.
17
+ #
18
+
19
+ @directory
20
+ attr_reader :directory
21
+
22
+ ##
23
+ # Constructor.
24
+ #
25
+
26
+ def initialize(directory)
27
+ @directory = directory
28
+ end
29
+
30
+ ##
31
+ # Alias for new.
32
+ #
33
+
34
+ def self.get(directory)
35
+ self::new(directory)
36
+ end
37
+
38
+ ##
39
+ # Creates storage according to file and puts it to it.
40
+ #
41
+
42
+ def self.put(file)
43
+ self::get(file.directory).put(file)
44
+ end
45
+
46
+ ##
47
+ # Puts file to storage.
48
+ #
49
+
50
+ def put(file)
51
+ self.do_actions! file
52
+ end
53
+
54
+ ##
55
+ # Indicates, storage is compressed.
56
+ #
57
+
58
+ def compressed?
59
+ self.directory.compressable?
60
+ end
61
+
62
+ ##
63
+ # Runs file actions.
64
+ #
65
+
66
+ def do_actions!(file)
67
+ entry = StorageModule::Entry::new(self, file)
68
+
69
+ # Loads them
70
+ actions = @directory.configuration[:action].split("+")
71
+ actions.map! do |i|
72
+ i.strip!
73
+ k, v = i.split(":", 2)
74
+ [k.to_sym, v]
75
+ end
76
+
77
+ # Does them
78
+ variables = { }
79
+
80
+ actions.each do |action, arguments|
81
+ case action
82
+ when :move, :copy, :append
83
+ variables[:filepath] = entry.put! action
84
+ when :remove
85
+ variables[:filepath] = file.remove!
86
+ when :create, :truncate
87
+ variables[:filepath] = file.create!
88
+ when :mail
89
+ variables[:filepath] = entry.mail! arguments
90
+ when :hook
91
+ name, arguments = arguments.split(":", 2)
92
+ variables.merge! Hook::new(name.to_sym, arguments, variables).run!
93
+ end
94
+ end
95
+ end
96
+
97
+ ##
98
+ # Cleanups expired items from the storage.
99
+ #
100
+
101
+ def cleanup!
102
+ self.each_entry do |entry|
103
+ entry.cleanup!
104
+ end
105
+ end
106
+
107
+ ##
108
+ # Returns item identifier of the storage.
109
+ #
110
+
111
+ def item_identifier
112
+ self.directory.configuration[:identifier]
113
+ end
114
+
115
+ ##
116
+ # Indicates numeric identifier.
117
+ #
118
+
119
+ def numeric_identifier?
120
+ self.item_identifier.to_sym == :numeric
121
+ end
122
+
123
+ ##
124
+ # Removes orphans.
125
+ #
126
+
127
+ def self.remove_orphans!
128
+ self::each_entry do |entry|
129
+ items_count = 0
130
+
131
+ entry.each_item do |item|
132
+ if item.expired?
133
+ item.remove!
134
+ elsif not item.exists?
135
+ item.unregister!
136
+ else
137
+ items_count += 1
138
+ end
139
+ end
140
+
141
+ file = entry.file
142
+ if (not file.exists?) and (items_count <= 0)
143
+ file.state.destroy!
144
+ end
145
+ end
146
+ end
147
+
148
+ ##
149
+ # Traverses through each item in current storage.
150
+ #
151
+
152
+ def each_item(&block)
153
+ self.each_entry do |entry|
154
+ entry.each_item(&block)
155
+ end
156
+ end
157
+
158
+ ##
159
+ # Traverses through all entries of this directory storage.
160
+ #
161
+
162
+ def each_entry
163
+ State::each_file do |path, state|
164
+ if state.directory == self.directory.identifier
165
+ file = File::new(path)
166
+ entry = StorageModule::Entry::new(self, file)
167
+
168
+ yield entry
169
+ end
170
+ end
171
+ end
172
+
173
+ ##
174
+ # Traverses through all items in global storage.
175
+ #
176
+
177
+ def self.each_item(&block)
178
+ self.each_entry do |entry|
179
+ entry.each_item(&block)
180
+ end
181
+ end
182
+
183
+ ##
184
+ # Traverses through all entries.
185
+ #
186
+
187
+ def self.each_entry
188
+ State::each_file do |path, state|
189
+ file = File::new(path)
190
+ storage = self::new(file.directory)
191
+ entry = StorageModule::Entry::new(storage, file)
192
+
193
+ yield entry
194
+ end
195
+ end
196
+
197
+ ##
198
+ # Traverses through all directories in storage.
199
+ #
200
+
201
+ def self.each_directory
202
+ Configuration::each_directory do |directory|
203
+ yield self::get(directory)
204
+ end
205
+ end
206
+
207
+ end
208
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+
3
+ require "rb.rotate/storage/item"
4
+ require "rb.rotate/mail"
5
+
6
+ module RbRotate
7
+ module StorageModule
8
+
9
+ ##
10
+ # Represents an entry of the storage.
11
+ # Entry is archived items of one file.
12
+ #
13
+
14
+ class Entry
15
+
16
+ ##
17
+ # Holds file of the entry.
18
+ #
19
+
20
+ @file
21
+ attr_reader :file
22
+
23
+ ##
24
+ # Holds parent storage.
25
+ #
26
+
27
+ @storage
28
+ attr_reader :storage
29
+
30
+ ##
31
+ # Constructor.
32
+ #
33
+
34
+ def initialize(storage, file)
35
+ @storage = storage
36
+ @file = file
37
+ end
38
+
39
+ ##
40
+ # Puts current version of the file to items.
41
+ #
42
+
43
+ def put!(method)
44
+
45
+ # If necessary, creates the state record
46
+ if not self.file.state.exists?
47
+ self.file.state.create(@file)
48
+ end
49
+
50
+ # Rotates other items
51
+ new_list = { }
52
+ self.each_item do |item|
53
+ if item.exists?
54
+ item.rotate!
55
+ new_list[item.identifier] = item.path
56
+ else
57
+ item.unregister!
58
+ end
59
+ end
60
+
61
+ # Puts new item
62
+ item = Item::new(self).allocate(method)
63
+ new_list[item.identifier] = item.path
64
+
65
+ self.file.state.touch!
66
+ self.file.state.items = new_list
67
+
68
+ return self.file.path
69
+ end
70
+
71
+ ##
72
+ # Cleanups the items.
73
+ #
74
+
75
+ def cleanup!
76
+ self.each_item do |item|
77
+ if item.expired?
78
+ item.remove!
79
+ end
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Mail file to specified address.
85
+ #
86
+
87
+ def mail!(to)
88
+ if to.nil?
89
+ to = @storage.directory.configuration[:mail]
90
+ end
91
+ if to.nil?
92
+ raise Exception("No e-mail address specified for sending log to.")
93
+ end
94
+
95
+ require "etc"
96
+ require "socket"
97
+
98
+ Mail::send(
99
+ :from => Etc.getlogin.dup << "@" << Socket.gethostname,
100
+ :to => to,
101
+ :subject => Socket.gethostname.dup << " : log : " << self.file.path,
102
+ :body => ::File.read(self.file.path)
103
+ )
104
+
105
+ return self.file.path
106
+ end
107
+
108
+ ##
109
+ # Traverses through all items.
110
+ #
111
+
112
+ def each_item
113
+ self.file.state.items.each_pair do |identifier, path|
114
+ yield Item::new(self, identifier, path)
115
+ end
116
+ end
117
+
118
+ end
119
+ end
120
+ end