]> Frank Brehm's Git Trees - my-stuff/py-logrotate.git/commitdiff
Mit compress() weitergekommen.
authorFrank Brehm <frank@brehm-online.com>
Fri, 1 Jul 2011 11:43:07 +0000 (11:43 +0000)
committerFrank Brehm <frank@brehm-online.com>
Fri, 1 Jul 2011 11:43:07 +0000 (11:43 +0000)
git-svn-id: http://svn.brehm-online.com/svn/my-stuff/python/PyLogrotate/trunk@271 ec8d2aa5-1599-4edb-8739-2b3a1bc399aa

LogRotateConfig.py
LogRotateHandler.py
po/LogRotateConfig.de.po
po/LogRotateConfig.pot
test/apache2

index 5d0dbe9578029ec4bb098fc426e6eea7b1b21d82..41947a83f0338f088d14380977a0032609b2c7e5 100755 (executable)
@@ -88,6 +88,7 @@ integer_options = (
 string_options = (
     'extension',
     'compresscmd',
+    'compressext',
     'compressoptions',
 )
 
@@ -393,9 +394,9 @@ class LogrotateConfigurationReader(object):
         self.default = {}
 
         self.default['compress']      = False
-        self.default['compress_cmd']  = 'internal_gzip'
-        self.default['compress_ext']  = None
-        self.default['compress_opts'] = None
+        self.default['compresscmd']   = 'internal_gzip'
+        self.default['compressext']   = None
+        self.default['compressopts']  = None
         self.default['copy']          = False
         self.default['copytruncate']  = False
         self.default['create']        = {
@@ -820,11 +821,11 @@ class LogrotateConfigurationReader(object):
                     )
                 # set a compress ext, if Compress is True
                 if self.new_log['compress']:
-                    if not self.new_log['compress_ext']:
-                        if self.new_log['compress_cmd'] == 'internal_gzip':
-                            self.new_log['compress_ext'] = '.gz'
-                        elif self.new_log['compress_cmd'] == 'internal_bzip2':
-                            self.new_log['compress_ext'] = '.bz2'
+                    if not self.new_log['compressext']:
+                        if self.new_log['compresscmd'] == 'internal_gzip':
+                            self.new_log['compressext'] = '.gz'
+                        elif self.new_log['compresscmd'] == 'internal_bzip2':
+                            self.new_log['compressext'] = '.bz2'
                         else:
                             msg = _("No extension for compressed logfiles given " +
                                     "(File of definition: '%(file)s', start definition: %(rownum)d).") \
@@ -960,6 +961,11 @@ class LogrotateConfigurationReader(object):
         else:
             self.logger.warning( ( _("Could not detect option in line '%s'.") % (line)))
             return False
+        val = re.sub(r'^\s+$', '', val)
+        if self.verbose > 4:
+            msg = _("Found option '%(opt)s' with value '%(val)s'.") \
+                    % {'opt': option, 'val': val}
+            self.logger.debug(msg)
 
         # Check for unsupported options
         pattern = r'^(' + '|'.join(unsupported_options) + r')$'
@@ -1107,7 +1113,7 @@ class LogrotateConfigurationReader(object):
             if key in options_with_values:
                 if self.verbose > 5:
                     self.logger.debug( ( _("Option '%s' must have a value.") %(key)))
-                if (val is None) or (re.search(r'^\s*$', val) is None):
+                if (val is None) or (val == ''):
                     self.logger.warning( ( _("Option '%s' without a value") %(key)))
                     return False
             if key == 'compresscmd':
@@ -1855,9 +1861,9 @@ class LogrotateConfigurationReader(object):
         self.new_log['file_patterns'] = []
 
         self.new_log['compress']      = self.default['compress']
-        self.new_log['compress_cmd']  = self.default['compress_cmd']
-        self.new_log['compress_ext']  = self.default['compress_ext']
-        self.new_log['compress_opts'] = self.default['compress_opts']
+        self.new_log['compresscmd']   = self.default['compresscmd']
+        self.new_log['compressext']   = self.default['compressext']
+        self.new_log['compressopts']  = self.default['compressopts']
         self.new_log['configfile']    = config_file
         self.new_log['configrow']     = rownum
         self.new_log['copy']          = self.default['copy']
index 63536bf73492690a5634ea4d6cf3c461dc86bd8f..ead7c7940b127dad795b5bf5deb823cd062a9d54 100755 (executable)
@@ -29,6 +29,8 @@ import shutil
 import glob
 from datetime import datetime, timedelta
 import time
+import gzip
+import bz2
 
 from LogRotateConfig import LogrotateConfigurationError
 from LogRotateConfig import LogrotateConfigurationReader
@@ -856,7 +858,7 @@ class LogrotateHandler(object):
         files_compress = self._collect_files_compress(oldfiles, compress_extension, cur_desc_index)
         if len(files_compress):
             for oldfile in files_compress:
-                self.files_compress = cur_desc_index
+                self.files_compress[oldfile] = cur_desc_index
 
         # write back date of rotation into state file
         self.state_file.set_rotation_date(logfile)
@@ -1248,7 +1250,7 @@ class LogrotateHandler(object):
         # for compress extension
         compress_extension = ''
         if definition['compress']:
-            compress_extension = definition['compress_ext']
+            compress_extension = definition['compressext']
             match = re.search(r'^\.', compress_extension)
             if not match:
                 compress_extension = "." + compress_extension
@@ -1687,7 +1689,301 @@ class LogrotateHandler(object):
 
     #------------------------------------------------------------
     def compress(self):
-        pass
+        '''
+        Compressing all logfiles in self.files_compress
+
+        @return: None
+        '''
+
+        _ = self.t.lgettext
+
+        msg = _("Compression of all uncompressed logfiles ...")
+        self.logger.debug(msg)
+
+        if not len(self.files_compress.keys()):
+            msg = _("No logfiles to compress found.")
+            self.logger.info(msg)
+
+        for logfile in sorted(self.files_compress.keys(), key=str.lower):
+
+            cur_desc_index = self.files_compress[logfile]
+            definition = self.config[cur_desc_index]
+            command = definition['compresscmd']
+            compress_extension = definition['compressext']
+            compress_opts = definition['compressopts']
+
+            match = re.search(r'^\.', compress_extension)
+            if not match:
+                compress_extension = "." + compress_extension
+            target = logfile + compress_extension
+
+            # Check existence source logfile
+            if not os.path.exists(logfile):
+                msg = _("Source file '%s' for compression doesn't exists.") % (logfile)
+                raise LogrotateHandlerError(msg)
+                return
+
+            # Check existence target (compressed file)
+            if os.path.exists(target):
+                if os.path.samefile(logfile, target):
+                    msg = _("Source file '%(source)s' and target file '%(target)s' are the same file.") \
+                            % {'source': logfile, 'target': target}
+                    raise LogrotateHandlerError(msg)
+                    return
+                msg = _("Target file '%s' for compression allready exists.") %(target)
+                self.logger.warning(msg)
+
+            # Check for filesize Zero => not compressed
+            filesize = os.path.getsize(logfile)
+            if filesize <= 0:
+                msg = _("File '%s' has a size of 0, skip compressing.") % (logfile)
+                self.logger.info(msg)
+                continue
+
+            # Execute compressing ...
+            msg = _("Compressing file '%(file)s' to '%(target)s' with '%(cmd)s' ...") \
+                    % {'file': logfile, 'target': target, 'cmd': command}
+            self.logger.info(msg)
+
+            if command == 'internal_gzip':
+                self._compress_internal_gzip(logfile, target)
+            elif command == 'internal_bzip2':
+                self._compress_internal_bzip2(logfile, target)
+            else:
+                self._compress_external(logfile, target, command, compress_opts)
+
+        return
+
+    #------------------------------------------------------------
+    def _compress_external(self, source, target, command, options):
+        '''
+        Compression of the given source file to the target file
+        with an external command.
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+        @param command: the OS command to use to compress
+        @type command:  str
+        @param options: additional options to the compress command
+                        possible placeholders inside the options:
+                            - {}: placeholder for sourcefile
+                            - []: placeholder for targetfile
+        @type options:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        test_mode = self.test
+        test_mode = False
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with command '%(cmd)s'.") \
+                    % {'source': source, 'target': target, 'cmd': command}
+            self.logger.debug(msg)
+
+
+    #------------------------------------------------------------
+    def _compress_internal_gzip(self, source, target):
+        '''
+        Compression of the given source file to the target file
+        with the Python module gzip.
+        As compression level is allways used 9 (highest compression).
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        test_mode = self.test
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with module gzip.") \
+                    % {'source': source, 'target': target}
+            self.logger.debug(msg)
+
+        if not test_mode:
+            # open source for reading
+            f_in = None
+            try:
+                f_in = open(source, 'rb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
+                        % {'file': source, 'err': str(e)}
+                self.logger.error(msg)
+                return False
+
+            # open target for writing
+            f_out = None
+            try:
+                f_out = gzip.open(target, 'wb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
+                        % {'file': target, 'err': str(e)}
+                self.logger.error(msg)
+                f_in.close()
+                return False
+
+            # compress and write target
+            f_out.writelines(f_in)
+            # close both files
+            f_out.close()
+            f_in.close()
+
+        # Copying permissions and timestamps from source to target
+        if self.verbose > 1:
+            msg = _("Copying permissions and timestamps from source to target.")
+            self.logger.debug(msg)
+        if not test_mode:
+            shutil.copystat(source, target)
+
+        # Copying ownership from source to target
+        statinfo = os.stat(source)
+        old_uid = statinfo.st_uid
+        old_gid = statinfo.st_gid
+        statinfo = os.stat(target)
+        new_uid = statinfo.st_uid
+        new_gid = statinfo.st_gid
+
+        if (old_uid != new_uid) or (old_gid != new_gid):
+            if self.verbose > 1:
+                msg = _("Copying ownershipfrom source to target.")
+                self.logger.debug(msg)
+            if not test_mode:
+                try:
+                    os.chown(target, old_uid, old_gid)
+                except OSError, e:
+                    msg = _("Error on chown of '%(file)s': %(err)s") \
+                            % {'file': target, 'err': e.strerror}
+                    self.logger.warning(msg)
+
+        # And last, but not least, delete uncompressed file
+        if self.verbose > 1:
+            msg = _("Deleting uncompressed file '%s' ...") % (source)
+            self.logger.debug(msg)
+
+        if not self.test:
+            try:
+                os.remove(source)
+            except OSError, e:
+                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                        % {'file': source, 'msg': str(e) }
+                self.logger.error(msg)
+                return False
+
+        return True
+
+    #------------------------------------------------------------
+    def _compress_internal_bzip2(self, source, target):
+        '''
+        Compression of the given source file to the target file
+        with the Python module bz2.
+        As compression level is allways used 9 (highest compression).
+
+        It raises a LogrotateHandlerError on some errors.
+
+        @param source: the source file to compress
+        @type source:  str
+        @param target: the filename of the compressed file.
+        @type target:  str
+
+        @return: success or not
+        @rtype:  bool
+        '''
+
+        _ = self.t.lgettext
+
+        test_mode = self.test
+
+        if self.verbose > 1:
+            msg = _("Compressing source '%(source)s' to target'%(target)s' with module bz2.") \
+                    % {'source': source, 'target': target}
+            self.logger.debug(msg)
+
+        if not test_mode:
+            # open source for reading
+            f_in = None
+            try:
+                f_in = open(source, 'rb')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on reading: %(err)s") \
+                        % {'file': source, 'err': str(e)}
+                self.logger.error(msg)
+                return False
+
+            # open target for writing
+            f_out = None
+            try:
+                f_out = bz2.BZ2File(target, 'w')
+            except IOError, e:
+                msg = _("Error on open file '%(file)s' on writing: %(err)s") \
+                        % {'file': target, 'err': str(e)}
+                self.logger.error(msg)
+                f_in.close()
+                return False
+
+            # compress and write target
+            f_out.writelines(f_in)
+            # close both files
+            f_out.close()
+            f_in.close()
+
+        # Copying permissions and timestamps from source to target
+        if self.verbose > 1:
+            msg = _("Copying permissions and timestamps from source to target.")
+            self.logger.debug(msg)
+        if not test_mode:
+            shutil.copystat(source, target)
+
+        # Copying ownership from source to target
+        statinfo = os.stat(source)
+        old_uid = statinfo.st_uid
+        old_gid = statinfo.st_gid
+        statinfo = os.stat(target)
+        new_uid = statinfo.st_uid
+        new_gid = statinfo.st_gid
+
+        if (old_uid != new_uid) or (old_gid != new_gid):
+            if self.verbose > 1:
+                msg = _("Copying ownershipfrom source to target.")
+                self.logger.debug(msg)
+            if not test_mode:
+                try:
+                    os.chown(target, old_uid, old_gid)
+                except OSError, e:
+                    msg = _("Error on chown of '%(file)s': %(err)s") \
+                            % {'file': target, 'err': e.strerror}
+                    self.logger.warning(msg)
+
+        # And last, but not least, delete uncompressed file
+        if self.verbose > 1:
+            msg = _("Deleting uncompressed file '%s' ...") % (source)
+            self.logger.debug(msg)
+
+        if not self.test:
+            try:
+                os.remove(source)
+            except OSError, e:
+                msg = _("Error removing uncompressed file '%(file)s': %(msg)") \
+                        % {'file': source, 'msg': str(e) }
+                self.logger.error(msg)
+                return False
+
+        return True
 
 #========================================================================
 
index 0b3463e4266552671f24dcb9935f36d8e9c55a0b..aa314c834fc7bb73f5b3d327c461f3a06a404ee9 100644 (file)
@@ -197,21 +197,26 @@ msgstr "Neuer externer Scriptname: »%s«"
 msgid "Syntax error in file '%(file)s', line %(line)s"
 msgstr "Syntaxfehler in Datei Datei »%(file)s«, Zeile %(line)s"
 
-#: LogRotateConfig.py:894
+#: LogRotateConfig.py:942
 #, python-format
 msgid ""
-"Checking line '%(line)s' for a logrotate option. (file '%(file)s', line "
-"%(lnr)s)"
+"Checking line '%(line)s' for a logrotate option. "
+"(file '%(file)s', line %(lnr)s)"
 msgstr ""
 "Überprüfe Zeile »%(line)s« nach einer Logrotate-Option. "
 "(Datei »%(file)s«, Zeile %(lnr)s)"
 
-#: LogRotateConfig.py:913
+#: LogRotateConfig.py:961
 #, python-format
 msgid "Could not detect option in line '%s'."
 msgstr "Konnte keine Option in Zeile »%s« ermitteln."
 
-#: LogRotateConfig.py:921
+#: LogRotateConfig.py:964
+#, python-format
+msgid "Found option '%(opt)s' with value '%(val)s'."
+msgstr "Option »%(opt)s« mit Wert »%(val)s« gefunden."
+
+#: LogRotateConfig.py:973
 #, python-format
 msgid "Unsupported option '%(option)s'. (file '%(file)s', line %(lnr)s)"
 msgstr "Nicht unterstützte Option »%(option)s«. (Datei »%(file)s«, Zeile %(lnr)s)"
index 59d39ebc56ddccda6a1c08f5fa0f5fa78de9856e..b962b875c385b87070b76b14863c1be46f99afbd 100644 (file)
@@ -175,17 +175,22 @@ msgstr ""
 msgid "Syntax error in file '%(file)s', line %(line)s"
 msgstr ""
 
-#: LogRotateConfig.py:894
+#: LogRotateConfig.py:942
 #, python-format
 msgid "Checking line '%(line)s' for a logrotate option. (file '%(file)s', line %(lnr)s)"
 msgstr ""
 
-#: LogRotateConfig.py:913
+#: LogRotateConfig.py:961
 #, python-format
 msgid "Could not detect option in line '%s'."
 msgstr ""
 
-#: LogRotateConfig.py:921
+#: LogRotateConfig.py:964
+#, python-format
+msgid "Found option '%(opt)s' with value '%(val)s'."
+msgstr ""
+
+#: LogRotateConfig.py:973
 #, python-format
 msgid "Unsupported option '%(option)s'. (file '%(file)s', line %(lnr)s)"
 msgstr ""
index 656af09ed9034d3700e992fa3575425b204d7800..e3d0880220097d01f27cb4c277a527f8b671a5d3 100644 (file)
@@ -27,6 +27,7 @@ endscript
 
 /home/frank/devel/Python/PyLogrotate/test/log/error_log {
     compress
+    compresscmd internal_bzip2
     nomissingok
     notifempty
     sharedscripts