~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/scripts/utilities/js/jslint.py

  • Committer: Curtis Hovey
  • Date: 2011-07-15 15:18:21 UTC
  • mto: This revision was merged to the branch mainline in revision 13449.
  • Revision ID: curtis.hovey@canonical.com-20110715151821-8nk0nv06t8vdnnua
Removed old jslint tool

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""jslint.py - run the JSLint linter ."""
2
 
 
3
 
__metaclass__ = type
4
 
__all__ = []
5
 
 
6
 
import optparse
7
 
import os
8
 
import subprocess
9
 
import sys
10
 
 
11
 
from bzrlib import branch, errors, workingtree
12
 
from bzrlib.plugin import load_plugins
13
 
 
14
 
HERE = os.path.join(os.path.dirname(__file__))
15
 
FULLJSLINT = os.path.join(HERE, 'fulljslint.js')
16
 
JSLINT_WRAPPER = os.path.join(HERE, 'jslint-wrapper.js')
17
 
 
18
 
class FiletypeFilter:
19
 
    include_html = False
20
 
    def __call__(self, path):
21
 
        """Return True for filetypes we want to lint."""
22
 
        return path.endswith('.js') or (self.include_html and
23
 
               path.endswith('.html'))
24
 
js_filter = FiletypeFilter()
25
 
 
26
 
 
27
 
class FileFinder:
28
 
    def __init__(self):
29
 
        self.tree = workingtree.WorkingTree.open_containing('.')[0]
30
 
 
31
 
    def find_files_to_lint(self, delta):
32
 
        """Return the modified and added files in a tree from a delta."""
33
 
        files_to_lint = []
34
 
        files_to_lint.extend(info[0] for info in delta.added)
35
 
        files_to_lint.extend(info[0] for info in delta.modified)
36
 
        # And look also at the renamed attribute for modified files.
37
 
        files_to_lint.extend(info[0] for info in delta.renamed if info[4])
38
 
 
39
 
        # Select only the appropriate files and turn them in absolute paths.
40
 
        return [self.tree.abspath(f) for f in files_to_lint if js_filter(f)]
41
 
 
42
 
    def find_files_to_lint_from_working_tree_or_parent(self):
43
 
        """Return the file paths to lint based on working tree changes."""
44
 
        working_tree_delta = self.tree.changes_from(self.tree.basis_tree())
45
 
        if not working_tree_delta.has_changed():
46
 
            return self.find_files_to_lint_from_parent()
47
 
        else:
48
 
            return self.find_files_to_lint(working_tree_delta)
49
 
 
50
 
    def find_files_to_lint_from_working_tree(self):
51
 
        """Return the file path to lint based on working tree changes."""
52
 
        working_tree_delta = self.tree.changes_from(self.tree.basis_tree())
53
 
        return self.find_files_to_lint(working_tree_delta)
54
 
 
55
 
    def find_files_to_lint_from_parent(self):
56
 
        """Return the file path to lint based on working tree changes."""
57
 
        submit = self.tree.branch.get_submit_branch()
58
 
        if submit is None:
59
 
            submit = self.tree.branch.get_parent()
60
 
            if submit is None:
61
 
                raise errors.NoSubmitBranch(self.tree.branch)
62
 
        submit_tree = branch.Branch.open(submit).basis_tree()
63
 
        return self.find_files_to_lint(self.tree.changes_from(submit_tree))
64
 
 
65
 
    def find_all_files_to_lint(self):
66
 
        """Return all the JS files that can be linted."""
67
 
        all_files = []
68
 
        for file_id in self.tree:
69
 
            path = self.tree.id2path(file_id)
70
 
            # Skip build files and third party files.
71
 
            if path.startswith('lib') or path.startswith('build'):
72
 
                continue
73
 
            if js_filter(path):
74
 
                all_files.append(self.tree.abspath(path))
75
 
        return all_files
76
 
 
77
 
 
78
 
class JSLinter:
79
 
    """Linter for Javascript."""
80
 
 
81
 
    def __init__(self, options=None):
82
 
        self.options = options
83
 
 
84
 
    def jslint_rhino(self, filenames):
85
 
        """Run the linter on all selected files using rhino."""
86
 
        args = ['rhino', '-f', FULLJSLINT, JSLINT_WRAPPER]
87
 
        if self.options:
88
 
            args.extend(['-o', self.options])
89
 
        args.extend(filenames)
90
 
        jslint = subprocess.Popen(args)
91
 
        return jslint.wait()
92
 
 
93
 
    def jslint_spidermonkey(self, filenames):
94
 
        """Run the linter on all selected files using spidermonkey."""
95
 
        args = ['js', '-f', FULLJSLINT, JSLINT_WRAPPER]
96
 
        if self.options:
97
 
            args.extend(['-o', self.options])
98
 
        args.extend(filenames)
99
 
        jslint = subprocess.Popen(args, stdin=subprocess.PIPE)
100
 
        # SpiderMonkey can only read from stdin, so we are multiplexing the
101
 
        # different files on stdin.
102
 
        files_to_send = list(filenames)
103
 
        if self.options:
104
 
            files_to_send.insert(0, self.options)
105
 
        for filename in files_to_send:
106
 
            fh = open(filename, 'r')
107
 
            jslint.stdin.write(fh.read())
108
 
            fh.close()
109
 
            jslint.stdin.write('\nEOF\n')
110
 
 
111
 
        return jslint.wait()
112
 
 
113
 
 
114
 
def get_options():
115
 
    """Parse the command line options."""
116
 
    parser = optparse.OptionParser(
117
 
        usage="%prog [options] [files]",
118
 
        description=(
119
 
            "Run Douglas Crockford JSLint script on the JS files. "
120
 
            "By default, all modified files in the current working tree are "
121
 
            "linted. Or all modified files since the parent branch, if there "
122
 
            "are no changes in the current working tree."
123
 
            ))
124
 
    parser.add_option(
125
 
        '-o', '--options', dest='options',
126
 
        help=('JS file returning a configuration object for the linter.'))
127
 
    parser.add_option(
128
 
        '-a', '--all', dest='all', default=False,
129
 
        action='store_true',
130
 
        help=('Lint all JavaScript files in the branch.'))
131
 
    parser.add_option(
132
 
        '-p', '--parent', dest='parent', default=False,
133
 
        action='store_true',
134
 
        help=('Lint all JavaScript files modified from the submit: branch.'))
135
 
    parser.add_option(
136
 
        '-w', '--working-tree', dest='working_tree', default=False,
137
 
        action='store_true',
138
 
        help=('Only lint changed files in the working tree.'))
139
 
    parser.add_option(
140
 
        '-e', '--engine', dest='engine', default='js', action='store',
141
 
        help=('Javascript engine to use. Defaults to "js" (SpiderMonkey). '
142
 
              'Use "rhino" to use the Java-based Rhino engine'))
143
 
    parser.add_option(
144
 
        '-i', '--include-html', dest='html', default=False,
145
 
        action='store_true', help=('Also lint .html files.'))
146
 
 
147
 
    options, args = parser.parse_args()
148
 
    if len(args) > 0:
149
 
        if options.all or options.parent or options.working_tree:
150
 
            parser.error(
151
 
                'Cannot specify files with --all, --parent or --working-tree')
152
 
    else:
153
 
        count = 0
154
 
        if options.all:
155
 
            count += 1
156
 
        if options.parent:
157
 
            count += 1
158
 
        if options.working_tree:
159
 
            count += 1
160
 
        if count > 1:
161
 
            parser.error(
162
 
                'Only one of --all, --parent or --working-tree should be '
163
 
                'specified.')
164
 
    if options.engine not in ['js', 'rhino']:
165
 
        parser.error(
166
 
            'Unrecognized engine. Use either "js" or "rhino".')
167
 
    return options, args
168
 
 
169
 
 
170
 
def main():
171
 
    options, args = get_options()
172
 
    linter = JSLinter(options.options)
173
 
    js_filter.include_html = options.html
174
 
    if args:
175
 
        files = [f for f in args if js_filter(f)]
176
 
    else:
177
 
        load_plugins()
178
 
        finder = FileFinder()
179
 
        if options.all:
180
 
            files = finder.find_all_files_to_lint()
181
 
        elif options.working_tree:
182
 
            files = finder.find_files_to_lint_from_working_tree()
183
 
        elif options.parent:
184
 
            files = finder.find_files_to_lint_from_parent()
185
 
        else:
186
 
            files = finder.find_files_to_lint_from_working_tree_or_parent()
187
 
    if not files:
188
 
        print 'jslint: No files to lint.'
189
 
    else:
190
 
        if len(files) == 1:
191
 
            print 'jslint: 1 file to lint.'
192
 
        else:
193
 
            print 'jslint: %d files to lint.' % len(files)
194
 
        if options.engine == 'js':
195
 
            jslint = linter.jslint_spidermonkey
196
 
        elif options.engine == 'rhino':
197
 
            jslint = linter.jslint_rhino
198
 
        else:
199
 
            raise AssertionError('Unknown engine: %s' % options.engine)
200
 
        sys.exit(jslint(files))
201