conduit r1373 - in trunk: . conduit conduit/dataproviders conduit/modules/FileModule test/python-tests test/python-tests/data



Author: jstowers
Date: Fri Mar 14 04:24:05 2008
New Revision: 1373
URL: http://svn.gnome.org/viewvc/conduit?rev=1373&view=rev

Log:
2008-03-14  John Stowers  <john stowers gmail com>

	* conduit/Vfs.py:
	* test/python-tests/TestCoreVfs.py: Add functions (and tests) for getting 
	the root uri for a removable volume.
	
	* conduit/dataproviders/File.py:
	* conduit/modules/FileModule/FileModule.py: Save the sync groups relative
	path and group name if it is stored on a removable volume. When a removable
	volume is inserted, check for this information and create a preconfigured
	folder dataprovider. Fixes #511691
	
	* test/python-tests/TestDataProviderFolder.py:
	* test/python-tests/data/folder.list: Tests for above.



Added:
   trunk/test/python-tests/TestDataProviderFolder.py
   trunk/test/python-tests/data/folder.list
Modified:
   trunk/ChangeLog
   trunk/NEWS
   trunk/conduit/Vfs.py
   trunk/conduit/dataproviders/File.py
   trunk/conduit/modules/FileModule/FileModule.py
   trunk/test/python-tests/TestCoreVfs.py

Modified: trunk/NEWS
==============================================================================
--- trunk/NEWS	(original)
+++ trunk/NEWS	Fri Mar 14 04:24:05 2008
@@ -3,6 +3,9 @@
 * You can now specify your own labels when saving emails
 * Removed the build dependency on dbus, just check for python-dbus > 0.80.0
 * Restore the expanded columns in the data provider pane
+* Improved removable volume support (like USB keys). Now, inserting a USB
+  key that has been synchronized on another computer will automatically create 
+  a preconfigured dataprovider for synchronizing the folders of interest.
 
 NEW in 0.3.8:
 ==============

Modified: trunk/conduit/Vfs.py
==============================================================================
--- trunk/conduit/Vfs.py	(original)
+++ trunk/conduit/Vfs.py	Fri Mar 14 04:24:05 2008
@@ -27,6 +27,40 @@
     APP = "gnome-open"
     os.spawnlp(os.P_NOWAIT, APP, APP, uri)
     
+def uri_to_local_path(uri):
+    """
+    @returns: The local path (/foo/bar) for the given URI. Throws a 
+    RuntimeError (wtf??) if the uri is not a local one    
+    """
+    return gnomevfs.get_local_path_from_uri(uri)
+    
+def uri_get_volume_root_uri(uri):
+    """
+    @returns: The root path of the volume at the given uri, or None
+    """
+    try:
+        path = uri_to_local_path(uri)
+        return VolumeMonitor().get_volume_for_path(path).get_activation_uri()
+    except:
+        return None
+    
+def uri_is_on_removable_volume(uri):
+    """
+    @returns: True if the specified uri is on a removable volume, like a USB key
+    or removable/mountable disk.
+    """
+    #HACKISH
+    #return uri.count("/media/") != 0
+    scheme = gnomevfs.get_uri_scheme(uri)
+    if scheme == "file":
+        try:
+            path = uri_to_local_path(uri)
+            return VolumeMonitor().get_volume_for_path(path).is_user_visible()
+        except:
+            return False
+    return False
+    
+    
 def uri_get_filesystem_type(uri):
     """
     @returns: The filesystem that uri is stored on or None if it cannot
@@ -35,7 +69,7 @@
     scheme = gnomevfs.get_uri_scheme(uri)
     if scheme == "file":
         try:
-            path = gnomevfs.get_local_path_from_uri(uri)
+            path = uri_to_local_path(uri)
             volume = VolumeMonitor().get_volume_for_path(path)
             return  volume.get_filesystem_type()
         except RuntimeError:
@@ -124,6 +158,16 @@
         log.warn("Error checking if location exists")
         return False
         
+def uri_make_directory(uri):
+    """
+    Makes a directory with the default permissions. Does not catch any
+    error
+    """
+    gnomevfs.make_directory(
+            uri,
+            gnomevfs.PERM_USER_ALL | gnomevfs.PERM_GROUP_READ | gnomevfs.PERM_GROUP_EXEC | gnomevfs.PERM_OTHER_READ | gnomevfs.PERM_OTHER_EXEC
+            )
+        
 def uri_make_directory_and_parents(uri):
     """
     Because gnomevfs.make_dir does not perform as mkdir -p this function
@@ -144,10 +188,7 @@
     dirs.reverse()
     for d in dirs:
         log.debug("Making directory %s" % d)
-        gnomevfs.make_directory(
-            d,
-            gnomevfs.PERM_USER_ALL | gnomevfs.PERM_GROUP_READ | gnomevfs.PERM_GROUP_EXEC | gnomevfs.PERM_OTHER_READ | gnomevfs.PERM_OTHER_EXEC
-            )
+        uri_make_directory(d)
 
 #
 # For monitoring locations

Modified: trunk/conduit/dataproviders/File.py
==============================================================================
--- trunk/conduit/dataproviders/File.py	(original)
+++ trunk/conduit/dataproviders/File.py	Fri Mar 14 04:24:05 2008
@@ -1,5 +1,6 @@
 import os.path
 import logging
+import ConfigParser
 log = logging.getLogger("dataproviders.File")
 
 import conduit
@@ -13,6 +14,59 @@
 TYPE_FILE = "0"
 TYPE_FOLDER = "1"
 
+def is_on_removable_volume(folderUri):
+    return Vfs.uri_is_on_removable_volume(folderUri)
+    
+def get_removable_volume_info(folderUri):
+    """
+    Returns the root uri of the volume, and local path of the 
+    group config file
+    """
+    rooturi = Vfs.uri_get_volume_root_uri(folderUri)
+    path = Vfs.uri_join(
+                Vfs.uri_to_local_path(rooturi),
+                ".conduit")
+    return rooturi,path
+    
+def save_removable_volume_group_file(folderUri, folderGroupName):
+    if is_on_removable_volume(folderUri):
+        #write to the /volume/root/.conduit file
+        rooturi,path = get_removable_volume_info(folderUri)
+        fp = open(path, "w+r")
+        conf = ConfigParser.SafeConfigParser()
+        conf.readfp(fp)
+        #save the relative path, and the group name
+        #in INI format
+        #
+        #[DEFAULT]
+        #relative/uri/from/volume/root = group name
+        #
+        log.debug("Saving group (%s = %s) to %s" % (folderUri,folderGroupName,path))
+        conf.set(
+            "DEFAULT",
+            folderUri.replace(rooturi,""),
+            folderGroupName
+            )
+        conf.write(fp)
+        fp.close()
+        return True
+    return False
+
+def read_removable_volume_group_file(folderUri):
+    if is_on_removable_volume(folderUri):
+        #read from the /volume/root/.conduit file
+        rooturi,path = get_removable_volume_info(folderUri)
+        if Vfs.uri_exists(path):
+            conf = ConfigParser.SafeConfigParser()
+            fp = open(path, "r")
+            conf.readfp(fp)
+            items = conf.items("DEFAULT")
+            fp.close()                
+            for i,j in items:
+                log.debug("Read group (%s = %s)" % (i,j))
+            return items
+    return ()
+
 class FileSource(DataProvider.DataSource, Vfs.FolderScannerThreadManager):
 
     _category_ = conduit.dataproviders.CATEGORY_FILES
@@ -172,7 +226,7 @@
         self.compareIgnoreMtime = compareIgnoreMtime
 
         self.files = []
-
+        
     def initialize(self):
         return True
 
@@ -261,6 +315,8 @@
     def finish(self, aborted, error, conflict):
         DataProvider.TwoWay.finish(self)
         self.files = []
+        #Save the .group file to the root of this volume (if it is removable)
+        save_removable_volume_group_file(self.folder, self.folderGroupName)
 
     def add(self, LUID):
         f = File.File(URI=LUID)

Modified: trunk/conduit/modules/FileModule/FileModule.py
==============================================================================
--- trunk/conduit/modules/FileModule/FileModule.py	(original)
+++ trunk/conduit/modules/FileModule/FileModule.py	Fri Mar 14 04:24:05 2008
@@ -15,7 +15,7 @@
 MODULES = {
 	"FileSource" :              { "type": "dataprovider" },
 	"FolderTwoWay" :            { "type": "dataprovider" },
-#    "RemovableDeviceFactory" :  { "type": "dataprovider-factory" }
+    "RemovableDeviceFactory" :  { "type": "dataprovider-factory" }
 }
 
 class FileSource(FileDataProvider.FileSource):
@@ -68,7 +68,6 @@
     DEFAULT_COMPARE_IGNORE_MTIME = False
 
     def __init__(self, *args):
-        print "#"*100,self.DEFAULT_FOLDER
         FileDataProvider.FolderTwoWay.__init__(self,
                 self.DEFAULT_FOLDER,
                 self.DEFAULT_GROUP,
@@ -135,9 +134,10 @@
 
     def __init__(self, **kwargs):
         VolumeFactory.VolumeFactory.__init__(self, **kwargs)
-        self.foo = {}
+        self._volumes = []
 
     def _make_class(self, folder, name):
+        log.info("Creating preconfigured folder dataprovider: %s" % folder)
         klass = type(
                 "FolderTwoWay",
                 (FolderTwoWay,),
@@ -156,27 +156,27 @@
             prop2 = self._get_properties(props["info.parent"])
             if prop2.has_key("storage.removable") and prop2["storage.removable"] == True:
                 mount,label = self._get_device_info(props)
-                #check for the presence of a mount/.conduit file
-                #which describe the folder sync groups, and their names, 
-                #on this volume
-                #
-                #The format of this file is n lines in the form
-                # group_name|path
-                # group_name|path
-                path = Vfs.uri_join(mount,".conduit")
-                if Vfs.uri_exists(path):
-                    self.foo[udi] = [self._make_class("/tmp",i) for i in range(2)]
+                log.info("Detected removable volume %s %s" % (label,mount))
+                #check for the presence of a mount/.conduit group file
+                #which describe the folder sync groups, and their names,
+                mountUri = "file://%s" % mount
+                for relativeUri,name in FileDataProvider.read_removable_volume_group_file(mountUri):
+                    klass = self._make_class(
+                                        #uri is relative, make it absolute
+                                        "%s%s" % (mountUri,relativeUri),
+                                        name)
+                    self._volumes.append(klass)                                        
                 return True
         return False
     
     def get_category(self, udi, **kwargs):
         return DataProviderCategory.DataProviderCategory(
                     kwargs['label'],
-                    "multimedia-player-ipod-video-white",
+                    "drive-removable-media",
                     udi)
 
     def get_dataproviders(self, udi, **kwargs):
-         return self.foo[udi]
+         return self._volumes
          
     def get_args(self, udi, **kwargs):
         return ()

Modified: trunk/test/python-tests/TestCoreVfs.py
==============================================================================
--- trunk/test/python-tests/TestCoreVfs.py	(original)
+++ trunk/test/python-tests/TestCoreVfs.py	Fri Mar 14 04:24:05 2008
@@ -36,4 +36,18 @@
 ok("Scanned /tmp ok - found %s" % fileuri, "file://"+fileuri in t1.get_uris())
 ok("Scanned %s ok (empty)" % tmpdiruri, t2.get_uris() == [])
 
+# Test the volume management stuff
+ntfsUri = get_external_resources('folder')['ntfs-volume']
+fstype = Vfs.uri_get_filesystem_type(ntfsUri)
+ok("Get filesystem type (%s)" % fstype,fstype == "ntfs")
+ok("Escape illegal chars in filenames", Vfs.uri_sanitize_for_filesystem("invalid:|name",fstype).count(":") == 0)
+
+localUri = get_external_resources('folder')['folder']
+ok("Local uri --> path", Vfs.uri_to_local_path(localUri) == "/tmp")
+ok("Local uri not removable", Vfs.uri_is_on_removable_volume(localUri) == False)
+
+removableUri = get_external_resources('folder')['removable-volume']
+ok("Removable volume detected removable", Vfs.uri_is_on_removable_volume(removableUri))
+ok("Removable volume calculate root path", Vfs.uri_get_volume_root_uri(removableUri) == "file:///media/media")
+
 finished()

Added: trunk/test/python-tests/TestDataProviderFolder.py
==============================================================================
--- (empty file)
+++ trunk/test/python-tests/TestDataProviderFolder.py	Fri Mar 14 04:24:05 2008
@@ -0,0 +1,17 @@
+#common sets up the conduit environment
+from common import *
+
+import conduit.dataproviders.File as FileDataProvider
+import conduit.Vfs as Vfs
+
+#Test removable volume support
+removableUri = get_external_resources('folder')['removable-volume']
+ok("Is on a removable volume", FileDataProvider.is_on_removable_volume(removableUri))
+
+#save and restore a group
+groupName = "GroupName Is Lame"
+groupInfo = (removableUri, groupName)
+ok("Save group info", FileDataProvider.save_removable_volume_group_file(*groupInfo))
+readInfo = FileDataProvider.read_removable_volume_group_file(removableUri)
+ok("Read group info (%s)" % str(readInfo), len(readInfo) > 0 and readInfo[0][1] == groupName)
+finished()

Added: trunk/test/python-tests/data/folder.list
==============================================================================
--- (empty file)
+++ trunk/test/python-tests/data/folder.list	Fri Mar 14 04:24:05 2008
@@ -0,0 +1,15 @@
+#So that we dont have to keep a bunch of files in svn or on the web
+#to run the test suite on different machines, this file allows locations
+#to be specified in a section (as returned by Utils.get_user_string())
+#
+#Note: Items in the default section should always be accessible
+#Note: If two items have the same key, the one in your section replaces
+#the one in the default section
+[DEFAULT]
+folder=file:///tmp
+
+[john nzjrs-desktop]
+removable-volume=file:///media/media/MusicToSort/Kora
+ntfs-volume=file:///media/windows
+
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]