Example #1
0
 def load_config(self, parser):
     import ConfigParser
     config_name = 'config.ini'
     config = ConfigParser.ConfigParser()
     configs = []
     path = os.path.join(os.path.dirname(sys.executable), config_name)
     if os.path.exists(path):
         configs.append(path)
     if os.path.exists(config_name):
         configs.append(config_name)
     user_ini = os.path.expanduser(os.path.join(self.default_home, config_name))
     if os.path.exists(user_ini):
         configs.append(user_ini)
     if len(configs) > 0:
         config.read(configs)
     if config.has_option(ConfigParser.DEFAULTSECT, 'env'):
         env = config.get(ConfigParser.DEFAULTSECT, 'env')
         args = AbstractOSIntegration.get(None).get_system_configuration()
         for item in config.items(env):
             if item[0] == 'env':
                 continue
             args[item[0].replace('-', '_')] = item[1]
         if len(args):
             parser.set_defaults(**args)
     else:
         parser.set_defaults(**AbstractOSIntegration.get(None).get_system_configuration())
 def set_folder_icon(self, ref, icon):
     if icon is None:
         return
     if AbstractOSIntegration.is_windows():
         self.set_folder_icon_win32(ref, icon)
     elif AbstractOSIntegration.is_mac():
         self.set_folder_icon_darwin(ref, icon)
Example #3
0
 def showMessage(self, title, message, icon=QtGui.QSystemTrayIcon.Information, timeout = 10000):
     if AbstractOSIntegration.is_mac():
         if AbstractOSIntegration.os_version_above("10.8"):
             from nxdrive.osi.darwin.pyNotificationCenter import notify
             # Use notification center
             return notify(title, None, message)
     return QtGui.QSystemTrayIcon.showMessage(self, title, message, icon, timeout)
Example #4
0
 def load_config(self, parser):
     import ConfigParser
     config_name = 'config.ini'
     config = ConfigParser.ConfigParser()
     configs = []
     path = os.path.join(os.path.dirname(sys.executable), config_name)
     if os.path.exists(path):
         configs.append(path)
     if os.path.exists(config_name):
         configs.append(config_name)
     user_ini = os.path.expanduser(
         os.path.join(self.default_home, config_name))
     if os.path.exists(user_ini):
         configs.append(user_ini)
     if len(configs) > 0:
         config.read(configs)
     if config.has_option(ConfigParser.DEFAULTSECT, 'env'):
         env = config.get(ConfigParser.DEFAULTSECT, 'env')
         args = AbstractOSIntegration.get(None).get_system_configuration()
         for item in config.items(env):
             if item[0] == 'env':
                 continue
             args[item[0].replace('-', '_')] = item[1]
         if len(args):
             parser.set_defaults(**args)
     else:
         parser.set_defaults(
             **AbstractOSIntegration.get(None).get_system_configuration())
Example #5
0
 def _check_last_sync(self):
     from nxdrive.engine.watcher.local_watcher import WIN_MOVE_RESOLUTION_PERIOD
     qm_active = self._queue_manager.active()
     qm_size = self._queue_manager.get_overall_size()
     empty_polls = self._remote_watcher.get_metrics()["empty_polls"]
     if not AbstractOSIntegration.is_windows():
         win_info = 'not Windows'
     else:
         win_info = 'Windows with win queue size = %d and win folder scan size = %d' % (
             self._local_watcher.get_win_queue_size(), self._local_watcher.get_win_folder_scan_size())
     log.debug('Checking sync completed: queue manager is %s, overall size = %d, empty polls count = %d'
               ', watchdog queue size = %d, %s',
               'active' if qm_active else 'inactive', qm_size, empty_polls,
               self._local_watcher.get_watchdog_queue_size(), win_info)
     local_metrics = self._local_watcher.get_metrics()
     if (qm_size == 0 and not qm_active and empty_polls > 0
             and self._local_watcher.empty_events()
             and (
                 not AbstractOSIntegration.is_windows()
                 or
                 self._local_watcher.win_queue_empty() and self._local_watcher.win_folder_scan_empty())):
         self._dao.update_config("last_sync_date", datetime.datetime.utcnow())
         if local_metrics['last_event'] == 0:
             log.warn("No watchdog event detected but sync is completed")
         if self._sync_started:
             self._sync_started = False
         log.debug('Emitting syncCompleted for engine %s', self.get_uid())
         self.syncCompleted.emit()
Example #6
0
 def remove_remote_id(self, ref, name='ndrive'):
     # Can be move to another class
     path = self._abspath(ref)
     log.trace('Removing xattr %s from %s', name, path)
     locker = self.unlock_path(path, False)
     if AbstractOSIntegration.is_windows():
         pathAlt = path + ":" + name
         try:
             if os.path.exists(pathAlt):
                 os.remove(pathAlt)
         except WindowsError as e:
             if e.errno == os.errno.EACCES:
                 self.unset_path_readonly(path)
                 os.remove(pathAlt)
                 self.set_path_readonly(path)
             else:
                 raise e
         finally:
             self.lock_path(path, locker)
     else:
         try:
             import xattr
             if AbstractOSIntegration.is_mac():
                 xattr.removexattr(path, name)
             else:
                 xattr.removexattr(path, 'user.' + name)
         except IOError as e:
             # Ignore IOError: [Errno 93] Attribute not found ( Mac )
             # IOError: [Errno 61] No data available ( Linux )
             if e.errno == 93 or e.errno == 61:
                 pass
             else:
                 raise
         finally:
             self.lock_path(path, locker)
Example #7
0
 def remove_remote_id(self, ref, name='ndrive'):
     # Can be move to another class
     path = self._abspath(ref)
     log.trace('Removing xattr %s from %s', name, path)
     locker = self.unlock_path(path, False)
     if AbstractOSIntegration.is_windows():
         pathAlt = path + ":" + name
         try:
             os.remove(pathAlt)
         except WindowsError as e:
             if e.errno == os.errno.EACCES:
                 self.unset_path_readonly(path)
                 os.remove(pathAlt)
                 self.set_path_readonly(path)
             else:
                 raise e
         finally:
             self.lock_path(path, locker)
     else:
         try:
             import xattr
             if AbstractOSIntegration.is_mac():
                 xattr.removexattr(path, name)
             else:
                 xattr.removexattr(path, 'user.' + name)
         finally:
             self.lock_path(path, locker)
Example #8
0
 def get_local_client(self, path):
     if AbstractOSIntegration.is_windows():
         from nxdrive.tests.win_local_client import WindowsLocalClient
         return WindowsLocalClient(path)
     if AbstractOSIntegration.is_mac():
         from nxdrive.tests.mac_local_client import MacLocalClient
         return MacLocalClient(path)
     return LocalClient(path)
Example #9
0
 def showMessage(self, title, message, icon=QtGui.QSystemTrayIcon.Information, timeout = 10000):
     if AbstractOSIntegration.is_mac():
         if AbstractOSIntegration.os_version_above("10.8"):
             from nxdrive.osi.darwin.pyNotificationCenter import notify
             # Use notification center
             log.trace("Display systray message: %s | %s | %s", QtCore.QCoreApplication.applicationName(), title, message)
             return notify(title, None, message)
     return QtGui.QSystemTrayIcon.showMessage(self, title, message, icon, timeout)
Example #10
0
 def has_folder_icon(self, ref):
     target_folder = self._abspath(ref)
     if AbstractOSIntegration.is_mac():
         meta_file = os.path.join(target_folder, "Icon\r")
         return os.path.exists(meta_file)
     if AbstractOSIntegration.is_windows():
         meta_file = os.path.join(target_folder, "desktop.ini")
         return os.path.exists(meta_file)
     return False
Example #11
0
 def unset_folder_icon(self, ref):
     '''
         Unset the red icon
     '''
     if AbstractOSIntegration.is_windows():
         # TODO Clean version
         desktop_ini_file_path = os.path.join(self._abspath(ref), "desktop.ini")
     if AbstractOSIntegration.is_mac():
         desktop_ini_file_path = os.path.join(self._abspath(ref), "Icon\r")
     if os.path.exists(desktop_ini_file_path):
         os.remove(desktop_ini_file_path)
 def get_local_client(self, path):
     if AbstractOSIntegration.is_mac() and (
                 self._testMethodName == 'test_local_delete_readonly_folder' or
                 self._testMethodName == 'test_local_rename_readonly_folder'):
         return LocalClient(path)
     # Old mac dont handle case rename
     if AbstractOSIntegration.is_mac() and AbstractOSIntegration.os_version_below("10.10") and (
                 self._testMethodName == 'test_local_rename_file_uppercase_stopped' or
                 self._testMethodName == 'test_local_rename_file_uppercase'):
         return LocalClient(path)
     return super(TestLocalMoveAndRename, self).get_local_client(path)
Example #13
0
    def __init__(self, manager, options, argv=()):
        super(Application, self).__init__(list(argv))
        self.setApplicationName(manager.get_appname())
        self.setQuitOnLastWindowClosed(False)
        self._delegator = None
        self.manager = manager
        from nxdrive.scripting import DriveUiScript
        self.manager.set_script_object(DriveUiScript(manager, self))
        self.options = options
        self.mainEngine = None
        self.filters_dlg = None
        self._conflicts_modals = dict()
        self.current_notification = None
        # Make dialog unique
        self.uniqueDialogs = dict()
        # Init translator
        self._init_translator()

        for _, engine in self.manager.get_engines().iteritems():
            self.mainEngine = engine
            break
        if self.mainEngine is not None and options.debug:
            from nxdrive.engine.engine import EngineLogger
            self.engineLogger = EngineLogger(self.mainEngine)
        self.engineWidget = None

        self.aboutToQuit.connect(self.manager.stop)
        self.manager.dropEngine.connect(self.dropped_engine)

        # Timer to spin the transferring icon
        self.icon_spin_timer = QtCore.QTimer()
        self.icon_spin_timer.timeout.connect(self.spin_transferring_icon)
        self.icon_spin_count = 0

        # Application update
        self.manager.get_updater().appUpdated.connect(self.app_updated)
        self.updated_version = None

        # This is a windowless application mostly using the system tray
        self.setQuitOnLastWindowClosed(False)

        self.setup_systray()

        # Direct Edit conflict
        self.manager.get_drive_edit().driveEditConflict.connect(self._direct_edit_conflict)

        # Check if actions is required, separate method so it can be override
        self.init_checks()
        self.engineWidget = None

        # Setup notification center for Mac
        if AbstractOSIntegration.is_mac():
            if AbstractOSIntegration.os_version_above("10.8"):
                self._setup_notification_center()
Example #14
0
 def showMessage(self,
                 title,
                 message,
                 icon=QtGui.QSystemTrayIcon.Information,
                 timeout=10000):
     if AbstractOSIntegration.is_mac():
         if AbstractOSIntegration.os_version_above("10.8"):
             from nxdrive.osi.darwin.pyNotificationCenter import notify
             # Use notification center
             return notify(title, None, message)
     return QtGui.QSystemTrayIcon.showMessage(self, title, message, icon,
                                              timeout)
Example #15
0
    def current_locale(self):
        """ Detect the OS default language. """

        encoding = locale.getdefaultlocale()[1]
        if AbstractOSIntegration.is_windows():
            l10n_code = ctypes.windll.kernel32.GetUserDefaultUILanguage()
            l10n = locale.windows_locale[l10n_code]
        elif AbstractOSIntegration.is_mac():
            l10n_code = NSLocale.currentLocale()
            l10n = NSLocale.localeIdentifier(l10n_code)
            encoding = 'UTF-8'
        else:
            l10n = locale.getdefaultlocale()[0]

        return '.'.join([l10n, encoding])
Example #16
0
    def __init__(self, manager, *args):
        super(Application, self).__init__(manager, *args)
        self.setQuitOnLastWindowClosed(False)
        self._delegator = None
        from nxdrive.scripting import DriveUiScript
        self.manager.set_script_object(DriveUiScript(manager, self))
        self.mainEngine = None
        self.filters_dlg = None
        self._conflicts_modals = dict()
        self.current_notification = None
        self.default_tooltip = self.manager.app_name

        for _, engine in self.manager.get_engines().iteritems():
            self.mainEngine = engine
            break
        if self.mainEngine is not None and Options.debug:
            from nxdrive.engine.engine import EngineLogger
            self.engineLogger = EngineLogger(self.mainEngine)
        self.engineWidget = None

        self.aboutToQuit.connect(self.manager.stop)
        self.manager.dropEngine.connect(self.dropped_engine)

        # Timer to spin the transferring icon
        self.icon_spin_timer = QtCore.QTimer()
        self.icon_spin_timer.timeout.connect(self.spin_transferring_icon)
        self.icon_spin_count = 0

        # Application update
        self.manager.get_updater().appUpdated.connect(self.app_updated)
        self.updated_version = None

        # This is a windowless application mostly using the system tray
        self.setQuitOnLastWindowClosed(False)

        self.setup_systray()

        # Direct Edit conflict
        self.manager.direct_edit.directEditConflict.connect(self._direct_edit_conflict)

        # Check if actions is required, separate method so it can be override
        self.init_checks()
        self.engineWidget = None

        # Setup notification center for macOS
        if (AbstractOSIntegration.is_mac()
                and AbstractOSIntegration.os_version_above('10.8')):
            self._setup_notification_center()
Example #17
0
 def _check_last_sync(self):
     empty_events = self._local_watcher.empty_events()
     blacklist_size = self._queue_manager.get_errors_count()
     qm_size = self._queue_manager.get_overall_size()
     qm_active = self._queue_manager.active()
     empty_polls = self._remote_watcher.get_metrics()["empty_polls"]
     if not AbstractOSIntegration.is_windows():
         win_info = 'not Windows'
     else:
         win_info = 'Windows with win queue size = %d and win folder scan size = %d' % (
             self._local_watcher.get_win_queue_size(), self._local_watcher.get_win_folder_scan_size())
     log.debug('Checking sync completed: queue manager is %s, overall size = %d, empty polls count = %d'
               ', local watcher empty events = %d, blacklist = %d, %s',
               'active' if qm_active else 'inactive', qm_size, empty_polls,
                 empty_events, blacklist_size, win_info)
     local_metrics = self._local_watcher.get_metrics()
     if (qm_size == 0 and not qm_active and empty_polls > 0
             and empty_events):
         if blacklist_size != 0:
             self.syncPartialCompleted.emit()
             return
         self._dao.update_config("last_sync_date", datetime.datetime.utcnow())
         if local_metrics['last_event'] == 0:
             log.warn("No watchdog event detected but sync is completed")
         if self._sync_started:
             self._sync_started = False
         log.debug('Emitting syncCompleted for engine %s', self.get_uid())
         self.syncCompleted.emit()
Example #18
0
    def _check_last_sync(self):
        from nxdrive.engine.watcher.local_watcher import WIN_MOVE_RESOLUTION_PERIOD

        qm_active = self._queue_manager.active()
        qm_size = self._queue_manager.get_overall_size()
        empty_polls = self._remote_watcher.get_metrics()["empty_polls"]
        log.debug(
            "Checking sync completed: queue manager is %s, overall size = %d, empty polls count = %d",
            "active" if qm_active else "inactive",
            qm_size,
            empty_polls,
        )
        local_metrics = self._local_watcher.get_metrics()
        if (
            qm_size == 0
            and not qm_active
            and empty_polls > 0
            and self._local_watcher.empty_events()
            and (
                not AbstractOSIntegration.is_windows()
                or self._local_watcher.win_queue_empty()
                and self._local_watcher.win_folder_scan_empty()
            )
        ):
            self._dao.update_config("last_sync_date", datetime.datetime.utcnow())
            if local_metrics["last_event"] == 0:
                log.warn("No watchdog event detected but sync is completed")
            if self._sync_started:
                self._sync_started = False
            log.debug("Emitting syncCompleted for engine %s", self.get_uid())
            self.syncCompleted.emit()
    def test_finder_in_use(self):
        if not AbstractOSIntegration.is_mac():
            raise SkipTest('Not relevant on Linux or Windows')
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        self.local_client_1.make_file('/', u'File.txt',
                                      content=u'Some Content 1'.encode('utf-8'))

        # Emulate the Finder in use flag
        OSX_FINDER_INFO_ENTRY_SIZE = 32
        key = (OSX_FINDER_INFO_ENTRY_SIZE)*[0]
        key[0] = 0x62
        key[1] = 0x72
        key[2] = 0x6F
        key[3] = 0x6B
        key[4] = 0x4D
        key[5] = 0x41
        key[6] = 0x43
        key[7] = 0x53
        import xattr
        xattr.setxattr(self.local_client_1._abspath(u'/File.txt'), xattr.XATTR_FINDERINFO_NAME, bytes(bytearray(key)))

        # The file should not be synced and there have no remote id
        self.wait_sync(wait_for_async=True, fail_if_timeout=False, timeout=10)
        info = self.local_client_1.get_remote_id(u'/File.txt')
        self.assertIsNone(info)

        # Remove the Finder flag
        self.local_client_1.remove_remote_id(u'/File.txt', xattr.XATTR_FINDERINFO_NAME)

        # The sync process should now handle the file and sync it
        self.wait_sync(wait_for_async=True, fail_if_timeout=False, timeout=10)
        info = self.local_client_1.get_remote_id(u'/File.txt')
        self.assertIsNotNone(info)
Example #20
0
    def load_config(self, parser):
        import ConfigParser
        config_name = 'config.ini'
        config = ConfigParser.ConfigParser()
        configs = []
        path = os.path.join(os.path.dirname(sys.executable), config_name)
        if os.path.exists(path):
            configs.append(path)
        if os.path.exists(config_name):
            configs.append(config_name)
        user_ini = os.path.expanduser(os.path.join(Options.nxdrive_home, config_name))
        if os.path.exists(user_ini):
            configs.append(user_ini)
        if configs:
            config.read(configs)

        args = AbstractOSIntegration.get(None).get_system_configuration()
        if config.has_option(ConfigParser.DEFAULTSECT, 'env'):
            env = config.get(ConfigParser.DEFAULTSECT, 'env')
            for item in config.items(env):
                if item[0] == 'env':
                    continue
                value = item[1]
                if value == '':
                    continue
                if '\n' in item[1]:
                    # Treat multiline option as a set
                    value = tuple(sorted(item[1].split()))
                args[item[0].replace('-', '_')] = value
        if args:
            Options.update(args, setter='local')
            parser.set_defaults(**args)
Example #21
0
 def _handle_watchdog_event_on_known_acquired_pair(self, doc_pair, evt, rel_path):
     if evt.event_type == 'deleted':
         # Delay on Windows the delete event
         if self._windows:
             self._win_lock.acquire()
             log.debug('Add pair to delete events: %r', doc_pair)
             try:
                 self._delete_events[doc_pair.remote_ref] = (current_milli_time(), doc_pair)
             finally:
                 self._win_lock.release()
         else:
             # In case of case sensitive can be an issue
             if self.client.exists(doc_pair.local_path):
                 remote_id = self.client.get_remote_id(doc_pair.local_path)
                 if remote_id == doc_pair.remote_ref or remote_id is None:
                     # This happens on update don't do anything
                     return
             self._handle_watchdog_delete(doc_pair)
         return
     if evt.event_type == 'created':
         # NXDRIVE-471 case maybe
         remote_ref = self.client.get_remote_id(rel_path)
         if remote_ref is None:
             log.debug("Created event on a known pair with no remote_ref,"
                       " this should only happen in case of a quick move and copy-paste: %r", doc_pair)
             return
         else:
             # NXDRIVE-509
             log.debug("Created event on a known pair with a remote_ref: %r", doc_pair)
     local_info = self.client.get_info(rel_path, raise_if_missing=False)
     if local_info is not None:
         # Unchanged folder
         if doc_pair.folderish:
             log.debug('Unchanged folder %s (watchdog event [%s]), only update last_local_updated',
                       rel_path, evt.event_type)
             self._dao.update_local_modification_time(doc_pair, local_info)
             return
         if doc_pair.local_state == 'synchronized':
             digest = local_info.get_digest()
             # Unchanged digest, can be the case if only the last modification time or file permissions
             # have been updated
             if doc_pair.local_digest == digest:
                 log.debug('Digest has not changed for %s (watchdog event [%s]), only update last_local_updated',
                           rel_path, evt.event_type)
                 if local_info.remote_ref is None:
                     self.client.set_remote_id(rel_path, doc_pair.remote_ref)
                 self._dao.update_local_modification_time(doc_pair, local_info)
                 return
             doc_pair.local_digest = digest
             doc_pair.local_state = 'modified'
         if AbstractOSIntegration.is_mac() and evt.event_type == 'modified' and doc_pair.remote_ref is not None and doc_pair.remote_ref != local_info.remote_ref:
             original_pair = self._dao.get_normal_state_from_remote(local_info.remote_ref)
             original_info = None
             if original_pair is not None:
                 original_info = self.client.get_info(original_pair.local_path, raise_if_missing=False)
             if original_info is not None and original_info.remote_ref == local_info.remote_ref:
                 log.debug("MacOSX has postponed overwriting of xattr, need to reset remote_ref for %r", doc_pair)
                 # We are in a copy/paste situation with OS overriding the xattribute
                 self.client.set_remote_id(doc_pair.local_path, doc_pair.remote_ref)
         self._dao.update_local_state(doc_pair, local_info)
Example #22
0
    def __init__(self, root, path, folderish, last_modification_time, size=0,
                 digest_func='md5', check_suspended=None, remote_ref=None):

        # Function to check during long-running processing like digest
        # computation if the synchronization thread needs to be suspended
        self.check_suspended = check_suspended
        self.size = size
        filepath = os.path.join(root, path[1:].replace(u'/', os.path.sep))
        root = unicodedata.normalize('NFC', root)
        path = unicodedata.normalize('NFC', path)
        normalized_filepath = os.path.join(root, path[1:].replace(u'/', os.path.sep))
        self.filepath = normalized_filepath

        # Normalize name on the file system if not normalized
        # See https://jira.nuxeo.com/browse/NXDRIVE-188
        if os.path.exists(filepath) and normalized_filepath != filepath and not AbstractOSIntegration.is_mac():
            log.debug('Forcing normalization of %r to %r', filepath, normalized_filepath)
            os.rename(filepath, normalized_filepath)

        self.root = root  # the sync root folder local path
        self.path = path  # the truncated path (under the root)
        self.folderish = folderish  # True if a Folder
        self.remote_ref = remote_ref

        # Last OS modification date of the file
        self.last_modification_time = last_modification_time

        # Function to use
        self._digest_func = digest_func.lower()

        # Precompute base name once and for all are it's often useful in
        # practice
        self.name = os.path.basename(path)
Example #23
0
    def load_config(self, parser):
        import ConfigParser
        config_name = 'config.ini'
        config = ConfigParser.ConfigParser()
        configs = []
        path = os.path.join(os.path.dirname(sys.executable), config_name)
        if os.path.exists(path):
            configs.append(path)
        if os.path.exists(config_name):
            configs.append(config_name)
        user_ini = os.path.expanduser(
            os.path.join(Options.nxdrive_home, config_name))
        if os.path.exists(user_ini):
            configs.append(user_ini)
        if configs:
            config.read(configs)

        args = AbstractOSIntegration.get(None).get_system_configuration()
        if config.has_option(ConfigParser.DEFAULTSECT, 'env'):
            env = config.get(ConfigParser.DEFAULTSECT, 'env')
            for item in config.items(env):
                if item[0] == 'env':
                    continue
                value = item[1]
                if value == '':
                    continue
                if '\n' in item[1]:
                    # Treat multiline option as a set
                    value = tuple(sorted(item[1].split()))
                args[item[0].replace('-', '_')] = value
        if args:
            Options.update(args, setter='local')
            parser.set_defaults(**args)
 def test_untrash_file_with_rename(self):
     self.local_client_1.make_file('/', 'File_To_Delete.txt', 'This is a content')
     self.wait_sync()
     self.assertTrue(self.remote_document_client_1.exists('/File_To_Delete.txt'))
     uid = self.local_client_1.get_remote_id('/File_To_Delete.txt')
     old_info = self.remote_document_client_1.get_info('/File_To_Delete.txt', use_trash=True)
     abs_path = self.local_client_1.abspath('/File_To_Delete.txt')
     # Pretend we had trash the file
     shutil.move(abs_path, os.path.join(self.local_test_folder_1, 'File_To_Delete2.txt'))
     self.wait_sync(wait_for_async=True)
     self.assertFalse(self.remote_document_client_1.exists('/File_To_Delete.txt'))
     self.assertFalse(self.local_client_1.exists('/File_To_Delete.txt'))
     with open(os.path.join(self.local_test_folder_1, 'File_To_Delete2.txt'), 'w') as f:
         f.write('New content')
     if AbstractOSIntegration.is_windows():
         # Python API overwrite the tag by default
         with open(os.path.join(self.local_test_folder_1, 'File_To_Delete2.txt:ndrive'), 'w') as f:
             f.write(uid)
     # See if it untrash or recreate
     shutil.move(os.path.join(self.local_test_folder_1, 'File_To_Delete2.txt'), self.local_client_1.abspath('/'))
     self.wait_sync(wait_for_async=True)
     self.assertTrue(self.remote_document_client_1.exists(old_info.uid))
     self.assertTrue(self.local_client_1.exists('/File_To_Delete2.txt'))
     self.assertFalse(self.local_client_1.exists('/File_To_Delete.txt'))
     self.assertEqual(self.local_client_1.get_content('/File_To_Delete2.txt'), 'New content')
 def is_ignored(self, parent_ref, file_name):
     # Add parent_ref to be able to filter on size if needed
     ignore = False
     # Office temp file
     # http://support.microsoft.com/kb/211632
     if file_name.startswith("~") and file_name.endswith(".tmp"):
         return True
     # Emacs auto save file
     # http://www.emacswiki.org/emacs/AutoSave
     if file_name.startswith("#") and file_name.endswith("#") and len(file_name) > 2:
         return True
     for suffix in self.ignored_suffixes:
         if file_name.endswith(suffix):
             ignore = True
             break
     for prefix in self.ignored_prefixes:
         if file_name.startswith(prefix):
             ignore = True
             break
     if ignore:
         return True
     if AbstractOSIntegration.is_windows():
         # NXDRIVE-465
         ref = self.get_children_ref(parent_ref, file_name)
         path = self._abspath(ref)
         if not os.path.exists(path):
             return False
         import win32con
         import win32api
         attrs = win32api.GetFileAttributes(path)
         if attrs & win32con.FILE_ATTRIBUTE_SYSTEM == win32con.FILE_ATTRIBUTE_SYSTEM:
             return True
         if attrs & win32con.FILE_ATTRIBUTE_HIDDEN == win32con.FILE_ATTRIBUTE_HIDDEN:
             return True
     return False
    def copy_with_xattr(src, dst):
        """
        Custom copy tree method that also copies xattr along with
        shutil.copytree functionality.
        """

        if AbstractOSIntegration.is_windows():
            # Make a copy of file1 using shell (to copy including xattr)
            shell.SHFileOperation((0, shellcon.FO_COPY, src, dst,
                                   shellcon.FOF_NOCONFIRMATION, None, None))
        elif AbstractOSIntegration.is_mac():
            fm = Cocoa.NSFileManager.defaultManager()
            fm.copyItemAtPath_toPath_error_(src, dst, None)
        else:
            shutil.copy2(src, dst)
            remote_id = xattr.getxattr(src, 'user.ndrive')
            xattr.setxattr(dst, 'user.ndrive', remote_id)
Example #27
0
 def test_move_and_copy_paste_folder_original_location_stopped(self):
     if AbstractOSIntegration.is_linux():
         raise SkipTest(
             "NXDRIVE-471: Not handled under Linux as creation time is not stored"
         )
     self._move_and_copy_paste_folder(self.folder_path_1,
                                      self.folder_path_2,
                                      os.path.dirname(self.folder_path_1))
    def test_local_delete_readonly_folder(self):
        local_client = self.local_client_1
        remote_client = self.remote_document_client_1

        # Check local folder
        self.assertTrue(local_client.exists(u'/Original Folder 1'))
        folder_1_state = self.get_dao_state_from_engine_1(
            u'/Original Folder 1')
        self.assertTrue(folder_1_state.remote_can_delete)

        # Set remote folder as readonly for test user
        folder_1_path = TEST_WORKSPACE_PATH + u'/Original Folder 1'
        op_input = "doc:" + folder_1_path
        self.root_remote_client.execute("Document.SetACE",
                                        op_input=op_input,
                                        user=self.user_1,
                                        permission="Read")
        self.root_remote_client.block_inheritance(folder_1_path,
                                                  overwrite=False)

        self.wait_sync(wait_for_async=True)

        # Check can_delete flag in pair state
        folder_1_state = self.get_dao_state_from_engine_1(
            u'/Original Folder 1')
        self.assertFalse(folder_1_state.remote_can_delete)

        # Delete local folder
        local_client.delete(u'/Original Folder 1')
        self.assertFalse(local_client.exists(u'/Original Folder 1'))

        self.wait_sync(wait_for_async=True)
        self.assertEqual(self.engine_1.get_dao().get_sync_count(), 6)

        # Check remote folder and its children have not been deleted
        folder_1_remote_info = remote_client.get_info(u'/Original Folder 1')
        self.assertEqual(folder_1_remote_info.name, u'Original Folder 1')

        file_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Original File 1.1.txt')
        self.assertEqual(file_1_1_remote_info.name, u'Original File 1.1.txt')

        folder_1_1_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.1')
        self.assertEqual(folder_1_1_remote_info.name, u'Sub-Folder 1.1')

        folder_1_2_remote_info = remote_client.get_info(
            u'/Original Folder 1/Sub-Folder 1.2')
        self.assertEqual(folder_1_2_remote_info.name, u'Sub-Folder 1.2')

        if not AbstractOSIntegration.is_windows():
            # Check filter has been created
            self.assertTrue(self.engine_1.get_dao().is_filter(
                folder_1_state.remote_parent_path + '/' +
                folder_1_state.remote_ref))

            # Check local folder haven't been re-created
            self.assertFalse(local_client.exists(u'/Original Folder 1'))
Example #29
0
    def test_binding_initialization_and_first_sync(self):
        local = self.local_client_1
        remote = self.remote_document_client_1

        # Create some documents in a Nuxeo workspace and bind this server to a
        # Nuxeo Drive local folder
        self.make_server_tree()

        # The root binding operation does not create the local folder yet.
        self.assertFalse(local.exists('/'))

        # Launch ndrive and check synchronization
        self.engine_1.start()
        self.wait_sync(wait_for_async=True)
        self.assertTrue(local.exists('/'))
        self.assertTrue(local.exists('/Folder 1'))
        self.assertEquals(local.get_content('/Folder 1/File 1.txt'), "aaa")
        self.assertTrue(local.exists('/Folder 1/Folder 1.1'))
        self.assertEquals(local.get_content('/Folder 1/Folder 1.1/File 2.txt'),
                          "bbb")
        self.assertTrue(local.exists('/Folder 1/Folder 1.2'))
        self.assertEquals(local.get_content('/Folder 1/Folder 1.2/File 3.txt'),
                          "ccc")
        self.assertTrue(local.exists('/Folder 2'))
        # Cannot predict the resolution in advance
        self.assertTrue(remote.get_content(self._duplicate_file_1),
                        "Some content.")
        self.assertTrue(remote.get_content(self._duplicate_file_2),
                        "Other content.")
        if local.get_content(
                '/Folder 2/Duplicated File.txt') == "Some content.":
            self.assertEquals(
                local.get_content('/Folder 2/Duplicated File__1.txt'),
                "Other content.")
        else:
            self.assertEquals(
                local.get_content('/Folder 2/Duplicated File.txt'),
                "Other content.")
            self.assertEquals(
                local.get_content('/Folder 2/Duplicated File__1.txt'),
                "Some content.")
        self.assertEquals(local.get_content('/Folder 2/File 4.txt'), "ddd")
        self.assertEquals(local.get_content('/File 5.txt'), "eee")

        # Unbind root and resynchronize
        remote.unregister_as_root(self.workspace)
        # Since errors are generated by the deletion events sent by Watchdog for the workspace children under UNIX,
        # don't enforce errors and increase timeout
        if not AbstractOSIntegration.is_windows():
            timeout = 60
            enforce_errors = False
        else:
            timeout = DEFAULT_WAIT_SYNC_TIMEOUT
            enforce_errors = True
        self.wait_sync(wait_for_async=True,
                       timeout=timeout,
                       enforce_errors=enforce_errors)
        self.assertFalse(local.exists('/'))
Example #30
0
 def get_path_remote_id(path, name="ndrive"):
     if AbstractOSIntegration.is_windows():
         path = path + ":" + name
         try:
             with open(path, "r") as f:
                 return unicode(f.read(), 'utf-8')
         except:
             return None
     else:
         import xattr
         try:
             if AbstractOSIntegration.is_mac():
                 value = xattr.getxattr(path, name)
             else:
                 value = xattr.getxattr(path, 'user.' + name)
             return unicode(value, 'utf-8')
         except:
             return None
Example #31
0
 def testLogs(self):
     from nxdrive.osi import AbstractOSIntegration
     if AbstractOSIntegration.is_windows():
         raise SkipTest("Temporarily skipped, need to investigate")
     # NXDRIVE-358
     report = Report(self.manager, os.path.join(self.folder, "report.zip"))
     log.debug("Strange encoding \xe9")
     log.debug(u"Unicode encoding \xe8")
     report.generate()
Example #32
0
 def testLogs(self):
     from nxdrive.osi import AbstractOSIntegration
     if AbstractOSIntegration.is_windows():
         raise SkipTest("Temporarily skipped, need to investigate")
     # NXDRIVE-358
     report = Report(self.manager, os.path.join(self.folder, "report.zip"))
     log.debug("Strange encoding \xe9")
     log.debug(u"Unicode encoding \xe8")
     report.generate()
Example #33
0
    def test_synchronize_deletion(self):
        local = self.local_client_1
        remote = self.remote_document_client_1
        self.engine_1.start()

        # Create a remote folder with 2 children then synchronize
        remote.make_folder('/', 'Remote folder')
        remote.make_file('/Remote folder', 'Remote file 1.odt',
                         'Some content.')
        remote.make_file('/Remote folder', 'Remote file 2.odt',
                         'Other content.')

        self.wait_sync(wait_for_async=True)
        self.assertTrue(local.exists('/Remote folder'))
        self.assertTrue(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertTrue(local.exists('/Remote folder/Remote file 2.odt'))

        # Delete remote folder then synchronize
        remote.delete('/Remote folder')

        self.wait_sync(wait_for_async=True)
        self.assertFalse(local.exists('/Remote folder'))
        self.assertFalse(local.exists('/Remote folder/Remote file 1.odt'))
        self.assertFalse(local.exists('/Remote folder/Remote file 2.odt'))

        # Create a local folder with 2 children then synchronize
        local.make_folder('/', 'Local folder')
        local.make_file('/Local folder', 'Local file 1.odt', 'Some content.')
        local.make_file('/Local folder', 'Local file 2.odt', 'Other content.')

        self.wait_sync()
        self.assertTrue(remote.exists('/Local folder'))
        self.assertTrue(remote.exists('/Local folder/Local file 1.odt'))
        self.assertTrue(remote.exists('/Local folder/Local file 2.odt'))

        # Delete local folder then synchronize
        time.sleep(OS_STAT_MTIME_RESOLUTION)
        local.delete('/Local folder')

        # Since errors are generated by the deletion events sent by Watchdog for the folder children under UNIX,
        # don't enforce errors and increase timeout
        if not AbstractOSIntegration.is_windows():
            timeout = 60
            enforce_errors = False
        else:
            timeout = DEFAULT_WAIT_SYNC_TIMEOUT
            enforce_errors = True
        self.wait_sync(timeout=timeout, enforce_errors=enforce_errors)
        self.assertFalse(remote.exists('/Local folder'))
        # Wait for async completion as recursive deletion of children is done
        # by the BulkLifeCycleChangeListener which is asynchronous
        self.wait()
        self.assertFalse(remote.exists('/Local folder/Local file 1.odt'))
        self.assertFalse(remote.exists('/Local folder/Local file 2.odt'))
 def _new_notification(self, notification):
     if not notification.is_bubble():
         return
     if AbstractOSIntegration.is_mac():
         if AbstractOSIntegration.os_version_above("10.8"):
             from nxdrive.osi.darwin.pyNotificationCenter import notify, NotificationDelegator
             if self._delegator is None:
                 self._delegator = NotificationDelegator.alloc().init()
                 self._delegator._manager = self.manager
             # Use notification center
             userInfo = dict()
             userInfo["uuid"] = notification.get_uid()
             return notify(notification.get_title(), None, notification.get_description(), userInfo=userInfo)
     self.current_notification = notification
     icon = QtGui.QSystemTrayIcon.Information
     if (notification.get_level() == Notification.LEVEL_WARNING):
         icon = QtGui.QSystemTrayIcon.Warning
     elif (notification.get_level() == Notification.LEVEL_ERROR):
         icon =  QtGui.QSystemTrayIcon.Critical
     self.show_message(notification.get_title(), notification.get_description(), icon=icon)
Example #35
0
 def get_creation_time(self, child_full_path):
     if self._windows:
         return os.path.getctime(child_full_path)
     else:
         stat = os.stat(child_full_path)
         # Try inode number as on HFS seems to be increasing
         if AbstractOSIntegration.is_mac() and hasattr(stat, "st_ino"):
             return stat.st_ino
         if hasattr(stat, "st_birthtime"):
             return stat.st_birthtime
         return 0
Example #36
0
    def rename(self, ref, to_name):
        """Rename a local file or folder

        Return the actualized info object.

        """
        new_name = safe_filename(to_name)
        source_os_path = self._abspath(ref)
        parent = ref.rsplit(u'/', 1)[0]
        old_name = ref.rsplit(u'/', 1)[1]
        parent = u'/' if parent == '' else parent
        locker = self.unlock_ref(ref)
        try:
            # Check if only case renaming
            if (old_name != new_name and old_name.lower() == new_name.lower()
                and not self.is_case_sensitive()):
                # Must use a temp rename as FS is not case sensitive
                temp_path = os.tempnam(self._abspath(parent),
                                       '.ren_' + old_name + '_')
                if AbstractOSIntegration.is_windows():
                    import ctypes
                    ctypes.windll.kernel32.SetFileAttributesW(
                                                unicode(temp_path), 2)
                os.rename(source_os_path, temp_path)
                source_os_path = temp_path
                # Try the os rename part
                target_os_path = self._abspath(os.path.join(parent, new_name))
            else:
                target_os_path, new_name = self._abspath_deduped(parent,
                                                                new_name, old_name)
            if old_name != new_name:
                os.rename(source_os_path, target_os_path)
            if AbstractOSIntegration.is_windows():
                import ctypes
                # See http://msdn.microsoft.com/en-us/library/aa365535%28v=vs.85%29.aspx
                ctypes.windll.kernel32.SetFileAttributesW(
                                            unicode(target_os_path), 128)
            new_ref = self.get_children_ref(parent, new_name)
            return self.get_info(new_ref)
        finally:
            self.lock_ref(ref, locker & 2)
Example #37
0
    def get_path_remote_id(path, name="ndrive"):
        if AbstractOSIntegration.is_windows():
            path = path + ":" + name
            try:
                with open(path, "r") as f:
                    return f.read()
            except:
                return None
        else:
            import xattr

            try:
                if AbstractOSIntegration.is_mac():
                    value = xattr.getxattr(path, name)
                else:
                    value = xattr.getxattr(path, "user." + name)
                if type(value).__name__ == "unicode":
                    value = unicode(value)
                return value
            except:
                return None
Example #38
0
 def _set_root_icon(self):
     local_client = self.get_local_client()
     if not local_client.exists('/') or local_client.has_folder_icon('/'):
         return
     if AbstractOSIntegration.is_mac():
         if AbstractOSIntegration.os_version_below("10.10"):
             icon = find_icon("NuxeoDrive_Mac_Folder.dat")
         else:
             icon = find_icon("NuxeoDrive_Mac_Yosemite_Folder.dat")
     elif AbstractOSIntegration.is_windows():
         icon = find_icon("NuxeoDrive_Windows_Folder.ico")
     else:
         # No implementation on Linux
         return
     if icon is None:
         return
     locker = local_client.unlock_ref('/', unlock_parent=False)
     try:
         local_client.set_folder_icon('/', icon)
     finally:
         local_client.lock_ref('/', locker)
Example #39
0
    def set_remote_id(self, ref, remote_id, name="ndrive"):
        if type(remote_id).__name__ == "unicode":
            remote_id = unicodedata.normalize("NFC", remote_id).encode("utf-8")
        # Can be move to another class
        path = self._abspath(ref)
        log.trace("Setting xattr %s with value %r on %r", name, remote_id, path)
        locker = self.unlock_path(path, False)
        if AbstractOSIntegration.is_windows():
            pathAlt = path + ":" + name
            try:
                if not os.path.exists(path):
                    raise NotFound()
                stat = os.stat(path)
                with open(pathAlt, "w") as f:
                    f.write(remote_id)
                # Avoid time modified change
                os.utime(path, (stat.st_atime, stat.st_mtime))
            except IOError as e:
                # Should not happen
                if e.errno == os.errno.EACCES:
                    self.unset_path_readonly(path)
                    with open(pathAlt, "w") as f:
                        f.write(remote_id)
                    self.set_path_readonly(path)
                else:
                    raise e
            finally:
                self.lock_path(path, locker)
        else:
            try:
                import xattr

                stat = os.stat(path)
                if AbstractOSIntegration.is_mac():
                    xattr.setxattr(path, name, remote_id)
                else:
                    xattr.setxattr(path, "user." + name, remote_id)
                os.utime(path, (stat.st_atime, stat.st_mtime))
            finally:
                self.lock_path(path, locker)
Example #40
0
 def test_fileinfo_normalization(self):
     import os
     from nxdrive.client.local_client import FileInfo
     from nose.plugins.skip import SkipTest
     from nxdrive.osi import AbstractOSIntegration
     if AbstractOSIntegration.is_mac():
         raise SkipTest("Normalization dont work on Mac")
     self.engine_1.stop()
     name = u'Teste\u0301'
     self.local_client.make_file('/', name, 'Test')
     info = FileInfo(self.local_client.base_folder, '/' + name, False, 0)
     # The encoding should be different - cannot trust the get_children as they use FileInfo
     children = os.listdir(self.local_client._abspath('/'))
     children.sort()
     self.assertNotEqual(children[0], name)