| Trees | Indices | Help |
|
|---|
|
|
1 import os.path
2 import logging
3 import ConfigParser
4 log = logging.getLogger("dataproviders.File")
5
6 import conduit
7 import conduit.dataproviders.DataProvider as DataProvider
8 import conduit.datatypes as DataType
9 import conduit.datatypes.File as File
10 import conduit.Vfs as Vfs
11 import conduit.Database as DB
12 import conduit.Exceptions as Exceptions
13
14 TYPE_FILE = "0"
15 TYPE_FOLDER = "1"
16
19
21 """
22 Returns the root uri of the volume, and local path of the
23 group config file
24 """
25 rooturi = Vfs.uri_get_volume_root_uri(folderUri)
26 path = Vfs.uri_join(
27 Vfs.uri_to_local_path(rooturi),
28 ".conduit")
29 return rooturi,path
30
32 """
33 Saves a file on the root of the drive, in ini format,
34 containing the uri and group
35
36 e.g.
37 [DEFAULT]
38 relative/uri/from/volume/root = group name
39 """
40 if is_on_removable_volume(folderUri):
41 #write to the /volume/root/.conduit file
42 rooturi,path = get_removable_volume_info(folderUri)
43 conf = ConfigParser.SafeConfigParser()
44 conf.read(path)
45
46 log.debug("Saving group (%s = %s) to %s" % (folderUri,folderGroupName,path))
47 conf.set(
48 "DEFAULT",
49 folderUri.replace(rooturi,""),
50 folderGroupName
51 )
52 fp = open(path, 'w')
53 conf.write(fp)
54 fp.close()
55 return True
56 return False
57
59 items = []
60 if is_on_removable_volume(folderUri):
61 #read from the /volume/root/.conduit file
62 rooturi,path = get_removable_volume_info(folderUri)
63 conf = ConfigParser.SafeConfigParser()
64 conf.read(path)
65 for p,n in conf.items("DEFAULT"):
66 log.debug("Read group (%s = %s)" % (p,n))
67 #check the path still exists on the volume
68 if Vfs.uri_exists(rooturi+p):
69 items.append((p,n))
70 return items
71
73
74 _category_ = conduit.dataproviders.CATEGORY_FILES
75 _module_type_ = "source"
76 _in_type_ = "file"
77 _out_type_ = "file"
78 _icon_ = "text-x-generic"
79
81 DataProvider.DataSource.__init__(self)
82 Vfs.FolderScannerThreadManager.__init__(self)
83
84 #One table stores the top level files and folders (config)
85 #The other stores all files to sync.
86 self.db = DB.ThreadSafeGenericDB()
87 self.db.create(
88 table="config",
89 fields=("URI","TYPE","CONTAINS_NUM_ITEMS","SCAN_COMPLETE","GROUP_NAME")
90 )
91 self.db.create(
92 table="files",
93 fields=("URI","BASEPATH","GROUPNAME")
94 )
95
101
107
110
112 self.db.close()
113
115 DataProvider.DataSource.refresh(self)
116 self.db.execute("DELETE FROM files")
117 #Make a whole bunch of threads to go and scan the directories
118 for oid,uri,groupname in self.db.select("SELECT oid,URI,GROUP_NAME FROM config WHERE TYPE = ?",(TYPE_FOLDER,)):
119 self.make_thread(
120 uri,
121 False, #FIXME: Dont include hidden?
122 self._on_scan_folder_progress,
123 self._on_scan_folder_completed,
124 oid,
125 groupname
126 )
127
128 #All threads must complete - otherwise we might miss some items
129 self.join_all_threads()
130
131 #now add the single files to the list
132 for oid,uri in self.db.select("SELECT oid,URI FROM config WHERE TYPE = ?",(TYPE_FILE,)):
133 f = File.File(URI=uri)
134 if f.exists():
135 self.db.insert(
136 table="files",
137 values=(uri,"","") #single files dont have basepath and groupname
138 )
139 else:
140 self.db.delete(
141 table="config",
142 oid=oid
143 )
144
146 DataProvider.DataSource.get(self, LUID)
147 basepath,group = self.db.select_one("SELECT BASEPATH,GROUPNAME FROM files WHERE URI = ?", (LUID,))
148 f = File.File(
149 URI= LUID,
150 basepath= basepath,
151 group= group
152 )
153 f.set_open_URI(LUID)
154 f.set_UID(LUID)
155 return f
156
158 f = File.File(URI=LUID)
159 if f.exists():
160 oid = self.db.select_one("SELECT oid FROM files WHERE URI = ?", (LUID,))
161 if oid != None:
162 log.debug("Could not add (already added): %s" % LUID)
163 return False
164
165 if f.is_directory():
166 log.debug("Adding folder: %s" % LUID)
167 self._add_folder(LUID,"FIXME")
168 else:
169 log.debug("Adding file: %s" % LUID)
170 self._add_file(LUID)
171 else:
172 log.warn("Could not add: %s" % LUID)
173 return False
174 return True
175
177 #combine the files contained inside dirs with those the user specified
178 files = [f for f, in self.db.select("SELECT URI FROM files")]
179 return files
180
184
186 """
187 Called by the folder scanner thread and used to update
188 the estimate of the number of items in the directory
189 """
190 self.db.update(
191 table="config",
192 oid=oid,
193 CONTAINS_NUM_ITEMS=numItems
194 )
195
197 log.debug("Folder scan complete %s" % folderScanner)
198 #Update scan status
199 self.db.update(
200 table="config",
201 oid=oid,
202 SCAN_COMPLETE=True,
203 GROUP_NAME=groupname
204 )
205 #Put all files into files
206 for f in folderScanner.get_uris():
207 self.db.insert(
208 table="files",
209 values=(f,folderScanner.baseURI,groupname)
210 )
211
213 """
214 TwoWay dataprovider for synchronizing a folder
215 """
216
217 _category_ = conduit.dataproviders.CATEGORY_FILES
218 _module_type_ = "twoway"
219 _in_type_ = "file"
220 _out_type_ = "file"
221 _icon_ = "folder"
222
223 - def __init__(self, folder, folderGroupName, includeHidden, compareIgnoreMtime, followSymlinks):
224 DataProvider.TwoWay.__init__(self)
225 self.folder = folder
226 self.folderGroupName = folderGroupName
227 self.includeHidden = includeHidden
228 self.compareIgnoreMtime = compareIgnoreMtime
229 self.followSymlinks = followSymlinks
230
231 self.fstype = None
232 self.files = []
233
235 try:
236 vfsFile.transfer(newURI, overwrite)
237 except File.FileTransferError:
238 raise Exceptions.SyncronizeFatalError("Transfer Cancelled")
239
242
245
247 DataProvider.TwoWay.refresh(self)
248 #cache the filesystem type for speed
249 self.fstype = Vfs.uri_get_filesystem_type(self.folder)
250
251 #scan the folder
252 scanThread = Vfs.FolderScanner(self.folder, self.includeHidden, self.followSymlinks)
253 scanThread.start()
254 scanThread.join()
255 self.files = scanThread.get_uris()
256
258 """
259 Puts vfsFile at the correct location. There are three scenarios
260 1) File came from a foreign DP like tomboy
261 2) File came from another file dp
262
263 Behaviour:
264 1) The foreign DP should have encoded enough information (such as
265 the filename) so that we can go ahead and put the file in the dir
266 2) First we see if the file has a group attribute.
267 a) If so, and the group matches the groupName here then we
268 put the files into the directory.
269 b) If not we put the file in a subdir by the name of the group
270
271 We always retain the relative path for the files
272 """
273 DataProvider.TwoWay.put(self, vfsFile, overwrite, LUID)
274 newURI = ""
275 if LUID != None:
276 newURI = LUID
277 elif vfsFile.basePath == "":
278 #came from another type of dataprovider such as tomboy
279 #where relative path makes no sense. Could also come from
280 #the FileSource dp when the user has selected a single file
281 log.debug("No basepath. Going to empty dir")
282 newURI = Vfs.uri_join(self.folder,vfsFile.get_filename())
283 else:
284 #Look for corresponding groups
285 relpath = vfsFile.get_relative_uri()
286 log.debug("Relative path: %s" % relpath)
287 if self.folderGroupName == vfsFile.group:
288 log.debug("Found corresponding group")
289 #put in the folder
290 newURI = Vfs.uri_join(self.folder,relpath)
291 else:
292 log.debug("Recreating group: %s" % vfsFile.group)
293 #unknown. Store in the dir but recreate the group
294 newURI = Vfs.uri_join(self.folder,vfsFile.group,relpath)
295
296 #escape illegal filesystem characters
297 if self.fstype:
298 newURI = Vfs.uri_sanitize_for_filesystem(newURI, self.fstype)
299
300 #overwrite is the easy case, as for it to be true, requires specific user
301 #interaction
302 if overwrite == True:
303 self._transfer_file(vfsFile, newURI, overwrite)
304 else:
305 #check for conflicts
306 destFile = File.File(URI=newURI)
307 if destFile.exists():
308 comp = vfsFile.compare(
309 destFile,
310 sizeOnly=self.compareIgnoreMtime
311 )
312
313 if LUID != None and comp == DataType.COMPARISON_NEWER:
314 #we were expecting an existing file, we found it, but
315 #we are newer, so overwrite it
316 self._transfer_file(vfsFile, newURI, True)
317 elif comp == DataType.COMPARISON_EQUAL:
318 #in File.compare, the files are compared based on size, if
319 #their mtimes are the same, so this case is true when
320 # 1) The sizes are the same, and the user told us
321 # to ignore the mtimes
322 # 2) The mtimes and size is the same, and we checked both
323 pass
324 else:
325 raise Exceptions.SynchronizeConflictError(comp, vfsFile, destFile)
326 else:
327 self._transfer_file(vfsFile, newURI, overwrite)
328
329 return self.get(newURI).get_rid()
330
335
337 DataProvider.TwoWay.get(self, uid)
338 f = File.File(
339 URI=uid,
340 basepath=self.folder,
341 group=self.folderGroupName
342 )
343 f.set_open_URI(uid)
344 f.set_UID(uid)
345 return f
346
350
352 DataProvider.TwoWay.finish(self)
353 self.files = []
354 try:
355 #Save the .group file to the root of this volume (if it is removable)
356 save_removable_volume_group_file(self.folder, self.folderGroupName)
357 except Exception, e:
358 log.warn("Error saving volume group file: %s" % e)
359
361 f = File.File(URI=LUID)
362 if f.exists() and f.is_directory():
363 self.folder = f._get_text_uri()
364 return True
365 return False
366
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0beta1 on Sat Aug 2 22:18:50 2008 | http://epydoc.sourceforge.net |