summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCalum Lind <calumlind+deluge@gmail.com>2013-05-21 23:45:26 +0100
committerCalum Lind <calumlind+deluge@gmail.com>2013-05-22 01:25:25 +0100
commit2c4ef9dbb306ebefcb3314b4415c736fc3b263d2 (patch)
tree384c6a210dcfed9fdda260a5f839566883cbc96d
parent2bbc1013be3a615fc29b998804f4e4bde639a9d4 (diff)
downloaddeluge-2c4ef9dbb30.zip
deluge-2c4ef9dbb30.tar.gz
deluge-2c4ef9dbb30.tar.bz2
Fixup saving and loading state files
* All state files have a backup created before saving * The backup will now be used if saving or loading fails * GTKUI state files stored in new gtkui_state dir and common load/save functions created * Detects bad shutdown and archives timestamped state files in separate config directory.
-rw-r--r--deluge/config.py4
-rw-r--r--deluge/core/authmanager.py66
-rw-r--r--deluge/core/core.py52
-rw-r--r--deluge/core/torrentmanager.py186
-rw-r--r--deluge/ui/gtkui/common.py52
-rw-r--r--deluge/ui/gtkui/files_tab.py34
-rw-r--r--deluge/ui/gtkui/gtkui.py20
-rw-r--r--deluge/ui/gtkui/listview.py35
-rw-r--r--deluge/ui/gtkui/peers_tab.py29
-rw-r--r--deluge/ui/gtkui/torrentdetails.py34
10 files changed, 283 insertions, 229 deletions
diff --git a/deluge/config.py b/deluge/config.py
index ff23169..8c963c2 100644
--- a/deluge/config.py
+++ b/deluge/config.py
@@ -486,8 +486,8 @@ what is currently in the config and it could not convert the value
# Make a backup of the old config
try:
- log.debug("Backing up old config file to %s~", filename)
- shutil.move(filename, filename + "~")
+ log.debug("Backing up old config file to %s.bak", filename)
+ shutil.move(filename, filename + ".bak")
except Exception, e:
log.warning("Unable to backup old config...")
diff --git a/deluge/core/authmanager.py b/deluge/core/authmanager.py
index f8cffbb..768d9f8 100644
--- a/deluge/core/authmanager.py
+++ b/deluge/core/authmanager.py
@@ -100,7 +100,7 @@ class AuthManager(component.Component):
def update(self):
auth_file = configmanager.get_config_dir("auth")
# Check for auth file and create if necessary
- if not os.path.exists(auth_file):
+ if not os.path.isfile(auth_file):
log.info("Authfile not found, recreating it.")
self.__load_auth_file()
return
@@ -192,36 +192,40 @@ class AuthManager(component.Component):
return True
def write_auth_file(self):
- old_auth_file = configmanager.get_config_dir("auth")
- new_auth_file = old_auth_file + '.new'
- bak_auth_file = old_auth_file + '.bak'
- # Let's first create a backup
- if os.path.exists(old_auth_file):
- shutil.copy2(old_auth_file, bak_auth_file)
+ filename = "auth"
+ filepath = os.path.join(configmanager,get_config_dir(), filename)
+ filepath_bak = filepath + ".bak"
try:
- fd = open(new_auth_file, "w")
- for account in self.__auth.values():
- fd.write(
- "%(username)s:%(password)s:%(authlevel_int)s\n" %
- account.data()
- )
- fd.flush()
- os.fsync(fd.fileno())
- fd.close()
- os.rename(new_auth_file, old_auth_file)
- except:
- # Something failed, let's restore the previous file
- if os.path.exists(bak_auth_file):
- os.rename(bak_auth_file, old_auth_file)
+ if os.path.isfile(filepath):
+ log.info("Creating backup of %s at: %s", filename, filepath_bak)
+ shutil.copy2(filepath, filepath_bak)
+ except IOError as ex:
+ log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
+ else:
+ log.info("Saving the %s at: %s", filename, filepath)
+ try:
+ with open(filepath, "wb") as _file:
+ for account in self.__auth.values():
+ _file.write("%(username)s:%(password)s:%(authlevel_int)s\n" % account.data())
+ _file.flush()
+ os.fsync(_file.fileno())
+ except (IOError) as ex:
+ log.error("Unable to save %s: %s", filename, ex)
+ if os.path.isfile(filepath_bak):
+ log.info("Restoring backup of %s from: %s", filename, filepath_bak)
+ shutil.move(filepath_bak, filepath)
self.__load_auth_file()
def __load_auth_file(self):
save_and_reload = False
- auth_file = configmanager.get_config_dir("auth")
+ filename = "auth"
+ auth_file = configmanager.get_config_dir(filename)
+ auth_file_bak = auth_file + ".bak"
+
# Check for auth file and create if necessary
- if not os.path.exists(auth_file):
+ if not os.path.isfile(auth_file):
create_localclient_account()
return self.__load_auth_file()
@@ -232,10 +236,20 @@ class AuthManager(component.Component):
# File didn't change, no need for re-parsing's
return
- # Load the auth file into a dictionary: {username: Account(...)}
- f = open(auth_file, "r").readlines()
+ for _filepath in (auth_file, auth_file_bak):
+ log.info("Opening %s for load: %s", filename, _filepath)
+ try:
+ with open(_filepath, "rb") as _file:
+ file_data = _file.readlines()
+ except (IOError), ex:
+ log.warning("Unable to load %s: %s", _filepath, ex)
+ file_data = []
+ else:
+ log.info("Successfully loaded %s: %s", filename, _filepath)
+ break
- for line in f:
+ # Load the auth file into a dictionary: {username: Account(...)}
+ for line in file_data:
line = line.strip()
if line.startswith("#") or not line:
# This line is a comment or empty
diff --git a/deluge/core/core.py b/deluge/core/core.py
index f971565..6b6757d 100644
--- a/deluge/core/core.py
+++ b/deluge/core/core.py
@@ -38,6 +38,7 @@ from deluge._libtorrent import lt
import os
import glob
+import shutil
import base64
import logging
import threading
@@ -50,7 +51,7 @@ import twisted.web.error
from deluge.httpdownloader import download_file
from deluge import path_chooser_common
-import deluge.configmanager
+from deluge.configmanager import ConfigManager, get_config_dir
import deluge.common
import deluge.component as component
from deluge.event import *
@@ -120,7 +121,7 @@ class Core(component.Component):
self.new_release = None
# Get the core config
- self.config = deluge.configmanager.ConfigManager("core.conf")
+ self.config = ConfigManager("core.conf")
self.config.save()
# If there was an interface value from the command line, use it, but
@@ -153,19 +154,46 @@ class Core(component.Component):
def __save_session_state(self):
"""Saves the libtorrent session state"""
+ filename = "session.state"
+ filepath = get_config_dir(filename)
+ filepath_bak = filepath + ".bak"
+
try:
- session_state = deluge.configmanager.get_config_dir("session.state")
- open(session_state, "wb").write(lt.bencode(self.session.save_state()))
- except Exception, e:
- log.warning("Failed to save lt state: %s", e)
+ if os.path.isfile(filepath):
+ log.info("Creating backup of %s at: %s", filename, filepath_bak)
+ shutil.copy2(filepath, filepath_bak)
+ except IOError as ex:
+ log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
+ else:
+ log.info("Saving the %s at: %s", filename, filepath)
+ try:
+ with open(filepath, "wb") as _file:
+ _file.write(lt.bencode(self.session.save_state()))
+ _file.flush()
+ os.fsync(_file.fileno())
+ except (IOError, EOFError) as ex:
+ log.error("Unable to save %s: %s", filename, ex)
+ if os.path.isfile(filepath_bak):
+ log.info("Restoring backup of %s from: %s", filename, filepath_bak)
+ shutil.move(filepath_bak, filepath)
def __load_session_state(self):
"""Loads the libtorrent session state"""
- try:
- session_state = deluge.configmanager.get_config_dir("session.state")
- self.session.load_state(lt.bdecode(open(session_state, "rb").read()))
- except Exception, e:
- log.warning("Failed to load lt state: %s", e)
+ filename = "session.state"
+ filepath = get_config_dir(filename)
+ filepath_bak = filepath + ".bak"
+
+ for _filepath in (filepath, filepath_bak):
+ log.info("Opening %s for load: %s", filename, _filepath)
+ try:
+ with open(_filepath, "rb") as _file:
+ state = lt.bdecode(_file.read())
+ except (IOError, EOFError, RuntimeError), ex:
+ log.warning("Unable to load %s: %s", _filepath, ex)
+ else:
+ log.info("Successfully loaded %s: %s", filename, _filepath)
+ self.session.load_state(state)
+ return
def get_new_release(self):
log.debug("get_new_release")
@@ -679,7 +707,7 @@ class Core(component.Component):
log.exception(e)
return
- f = open(os.path.join(deluge.configmanager.get_config_dir(), "plugins", filename), "wb")
+ f = open(os.path.join(get_config_dir(), "plugins", filename), "wb")
f.write(filedump)
f.close()
component.get("CorePluginManager").scan_for_plugins()
diff --git a/deluge/core/torrentmanager.py b/deluge/core/torrentmanager.py
index 884e588..a2f2a42 100644
--- a/deluge/core/torrentmanager.py
+++ b/deluge/core/torrentmanager.py
@@ -144,8 +144,9 @@ class TorrentManager(component.Component):
self.config = ConfigManager("core.conf")
# Make sure the state folder has been created
- if not os.path.exists(os.path.join(get_config_dir(), "state")):
- os.makedirs(os.path.join(get_config_dir(), "state"))
+ self.state_dir = os.path.join(get_config_dir(), "state")
+ if not os.path.exists(self.state_dir):
+ os.makedirs(self.state_dir)
# Create the torrents dict { torrent_id: Torrent }
self.torrents = {}
@@ -212,6 +213,34 @@ class TorrentManager(component.Component):
# Get the pluginmanager reference
self.plugins = component.get("CorePluginManager")
+ # Check for temp file
+ self.temp_file = os.path.join(self.state_dir, ".safe_state_check")
+ if os.path.isfile(self.temp_file):
+ def archive_file(filename):
+ import datetime
+ filepath = os.path.join(self.state_dir, filename)
+ filepath_bak = state_filepath + ".bak"
+ archive_dir = os.path.join(get_config_dir(), "archive")
+ if not os.path.exists(archive_dir):
+ os.makedirs(archive_dir)
+
+ for _filepath in (filepath, filepath_bak):
+ timestamp = datetime.datetime.now().replace(microsecond=0).isoformat().replace(':', '-')
+ archive_filepath = os.path.join(archive_dir, filename + "-" + timestamp)
+ try:
+ shutil.copy2(_filepath, archive_filepath)
+ except IOError:
+ log.error("Unable to archive: %s", filename)
+ else:
+ log.info("Archive of %s successful: %s", filename, archive_filepath)
+
+ log.warning("Potential bad shutdown of Deluge detected, archiving torrent state files...")
+ archive_file("torrents.state")
+ archive_file("torrents.fastresume")
+ else:
+ with file(self.temp_file, 'a'):
+ os.utime(self.temp_file, None)
+
# Run the old state upgrader before loading state
deluge.core.oldstateupgrader.OldStateUpgrader()
@@ -246,7 +275,13 @@ class TorrentManager(component.Component):
# Stop the status cleanup LoopingCall here
self.torrents[key].prev_status_cleanup_loop.stop()
- return self.save_resume_data(self.torrents.keys())
+ def remove_temp_file(result):
+ if result and os.path.isfile(self.temp_file):
+ os.remove(self.temp_file)
+
+ d = self.save_resume_data(self.torrents.keys())
+ d.addCallback(remove_temp_file)
+ return d
def update(self):
for torrent_id, torrent in self.torrents.items():
@@ -301,8 +336,7 @@ class TorrentManager(component.Component):
"""Returns an entry with the resume data or None"""
fastresume = ""
try:
- _file = open(os.path.join(get_config_dir(), "state",
- torrent_id + ".fastresume"), "rb")
+ _file = open(os.path.join(self.state_dir, torrent_id + ".fastresume"), "rb")
fastresume = _file.read()
_file.close()
except IOError, e:
@@ -312,8 +346,7 @@ class TorrentManager(component.Component):
def legacy_delete_resume_data(self, torrent_id):
"""Deletes the .fastresume file"""
- path = os.path.join(get_config_dir(), "state",
- torrent_id + ".fastresume")
+ path = os.path.join(self.state_dir, torrent_id + ".fastresume")
log.debug("Deleting fastresume file: %s", path)
try:
os.remove(path)
@@ -501,9 +534,7 @@ class TorrentManager(component.Component):
# Write the .torrent file to the state directory
if filedump:
try:
- save_file = open(os.path.join(get_config_dir(), "state",
- torrent.torrent_id + ".torrent"),
- "wb")
+ save_file = open(os.path.join(self.state_dir, torrent.torrent_id + ".torrent"), "wb")
save_file.write(filedump)
save_file.close()
except IOError, e:
@@ -546,10 +577,7 @@ class TorrentManager(component.Component):
# Get the torrent data from the torrent file
try:
log.debug("Attempting to open %s for add.", torrent_id)
- _file = open(
- os.path.join(
- get_config_dir(), "state", torrent_id + ".torrent"),
- "rb")
+ _file = open(os.path.join(self.state_dir, torrent_id + ".torrent"), "rb")
filedump = lt.bdecode(_file.read())
_file.close()
except (IOError, RuntimeError), e:
@@ -636,16 +664,24 @@ class TorrentManager(component.Component):
def load_state(self):
"""Load the state of the TorrentManager from the torrents.state file"""
- state = TorrentManagerState()
+ filename = "torrents.state"
+ filepath = os.path.join(self.state_dir, filename)
+ filepath_bak = filepath + ".bak"
- try:
- log.debug("Opening torrent state file for load.")
- state_file = open(
- os.path.join(get_config_dir(), "state", "torrents.state"), "rb")
- state = cPickle.load(state_file)
- state_file.close()
- except (EOFError, IOError, Exception, cPickle.UnpicklingError), e:
- log.warning("Unable to load state file: %s", e)
+ for _filepath in (filepath, filepath_bak):
+ log.info("Opening %s for load: %s", filename, _filepath)
+ try:
+ with open(_filepath, "rb") as _file:
+ state = cPickle.load(_file)
+ except (IOError, EOFError, cPickle.UnpicklingError), ex:
+ log.warning("Unable to load %s: %s", _filepath, ex)
+ state = None
+ else:
+ log.info("Successfully loaded %s: %s", filename, _filepath)
+ break
+
+ if state is None:
+ state = TorrentManagerState()
# Try to use an old state
try:
@@ -727,28 +763,29 @@ class TorrentManager(component.Component):
)
state.torrents.append(torrent_state)
- # Pickle the TorrentManagerState object
- try:
- log.debug("Saving torrent state file.")
- state_file = open(os.path.join(get_config_dir(),
- "state", "torrents.state.new"), "wb")
- cPickle.dump(state, state_file)
- state_file.flush()
- os.fsync(state_file.fileno())
- state_file.close()
- except IOError, e:
- log.warning("Unable to save state file: %s", e)
- return True
+ filename = "torrents.state"
+ filepath = os.path.join(self.state_dir, filename)
+ filepath_bak = filepath + ".bak"
- # We have to move the 'torrents.state.new' file to 'torrents.state'
try:
- shutil.move(
- os.path.join(get_config_dir(), "state", "torrents.state.new"),
- os.path.join(get_config_dir(), "state", "torrents.state"))
- except IOError:
- log.warning("Unable to save state file.")
- return True
-
+ if os.path.isfile(filepath):
+ log.info("Creating backup of %s at: %s", filename, filepath_bak)
+ shutil.copy2(filepath, filepath_bak)
+ except IOError as ex:
+ log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
+ else:
+ log.info("Saving the %s at: %s", filename, filepath)
+ try:
+ with open(filepath, "wb") as _file:
+ # Pickle the TorrentManagerState object
+ cPickle.dump(state, _file)
+ _file.flush()
+ os.fsync(_file.fileno())
+ except (IOError, cPickle.PicklingError) as ex:
+ log.error("Unable to save %s: %s", filename, ex)
+ if os.path.isfile(filepath_bak):
+ log.info("Restoring backup of %s from: %s", filename, filepath_bak)
+ shutil.move(filepath_bak, filepath)
# We return True so that the timer thread will continue
return True
@@ -760,7 +797,6 @@ class TorrentManager(component.Component):
:returns: A Deferred whose callback will be invoked when save is complete
:rtype: twisted.internet.defer.Deferred
"""
-
if torrent_ids is None:
torrent_ids = (t[0] for t in self.torrents.iteritems() if t[1].handle.need_save_resume_data())
@@ -779,43 +815,63 @@ class TorrentManager(component.Component):
def on_all_resume_data_finished(result):
if result:
- self.save_resume_data_file()
+ if self.save_resume_data_file():
+ return True
return DeferredList(deferreds).addBoth(on_all_resume_data_finished)
def load_resume_data_file(self):
- resume_data = {}
- try:
- log.debug("Opening torrents fastresume file for load.")
- fastresume_file = open(os.path.join(get_config_dir(), "state",
- "torrents.fastresume"), "rb")
- resume_data = lt.bdecode(fastresume_file.read())
- fastresume_file.close()
- except (EOFError, IOError, Exception), e:
- log.warning("Unable to load fastresume file: %s", e)
+ filename = "torrents.fastresume"
+ filepath = os.path.join(self.state_dir, filename)
+ filepath_bak = filepath + ".bak"
+ old_data_filepath = os.path.join(get_config_dir(), filename)
+ for _filepath in (filepath, filepath_bak, old_data_filepath):
+ log.info("Opening %s for load: %s", filename, _filepath)
+ try:
+ with open(_filepath, "rb") as _file:
+ resume_data = lt.bdecode(_file.read())
+ except (IOError, EOFError, RuntimeError), ex:
+ log.warning("Unable to load %s: %s", _filepath, ex)
+ resume_data = None
+ else:
+ log.info("Successfully loaded %s: %s", filename, _filepath)
+ break
# If the libtorrent bdecode doesn't happen properly, it will return None
# so we need to make sure we return a {}
if resume_data is None:
return {}
-
- return resume_data
+ else:
+ return resume_data
def save_resume_data_file(self):
"""
Saves the resume data file with the contents of self.resume_data.
"""
- path = os.path.join(get_config_dir(), "state", "torrents.fastresume")
+ filename = "torrents.fastresume"
+ filepath = os.path.join(self.state_dir, filename)
+ filepath_bak = filepath + ".bak"
try:
- log.debug("Saving fastresume file: %s", path)
- fastresume_file = open(path, "wb")
- fastresume_file.write(lt.bencode(self.resume_data))
- fastresume_file.flush()
- os.fsync(fastresume_file.fileno())
- fastresume_file.close()
- except IOError:
- log.warning("Error trying to save fastresume file")
+ if os.path.isfile(filepath):
+ log.info("Creating backup of %s at: %s", filename, filepath_bak)
+ shutil.copy2(filepath, filepath_bak)
+ except IOError as ex:
+ log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
+ else:
+ log.info("Saving the %s at: %s", filename, filepath)
+ try:
+ with open(filepath, "wb") as _file:
+ _file.write(lt.bencode(self.session.save_state()))
+ _file.flush()
+ os.fsync(_file.fileno())
+ except (IOError, EOFError) as ex:
+ log.error("Unable to save %s: %s", filename, ex)
+ if os.path.isfile(filepath_bak):
+ log.info("Restoring backup of %s from: %s", filename, filepath_bak)
+ shutil.move(filepath_bak, filepath)
+ else:
+ return True
def get_queue_position(self, torrent_id):
"""Get queue position of torrent"""
diff --git a/deluge/ui/gtkui/common.py b/deluge/ui/gtkui/common.py
index 0882238..1c31453 100644
--- a/deluge/ui/gtkui/common.py
+++ b/deluge/ui/gtkui/common.py
@@ -41,6 +41,8 @@ import pygtk
pygtk.require('2.0')
import gtk
import logging
+import cPickle
+import shutil
import deluge.component as component
import deluge.common
@@ -264,3 +266,53 @@ def associate_magnet_links(overwrite=False):
log.error("Unable to register Deluge as default magnet uri handler.")
return False
return False
+
+def save_pickled_state_file(filename, state):
+ """Save a file in the config directory and creates a backup
+ filename: Filename to be saved to config
+ state: The data to be pickled and written to file
+ """
+ from deluge.configmanager import get_config_dir
+ filepath = os.path.join(get_config_dir(), "gtkui_state", filename)
+ filepath_bak = filepath + ".bak"
+
+ try:
+ if os.path.isfile(filepath):
+ log.info("Creating backup of %s at: %s", filename, filepath_bak)
+ shutil.copy2(filepath, filepath_bak)
+ except IOError as ex:
+ log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex)
+ else:
+ log.info("Saving the %s at: %s", filename, filepath)
+ try:
+ with open(filepath, "wb") as _file:
+ # Pickle the state object
+ cPickle.dump(state, _file)
+ _file.flush()
+ os.fsync(_file.fileno())
+ except (IOError, EOFError, cPickle.PicklingError) as ex:
+ log.error("Unable to save %s: %s", filename, ex)
+ if os.path.isfile(filepath_bak):
+ log.info("Restoring backup of %s from: %s", filename, filepath_bak)
+ shutil.move(filepath_bak, filepath)
+
+def load_pickled_state_file(filename):
+ """Loads a file from the config directory, attempting backup if original fails to load.
+ filename: Filename to be loaded from config
+ returns unpickled state
+ """
+ from deluge.configmanager import get_config_dir
+ filepath = os.path.join(get_config_dir(), "gtkui_state", filename)
+ filepath_bak = filepath + ".bak"
+ old_data_filepath = os.path.join(get_config_dir(), filename)
+
+ for _filepath in (filepath, filepath_bak, old_data_filepath):
+ log.info("Opening %s for load: %s", filename, _filepath)
+ try:
+ with open(_filepath, "rb") as _file:
+ state = cPickle.load(_file)
+ except (IOError, cPickle.UnpicklingError), ex:
+ log.warning("Unable to load %s: %s", _filepath, ex)
+ else:
+ log.info("Successfully loaded %s: %s", filename, _filepath)
+ return state
diff --git a/deluge/ui/gtkui/files_tab.py b/deluge/ui/gtkui/files_tab.py
index 82f8ec5..5fa36c4 100644
--- a/deluge/ui/gtkui/files_tab.py
+++ b/deluge/ui/gtkui/files_tab.py
@@ -38,15 +38,14 @@ import gtk
import gtk.gdk
import gobject
import os.path
-import cPickle
import logging
+import cPickle
from deluge.ui.gtkui.torrentdetails import Tab
from deluge.ui.client import client
-import deluge.configmanager
import deluge.component as component
import deluge.common
-import common
+from deluge.ui.gtkui.common import reparent_iter, save_pickled_state_file, load_pickled_state_file
log = logging.getLogger(__name__)
@@ -242,7 +241,6 @@ class FilesTab(Tab):
getattr(widget, attr)()
def save_state(self):
- filename = "files_tab.state"
# Get the current sort order of the view
column_id, sort_order = self.treestore.get_sort_column_id()
@@ -259,30 +257,10 @@ class FilesTab(Tab):
"width": column.get_width()
}
- # Get the config location for saving the state file
- config_location = deluge.configmanager.get_config_dir()
-
- try:
- log.debug("Saving FilesTab state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "wb")
- cPickle.dump(state, state_file)
- state_file.close()
- except IOError, e:
- log.warning("Unable to save state file: %s", e)
+ save_pickled_state_file("files_tab.state", state)
def load_state(self):
- filename = "files_tab.state"
- # Get the config location for loading the state file
- config_location = deluge.configmanager.get_config_dir()
- state = None
-
- try:
- log.debug("Loading FilesTab state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "rb")
- state = cPickle.load(state_file)
- state_file.close()
- except (EOFError, IOError, AttributeError, cPickle.UnpicklingError), e:
- log.warning("Unable to load state file: %s", e)
+ state = load_pickled_state_file("files_tabs.state")
if state == None:
return
@@ -807,14 +785,14 @@ class FilesTab(Tab):
return
if new_folder_iter:
# This means that a folder by this name already exists
- common.reparent_iter(self.treestore, self.treestore.iter_children(old_folder_iter), new_folder_iter)
+ reparent_iter(self.treestore, self.treestore.iter_children(old_folder_iter), new_folder_iter)
else:
parent = old_folder_iter_parent
for ns in new_split[:-1]:
parent = self.treestore.append(parent, [ns + "/", 0, "", 0, 0, -1, gtk.STOCK_DIRECTORY])
self.treestore[old_folder_iter][0] = new_split[-1] + "/"
- common.reparent_iter(self.treestore, old_folder_iter, parent)
+ reparent_iter(self.treestore, old_folder_iter, parent)
# We need to check if the old_folder_iter_parent no longer has children
# and if so, we delete it
diff --git a/deluge/ui/gtkui/gtkui.py b/deluge/ui/gtkui/gtkui.py
index 28b892d..f4ed2be 100644
--- a/deluge/ui/gtkui/gtkui.py
+++ b/deluge/ui/gtkui/gtkui.py
@@ -40,6 +40,7 @@ gobject.set_prgname("deluge")
from twisted.internet import gtk2reactor
reactor = gtk2reactor.install()
+import os
import gtk
import sys
import logging
@@ -71,14 +72,13 @@ from queuedtorrents import QueuedTorrents
from addtorrentdialog import AddTorrentDialog
from deluge.ui.sessionproxy import SessionProxy
import dialogs
-import common
-
-import deluge.configmanager
+from deluge.ui.gtkui.common import associate_magnet_links
+from deluge.configmanager import ConfigManager, get_config_dir
import deluge.common
import deluge.error
-
from deluge.ui.ui import _UI
+
class Gtk(_UI):
help = """Starts the Deluge GTK+ interface"""
@@ -90,6 +90,7 @@ class Gtk(_UI):
super(Gtk, self).start()
GtkUI(self.args)
+
def start():
Gtk().start()
@@ -152,6 +153,7 @@ DEFAULT_PREFS = {
"focus_main_window_on_add": True,
}
+
class GtkUI(object):
def __init__(self, args):
self.daemon_bps = (0,0,0)
@@ -192,10 +194,14 @@ class GtkUI(object):
# Attempt to register a magnet URI handler with gconf, but do not overwrite
# if already set by another program.
- common.associate_magnet_links(False)
+ associate_magnet_links(False)
# Make sure gtkui.conf has at least the defaults set
- self.config = deluge.configmanager.ConfigManager("gtkui.conf", DEFAULT_PREFS)
+ self.config = ConfigManager("gtkui.conf", DEFAULT_PREFS)
+
+ # Make sure the gtkui state folder has been created
+ if not os.path.exists(os.path.join(get_config_dir(), "gtkui_state")):
+ os.makedirs(os.path.join(get_config_dir(), "gtkui_state"))
# We need to check on exit if it was started in classic mode to ensure we
# shutdown the daemon.
@@ -370,7 +376,7 @@ Please see the details below for more information."), details=traceback.format_e
if self.config["autostart_localhost"] and host in ("localhost", "127.0.0.1"):
log.debug("Autostarting localhost:%s", host)
try_connect = client.start_daemon(
- port, deluge.configmanager.get_config_dir()
+ port, get_config_dir()
)
log.debug("Localhost started: %s", try_connect)
if not try_connect:
diff --git a/deluge/ui/gtkui/listview.py b/deluge/ui/gtkui/listview.py
index 07af28b..07f45d1 100644
--- a/deluge/ui/gtkui/listview.py
+++ b/deluge/ui/gtkui/listview.py
@@ -34,19 +34,13 @@
#
#
-
-import cPickle
-import os.path
import logging
-
import pygtk
pygtk.require('2.0')
import gtk
-import gettext
-from deluge.configmanager import ConfigManager
-import deluge.configmanager
import deluge.common
+from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_file
from gobject import signal_new, SIGNAL_RUN_LAST, TYPE_NONE
from gtk import gdk
@@ -333,34 +327,11 @@ class ListView:
state.append(self.create_column_state(column, counter))
state += self.removed_columns_state
-
- # Get the config location for saving the state file
- config_location = deluge.configmanager.get_config_dir()
-
- try:
- log.debug("Saving ListView state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "wb")
- cPickle.dump(state, state_file)
- state_file.close()
- except IOError, e:
- log.warning("Unable to save state file: %s", e)
+ save_pickled_state_file(filename, state)
def load_state(self, filename):
"""Load the listview state from filename."""
- # Get the config location for loading the state file
- config_location = deluge.configmanager.get_config_dir()
- state = None
-
- try:
- log.debug("Loading ListView state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "rb")
- state = cPickle.load(state_file)
- state_file.close()
- except (EOFError, IOError, cPickle.UnpicklingError), e:
- log.warning("Unable to load state file: %s", e)
-
- # Keep the state in self.state so we can access it as we add new columns
- self.state = state
+ self.state = load_pickled_state_file(filename)
def set_treeview(self, treeview_widget):
"""Set the treeview widget that this listview uses."""
diff --git a/deluge/ui/gtkui/peers_tab.py b/deluge/ui/gtkui/peers_tab.py
index e3adde3..5efbaa3 100644
--- a/deluge/ui/gtkui/peers_tab.py
+++ b/deluge/ui/gtkui/peers_tab.py
@@ -36,16 +36,15 @@
import gtk
import logging
import os.path
-import cPickle
from itertools import izip
from deluge.ui.client import client
-import deluge.configmanager
import deluge.component as component
import deluge.common
from deluge.ui.gtkui.listview import cell_data_speed as cell_data_speed
from deluge.ui.gtkui.torrentdetails import Tab
from deluge.ui.countries import COUNTRIES
+from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_file
log = logging.getLogger(__name__)
@@ -171,7 +170,6 @@ class PeersTab(Tab):
self.torrent_id = None
def save_state(self):
- filename = "peers_tab.state"
# Get the current sort order of the view
column_id, sort_order = self.liststore.get_sort_column_id()
@@ -187,31 +185,10 @@ class PeersTab(Tab):
"position": index,
"width": column.get_width()
}
-
- # Get the config location for saving the state file
- config_location = deluge.configmanager.get_config_dir()
-
- try:
- log.debug("Saving FilesTab state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "wb")
- cPickle.dump(state, state_file)
- state_file.close()
- except IOError, e:
- log.warning("Unable to save state file: %s", e)
+ save_pickled_state_file("peers_tab.state", state)
def load_state(self):
- filename = "peers_tab.state"
- # Get the config location for loading the state file
- config_location = deluge.configmanager.get_config_dir()
- state = None
-
- try:
- log.debug("Loading PeersTab state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "rb")
- state = cPickle.load(state_file)
- state_file.close()
- except (EOFError, IOError, AttributeError, cPickle.UnpicklingError), e:
- log.warning("Unable to load state file: %s", e)
+ state = load_pickled_state_file("peers_tabs.state")
if state == None:
return
diff --git a/deluge/ui/gtkui/torrentdetails.py b/deluge/ui/gtkui/torrentdetails.py
index 2d836c6..3de609d 100644
--- a/deluge/ui/gtkui/torrentdetails.py
+++ b/deluge/ui/gtkui/torrentdetails.py
@@ -37,15 +37,11 @@
"""The torrent details component shows info about the selected torrent."""
import gtk
-import os
-import os.path
-import cPickle
import logging
import deluge.component as component
from deluge.ui.client import client
-from deluge.configmanager import ConfigManager
-import deluge.configmanager
+from deluge.ui.gtkui.common import save_pickled_state_file, load_pickled_state_file
log = logging.getLogger(__name__)
@@ -411,8 +407,6 @@ class TorrentDetails(component.Component):
def save_state(self):
"""We save the state, which is basically the tab_index list"""
- filename = "tabs.state"
-
#Update the visiblity status of all tabs
#Leave tabs we dont know anything about it the state as they
#might come from a plugin
@@ -423,29 +417,7 @@ class TorrentDetails(component.Component):
log.debug("Set to %s %d" % self.state[i])
state = self.state
- # Get the config location for saving the state file
- config_location = deluge.configmanager.get_config_dir()
-
- try:
- log.debug("Saving TorrentDetails state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "wb")
- cPickle.dump(state, state_file)
- state_file.close()
- except IOError, e:
- log.warning("Unable to save state file: %s", e)
+ save_pickled_state_file("tabs.state", state)
def load_state(self):
- filename = "tabs.state"
- # Get the config location for loading the state file
- config_location = deluge.configmanager.get_config_dir()
- state = None
-
- try:
- log.debug("Loading TorrentDetails state file: %s", filename)
- state_file = open(os.path.join(config_location, filename), "rb")
- state = cPickle.load(state_file)
- state_file.close()
- except (EOFError, IOError, cPickle.UnpicklingError), e:
- log.warning("Unable to load state file: %s", e)
-
- return state
+ return load_pickled_state_file("tabs.state")