Esempio n. 1
0
 def _sync(self):
   with Pfx("_sync"):
     if defaults.S is None:
       raise RuntimeError("RUNTIME: defaults.S is None!")
     archive = self.archive
     if not self.readonly and archive is not None:
       with self._lock:
         E = self.E
         updated = False
         X("snapshot %r  ...", E)
         E.snapshot()
         X("snapshot: afterwards E=%r", E)
         fs_inode_dirents = self._inodes.get_fs_inode_dirents()
         X("_SYNC: FS_INODE_DIRENTS:")
         dump_Dirent(fs_inode_dirents)
         X("set meta.fs_inode_dirents")
         if fs_inode_dirents.size > 0:
           E.meta['fs_inode_dirents'] = str(fs_inode_dirents)
         else:
           E.meta['fs_inode_dirents'] = ''
         new_state = bytes(E)
         if new_state != self._last_sync_state:
           archive.update(E)
           self._last_sync_state = new_state
           updated = True
       # debugging
       if updated:
         dump_Dirent(E, recurse=False)
Esempio n. 2
0
 def noexc_gen_wrapper(*args, **kwargs):
     try:
         it = iter(func(*args, **kwargs))
     except Exception as e0:
         try:
             exception("exception calling %s(*%s, **(%s)): %s",
                       func.__name__, args, kwargs, e0)
         except Exception as e2:
             try:
                 X("exception calling %s(*%s, **(%s)): %s", func.__name__,
                   args, kwargs, e2)
             except Exception:
                 pass
         return
     while True:
         try:
             item = next(it)
         except StopIteration:
             raise
         except Exception as e:
             try:
                 exception("exception calling next(%s(*%s, **(%s))): %s",
                           func.__name__, args, kwargs, e)
             except Exception:
                 try:
                     X("exception calling next(%s(*%s, **(%s))): %s",
                       func.__name__, args, kwargs, e)
                 except Exception:
                     pass
             return
         else:
             yield item
Esempio n. 3
0
 def rename(self, new_name):
     if self.name == new_name:
         warning("rename tag %r: no change", self.name)
         return
     X("Tag[%d:%r].rename(new_name=%r)", self.id, self.name, new_name)
     T = self._table
     try:
         otag = T[new_name]
     except KeyError:
         # name not in use, rename current tag
         T.update('name', new_name, 'id = %d' % (self.id, ))
     else:
         X("other tag for new_name = %d:%r", otag.id, otag.name)
         if otag.id == self.id:
             # case insensitive or the like: update the name in place
             T.update('name', new_name, 'id = %d' % (self.id, ))
         else:
             # update related objects (books?)
             # to point at the other tag
             for B in self.books:
                 X("  update Book[%d:%r]{%s} ...", B.id, B.name,
                   ','.join(T.name for T in B.tags))
                 B.add_tag(new_name)
                 B.remove_tag(self.name)
             # delete our tag, become the other tag
             T.delete('id = ?', self.id)
             self.ns.id = otag.id
     self.name = new_name
Esempio n. 4
0
def XP(msg, *args, **kwargs):
    ''' Variation on `cs.x.X`
      which prefixes the message with the current Pfx prefix.
  '''
    if args:
        return X("%s: " + msg, prefix(), *args, **kwargs)
    return X(prefix() + DEFAULT_SEPARATOR + msg, **kwargs)
Esempio n. 5
0
 def _row_of_tags(self):
   ''' Make a row of tag widgets.
   '''
   X("TagsView_Frame: TAGS=%s", self.tags)
   ##row = [self._get_tag_widget(tag) for tag in self.tags]
   row = [sg.Text(str(tag)) for tag in self.tags]
   X("ROW OF TAGS: %r", row)
   return row
Esempio n. 6
0
 def set_tags(self, tags):
   super().set_tags(tags)
   X("%s.set_tags: self.tags=%s", type(self).__name__, self.tags)
   X("CALL SELF.LAYOUT(SELF.LAYOUT_TAGS)")
   self.layout(self.layout_tags(self.tags))
   if self.Widget is not None:
     X("CONTENTS_CHANGED")
     self.contents_changed()
Esempio n. 7
0
 def handle(self, *a, **kw):
     ''' Wrapper for FUSE handler methods.
 '''
     syscall = method.__name__
     if syscall == 'write':
         fh, offset, bs = a
         arg_desc = [
             str(a[0]),
             str(a[1]),
             "%d bytes:%r..." % (len(bs), bytes(bs[:16]))
         ]
     else:
         arg_desc = [(("<%s>" % (type(arg).__name__, )) if isinstance(
             arg, llfuse.RequestContext) else repr(arg)) for arg in a]
     arg_desc.extend("%s=%r" % (kw_name, kw_value)
                     for kw_name, kw_value in kw.items())
     arg_desc = ','.join(arg_desc)
     with Pfx("%s.%s(%s)", type(self).__name__, syscall, arg_desc):
         trace = syscall in (
             ##'getxattr',
             ##'setxattr',
             ##'statfs',
         )
         if trace:
             X("CALL %s(%s)", syscall, arg_desc)
         fs = self._vtfs
         try:
             with stackattrs(defaults, fs=fs):
                 with fs.S:
                     with LogTime("SLOW SYSCALL", threshold=5.0):
                         result = method(self, *a, **kw)
                     if trace:
                         if isinstance(result, bytes):
                             X("CALL %s result => %d bytes, %r...", syscall,
                               len(result), result[:16])
                         else:
                             X("CALL %s result => %s", syscall, result)
                     return result
         ##except FuseOSError as e:
         ##  warning("=> FuseOSError %s", e, exc_info=False)
         ##  raise
         except OSError as e:
             ##warning("=> OSError %s => FuseOSError", e, exc_info=False)
             raise FuseOSError(e.errno) from e
         except MissingHashcodeError as e:
             error("raising IOError from missing hashcode: %s", e)
             raise FuseOSError(errno.EIO) from e
         except Exception as e:
             exception("unexpected exception, raising EINVAL %s:%s",
                       type(e), e)
             raise FuseOSError(errno.EINVAL) from e
         except BaseException as e:
             error("UNCAUGHT EXCEPTION: %s", e)
             raise RuntimeError("UNCAUGHT EXCEPTION") from e
         except:
             error("=> EXCEPTION %r", sys.exc_info())
Esempio n. 8
0
 def __getattribute__(self, attr):
     X("TracingObject.__getattribute__(attr=%r)", attr)
     _proxied = Proxy.__getattribute__(self, '_proxied')
     try:
         value = object.__getattribute__(_proxied, attr)
     except AttributeError:
         X("no .%s attribute", attr)
         raise
     else:
         X("getattr .%s", attr)
         return TracingObject(value)
Esempio n. 9
0
def mount(mnt,
          E,
          *,
          S=None,
          archive=None,
          subpath=None,
          readonly=None,
          append_only=False,
          fsname=None):
    ''' Run a FUSE filesystem, return the Thread running the filesystem.

      Parameters:
      * `mnt`: mount point
      * `E`: Dirent of root Store directory
      * `S`: optional backing Store, default from defaults.S
      * `archive`: if not None, an Archive or similar, with a
        `.update(Dirent[,when])` method
      * `subpath`: relative path from `E` to the directory to attach
        to the mountpoint
      * `readonly`: forbid data modification operations
      * `append_only`: files may not be truncated or overwritten
      * `fsname`: optional filesystem name for use by llfuse
  '''
    if readonly is None:
        readonly = S.readonly
    else:
        if not readonly and S.readonly:
            warning(
                "Store %s is readonly, using readonly option for mount (was %r)",
                S, readonly)
            readonly = True
    # forget the archive if readonly
    if readonly:
        if archive is not None:
            warning("readonly, forgetting archive %s", archive)
            archive = None
    log = getLogger(LOGGER_NAME)
    log.propagate = False
    log_handler = LogFileHandler(LOGGER_FILENAME)
    log_formatter = LogFormatter(DEFAULT_BASE_FORMAT)
    log_handler.setFormatter(log_formatter)
    log.addHandler(log_handler)
    X("mount: S=%s", S)
    X("mount: E=%s", E)
    ##dump_Dirent(E, recurse=True)
    FS = StoreFS(E,
                 S=S,
                 archive=archive,
                 subpath=subpath,
                 readonly=readonly,
                 append_only=append_only,
                 show_prev_dirent=True)
    return FS._vt_runfuse(mnt, fsname=fsname)
Esempio n. 10
0
def dump_Block(block, indent=''):
  ''' Dump a Block.
  '''
  X("%s%s", indent, block)
  if block.indirect:
    indent += '  '
    subblocks = block.subblocks
    X(
        "%sindirect %d subblocks, span %d bytes", indent, len(subblocks),
        len(block)
    )
    for B in subblocks:
      dump_Block(B, indent=indent)
Esempio n. 11
0
def datetime_from_http_date(s):
    ''' Parse an HTTP-date from a string, return a datetime object.
      See RFC2616 section 3.3.1.
  '''
    try:
        return datetime_from_rfc1123_date(s)
    except ValueError as e:
        X("datetime_from_rfc1123_date(%r): %s", s, e)
        try:
            return datetime_from_rfc850_date(s)
        except ValueError as e:
            X("datetime_from_rfc850_date(%r): %s", s, e)
            return datetime_from_asctime_date(s)
Esempio n. 12
0
 def load_fs_inode_dirents(self, D):
   ''' Load entries from an `fs_inode_dirents` Dir into the Inode table.
   '''
   X("LOAD FS INODE DIRENTS:")
   dump_Dirent(D)
   for name, E in D.entries.items():
     X("  name=%r, E=%r", name, E)
     with Pfx(name):
       # get the refcount from the :uuid:refcount" name
       _, refcount_s = name.split(':')[:2]
       I = self.add(E)
       I.refcount = int(refcount_s)
       X("  I=%s", I)
Esempio n. 13
0
 def setxattr(self, inum, xattr_name, xattr_value):
   ''' Set the extended attribute `xattr_name` to `xattr_value`
       on inode `inum`.
   '''
   if self.readonly:
     OS_EROFS("fs is read only")
   E = self.i2E(inum)
   xattr_name = Meta.xattrify(xattr_name)
   if not xattr_name.startswith(XATTR_VT_PREFIX):
     # ordinary attribute, set it and return
     E.meta.setxattr(xattr_name, xattr_value)
     return
   # process special attribute names
   with Pfx("%s.setxattr(%d,%r,%r)", self, inum, xattr_name, xattr_value):
     suffix = xattr_name[len(XATTR_VT_PREFIX):]
     with Pfx(suffix):
       if suffix == 'block':
         # update the Dirent's content directly
         if not E.isfile:
           OS_EINVAL("tried to update the data content of a nonfile: %s", E)
         block_s = Meta.xattrify(xattr_value)
         B, offset = parse(block_s)
         if offset < len(block_s):
           OS_EINVAL("unparsed text after trancription: %r", block_s[offset:])
         if not isBlock(B):
           OS_EINVAL("not a Block transcription")
         info("%s: update .block directly to %r", E, str(B))
         E.block = B
         return
       if suffix == 'control':
         argv = shlex.split(xattr_value.decode('utf-8'))
         if not argv:
           OS_EINVAL("no control command")
         op = argv.pop(0)
         with Pfx(op):
           if op == 'cache':
             if argv:
               OS_EINVAL("extra arguments: %r", argv)
             B = E.block
             if B.indirect:
               X("ADD BLOCK CACHE FOR %s", B)
               bm = self.block_cache.get_blockmap(B)
               X("==> BLOCKMAP: %s", bm)
             else:
               X("IGNORE BLOCK CACHE for %s: not indirect", B)
             return
           OS_EINVAL("unrecognised control command")
       OS_EINVAL("invalid %r prefixed name", XATTR_VT_PREFIX)
Esempio n. 14
0
   def preprocess(context, row):
       ''' Convert some row columns before assimilation.
 '''
       if context.index > 0:
           for i, attr in enumerate(context.cls.attrs_):
               if attr in (
                       'bit_rate',
                       'disc_count',
                       'disc_number',
                       'my_rating',
                       'plays',
                       'sample_rate',
                       'size',
                       'time',
                       'track_count',
                       'track_number',
                       'year',
               ):
                   row[i] = int(row[i]) if row[i] else None
               elif attr in (
                       'date_added',
                       'date_modified',
                       'last_played',
               ):
                   row[i] = playlist_date(row[i]) if row[i] else None
       X("row = %r", row)
       return row
Esempio n. 15
0
 def db_book(self):
     ''' Return a cached reference to the database book record.
 '''
     db = self.tree.db
     with db.db_session() as session:
         X("FETCH BOOK %r", self.dbid)
         return db.books.by_id(self.dbid, session=session)
Esempio n. 16
0
    def _run(self, *calargv, subp_options=None):
        ''' Run a Calibre utility command.

        Parameters:
        * `calargv`: an iterable of the calibre command to issue;
          if the command name is not an absolute path
          it is expected to come from `self.CALIBRE_BINDIR_DEFAULT`
        * `subp_options`: optional mapping of keyword arguments
          to pass to `subprocess.run`
    '''
        X("calargv=%r", calargv)
        if subp_options is None:
            subp_options = {}
        subp_options.setdefault('check', True)
        cmd, *calargv = calargv
        if not isabspath(cmd):
            cmd = joinpath(self.CALIBRE_BINDIR_DEFAULT, cmd)
        print("RUN", cmd, *calargv)
        try:
            cp = pfx_call(run, [cmd, *calargv], **subp_options)
        except CalledProcessError as cpe:
            error(
                "run fails, exit code %s:\n  %s",
                cpe.returncode,
                ' '.join(map(repr, cpe.cmd)),
            )
            if cpe.stderr:
                print(cpe.stderr.replace('\n', '  \n'), file=sys.stderr)
            raise
        return cp
Esempio n. 17
0
 def acquire(self, timeout=-1, _caller=None):
   ''' Acquire the lock and note the caller who takes it.
   '''
   if _caller is None:
     _caller = caller()
   lock = self._lock
   hold = _LockContext(_caller, current_thread())
   if timeout != -1:
     warning(
         "%s:%d: lock %s: timeout=%s", hold.caller.filename,
         hold.caller.lineno, lock, timeout
     )
   contended = False
   if True:
     if lock.acquire(0):
       lock.release()
     else:
       contended = True
       held = self._held
       warning(
           "%s:%d: lock %s: waiting for contended lock, held by %s:%s:%d",
           hold.caller.filename, hold.caller.lineno, lock, held.thread,
           held.caller.filename, held.caller.lineno
       )
   acquired = lock.acquire(timeout=timeout)
   if contended:
     warning(
         "%s:%d: lock %s: %s", hold.caller.filename, hold.caller.lineno, lock,
         "acquired" if acquired else "timed out"
     )
   self._held = hold
   if acquired and self.trace_acquire:
     X("ACQUIRED %r", self)
     stack_dump()
   return acquired
Esempio n. 18
0
 def layout_tags(self, tags):
   ''' Create a layout for `tags`.
   '''
   ##layout = [[self._get_tag_widget(tag)] for tag in sorted(tags)]
   layout = [[sg.Text(str(tag))] for tag in sorted(tags)]
   X("%s.layout_tags => %r", type(self).__name__, layout)
   return layout
Esempio n. 19
0
 def statusline(self, new_status):
     ''' Set the status line value.
 '''
     assert new_status is None or isinstance(new_status, str)
     self._statusline = new_status
     X("statusbar => %r", new_status)
     self.widget.statusBar().showMessage(new_status if new_status else '')
Esempio n. 20
0
 def test(self):
     if False:
         # to help with debugging:
         # print the first 16 sync points - some _may_ be in the audio data
         bfr = CornuCopyBuffer.from_filename(TESTFILE)
         count = 16
         while not bfr.at_eof() and count > 0:
             bs = b''.join(MP3AudioFrame.scan_for_sync(bfr))
             X("AUDIO at %d after %d bytes", bfr.offset, len(bs))
             bfr.take(1)
             count -= 1
     S = os.stat(TESTFILE)
     mp3_size = S.st_size
     bfr = CornuCopyBuffer.from_filename(TESTFILE)
     for offset, frame, post_offset in MP3Frame.scan_with_offsets(bfr):
         frame_size = post_offset - offset
         frame_bs = bytes(frame)
         ##frame2 = MP3Frame.from_bytes(frame_bs)
         ##self.assertIs(type(frame), type(frame2))
         # There used to be a round trip size check, but we repair
         # some input data and write it out correctly, so the size can
         # change. Example: a USC-2 text field missing its BOM.
     self.assertEqual(
         bfr.offset, mp3_size,
         "file size = %d, buffer offset = %d" % (mp3_size, bfr.offset))
     self.assertTrue(bfr.at_eof())
     bfr.close()
Esempio n. 21
0
 def set_tags(self, tags):
   super().set_tags(tags)
   tag_row = self._row_of_tags()
   self.__layout[1:] = tag_row
   X("SET TAG 0: __layout=%r", self.__layout)
   ##self.update()
   ##self.contents_changed()
   ##self.layout(self.__layout)
   canvas = self.__canvas.tk_canvas
   canvas.delete(canvas.find_all())
   for tag in self.tags:
     for tag_item in tag_row:
       canvas.create_window(20, 20, window=tag_item.Widget)
   self.__layout[1:] = []
   X("SET TAG 0: __layout=%r", self.__layout)
   ##self.update()
   self.contents_changed()
Esempio n. 22
0
 def flush(self):
   ''' Commit file contents to Store.
       Chooses a scanner based on the Dirent.name.
   '''
   X("FileHandle.flush: self.E.name=%r", self.E.name)
   mime_type = self.E.meta.mime_type
   if mime_type is None:
     scanner = None
   else:
     X("look up scanner from mime_type %r", mime_type)
     scanner = scanner_from_mime_type(mime_type)
   if scanner is None:
     X("look up scanner from filename %r", self.E.name)
     scanner = scanner_from_filename(self.E.name)
   self.E.flush(scanner, dispatch=self.bg)
   ## no touch, already done by any writes
   X("FileHandle.Flush DONE")
Esempio n. 23
0
 def pixmap(self):
     ''' The image pixmap.
 '''
     pm = self._pixmap
     if not pm:
         X("load pixmap from %r", self.image_path)
         pm = self._pixmap = QPixmap(self.image_path)
     return pm
Esempio n. 24
0
 def add(self, new_tab):
     ''' Add an element to the tab set.
 '''
     assert isinstance(new_tab, _Element)
     self.tabs.append(new_tab)
     X("add qt %s to tab set %s", new_tab.widget, self.widget)
     self.widget.addTab(new_tab.widget, new_tab.title)
     return new_tab
Esempio n. 25
0
    def access(self,
               access_mode,
               access_uid=None,
               access_gid=None,
               default_uid=None,
               default_gid=None):
        ''' POSIX like access call, accepting os.access `access_mode`.

        Parameters:
        * `access_mode`: a bitmask of os.{R_OK,W_OK,X_OK} as for
          the os.access function.
        * `access_uid`: the effective uid of the querying user.
        * `access_gid`: the effective gid of the querying user.
        * `default_uid`: the reference uid to use if this Meta.uid is None
        * `default_gid`: the reference gid to use if this Meta.gid is None

        If the Meta has no uid or `access_uid == Meta.uid`,
        use the owner permissions.
        Otherwise if the Meta has no gid or `access_gid == Meta.gid`,
        use the group permissions.
        Otherwise use the "other" permissions.
    '''
        X("META.ACCESS...")
        u = self.uid
        if u is None:
            u = default_uid
        g = self.gid
        if g is None:
            g = default_gid
        perms = self.unix_perm_bits
        if access_mode & os.R_OK:
            if u is None or (access_uid is not None and access_uid == u):
                if not (perms >> 6) & 4:
                    return False
            elif g is None or (access_gid is not None and access_gid == g):
                if not (perms >> 3) & 4:
                    return False
            elif not perms & 4:
                return False
        if access_mode & os.W_OK:
            if u is None or (access_uid is not None and access_uid == u):
                if not (perms >> 6) & 2:
                    return False
            elif g is None or (access_gid is not None and access_gid == g):
                if not (perms >> 3) & 2:
                    return False
            elif not perms & 2:
                return False
        if access_mode & os.X_OK:
            if u is None or (access_uid is not None and access_uid == u):
                if not (perms >> 6) & 1:
                    return False
            elif g is None or (access_gid is not None and access_gid == g):
                if not (perms >> 3) & 1:
                    return False
            elif not perms & 1:
                return False
        return True
Esempio n. 26
0
def dump_Dirent(E, indent='', recurse=False, not_dir=False):
  ''' Dump a Dirent.
  '''
  X("%s%r", indent, E)
  if E.isdir and not not_dir:
    indent += '  '
    for name in sorted(E.keys()):
      E2 = E[name]
      dump_Dirent(E2, indent, recurse=recurse, not_dir=not recurse)
Esempio n. 27
0
 def line(self):
   line = "%-15s %d/%s" % (self.name if self.name else '',
                           self.portnum,
                           self.proto)
   if self.aliases:
     X("line=%s, aliases=%s", line, self.aliases)
     line += '    ' + ' '.join(self.aliases)
   if self.comment:
     line += '  # ' + self.comment
   return line
Esempio n. 28
0
 def insert1(self, **kw):
   ''' Insert a single row, return the new row id.
   '''
   column_names = []
   values = []
   for column_name, value in kw.items():
     column_names.append(column_name)
     values.append(value)
   X("insert1: column_names=%r, values=%r", column_names, values)
   return self.insert(column_names, (values,))
Esempio n. 29
0
 def __init__(self, ont_path: str):
   self.ont_path = ont_path
   tagsets, ont_pfx_map = self.tagsetses_from_path(ont_path)
   super().__init__(tagsets)
   # apply any prefix TagSetses
   for prefix, subtagsets in sorted(ont_pfx_map.items(), key=lambda item:
                                    (len(item[0]), item[0])):
     prefix_ = prefix + '.'
     X("add %r => %s", prefix_, subtagsets)
     self.add_tagsets(subtagsets, prefix_)
Esempio n. 30
0
 def default(self, line):
     ''' Default command action.
 '''
     if line == 'EOF':
         return True
     try:
         exec_code(line, globals(), self.vars)
     except Exception as e:
         X("Exception: %s", e)
     self.stdout.flush()
     return False