1# -*- test-case-name: twisted.lore.test.test_lore -*-
2# Copyright (c) Twisted Matrix Laboratories.
3# See LICENSE for details.
4
5#
6import sys, os
7import tree #todo: get rid of this later
8import indexer
9
10class NoProcessorError(Exception):
11    pass
12
13class ProcessingFailure(Exception):
14    pass
15
16cols = 79
17
18def dircount(d):
19    return len([1 for el in d.split("/") if el != '.'])
20
21
22class Walker:
23
24    def __init__(self, df, fext, linkrel):
25        self.df = df
26        self.linkrel = linkrel
27        self.fext = fext
28        self.walked = []
29        self.failures = []
30
31    def walkdir(self, topdir, prefix=''):
32        self.basecount = dircount(topdir)
33        os.path.walk(topdir, self.walk, prefix)
34
35    def walk(self, prefix, d, names):
36        linkrel = prefix + '../' * (dircount(d) - self.basecount)
37        for name in names:
38            fullpath = os.path.join(d, name)
39            fext = os.path.splitext(name)[1]
40            if fext == self.fext:
41                self.walked.append((linkrel, fullpath))
42
43    def generate(self):
44        i = 0
45        indexer.clearEntries()
46        tree.filenum = 0
47        for linkrel, fullpath in self.walked:
48            linkrel = self.linkrel + linkrel
49            i += 1
50            fname = os.path.splitext(fullpath)[0]
51            self.percentdone((float(i) / len(self.walked)), fname)
52            try:
53                self.df(fullpath, linkrel)
54            except ProcessingFailure, e:
55                self.failures.append((fullpath, e))
56        indexer.generateIndex()
57        self.percentdone(1., None)
58
59    def percentdone(self, percent, fname):
60        # override for neater progress bars
61        proglen = 40
62        hashes = int(percent * proglen)
63        spaces = proglen - hashes
64        progstat = "[%s%s] (%s)" %('#' * hashes, ' ' * spaces,fname or "*Done*")
65        progstat += (cols - len(progstat)) * ' '
66        progstat += '\r'
67        sys.stdout.write(progstat)
68        sys.stdout.flush()
69        if fname is None:
70            print
71
72class PlainReportingWalker(Walker):
73
74    def percentdone(self, percent, fname):
75        if fname:
76            print fname
77
78class NullReportingWalker(Walker):
79
80    def percentdone(self, percent, fname):
81        pass
82
83def parallelGenerator(originalFileName, outputExtension):
84    return os.path.splitext(originalFileName)[0]+outputExtension
85
86def fooAddingGenerator(originalFileName, outputExtension):
87    return os.path.splitext(originalFileName)[0]+"foo"+outputExtension
88
89def outputdirGenerator(originalFileName, outputExtension, inputdir, outputdir):
90    originalFileName = os.path.abspath(originalFileName)
91    abs_inputdir = os.path.abspath(inputdir)
92    if os.path.commonprefix((originalFileName, abs_inputdir)) != abs_inputdir:
93        raise ValueError("Original file name '" + originalFileName +
94              "' not under input directory '" + abs_inputdir + "'")
95
96    adjustedPath = os.path.join(outputdir, os.path.basename(originalFileName))
97    return tree.getOutputFileName(adjustedPath, outputExtension)
98
99def getFilenameGenerator(config, outputExt):
100    if config.get('outputdir'):
101        return (lambda originalFileName, outputExtension:
102            outputdirGenerator(originalFileName, outputExtension,
103                               os.path.abspath(config.get('inputdir')),
104                               os.path.abspath(config.get('outputdir'))))
105    else:
106        return tree.getOutputFileName
107
108def getProcessor(module, output, config):
109    try:
110        m = getattr(module.factory, 'generate_'+output)
111    except AttributeError:
112        raise NoProcessorError("cannot generate "+output+" output")
113
114    if config.get('ext'):
115        ext = config['ext']
116    else:
117        from default import htmlDefault
118        ext = htmlDefault['ext']
119
120    return m(config, getFilenameGenerator(config, ext))
121