Example #1
0
 def process(self, renamer, options):
     arg = renamer.currentArgument
     logging.msg('Processing "%s"' % (arg.path,),
                 verbosity=3)
     d = defer.maybeDeferred(self.processArgument, arg)
     d.addCallback(self.buildDestination, options, arg)
     return d
Example #2
0
    def parseOptions(self):
        """
        Parse configuration file and command-line options.
        """
        _options = Options({})
        _options.parseOptions()
        self._obs.verbosity = _options['verbosity']

        self._configFile = config.ConfigFile(
            FilePath(os.path.expanduser(_options['config'])))
        command = self.getCommand(_options)

        options = Options(self._configFile)
        # Apply global defaults.
        options.update(self._configFile.get('renamer', options))
        # Apply command-specific overrides for the global config.
        options.update(
            (k, v) for k, v in
            self._configFile.get(command.name, options).iteritems()
            if k in options)
        # Command-line options trump the config file.
        options.parseOptions()

        logging.msg(
            'Global options: %r' % (options,),
            verbosity=5)

        return options
Example #3
0
 def makedirs(self, parent):
     """
     Create any directory structure that does not yet exist.
     """
     if not parent.exists():
         logging.msg('Creating directory structure for "%s"' % (
             parent.path,), verbosity=2)
         parent.makedirs()
Example #4
0
 def checkExisting(self, dst):
     """
     Ensure that the destination file does not yet exist.
     """
     if dst.exists():
         msg = 'Refusing to clobber existing file "%s"' % (
             dst.path,)
         logging.msg(msg)
         raise errors.NoClobber(msg)
Example #5
0
 def runCommand(self, command):
     """
     Run a generic command.
     """
     logging.msg(
         'Using command "%s"' % (command.name,),
         verbosity=4)
     logging.msg(
         'Command options: %r' % (command,),
         verbosity=5)
     return defer.maybeDeferred(command.process, self, self.options)
Example #6
0
    def lookupMetadata(self, seriesName, season, episode):
        """
        Look up TV episode metadata on TVRage.
        """
        url = self.buildURL(seriesName, season, episode)
        logging.msg('Looking up TVRage metadata at %s' % (url,),
                    verbosity=4)

        d = self.agent.request('GET', url)
        d.addCallback(deliverBody, BodyReceiver)
        d.addCallback(self.extractMetadata)
        return d
Example #7
0
    def pruneActions(self):
        """
        Remove any L{renamer.history.Action}s that do not have references to a
        L{renamer.history.Changeset}. These are actions most likely created and
        never used, so there is no need to store them.
        """
        count = 0
        for action in self.store.query(Action, Action.changeset == None):
            action.deleteFromStore()
            count += 1

        logging.msg(
            'Pruned %d actions' % (count,),
            verbosity=3)

        return count
Example #8
0
    def runRenamingCommand(self, command):
        """
        Run a renaming command.
        """
        def _processOne(src):
            self.currentArgument = src
            d = self.runCommand(command)
            d.addCallback(self.performRename, src)
            return d

        self.changeset = self.history.newChangeset()
        logging.msg(
            'Running, doing at most %d concurrent operations' % (
                self.options['concurrency'],),
            verbosity=3)
        return util.parallel(
            self.args, self.options['concurrency'], _processOne)
Example #9
0
    def pruneChangesets(self):
        """
        Prune empty changesets from the currently active changesets.
        """
        prunedChangesets = 0
        prunedActions = self.pruneActions()
        for cs in self.store.query(Changeset):
            if not cs.numActions:
                cs.deleteFromStore()
                prunedChangesets += 1
            elif cs.history is None:
                cs.history = self

        logging.msg(
            'Pruned %d changesets' % (prunedChangesets,),
            verbosity=3)

        return prunedChangesets, prunedActions
Example #10
0
    def buildDestination(self, mapping, options, src):
        """
        Build a destination path.

        Substitution of C{mapping} into the C{'prefix'} command-line option
        (defaulting to L{defaultPrefixTemplate}) and the C{'name'} command-line
        option (defaulting to L{defaultNameTemplate}) is performed.

        @type  mapping: C{dict} mapping C{str} to C{unicode}
        @param mapping: Mapping of template variables, used for template
            substitution.

        @type  options: C{dict}

        @type  src: L{twisted.python.filepath.FilePath}
        @param src: Source path.

        @rtype:  L{twisted.python.filepath.FilePath}
        @return: Destination path.
        """
        prefixTemplate = options['prefix']
        if prefixTemplate is None:
            prefixTemplate = self.defaultPrefixTemplate

        if prefixTemplate is not None:
            prefix = os.path.expanduser(
                prefixTemplate.safe_substitute(mapping))
        else:
            prefixTemplate = string.Template(src.dirname())
            prefix = prefixTemplate.template

        ext = src.splitext()[-1]

        nameTemplate = options['name']
        if nameTemplate is None:
            nameTemplate = self.defaultNameTemplate

        filename = nameTemplate.safe_substitute(mapping)
        logging.msg(
            'Building filename: prefix=%r  name=%r  mapping=%r' % (
                prefixTemplate.template, nameTemplate.template, mapping),
            verbosity=3)
        return FilePath(prefix).child(filename).siblingExtension(ext)
Example #11
0
    def getTag(self, path, tagNames, default=u'UNKNOWN'):
        """
        Get a metadata field by name.

        @type filename: L{twisted.python.filepath.FilePath}

        @type tagNames: C{list} of C{unicode}
        @param tagNames: A C{|} separated list of tag names to attempt when
            retrieving a value, the first successful result is returned

        @return: Tag value as C{unicode} or C{default}
        """
        logging.msg('Getting metadata for %r from "%s"' % (tagNames, path.path),
                    verbosity=4)
        md = self._getMetadata(path.path)
        for tagName in tagNames:
            try:
                return unicode(md[tagName][0])
            except KeyError:
                pass

        return default
Example #12
0
    def performRename(self, dst, src):
        """
        Perform a file rename.
        """
        if self.options['no-act']:
            logging.msg('Simulating: %s => %s' % (src.path, dst.path))
            return

        if src == dst:
            logging.msg('Skipping noop "%s"' % (src.path,), verbosity=2)
            return

        if self.options['link-dst']:
            self.changeset.do(
                self.changeset.newAction(u'symlink', src, dst),
                self.options)
        else:
            self.changeset.do(
                self.changeset.newAction(u'move', src, dst),
                self.options)
            if self.options['link-src']:
                self.changeset.do(
                    self.changeset.newAction(u'symlink', dst, src),
                    self.options)
Example #13
0
    def extractParts(self, filename, overrides=None):
        """
        Get TV episode information from a filename.
        """
        if overrides is None:
            overrides = {}

        rules = ['complete_strict', 'complete_lenient']
        # We can only try the partial rules if there are some overrides.
        if filter(None, overrides.values()):
            rules.extend([
                'only_episode',
                'partial_silly',
                'only_series',
                'only_episode_silly'])

        for rule in rules:
            g = FilenameGrammar(filename)
            logging.msg('Trying grammar rule "%s"' % (rule,),
                        verbosity=5)
            try:
                res, err = g.apply(rule)
            except ParseError, e:
                try:
                    logging.msg('Parsing error:', verbosity=5)
                    for line in (e.formatError(filename).strip()).splitlines():
                        logging.msg(line, verbosity=5)
                except:
                    pass
                continue
            else:
                series, (season, episode) = res
                parts = (
                    overrides.get('series') or series,
                    overrides.get('season') or season,
                    overrides.get('episode') or episode)
                if None not in parts:
                    logging.msg('Found parts in "%s": %r' % (filename, parts),
                                verbosity=4)
                    return parts
Example #14
0
 def undo(self, options):
     if self.dst.islink():
         logging.msg('Symlink: Removing %s' % (self.dst.path,))
         self.dst.remove()
Example #15
0
 def do(self, options):
     self.prepare(self.dst, options)
     logging.msg('Symlink: %s => %s' % (self.src.path, self.dst.path))
     self.src.linkTo(self.dst)
Example #16
0
 def _move(self, src, dst, options):
     self.prepare(dst, options)
     logging.msg('Move: %s => %s' % (src.path, dst.path))
     util.rename(src, dst, oneFileSystem=options['one-file-system'])