diff -Nru bleachbit-1.10/bleachbit/Action.py bleachbit-1.12~xenial/bleachbit/Action.py --- bleachbit-1.10/bleachbit/Action.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Action.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ import glob +import logging import os import re import types @@ -36,7 +37,10 @@ from Common import _ if 'posix' == os.name: + re_flags = 0 import Unix +else: + re_flags = re.IGNORECASE # @@ -86,8 +90,13 @@ assert(isinstance(self.regex, (str, unicode, types.NoneType))) self.nregex = action_element.getAttribute('nregex') assert(isinstance(self.nregex, (str, unicode, types.NoneType))) + self.wholeregex = action_element.getAttribute('wholeregex') + assert(isinstance(self.wholeregex, (str, unicode, types.NoneType))) + self.nwholeregex = action_element.getAttribute('nwholeregex') + assert(isinstance(self.nwholeregex, (str, unicode, types.NoneType))) self.search = action_element.getAttribute('search') - self.path = os.path.expanduser(os.path.expandvars( + self.object_type = action_element.getAttribute('type') + self.path = os.path.expanduser(FileUtilities.expandvars( action_element.getAttribute('path'))) if 'nt' == os.name and self.path: # convert forward slash to backslash for compatibility with getsize() @@ -102,13 +111,52 @@ action_element.getAttribute('cache')) self.ds['command'] = action_element.getAttribute('command') self.ds['path'] = self.path + if not any([self.object_type, self.regex, self.nregex, + self.wholeregex, self.nwholeregex]): + # If the filter is not needed, bypass it for speed. + self.get_paths = self._get_paths def get_deep_scan(self): if 0 == len(self.ds): raise StopIteration yield self.ds + def path_filter(self, path): + """Process the filters: regex, nregex, type + + If a filter is defined and it fails to match, this function + returns False. Otherwise, this function returns True.""" + + if self.regex: + if not self.regex_c.search(os.path.basename(path)): + return False + + if self.nregex: + if self.nregex_c.search(os.path.basename(path)): + return False + + if self.wholeregex: + if not self.wholeregex_c.search(path): + return False + + if self.nwholeregex: + if self.nwholeregex_c.search(path): + return False + + if self.object_type: + if 'f' == self.object_type and not os.path.isfile(path): + return False + elif 'd' == self.object_type and not os.path.isdir(path): + return False + + return True + def get_paths(self): + import itertools + for f in itertools.ifilter(self.path_filter, self._get_paths()): + yield f + + def _get_paths(self): """Return a filtered list of files""" def get_file(path): @@ -117,12 +165,14 @@ def get_walk_all(top): for expanded in glob.iglob(top): - for path in FileUtilities.children_in_directory(expanded, True): + for path in FileUtilities.children_in_directory( + expanded, True): yield path def get_walk_files(top): for expanded in glob.iglob(top): - for path in FileUtilities.children_in_directory(expanded, False): + for path in FileUtilities.children_in_directory( + expanded, False): yield path if 'deep' == self.search: @@ -139,34 +189,19 @@ raise RuntimeError("invalid search='%s'" % self.search) if self.regex: - regex_c = re.compile(self.regex) + self.regex_c = re.compile(self.regex, re_flags) if self.nregex: - nregex_c = re.compile(self.nregex) + self.nregex_c = re.compile(self.nregex, re_flags) - # Sometimes this loop repeats many times, so optimize it by - # putting the conditional outside the loop. + if self.wholeregex: + self.wholeregex_c = re.compile(self.wholeregex, re_flags) - if not self.regex and not self.nregex: - for path in func(self.path): - yield path - elif self.regex and not self.nregex: - for path in func(self.path): - if not regex_c.search(os.path.basename(path)): - continue - yield path - elif self.nregex: - for path in func(self.path): - if nregex_c.search(os.path.basename(path)): - continue - yield path - else: - for path in func(self.path): - if not regex_c.search(os.path.basename(path)): - continue - if nregex_c.search(os.path.basename(path)): - continue - yield path + if self.nwholeregex: + self.nwholeregex_c = re.compile(self.nwholeregex, re_flags) + + for path in func(self.path): + yield path def get_commands(self): raise NotImplementedError('not implemented') @@ -338,6 +373,44 @@ _('Clean')) +class Process(ActionProvider): + + """Action to run a process""" + action_key = 'process' + + def __init__(self, action_element): + self.cmd = FileUtilities.expandvars(action_element.getAttribute('cmd')) + # by default, wait + self.wait = True + wait = action_element.getAttribute('wait') + if wait and wait.lower()[0] in ('f', 'n'): + # false or no + self.wait = False + + def get_commands(self): + + def run_process(): + try: + if self.wait: + args = self.cmd.split(' ') + (rc, stdout, stderr) = General.run_external(args) + else: + rc = 0 # unknown because we don't wait + from subprocess import Popen + Popen(self.cmd) + except Exception, e: + raise RuntimeError( + 'Exception in external command\nCommand: %s\nError: %s' % (self.cmd, str(e))) + else: + if not 0 == rc: + logger = logging.getLogger(__name__) + logger.warning( + 'Command: %s\nReturn code: %d\nStdout: %s\nStderr: %s\n' % + (self.cmd, rc, stdout, stderr)) + return 0 + yield Command.Function(path=None, func=run_process, label=_("Run external command: %s") % self.cmd) + + class Shred(FileActionProvider): """Action to shred files (override preference)""" diff -Nru bleachbit-1.10/bleachbit/backport.py bleachbit-1.12~xenial/bleachbit/backport.py --- bleachbit-1.10/bleachbit/backport.py 1970-01-01 00:00:00.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/backport.py 2016-07-01 21:01:49.000000000 +0000 @@ -0,0 +1,97 @@ + +# from Python 2.7 +# https://github.com/python/cpython/blob/75891384fae8e4c564b7d8ca9c16a58922d2f7c0/Lib/ntpath.py + +# because the Python 2.5 version used on Windows has bugs such as removing +# "$foo" where foo is unknown. This is a problem because it can be a legitimate +# filename. + +import os +import sys + +_unicode = unicode + + +def expandvars(path): + """Expand shell variables of the forms $var, ${var} and %var%. + + Unknown variables are left unchanged.""" + if '$' not in path and '%' not in path: + return path + import string + varchars = string.ascii_letters + string.digits + '_-' + if isinstance(path, _unicode): + encoding = sys.getfilesystemencoding() + + def getenv(var): + return os.environ[var.encode(encoding)].decode(encoding) + else: + def getenv(var): + return os.environ[var] + res = '' + index = 0 + pathlen = len(path) + while index < pathlen: + c = path[index] + if c == '\'': # no expansion within single quotes + path = path[index + 1:] + pathlen = len(path) + try: + index = path.index('\'') + res = res + '\'' + path[:index + 1] + except ValueError: + res = res + c + path + index = pathlen - 1 + elif c == '%': # variable or '%' + if path[index + 1:index + 2] == '%': + res = res + c + index = index + 1 + else: + path = path[index + 1:] + pathlen = len(path) + try: + index = path.index('%') + except ValueError: + res = res + '%' + path + index = pathlen - 1 + else: + var = path[:index] + try: + res = res + getenv(var) + except KeyError: + res = res + '%' + var + '%' + elif c == '$': # variable or '$$' + if path[index + 1:index + 2] == '$': + res = res + c + index = index + 1 + elif path[index + 1:index + 2] == '{': + path = path[index + 2:] + pathlen = len(path) + try: + index = path.index('}') + var = path[:index] + try: + res = res + getenv(var) + except KeyError: + res = res + '${' + var + '}' + except ValueError: + res = res + '${' + path + index = pathlen - 1 + else: + var = '' + index = index + 1 + c = path[index:index + 1] + while c != '' and c in varchars: + var = var + c + index = index + 1 + c = path[index:index + 1] + try: + res = res + getenv(var) + except KeyError: + res = res + '$' + var + if c != '': + index = index - 1 + else: + res = res + c + index = index + 1 + return res diff -Nru bleachbit-1.10/bleachbit/CleanerML.py bleachbit-1.12~xenial/bleachbit/CleanerML.py --- bleachbit-1.10/bleachbit/CleanerML.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/CleanerML.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -97,7 +97,7 @@ logger = logging.getLogger(__name__) logger.exception( 'error in handle_cleaner_option() for cleaner id = %s, option XML=%s', - self.cleaner.id, option.toxml()) + self.cleaner.id, option.toxml()) self.handle_cleaner_running(cleaner.getElementsByTagName('running')) self.handle_localizations( cleaner.getElementsByTagName('localizations')) diff -Nru bleachbit-1.10/bleachbit/Cleaner.py bleachbit-1.12~xenial/bleachbit/Cleaner.py --- bleachbit-1.10/bleachbit/Cleaner.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Cleaner.py 2016-09-24 21:01:32.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ import Windows from Common import _ -from FileUtilities import children_in_directory +from FileUtilities import children_in_directory, expandvars from Options import options # Suppress GTK warning messages while running in CLI #34 @@ -164,7 +164,7 @@ print "debug: process '%s' is running" % pathname return True elif 'pathname' == test: - expanded = os.path.expanduser(os.path.expandvars(pathname)) + expanded = os.path.expanduser(expandvars(pathname)) for globbed in glob.iglob(expanded): if os.path.exists(globbed): print "debug: file '%s' exists indicating '%s' is running" % (globbed, self.name) @@ -217,7 +217,7 @@ 'Clean database fragmentation to reduce space and improve speed without removing any data')) if 'posix' == os.name: - self.profile_dir = "~/.mozilla/firefox*/*.default*/" + self.profile_dir = "~/.mozilla/firefox*/*/" self.add_running('exe', 'firefox') self.add_running('exe', 'firefox-bin') self.add_running('pathname', self.profile_dir + 'lock') @@ -270,7 +270,7 @@ if 'posix' == os.name: crashdir = os.path.expanduser("~/.mozilla/firefox/Crash Reports") if 'nt' == os.name: - crashdir = os.path.expandvars( + crashdir = expandvars( "$USERPROFILE\\Application Data\\Mozilla\\Firefox\\Crash Reports") if 'crash_reports' == option_id: for filename in children_in_directory(crashdir, False): @@ -445,7 +445,7 @@ # options for Linux and BSD # if 'posix' == os.name: - # TRANSLATORS: desktop entries are .desktop files in Linux tha + # TRANSLATORS: desktop entries are .desktop files in Linux that # make up the application menu (the menu that shows BleachBit, # Firefox, and others. The .desktop files also associate file # types, so clicking on an .html file in Nautilus brings up @@ -620,7 +620,7 @@ '$windir\\system32\\wbem\\Logs\\*.log', ) for path in paths: - expanded = os.path.expandvars(path) + expanded = expandvars(path) for globbed in glob.iglob(expanded): files += [globbed] @@ -632,10 +632,10 @@ # how to manually create this file # http://www.pctools.com/guides/registry/detail/856/ if 'nt' == os.name and 'memory_dump' == option_id: - fname = os.path.expandvars('$windir\\memory.dmp') + fname = expandvars('$windir\\memory.dmp') if os.path.exists(fname): files += [fname] - for fname in glob.iglob(os.path.expandvars('$windir\\Minidump\\*.dmp')): + for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')): files += [fname] # most recently used documents list @@ -676,7 +676,7 @@ # temporary files if 'nt' == os.name and 'tmp' == option_id: - dirname = os.path.expandvars( + dirname = expandvars( "$USERPROFILE\\Local Settings\\Temp\\") # whitelist the folder %TEMP%\Low but not its contents # https://bugs.launchpad.net/bleachbit/+bug/1421726 @@ -684,7 +684,7 @@ for filename in children_in_directory(dirname, True): if not low == filename.lower(): yield Command.Delete(filename) - dirname = os.path.expandvars("$windir\\temp\\") + dirname = expandvars("$windir\\temp\\") for filename in children_in_directory(dirname, True): yield Command.Delete(filename) @@ -747,7 +747,7 @@ # prefetch if 'nt' == os.name and 'prefetch' == option_id: - for path in glob.iglob(os.path.expandvars('$windir\\Prefetch\\*.pf')): + for path in glob.iglob(expandvars('$windir\\Prefetch\\*.pf')): yield Command.Delete(path) # recycle bin @@ -803,8 +803,13 @@ regexes.append('^' + os.path.expanduser('~/.cache/wallpaper/')) # Clean Firefox cache from Firefox cleaner (LP#1295826) regexes.append('^' + os.path.expanduser('~/.cache/mozilla')) + # Clean Google Chrome cache from Google Chrome cleaner (LP#656104) + regexes.append('^' + os.path.expanduser('~/.cache/google-chrome')) regexes.append( '^' + os.path.expanduser('~/.cache/gnome-control-center/')) + # iBus Pinyin + # https://bugs.launchpad.net/bleachbit/+bug/1538919 + regexes.append('^' + os.path.expanduser('~/.cache/ibus/')) for regex in regexes: if None != re.match(regex, pathname): return True diff -Nru bleachbit-1.10/bleachbit/CLI.py bleachbit-1.12~xenial/bleachbit/CLI.py --- bleachbit-1.10/bleachbit/CLI.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/CLI.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -129,7 +129,7 @@ # TRANSLATORS: This is the command line usage. Don't translate # %prog, but do translate usage, options, cleaner, and option. # More information about the command line is here - # http://bleachbit.sourceforge.net/documentation/command-line + # http://www.bleachbit.org/documentation/command-line usage = _("usage: %prog [options] cleaner.option1 cleaner.option2") parser = optparse.OptionParser(usage) parser.add_option("-l", "--list-cleaners", action="store_true", @@ -173,7 +173,7 @@ if options.version: print """ BleachBit version %s -Copyright (C) 2008-2015 Andrew Ziem. All rights reserved. +Copyright (C) 2008-2016 Andrew Ziem. All rights reserved. License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.""" % APP_VERSION diff -Nru bleachbit-1.10/bleachbit/Command.py bleachbit-1.12~xenial/bleachbit/Command.py --- bleachbit-1.10/bleachbit/Command.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Command.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -140,6 +140,9 @@ assert isinstance(func_ret, (int, long)) ret['size'] = func_ret else: + if os.path.isdir(self.path): + raise RuntimeError('Attempting to run file function %s on directory %s' % + (self.func.func_name, self.path)) # Function takes a path. We check the size. oldsize = FileUtilities.getsize(self.path) try: diff -Nru bleachbit-1.10/bleachbit/Common.py bleachbit-1.12~xenial/bleachbit/Common.py --- bleachbit-1.10/bleachbit/Common.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Common.py 2016-09-24 20:58:32.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,9 +29,9 @@ import os import sys -APP_VERSION = "1.10" +APP_VERSION = "1.12" APP_NAME = "BleachBit" -APP_URL = "http://bleachbit.sourceforge.net" +APP_URL = "http://www.bleachbit.org" socket_timeout = 10 @@ -51,7 +51,7 @@ # Setting below value to false disables update notification (useful # for packages in repositories). -online_update_notification_enabled = True +online_update_notification_enabled = False # # Paths @@ -117,8 +117,7 @@ sys.platform) # local cleaners directory (for running from source tree) -local_cleaners_dir = os.path.normpath( - os.path.join(bleachbit_exe_path, '../cleaners')) +local_cleaners_dir = os.path.normpath(personal_cleaners_dir) # application icon __icons = ('/usr/share/pixmaps/bleachbit.png', # Linux diff -Nru bleachbit-1.10/bleachbit/DeepScan.py bleachbit-1.12~xenial/bleachbit/DeepScan.py --- bleachbit-1.10/bleachbit/DeepScan.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/DeepScan.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/Diagnostic.py bleachbit-1.12~xenial/bleachbit/Diagnostic.py --- bleachbit-1.10/bleachbit/Diagnostic.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Diagnostic.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/FileUtilities.py bleachbit-1.12~xenial/bleachbit/FileUtilities.py --- bleachbit-1.10/bleachbit/FileUtilities.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/FileUtilities.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -323,12 +323,24 @@ """Join pathname1 and pathname1, expand pathname, glob, and return as list""" ret = [] pathname3 = os.path.expanduser( - os.path.expandvars(os.path.join(pathname1, pathname2))) + expandvars(os.path.join(pathname1, pathname2))) for pathname4 in glob.iglob(pathname3): ret.append(pathname4) return ret +def expandvars(path): + if (2, 5) == sys.version_info[0:2] and 'nt' == os.name: + # Python 2.5 should not change $foo when foo is unknown, but + # it actually strips it out. + import backport + expandvars = backport.expandvars + return backport.expandvars(path) + else: + expandvars = os.path.expandvars + return os.path.expandvars(path) + + def extended_path(path): """If applicable, return the extended Windows pathname""" if 'nt' == os.name: @@ -412,7 +424,7 @@ if not same_partition(home, '/tmp/'): ret.append('/tmp') elif 'nt' == os.name: - localtmp = os.path.expandvars('$TMP') + localtmp = expandvars('$TMP') logger = logging.getLogger(__name__) if not os.path.exists(localtmp): logger.warning('%TMP% does not exist: %s', localtmp) diff -Nru bleachbit-1.10/bleachbit/General.py bleachbit-1.12~xenial/bleachbit/General.py --- bleachbit-1.10/bleachbit/General.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/General.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/GuiBasic.py bleachbit-1.12~xenial/bleachbit/GuiBasic.py --- bleachbit-1.10/bleachbit/GuiBasic.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/GuiBasic.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ title=title, buttons=( gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - stock_button, gtk.RESPONSE_OK), + stock_button, gtk.RESPONSE_OK), action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER) chooser.set_select_multiple(multiple) chooser.set_current_folder(os.path.expanduser('~')) @@ -170,7 +170,7 @@ host = url else: host = ret.group(2) - # TRANSLATORS: %s expands to bleachbit.sourceforge.net or similar + # TRANSLATORS: %s expands to www.bleachbit.org or similar msg = _("Open web browser to %s?") % host resp = message_dialog(parent_window, msg, gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL) diff -Nru bleachbit-1.10/bleachbit/GuiPreferences.py bleachbit-1.12~xenial/bleachbit/GuiPreferences.py --- bleachbit-1.10/bleachbit/GuiPreferences.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/GuiPreferences.py 2016-07-01 21:01:49.000000000 +0000 @@ -3,8 +3,8 @@ # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/GUI.py bleachbit-1.12~xenial/bleachbit/GUI.py --- bleachbit-1.10/bleachbit/GUI.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/GUI.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -281,7 +281,7 @@ # as seen on Ubuntu 9.04 with Italian and Spanish. gobject.idle_add(lambda: self.textview.scroll_mark_onscreen( - self.textbuffer.get_insert())) + self.textbuffer.get_insert())) def on_selection_changed(self, selection): """When the tree view selection changed""" @@ -426,7 +426,7 @@ link: GuiBasic.open_url(link, self.window, False)) dialog = gtk.AboutDialog() dialog.set_comments(_("Program to clean unnecessary files")) - dialog.set_copyright("Copyright (C) 2008-2015 Andrew Ziem") + dialog.set_copyright("Copyright (C) 2008-2016 Andrew Ziem") try: dialog.set_license(open(license_filename).read()) except: @@ -882,7 +882,7 @@ if 'nt' == os.name: # BitDefender false positive. BitDefender didn't mark BleachBit as infected or show # anything in its log, but sqlite would fail to import unless BitDefender was in "game mode." - # http://bleachbit.sourceforge.net/forum/074-fails-errors + # http://www.bleachbit.org/forum/074-fails-errors try: import sqlite3 except ImportError, e: diff -Nru bleachbit-1.10/bleachbit/Memory.py bleachbit-1.12~xenial/bleachbit/Memory.py --- bleachbit-1.10/bleachbit/Memory.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Memory.py 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/Options.py bleachbit-1.12~xenial/bleachbit/Options.py --- bleachbit-1.10/bleachbit/Options.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Options.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -97,7 +97,14 @@ # restore colon lost because ConfigParser treats colon special # in keys pathname = pathname[0] + ':' + pathname[1:] - if not os.path.lexists(pathname): + exists = False + try: + exists = os.path.lexists(pathname) + except: + # this deals with corrupt keys + # https://www.bleachbit.org/forum/bleachbit-wont-launch-error-startup + print 'ERROR: error checking whether path exists: %s ' % pathname + if not exists: # the file does not on exist, so forget it self.config.remove_option('hashpath', option) diff -Nru bleachbit-1.10/bleachbit/RecognizeCleanerML.py bleachbit-1.12~xenial/bleachbit/RecognizeCleanerML.py --- bleachbit-1.10/bleachbit/RecognizeCleanerML.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/RecognizeCleanerML.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/Special.py bleachbit-1.12~xenial/bleachbit/Special.py --- bleachbit-1.10/bleachbit/Special.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Special.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -41,12 +41,12 @@ """Create an SQL command to shred character columns""" cmd = "" if cols and options.get('shred'): - cmd += "update %s set %s %s;" % \ + cmd += "update or ignore %s set %s %s;" % \ (table, ",".join(["%s = randomblob(length(%s))" % (col, col) - for col in cols]), where) - cmd += "update %s set %s %s;" % \ + for col in cols]), where) + cmd += "update or ignore %s set %s %s;" % \ (table, ",".join(["%s = zeroblob(length(%s))" % (col, col) - for col in cols]), where) + for col in cols]), where) cmd += "delete from %s %s;" % (table, where) return cmd @@ -97,7 +97,7 @@ cmds += __shred_sqlite_char_columns('autofill_profiles', cols) cols = ( 'company_name', 'street_address', 'address_1', 'address_2', 'address_3', 'address_4', - 'postal_code', 'country_code', 'language_code', 'recipient_name', 'phone_number') + 'postal_code', 'country_code', 'language_code', 'recipient_name', 'phone_number') cmds += __shred_sqlite_char_columns('server_addresses', cols) FileUtilities.execute_sqlite3(path, cmds) @@ -117,7 +117,7 @@ ver = __get_chrome_history(path) cmds = "" - if ver in [4, 20, 22, 23, 25, 26, 28, 29]: + if ver in [4, 20, 22, 23, 25, 26, 28, 29, 32]: # Version 4 includes Chromium 12 # Version 20 includes Chromium 14, Google Chrome 15, Google Chrome 19 # Version 22 includes Google Chrome 20 @@ -125,6 +125,7 @@ # Version 26 is Google Chrome 29 # Version 28 is Google Chrome 30 # Version 29 is Google Chrome 37 + # Version 32 is Google Chrome 51 # icon_mapping cols = ('page_url',) diff -Nru bleachbit-1.10/bleachbit/Unix.py bleachbit-1.12~xenial/bleachbit/Unix.py --- bleachbit-1.10/bleachbit/Unix.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Unix.py 2016-09-24 20:58:32.000000000 +0000 @@ -2,8 +2,8 @@ # -*- coding: UTF-8 -*- # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,6 +25,7 @@ import glob +import logging import os import re import shlex @@ -36,18 +37,6 @@ import FileUtilities import General -HAVE_GNOME_VFS = True -try: - import gnomevfs -except: - try: - # this is the deprecated name - import gnome.vfs - except: - HAVE_GNOME_VFS = False - else: - gnomevfs = gnome.vfs - class Locales: @@ -209,6 +198,7 @@ 'pl': 'polski', 'ps': 'پښتو', 'pt': 'Português', + 'pt_BR': 'Português do Brasil', 'qu': 'Runa Simi', 'rm': 'rumantsch grischun', 'rn': 'Ikirundi', @@ -266,6 +256,8 @@ 'yo': 'Yorùbá', 'za': 'Saɯ cueŋƅ', 'zh': '中文', + 'zh_CN': '中文', + 'zh_TW': '中文', 'zu': 'isiZulu'} _paths = [] @@ -280,7 +272,7 @@ if not locales_to_keep: raise RuntimeError('Found no locales to keep') purgeable_locales = frozenset((locale for locale in Locales.native_locale_names.keys() - if locale not in locales_to_keep)) + if locale not in locales_to_keep)) for xml_node in self._paths: for (locale, path) in Locales.handle_path('', xml_node): @@ -442,6 +434,20 @@ return False +def is_unregistered_mime(mimetype): + """Returns True if the MIME type is known to be unregistered. If + registered or unknown, conservatively returns False.""" + try: + import gio + if 0 == len(gio.app_info_get_all_for_type(mimetype)): + return True + except: + logger = logging.getLogger(__name__) + logger.warning( + 'error calling gio.app_info_get_all_for_type(%s)' % mimetype) + return False + + def is_broken_xdg_desktop(pathname): """Returns boolean whether the given XDG desktop entry file is broken. Reference: http://standards.freedesktop.org/desktop-entry-spec/latest/""" @@ -466,7 +472,7 @@ print "info: is_broken_xdg_menu: missing required option 'MimeType': '%s'" % (pathname) return True mimetype = config.get('Desktop Entry', 'MimeType').strip().lower() - if HAVE_GNOME_VFS and 0 == len(gnomevfs.mime_get_all_applications(mimetype)): + if is_unregistered_mime(mimetype): print "info: is_broken_xdg_menu: MimeType '%s' not " \ "registered '%s'" % (mimetype, pathname) return True diff -Nru bleachbit-1.10/bleachbit/Update.py bleachbit-1.12~xenial/bleachbit/Update.py --- bleachbit-1.10/bleachbit/Update.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Update.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,8 @@ # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff -Nru bleachbit-1.10/bleachbit/Winapp.py bleachbit-1.12~xenial/bleachbit/Winapp.py --- bleachbit-1.10/bleachbit/Winapp.py 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/bleachbit/Winapp.py 2016-07-01 21:01:49.000000000 +0000 @@ -1,8 +1,9 @@ + # vim: ts=4:sw=4:expandtab # BleachBit -# Copyright (C) 2008-2015 Andrew Ziem -# http://bleachbit.sourceforge.net +# Copyright (C) 2008-2016 Andrew Ziem +# http://www.bleachbit.org # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -122,6 +123,17 @@ return False +def fnmatch_translate(pattern): + """Same as the original without the end""" + import fnmatch + r = fnmatch.translate(pattern) + if r.endswith('$'): + return r[:-1] + if r.endswith(r'\Z(?ms)'): + return r[:-7] + return r + + class Winapp: """Create cleaners from a Winapp2.ini-style file""" @@ -165,6 +177,57 @@ self.add_section(cleanerid, langsecref) return cleanerid + def excludekey_to_nwholeregex(self, excludekey): + """Translate one ExcludeKey to CleanerML nwholeregex + + Supported examples + FILE=%LocalAppData%\BleachBit\BleachBit.ini + FILE=%LocalAppData%\BleachBit\|BleachBit.ini + FILE=%LocalAppData%\BleachBit\|*.ini + FILE=%LocalAppData%\BleachBit\|*.ini;*.bak + PATH=%LocalAppData%\BleachBit\ + PATH=%LocalAppData%\BleachBit\|*.* + """ + parts = excludekey.split('|') + parts[0] = parts[0].upper() + if 'REG' == parts[0]: + raise NotImplementedError('REG not supported in ExcludeKey') + + # the last part contains the filename(s) + files = None + files_regex = '' + if 3 == len(parts): + files = parts[2].split(';') + if 1 == len(files): + # one file pattern like *.* or *.log + files_regex = fnmatch_translate(files[0]) + if '*.*' == files_regex: + files = None + elif len(files) > 1: + # multiple file patterns like *.log;*.bak + files_regex = '(%s)' % '|'.join( + [fnmatch_translate(f) for f in files]) + + # the middle part contains the file + regexes = [] + for expanded in winapp_expand_vars(parts[1]): + regex = None + if not files: + # There is no third part, so this is either just a folder, + # or sometimes the file is specified directly. + regex = fnmatch_translate(expanded) + if files: + # match one or more file types, directly in this tree or in any + # sub folder + regex = '%s.*%s' % ( + fnmatch_translate(expanded), files_regex) + regexes.append(regex) + + if 1 == len(regexes): + return regexes[0] + else: + return '(%s)' % '|'.join(regexes) + def handle_section(self, section): """Parse a section""" # if simple detection fails then discard the section @@ -198,10 +261,14 @@ matches = matches + 1 if 0 == matches: return - # not yet implemented - if self.parser.has_option(section, 'excludekey'): - print 'ERROR: ExcludeKey not implemented, section=', section - return + # excludekeys ignores a file, path, or registry key + excludekeys = [] + if self.parser.has_option(section, 'excludekey1'): + for n in range(1, MAX_DETECT): + option_id = 'excludekey%d' % n + if self.parser.has_option(section, option_id): + excludekeys.append( + self.excludekey_to_nwholeregex(self.parser.get(section, option_id))) # there are two ways to specify sections: langsecref= and section= if self.parser.has_option(section, 'langsecref'): # verify the langsecref number is known @@ -218,7 +285,7 @@ section2option(section), section.replace('*', ''), '') for option in self.parser.options(section): if option.startswith('filekey'): - self.handle_filekey(lid, section, option) + self.handle_filekey(lid, section, option, excludekeys) elif option.startswith('regkey'): self.handle_regkey(lid, section, option) elif option == 'warning': @@ -232,7 +299,7 @@ print 'WARNING: unknown option %s in section %s' % (option, section) return - def __make_file_provider(self, dirname, filename, recurse, removeself): + def __make_file_provider(self, dirname, filename, recurse, removeself, excludekeys): """Change parsed FileKey to action provider""" regex = '' if recurse: @@ -244,21 +311,31 @@ if removeself: search = 'walk.all' else: - regex = ' regex="%s" ' % (re.escape(filename) + '$') + import fnmatch + regex = ' regex="%s" ' % (fnmatch.translate(filename)) else: search = 'glob' path = os.path.join(dirname, filename) if -1 == path.find('*'): search = 'file' - action_str = ' diff -Nru bleachbit-1.10/cleaners/exaile.xml bleachbit-1.12~xenial/cleaners/exaile.xml --- bleachbit-1.10/cleaners/exaile.xml 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/cleaners/exaile.xml 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ + diff -Nru bleachbit-1.10/cleaners/google_chrome.xml bleachbit-1.12~xenial/cleaners/google_chrome.xml --- bleachbit-1.10/cleaners/google_chrome.xml 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/cleaners/google_chrome.xml 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ + @@ -122,7 +124,9 @@ + + @@ -168,7 +172,8 @@ - + + @@ -177,7 +182,8 @@ - + + diff -Nru bleachbit-1.10/cleaners/google_earth.xml bleachbit-1.12~xenial/cleaners/google_earth.xml --- bleachbit-1.10/cleaners/google_earth.xml 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/cleaners/google_earth.xml 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ + diff -Nru bleachbit-1.10/cleaners/windows_media_player.xml bleachbit-1.12~xenial/cleaners/windows_media_player.xml --- bleachbit-1.10/cleaners/windows_media_player.xml 2015-12-31 04:42:40.000000000 +0000 +++ bleachbit-1.12~xenial/cleaners/windows_media_player.xml 2016-07-01 21:01:49.000000000 +0000 @@ -2,8 +2,8 @@ - - + +