1 import os
2 import tempfile
3 import datetime
4 import traceback
5 import logging
6 log = logging.getLogger("datatypes.File")
7
8 try:
9 import gnomevfs
10 except ImportError:
11 from gnome import gnomevfs
12
13 import conduit
14 import conduit.datatypes.DataType as DataType
15 import conduit.Vfs as Vfs
16
19
20 -class File(DataType.DataType):
21
22 _name_ = "file"
23
25 """
26 File constructor.
27 Compulsory args
28 - URI: The title of the note
29
30 Optional kwargs
31 - basepath: The files basepath
32 - group: A named group to which this file belongs
33 """
34 DataType.DataType.__init__(self)
35
36 self.URI = gnomevfs.URI(URI)
37
38
39 self.basePath = kwargs.get("basepath","")
40 self.group = kwargs.get("group","")
41
42
43 self.fileInfo = None
44 self.fileExists = False
45 self.triedOpen = False
46 self._newFilename = None
47 self._newMtime = None
48
49 self._isProxyFile = False
50 self._proxyFileSize = None
51
53 if self.triedOpen == False:
54 self.triedOpen = True
55 self.fileExists = gnomevfs.exists(self.URI)
56
58 log.debug("Closing file")
59 self.fileInfo = None
60 self.fileExists = False
61 self.triedOpen = False
62
63
64 if self.get_filename() == self._newFilename:
65 log.debug("Clearing pending rename")
66 self._newFilename = None
67 if self.get_mtime() == self._newMtime:
68 log.debug("Clearing pending mtime")
69 self._newMtime = None
70
73
75
76 try:
77 if cancel_func():
78 log.info("Transfer of %s -> %s cancelled" % (info.source_name, info.target_name))
79 return 0
80 except Exception, ex:
81 log.warn("Could not call gnomevfs cancel function")
82 return 0
83 return True
84
85 - def _get_text_uri(self):
86 """
87 The mixing of text_uri and gnomevfs.URI in the gnomevfs api is very
88 annoying. This function returns the full text uri for the file
89 """
90 return str(self.URI)
91
93 """
94 Gets the file info. Because gnomevfs is dumb this method works a lot
95 more reliably than self.vfsFileHandle.get_file_info().
96
97 Only tries to get the info once for performance reasons
98 """
99 self._open_file()
100
101 if self.fileInfo == None:
102 if self.exists() == True:
103 self.fileInfo = gnomevfs.get_file_info(self.URI, gnomevfs.FILE_INFO_DEFAULT)
104 else:
105 log.warn("Cannot get info on non-existant file %s" % self.URI)
106
108 """
109 In the event that the file is on a read-only volume this call defers the
110 file rename till after the transfer proces
111 """
112 log.debug("Defering rename till transfer (New name: %s)" % filename)
113 self._newFilename = filename
114
116 return self._newFilename != None
117
119 """
120 In the event that the file is on a read-only volume this call defers the
121 file mtime modification till after the transfer proces
122 """
123 log.debug("Defering new mtime till transfer (New mtime: %s)" % mtime)
124 self._newMtime = mtime
125
127 return self._newMtime != None
128
130 tmpdir = tempfile.gettempdir()
131 if self.is_local() and self.URI.path.startswith(tmpdir):
132 return True
133 else:
134 return False
135
137 return self._isProxyFile
138
140 timestamp = conduit.utils.datetime_get_timestamp(mtime)
141 log.debug("Setting mtime of %s to %s (%s)" % (self.URI, timestamp, type(timestamp)))
142 newInfo = gnomevfs.FileInfo()
143 newInfo.mtime = timestamp
144 gnomevfs.set_file_info(self.URI,newInfo,gnomevfs.SET_FILE_INFO_TIME)
145
146 self._close_file()
147
149 newInfo = gnomevfs.FileInfo()
150
151
152 filename = str(filename)
153 oldname = str(self.get_filename())
154
155 if filename != oldname:
156 newInfo.name = filename
157 olduri = self._get_text_uri()
158 newuri = olduri.replace(oldname, filename)
159
160 log.debug("Trying to rename file %s (%s) -> %s (%s)" % (olduri,oldname,newuri,filename))
161 gnomevfs.set_file_info(self.URI,newInfo,gnomevfs.SET_FILE_INFO_NAME)
162
163 self.URI = gnomevfs.URI(newuri)
164 self._close_file()
165
167 """
168 Function to give this file all the properties of the
169 supplied instance. This is important in converters where there
170 might be pending renames etc on the file that you
171 do not want to lose
172 """
173 self.URI = f.URI
174 self.basePath = f.basePath
175 self.group = f.group
176 self.fileInfo = f.fileInfo
177 self.fileExists = f.fileExists
178 self.triedOpen = f.triedOpen
179 self._newFilename = f._newFilename
180 self._newMtime = f._newMtime
181 self._isProxyFile = f._isProxyFile
182 self._proxyFileSize = f._proxyFileSize
183
185 """
186 Copies this file to a temporary file in the system tempdir
187 @returns: The local file path
188 """
189
190 tempname = tempfile.mkstemp(prefix="conduit")[1]
191 log.debug("Tempfile %s -> %s" % (self.URI, tempname))
192 filename = self.get_filename()
193 mtime = self.get_mtime()
194 self.transfer(
195 newURIString=tempname,
196 overwrite=True
197 )
198
199 self.force_new_filename(filename)
200 self.force_new_mtime(mtime)
201 return tempname
202
206
208 """
209 Checks if a File is on the local filesystem or not. If not, it is
210 expected that the caller will call get_local_uri, which will
211 copy the file to that location, and return the new path
212 """
213 return self.URI.is_local
214
216 """
217 @returns: True if the File is a directory
218 """
219 self._get_file_info()
220 return self.fileInfo.type == gnomevfs.FILE_TYPE_DIRECTORY
221
243
245 """
246 Changes the file extension to ext.
247 @param ext: The new file extension (including the dot)
248 """
249 curname,curext = self.get_filename_and_extension()
250 if curext != ext:
251 self.force_new_filename(curname+ext)
252
271
272 - def transfer(self, newURIString, overwrite=False, cancel_function=None):
273 """
274 Transfers the file to newURI. Thin wrapper around go_gnomevfs_transfer
275 because it also sets the new info of the file. By wrapping the xfer_uri
276 funtion it gives the ability to cancel transfers
277
278 @type newURIString: C{string}
279 """
280
281 if cancel_function == None:
282 cancel_function = self._xfer_check_global_cancel_flag
283
284 if self._is_deferred_rename():
285 newURI = gnomevfs.URI(newURIString)
286
287
288 if gnomevfs.exists(newURI):
289 info = gnomevfs.get_file_info(newURI, gnomevfs.FILE_INFO_DEFAULT)
290 if info.type == gnomevfs.FILE_TYPE_DIRECTORY:
291
292 newURI = newURI.append_file_name(self._newFilename)
293 log.debug("Using deferred filename in transfer")
294 else:
295 newURI = gnomevfs.URI(newURIString)
296
297 if overwrite:
298 mode = gnomevfs.XFER_OVERWRITE_MODE_REPLACE
299 else:
300 mode = gnomevfs.XFER_OVERWRITE_MODE_SKIP
301
302 log.debug("Transfering File %s -> %s" % (self.URI, newURI))
303
304
305 parent = str(newURI.parent)
306 if not gnomevfs.exists(parent):
307 Vfs.uri_make_directory_and_parents(parent)
308
309
310 try:
311 result = gnomevfs.xfer_uri(
312 source_uri=self.URI,
313 target_uri=newURI,
314 xfer_options=gnomevfs.XFER_NEW_UNIQUE_DIRECTORY,
315 error_mode=gnomevfs.XFER_ERROR_MODE_ABORT,
316 overwrite_mode=mode,
317 progress_callback=self._xfer_progress_callback,
318 data=cancel_function
319 )
320 except gnomevfs.InterruptedError:
321 raise FileTransferError
322
323
324 self.URI = newURI
325 self._close_file()
326
327
328
329 self._isProxyFile = False
330
331
332 if self._is_deferred_rename():
333 self.force_new_filename(self._newFilename)
334 if self._is_deferred_new_mtime():
335 self.force_new_mtime(self._newMtime)
336
338
339 self._close_file()
340 log.debug("Deleting %s" % self.URI)
341 result = gnomevfs.unlink(self.URI)
342
344 self._get_file_info()
345 try:
346 return self.fileInfo.mime_type
347 except ValueError:
348
349 return gnomevfs.get_mime_type(self._get_text_uri())
350
352 """
353 Returns the modification time for the file
354
355 @returns: A python datetime object containing the modification time
356 of the file or None on error.
357 @rtype: C{datetime}
358 """
359 if self._is_deferred_new_mtime():
360 return self._newMtime
361 else:
362 self._get_file_info()
363 try:
364 return datetime.datetime.fromtimestamp(self.fileInfo.mtime)
365 except:
366 return None
367
369 """
370 Sets the modification time of the file
371 """
372 if mtime != None:
373 try:
374 self.force_new_mtime(mtime)
375 except Exception, err:
376 log.warn("Error setting mtime of %s. \n%s" % (self.URI, traceback.format_exc()))
377
379 """
380 Gets the file size
381 """
382 if self._is_proxyfile():
383 return self._proxyFileSize
384 else:
385 self._get_file_info()
386 try:
387 return self.fileInfo.size
388 except:
389 return None
390
392
393
394 tagstr = "".join(self.get_tags())
395
396 return hash(tagstr)
397
399 """
400 Returns the filename of the file
401 """
402 if self._is_deferred_rename():
403 return self._newFilename
404 else:
405 self._get_file_info()
406 return self.fileInfo.name
407
409 """
410 @returns: filename,file_extension
411 """
412 return os.path.splitext(self.get_filename())
413
415 return gnomevfs.read_entire_file(self._get_text_uri())
416
418 """
419 Gets the local URI (full path) for the file. If the file is
420 already on the local system then its local path is returned
421 (excluding the vfs sheme, i.e. file:///foo/bar becomes /foo/bar)
422
423 If it is a remote file then a local temporary file copy is created
424
425 This function is useful for non gnomevfs enabled libs
426
427 @returns: local absolute path the the file or None on error
428 @rtype: C{string}
429 """
430 if self.is_local():
431
432
433 u = gnomevfs.get_local_path_from_uri(self._get_text_uri())
434
435
436 return u
437 else:
438 return self.to_tempfile()
439
448
449 - def compare(self, B, sizeOnly=False):
504
516
518 fd, name = tempfile.mkstemp(prefix="netsync")
519 os.write(fd, data['data'])
520 os.close(fd)
521
522 self.URI = gnomevfs.URI(name)
523 self.basePath = data['basePath']
524 self.group = data['group']
525 self._defer_rename(data['filename'])
526 self._defer_new_mtime(data['filemtime'])
527
528
529 self.fileInfo = None
530 self.fileExists = False
531 self.triedOpen = False
532
533 DataType.DataType.__setstate__(self, data)
534
536 """
537 Creates a file in the system temp directory with the given contents.
538 """
540
541 fd, name = tempfile.mkstemp(prefix="conduit")
542 os.write(fd, contents)
543 os.close(fd)
544 File.__init__(self, name)
545 log.debug("New tempfile created at %s" % name)
546
548 """
549 Pretends to be a file for the sake of comparison and transer. Typically
550 located on a remote, read only resource, such as http://. Once transferred
551 to the local filesystem, it behaves just like a file.
552 """
553 - def __init__(self, URI, name, modified, size, **kwargs):
563