Exemple #1
0
 def execute_user_command(self, cmd_type, command):
   """Run the after user command"""
   # Before or after command?
   if cmd_type == 1:
     cmd_type_str = 'Before'
   elif cmd_type == 2:
     cmd_type_str = 'After'
   else:
     raise ValueError('Unknown command type value "%s"' % cmd_type)
   # Execute the command
   self.logger.logmsg('INFO', _("Executing '%s' command") % cmd_type_str)
   sub = fwbackups.executeSub(command, env=self.environment, shell=True)
   self.pids.append(sub.pid)
   self.logger.logmsg('DEBUG', _('Starting subprocess with PID %s') % sub.pid)
   # track stdout
   errors = []
   # use nonblocking I/O
   fl = fcntl.fcntl(sub.stderr, fcntl.F_GETFL)
   fcntl.fcntl(sub.stderr, fcntl.F_SETFL, fl | os.O_NONBLOCK)
   while sub.poll() in ["", None]:
     time.sleep(0.01)
     try:
       errors += sub.stderr.readline()
     except IOError, description:
       pass
Exemple #2
0
 def history(self):
     """Get + print all old log messages stored in the log file"""
     stream = open(LOGLOC, 'r')
     text = stream.read()
     stream.close()
     if text.strip() != '':
         self.console.write_line('-- %s --%s%s' % (_('Previous log messages')\
   , os.linesep, os.linesep), self.console.style_ps2)
         for i in text.split(os.linesep):
             errType = i.split(' ')
             if len(errType) >= 5:
                 if errType[4] == _('CRITICAL') or errType[4] == _('ERROR'):
                     self.console.write_line('%s%s' % (i, os.linesep),
                                             self.console.style_err)
                 elif errType[4] == _('WARNING'):
                     self.console.write_line('%s%s' % (i, os.linesep),
                                             self.console.style_warn)
                 else:
                     self.console.write_line('%s%s' % (i, os.linesep),
                                             self.console.style_ps1)
             else:
                 self.console.write_line('%s%s' % (i, os.linesep),
                                         self.console.style_ps1)
     else:
         self.console.write_line('-- %s --%s' % (_('No previous log messages to display'),\
   os.linesep), self.console.style_ps2)
Exemple #3
0
    def __init__(self, treeview, statusbar, ui):
        self.treeview = treeview
        self.logger = fwlogger.getLogger()
        self.statusbar = statusbar
        self.ui = ui
        self.liststore = gtk.ListStore(gobject.TYPE_BOOLEAN,
                                       gobject.TYPE_STRING)
        # Give it columns
        cell = gtk.CellRendererToggle()
        cell.connect('toggled', self._on_toggled, self.liststore)
        cell.set_property('activatable', True)
        col = gtk.TreeViewColumn(_('Export'), cell, active=0)
        col.set_resizable(True)
        self.treeview.append_column(col)

        cell = gtk.CellRendererText()
        cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
        col = gtk.TreeViewColumn(_('Set'), cell, text=1)
        col.set_resizable(True)
        self.treeview.append_column(col)

        self.treeview.set_model(self.liststore)
        self.treeview.set_reorderable(False)
        # Just to keep things clean.
        self._clear()
Exemple #4
0
 def _load(self):
   """Load all set .conf files into the view"""
   loaded_count = 0
   self.logger.logmsg('DEBUG', _('Parsing configuration files'))
   files = os.listdir(SETLOC)
   for file in files:
     if file.endswith('.conf'):
       self.liststore.append([True, file.split('.conf')[0]])
     else:
       self.logger.logmsg('WARNING', _('Refusing to parse file `%s\': configuration files must end in `.conf\'') % file)
Exemple #5
0
 def cancelOperation(self):
   """Requests the current operation stops as soon as possible"""
   self.logger.logmsg('INFO', _('Canceling the current operation!'))
   if self.pids:
     for process in self.pids:
       try:
         self.logger.logmsg('DEBUG', _('Stopping process with ID %s') % process)
         fwbackups.kill(process, 9)
       except Exception, error:
         self.logger.logmsg('WARNING', _('Could not stop process %(a)s: %(b)s' % (process, error)))
         continue
Exemple #6
0
 def write_log_line(self, i):
   """Wrapper for write_line for log messages"""
   errType = i.split(' ')
   if len(errType) >= 5:
     if errType[4] == _('CRITICAL') or errType[4] == _('ERROR'):
       self.write_line('%s%s' % (i, os.linesep), self.style_err)
     elif errType[4] == _('WARNING'):
       self.write_line('%s%s' % (i, os.linesep), self.style_warn)
     else:
       self.write_line('%s%s' % (i, os.linesep), self.style_ps1)
   else:
     self.write_line('%s%s' % (i, os.linesep), self.style_ps1)
Exemple #7
0
 def write_log_line(self, i):
     """Wrapper for write_line for log messages"""
     errType = i.split(' ')
     if len(errType) >= 5:
         if errType[4] == _('CRITICAL') or errType[4] == _('ERROR'):
             self.write_line('%s%s' % (i, os.linesep), self.style_err)
         elif errType[4] == _('WARNING'):
             self.write_line('%s%s' % (i, os.linesep), self.style_warn)
         else:
             self.write_line('%s%s' % (i, os.linesep), self.style_ps1)
     else:
         self.write_line('%s%s' % (i, os.linesep), self.style_ps1)
Exemple #8
0
 def prepareDestinationFolder(self, folder, createNonExistant=True):
   """Prepare a destination folder for an operation"""
   if os.path.exists(encode(folder)):
     self.logger.logmsg('DEBUG', _('Destination folder `%s\' exists') % folder)
   # folder doesn't exist; try to create if specified
   elif createNonExistant:
     try:
       os.mkdir(encode(folder), 0755)
       self.logger.logmsg('DEBUG', _("Created destination folder `%s'") % folder)
     except OSError, error:
       self.logger.logmsg('ERROR', _("The destination folder `%(a)s' could not be created: %(b)s") % {'a': folder, 'b': error})
       return False
Exemple #9
0
 def _load(self):
     """Load all set .conf files into the view"""
     loaded_count = 0
     self.logger.logmsg('DEBUG', _('Parsing configuration files'))
     files = os.listdir(SETLOC)
     for file in files:
         if file.endswith('.conf'):
             self.liststore.append([True, file.split('.conf')[0]])
         else:
             self.logger.logmsg(
                 'WARNING',
                 _('Refusing to parse file `%s\': configuration files must end in `.conf\''
                   ) % file)
Exemple #10
0
  def history(self):
    """Get + print all old log messages stored in the log file"""
    stream = open(LOGLOC, 'r')
    text = stream.read()
    stream.close()
    if text.strip() != '':
      self.write_line('-- %s --%s%s' % (_('Previous log messages'), os.linesep, os.linesep), self.style_ps2)
      for i in text.split('\n'):
        self.write_log_line(i)
    else:
      self.write_line('-- %s --%s' % (_('No previous log messages to display'),\
os.linesep), self.style_ps2)
    self.write_line('-- %s --%s%s' % (_('Current session\'s log messages'), os.linesep, os.linesep), self.style_ps2)
Exemple #11
0
 def createDiskInfo(self):
   """Print disk info to a file in tempdir"""
   fd, path = tempfile.mkstemp(suffix='.txt', prefix="%s - tmp" % _('Disk Information'))
   fh = os.fdopen(fd, 'w')
   retval, stdout, stderr = fwbackups.execute('fdisk -l', env=self.environment, shell=True, stdoutfd=fh)
   fh.close()
   return path
Exemple #12
0
  def __init__(self, console):
    logging.FileHandler.__init__(self, LOGLOC)
    self.console = console
    self.history()
    self.stream = None
    self.console.write_line('-- %s --%s%s' % (_('Current session\'s log \
messages'), os.linesep, os.linesep), self.console.style_ps2)
Exemple #13
0
    def start(self):
        """One-time backup"""
        paths = self.parsePaths(self.config)
        if not paths:
            self.logger.logmsg("WARNING", _("There are no paths to backup!"))
            return False

        if self.options["DestinationType"] == "remote (ssh)":  # check if server settings are OK
            self.checkRemoteServer()

        if self.options["PkgListsToFile"]:
            pkgListfiles = self.createPkgLists()
        else:
            pkgListfiles = []
        if self.options["DiskInfoToFile"]:
            pkgListfiles.append(self.createDiskInfo())

        if not (
            self.options["Engine"] == "rsync"
            and self.options["Incremental"]
            and not self.options["DestinationType"] == "remote (ssh)"
        ):
            if not self.prepareDestinationFolder(self.options["Destination"]):
                return False
            if os.path.exists(encode(self.dest)):
                self.logger.logmsg("WARNING", _("`%s' exists and will be overwritten.") % self.dest)
                shutil_modded.rmtree(encode(self.dest), onerror=self.onError)
        self.ifCancel()

        command = self.parseCommand(self.config)
        self.addListFilesToBackup(pkgListfiles, command, self.options["Engine"], paths)

        # Now that the paths & commands are set up...
        retval = self.backupPaths(paths, command)

        self.deleteListFiles(pkgListfiles)
        self.ifCancel()

        if self.options["DestinationType"] == "local":
            try:
                os.chmod(self.dest, 0711)
            except:
                pass

        # All done!
        self.logger.logmsg("INFO", _("Finished one-time backup"))
        return retval
Exemple #14
0
 def __init__(self, restorePath, logger=None):
   """Initializes a restore operation. If no logger is specified, a new one
   will be created."""
   operations.Common.__init__(self, logger)
   self.logger.logmsg('INFO', _('Starting restore operation'))
   self.config = config.RestoreConf(restorePath)
   self.options = self.getOptions(self.config)
   self.options['Engine'] = 'null' # workaround so prepareDestinationFolder doesn't complain
Exemple #15
0
    def __init__(self, console):
        logging.FileHandler.__init__(self, LOGLOC)
        self.console = console
        self.history()
        self.stream = None
        self.console.write_line(
            '-- %s --%s%s' % (_('Current session\'s log \
messages'), os.linesep, os.linesep), self.console.style_ps2)
Exemple #16
0
 def addFolder(self):
   """Add a folder to the pathview"""
   fileDialog = PathDia(self.ui.path_dia, _('Choose folder(s)'), self.parent, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, multiple=True)
   response = fileDialog.run()
   if response == gtk.RESPONSE_OK:
     paths = [path.decode('utf-8') for path in fileDialog.get_filenames()]
     self.add(paths, self._buildListstoreIndex(self.liststore, 1))
   fileDialog.destroy()
Exemple #17
0
 def ifCancel(self, fh=None):
   """Checks if another thread requested the operation be cancelled via
   cancelOperation(). If a file-handle 'fh' is given, it will be closed."""
   if self.toCancel:
     self.logger.logmsg('INFO', _('The operation has been cancelled.'))
     if fh != None:
       fh.close()
     raise SystemExit
Exemple #18
0
 def __init__(self, onetPath, logger=None):
     """Initializes a one-time backup operation. If no logger is specified, a new one
 will be created. logger will be created if needed."""
     BackupOperation.__init__(self, logger)
     self.logger.logmsg("INFO", _("Starting one-time backup operation"))
     self.config = config.OneTimeConf(onetPath)
     self.options = self.getOptions(self.config)
     # Parse backup folder format
     date = time.strftime("%Y-%m-%d_%H-%M")
     self.dest = os.path.join(self.options["Destination"], "%s-%s-%s" % (_("Backup"), _("OneTime"), date))
     # IF tar || tar.gz, add .tar || tar.gz respectively to the dest since
     # the dest is to be a file, not a folder...
     if self.options["Engine"] == "tar":
         self.dest += ".tar"
     elif self.options["Engine"] == "tar.gz":
         self.dest += ".tar.gz"
     elif self.options["Engine"] == "tar.bz2":
         self.dest += ".tar.bz2"
Exemple #19
0
 def __init__(self, restorePath, logger=None):
     """Initializes a restore operation. If no logger is specified, a new one
 will be created."""
     operations.Common.__init__(self, logger)
     self.logger.logmsg('INFO', _('Starting restore operation'))
     self.config = config.RestoreConf(restorePath)
     self.options = self.getOptions(self.config)
     self.options[
         'Engine'] = 'null'  # workaround so prepareDestinationFolder doesn't complain
Exemple #20
0
 def __init__(self, onetPath, logger=None):
   """Initializes a one-time backup operation. If no logger is specified, a new one
   will be created. logger will be created if needed."""
   BackupOperation.__init__(self, logger)
   self.logger.logmsg('INFO', _('Starting one-time backup operation'))
   self.config = config.OneTimeConf(onetPath)
   self.options = self.getOptions(self.config)
   # Parse backup folder format
   date = time.strftime('%Y-%m-%d_%H-%M')
   self.dest = os.path.join(self.options['Destination'], "%s-%s-%s" % (_('Backup'), _('OneTime'), date))
   # IF tar || tar.gz, add .tar || tar.gz respectively to the dest since
   # the dest is to be a file, not a folder...
   if self.options['Engine'] == 'tar':
     self.dest += '.tar'
   elif self.options['Engine'] == 'tar.gz':
     self.dest += '.tar.gz'
   elif self.options['Engine'] == 'tar.bz2':
     self.dest += '.tar.bz2'
Exemple #21
0
def putFolder(sftp, src, dst, symlinks=False, excludes=[]):
    """Copies src (local) to dst/[src] (remote). Folder dst must exist"""
    # Check if the src itself is an exclude
    # FIXME: This means we check any subdirectory against excludes 2x
    SKIPME = 0
    for exclude in excludes:  # excludes pattern matching
        if src in myglob(exclude, os.path.dirname(src)):
            SKIPME = 1
            break  # it is pointless to process further excludes
    if SKIPME:
        return
    errors = []
    dst = os.path.join(dst, os.path.basename(src))
    if not exists(sftp, dst):
        sftp.mkdir(dst)
    #sftp.chdir(dst)
    for item in os.listdir(src):
        # make absolute paths
        src_abs = os.path.join(src, item)
        dst_abs = os.path.join(dst, item)
        SKIPME = 0
        for exclude in excludes:  # excludes pattern matching
            if src_abs in myglob(exclude, os.path.dirname(src_abs)):
                SKIPME = 1
                break  # it is pointless to process further excludes
        if SKIPME:
            continue
        try:
            # at this point, excludes have been handled and we're ready to copy.
            if symlinks and os.path.islink(src_abs):
                linkto = os.readlink(src_abs)
                sftp.symlink(linkto, dst_abs)
            elif os.path.isdir(src_abs):
                # run this again in the subfolder, uploading to the parent folder
                putFolder(sftp, src_abs, os.path.dirname(dst_abs), symlinks,
                          excludes)
            elif os.path.isfile(src_abs):
                sftp.put(src_abs, dst_abs)
            else:
                print _(
                    '`%s\' is not a file, folder or link! Skipping.') % src_abs
        except (IOError, os.error), reason:
            # don't halt the entire copy, just print the errors at the end
            errors.append('%s --> %s: %s' % (src_abs, dst_abs, reason))
Exemple #22
0
  def start(self):
    """One-time backup"""
    paths = self.parsePaths(self.config)
    if not paths:
      self.logger.logmsg('WARNING', _('There are no paths to backup!'))
      return False

    if self.options['DestinationType'] == 'remote (ssh)': # check if server settings are OK
      self.checkRemoteServer()

    if self.options['PkgListsToFile']:
      pkgListfiles = self.createPkgLists()
    else:
      pkgListfiles = []
    if self.options['DiskInfoToFile']:
      pkgListfiles.append(self.createDiskInfo())

    if not (self.options['Engine'] == 'rsync' and self.options['Incremental'] and \
       not self.options['DestinationType'] == 'remote (ssh)'):
      if not self.prepareDestinationFolder(self.options['Destination']):
        return False
      if os.path.exists(encode(self.dest)):
        self.logger.logmsg('WARNING', _('`%s\' exists and will be overwritten.') % self.dest)
        shutil_modded.rmtree(encode(self.dest), onerror=self.onError)
    self.ifCancel()

    command = self.parseCommand()
    self.addListFilesToBackup(pkgListfiles, command, self.options['Engine'], paths)

    # Now that the paths & commands are set up...
    retval = self.backupPaths(paths, command)

    self.deleteListFiles(pkgListfiles)
    self.ifCancel()

    if self.options['DestinationType'] == 'local':
      try:
        os.chmod(self.dest, 0711)
      except:
        pass

    # All done!
    self.logger.logmsg('INFO', _('Finished one-time backup'))
    return retval
Exemple #23
0
 def removePath(self):
   """Remote a path from the pathview"""
   try:
     model, paths = self.treeview.get_selection().get_selected_rows()
     for i in paths:
       model, paths = self.treeview.get_selection().get_selected_rows()
       model.remove(model.get_iter(paths[0]))
   except TypeError:
     self.statusbar.newmessage(_('Please select a path before choosing an action.'), 3)
     return
Exemple #24
0
 def history(self):
     """Get + print all old log messages stored in the log file"""
     stream = open(LOGLOC, 'r')
     text = stream.read()
     stream.close()
     if text.strip() != '':
         self.write_line(
             '-- %s --%s%s' %
             (_('Previous log messages'), os.linesep, os.linesep),
             self.style_ps2)
         for i in text.split('\n'):
             self.write_log_line(i)
     else:
         self.write_line('-- %s --%s' % (_('No previous log messages to display'),\
   os.linesep), self.style_ps2)
     self.write_line(
         '-- %s --%s%s' %
         (_('Current session\'s log messages'), os.linesep, os.linesep),
         self.style_ps2)
Exemple #25
0
def putFolder(sftp, src, dst, symlinks=False, excludes=[]):
  """Copies src (local) to dst/[src] (remote). Folder dst must exist"""
  # Check if the src itself is an exclude
  # FIXME: This means we check any subdirectory against excludes 2x
  SKIPME = 0
  for exclude in excludes: # excludes pattern matching
    if src in myglob(exclude, os.path.dirname(src)):
      SKIPME = 1
      break # it is pointless to process further excludes
  if SKIPME:
    return
  errors = []
  dst = os.path.join(dst, os.path.basename(src))
  if not exists(sftp, dst):
    sftp.mkdir(dst)
  #sftp.chdir(dst)
  for item in os.listdir(src):
    # make absolute paths
    src_abs =  os.path.join(src, item)
    dst_abs = os.path.join(dst, item)
    SKIPME = 0
    for exclude in excludes: # excludes pattern matching
      if src_abs in myglob(exclude, os.path.dirname(src_abs)):
        SKIPME = 1
        break # it is pointless to process further excludes
    if SKIPME:
      continue
    try:
      # at this point, excludes have been handled and we're ready to copy.
      if symlinks and os.path.islink(src_abs):
        linkto = os.readlink(src_abs)
        sftp.symlink(linkto, dst_abs)
      elif os.path.isdir(src_abs):
        # run this again in the subfolder, uploading to the parent folder
        putFolder(sftp, src_abs, os.path.dirname(dst_abs), symlinks, excludes)
      elif os.path.isfile(src_abs):
        sftp.put(src_abs, dst_abs)
      else:
        print _('`%s\' is not a file, folder or link! Skipping.') % src_abs
    except (IOError, os.error), reason:
      # don't halt the entire copy, just print the errors at the end
      errors.append('%s --> %s: %s' % (src_abs, dst_abs, reason))
Exemple #26
0
 def __init__(self, setPath, logger=None):
   """Initializes the automatic backup operation of set defined at setPath.
   If no logger is supplied, a new one will be created."""
   BackupOperation.__init__(self, logger)
   self.config = config.BackupSetConf(setPath)
   self.options = self.getOptions(self.config)
   if self.options['Enabled']:
     self.logger.logmsg('INFO', _('Starting automatic backup operation of set `%s\'') % self.config.getSetName())
   # Parse backup folder format
   # date stored as class variable due to re-use in user commands later
   self.date = time.strftime('%Y-%m-%d_%H-%M')
   self.dest = os.path.join(self.options['Destination'], u"%s-%s-%s" % (_('Backup'), self.config.getSetName(), self.date))
   # set-specific options
   # IF tar || tar.gz, add .tar || tar.gz respectively to the dest since
   # the dest is to be a file, not a folder...
   if self.options['Engine'] == 'tar':
     self.dest += '.tar'
   elif self.options['Engine'] == 'tar.gz':
     self.dest += '.tar.gz'
   elif self.options['Engine'] == 'tar.bz2':
     self.dest += '.tar.bz2'
Exemple #27
0
 def removePath(self):
     """Remote a path from the pathview"""
     try:
         model, paths = self.treeview.get_selection().get_selected_rows()
         for i in paths:
             model, paths = self.treeview.get_selection().get_selected_rows(
             )
             model.remove(model.get_iter(paths[0]))
     except TypeError:
         self.statusbar.newmessage(
             _('Please select a path before choosing an action.'), 3)
         return
Exemple #28
0
    def createPkgLists(self):
        """Create the pkg lists in tempdir"""
        # Start as a dictionary so we can keep track of which items we have already
        # processed. See comment at retur for more info.
        pkgListFiles = {}
        for path in os.environ["PATH"].split(":"):
            if os.path.exists(os.path.join(path, "rpm")) and not pkgListFiles.has_key("rpm"):
                fd, path = tempfile.mkstemp(suffix=".txt", prefix="%s - tmp" % _("rpm - Package list"))
                fh = os.fdopen(fd, "w")
                # try with rpm-python, but if not just execute it like the rest
                try:
                    import rpm

                    pyrpm = True
                except ImportError:
                    pyrpm = False
                if pyrpm:
                    ts = rpm.ts()
                    # Equivalent to rpm -qa
                    mi = ts.dbMatch()
                    for hdr in mi:
                        fh.write("%s-%s-%s.%s\n" % (hdr["name"], hdr["version"], hdr["release"], hdr["arch"]))
                else:
                    retval, stdout, stderr = fwbackups.execute("rpm -qa", env=self.environment, shell=True, stdoutfd=fh)
                pkgListFiles["rpm"] = path
                fh.close()
            if os.path.exists(os.path.join(path, "pacman")) and not pkgListFiles.has_key("pacman"):
                fd, path = tempfile.mkstemp(suffix=".txt", prefix="%s - tmp" % _("Pacman - Package list"))
                fh = os.fdopen(fd, "w")
                retval, stdout, stderr = fwbackups.execute("pacman -Qq", env=self.environment, shell=True, stdoutfd=fh)
                pkgListFiles["pacman"] = path
                fh.close()
            if os.path.exists(os.path.join(path, "dpkg")) and not pkgListFiles.has_key("dpkg"):
                fd, path = tempfile.mkstemp(suffix=".txt", prefix="%s - tmp" % _("dpkg - Package list"))
                fh = os.fdopen(fd, "w")
                retval, stdout, stderr = fwbackups.execute("dpkg -l", env=self.environment, shell=True, stdoutfd=fh)
                pkgListFiles["dpkg"] = path
                fh.close()
        # We want to return a list of only the filenames
        return pkgListFiles.values()
def usage(error=None):
  if error:
    print _('Error: %s'  % error)
    print _('Run with --help for usage information.')
  else:
    print _("""Usage: fwbackups-runonce --destination-type=TYPE --engine=ENGINE [OPTIONS] Path(s) Destination
Options:
  -v, --verbose  :  Increase verbosity (print debug messages)
  -h, --help  :  Print this message and exit
  -r, --recursive  :  Perform a recursive backup
  -i, --hidden  :  Include hidden files in the backup
  -p, --packages2file  :  Print installed package list to a text file
  -d, --diskinfo2file  :  Print disk geometry to a file (must be root)
  -s, --sparse  :  Handle sparse files efficiently
  -e, --engine=ENGINE  :  Use specified backup engine.
              Valid engines are tar, tar.gz, tar.bz2 and rsync.
  -x, --exclude='PATTERN'  :  Skip files matching PATTERN.
  -n, --nice=NICE  :  Indicate the niceness of the backup process (-20 to 19)
  --destination-type=TYPE  :  Destination type (`local' or `remote (ssh)')
  --remote-host=HOSTNAME  :  Connect to remote host `HOSTNAME'
  --remote-user=USERNAME  :  Connect as specified username
  --remote-password=PASSWORD  :  Connect using password `PASSWORD'
  --remote-port=PORT  :  Connect on specified port (default 22)

Path(s) is space-seperated list of paths to include in the backup.
Destination is the directory where the OneTime backup should be placed within.

Defaults to tar engine and local destination unless specified otherwise.
Supplying --remote* will have no effect unless thedestination type is
`remote (ssh)'.""")
def usage(error=None):
    if error:
        print _('Error: %s' % error)
        print _('Run with --help for usage information.')
    else:
        print _(
            """Usage: fwbackups-runonce --destination-type=TYPE --engine=ENGINE [OPTIONS] Path(s) Destination
Options:
  -v, --verbose  :  Increase verbosity (print debug messages)
  -h, --help  :  Print this message and exit
  -r, --recursive  :  Perform a recursive backup
  -i, --hidden  :  Include hidden files in the backup
  -p, --packages2file  :  Print installed package list to a text file
  -d, --diskinfo2file  :  Print disk geometry to a file (must be root)
  -s, --sparse  :  Handle sparse files efficiently
  -e, --engine=ENGINE  :  Use specified backup engine.
              Valid engines are tar, tar.gz, tar.bz2 and rsync.
  -x, --exclude='PATTERN'  :  Skip files matching PATTERN.
  -n, --nice=NICE  :  Indicate the niceness of the backup process (-20 to 19)
  --destination-type=TYPE  :  Destination type (`local' or `remote (ssh)')
  --remote-host=HOSTNAME  :  Connect to remote host `HOSTNAME'
  --remote-user=USERNAME  :  Connect as specified username
  --remote-password=PASSWORD  :  Connect using password `PASSWORD'
  --remote-port=PORT  :  Connect on specified port (default 22)

Path(s) is space-seperated list of paths to include in the backup.
Destination is the directory where the OneTime backup should be placed within.

Defaults to tar engine and local destination unless specified otherwise.
Supplying --remote* will have no effect unless thedestination type is
`remote (ssh)'.""")
Exemple #31
0
def copytree(src, dst, symlinks=False):
    """Recursively copy a directory tree using copy2().

  The destination directory must not already exist.
  If exception(s) occur, an Error is raised with a list of reasons.

  If the optional symlinks flag is true, symbolic links in the
  source tree result in symbolic links in the destination tree; if
  it is false, the contents of the files pointed to by symbolic
  links are copied."""
    if os.path.isdir(src):
        names = os.listdir(src)
    else:
        names = [src]
    if not os.path.exists(dst):
        os.mkdir(dst, 0755)
    errors = []
    for name in names:
        srcname = os.path.join(src, name)
        #dstname = os.path.join(dst, name)
        dstname = os.path.join(dst, os.path.split(name)[1])
        try:
            if symlinks and os.path.islink(srcname):
                linkto = os.readlink(srcname)
                os.symlink(linkto, dstname)
            elif os.path.isdir(srcname):
                copytree(srcname, dstname, symlinks)
            elif not os.path.isfile(srcname):
                print _(
                    '`%s\' isn\'t a file, folder or link! Skipping.') % srcname
            else:
                copy2(srcname, dstname)
            # XXX What about devices, sockets etc.? Done.
        except (IOError, os.error), why:
            errors.append('%s --> %s: %s' % (srcname, dstname, why))
        # catch the Error from the recursive copytree so that we can
        # continue with other files
        except Error, err:
            errors.extend(err.args[0])
Exemple #32
0
 def createPkgLists(self):
   """Create the pkg lists in tempdir"""
   # Start as a dictionary so we can keep track of which items we have already
   # processed. See comment at retur for more info.
   pkgListFiles = {}
   for path in os.environ['PATH'].split(':'):
     if os.path.exists(os.path.join(path, 'rpm')) and not pkgListFiles.has_key('rpm'):
       fd, path = tempfile.mkstemp(suffix='.txt', prefix="%s - tmp" % _('rpm - Package list'))
       fh = os.fdopen(fd, "w")
       # try with rpm-python, but if not just execute it like the rest
       try:
         import rpm
         pyrpm = True
       except ImportError:
         pyrpm = False
       if pyrpm:
         ts=rpm.ts()
         # Equivalent to rpm -qa
         mi=ts.dbMatch()
         for hdr in mi:
           fh.write("%s-%s-%s.%s\n" % (hdr['name'], hdr['version'], hdr['release'], hdr['arch']))
       else:
         retval, stdout, stderr = fwbackups.execute('rpm -qa', env=self.environment, shell=True, stdoutfd=fh)
       pkgListFiles['rpm'] = path
       fh.close()
     if os.path.exists(os.path.join(path, 'pacman')) and not pkgListFiles.has_key('pacman'):
       fd, path = tempfile.mkstemp(suffix='.txt', prefix="%s - tmp" % _('Pacman - Package list'))
       fh = os.fdopen(fd, 'w')
       retval, stdout, stderr = fwbackups.execute('pacman -Qq', env=self.environment, shell=True, stdoutfd=fh)
       pkgListFiles['pacman'] = path
       fh.close()
     if os.path.exists(os.path.join(path, 'dpkg')) and not pkgListFiles.has_key('dpkg'):
       fd, path = tempfile.mkstemp(suffix='.txt', prefix="%s - tmp" % _('dpkg - Package list'))
       fh = os.fdopen(fd, 'w')
       retval, stdout, stderr = fwbackups.execute('dpkg -l', env=self.environment, shell=True, stdoutfd=fh)
       pkgListFiles['dpkg'] = path
       fh.close()
   # We want to return a list of only the filenames
   return pkgListFiles.values()
Exemple #33
0
  def history(self):
    """Get + print all old log messages stored in the log file"""
    stream = open(LOGLOC, 'r')
    text = stream.read()
    stream.close()
    if text.strip() != '':
      self.console.write_line('-- %s --%s%s' % (_('Previous log messages')\
, os.linesep, os.linesep), self.console.style_ps2)
      for i in text.split(os.linesep):
        errType = i.split(' ')
        if len(errType) >= 5:
          if errType[4] == _('CRITICAL') or errType[4] == _('ERROR'):
            self.console.write_line('%s%s' % (i, os.linesep), self.console.style_err)
          elif errType[4] == _('WARNING'):
            self.console.write_line('%s%s' % (i, os.linesep), self.console.style_warn)
          else:
            self.console.write_line('%s%s' % (i, os.linesep), self.console.style_ps1)
        else:
          self.console.write_line('%s%s' % (i, os.linesep), self.console.style_ps1)
    else:
      self.console.write_line('-- %s --%s' % (_('No previous log messages to display'),\
os.linesep), self.console.style_ps2)
Exemple #34
0
 def logmsg(self, severity, message):
   """Logs a message. Severity is one of 'debug', 'info', 'warning', 'error'
   or 'critical'."""
   date = datetime.datetime.now().strftime('%b %d %H:%M:%S')
   level = self.getEffectiveLevel()
   if level <= LEVELS[severity]:
     entry = '%s :: %s : %s' % (date, _(severity), message)
     self.log(LEVELS[severity], entry)
     if self.__printToo:
       print entry.encode('utf-8')
     # pull in & execute the appropriate function
     for i in self.__functions:
       i(severity, entry)
def copytree(src, dst, symlinks=False):
  """Recursively copy a directory tree using copy2().

  The destination directory must not already exist.
  If exception(s) occur, an Error is raised with a list of reasons.

  If the optional symlinks flag is true, symbolic links in the
  source tree result in symbolic links in the destination tree; if
  it is false, the contents of the files pointed to by symbolic
  links are copied."""
  if os.path.isdir(src):
    names = os.listdir(src)
  else:
    names = [src]
  if not os.path.exists(dst):
    os.mkdir(dst, 0755)
  errors = []
  for name in names:
    srcname = os.path.join(src, name)
    #dstname = os.path.join(dst, name)
    dstname = os.path.join(dst, os.path.split(name)[1])
    try:
      if symlinks and os.path.islink(srcname):
        linkto = os.readlink(srcname)
        os.symlink(linkto, dstname)
      elif os.path.isdir(srcname):
        copytree(srcname, dstname, symlinks)
      elif not os.path.isfile(srcname):
        print _('`%s\' isn\'t a file, folder or link! Skipping.') % srcname
      else:
        copy2(srcname, dstname)
      # XXX What about devices, sockets etc.? Done.
    except (IOError, os.error), why:
      errors.append('%s --> %s: %s' % (srcname, dstname, why))
    # catch the Error from the recursive copytree so that we can
    # continue with other files
    except Error, err:
      errors.extend(err.args[0])
Exemple #36
0
 def logmsg(self, severity, message):
     """Logs a message. Severity is one of 'debug', 'info', 'warning', 'error'
 or 'critical'."""
     date = datetime.datetime.now().strftime('%b %d %H:%M:%S')
     level = self.getEffectiveLevel()
     if level <= LEVELS[severity]:
         entry = u'%s :: %s : %s' % (date.decode('utf-8'), _(severity),
                                     message)
         self.log(LEVELS[severity], entry.encode('utf-8'))
         if self.__printToo:
             print entry.encode('utf-8')
         # pull in & execute the appropriate function
         for i in self.__functions:
             i(severity, entry)
Exemple #37
0
 def addFolder(self):
     """Add a folder to the pathview"""
     fileDialog = PathDia(self.ui.path_dia,
                          _('Choose folder(s)'),
                          self.parent,
                          gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
                          multiple=True)
     response = fileDialog.run()
     if response == gtk.RESPONSE_OK:
         paths = [
             path.decode('utf-8') for path in fileDialog.get_filenames()
         ]
         self.add(paths, self._buildListstoreIndex(self.liststore, 1))
     fileDialog.destroy()
Exemple #38
0
 def removeOldBackups(self):
     """Get list of old backups and remove them"""
     # get listing, local or remote
     if self.options["DestinationType"] == "remote (ssh)":
         client, sftpClient = sftp.connect(
             self.options["RemoteHost"],
             self.options["RemoteUsername"],
             self.options["RemotePassword"],
             self.options["RemotePort"],
         )
         listing = sftpClient.listdir(self.options["RemoteFolder"])
     else:
         listing = os.listdir(encode(self.options["Destination"]))
     # Normalize the unicode strings storing the filenames. This fixes a problem
     # on HFS+ filesystems where supplying a set name on the command line
     # resulted in a different Unicode string than the filename of the set.
     listing = [decode(i, filename=True) for i in listing]
     listing.sort()
     oldbackups = []
     for i in listing:
         backupPrefix = "%s-%s-" % (_("Backup"), self.config.getSetName())
         if i.startswith(backupPrefix):
             oldbackups.append(i)
     # ...And remove them.
     oldbackups.reverse()
     if self.options["DestinationType"] == "remote (ssh)":
         for i in oldbackups[self.options["OldToKeep"] :]:
             remoteBackup = os.path.join(self.options["RemoteFolder"], i)
             self.logger.logmsg(
                 "DEBUG",
                 _("Removing old backup `%(a)s' on %(b)s") % {"a": remoteBackup, "b": self.options["RemoteHost"]},
             )
             sftp.remove(sftpClient, remoteBackup)
         sftpClient.close()
         client.close()
     else:
         if self.options["Engine"] == "rsync" and self.options["Incremental"] and oldbackups:
             for i in oldbackups[:-1]:
                 self.logger.logmsg("DEBUG", _("Removing old backup `%s'") % i)
                 path = os.path.join(self.options["Destination"], i)
                 shutil_modded.rmtree(encode(path), onerror=self.onError)
             oldIncrementalBackup = os.path.join(self.options["Destination"], oldbackups[-1])
             if (
                 not oldIncrementalBackup.endswith(".tar")
                 and not oldIncrementalBackup.endswith(".tar.gz")
                 and not oldIncrementalBackup.endswith(".tar.bz2")
             ):  # oldIncrementalBackup = rsync
                 self.logger.logmsg("DEBUG", _("Moving  `%s' to `%s'") % (oldIncrementalBackup, self.dest))
                 shutil_modded.move(encode(oldIncrementalBackup), encode(self.dest))
             else:  # source = is not a rsync backup - remove it and start fresh
                 self.logger.logmsg("DEBUG", _("`%s' is not an rsync backup - removing.") % oldIncrementalBackup)
                 shutil_modded.rmtree(encode(oldIncrementalBackup), onerror=self.onError)
         else:
             for i in oldbackups[self.options["OldToKeep"] :]:
                 self.logger.logmsg("DEBUG", _("Removing old backup `%s'") % i)
                 path = os.path.join(self.options["Destination"], i)
                 shutil_modded.rmtree(encode(path), onerror=self.onError)
Exemple #39
0
  def __init__(self, treeview, statusbar, ui):
    self.treeview = treeview
    self.logger = fwlogger.getLogger()
    self.statusbar= statusbar
    self.ui = ui
    self.liststore = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING)
    # Give it columns
    cell = gtk.CellRendererToggle()
    cell.connect('toggled', self._on_toggled, self.liststore)
    cell.set_property('activatable', True)
    col = gtk.TreeViewColumn(_('Export'), cell, active=0)
    col.set_resizable(True)
    self.treeview.append_column(col)

    cell = gtk.CellRendererText()
    cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
    col = gtk.TreeViewColumn(_('Set'), cell, text=1)
    col.set_resizable(True)
    self.treeview.append_column(col)

    self.treeview.set_model(self.liststore)
    self.treeview.set_reorderable(False)
    # Just to keep things clean.
    self._clear()
Exemple #40
0
 def __init__(self, name, level=logging.DEBUG):
   """Setup the fwbackups logger, text mode"""
   logging.Logger.__init__(self, name, level)
   self.__printToo = False
   self.__functions = []
   self.__newmessages = False
   try:
     # need a handler
     loghandler = logging.FileHandler(encode(LOGLOC), 'a')
     # Create formatter & add formatter to handler
     logformatter = logging.Formatter("%(message)s")
     loghandler.setFormatter(logformatter)
     # add handler to logger
     self.addHandler(loghandler)
   except Exception, error:
     from fwbackups import fwbackupsError
     raise fwbackupsError(_('Could not set up the logger: %s' % str(error)))
def usage(error=None):
  if error:
    print _('Error: %s'  % error)
    print _('Run with --help for usage information.')
  else:
    print _("""Usage: fwbackups-run [OPTIONS] Set_Name(s)
Options:
  -v, --verbose  :  Increase verbosity (print debug messages)
  -h, --help  :  Print this message and exit
  -l, --silent  :  Print messages to log file only

Set_Name(s) is space-seperated list of set names to run backups of.""")
Exemple #42
0
 def __init__(self, name, level=logging.DEBUG):
     """Setup the fwbackups logger, text mode"""
     logging.Logger.__init__(self, name, level)
     self.__printToo = False
     self.__functions = []
     self.__newmessages = False
     try:
         # need a handler
         loghandler = logging.FileHandler(encode(LOGLOC), 'a')
         # Create formatter & add formatter to handler
         logformatter = logging.Formatter("%(message)s")
         loghandler.setFormatter(logformatter)
         # add handler to logger
         self.addHandler(loghandler)
     except Exception, error:
         from fwbackups import fwbackupsError
         raise fwbackupsError(
             _('Could not set up the logger: %s' % str(error)))
Exemple #43
0
def usage(error=None):
    if error:
        print _('Error: %s' % error)
        print _('Run with --help for usage information.')
    else:
        print _("""Usage: fwbackups-run [OPTIONS] Set_Name(s)
Options:
  -v, --verbose  :  Increase verbosity (print debug messages)
  -h, --help  :  Print this message and exit
  -l, --silent  :  Print messages to log file only
  -f, --force :  Run the backup even if the set is disabled.

Set_Name(s) is space-seperated list of set names to run backups of.""")
Exemple #44
0
 def __init__(self, setPath, logger=None, forceRun=False):
   """Initializes the automatic backup operation of set defined at setPath.
   If no logger is supplied, a new one will be created."""
   BackupOperation.__init__(self, logger)
   self.config = config.BackupSetConf(setPath)
   self.options = self.getOptions(self.config, forceEnabled=forceRun)
   # Parse backup folder format
   # date stored as class variable due to re-use in user commands later
   self.date = time.strftime('%Y-%m-%d_%H-%M')
   self.dest = os.path.join(self.options['Destination'], u"%s-%s-%s" % (_('Backup'), self.config.getSetName(), self.date))
   # set-specific options
   # IF tar || tar.gz, add .tar || tar.gz respectively to the dest since
   # the dest is to be a file, not a folder...
   if self.options['Engine'] == 'tar':
     self.dest += '.tar'
   elif self.options['Engine'] == 'tar.gz':
     self.dest += '.tar.gz'
   elif self.options['Engine'] == 'tar.bz2':
     self.dest += '.tar.bz2'
Exemple #45
0
 def backupPaths(self, paths, command):
   """Does the actual copying dirty work"""
   # this is in common
   self._current = 0
   if len(paths) == 0:
     return True
   self._total = len(paths)
   self._status = STATUS_BACKING_UP
   wasAnError = False
   if self.options['Engine'] == 'tar':
     if MSWINDOWS:
       self.logger.logmsg('INFO', _('Using %s on Windows: Cancel function will only take effect after a path has been completed.' % self.options['Engine']))
       import tarfile
       fh = tarfile.open(self.dest, 'w')
       for i in paths:
         self.ifCancel()
         self._current += 1
         self.logger.logmsg('DEBUG', _('Backing up path %(a)i/%(b)i: %(c)s' % {'a': self._current, 'b': self._total, 'c': i}))
         fh.add(i, recursive=self.options['Recursive'])
       fh.close()
     else: # not MSWINDOWS
       for i in paths:
         i = fwbackups.escapeQuotes(i, 1)
         self.ifCancel()
         self._current += 1
         self.logger.logmsg('DEBUG', _("Running command: nice -n %(a)i %(b)s '%(c)s'" % {'a': self.options['Nice'], 'b': command, 'c': i}))
         sub = fwbackups.executeSub("nice -n %i %s '%s'" % (self.options['Nice'], command, i), env=self.environment, shell=True)
         self.pids.append(sub.pid)
         self.logger.logmsg('DEBUG', _('Starting subprocess with PID %s') % sub.pid)
         # track stdout
         errors = []
         # use nonblocking I/O
         fl = fcntl.fcntl(sub.stderr, fcntl.F_GETFL)
         fcntl.fcntl(sub.stderr, fcntl.F_SETFL, fl | os.O_NONBLOCK)
         while sub.poll() in ["", None]:
           time.sleep(0.01)
           try:
             errors += sub.stderr.readline()
           except IOError, description:
             pass
         self.pids.remove(sub.pid)
         retval = sub.poll()
         self.logger.logmsg('DEBUG', _('Subprocess with PID %(a)s exited with status %(b)s' % {'a': sub.pid, 'b': retval}))
         # Something wrong?
         if retval != EXIT_STATUS_OK and retval != 2:
           wasAnError = True
           self.logger.logmsg('ERROR', 'An error occurred while backing up path \'%s\'.\nPlease check the error output below to determine if any files are incomplete or missing.' % str(i))
           self.logger.logmsg('ERROR', _('Process exited with status %(a)s. Errors: %(b)s' % {'a': retval, 'b': ''.join(errors)}))
Exemple #46
0
 def removeOldBackups(self):
   """Get list of old backups and remove them"""
   # get listing, local or remote
   if self.options['DestinationType'] == 'remote (ssh)':
     client, sftpClient = sftp.connect(self.options['RemoteHost'], self.options['RemoteUsername'], self.options['RemotePassword'], self.options['RemotePort'])
     listing = sftpClient.listdir(self.options['RemoteFolder'])
   else:
     listing = os.listdir(encode(self.options['Destination']))
   # Normalize the unicode strings storing the filenames. This fixes a problem
   # on HFS+ filesystems where supplying a set name on the command line
   # resulted in a different Unicode string than the filename of the set.
   listing = [decode(i, filename=True) for i in listing]
   listing.sort()
   oldbackups = []
   for i in listing:
     backupPrefix = '%s-%s-' % (_('Backup'), self.config.getSetName())
     if i.startswith(backupPrefix):
       oldbackups.append(i)
   # ...And remove them.
   oldbackups.reverse()
   if self.options['DestinationType'] == 'remote (ssh)':
     for i in oldbackups[self.options['OldToKeep']:]:
       remoteBackup = os.path.join(self.options['RemoteFolder'], i)
       self.logger.logmsg('DEBUG', _('Removing old backup `%(a)s\' on %(b)s') % {'a': remoteBackup, 'b': self.options['RemoteHost']})
       sftp.remove(sftpClient, remoteBackup)
     sftpClient.close()
     client.close()
   else:
     if self.options['Engine'] == 'rsync' and self.options['Incremental'] and oldbackups:
       for i in oldbackups[:-1]:
         self.logger.logmsg('DEBUG', _('Removing old backup `%s\'') % i)
         path = os.path.join(self.options['Destination'], i)
         shutil_modded.rmtree(encode(path), onerror=self.onError)
       oldIncrementalBackup = os.path.join(self.options['Destination'], oldbackups[-1])
       if not oldIncrementalBackup.endswith('.tar') and not oldIncrementalBackup.endswith('.tar.gz') and \
           not oldIncrementalBackup.endswith('.tar.bz2'): # oldIncrementalBackup = rsync
         self.logger.logmsg('DEBUG', _('Moving  `%s\' to `%s\'') % (oldIncrementalBackup, self.dest))
         shutil_modded.move(encode(oldIncrementalBackup), encode(self.dest))
       else: # source = is not a rsync backup - remove it and start fresh
         self.logger.logmsg('DEBUG', _('`%s\' is not an rsync backup - removing.') % oldIncrementalBackup)
         shutil_modded.rmtree(encode(oldIncrementalBackup), onerror=self.onError)
     else:
       for i in oldbackups[self.options['OldToKeep']:]:
         self.logger.logmsg('DEBUG', _('Removing old backup `%s\'') % i)
         path = os.path.join(self.options['Destination'], i)
         shutil_modded.rmtree(encode(path), onerror=self.onError)
Exemple #47
0
 def checkRemoteServer(self):
   """Checks if a connection to the remote server can be established"""
   self.logger.logmsg('DEBUG', _('Attempting to connect to server %s...') % self.options['RemoteHost'])
   thread = fwbackups.runFuncAsThread(sftp.testConnection,
                                      self.options['RemoteHost'], self.options['RemoteUsername'],
                                      self.options['RemotePassword'], self.options['RemotePort'],
                                      self.options['RemoteFolder'])
   while thread.retval == None:
     time.sleep(0.1)
   # Check for errors, if any
   import paramiko
   import socket
   if thread.retval == True:
     self.logger.logmsg('DEBUG', _('Attempt to connect succeeded.'))
     return True
   elif type(thread.exception) == IOError:
     self.logger.logmsg('ERROR', _('The backup destination was either not ' + \
                    'found or it cannot be written to due to insufficient permissions.'))
     return False
   elif type(thread.exception) == paramiko.AuthenticationException:
     self.logger.logmsg('ERROR', _('A connection was established, but authentication ' + \
                     'failed. Please verify the username and password ' + \
                     'and try again.'))
     return False
   elif type(thread.exception) == socket.gaierror or type(thread.exception) == socket.error:
     self.logger.logmsg('ERROR', _('A connection to the server could not be established.\n' + \
                     'Error %(a)s: %(b)s' % {'a': type(thread.exception), 'b': str(thread.exception)} + \
                     '\nPlease verify your settings and try again.'))
     return False
   elif type(thread.exception) == socket.timeout:
     self.logger.logmsg('ERROR', _('A connection to the server has timed out. ' + \
                     'Please verify your settings and try again.'))
     return False
   elif type(thread.exception) == paramiko.SSHException:
     self.logger.logmsg('ERROR', _('A connection to the server could not be established ' + \
                     'because an error occurred: %s' % str(thread.exception) + \
                     '\nPlease verify your settings and try again.'))
     return False
   else: # not remote, just pass
     return True
Exemple #48
0
                linkto = os.readlink(src_abs)
                sftp.symlink(linkto, dst_abs)
            elif os.path.isdir(src_abs):
                # run this again in the subfolder, uploading to the parent folder
                putFolder(sftp, src_abs, os.path.dirname(dst_abs), symlinks,
                          excludes)
            elif os.path.isfile(src_abs):
                sftp.put(src_abs, dst_abs)
            else:
                print _(
                    '`%s\' is not a file, folder or link! Skipping.') % src_abs
        except (IOError, os.error), reason:
            # don't halt the entire copy, just print the errors at the end
            errors.append('%s --> %s: %s' % (src_abs, dst_abs, reason))
    if errors:
        print _('Could not copy some files due to errors:')
        print '\n'.join(errors)


# Remember we wrap this in callbacks.py
def testConnection(host, username, password, port, path):
    """Tests connecting to a SSH/SFTP connection with the supplied arguments.
  Returns True if connection was successful."""
    client, sftp = connect(host, username, password, port, timeout=30)
    try:
        doesExist = isFolder(sftp, path)
    except IOError:  # Not using finally: to remain compatible with python < 2.5
        sftp.close()
        client.close()
        raise
    client.close()
Exemple #49
0
 def __init__(self, dialog, textview, parent, tracebackText):
     """Uses `dialog' to show bug report `traceback' in `textview' on top
     of `parent'"""
     GenericDia.__init__(self, dialog, _('Bug Report'), parent)
     textview.get_buffer().set_text(tracebackText)
Exemple #50
0
    def __init__(self, treeview, statusbar, ui, parent):
        self.treeview = treeview
        self.statusbar = statusbar
        self.ui = ui
        self.parent = parent
        self.logger = fwlogger.getLogger()

        # Give it columns
        cell = gtk.CellRendererPixbuf()
        col = gtk.TreeViewColumn(_('Access'), cell, stock_id=0)
        col.set_resizable(True)
        self.treeview.append_column(col)

        cell = gtk.CellRendererText()
        cell.set_property('ellipsize', pango.ELLIPSIZE_MIDDLE)
        col = gtk.TreeViewColumn(_('Path'), cell, text=1)
        col.set_resizable(True)
        self.treeview.append_column(col)

        self.liststore = gtk.ListStore(gobject.TYPE_STRING,
                                       gobject.TYPE_STRING)
        self.treeview.set_model(self.liststore)
        self.treeview.set_reorderable(False)
        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE)

        # Allow enable drag and drop of rows including row move
        #self.TARGETS = [('text/plain', 0, 1)]
        #self.treeview.enable_model_drag_dest(self.TARGETS, gtk.gdk.ACTION_DEFAULT)
        target = [('text/uri-list', 0, 0)]
        self.treeview.drag_dest_set(gtk.DEST_DEFAULT_ALL, target,
                                    gtk.gdk.ACTION_COPY)

        def escape(uri):
            "Convert each space to %20, etc"
            _to_utf8 = codecs.getencoder('utf-8')
            return re.sub('[^:-_./a-zA-Z0-9]',
                          lambda match: '%%%02x' % ord(match.group(0)),
                          _to_utf8(uri)[0])

        def unescape(uri):
            "Convert each %20 to a space, etc"
            if '%' not in uri: return uri
            return re.sub('%[0-9a-fA-F][0-9a-fA-F]',
                          lambda match: chr(int(match.group(0)[1:], 16)), uri)

        def get_local_path(uri):
            """Convert 'uri' to a local path and return, if possible. If 'uri'
      is a resource on a remote machine, return None. URI is in the escaped form
      (%20 for space)."""
            if not uri:
                return None

            if uri[0] == '/':
                if uri[1:2] != '/':
                    return unescape(uri)  # A normal Unix pathname
                i = uri.find('/', 2)
                if i == -1:
                    return None  # //something
                if i == 2:
                    if MSWINDOWS:
                        return unescape(
                            uri[3:])  # ///path - from the removal of file:///
                    else:
                        return unescape(
                            uri[2:]
                        )  # ///path - from the removal of file:// as we need / (is root)
                remote_host = uri[2:i]
                if remote_host == our_host_name():
                    return unescape(uri[i:])  # //localhost/path
                # //otherhost/path
            elif uri[:5].lower() == 'file:':
                if uri[5:6] == '/':
                    return get_local_path(uri[5:])
            elif uri[:2] == './' or uri[:3] == '../':
                return unescape(uri)
            return None

        def drag_data_received(w, context, x, y, data, info, time):
            paths = []
            if data and data.format == 8:
                for i in data.data.split('\r\n'):
                    if i != "" or i != None:
                        path = get_local_path(i)
                        if path != None:
                            paths.append(path.decode('utf-8'))
            for i in paths:
                self.add([os.path.normpath(i)],
                         self._buildListstoreIndex(self.liststore, 1))
            context.finish(True, False, time)

        self.treeview.connect('drag_data_received', drag_data_received)
        # Just to keep things clean.
        self.clear()