def _upload_photo(self, uploadInfo): """ Import a file into the f-spot catalog """ # Check if remote is read only if self.photo_remote.IsReadOnly(): raise Exceptions.SyncronizeError( _("F-Spot DBus interface is operating in read-only mode")) # create roll if necessary if not self.has_roll: self.prepare_roll() # start with enabled tags from gui, they exist in fspot for sure tags = list(self.enabledTags) # add tags from upload info for tag in uploadInfo.tags: self._create_tag(tag) tags.append(tag) # import the photo try: id = self.photo_remote.ImportPhoto(uploadInfo.url, True, tags) return Rid(uid=str(id)) except: raise Exceptions.SynchronizeError('Import Failed')
def run(self): """ The main refresh state machine. Takes the conduit through the init->is_configured->refresh steps, setting its status at the appropriate time and performing nicely in the case of errors. """ log.debug("Started thread %s (thread: %s)" % (self, thread.get_ident())) try: log.debug("Refresh %s beginning" % self) self.cond.emit("sync-started") if not self.dataproviderWrapper.module.is_configured( isSource=self.cond.get_dataprovider_position( self.dataproviderWrapper)[0] == 0, isTwoWay=self.cond.is_two_way()): self.dataproviderWrapper.module.set_status( DataProvider.STATUS_DONE_SYNC_NOT_CONFIGURED) #Cannot continue if source not configured raise Exceptions.StopSync(self.state) self.state = self.REFRESH_STATE try: self.dataproviderWrapper.module.refresh() self.dataproviderWrapper.module.set_status( DataProvider.STATUS_DONE_REFRESH_OK) except Exceptions.RefreshError: self.dataproviderWrapper.module.set_status( DataProvider.STATUS_DONE_REFRESH_ERROR) log.warn("RefreshError: %s" % self.dataproviderWrapper) #Cannot continue with no source data raise Exceptions.StopSync(self.state) except Exception: self.dataproviderWrapper.module.set_status( DataProvider.STATUS_DONE_REFRESH_ERROR) log.critical( "UNKNOWN REFRESH ERROR: %s\n%s" % (self.dataproviderWrapper, traceback.format_exc())) #Cannot continue with no source data raise Exceptions.StopSync(self.state) except Exceptions.StopSync: log.warn("Sync Aborted") self.aborted = True conduit.GLOBALS.mappingDB.save() self.cond.emit("sync-completed", self.aborted, self.did_sync_error(), self.did_sync_conflict())
def put(self, data, overwrite, LUID=None): DataProvider.DataSink.put(self, data, overwrite, LUID) if self.slow: time.sleep(1) if self.count >= self.errorAfter: if self.errorFatal: raise Exceptions.SyncronizeFatalError( "Error After:%s Count:%s" % (self.errorAfter, self.count)) else: raise Exceptions.SyncronizeError("Error After:%s Count:%s" % (self.errorAfter, self.count)) self.count += 1 newData = TestDataType(data.get_UID()) return newData.get_rid()
def put(self, data, overwrite, LUID=None): DataProvider.DataSink.put(self, data, overwrite, LUID) newData = TestDataType(data.get_UID()) if not overwrite: raise Exceptions.SynchronizeConflictError( conduit.datatypes.COMPARISON_UNKNOWN, data, newData) return newData.get_rid()
def put(self, data, overwrite, LUID): """ @returns: The Rid of the page at location LUID """ DataProvider.TwoWay.put(self, data, overwrite, LUID) #If LUID is None, then we have once-upon-a-time uploaded this data if LUID != None: #Check if the remote data exists (i.e. has it been deleted) if self._data_exists(LUID): #The remote page exists if overwrite == False: #Only replace the data if it is newer than the remote one oldData = self._get_data(LUID) comp = data.compare(oldData) if comp == conduit.datatypes.COMPARISON_NEWER: return self._replace_data(LUID, data) elif comp == conduit.datatypes.COMPARISON_EQUAL: #We are the same, so return either rid return oldData.get_rid() else: #If we are older that the remote page, or if the two could not #be compared, then we must ask the user what to do via a conflict raise Exceptions.SynchronizeConflictError( comp, data, oldData) #If we get here then the data is new return self._put_data(data)
def refresh(self): DataProvider.DataSource.refresh(self) #only work if Banshee is installed if not os.path.exists(BansheeSource.MUSIC_DB): raise Exceptions.RefreshError("Banshee is not installed") #Stupid pysqlite thread stuff. #Connection must be made in the same thread #as any execute statements con = sqlite.connect(BansheeSource.MUSIC_DB) cur = con.cursor() for playlistid in self.playlists: if BANSHEE_VERSION_1: cur.execute( "select Uri from CoreTracks INNER JOIN CorePlaylistEntries ON CorePlaylistEntries.TrackID=CoreTracks.TrackID where PlaylistID=%s" % (playlistid)) else: cur.execute( "select Uri from Tracks INNER JOIN PlaylistEntries ON PlaylistEntries.TrackID=Tracks.TrackID where PlaylistID=%s" % (playlistid)) for Uri in cur: self.tracks.append(self._get_full_uri(Uri[0])) for playlistid in self.smart_playlists + self.video_playlists: cur.execute( "select Uri from CoreTracks INNER JOIN CoreSmartPlaylistEntries ON CoreSmartPlaylistEntries.TrackID where PlaylistID=%s" % (playlistid)) for Uri in cur: self.tracks.append(self._get_full_uri(Uri[0])) con.close()
def put(self, localfile, overwrite, LUID): """ Stores the given File object remotely on Amazon S3, if certain conditions are met. @returns: The Rid of the page at location LUID. """ DataProvider.TwoWay.put(self, localfile, overwrite, LUID) # If LUID is None, then we have once-upon-a-time uploaded this file if LUID != None: # Check if the remote file exists (i.e. has it been deleted) if self._data_exists(LUID): # The remote file exists if not overwrite: # Only replace the data if it is newer than the remote one remotefile = self._get_data(LUID) comp = localfile.compare(remotefile) if comp == conduit.datatypes.COMPARISON_NEWER: return self._replace_data(LUID, localfile) elif comp == conduit.datatypes.COMPARISON_EQUAL: # We are the same, so return either rid return remotefile.get_rid() else: # If we are older than the remote page, or if the two # could not be compared, then we must ask the user what # to do via a conflict raise Exceptions.SynchronizeConflictError( comp, localfile, remotefile) # If we get here then the file is new return self._put_data(localfile)
def refresh(self): Image.ImageTwoWay.refresh(self) self.photos = [] if self._connect_to_fspot(): self.photos = self.photo_remote.Query(self.enabledTags) else: raise Exceptions.RefreshError("FSpot not available")
def refresh(self): DataProvider.TwoWay.refresh(self) self.notes = [] if self._connect_to_tomboy(): self.notes = [str(i) for i in self.remoteTomboy.ListAllNotes()] else: raise Exceptions.RefreshError("Tomboy not available")
def put(self, note, overwrite, LUID=None): """ Stores a Note in Tomboy. """ DataProvider.TwoWay.put(self, note, overwrite, LUID) log.debug("Put note LUID: %s" % LUID) #Check if the note, or one with same title exists existingNote = None if LUID != None: if self.remoteTomboy.NoteExists(LUID): existingNote = self._get_note(LUID) else: LUID = self.remoteTomboy.FindNote(note.get_title()) if LUID != "": existingNote = self._get_note(str(LUID)) #compare with the existing note if existingNote != None: comp = note.compare(existingNote) log.debug("Comparing new %s with existing %s" % (note.get_title(), existingNote.get_title())) if comp == conduit.datatypes.COMPARISON_EQUAL: log.info("Notes are equal") elif overwrite == True or comp == conduit.datatypes.COMPARISON_NEWER: log.info("Updating note") self._update_note(LUID, note) else: raise Exceptions.SynchronizeConflictError( comp, note, existingNote) else: log.info("Saving new Note") LUID = self._create_note(note) return self.get(LUID).get_rid()
def put(self, obj, overwrite, LUID=None): DataProvider.TwoWay.put(self, obj, overwrite, LUID) if LUID != None: existing = self._get_object(LUID) if existing != None: if overwrite == True: rid = self._update_object(LUID, obj) return rid else: comp = obj.compare( existing, "%s-%s" % (self.__class__.__name__, self.get_UID())) # only update if newer if comp != conduit.datatypes.COMPARISON_NEWER: raise Exceptions.SynchronizeConflictError( comp, obj, existing) else: # overwrite and return new ID rid = self._update_object(LUID, obj) return rid # if we get here then it is new... log.info("Creating new object") rid = self._create_object(obj) return rid
def _update_object(self, uid, obj): if self._delete_object(uid): uid = self._create_object(obj) return uid else: raise Exceptions.SyncronizeError( "Error updating object (uid: %s)" % uid)
def refresh(self): d = File.File(URI=self.folder) if not d.exists(): try: d.make_directory_and_parents() except: raise Exceptions.RefreshError("Error Creating Directory") FileDataProvider.FolderTwoWay.refresh(self)
def _upload_photo(self, uploadInfo): """ Upload to album """ try: fotoId = self.zapi.add_to_album(uploadInfo, self.albumId) except Exception, e: raise Exceptions.SyncronizeError("Zoto Upload Error.")
def _replace_photo(self, id, uploadInfo): """ Updates a photo (binary and metadata) """ try: fotoId = self.zapi.update_photo(id, uploadInfo) except Exception, e: raise Exceptions.SyncronizeError("Zoto Update Error.")
def put(self, photo, overwrite, LUID=None): """ Accepts a vfs file. Must be made local. I also store a md5 of the photos uri to check for duplicates """ DataProvider.DataSink.put(self, photo, overwrite, LUID) originalName = photo.get_filename() #Gets the local URI (/foo/bar). If this is a remote file then #it is first transferred to the local filesystem photoURI = photo.get_local_uri() mimeType = photo.get_mimetype() tags = photo.get_tags() caption = photo.get_caption() uploadInfo = UploadInfo(photoURI, mimeType, originalName, tags, caption) if overwrite and LUID: rid = self._replace_photo(LUID, uploadInfo) else: if LUID and self._get_photo_info(LUID): remotePhoto = self.get(LUID) comp = photo.compare(remotePhoto, False) log.debug( "Compared %s with %s. Result = %s" % (photo.get_filename(), remotePhoto.get_filename(), comp)) if LUID != None and comp == conduit.datatypes.COMPARISON_NEWER: rid = self._replace_photo(LUID, uploadInfo) elif comp == conduit.datatypes.COMPARISON_EQUAL: rid = remotePhoto.get_rid() else: raise Exceptions.SynchronizeConflictError( comp, photo, remotePhoto) else: log.debug( "Uploading Photo URI = %s, Mimetype = %s, Original Name = %s" % (photoURI, mimeType, originalName)) rid = self._upload_photo(uploadInfo) if not rid: raise Exceptions.SyncronizeError("Error putting/updating photo") else: return rid
def _upload_photo(self, uploadInfo): """ Upload to album """ try: ret = self.salbum.uploadPhoto(uploadInfo.url, uploadInfo.mimeType, uploadInfo.name) return Rid(ret.id) except Exception, e: raise Exceptions.SyncronizeError("Shutterfly Upload Error.")
def _update_note(self, uid, note): log.debug("Updating note uid: %s" % uid) if note.get_xml() != None: ok = self.remoteTomboy.SetNoteCompleteXml(uid, note.get_xml()) else: ok = self.remoteTomboy.SetNoteContents(uid, note.get_contents()) if not ok: raise Exceptions.SyncronizeError( "Error setting Tomboy note content (uri: %s)" % uid)
def check_thread_not_cancelled(self, dataprovidersToCancel): """ Checks if the thread has been scheduled to be cancelled. If it has then this function sets the status of the dataproviders to indicate that they were stopped through a cancel operation. """ if self.cancelled: for s in dataprovidersToCancel: s.module.set_status(DataProvider.STATUS_DONE_SYNC_CANCELLED) raise Exceptions.StopSync(self.state)
def get(self, LUID): try: DataProvider.DataSource.get(self, LUID) songuri = str(self.dbus.GetTrackInfo(LUID, 'location')) f = RhythmboxAudio(URI=songuri) f.set_UID(LUID) f.set_open_URI(songuri) return f except DBusClosedConnectionError: raise Exceptions.SyncronizeFatalError()
def _get_all_albums(self): #only work if picasa has been configured to use a CSV DB #http://www.zmarties.com/picasa/ dbfile = os.path.join(PICASA_DIR, 'drive_c', 'Program Files', 'Picasa2', 'db', 'dirscanner.csv') if not os.path.exists(dbfile): raise Exceptions.RefreshError( "Picasa Not Configured to use CSV Database") pals = [] #Open the CSV file and find all entries with Type = 19 (albums) f = open(dbfile, 'rt') try: reader = csv.DictReader(f) for row in reader: if row['Type'] == '19': #wine picasa stores all pal files (that describes an album) #in the following base dir parts = [ PICASA_DIR, 'drive_c', 'Documents and Settings', os.getlogin(), 'Local Settings' ] #and then as given in the csv file #but first change the windows path to a linux one parts += row['Name'].split("\\") path = os.path.abspath(os.sep.join(parts)) pals.append(path) finally: f.close() #parse each pal file to get album info albums = [] for pal in pals: log.debug("Parsing album file %s" % pal) doc = xml.dom.minidom.parse(pal) #album name for prop in doc.getElementsByTagName('property'): if prop.hasAttribute("name") and prop.getAttribute( "name") == "name": name = prop.getAttribute("value") #image filenames photos = [] for f in doc.getElementsByTagName('filename'): filename = self._fix_picasa_image_filename(f.firstChild.data) if filename != None: photos.append(filename) albums.append(( pal, #FILENAME_IDX name, #DISPLAYNAME_IDX photos)) #PHOTOS_IDX return albums
def _upload_photo(self, uploadInfo): """ Upload to album; and return image id here """ try: rsp = self.fapi.photos.upload(uploadInfo.url, aid=self.albums.get( self.albumname, None)) pid = str(rsp["pid"]) return Rid(uid=pid) except pyfacebook.FacebookError, f: raise Exceptions.SyncronizeError("Facebook Upload Error %s" % f)
def get(self, LUID): for title in self._notes: uid, timestamp, content = self._notes[title] if uid == LUID: n = Note.Note( title=title, #FIXME: Backpack doesnt have mtime, only creation time modified=datetime.datetime.fromtimestamp(timestamp), contents=content) n.set_UID(LUID) return n raise Exceptions.SyncronizeError("Could not find note %s" % LUID)
def marshal_fault_to_exception(fault, **kwargs): if fault.faultCode in XML_RPC_EASY_EXCEPTIONS: klass = getattr(Exceptions, fault.faultCode) #exception.message = fault.faultString raise klass(fault.faultString) elif fault.faultCode == "SynchronizeConflictError": fromData = kwargs['server'].get(kwargs['fromDataLUID']) toData = kwargs['toData'] raise Exceptions.SynchronizeConflictError(fault.faultString, fromData, toData) else: raise Exception("Remote Exception:\n%s" % fault.faultString)
def get_all(self): DataProvider.DataSource.get_all(self) try: # LUID is now a Rhythmbox ID, that only makes sense to Rhythmbox songs = [] #only consider enabled playlists for playlist in [ p for p in self.allPlaylists if p in self.playlists ]: for song in self.dbus.GetPlaylistTracks(playlist): songs.append(str(song)) return songs except DBusClosedConnectionError: raise Exceptions.SyncronizeFatalError()
def delete(self, LUID): """ Delete a photo by ID """ if not self.sphotos.has_key(LUID): log.warn("Photo does not exist") return try: self.zapi.delete_from_album(LUID, self.albumId) del self.sphotos[LUID] except xmlrpclib.Fault, e: raise Exceptions.SyncronizeError("Zoto Delete Error: " + e.faultString)
def _create_object(self, note): obj = evolution.ecal.ECalComponent( evolution.ecal.CAL_COMPONENT_JOURNAL) obj.set_summary(note.title) if note.contents != None: obj.set_description(note.contents) uid = self.memos.add_object(obj) if uid != None: mtime = datetime.datetime.fromtimestamp(obj.get_modified()) note = self._get_object(uid) return note.get_rid() else: raise Exceptions.SyncronizeError("Error creating memo")
def _create_object(self, event): # work around.. (avoid duplicate UIDs) if "UID" in [x.name for x in list(event.iCal.lines())]: event.iCal.remove(event.iCal.uid) obj = evolution.ecal.ECalComponent(evolution.ecal.CAL_COMPONENT_TODO, event.get_ical_string()) if self.tasks.add_object(obj): mtime = datetime.datetime.fromtimestamp(obj.get_modified()) return conduit.datatypes.Rid(uid=obj.get_uid(), mtime=mtime, hash=mtime) else: raise Exceptions.SyncronizeError("Error creating event")
def put(self, photo, overwrite, LUID=None): """ Accepts a vfs file. Must be made local. I also store a md5 of the photos uri to check for duplicates """ DataProvider.DataSink.put(self, photo, overwrite, LUID) originalName = photo.get_filename() #Gets the local URI (/foo/bar). If this is a remote file then #it is first transferred to the local filesystem photoURI = photo.get_local_uri() mimeType = photo.get_mimetype() tags = photo.get_tags() caption = photo.get_caption() uploadInfo = UploadInfo(photoURI, mimeType, originalName, tags, caption) #Check if we have already uploaded the photo if LUID != None: info = self._get_photo_info(LUID) #check if a photo exists at that UID if info != None: if overwrite == True: #replace the photo return self._replace_photo(LUID, uploadInfo) else: #Only upload the photo if it is newer than the Remote one url = self._get_raw_photo_url(info) remoteFile = File.File(url) #this is a limited test for equality type comparison comp = photo.compare(remoteFile, True) log.debug( "Compared %s with %s to check if they are the same (size). Result = %s" % (photo.get_filename(), remoteFile.get_filename(), comp)) if comp != conduit.datatypes.COMPARISON_EQUAL: raise Exceptions.SynchronizeConflictError( comp, photo, remoteFile) else: return conduit.datatypes.Rid(uid=LUID) log.debug( "Uploading Photo URI = %s, Mimetype = %s, Original Name = %s" % (photoURI, mimeType, originalName)) #upload the file return self._upload_photo(uploadInfo)
def delete(self, LUID): """ Delete a photo by ID Deleting a photo invalidates album length and photo index values. We must reload the photos (or do something else...) """ if not self.sphotos.has_key(LUID): log.warn("Photo does not exist") return try: self.salbum.deletePhoto(self.sphotos[LUID]) except Exception, e: raise Exceptions.SyncronizeError( "Shutterfly Delete Error - Try Again.")