Commit Graph

21 Commits

Author SHA1 Message Date
Andrew Halberstadt
3b8e56ae22 Bug 1460690 - [mozlint] Make sure vcs_paths are always joined to the repository root, r=standard8
Files returned from version control (i.e via --outgoing or --workdir), are currently joined to
cwd. This will cause failures if |mach lint| is run from anywhere other than topsrcdir.

However we *do* want to join manually specified paths to cwd so things like:
cd devtools && mach lint client

continue to work. This patch makes sure we join the proper kind of path to the proper place.

MozReview-Commit-ID: EQmRhAr3Oog
2018-05-11 11:13:36 -04:00
Andrew Halberstadt
1caf5b4687 Bug 1373368 - [mozlint] Lint whole tree if using --workdir/--outgoing and support-file was modified, r=standard8
Previously, using --workdir or --outgoing could miss errors when modifying a
support file since those could affect unmodified files.

This patch allows linters to define support-files in their .yml configuration.
If using --outgoing or --workdir and a file matching one of those patterns was
modified, we'll lint the entire tree.

MozReview-Commit-ID: CuGLYwQwiWr
2018-02-16 17:46:04 -05:00
Andrew Halberstadt
589049ea6c Bug 1369711 - [mozlint] Make sure KeyboardInterrupts are handled well wherever they happen r=gps
There a few pieces needed here to properly handle KeyboardInterrupts.

1. All in-progress work needs to abort. Ideally the underlying linters will be
able to catch KeyboardInterrupt, and return partial results (like the flake8
linter does). Linters may alternatively allow the KeyboardInterrupt to
propagate up. Mozlint will catch and handle this appropriately, though any
results found will be lost. The only change to this behaviour was fixing a bug
in the flake8 linter.

2. Any unstarted jobs need to be canceled. In concurrent.futures, there are two
different queues. First, jobs are placed on the work queue, which is just a list
maintained by the parent process. As workers become available, jobs are moved
off the work queue, and onto the call queue (which is a multiprocessing.Queue).
Jobs that live on the work queue can be canceled with 'future.cancel()', whereas
jobs that live on the call queue cannot. The number of extra jobs that are stored
on the call queue is determined by this variable:
https://hg.mozilla.org/mozilla-central/file/deb7714a7bcd/third_party/python/futures/concurrent/futures/process.py#l86

In this patch, the parent process' sigint handler (which will be called on Ctrl-C)
is responsible for canceling all the jobs on the work queue. For the jobs on the
call queue, the best we can do is set a global variable that tells workers to
abort early.

3. Idle workers should exit gracefully. When there are no more jobs left, workers
will block on the call queue (either waiting for more jobs, or waiting for the
executor to send the shutdown signal). If a KeyboardInterrupt is received while a
worker is blocking, it isn't possible to intercept that anywhere (due to quirks
of how concurrent.futures is implemented). The InterruptableQueue class was
created to solve this problem. It will return None instead of propagating
KeyboardInterrupt. A None value will wake the worker up and tell it to gracefully
shutdown. This way, we avoid cryptic tracebacks in the output.

With all of these various pieces solved, pressing Ctrl-C appears to always exit
gracefully, sometimes even printing partial results.

MozReview-Commit-ID: 36Pe3bbUKmk
2018-02-23 08:55:06 -05:00
Andrew Halberstadt
5b723dd152 Bug 1369711 - [mozlint] Refactor concurrent.futures ProcessPoolExecutor code for readability r=gps
This commit doesn't change any behaviour, just attempts to make this a little
more readable.  The workers will call '_collect_results' for each WorkItem they
process (either because it is finished or because it was canceled).

This also differentiates between setup failures and run failures.

MozReview-Commit-ID: 36Pe3bbUKmk
2018-02-23 09:02:16 -05:00
Andrew Halberstadt
2359a4b0a5 Bug 1429457 - [mozlint] Create formal 'setup' mechanism for bootstrapping lint dependencies, r=gbrown
This allows linters to define a 'setup' method which will automatically be
called by |mach lint| before running the linter. Users can also explicitly run
these methods (without doing any actual linting) by running |mach lint --setup|.

MozReview-Commit-ID: 74aY1pfsaX1
2018-01-25 13:40:02 -05:00
Andrew Halberstadt
8f88407aaf Bug 1430825 - [mozlint] Split work up by paths instead of by linters, r=standard8
The initial motivation for this patch, was to prevent command lines that are
too long on Windows. To that end, there is a cap to the number of paths that
can be run per job. For now that cap is set to 50. This will allow for an
average path length of 160 characters, which should be sufficient with room to
spare.

But another big benefit of this patch is that we are running more things in
parallel. Previously, mozlint ran each linter in its own subprocess, but that's
it. If running eslint is 90% of the work, it'll still only get a single
process. This means we are wasting cores as soon as the other linters are
finished.

This patch chunks the number of specified paths such that there will be N*L
jobs where 'N' is the number of cores and 'L' is the number of linters.  This
means even when there's a dominant linter, we'll be making better use of our
resources. This isn't perfect of course, as some paths might contain a small
number of files, and some will contain a very large number of files.  But it's
a start

A limitation to this approach is that if there are fewer paths specified than
there are cores, we won't schedule enough jobs per linter to use those extra
cores. One idea might be to expand specified directories and individually list
all the paths under the directory. But this has some hairy edge cases that
would be tough to catch. Doing this in a non-hacky way would also require a
medium scale refactor.

So I propose further parallelization efforts be destined for follow-ups.

MozReview-Commit-ID: JRRu13AFaii
2018-01-16 16:01:20 -05:00
Gurzau Raul
df590e36a5 Backed out changeset 5bb16f349a38 (bug 1430825) for Windows build bustage on a CLOSED TREE 2018-01-22 21:54:08 +02:00
Andrew Halberstadt
4712493d77 Bug 1430825 - [mozlint] Split work up by paths instead of by linters, r=standard8
The initial motivation for this patch, was to prevent command lines that are
too long on Windows. To that end, there is a cap to the number of paths that
can be run per job. For now that cap is set to 50. This will allow for an
average path length of 160 characters, which should be sufficient with room to
spare.

But another big benefit of this patch is that we are running more things in
parallel. Previously, mozlint ran each linter in its own subprocess, but that's
it. If running eslint is 90% of the work, it'll still only get a single
process. This means we are wasting cores as soon as the other linters are
finished.

This patch chunks the number of specified paths such that there will be N*L
jobs where 'N' is the number of cores and 'L' is the number of linters.  This
means even when there's a dominant linter, we'll be making better use of our
resources. This isn't perfect of course, as some paths might contain a small
number of files, and some will contain a very large number of files.  But it's
a start

A limitation to this approach is that if there are fewer paths specified than
there are cores, we won't schedule enough jobs per linter to use those extra
cores. One idea might be to expand specified directories and individually list
all the paths under the directory. But this has some hairy edge cases that
would be tough to catch. Doing this in a non-hacky way would also require a
medium scale refactor.

So I propose further parallelization efforts be destined for follow-ups.

MozReview-Commit-ID: JRRu13AFaii
2018-01-16 16:01:20 -05:00
Steve Armand
7f77fd4581 Bug 1397423 - Enable py2 linter on python/mozlint. r=ahal
MozReview-Commit-ID: 6QX7YCmfjdJ
2017-09-06 22:52:46 -04:00
Andrew Halberstadt
f7b445f2f2 Bug 1339178 - Use pytest to run python-tests, r=davehunt
This switches most tests over to use pytest as the runner instead of unittest (taking
advantage of the fact that pytest can run unittest based tests).

There were a couple tests that had failures when swithing to pytest:
config/tests/unit-expandlibs.py
xpcom/idl-parser/xpidl/runtests.py

For these tests, I added a runwith='unittest' argument so that they still run the
same way as before. Once we fix them to use pytest, the unittest logic in mozunit.py
can be deleted.

MozReview-Commit-ID: Gcsz6z8MeOi
2017-08-29 14:50:33 -04:00
Andrew Halberstadt
f58b1651f0 Bug 1288432 - [mozlint] Use yaml for lint definitions and separate implementation of external linters, r=bc
Rather than using .lint.py files that contain a LINTER object, linter definitions are now in
standalone .yml files. In the case of external linters that need to run python code, the payload
is now of the form:
<module path>:<object path>

The <module path> is the import path to the module, and <object path> is the callable object to
use within that module. It is up to the consumer of mozlint to ensure the <module path> lives on
sys.path. For example, if an external lint's function lives in package 'foo', file 'bar.py' and
function 'lint', the payload would read:
foo.bar:lint

This mechanism was borrowed from taskcluster.

MozReview-Commit-ID: AIsfbVmozy4
2017-06-02 09:49:26 -04:00
Mark Banner
1584c1721b Bug 1358540 - Change the *.lint files to be *.lint.py to better support editor integration & flake8 linting. r=smacleod
MozReview-Commit-ID: 4KK2GZK7xul
2017-04-21 17:31:15 +01:00
Andrew Halberstadt
ab127bc249 Bug 1316925 - Keep track of failed linters in stylish formatter summary, r=jgraham
This replaces the "return_code" property on the LintRoller object with a list of "failed"
linters. This is a bit more useful as it lets us know exactly which linters had a problem
(whereas previously we just knew *something* went wrong). This patch pushes determining
the return code back into cli.py, which I think is fine.

In addition, we now pass the list of failed linters into the formatter. This allows us to
clarify exactly how many linters hit a failure which is a lot better than a seemingly
"successful" summary message.

Finally I also removed the "no files to lint" message because I've seen several people
confuse it for an error. I'll probably add it back as a debug log message when we switch
to using mozlog for output.

MozReview-Commit-ID: 4wyCeOZdOf8
2016-11-14 11:56:46 -05:00
Andrew Halberstadt
4831d5a694 Bug 1309963 - Make sure return codes are passed from .lint files up to the cli, r=jgraham
If a linter returns a status code instead of a list of results, mozlint will throw away
that status code and move on to the next linter. We should make sure that status code
bubbles all the way up to the cli.

MozReview-Commit-ID: 9fXpmtlUUT1
2016-10-13 16:23:13 -04:00
Andrew Halberstadt
4f16b60703 Bug 1302172 - [mozlint] Convert unittest tests to use pytest instead, r=maja_zf
MozReview-Commit-ID: D4bN62QbkKm
2016-09-09 16:20:09 -04:00
Andrew Halberstadt
6de31fa92d Bug 1297699 - Mozlint tests should run with test directory as the "project root", r=smacleod
MozReview-Commit-ID: 9sbhlc11YF5
2016-08-24 09:55:04 -04:00
Andrew Halberstadt
f4b5bbd86c Bug 1288425 - Make sure we skip invalid extensions when linting with --rev or --workdir, r=smacleod
Some linters, such as flake8, will lint invalid file extensions if you explicitly pass them in. E.g,
|flake8 foobar.js| will result in flake8 attempting to lint a JS file. This is a problem because passing
in files explicitly is exactly what the --rev/--workdir options do. If a developer modifies a JS file
then runs |mach lint -l flake8 -w|, that JS file will get linted.

To prevent this, mozlint needs to handle file extensions instead of relying on the underlying linter to
do it. This patch adds an "extensions" config option to the LINTER dict, and will filter these files out
as part of the 'filterpaths' steps.

MozReview-Commit-ID: KYhC6SEySC3
2016-08-09 16:24:04 -04:00
Andrew Halberstadt
b0ccc9546d Bug 1289805 - Resolve vcs arguments directly in LintRoller class, r=smacleod
Previously, vcs related stuff was resolved in the cli.py module. But it's possible
for consumers to bypass the cli and instantiate a LintRoller directly. In fact this
is what the mozlint tests do.

Now that we always try to find the vcs root, calling into vcs is no longer optional.
This patch moves the VCSFiles class to a new vcs.py module and makes LintRoller
responsible for instantiating it instead of cli.py.

MozReview-Commit-ID: 5yA3gDZ1UGM
2016-08-10 10:21:43 -04:00
Iris Hsiao
08d28a33eb Backed out changeset 2141360b4137 (bug 1288425) for build bustage 2016-07-27 10:59:10 +08:00
Andrew Halberstadt
f3e926935f Bug 1288425 - Make sure we skip invalid extensions when linting with --rev or --workdir, r=smacleod
Some linters, such as flake8, will lint invalid file extensions if you explicitly pass them in. E.g,
|flake8 foobar.js| will result in flake8 attempting to lint a JS file. This is a problem because passing
in files explicitly is exactly what the --rev/--workdir options do. If a developer modifies a JS file
then runs |mach lint -l flake8 -w|, that JS file will get linted.

To prevent this, mozlint needs to handle file extensions instead of relying on the underlying linter to
do it. This patch adds an "extensions" config option to the LINTER dict, and will filter these files out
as part of the 'filterpaths' steps.

MozReview-Commit-ID: KYhC6SEySC3
2016-07-19 13:50:25 -04:00
Andrew Halberstadt
9b8568c92e Bug 1230962 - Add python/mozlint for running several linters at once, r=smacleod
Mozlint provides two main benefits:
1. A common system for defining lints across multiple languages
2. A common interface and result format for running them

This commit only adds the core library, it does not add any consumers of mozlint just yet.

MozReview-Commit-ID: CSQzq5del5k
2016-03-16 14:55:21 -04:00