Пример #1
0
def on_change(ignored, path, mask):
    """
    @param ignored: DO NOT USE. Read: http://twistedmatrix.com/documents/current/api/twisted.internet.inotify.html
    @param path: FilePath on which the event happened.
    @param mask: inotify event as hexadecimal masks
    """

    global proc
    events = set(inotify.humanReadableMask(mask))
    print(events)
    if debug:
        click.echo(
            '==> reloopd, DEBUG : inotify event(s) - [{}], path: {}'.format(
                ', '.join(inotify.humanReadableMask(mask)), path))

    if ('create' or 'delete' or 'modify') in events:

        if proc is not None and proc.poll() is None:
            click.echo('==> reloopd, INFO  : terminating previous process')
            proc.kill()
            proc.wait()

        if before_command:
            subprocess.call(shlex.split(before_command))

        proc = subprocess.Popen(shlex.split(command))
Пример #2
0
    def test_humanReadableMask(self):
        """
        L{inotify.humaReadableMask} translates all the possible event
        masks to a human readable string.
        """
        for mask, value in inotify._FLAG_TO_HUMAN:
            self.assertEqual(inotify.humanReadableMask(mask)[0], value)

        checkMask = inotify.IN_CLOSE_WRITE | inotify.IN_ACCESS | inotify.IN_OPEN
        self.assertEqual(set(inotify.humanReadableMask(checkMask)), set(["close_write", "access", "open"]))
Пример #3
0
    def test_humanReadableMask(self):
        """
        L{inotify.humaReadableMask} translates all the possible event
        masks to a human readable string.
        """
        for mask, value in inotify._FLAG_TO_HUMAN:
            self.assertEqual(inotify.humanReadableMask(mask)[0], value)

        checkMask = (inotify.IN_CLOSE_WRITE | inotify.IN_ACCESS
                     | inotify.IN_OPEN)
        self.assertEqual(set(inotify.humanReadableMask(checkMask)),
                         set(['close_write', 'access', 'open']))
Пример #4
0
 def notify(self, ignore, filepath, mask):
     # self.input = False
     print "event %s on %s" % (', '.join(inotify.humanReadableMask(mask)), filepath)
     action = inotify.humanReadableMask(mask)[0]
     # This might break.... depending on the queue of the 
     path = os.path.relpath(filepath.path)
     # Check for swp or temp file
     check = path.endswith('swp') or path.endswith('~') or path.endswith('swx') or '.goutputstream' in path
     # update userfilemap
     if action == 'attrib' or action == "moved_to":
         if not check:
             self.sendData(['upload-request',path])
     if action == 'delete' or action == 'moved_from':
         if not check:
             self.sendData(['remove',path])
Пример #5
0
    def inotify(self, ignored, filepath, mask):
        """
            Callback for the INotify. It should call the sse resource with the
            changed layouts in the layout file if there are changes in the
            layout file.
            It calls the inotify_callback method first which must be overwritten
            by its children.
        """
        hmask = humanReadableMask(mask)

        # Some editors move the file triggering several events in inotify. All
        # of them change some attribute of the file, so if that event happens,
        # see if there are changes and alert the sse resource in that case.
        if 'attrib' in hmask or 'modify' in hmask:
            self.fp.close()
            self.fp = open(self.fp.name, 'r')
            self.fp.seek(0)

            jdata = {}
            self.inotify_callback(jdata)

            changes = 0
            for _, l in jdata.items():
                changes += len(l)

            if changes > 0:
                for callback in self.inotify_callbacks:
                    callback(jdata)
                log.msg("Change in %s" % self.fp.name)

        # Some editors move the file and inotify lose track of the file, so the
        # notifier must be restarted when some attribute changed is received.
        if 'attrib' in hmask:
            self.notifier.stopReading()
            self.setup_inotify()
Пример #6
0
    def notify(self, notifier: INotify, filepath: FilePath, mask: int) -> None:
        try:
            maskNames = humanReadableMask(mask)
            if maskNames[0] == 'delete_self':
                if not filepath.exists():
                    log.info("%s delete_self", filepath)
                    self.fileGone()
                    return
                else:
                    log.warn(
                        "%s delete_self event but file is here. "
                        "probably a new version moved in", filepath)

            # we could filter these out in the watch() call, but I want
            # the debugging
            if maskNames[0] in ['open', 'access', 'close_nowrite', 'attrib']:
                log.debug("%s %s event, ignoring" % (filepath, maskNames))
                return

            try:
                if filepath.getModificationTime() == self.lastWriteTimestamp:
                    log.debug("%s changed, but we did this write", filepath)
                    return
            except OSError as e:
                log.error("%s: %r" % (filepath, e))
                # getting OSError no such file, followed by no future reads
                reactor.callLater(.5, self.addWatch)  # ?

                return

            log.info("reread %s because of %s event", filepath, maskNames)

            self.reread()
        except Exception:
            traceback.print_exc()
Пример #7
0
				def _notify(ignored, filepath, mask, file=file):
					if filepath.isfile() and file.endswith(filepath.basename()):
						log.msg(self, 'change', filepath,
							humanReadableMask(mask))

						# Reload file
						self.read(filepath.path)
Пример #8
0
    def notify(self, notifier, filepath, mask):
        try:
            maskNames = humanReadableMask(mask)
            if maskNames[0] == 'delete_self':
                if not filepath.exists():
                    log.info("%s delete_self", filepath)
                    self.fileGone()
                    return
                else:
                    log.warn("%s delete_self event but file is here. "
                             "probably a new version moved in",
                             filepath)

            # we could filter these out in the watch() call, but I want
            # the debugging
            if maskNames[0] in ['open', 'access', 'close_nowrite', 'attrib']:
                log.debug("%s %s event, ignoring" % (filepath, maskNames))
                return

            try:
                if filepath.getModificationTime() == self.lastWriteTimestamp:
                    log.debug("%s changed, but we did this write", filepath)
                    return
            except OSError as e:
                log.error("%s: %r" % (filepath, e))
                # getting OSError no such file, followed by no future reads
                reactor.callLater(.5, self.addWatch) # ?

                return

            log.info("reread %s because of %s event", filepath, maskNames)

            self.reread()
        except Exception:
            traceback.print_exc()
Пример #9
0
 def onChange(self, watch, fpath, mask):
     index = fpath.path.find('onedir')
     path = fpath.path[index:]
     match = re.search('CS3240/(.*)/onedir', fpath.path)
     if match:
         user = match.group(1)
         cmd = ' '.join(inotify.humanReadableMask(mask))
         self.dispatch(path, cmd, user)
Пример #10
0
 def onChange(self, watch, fpath, mask):
     index = fpath.path.find('onedir')
     path = fpath.path[index:]
     match = re.search('CS3240/(.*)/onedir', fpath.path)
     if match:
         user = match.group(1)
         cmd = ' '.join(inotify.humanReadableMask(mask))
         self.dispatch(path, cmd, user)
Пример #11
0
            def notify(self, filepath, mask):
                filepath = filepath.realpath().path[len(watch_dir) + 1:]
                if not filepath.endswith('___jb_bak___') and not filepath.endswith('___jb_old___'):
                    print "%s> %s" % (', '.join(inotify.humanReadableMask(mask)), filepath)

                    new_cmd = raw_command + [os.path.join(dst_dir, filepath), os.path.join(src_ref, filepath)]
                    process = subprocess.Popen(new_cmd, env=env)
                    process.wait()
Пример #12
0
    def notify(self, unknown, filepath, mask):
        logger.debug("event %s on %s" % (", ".join(inotify.humanReadableMask(mask)), filepath))

        basename = filepath.basename()
        if not basename.endswith(config.GROWING_FILE_SUFFIX):
            return
        path = os.path.join(filepath.dirname(), basename)
        if mask == inotify.IN_CREATE:
            self.handle_in_create(path)
        elif mask == inotify.IN_DELETE:
            self.handle_in_delete(path)
Пример #13
0
def notify(ignored, filepath, mask):
   """
   For historical reasons, an opaque handle is passed as first
   parameter. This object should never be used.

   @param filepath: FilePath on which the event happened.
   @param mask: inotify event as hexadecimal masks
   """
   print mask
   print "event %s on %s" % (
       ', '.join(inotify.humanReadableMask(mask)), filepath)
Пример #14
0
	def handle_change(self, stuff, path, mask):
		mask_str = inotify.humanReadableMask(mask)
		log.noise('Event: {} ({})'.format(path, mask_str))

		## Filtering
		path_real = path.realpath()
		if not path_real.isfile():
			log.debug( 'Ignoring event for'
				' non-regular file: {} (realpath: {})'.format(path, path_real) )
			return
		dir_key = path_real.parent().realpath()
		if dir_key not in self.paths_watch:
			log.warn( 'Ignoring event for file outside of watched'
				' set of paths: {} (realpath: {})'.format(path, path_real) )
			return
		for pat in self.paths_watch[dir_key]:
			if fnmatch(bytes(path.basename()), pat): break
		else:
			log.noise( 'Non-matched path in one of'
				' the watched dirs: {} (realpath: {})'.format(path, path_real) )
			return

		## Get last position
		if self.paths_pos.get(path_real) is not None:
			pos, size, data = self.paths_pos[path_real]
			if self.file_end_check(path_real, pos, size=size, data=data):
				log.debug(( 'Event (mask: {}) for unchanged'
					' path, ignoring: {}' ).format(mask_str, path))
				return
			if path_real.getsize() < pos:
				log.debug( 'Detected truncation'
					' of a path, rewinding: {}'.format(path) )
				pos = None
		else: pos = None

		## Actual processing
		line = self.paths_buff.setdefault(path_real, '')
		with path_real.open('rb') as src:
			if pos:
				src.seek(pos)
				pos = None
			while True:
				buff = src.readline()
				if not buff: # eof
					self.paths_pos[path_real] = self.file_end_mark(path_real, data=line)
				line += buff
				if line.endswith('\n'):
					log.noise('New line (source: {}): {!r}'.format(path, line))
					reactor.callLater(0, self.handle_line, line)
					line = self.paths_buff[path_real] = ''
				else:
					line, self.paths_buff[path_real] = None, line
					break
Пример #15
0
    def notify(self, unknown, filepath, mask):
        logger.debug('event %s on %s' %
                     (', '.join(inotify.humanReadableMask(mask)), filepath))

        basename = filepath.basename()
        if not basename.endswith(config.GROWING_FILE_SUFFIX):
            return
        path = os.path.join(filepath.dirname(), basename)
        if mask == inotify.IN_CREATE:
            self.handle_in_create(path)
        elif mask == inotify.IN_DELETE:
            self.handle_in_delete(path)
Пример #16
0
    def notify(self, ignored, filepath, mask):
       """
       For historical reasons, an opaque handle is passed as first
       parameter. This object should never be used.

       @param filepath: FilePath on which the event happened.
       @param mask: inotify event as hexadecimal masks
       """
       if self.name_regex and not self.name_regex.match(filepath.basename):
           return None
       str_event = inotify.humanReadableMask(mask)[0]
       if str_event in self.events:
           self.callbacks.get(str_event)(filepath)
       if 'all' in self.events:
           self.callbacks['all'](str_event, filepath)
Пример #17
0
    def notifyCallback(self, ignored, filepath, mask):
        LOGGER.debug("Notify event %s on %s" % (humanReadableMask(mask), filepath.basename()))
        if mask & IN_CREATE and filepath == self.lastCaptureLink:
            capture = filepath.realpath().basename()
            LOGGER.info("New capture detected: %s" % capture)
            try:
                self.lastCaptureTime = self.extractDateTimeFromCaptureName(capture)
                self.lastCaptureName = capture
            except ValueError:
                self.errbackDefers(Failure())

            if self.defers:
                defers = self.defers
                self.defers = []
                for d in defers:
                    if not d.called:
                        d.callback(capture)
Пример #18
0
 def status_file_changed(self, ignored, filepath, mask):
     """ This is a callback for the twisted INotify module to inform about
         file changes on status files. This methods searches for the
         associated instances and schedules a loadInstances with a timeout
         of one second to handle multiple file changes only once."""
     instance = None
     for one_instance in self.config.instances.values():
         if one_instance.status_file == filepath.path:
             instance = one_instance
             break
     if instance is None:
         print('unknown status file: {0}'.format(filepath.path))
         return
     from twisted.internet import reactor
     instance.version += 1
     deferLater(reactor, 1, self.status_file_change_done,
                instance, instance.version,
                ','.join(inotify.humanReadableMask(mask)))
Пример #19
0
    def load_config(self, *args):
        if args:
            masks = inotify.humanReadableMask(args[2])
            #print masks
            if not set(masks).intersection(set(('delete_self', ))):
                return

        self.config = ConfigParser()
        self.config.read(CONFIG)
        self.commands = self.config.items('commands')

        if args:
            print "config reloaded"

        notifier = inotify.INotify()
        notifier.startReading()
        #print "adding watcher"
        notifier.watch(filepath.FilePath(CONFIG), callbacks=[self.load_config])
        print "config watcher started"
        reactor.callLater(.5, self.send, commands=self.commands)
Пример #20
0
    def notify(self, ignore, path, mask, parameter=None):
        self.info(
            'Event %s on %s - parameter %r',
            ', '.join(humanReadableMask(mask)),
            path.path,
            parameter,
        )

        if mask & IN_CHANGED:
            # FIXME react maybe on access right changes, loss of read rights?
            # print(f'{path} was changed, parent {parameter:d} ({iwp.path})')
            pass

        if mask & IN_DELETE or mask & IN_MOVED_FROM:
            self.info(f'{path.path} was deleted, '
                      f'parent {parameter!r} ({path.parent().path})')
            id = self.get_id_by_name(parameter, path.path)
            if id is not None:
                self.remove(id)
        if mask & IN_CREATE or mask & IN_MOVED_TO:
            if mask & IN_ISDIR:
                self.info(f'directory {path.path} was created, '
                          f'parent {parameter!r} ({path.parent().path})')
            else:
                self.info(f'file {path.path} was created, '
                          f'parent {parameter!r} ({path.parent().path})')
            if self.get_id_by_name(parameter, path.path) is None:
                if path.isdir():
                    self.walk(
                        path.path,
                        self.get_by_id(parameter),
                        self.ignore_file_pattern,
                    )
                else:
                    if self.ignore_file_pattern.match(parameter) is None:
                        self.append(str(path.path),
                                    str(self.get_by_id(parameter)))
Пример #21
0
 def on_file_changed(self, ignored, filepath, mask):
     handler = {self.EVENT_MODIFIED: self.read_more, self.EVENT_RENAMED: self.rebind_events}.get(mask)
     if not handler:
         print "Ignoring event %s (%s)" % (mask, inotify.humanReadableMask(mask))
         return
     return handler()
Пример #22
0
 def inotify_twisted(self, ignored, path, mask):
     alpha_event = inotify.humanReadableMask(mask)
     event = {time.time(): {'mask':mask, 'event':alpha_event[0], 'path':self.path}}
     self.signal_event(event)
Пример #23
0
 def onChange(self, watch, fpath, mask):
     cursor.execute("SELECT auto_sync FROM account WHERE user_id = %s", (self._user,))
     if cursor.fetchone()[0] == 1:
         path = adjustPath(fpath.path)
         cmd = ' '.join(inotify.humanReadableMask(mask))
         self.dispatch(path, cmd)
Пример #24
0
	def handle_change(self, stuff, path, mask):
		mask_str = inotify.humanReadableMask(mask)
		log.noise('Event: {} ({})'.format(path, mask_str))

		## Filtering
		path_real = path.realpath()
		if not path_real.isfile():
			log.debug( 'Ignoring event for'
				' non-regular file: {} (realpath: {})'.format(path, path_real) )
			return
		dir_key = path_real.parent().realpath()
		if dir_key not in self.paths_watch:
			log.warn( 'Ignoring event for file outside of watched'
				' set of paths: {} (realpath: {})'.format(path, path_real) )
			return
		for pat in self.paths_watch[dir_key]:
			if fnmatch(bytes(path.basename()), pat): break
		else:
			log.noise( 'Non-matched path in one of'
				' the watched dirs: {} (realpath: {})'.format(path, path_real) )
			return
		for pat in self.exclude:
			if pat.search(path.path):
				log.noise( 'Matched path by exclude-pattern'
					' ({}): {} (realpath: {})'.format(pat, path, path_real) )
				return

		## Get last position
		pos = self.paths_pos.get(path_real)
		if not pos: # try restoring it from xattr
			try: pos = pickle.loads(xattr(path_real.path)[self.conf.xattr_name])
			except KeyError:
				log.debug('Failed to restore last log position from xattr for path: {}'.format(path))
			else:
				log.noise(
					'Restored pos from xattr ({}) for path {}: {!r}'\
					.format(self.conf.xattr_name, path_real, pos) )
		if pos:
			pos, size, data_hash = pos
			if self.file_end_check(path_real, pos, size=size, data_hash=data_hash):
				log.noise(( 'Event (mask: {}) for unchanged'
					' path, ignoring: {}' ).format(mask_str, path))
				return
			if path_real.getsize() < pos:
				log.debug( 'Detected truncation'
					' of a path, rewinding: {}'.format(path) )
				pos = None

		## Actual processing
		buff_agg = self.paths_buff.setdefault(path_real, '')
		with path_real.open() as src:
			if pos:
				src.seek(pos)
				pos = None
			while True:
				pos = src.tell()
				try: buff, pos = self.read(src), src.tell()
				except StopIteration:
					buff_agg = ''
					src.seek(pos) # revert back to starting position
					buff, pos = self.read(src), src.tell()
				if not buff: # eof, try to mark the position
					if not buff_agg: # clean eof at the end of the chunk - mark it
						pos = self.file_end_mark(path_real, pos=pos, data=buff_agg)
						self.paths_pos[path_real] = pos
						xattr(path_real.path)[self.conf.xattr_name] = pickle.dumps(pos)
						log.noise( 'Updated xattr ({}) for path {} to: {!r}'\
							.format(self.conf.xattr_name, path_real, pos) )
					break
				buff_agg = self.paths_buff[path_real] = self.process(buff_agg + buff, path)
Пример #25
0
 def notify(self, ignored, path, mask):
     print 'event {} on {}'.format(
         inotify.humanReadableMask(mask),
         path
     )
Пример #26
0
 def _debug_notify(self, notifier, path, mask):
     from twisted.internet.inotify import humanReadableMask
     print path, humanReadableMask(mask)
Пример #27
0
 def notify(self, filepath, mask):
     mstr =  ', '.join(inotify.humanReadableMask(mask))
     print "event %s on %s" % (mstr, filepath)
     self._proto.sendLine('%s' %mstr)
Пример #28
0
 def eventReceived(self, _Watch, filepath, mask):
     print "event %s on %s" % (
         ', '.join(inotify.humanReadableMask(mask)), filepath)
     for line in self.f.readlines():
         self.lineReceived(line)
Пример #29
0
 def _debug_notify(self, notifier, path, mask):
     from twisted.internet.inotify import humanReadableMask
     print path, humanReadableMask(mask)
Пример #30
0
 def eventReceived(self, _Watch, filepath, mask):
     print "event %s on %s" % (', '.join(
         inotify.humanReadableMask(mask)), filepath)
     for line in self.f.readlines():
         self.lineReceived(line)
Пример #31
0
 def notify(self, _, path: filepath.FilePath, mask: int) -> None:
     if path.path.endswith("{}_config.json".format(
             self.operatingsystem).encode('utf8')):
         log.msg("event {} on {}".format(
             ', '.join(inotify.humanReadableMask(mask)), path.path))
         asyncio.ensure_future(self.read_data())
Пример #32
0
    def _invoke_callback(self, ignored, filepath, mask):
        mask_h = inotify.humanReadableMask(mask)

        # meta updating file via vim shows up as UPDATE, and triggers
        # sometimes only once, and sometimes TWICE :/ (See inotify docs
        # on coalesced events)
        # meta updating file via `echo ' ' >> FILE` shows up as UPDATE
        # meta updating file via rsync shows up as ATTRIB, then DELETE_SELF
        if mask == self.UPDATE:
            # When file is updated via linux `cp`,
            # Sometimes UPDATE happens twice about 2 milliseconds apart.
            # (And the file is still empty when the first one hits)
            # Other times those two events are coalesced into one
            # (See inotify man page regarding coalesced events)
            # THEREFORE we trigger on only the first within a time window,
            # BUT we also insert a small delay to give the file
            # time to actually be populated.
            now = datetime.now()
            delta = now - self._recent_update
            self._recent_update = now
            delta_seconds = delta.seconds + delta.microseconds / 1e6
            action = (
                f'Callback skipped because duplicate. delta_seconds: {delta_seconds}'
            )

            # Rate limit this event by only allowing the first of events in a window
            if delta > timedelta(
                    milliseconds=self.DUPLICATE_WINDOW_MILLISECONDS):
                action = f'Callback will be invoked in {self.FILE_POPULATION_DELAY_SECONDS}s.'
                # pylint: disable=redefined-outer-name,import-outside-toplevel
                from twisted.internet import reactor

                # pylint: disable=no-member
                # Call it enough in the future that the file is actually there
                reactor.callLater(self.FILE_POPULATION_DELAY_SECONDS,
                                  self.callback)

        if mask == self.ATTRIB:
            # When file is updated (remotely) via rsync , we end up here
            msg = self._archive_file()
            action = f'{msg}Callback invoked now.'
            self.callback()

        if mask == self.DELETE_SELF:
            # For some reason when updating the file via rsync (remotely)
            # DELETE_SELF is triggered, which causes the file to no longer be watched

            # Tell it to delete the file descriptor (connectionLost).
            # Otherwise we eventually run out of file descriptors
            # Note we do this in the future, because if we call it inline (now),
            # our process stops watching the file.
            action = 'restarted file watcher'
            # pylint: disable=import-outside-toplevel
            from twisted.internet import reactor

            # pylint: disable=no-member
            reactor.callLater(
                self.CONNECTION_LOST_DELAY_SECONDS,
                self._notifier.connectionLost,
                'rsync issued DELETE_SELF',
            )
            # Start Over
            self.watch()

        print(f'MASK: {mask_h}, action: {action}')