PageRenderTime 24ms CodeModel.GetById 12ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lib/log/conf/log_file_rotated.e

http://github.com/tybor/Liberty
Specman e | 219 lines | 178 code | 17 blank | 24 comment | 10 complexity | 1892664b906e1b4ad116bf9c87d0700f MD5 | raw file
  1-- This file is part of a Liberty Eiffel library.
  2-- See the full copyright at the end.
  3--
  4class LOG_FILE_ROTATED
  5
  6inherit
  7   LOG_FILE_OPTION
  8
  9create {LOG_FILE_OPTIONS}
 10   make
 11
 12feature {LOG_FILE_OPTIONS, LOG_FILE_OPTION}
 13   retrieve (stream: OUTPUT_STREAM): OUTPUT_STREAM
 14      local
 15         s: STREAM
 16         file: FILE_STREAM
 17      do
 18         Result := parent.retrieve(stream)
 19         s := Result
 20         if file ?:= s then -- TODO: BERK (inheritance branch skipped)
 21            file ::= s
 22            if condition.item([file]) then
 23               s := rotate(file)
 24               Result ::= s
 25            end
 26         end
 27      end
 28
 29feature {}
 30   make (a_parent: like parent; a_condition: like condition; a_retention: like retention)
 31      require
 32         a_parent /= Void
 33         a_condition /= Void
 34      do
 35         parent := a_parent
 36         condition := a_condition
 37         retention := a_retention
 38      ensure
 39         parent = a_parent
 40         condition = a_condition
 41         retention = a_retention
 42      end
 43
 44   parent: LOG_FILE_OPTION
 45   condition: PREDICATE[TUPLE[FILE_STREAM]]
 46   retention: INTEGER_64
 47
 48   file_pattern (base_name: STRING): REGULAR_EXPRESSION
 49      local
 50         file_name: STRING; i: INTEGER; c: CHARACTER
 51         regex: REGULAR_EXPRESSION_BUILDER
 52      do
 53         file_name := once ""
 54         file_name.with_capacity(base_name.count + 20)
 55         file_name.copy(once "^")
 56         from
 57            i := base_name.lower
 58         until
 59            i > base_name.upper
 60         loop
 61            c := base_name.item(i)
 62            inspect
 63               c
 64            when '.', '\', '*', '+', '?', '{', '}', '|', '^', '$', '(', ')' then
 65               file_name.extend('\')
 66               file_name.extend(c)
 67            else
 68               file_name.extend(c)
 69            end
 70            i := i + 1
 71         end
 72         file_name.append(once "\.([0-9]+)(\..*)?$")
 73         Result := regex.convert_posix_pattern(file_name)
 74      end
 75
 76   rotate (file: FILE_STREAM): FILE_STREAM
 77      require
 78         file.is_connected
 79      local
 80         file_name_pattern: REGULAR_EXPRESSION
 81         file_path, dir_name, file_name, new_file_name: STRING
 82         i: INTEGER
 83      do
 84         file_path := file.path
 85         file.disconnect
 86
 87         dir_name := once ""
 88         bd.compute_parent_directory_of(file_path)
 89         if bd.last_entry.is_empty then
 90            dir_name.make_from_string(bd.current_working_directory)
 91         else
 92            dir_name.copy(bd.last_entry)
 93         end
 94
 95         file_name := once ""
 96         bd.compute_short_name_of(file_path)
 97         file_name.copy(bd.last_entry)
 98
 99         if retention /= 0 then
100            last_index := 0
101            file_name_pattern := file_pattern(file_name)
102            from
103               map(dir_name, file_name_pattern, agent set_last_index(?))
104               i := last_index
105            until
106               i = 0
107            loop
108               map(dir_name, file_name_pattern, agent rotate_file(dir_name, file_name_pattern, i, ?, ?))
109               i := i - 1
110            end
111            new_file_name := once ""
112            new_file_name.copy(file_name)
113            new_file_name.append(once ".1")
114            bd.compute_file_path_with(dir_name, new_file_name)
115            ft.rename_to(file_path, bd.last_entry)
116         end
117
118         create {TEXT_FILE_WRITE} Result.connect_to(file_path)
119         do_at_exit(agent (file_: FILE_STREAM) do if file_.is_connected then file_.disconnect end end (Result))
120      ensure
121         Result /= file
122         Result.is_connected
123         not file.is_connected
124      end
125
126   map (dir_name: STRING; file_name_pattern: REGULAR_EXPRESSION; action: PROCEDURE[TUPLE[INTEGER, STRING]])
127         -- non-Void if the file exists; in that case the result contains the exact name of the log file.
128      require
129         dir_name /= Void
130         file_name_pattern /= Void
131         action /= Void
132      local
133         buf, file_name: STRING
134      do
135         buf := once ""
136         bd.connect_to(dir_name)
137         if bd.is_connected then
138            from
139               file_name := once ""
140               bd.read_entry
141            until
142               bd.end_of_input
143            loop
144               file_name.copy(bd.last_entry)
145               if file_name_pattern.match(file_name) then
146                  buf.clear_count
147                  file_name_pattern.append_ith_group(file_name, buf, 1)
148                  check
149                     buf.is_integer
150                  end
151                  action.call([buf.to_integer, file_name])
152               end
153               bd.read_entry
154            end
155            bd.disconnect
156         end
157      end
158
159   last_index: INTEGER
160
161   set_last_index (index: INTEGER)
162      do
163         if index > last_index then
164            last_index := index
165         end
166      end
167
168   rotate_file (dir_name: STRING; file_name_pattern: REGULAR_EXPRESSION; at_index, index: INTEGER; file_name: STRING)
169      require
170         last_index > 0
171      local
172         path, new_file_name, new_index: STRING
173      do
174         if retention /= -1 and then index > retention then
175            bd.compute_file_path_with(dir_name, file_name)
176            ft.delete(bd.last_entry)
177         elseif index = at_index then
178            path := once ""
179            bd.compute_file_path_with(dir_name, file_name)
180            path.copy(bd.last_entry)
181            new_index := once ""
182            new_index.clear_count
183            ;(index + 1).append_in(new_index)
184            new_file_name := once ""
185            new_file_name.copy(file_name)
186            if file_name_pattern.match(new_file_name) then
187               new_file_name.replace_substring(new_index, file_name_pattern.ith_group_first_index(1), file_name_pattern.ith_group_last_index(1))
188               bd.compute_file_path_with(dir_name, new_file_name)
189               ft.rename_to(path, bd.last_entry)
190            else
191               check False end
192            end
193         end
194      end
195
196   bd: BASIC_DIRECTORY
197   ft: FILE_TOOLS
198
199end -- class LOG_FILE_ROTATED
200--
201-- Copyright (C) 2009-2017: by all the people cited in the AUTHORS file.
202--
203-- Permission is hereby granted, free of charge, to any person obtaining a copy
204-- of this software and associated documentation files (the "Software"), to deal
205-- in the Software without restriction, including without limitation the rights
206-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
207-- copies of the Software, and to permit persons to whom the Software is
208-- furnished to do so, subject to the following conditions:
209--
210-- The above copyright notice and this permission notice shall be included in
211-- all copies or substantial portions of the Software.
212--
213-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
214-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
215-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
216-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
217-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
219-- THE SOFTWARE.