示例#1
0
def guess_overwrite_paths():
    """Guess which partitions to overwrite (to hide deleted files)"""
    # In case overwriting leaves large files, placing them in
    # ~/.config makes it easy to find them and clean them.
    ret = []
    if 'posix' == os.name:
        home = expanduser('~/.cache')
        if not os.path.exists(home):
            home = expanduser("~")
        ret.append(home)
        if not same_partition(home, '/tmp/'):
            ret.append('/tmp')
    elif 'nt' == os.name:
        localtmp = bleachbit.expandvars('$TMP')
        if not os.path.exists(localtmp):
            logger.warning('%TMP% does not exist: %s', localtmp)
            localtmp = None
        from bleachbit.Windows import get_fixed_drives
        for drive in get_fixed_drives():
            if localtmp and same_partition(localtmp, drive):
                ret.append(localtmp)
            else:
                ret.append(drive)
    else:
        NotImplementedError('Unsupported OS in guess_overwrite_paths')
    return ret
示例#2
0
 def whitelisted(self, pathname):
     """Return boolean whether file is whitelisted"""
     regexes = [
         '^/tmp/.X0-lock$',
         '^/tmp/.truecrypt_aux_mnt.*/(control|volume)$',
         '^/tmp/.vbox-[^/]+-ipc/lock$',
         '^/tmp/.wine-[0-9]+/server-.*/lock$',
         '^/tmp/gconfd-[^/]+/lock/ior$',
         '^/tmp/fsa/',  # fsarchiver
         '^/tmp/kde-',
         '^/tmp/kdesudo-',
         '^/tmp/ksocket-',
         '^/tmp/orbit-[^/]+/bonobo-activation-register[a-z0-9-]*.lock$',
         '^/tmp/orbit-[^/]+/bonobo-activation-server-[a-z0-9-]*ior$',
         '^/tmp/pulse-[^/]+/pid$',
         '^/var/tmp/kdecache-',
         '^' + expanduser('~/.cache/wallpaper/'),
         # Clean Firefox cache from Firefox cleaner (LP#1295826)
         '^' + expanduser('~/.cache/mozilla'),
         # Clean Google Chrome cache from Google Chrome cleaner (LP#656104)
         '^' + expanduser('~/.cache/google-chrome'),
         '^' + expanduser('~/.cache/gnome-control-center/'),
         # iBus Pinyin
         # https://bugs.launchpad.net/bleachbit/+bug/1538919
         '^' + expanduser('~/.cache/ibus/')]
     for regex in regexes:
         if re.match(regex, pathname) is not None:
             return True
     return False
示例#3
0
def guess_overwrite_paths():
    """Guess which partitions to overwrite (to hide deleted files)"""
    # In case overwriting leaves large files, placing them in
    # ~/.config makes it easy to find them and clean them.
    ret = []
    if 'posix' == os.name:
        home = expanduser('~/.cache')
        if not os.path.exists(home):
            home = expanduser("~")
        ret.append(home)
        if not same_partition(home, '/tmp/'):
            ret.append('/tmp')
    elif 'nt' == os.name:
        localtmp = bleachbit.expandvars('$TMP')
        if not os.path.exists(localtmp):
            logger.warning(_("%TMP% does not exist: %s"), localtmp)
            localtmp = None
        from bleachbit.Windows import get_fixed_drives
        for drive in get_fixed_drives():
            if localtmp and same_partition(localtmp, drive):
                ret.append(localtmp)
            else:
                ret.append(drive)
    else:
        NotImplementedError('Unsupported OS in guess_overwrite_paths')
    return ret
示例#4
0
 def init_whitelist(self):
     """Initialize the whitelist only once for performance"""
     regexes = [
         '^/tmp/.X0-lock$',
         '^/tmp/.truecrypt_aux_mnt.*/(control|volume)$',
         '^/tmp/.vbox-[^/]+-ipc/lock$',
         '^/tmp/.wine-[0-9]+/server-.*/lock$',
         '^/tmp/gconfd-[^/]+/lock/ior$',
         '^/tmp/fsa/',  # fsarchiver
         '^/tmp/kde-',
         '^/tmp/kdesudo-',
         '^/tmp/ksocket-',
         '^/tmp/orbit-[^/]+/bonobo-activation-register[a-z0-9-]*.lock$',
         '^/tmp/orbit-[^/]+/bonobo-activation-server-[a-z0-9-]*ior$',
         '^/tmp/pulse-[^/]+/pid$',
         '^/var/tmp/kdecache-',
         '^' + expanduser('~/.cache/wallpaper/'),
         # Flatpak mount point
         '^' + expanduser('~/.cache/doc($|/)'),
         # Clean Firefox cache from Firefox cleaner (LP#1295826)
         '^' + expanduser('~/.cache/mozilla/'),
         # Clean Google Chrome cache from Google Chrome cleaner (LP#656104)
         '^' + expanduser('~/.cache/google-chrome/'),
         '^' + expanduser('~/.cache/gnome-control-center/'),
         # Clean Evolution cache from Evolution cleaner (GitHub #249)
         '^' + expanduser('~/.cache/evolution/'),
         # iBus Pinyin
         # https://bugs.launchpad.net/bleachbit/+bug/1538919
         '^' + expanduser('~/.cache/ibus/'),
         # Linux Bluetooth daemon obexd directory is typically empty, so be careful
         # not to delete the empty directory.
         '^' + expanduser('~/.cache/obexd($|/)')
     ]
     for regex in regexes:
         self.regexes_compiled.append(re.compile(regex))
示例#5
0
    def worker_done(self, worker, really_delete):
        """Callback for when Worker is done"""
        self.progressbar.set_text("")
        self.progressbar.set_fraction(1)
        self.progressbar.set_text(_("Done."))
        self.textview.scroll_mark_onscreen(self.textbuffer.get_insert())
        self.set_sensitive(True)

        # Close the program after cleaning is completed.
        # if the option is selected under preference.

        if really_delete:
            if options.get("exit_done"):
                sys.exit()

        # notification for long-running process
        elapsed = (time.time() - self.start_time)
        logger.debug('elapsed time: %d seconds', elapsed)
        if elapsed < 10 or self.is_active():
            return
        try:
            gi.require_version('Notify', '0.7')
            from gi.repository import Notify
        except:
            logger.debug('Notify not available')
        else:
            if Notify.init(APP_NAME):
                notify = Notify.Notification.new('BleachBit', _("Done."),
                                                 'bleachbit')
                if os.name == 'posix' and bleachbit.expanduser('~') == '/root':
                    notify.set_hint("desktop-entry", "bleachbit-root")
                else:
                    notify.set_hint("desktop-entry", "bleachbit")
                notify.show()
                notify.set_timeout(10000)
示例#6
0
def browse_folder(parent, title, multiple, stock_button):
    """Ask the user to select a folder.  Return the full path or None."""

    if os.name == 'nt' and not os.getenv('BB_NATIVE'):
        ret = Windows.browse_folder(parent, title)
        return [ret] if multiple and not ret is None else ret

    # fall back to GTK+
    chooser = Gtk.FileChooserDialog(transient_for=parent,
                                    title=title,
                                    action=Gtk.FileChooserAction.SELECT_FOLDER)
    chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, stock_button,
                        Gtk.ResponseType.OK)
    chooser.set_default_response(Gtk.ResponseType.OK)
    chooser.set_select_multiple(multiple)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    if multiple:
        ret = chooser.get_filenames()
    else:
        ret = chooser.get_filename()
    chooser.hide()
    chooser.destroy()
    if Gtk.ResponseType.OK != resp:
        # user cancelled
        return None
    return ret
示例#7
0
 def test_delete(self):
     """Unit test for class Delete"""
     paths = [u'~']
     if 'nt' == os.name:
         # Python 2.6 and later supports %foo%
         paths.append(u'%USERPROFILE%')
         # Python 2.5 and later supports $foo
         paths.append(u'${USERPROFILE}')
         paths.append(u'$USERPROFILE')
     if 'posix' == os.name:
         paths.append(u'$HOME')
     for path in paths:
         for mode in ('delete', 'truncate', 'delete_forward'):
             expanded = expanduser(expandvars(path))
             filename = self.mkstemp(dir=expanded,
                                     prefix='bleachbit-action-delete')
             command = mode
             if 'delete_forward' == mode:
                 # forward slash needs to be normalized on Windows
                 if 'nt' == os.name:
                     command = 'delete'
                     filename = filename.replace('\\', '/')
                 else:
                     # test not needed on this OS
                     os.remove(filename)
                     continue
             action_str = u'<action command="%s" search="file" path="%s" />' % \
                 (command, filename)
             self._test_action_str(action_str)
             self.assertNotExists(filename)
示例#8
0
 def is_running(self):
     """Return whether the program is currently running"""
     logger = logging.getLogger(__name__)
     for running in self.running:
         test = running[0]
         pathname = running[1]
         if 'exe' == test and 'posix' == os.name:
             if Unix.is_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'pathname' == test:
             expanded = expanduser(expandvars(pathname))
             for globbed in glob.iglob(expanded):
                 if os.path.exists(globbed):
                     logger.debug(
                         "file '%s' exists indicating '%s' is running", globbed, self.name)
                     return True
         else:
             raise RuntimeError(
                 "Unknown running-detection test '%s'" % test)
     return False
示例#9
0
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        Gtk.Application.__init__(self, application_id='org.gnome.Bleachbit', flags=Gio.ApplicationFlags.FLAGS_NONE)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        GObject.threads_init()

        if shred_paths:
            self.shred_paths(shred_paths)
            return
        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."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it."))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            print('Success')
            GObject.idle_add(lambda: self.quit(), priority=GObject.PRIORITY_LOW)
示例#10
0
 def __init__(self, action_element):
     """Initialize file search"""
     self.regex = action_element.getAttribute('regex')
     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.object_type = action_element.getAttribute('type')
     self.path = expanduser(expandvars(action_element.getAttribute('path')))
     if 'nt' == os.name and self.path:
         # convert forward slash to backslash for compatibility with getsize()
         # and for display.  Do not convert an empty path, or it will become
         # the current directory (.).
         self.path = os.path.normpath(self.path)
     self.ds = {}
     if 'deep' == self.search:
         self.ds['regex'] = self.regex
         self.ds['nregex'] = self.nregex
         self.ds['cache'] = General.boolstr_to_bool(
             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
示例#11
0
 def is_running(self):
     """Return whether the program is currently running"""    # 프로그램이 현재 실행 중인지 여부를 반환하는 함수
     logger = logging.getLogger(__name__)            # __name__에서 로거 추출
     for running in self.running:           # running 리스트의 값들 반복      
         test = running[0]         # running[0] = detection_type   ( add_running 함수 참고)               
         pathname = running[1]             
         if 'exe' == test and 'posix' == os.name:  # os이름이 posix이고 exe 타입인지 확인
             if Unix.is_running(pathname): # Unix에서 is_running함수썼을때 True이면 
                 logger.debug("process '%s' is running", pathname) # 프로세스가 실행중이라는 debug 메세지를 로그하고 True반환
                 return True
         elif 'exe' == test and 'nt' == os.name: # os이름이 nt 이고 exe타입인지 확인
             if Windows.is_process_running(pathname):  # 만약 Windows에서 is_process_running 함수를 사용했을때 true이면
                 logger.debug("process '%s' is running", pathname) # 프로세스가 실행중이라는 debug 메세지를 로그하고 true반환
                 return True
         elif 'pathname' == test:                # test 
             expanded = expanduser(expandvars(pathname)) # pathname 안에 환경변수가 있으면 확장하고 현재 사용자 디렉토리의 절대경로로 대체
                                                         # ex) C:\\Documents and Settings\\Administrator\\pathname 
             for globbed in glob.iglob(expanded):  # iglob() : expanded의 모든 값을 실제로 동시에 저장하지 않고
                                                   #  glob()값과 동일한 값을 산출하는 반복기를 반환함
                 if os.path.exists(globbed): # globbed로 저장한 경로에 특정파일이 존재하는지 확인
                     logger.debug(
                         "file '%s' exists indicating '%s' is running", globbed, self.name)
                             # 존재하면 파일이 존재하며 실행중임을 나타내는 메세지출력
                     return True
         else:
             raise RuntimeError( 
                 "Unknown running-detection test '%s'" % test) # test가 exe , pathname도 아니면 알수없는 실행타입메세지와 함께 런타임에러발생
     return False
示例#12
0
    def test_children_in_directory(self):
        """Unit test for function children_in_directory()"""

        # test an existing directory that usually exists
        dirname = expanduser("~/.config")
        for filename in children_in_directory(dirname, True):
            self.assertTrue(os.path.isabs(filename))
        for filename in children_in_directory(dirname, False):
            self.assertTrue(os.path.isabs(filename))
            self.assertFalse(os.path.isdir(filename))

        # test a constructed file in a constructed directory
        dirname = self.mkdtemp(prefix='bleachbit-test-children')
        filename = self.mkstemp(prefix="somefile", dir=dirname)
        for loopfilename in children_in_directory(dirname, True):
            self.assertEqual(loopfilename, filename)
        for loopfilename in children_in_directory(dirname, False):
            self.assertEqual(loopfilename, filename)
        os.remove(filename)

        # test subdirectory
        subdirname = os.path.join(dirname, "subdir")
        os.mkdir(subdirname)
        for filename in children_in_directory(dirname, True):
            self.assertEqual(filename, subdirname)
        for filename in children_in_directory(dirname, False):
            raise AssertionError('Found a file that shouldn\'t have been found: ' + filename)
        os.rmdir(subdirname)

        os.rmdir(dirname)
示例#13
0
 def test_listdir(self):
     """Unit test for listdir()"""
     if 'posix' == os.name:
         dir1 = '/tmp'
         dir2 = expanduser('~/.config')
     if 'nt' == os.name:
         dir1 = expandvars(r'%windir%\fonts')
         dir2 = expandvars(r'%userprofile%\desktop')
     # If these directories do not exist, the test results are not valid.
     self.assertExists(dir1)
     self.assertExists(dir2)
     # Every path found in dir1 and dir2 should be found in (dir1, dir2).
     paths1 = set(listdir(dir1))
     paths2 = set(listdir(dir2))
     paths12 = set(listdir((dir1,dir2)))
     self.assertTrue(paths1 < paths12)
     self.assertTrue(paths2 < paths12)
     # The individual calls should be equivalent to a combined call.
     self.assertSetEqual(paths1.union(paths2), paths12)
     # The directories should not be empty.
     self.assertGreater(len(paths1), 0)
     self.assertGreater(len(paths2), 0)
     # Every path found should exist.
     for pathname in paths12:
         self.assertLExists(pathname)
示例#14
0
    def test_children_in_directory(self):
        """Unit test for function children_in_directory()"""

        # test an existing directory that usually exists
        dirname = expanduser("~/.config")
        for filename in children_in_directory(dirname, True):
            self.assertTrue(os.path.isabs(filename))
        for filename in children_in_directory(dirname, False):
            self.assertTrue(os.path.isabs(filename))
            self.assertFalse(os.path.isdir(filename))

        # test a constructed file in a constructed directory
        dirname = self.mkdtemp(prefix='bleachbit-test-children')
        filename = self.mkstemp(prefix="somefile", dir=dirname)
        for loopfilename in children_in_directory(dirname, True):
            self.assertEqual(loopfilename, filename)
        for loopfilename in children_in_directory(dirname, False):
            self.assertEqual(loopfilename, filename)
        os.remove(filename)

        # test subdirectory
        subdirname = os.path.join(dirname, "subdir")
        os.mkdir(subdirname)
        for filename in children_in_directory(dirname, True):
            self.assertEqual(filename, subdirname)
        for filename in children_in_directory(dirname, False):
            raise AssertionError('Found a file that shouldn\'t have been found: ' + filename)
        os.rmdir(subdirname)

        os.rmdir(dirname)
示例#15
0
    def test_free_space(self):
        """Unit test for free_space()"""
        home = expanduser('~')
        result = free_space(home)
        self.assertNotEqual(result, None)
        self.assertGreater(result, -1)
        self.assertIsInteger(result)

        # compare to WMIC
        if 'nt' != os.name:
            return
        args = ['wmic',  'LogicalDisk', 'get', 'DeviceID,', 'FreeSpace']
        from bleachbit.General import run_external
        (rc, stdout, stderr) = run_external(args)
        if rc:
            print('error calling WMIC\nargs=%s\nstderr=%s' % (args, stderr))
            return
        import re
        for line in stdout.split('\n'):
            line = line.strip()
            if not re.match('([A-Z]):\s+(\d+)', line):
                continue
            drive, bytes_free = re.split('\s+', line)
            print('Checking free space for %s' % drive)
            bytes_free = int(bytes_free)
            free = free_space(unicode(drive))
            self.assertEqual(bytes_free, free)
示例#16
0
def browse_folder(parent, title, multiple, stock_button):
    """Ask the user to select a folder.  Return the full path or None."""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        ret = Windows.browse_folder(parent.window.handle if parent else None,
                                    title)
        return [ret] if multiple and not ret is None else ret

    # fall back to GTK+
    chooser = gtk.FileChooserDialog(
        parent=parent,
        title=title,
        buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, stock_button,
                 gtk.RESPONSE_OK),
        action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
    chooser.set_select_multiple(multiple)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    if multiple:
        ret = chooser.get_filenames()
    else:
        ret = chooser.get_filename()
    chooser.hide()
    chooser.destroy()
    if gtk.RESPONSE_OK != resp:
        # user cancelled
        return None
    return ret
示例#17
0
 def test_listdir(self):
     """Unit test for listdir()"""
     if 'posix' == os.name:
         dir1 = '/tmp'
         dir2 = expanduser('~/.config')
     if 'nt' == os.name:
         dir1 = expandvars(r'%windir%\fonts')
         dir2 = expandvars(r'%userprofile%\desktop')
     # If these directories do not exist, the test results are not valid.
     self.assertExists(dir1)
     self.assertExists(dir2)
     # Every path found in dir1 and dir2 should be found in (dir1, dir2).
     paths1 = set(listdir(dir1))
     paths2 = set(listdir(dir2))
     paths12 = set(listdir((dir1,dir2)))
     self.assertTrue(paths1 < paths12)
     self.assertTrue(paths2 < paths12)
     # The individual calls should be equivalent to a combined call.
     self.assertSetEqual(paths1.union(paths2), paths12)
     # The directories should not be empty.
     self.assertGreater(len(paths1), 0)
     self.assertGreater(len(paths2), 0)
     # Every path found should exist.
     for pathname in paths12:
         self.assertLExists(pathname)
示例#18
0
def expand_glob_join(pathname1, pathname2):
    """Join pathname1 and pathname1, expand pathname, glob, and return as list"""
    ret = []
    pathname3 = expanduser(bleachbit.expandvars(os.path.join(pathname1, pathname2)))
    for pathname4 in glob.iglob(pathname3):
        ret.append(pathname4)
    return ret
示例#19
0
文件: GuiBasic.py 项目: az0/bleachbit
def browse_folder(parent, title, multiple, stock_button):
    """Ask the user to select a folder.  Return the full path or None."""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        ret = Windows.browse_folder(
            parent.window.handle if parent else None, title)
        return [ret] if multiple and not ret is None else ret

    # fall back to GTK+
    chooser = Gtk.FileChooserDialog(transient_for=parent,
                                    title=title,
                                    action = Gtk.FileChooserAction.SELECT_FOLDER)
    chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, stock_button, Gtk.ResponseType.OK)
    chooser.set_default_response(Gtk.ResponseType.OK)
    chooser.set_select_multiple(multiple)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    if multiple:
        ret = chooser.get_filenames()
    else:
        ret = chooser.get_filename()
    chooser.hide()
    chooser.destroy()
    if Gtk.ResponseType.OK != resp:
        # user cancelled
        return None
    return ret
示例#20
0
文件: GUI.py 项目: tstenner/bleachbit
    def worker_done(self, worker, really_delete):
        """Callback for when Worker is done"""
        self.progressbar.set_text("")
        self.progressbar.set_fraction(1)
        self.progressbar.set_text(_("Done."))
        self.textview.scroll_mark_onscreen(self.textbuffer.get_insert())
        self.set_sensitive(True)

        # Close the program after cleaning is completed.
        # if the option is selected under preference.

        if really_delete:
            if options.get("exit_done"):
                sys.exit()

        # notification for long-running process
        elapsed = (time.time() - self.start_time)
        logger.debug('elapsed time: %d seconds', elapsed)
        if elapsed < 10 or self.window.is_active():
            return
        try:
            import pynotify
        except ImportError:
            logger.debug('pynotify not available')
        else:
            if pynotify.init(APP_NAME):
                notify = pynotify.Notification('BleachBit', _("Done."),
                                               icon='bleachbit')
                if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
                    notify.set_hint("desktop-entry", "bleachbit-root")
                else:
                    notify.set_hint("desktop-entry", "bleachbit")
                notify.show()
                notify.set_timeout(10000)
示例#21
0
 def is_running(self):
     """Return whether the program is currently running"""
     logger = logging.getLogger(__name__)
     for running in self.running:
         test = running[0]
         pathname = running[1]
         if 'exe' == test and 'posix' == os.name:
             if Unix.is_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'pathname' == test:
             expanded = expanduser(expandvars(pathname))
             for globbed in glob.iglob(expanded):
                 if os.path.exists(globbed):
                     logger.debug(
                         "file '%s' exists indicating '%s' is running",
                         globbed, self.name)
                     return True
         else:
             raise RuntimeError("Unknown running-detection test '%s'" %
                                test)
     return False
示例#22
0
    def test_free_space(self):
        """Unit test for free_space()"""
        home = expanduser('~')
        result = free_space(home)
        self.assertNotEqual(result, None)
        self.assertGreater(result, -1)
        self.assertIsInteger(result)

        # compare to WMIC
        if 'nt' != os.name:
            return
        args = ['wmic',  'LogicalDisk', 'get', 'DeviceID,', 'FreeSpace']
        from bleachbit.General import run_external
        (rc, stdout, stderr) = run_external(args)
        if rc:
            print('error calling WMIC\nargs=%s\nstderr=%s' % (args, stderr))
            return
        import re
        for line in stdout.split('\n'):
            line = line.strip()
            if not re.match('([A-Z]):\s+(\d+)', line):
                continue
            drive, bytes_free = re.split('\s+', line)
            print('Checking free space for %s' % drive)
            bytes_free = int(bytes_free)
            free = free_space(unicode(drive))
            self.assertEqual(bytes_free, free)
示例#23
0
def browse_folder(parent, title, multiple, stock_button):
    """Ask the user to select a folder.  Return the full path or None."""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        ret = Windows.browse_folder(
            parent.window.handle if parent else None, title)
        return [ret] if multiple and not ret is None else ret

    # fall back to GTK+
    chooser = gtk.FileChooserDialog(parent=parent,
                                    title=title,
                                    buttons=(
                                        gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        stock_button, gtk.RESPONSE_OK),
                                    action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
    chooser.set_select_multiple(multiple)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    if multiple:
        ret = chooser.get_filenames()
    else:
        ret = chooser.get_filename()
    chooser.hide()
    chooser.destroy()
    if gtk.RESPONSE_OK != resp:
        # user cancelled
        return None
    return ret
示例#24
0
def expand_glob_join(pathname1, pathname2):
    """Join pathname1 and pathname1, expand pathname, glob, and return as list"""
    ret = []
    pathname3 = expanduser(bleachbit.expandvars(os.path.join(pathname1, pathname2)))
    for pathname4 in glob.iglob(pathname3):
        ret.append(pathname4)
    return ret
示例#25
0
 def test_delete(self):
     """Unit test for class Delete"""
     paths = [u'~']
     if 'nt' == os.name:
         # Python 2.6 and later supports %foo%
         paths.append(u'%USERPROFILE%')
         # Python 2.5 and later supports $foo
         paths.append(u'${USERPROFILE}')
         paths.append(u'$USERPROFILE')
     if 'posix' == os.name:
         paths.append(u'$HOME')
     for path in paths:
         for mode in ('delete', 'truncate', 'delete_forward'):
             expanded = expanduser(expandvars(path))
             filename = self.mkstemp(dir=expanded, prefix='bleachbit-action-delete')
             command = mode
             if 'delete_forward' == mode:
                 # forward slash needs to be normalized on Windows
                 if 'nt' == os.name:
                     command = 'delete'
                     filename = filename.replace('\\', '/')
                 else:
                     # test not needed on this OS
                     os.remove(filename)
                     continue
             action_str = u'<action command="%s" search="file" path="%s" />' % \
                 (command, filename)
             self._test_action_str(action_str)
             self.assertNotExists(filename)
示例#26
0
 def is_running(self):
     """Return whether the program is currently running"""
     resp_cli=""
     logger = logging.getLogger(__name__)
     for running in self.running:
         test = running[0]
         pathname = running[1]
         if 'exe' == test and 'posix' == os.name:
             if Unix.is_running(pathname):
                 #print "debug: process '%s' is running" % pathname
                 logger.debug("Debug: process '%s' is running", pathname)
                 if options.get("close_run"):
                     if not subprocess.mswindows:
                         #print "debug: Closing process '%s'" % pathname
                         if "--preset" in sys.argv:
                             resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ")
                         else:
                             resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO)
                         if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y":
                         # user cancelled, so don't toggle option
                             logger.debug("Debug: Closing process '%s'",pathname)
                             subprocess.check_output(["killall", "-9", pathname])
                         if not Unix.is_running(pathname):
                             logger.debug("Debug: Closing process '%s' successful",pathname)
                             return False
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 #print "debug: process '%s' is running" % pathname
                 logger.debug("Debug: process '%s' is running", pathname)
                 if options.get("close_run"):
                     if subprocess.mswindows:
                         #print "debug: Closing process '%s'" % pathname
                         if "--preset" in sys.argv:
                             resp_cli = raw_input("Do you Want BleachBit to Close " + pathname + " y/n : ")
                         else:
                             resp = GuiBasic.message_dialog(None,"Do you Want BleachBit to Close " + pathname,gtk.MESSAGE_WARNING, gtk.BUTTONS_YES_NO)
                         if gtk.RESPONSE_YES == resp or resp_cli.lower() == "y":
                             logger.debug("debug: Closing process '%s'",pathname)
                             subprocess.check_output(["taskkill", "/IM", pathname])
                         if not Windows.is_process_running(pathname):
                             logger.debug("debug: Closing process '%s' successful",pathname)
                             return False
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'exe' == test and 'nt' == os.name:
             if Windows.is_process_running(pathname):
                 logger.debug("process '%s' is running", pathname)
                 return True
         elif 'pathname' == test:
             expanded = expanduser(expandvars(pathname))
             for globbed in glob.iglob(expanded):
                 if os.path.exists(globbed):
                     logger.debug("file '%s' exists indicating '%s' is running", self.name)
                     return True
         else:
             raise RuntimeError(
                 "Unknown running-detection test '%s'" % test)
     return False
示例#27
0
def diagnostic_info():
    """Return diagnostic information as a string"""
    s = "BleachBit version %s" % bleachbit.APP_VERSION
    try:
        import gtk
        s += '\nGTK version %s' % '.'.join([str(x) for x in gtk.gtk_version])
    except:
        pass
    s += "\nlocal_cleaners_dir = %s" % bleachbit.local_cleaners_dir
    s += "\nlocale_dir = %s" % bleachbit.locale_dir
    s += "\noptions_dir = %s" % bleachbit.options_dir.decode(bleachbit.FSE)
    s += "\npersonal_cleaners_dir = %s" % bleachbit.personal_cleaners_dir.decode(bleachbit.FSE)
    s += "\nsystem_cleaners_dir = %s" % bleachbit.system_cleaners_dir
    s += "\nlocale.getdefaultlocale = %s" % str(locale.getdefaultlocale())
    if 'posix' == os.name:
        envs = ('DESKTOP_SESSION', 'LOGNAME', 'USER', 'SUDO_UID')
    if 'nt' == os.name:
        envs = ('APPDATA', 'LocalAppData', 'LocalAppDataLow', 'Music',
                'USERPROFILE', 'ProgramFiles', 'ProgramW6432', 'TMP')
    for env in envs:
        if os.getenv(env):
            s += "\nos.getenv('%s') = %s" % (env, os.getenv(env).decode(bleachbit.FSE))
        else:
            s += "\nos.getenv('%s') = %s" % (env, os.getenv(env))
    s += "\nos.path.expanduser('~') = %s" % bleachbit.expanduser('~').decode(bleachbit.FSE)
    if sys.platform.startswith('linux'):
        if hasattr(platform, 'linux_distribution'):
            s += "\nplatform.linux_distribution() = %s" % str(
                platform.linux_distribution())
        else:
            s += "\nplatform.dist() = %s" % str(platform.dist())
            
    # Mac Version Name - Dictonary "masosx_dict"
    macosx_dict = {'5':'Lepoard','6':'Snow Lepoard','7':'Lion','8':'Mountain Lion','9':'Mavericks','10':'Yosemite','11':'El Capitan','12':'Sierra'}

    if sys.platform.startswith('darwin'):
        if hasattr(platform, 'mac_ver'):
            for key in macosx_dict:
                if (platform.mac_ver()[0].split('.')[1] == key):
                    s += "\nplatform.mac_ver() = %s" % str(
                        platform.mac_ver()[0] + " (" + macosx_dict[key] + ")")
        else:
            s += "\nplatform.dist() = %s" % str(platform.dist())

    if 'nt' == os.name:
        s += "\nplatform.win32_ver[1]() = %s" % platform.win32_ver()[1]
    s += "\nplatform.platform = %s" % platform.platform()
    s += "\nplatform.version = %s" % platform.version()
    s += "\nsys.argv = %s" % sys.argv
    s += "\nsys.executable = %s" % sys.executable
    s += "\nsys.version = %s" % sys.version
    if 'nt' == os.name:
        s += "\nwin32com.shell.shell.IsUserAnAdmin() = %s" % shell.IsUserAnAdmin(
        )
    s += "\n__file__ = %s" % __file__

    return s
示例#28
0
文件: GUI.py 项目: petrohs/bleachbit
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        self.create_window()
        gobject.threads_init()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None):
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)
        if shred_paths:
            self.shred_paths(shred_paths)
            return
        if options.get("first_start") and 'posix' == os.name:
            pref = PreferencesDialog(self.window, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if bleachbit.online_update_notification_enabled and options.get(
                "check_online_updates"):
            self.check_online_updates()
        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."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."
                      ))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'
                  ))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'
                      ))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            gobject.idle_add(lambda: gtk.main_quit(),
                             priority=gobject.PRIORITY_LOW)
示例#29
0
    def clean_operation(self, operation):
        """Perform a single cleaning operation"""
        operation_options = self.operations[operation]
        assert (isinstance(operation_options, list))
        logger.debug("clean_operation('%s'), options = '%s'", operation,
                     operation_options)

        if not operation_options:
            raise StopIteration

        if self.really_delete and backends[operation].is_running():
            # TRANSLATORS: %s expands to a name such as 'Firefox' or 'System'.
            # TRANSLATORs: %s은(는) 'Firefox' 또는 'System'과 같은 이름으로 확장
            err = _("%s cannot be cleaned because it is currently running.  Close it, and try again.") \
                % backends[operation].get_name()
            self.ui.append_text(err + "\n", 'error')
            self.total_errors += 1
            return
        import time
        self.yield_time = time.time()

        total_size = 0
        for option_id in operation_options:
            self.size = 0
            assert (isinstance(option_id, (str, unicode)))
            # normal scan
            for cmd in backends[operation].get_commands(option_id):
                for ret in self.execute(cmd, '%s.%s' % (operation, option_id)):
                    if True == ret:
                        # Return control to PyGTK idle loop to keep
                        # it responding allow the user to abort
                        # PyGTK 유휴 루프에 컨트롤을 되돌려 보관
                        # 응답 중 사용자가 중단하도록 허용
                        self.yield_time = time.time()
                        yield True
                if time.time() - self.yield_time > 0.25:
                    if self.really_delete:
                        self.ui.update_total_size(self.total_bytes)
                    yield True
                    self.yield_time = time.time()

            self.ui.update_item_size(operation, option_id, self.size)
            total_size += self.size

            # deep scan
            # deep scan
            for ds in backends[operation].get_deep_scan(option_id):
                if '' == ds['path']:
                    ds['path'] = expanduser('~')
                if 'delete' != ds['command']:
                    raise NotImplementedError(
                        'Deep scan only supports deleting now')
                if ds['path'] not in self.deepscans:
                    self.deepscans[ds['path']] = []
                self.deepscans[ds['path']].append(ds)
        self.ui.update_item_size(operation, -1, total_size)
示例#30
0
    def __init__(self, auto_exit, *args, **kwargs):
        super(GUI, self).__init__(*args, **kwargs)

        self.auto_exit = auto_exit

        self.set_wmclass(APP_NAME, APP_NAME)
        self.populate_window()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if os.name == 'nt' and getattr(sys, 'frozen', None) == 'windows_exe':
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)

        Gtk.Settings.get_default().set_property(
            'gtk-application-prefer-dark-theme', options.get('dark_mode'))

        if options.is_corrupt():
            logger.error(
                _('Resetting the configuration file because it is corrupt: %s')
                % bleachbit.options_file)
            bleachbit.Options.init_configuration()

        if options.get("first_start") and os.name == 'posix' and not auto_exit:
            pref = PreferencesDialog(self, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if os.name == 'nt':
            # 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
            try:
                import sqlite3
            except ImportError as e:
                self.append_text(
                    _("Error loading the SQLite module: the antivirus software may be blocking it."
                      ), 'error')

        if os.name == 'posix' and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'
                  ))
        if os.name == 'nt' and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'
                      ))
                self.append_text('\n')

        GLib.idle_add(self.cb_refresh_operations)
示例#31
0
 def test_same_partition(self):
     """Unit test for same_partition()"""
     home = expanduser('~')
     self.assertTrue(same_partition(home, home))
     if 'posix' == os.name:
         self.assertFalse(same_partition(home, '/dev'))
     if 'nt' == os.name:
         home_drive = os.path.splitdrive(home)[0]
         from bleachbit.Windows import get_fixed_drives
         for drive in get_fixed_drives():
             this_drive = os.path.splitdrive(drive)[0]
             self.assertEqual(same_partition(home, drive), home_drive == this_drive)
示例#32
0
 def _set_paths(self, raw_path, path_vars):
     """Set the list of paths to work on"""
     self.paths = []
     # expand special $$foo$$ which may give multiple values
     for path2 in expand_multi_var(raw_path, path_vars):
         path3 = expanduser(expandvars(path2))
         if os.name == 'nt' and path3:
             # convert forward slash to backslash for compatibility with getsize()
             # and for display.  Do not convert an empty path, or it will become
             # the current directory (.).
             path3 = os.path.normpath(path3)
         self.paths.append(path3)
示例#33
0
 def _set_paths(self, raw_path, path_vars):
     """Set the list of paths to work on"""
     self.paths = []
     # expand special $$foo$$ which may give multiple values
     for path2 in expand_multi_var(raw_path, path_vars):
         path3 = expanduser(expandvars(path2))
         if os.name == 'nt' and path3:
             # convert forward slash to backslash for compatibility with getsize()
             # and for display.  Do not convert an empty path, or it will become
             # the current directory (.).
             path3 = os.path.normpath(path3)
         self.paths.append(path3)
示例#34
0
 def test_same_partition(self):
     """Unit test for same_partition()"""
     home = expanduser('~')
     self.assertTrue(same_partition(home, home))
     if 'posix' == os.name:
         self.assertFalse(same_partition(home, '/dev'))
     if 'nt' == os.name:
         home_drive = os.path.splitdrive(home)[0]
         from bleachbit.Windows import get_fixed_drives
         for drive in get_fixed_drives():
             this_drive = os.path.splitdrive(drive)[0]
             self.assertEqual(same_partition(home, drive), home_drive == this_drive)
示例#35
0
 def init_whitelist(self):
     """Initialize the whitelist only once for performance
        성능을 위해 한 번만 화이트리스트 초기화 """
     regexes = [
         '^/tmp/.X0-lock$',
         '^/tmp/.truecrypt_aux_mnt.*/(control|volume)$',
         '^/tmp/.vbox-[^/]+-ipc/lock$',
         '^/tmp/.wine-[0-9]+/server-.*/lock$',
         '^/tmp/gconfd-[^/]+/lock/ior$',
         '^/tmp/fsa/',  # fsarchiver
         '^/tmp/kde-',
         '^/tmp/kdesudo-',
         '^/tmp/ksocket-',
         '^/tmp/orbit-[^/]+/bonobo-activation-register[a-z0-9-]*.lock$',
         '^/tmp/orbit-[^/]+/bonobo-activation-server-[a-z0-9-]*ior$',
         '^/tmp/pulse-[^/]+/pid$',
         '^/var/tmp/kdecache-',
         '^' + expanduser('~/.cache/wallpaper/'), # ~을 사용자 디렉토리로 대체하여 ^에 추가 
         # Clean Firefox cache from Firefox cleaner (LP#1295826)
         '^' + expanduser('~/.cache/mozilla'), # ~을 사용자 디렉토리로 대체하여 ^에 추가 
         # Clean Google Chrome cache from Google Chrome cleaner (LP#656104)
         '^' + expanduser('~/.cache/google-chrome'), # ~을 사용자 디렉토리로 대체하여 ^에 추가  
         '^' + expanduser('~/.cache/gnome-control-center/'), # ~을 사용자 디렉토리로 대체하여 ^에 추가  
         # iBus Pinyin
         # https://bugs.launchpad.net/bleachbit/+bug/1538919
         '^' + expanduser('~/.cache/ibus/'), # ~을 사용자 디렉토리로 대체하여 ^에 추가  
         # Linux Bluetooth daemon obexd
         '^' + expanduser('~/.cache/obexd/')] # ~을 사용자 디렉토리로 대체하여 ^에 추가  
     for regex in regexes:
         self.regexes_compiled.append(re.compile(regex)) # regexes_compiled 리스트에 컴파일한 regexes요소들을 추가
示例#36
0
 def init_whitelist(self):
     """Initialize the whitelist only once for performance"""
     regexes = [
         '^/tmp/.X0-lock$',
         '^/tmp/.truecrypt_aux_mnt.*/(control|volume)$',
         '^/tmp/.vbox-[^/]+-ipc/lock$',
         '^/tmp/.wine-[0-9]+/server-.*/lock$',
         '^/tmp/gconfd-[^/]+/lock/ior$',
         '^/tmp/fsa/',  # fsarchiver
         '^/tmp/kde-',
         '^/tmp/kdesudo-',
         '^/tmp/ksocket-',
         '^/tmp/orbit-[^/]+/bonobo-activation-register[a-z0-9-]*.lock$',
         '^/tmp/orbit-[^/]+/bonobo-activation-server-[a-z0-9-]*ior$',
         '^/tmp/pulse-[^/]+/pid$',
         '^/var/tmp/kdecache-',
         '^' + expanduser('~/.cache/wallpaper/'),
         # Clean Firefox cache from Firefox cleaner (LP#1295826)
         '^' + expanduser('~/.cache/mozilla'),
         # Clean Google Chrome cache from Google Chrome cleaner (LP#656104)
         '^' + expanduser('~/.cache/google-chrome'),
         '^' + expanduser('~/.cache/gnome-control-center/'),
         # iBus Pinyin
         # https://bugs.launchpad.net/bleachbit/+bug/1538919
         '^' + expanduser('~/.cache/ibus/'),
         # Linux Bluetooth daemon obexd
         '^' + expanduser('~/.cache/obexd/')]
     for regex in regexes:
         self.regexes_compiled.append(re.compile(regex))
示例#37
0
    def clean_operation(self, operation):
        """Perform a single cleaning operation"""
        operation_options = self.operations[operation]
        assert(isinstance(operation_options, list))
        logger.debug("clean_operation('%s'), options = '%s'",
                     operation, operation_options)

        if not operation_options:
            raise StopIteration

        if self.really_delete and backends[operation].is_running():
            # TRANSLATORS: %s expands to a name such as 'Firefox' or 'System'.
            err = _("%s cannot be cleaned because it is currently running.  Close it, and try again.") \
                % backends[operation].get_name()
            self.ui.append_text(err + "\n", 'error')
            self.total_errors += 1
            return
        import time
        self.yield_time = time.time()

        total_size = 0
        for option_id in operation_options:
            self.size = 0
            assert(isinstance(option_id, (str, unicode)))
            # normal scan
            for cmd in backends[operation].get_commands(option_id):
                for ret in self.execute(cmd, '%s.%s' % (operation, option_id)):
                    if True == ret:
                        # Return control to PyGTK idle loop to keep
                        # it responding allow the user to abort
                        self.yield_time = time.time()
                        yield True
                if time.time() - self.yield_time > 0.25:
                    if self.really_delete:
                        self.ui.update_total_size(self.total_bytes)
                    yield True
                    self.yield_time = time.time()

            self.ui.update_item_size(operation, option_id, self.size)
            total_size += self.size

            # deep scan
            for ds in backends[operation].get_deep_scan(option_id):
                if '' == ds['path']:
                    ds['path'] = expanduser('~')
                if 'delete' != ds['command']:
                    raise NotImplementedError(
                        'Deep scan only supports deleting now')
                if ds['path'] not in self.deepscans:
                    self.deepscans[ds['path']] = []
                self.deepscans[ds['path']].append(ds)
        self.ui.update_item_size(operation, -1, total_size)
示例#38
0
文件: GUI.py 项目: tstenner/bleachbit
    def __init__(self, uac=True, shred_paths=None, exit=False):
        if uac and 'nt' == os.name and Windows.elevate_privileges():
            # privileges escalated in other process
            sys.exit(0)
        if not exit:
            from bleachbit import RecognizeCleanerML
            RecognizeCleanerML.RecognizeCleanerML()
            register_cleaners()
        self.create_window()
        gobject.threads_init()

        # Redirect logging to the GUI.
        bb_logger = logging.getLogger('bleachbit')
        gtklog = GtkLoggerHandler(self.append_text)
        bb_logger.addHandler(gtklog)
        if 'nt' == os.name and 'windows_exe' == getattr(sys, 'frozen', None):
            # On Microsoft Windows this avoids py2exe redirecting stderr to
            # bleachbit.exe.log.
            # sys.frozen = console_exe means the console is shown
            from bleachbit import logger_sh
            bb_logger.removeHandler(logger_sh)
        if shred_paths:
            self.shred_paths(shred_paths)
            return
        if options.get("first_start") and 'posix' == os.name:
            pref = PreferencesDialog(self.window, self.cb_refresh_operations)
            pref.run()
            options.set('first_start', False)
        if bleachbit.online_update_notification_enabled and options.get("check_online_updates"):
            self.check_online_updates()
        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."
            # https://www.bleachbit.org/forum/074-fails-errors
            try:
                import sqlite3
            except ImportError:
                logger.exception(_("Error loading the SQLite module: the antivirus software may be blocking it."))
        if 'posix' == os.name and bleachbit.expanduser('~') == '/root':
            self.append_text(
                _('You are running BleachBit with administrative privileges for cleaning shared parts of the system, and references to the user profile folder will clean only the root account.'))
        if 'nt' == os.name and options.get('shred'):
            from win32com.shell.shell import IsUserAnAdmin
            if not IsUserAnAdmin():
                self.append_text(
                    _('Run BleachBit with administrator privileges to improve the accuracy of overwriting the contents of files.'))
                self.append_text('\n')
        if exit:
            # This is used for automated testing of whether the GUI can start.
            gobject.idle_add(
                lambda: gtk.main_quit(), priority=gobject.PRIORITY_LOW)
示例#39
0
 def test_DeepScan(self):
     """Unit test for class DeepScan.  Preview real files."""
     ds = DeepScan()
     path = expanduser('~')
     ds.add_search(path, '^Makefile$')
     ds.add_search(path, '~$')
     ds.add_search(path, 'bak$')
     ds.add_search(path, '^Thumbs.db$')
     ds.add_search(path, '^Thumbs.db:encryptable$')
     for ret in ds.scan():
         if True == ret:
             # it's yielding control to the GTK idle loop
             continue
         self.assertLExists(ret)
示例#40
0
 def test_DeepScan(self):
     """Unit test for class DeepScan.  Preview real files."""
     ds = DeepScan()
     path = expanduser('~')
     ds.add_search(path, '^Makefile$')
     ds.add_search(path, '~$')
     ds.add_search(path, 'bak$')
     ds.add_search(path, '^Thumbs.db$')
     ds.add_search(path, '^Thumbs.db:encryptable$')
     for ret in ds.scan():
         if True == ret:
             # it's yielding control to the GTK idle loop
             continue
         self.assertLExists(ret)
示例#41
0
    def test_expanduser(self):
        """Unit test for function expanduser()"""
        # already absolute
        test_input = '/home/user/foo'
        test_output = expanduser(test_input)
        self.assertEqual(test_input, test_output)

        # tilde not at beginning
        test_input = '/home/user/~'
        test_output = expanduser(test_input)
        self.assertEqual(test_input, test_output)

        # should be expanded
        if os.name == 'nt':
            test_inputs = ('~', r'~\ntuser.dat')
        if os.name == 'posix':
            test_inputs = ('~', '~/.profile')
        for test_input in test_inputs:
            test_output = expanduser(test_input)
            self.assertNotEqual(test_input, test_output)
            self.assertExists(test_output)
            if os.name == 'posix':
                self.assert_(os.path.samefile(
                    test_output, os.path.expanduser(test_input)))
示例#42
0
def listdir(directory):
    """Return full path of files in directory.

    Path may be a tuple of directories."""

    if type(directory) is tuple:
        for dirname in directory:
            for pathname in listdir(dirname):
                yield pathname
        return
    dirname = expanduser(directory)
    if not os.path.lexists(dirname):
        return
    for filename in os.listdir(dirname):
        yield os.path.join(dirname, filename)
示例#43
0
def listdir(directory):
    """Return full path of files in directory.

    Path may be a tuple of directories."""

    if type(directory) is tuple:
        for dirname in directory:
            for pathname in listdir(dirname):
                yield pathname
        return
    dirname = expanduser(directory)
    if not os.path.lexists(dirname):
        return
    for filename in os.listdir(dirname):
        yield os.path.join(dirname, filename)
示例#44
0
 def test_DeepScan(self):
     """Unit test for class DeepScan.  Preview real files."""
     ds = DeepScan()
     path = expanduser('~')
     ds.add_search(path, '^Makefile$')
     ds.add_search(path, '~$')
     ds.add_search(path, 'bak$')
     ds.add_search(path, '^Thumbs.db$')
     ds.add_search(path, '^Thumbs.db:encryptable$')
     try:
         for ret in ds.scan():
             if True == ret:
                 # it's yielding control to the GTK idle loop
                 continue
             self.assertLExists(ret)
     except UnicodeDecodeError:
         # Expectedly ds.scan() throws exception
         # when we have unicode paths and LANG==C.
         self.assertTrue(os.environ['LANG'] == 'C')
示例#45
0
def browse_file(parent, title):
    """Prompt user to select a single file"""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        return Windows.browse_file(parent.window.handle, title)

    chooser = gtk.FileChooserDialog(title=title,
                                    parent=parent,
                                    action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                    buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    path = chooser.get_filename()
    chooser.destroy()

    if gtk.RESPONSE_OK != resp:
        # user cancelled
        return None

    return path
示例#46
0
文件: GuiBasic.py 项目: az0/bleachbit
def browse_file(parent, title):
    """Prompt user to select a single file"""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        return Windows.browse_file(parent.window.handle, title)

    chooser = Gtk.FileChooserDialog(title=title,
                                    transient_for=parent,
                                    action=Gtk.FileChooserAction.OPEN)
    chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.OK)
    chooser.set_default_response(Gtk.ResponseType.OK)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    path = chooser.get_filename()
    chooser.destroy()

    if Gtk.ResponseType.OK != resp:
        # user cancelled
        return None

    return path
示例#47
0
 def test_whitelist(self):
     tests = [
         ('/tmp/.truecrypt_aux_mnt1/control', True),
         ('/tmp/.truecrypt_aux_mnt1/volume', True),
         ('/tmp/.vbox-foo-ipc/lock', True),
         ('/tmp/.wine-500/server-806-102400f/lock', True),
         ('/tmp/gconfd-foo/lock/ior', True),
         ('/tmp/ksocket-foo/Arts_SoundServerV2', True),
         ('/tmp/ksocket-foo/secret-cookie', True),
         ('/tmp/orbit-foo/bonobo-activation-server-ior', True),
         ('/tmp/orbit-foo/bonobo-activation-register.lock', True),
         ('/tmp/orbit-foo/bonobo-activation-server-a9cd6cc4973af098918b154c4957a93f-ior',
          True),
         ('/tmp/orbit-foo/bonobo-activation-register-a9cd6cc4973af098918b154c4957a93f.lock',
          True), ('/tmp/pulse-foo/pid', True), ('/tmp/tmpsDOBFd', False),
         (os.path.expanduser('~/.cache/obexd'), True),
         (os.path.expanduser('~/.cache/obexd/'), True),
         (os.path.expanduser('~/.cache/obexd/foo'), True),
         (os.path.expanduser('~/.cache/obex'), False),
         (os.path.expanduser('~/.cache/obexd-foo'), False)
     ]
     list(register_cleaners())
     for test in tests:
         self.assertEqual(backends['system'].whitelisted(test[0]), test[1],
                          test[0])
     # Make sure directory ~/.cache/obexd is ignored
     # https://github.com/bleachbit/bleachbit/issues/572
     from bleachbit import expanduser
     obexd_dir = expanduser('~/.cache/obexd')
     if not os.path.exists(obexd_dir):
         os.makedirs(obexd_dir)
     obexd_fn = os.path.join(obexd_dir, 'bleachbit-test')
     common.touch_file(obexd_fn)
     found_canary = False
     for cmd in backends['system'].get_commands('cache'):
         for result in cmd.execute(really_delete=False):
             self.assertNotEqual(cmd.path, obexd_fn)
             self.assertFalse('/.cache/obexd/' in cmd.path)
     from bleachbit.FileUtilities import delete
     delete(obexd_fn, ignore_missing=True)
示例#48
0
def browse_file(parent, title):
    """Prompt user to select a single file"""

    if os.name == 'nt' and not os.getenv('BB_NATIVE'):
        return Windows.browse_file(parent, title)

    chooser = Gtk.FileChooserDialog(title=title,
                                    transient_for=parent,
                                    action=Gtk.FileChooserAction.OPEN)
    chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"),
                        Gtk.ResponseType.OK)
    chooser.set_default_response(Gtk.ResponseType.OK)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    path = chooser.get_filename()
    chooser.destroy()

    if Gtk.ResponseType.OK != resp:
        # user cancelled
        return None

    return path
示例#49
0
def browse_files(parent, title):
    """Prompt user to select multiple files to delete"""

    if 'nt' == os.name and None == os.getenv('BB_NATIVE'):
        return Windows.browse_files(parent.window.handle, title)

    chooser = Gtk.FileChooserDialog(title=title,
                                    transient_for=parent,
                                    action=Gtk.FileChooserAction.OPEN)
    chooser.add_buttons(_("_Cancel"), Gtk.ResponseType.CANCEL, _("_Delete"),
                        Gtk.ResponseType.OK)
    chooser.set_default_response(Gtk.ResponseType.OK)
    chooser.set_select_multiple(True)
    chooser.set_current_folder(expanduser('~'))
    resp = chooser.run()
    paths = chooser.get_filenames()
    chooser.destroy()

    if Gtk.ResponseType.OK != resp:
        # user cancelled
        return None

    return paths
示例#50
0
    def test_expanduser(self):
        """Unit test for expanduser."""
        # Return Unicode when given str.
        self.assertIsUnicodeString(bleachbit.expanduser('~'))

        # Return Unicode when given Unicode.
        self.assertIsUnicodeString(bleachbit.expanduser(u'~'))

        # Blank input should give blank output.
        self.assertEqual(bleachbit.expanduser(''), u'')

        # An absolute path should not be altered.
        abs_dirs = {'posix': '$HOME', 'nt': '%USERPROFILE%'}
        abs_dir = os.path.expandvars(abs_dirs[os.name])
        self.assertExists(abs_dir)
        self.assertEqual(bleachbit.expanduser(abs_dir), abs_dir)
        # Path with tilde should be expanded
        self.assertEqual(os.path.normpath(bleachbit.expanduser('~')),
                         os.path.normpath(os.path.expanduser('~')))
        # A relative path (without a reference to the home directory)
        # should not be expanded.
        self.assertEqual(bleachbit.expanduser('common'), 'common')
示例#51
0
    def get_commands(self, option_id):
        # cache
        if 'posix' == os.name and 'cache' == option_id:
            dirname = expanduser("~/.cache/")
            for filename in children_in_directory(dirname, True):
                if not self.whitelisted(filename):
                    yield Command.Delete(filename)

        # custom
        if 'custom' == option_id:
            for (c_type, c_path) in options.get_custom_paths():
                if 'file' == c_type:
                    yield Command.Delete(c_path)
                elif 'folder' == c_type:
                    yield Command.Delete(c_path)
                    for path in children_in_directory(c_path, True):
                        yield Command.Delete(path)
                else:
                    raise RuntimeError(
                        'custom folder has invalid type %s' % c_type)

        # menu
        menu_dirs = ['~/.local/share/applications',
                     '~/.config/autostart',
                     '~/.gnome/apps/',
                     '~/.gnome2/panel2.d/default/launchers',
                     '~/.gnome2/vfolders/applications/',
                     '~/.kde/share/apps/RecentDocuments/',
                     '~/.kde/share/mimelnk',
                     '~/.kde/share/mimelnk/application/ram.desktop',
                     '~/.kde2/share/mimelnk/application/',
                     '~/.kde2/share/applnk']

        if 'posix' == os.name and 'desktop_entry' == option_id:
            for dirname in menu_dirs:
                for filename in [fn for fn in children_in_directory(dirname, False)
                                 if fn.endswith('.desktop')]:
                    if Unix.is_broken_xdg_desktop(filename):
                        yield Command.Delete(filename)

        # unwanted locales
        if 'posix' == os.name and 'localizations' == option_id:
            for path in Unix.locales.localization_paths(locales_to_keep=options.get_languages()):
                if os.path.isdir(path):
                    for f in FileUtilities.children_in_directory(path, True):
                        yield Command.Delete(f)
                yield Command.Delete(path)

        # Windows logs
        if 'nt' == os.name and 'logs' == option_id:
            paths = (
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\*.log',
                '$ALLUSERSPROFILE\\Application Data\\Microsoft\\Dr Watson\\user.dmp',
                '$LocalAppData\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$LocalAppData\\Microsoft\\Windows\WER\\ReportQueue\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportArchive\\*\\*',
                '$programdata\\Microsoft\\Windows\\WER\\ReportQueue\\*\\*',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$localappdata\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\*.log',
                '$windir\\imsins.BAK',
                '$windir\\OEWABLog.txt',
                '$windir\\SchedLgU.txt',
                '$windir\\ntbtlog.txt',
                '$windir\\setuplog.txt',
                '$windir\\REGLOCS.OLD',
                '$windir\\Debug\\*.log',
                '$windir\\Debug\\Setup\\UpdSh.log',
                '$windir\\Debug\\UserMode\\*.log',
                '$windir\\Debug\\UserMode\\ChkAcc.bak',
                '$windir\\Debug\\UserMode\\userenv.bak',
                '$windir\\Microsoft.NET\Framework\*\*.log',
                '$windir\\pchealth\\helpctr\\Logs\\hcupdate.log',
                '$windir\\security\\logs\\*.log',
                '$windir\\security\\logs\\*.old',
                '$windir\\SoftwareDistribution\\*.log',
                '$windir\\SoftwareDistribution\\DataStore\\Logs\\*',
                '$windir\\system32\\TZLog.log',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.bak',
                '$windir\\system32\\config\\systemprofile\\Application Data\\Microsoft\\Internet Explorer\\brndlog.txt',
                '$windir\\system32\\LogFiles\\AIT\\AitEventLog.etl.???',
                '$windir\\system32\\LogFiles\\Firewall\\pfirewall.log*',
                '$windir\\system32\\LogFiles\\Scm\\SCM.EVM*',
                '$windir\\system32\\LogFiles\\WMI\\Terminal*.etl',
                '$windir\\system32\\LogFiles\\WMI\\RTBackup\EtwRT.*etl',
                '$windir\\system32\\wbem\\Logs\\*.lo_',
                '$windir\\system32\\wbem\\Logs\\*.log', )

            for path in paths:
                expanded = expandvars(path)
                for globbed in glob.iglob(expanded):
                    yield Command.Delete(globbed)

        # memory
        if sys.platform.startswith('linux') and 'memory' == option_id:
            yield Command.Function(None, Memory.wipe_memory, _('Memory'))

        # memory dump
        # how to manually create this file
        # http://www.pctools.com/guides/registry/detail/856/
        if 'nt' == os.name and 'memory_dump' == option_id:
            fname = expandvars('$windir\\memory.dmp')
            if os.path.exists(fname):
                yield Command.Delete(fname)
            for fname in glob.iglob(expandvars('$windir\\Minidump\\*.dmp')):
                yield Command.Delete(fname)

        # most recently used documents list
        if 'posix' == os.name and 'recent_documents' == option_id:
            ru_fn = expanduser("~/.recently-used")
            if os.path.lexists(ru_fn):
                yield Command.Delete(ru_fn)
            # GNOME 2.26 (as seen on Ubuntu 9.04) will retain the list
            # in memory if it is simply deleted, so it must be shredded
            # (or at least truncated).
            #
            # GNOME 2.28.1 (Ubuntu 9.10) and 2.30 (10.04) do not re-read
            # the file after truncation, but do re-read it after
            # shredding.
            #
            # https://bugzilla.gnome.org/show_bug.cgi?id=591404

            def gtk_purge_items():
                """Purge GTK items"""
                gtk.RecentManager().purge_items()
                yield 0

            for pathname in ["~/.recently-used.xbel", "~/.local/share/recently-used.xbel"]:
                pathname = expanduser(pathname)
                if os.path.lexists(pathname):
                    yield Command.Shred(pathname)
            if HAVE_GTK:
                # Use the Function to skip when in preview mode
                yield Command.Function(None, gtk_purge_items, _('Recent documents list'))

        if 'posix' == os.name and 'rotated_logs' == option_id:
            for path in Unix.rotated_logs():
                yield Command.Delete(path)

        # temporary files
        if 'posix' == os.name and 'tmp' == option_id:
            dirnames = ['/tmp', '/var/tmp']
            for dirname in dirnames:
                for path in children_in_directory(dirname, True):
                    is_open = FileUtilities.openfiles.is_open(path)
                    ok = not is_open and os.path.isfile(path) and \
                        not os.path.islink(path) and \
                        FileUtilities.ego_owner(path) and \
                        not self.whitelisted(path)
                    if ok:
                        yield Command.Delete(path)

        # temporary files
        if 'nt' == os.name and 'tmp' == option_id:
            dirname1 = expandvars(
                "$USERPROFILE\\Local Settings\\Temp\\")
            dirname2 = expandvars(r'%temp%')
            dirname3 = expandvars("%windir%\\temp\\")
            dirnames = []
            if Windows.get_windows_version() >= 6.0:
                # Windows Vista or later
                dirnames.append(dirname2)
            else:
                # Windows XP
                dirnames.append(dirname1)
            dirnames.append(dirname3)
            # whitelist the folder %TEMP%\Low but not its contents
            # https://bugs.launchpad.net/bleachbit/+bug/1421726
            for dirname in dirnames:
                low = os.path.join(dirname, 'low').lower()
                for filename in children_in_directory(dirname, True):
                    if not low == filename.lower():
                        yield Command.Delete(filename)

        # trash
        if 'posix' == os.name and 'trash' == option_id:
            dirname = expanduser("~/.Trash")
            for filename in children_in_directory(dirname, False):
                yield Command.Delete(filename)
            # fixme http://www.ramendik.ru/docs/trashspec.html
            # http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
            # ~/.local/share/Trash
            # * GNOME 2.22, Fedora 9
            # * KDE 4.1.3, Ubuntu 8.10
            dirname = expanduser("~/.local/share/Trash/files")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/info")
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)
            dirname = expanduser("~/.local/share/Trash/expunged")
            # [email protected] tells me that the trash
            # backend puts files in here temporary, but in some situations
            # the files are stuck.
            for filename in children_in_directory(dirname, True):
                yield Command.Delete(filename)

        # clipboard
        if HAVE_GTK and 'clipboard' == option_id:
            def clear_clipboard():
                gtk.gdk.threads_enter()
                clipboard = gtk.clipboard_get()
                clipboard.set_text("")
                gtk.gdk.threads_leave()
                return 0
            yield Command.Function(None, clear_clipboard, _('Clipboard'))

        # overwrite free space
        shred_drives = options.get_list('shred_drives')
        if 'free_disk_space' == option_id and shred_drives:
            for pathname in shred_drives:
                # TRANSLATORS: 'Free' means 'unallocated.'
                # %s expands to a path such as C:\ or /tmp/
                display = _("Overwrite free disk space %s") % pathname

                def wipe_path_func():
                    for ret in FileUtilities.wipe_path(pathname, idle=True):
                        # Yield control to GTK idle because this process
                        # is very slow.  Also display progress.
                        yield ret
                    yield 0
                yield Command.Function(None, wipe_path_func, display)

        # MUICache
        if 'nt' == os.name and 'muicache' == option_id:
            keys = (
                'HKCU\\Software\\Microsoft\\Windows\\ShellNoRoam\\MUICache',
                'HKCU\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache')
            for key in keys:
                yield Command.Winreg(key, None)

        # prefetch
        if 'nt' == os.name and 'prefetch' == option_id:
            for path in glob.iglob(expandvars('$windir\\Prefetch\\*.pf')):
                yield Command.Delete(path)

        # recycle bin
        if 'nt' == os.name and 'recycle_bin' == option_id:
            # This method allows shredding
            recycled_any = False
            for path in Windows.get_recycle_bin():
                recycled_any = True
                yield Command.Delete(path)
            # If there were any files deleted, Windows XP will show the
            # wrong icon for the recycle bin indicating it is not empty.
            # The icon will be incorrect until logging in to Windows again
            # or until it is emptied using the Windows API call for emptying
            # the recycle bin.

            # Windows 10 refreshes the recycle bin icon when the user
            # opens the recycle bin folder.

            # This is a hack to refresh the icon.
            def empty_recycle_bin_func():
                import tempfile
                tmpdir = tempfile.mkdtemp()
                Windows.move_to_recycle_bin(tmpdir)
                try:
                    Windows.empty_recycle_bin(None, True)
                except:
                    logging.getLogger(__name__).info('error in empty_recycle_bin()', exc_info=True)
                yield 0
            # Using the Function Command prevents emptying the recycle bin
            # when in preview mode.
            if recycled_any:
                yield Command.Function(None, empty_recycle_bin_func, _('Empty the recycle bin'))

        # Windows Updates
        if 'nt' == os.name and 'updates' == option_id:
            for wu in Windows.delete_updates():
                yield wu
示例#52
0
 def add_search(self, dirname, regex):
     parent.assertEqual(dirname, expanduser('~'))
     parent.assertIn(regex, ['^Thumbs\\.db$', '^Thumbs\\.db:encryptable$'])
示例#53
0
def diagnostic_info():
    """Return diagnostic information as a string"""
    # this section is for application and library versions
    s = "BleachBit version %s" % bleachbit.APP_VERSION

    try:
        from bleachbit.Revision import revision
        s += '\nGit revision %s' % revision
    except:
        pass
    try:
        from gi.repository import Gtk
        s += '\nGTK version {0}.{1}.{2}'.format(Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version())
    except:
        pass
    import sqlite3
    s += "\nSQLite version %s" % sqlite3.sqlite_version

    # this section is for variables defined in __init__.py
    s += "\nFSE = %s" % bleachbit.FSE
    s += "\nlocal_cleaners_dir = %s" % bleachbit.local_cleaners_dir
    s += "\nlocale_dir = %s" % bleachbit.locale_dir
    s += "\noptions_dir = %s" % bleachbit.options_dir.decode(bleachbit.FSE)
    s += "\npersonal_cleaners_dir = %s" % bleachbit.personal_cleaners_dir.decode(
        bleachbit.FSE)
    s += "\nsystem_cleaners_dir = %s" % bleachbit.system_cleaners_dir

    # this section is for information about the system environment
    s += "\nlocale.getdefaultlocale = %s" % str(locale.getdefaultlocale())
    if 'posix' == os.name:
        envs = ('DESKTOP_SESSION', 'LOGNAME', 'USER', 'SUDO_UID')
    if 'nt' == os.name:
        envs = ('APPDATA', 'LocalAppData', 'LocalAppDataLow', 'Music',
                'USERPROFILE', 'ProgramFiles', 'ProgramW6432', 'TMP')
    for env in envs:
        if os.getenv(env):
            s += "\nos.getenv('%s') = %s" % (env,
                                             os.getenv(env).decode(bleachbit.FSE))
        else:
            s += "\nos.getenv('%s') = %s" % (env, os.getenv(env))
    s += "\nos.path.expanduser('~') = %s" % bleachbit.expanduser(
        '~').decode(bleachbit.FSE)
    if sys.platform.startswith('linux'):
        if hasattr(platform, 'linux_distribution'):
            s += "\nplatform.linux_distribution() = %s" % str(
                platform.linux_distribution())
        else:
            s += "\nplatform.dist() = %s" % str(platform.dist())
            
    # Mac Version Name - Dictionary
    macosx_dict = {'5': 'Leopard', '6': 'Snow Leopard', '7': 'Lion', '8': 'Mountain Lion',
                   '9': 'Mavericks', '10': 'Yosemite', '11': 'El Capitan', '12': 'Sierra'}

    if sys.platform.startswith('darwin'):
        if hasattr(platform, 'mac_ver'):
            for key in macosx_dict:
                if (platform.mac_ver()[0].split('.')[1] == key):
                    s += "\nplatform.mac_ver() = %s" % str(
                        platform.mac_ver()[0] + " (" + macosx_dict[key] + ")")
        else:
            s += "\nplatform.dist() = %s" % str(platform.dist())

    if 'nt' == os.name:
        s += "\nplatform.win32_ver[1]() = %s" % platform.win32_ver()[1]
    s += "\nplatform.platform = %s" % platform.platform()
    s += "\nplatform.version = %s" % platform.version()
    s += "\nsys.argv = %s" % sys.argv
    s += "\nsys.executable = %s" % sys.executable
    s += "\nsys.version = %s" % sys.version
    if 'nt' == os.name:
        s += "\nwin32com.shell.shell.IsUserAnAdmin() = %s" % shell.IsUserAnAdmin(
        )
    s += "\n__file__ = %s" % __file__

    return s