Ticket #1636: 0001-Share-Journal-entries-over-USB-1636.patch
File 0001-Share-Journal-entries-over-USB-1636.patch, 10.0 KB (added by erikos, 14 years ago) |
---|
-
src/jarabe/journal/model.py
From 7410946e0eb569925f1b8a376dff30c0ca946b7e Mon Sep 17 00:00:00 2001 From: Simon Schampijer <simon@schampijer.de> Date: Thu, 9 Sep 2010 12:15:42 +0200 Subject: [PATCH] Share Journal entries over USB #1636 --- src/jarabe/journal/model.py | 160 +++++++++++++++++++++++++++++++++++++++---- 1 files changed, 146 insertions(+), 14 deletions(-) diff --git a/src/jarabe/journal/model.py b/src/jarabe/journal/model.py index f4186f0..4060221 100644
a b import os 19 19 from datetime import datetime 20 20 import time 21 21 import shutil 22 import tempfile 22 23 from stat import S_IFMT, S_IFDIR, S_IFREG 23 24 import traceback 24 25 import re 26 import json 25 27 26 28 import gobject 27 29 import dbus … … class InplaceResultSet(BaseResultSet): 308 310 files = self._file_list[offset:offset + limit] 309 311 310 312 entries = [] 311 for file_path, stat, mtime_ in files: 312 metadata = _get_file_metadata(file_path, stat) 313 for file_path, stat, mtime_, metadata in files: 314 if metadata is None: 315 # FIXME: the find should fetch metadata 316 metadata = _get_file_metadata(file_path, stat) 313 317 metadata['mountpoint'] = self._mount_point 314 318 entries.append(metadata) 315 319 … … class InplaceResultSet(BaseResultSet): 333 337 334 338 elif S_IFMT(stat.st_mode) == S_IFREG: 335 339 add_to_list = True 340 metadata = None 336 341 337 342 if self._regex is not None and \ 338 343 not self._regex.match(full_path): 339 344 add_to_list = False 345 metadata = _get_file_metadata_from_json( \ 346 dir_path, entry, preview=False) 347 if metadata is not None: 348 for f in ['fulltext', 'title', 349 'description', 'tags']: 350 if f in metadata and \ 351 self._regex.match(metadata[f]): 352 add_to_list = True 353 break 340 354 341 355 if None not in [self._date_start, self._date_end] and \ 342 356 (stat.st_mtime < self._date_start or … … class InplaceResultSet(BaseResultSet): 349 363 add_to_list = False 350 364 351 365 if add_to_list: 352 file_info = (full_path, stat, int(stat.st_mtime) )366 file_info = (full_path, stat, int(stat.st_mtime), metadata) 353 367 self._file_list.append(file_info) 354 368 355 369 self.progress.send(self) … … class InplaceResultSet(BaseResultSet): 364 378 self._pending_directories -= 1 365 379 366 380 def _get_file_metadata(path, stat): 381 """Returns the metadata from the corresponding file 382 on the external device or does create the metadata 383 based on the file properties. 384 385 """ 386 filename = os.path.basename(path) 387 dir_path = os.path.dirname(path) 388 metadata = _get_file_metadata_from_json(dir_path, filename, preview=True) 389 if metadata: 390 return metadata 391 367 392 client = gconf.client_get_default() 368 393 return {'uid': path, 369 394 'title': os.path.basename(path), … … def _get_file_metadata(path, stat): 374 399 'icon-color': client.get_string('/desktop/sugar/user/color'), 375 400 'description': path} 376 401 402 def _get_file_metadata_from_json(dir_path, filename, preview=False): 403 """Returns the metadata from the json file and the preview 404 stored on the external device. 405 406 """ 407 metadata = None 408 metadata_path = os.path.join(dir_path, 409 '.' + filename + '.metadata') 410 if os.path.exists(metadata_path): 411 try: 412 metadata = json.load(open(metadata_path)) 413 except ValueError: 414 logging.debug("Could not read metadata for file %r on" \ 415 "external device.", filename) 416 else: 417 metadata['uid'] = os.path.join(dir_path, filename) 418 if preview: 419 preview_path = os.path.join(dir_path, 420 '.' + filename + '.preview') 421 if os.path.exists(preview_path): 422 try: 423 metadata['preview'] = dbus.ByteArray(open(preview_path).read()) 424 except: 425 logging.debug("Could not read preview for file %r on" \ 426 "external device.", filename) 427 else: 428 if metadata and 'preview' in metadata: 429 del(metadata['preview']) 430 return metadata 431 377 432 _datastore = None 378 433 def _get_datastore(): 379 434 global _datastore … … def delete(object_id): 460 515 """ 461 516 if os.path.exists(object_id): 462 517 os.unlink(object_id) 518 dir_path = os.path.dirname(object_id) 519 filename = os.path.basename(object_id) 520 old_files = [os.path.join(dir_path, '.' + filename + '.metadata'), 521 os.path.join(dir_path, '.' + filename + '.preview')] 522 for old_file in old_files: 523 if os.path.exists(old_file): 524 try: 525 os.unlink(old_file) 526 except: 527 pass 463 528 deleted.send(None, object_id=object_id) 464 529 else: 465 530 _get_datastore().delete(object_id) … … def write(metadata, file_path='', update_mtime=True, transfer_ownership=True): 495 560 file_path, 496 561 transfer_ownership) 497 562 else: 498 if not os.path.exists(file_path): 499 raise ValueError('Entries without a file cannot be copied to ' 500 'removable devices') 563 object_id = _write_entry_on_external_device(metadata, file_path) 501 564 502 file_name = _get_file_name(metadata['title'], metadata['mime_type']) 503 file_name = _get_unique_file_name(metadata['mountpoint'], file_name) 565 return object_id 566 567 def _write_entry_on_external_device(metadata, file_path): 568 """This creates and updates an entry copied from the 569 DS to external storage device. Besides copying the 570 associated file a hidden file for the preview and one 571 for the metadata are stored. We make sure that the 572 metadata and preview file are in the same directory 573 as the data file. 574 575 This function handles renames of an entry on the 576 external device and avoids name collisions. Renames are 577 handled failsafe. 578 579 """ 580 if 'uid' in metadata and os.path.exists(metadata['uid']): 581 file_path = metadata['uid'] 582 583 if not file_path or not os.path.exists(file_path): 584 raise ValueError('Entries without a file cannot be copied to ' 585 'removable devices') 504 586 587 file_name = _get_file_name(metadata['title'], metadata['mime_type']) 588 589 destination_path = os.path.join(metadata['mountpoint'], file_name) 590 if destination_path != file_path: 591 file_name = _get_unique_file_name(metadata['mountpoint'], file_name) 505 592 destination_path = os.path.join(metadata['mountpoint'], file_name) 593 clean_name, extension_ = os.path.splitext(file_name) 594 metadata['title'] = clean_name 595 596 metadata_copy = metadata.copy() 597 del metadata_copy['mountpoint'] 598 if 'uid' in metadata_copy: 599 del metadata_copy['uid'] 600 601 if 'preview' in metadata_copy: 602 preview = metadata_copy['preview'] 603 preview_fname = '.' + file_name + '.preview' 604 preview_path = os.path.join(metadata['mountpoint'], preview_fname) 605 metadata_copy['preview'] = preview_fname 606 607 (fh, fn) = tempfile.mkstemp(dir=metadata['mountpoint']) 608 os.write(fh, preview) 609 os.close(fh) 610 os.rename(fn, preview_path) 611 612 metadata_path = os.path.join(metadata['mountpoint'], 613 '.' + file_name + '.metadata') 614 (fh, fn) = tempfile.mkstemp(dir=metadata['mountpoint']) 615 os.write(fh, json.dumps(metadata_copy)) 616 os.close(fh) 617 os.rename(fn, metadata_path) 618 619 if os.path.dirname(destination_path) == os.path.dirname(file_path): 620 old_file_path = file_path 621 if old_file_path != destination_path: 622 os.rename(file_path, destination_path) 623 old_fname = os.path.basename(file_path) 624 old_files = [os.path.join(metadata['mountpoint'], 625 '.' + old_fname + '.metadata'), 626 os.path.join(metadata['mountpoint'], 627 '.' + old_fname + '.preview')] 628 for ofile in old_files: 629 if os.path.exists(ofile): 630 try: 631 os.unlink(ofile) 632 except: 633 pass 634 else: 506 635 shutil.copy(file_path, destination_path) 507 object_id = destination_path 508 created.send(None, object_id=object_id) 636 637 object_id = destination_path 638 created.send(None, object_id=object_id) 509 639 510 640 return object_id 511 641 512 642 def _get_file_name(title, mime_type): 513 643 file_name = title 514 644 515 extension = '.' + mime.get_primary_extension(mime_type) 516 if not file_name.endswith(extension): 517 file_name += extension 645 mime_extension = mime.get_primary_extension(mime_type) 646 if mime_extension: 647 extension = '.' + mime_extension 648 if not file_name.endswith(extension): 649 file_name += extension 518 650 519 651 # Invalid characters in VFAT filenames. From 520 652 # http://en.wikipedia.org/wiki/File_Allocation_Table … … def _get_file_name(title, mime_type): 534 666 def _get_unique_file_name(mount_point, file_name): 535 667 if os.path.exists(os.path.join(mount_point, file_name)): 536 668 i = 1 669 name, extension = os.path.splitext(file_name) 537 670 while len(file_name) <= 255: 538 name, extension = os.path.splitext(file_name)539 671 file_name = name + '_' + str(i) + extension 540 672 if not os.path.exists(os.path.join(mount_point, file_name)): 541 673 break