Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added erlang-rebar3 checker #1144

Merged
merged 2 commits into from
May 22, 2017
Merged

Added erlang-rebar3 checker #1144

merged 2 commits into from
May 22, 2017

Conversation

joedevivo
Copy link
Contributor

I wrote a flycheck checker for erlang projects using rebar3, but when I tried adding it to melpa, they said it was pretty basic, so I should try including it in flycheck, so here I am :D

As per the suggestion here: melpa/melpa#4342

@CLAassistant
Copy link

CLAassistant commented Oct 21, 2016

CLA assistant check
All committers have signed the CLA.

@swsnr
Copy link
Contributor

swsnr commented Oct 23, 2016

@joedevivo Thank you very much. I'll leave a first review.

Copy link
Contributor

@swsnr swsnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you clarify how this checker should interact with the existing erlang checker? Should they be used together?

Also, could you perhaps try and write an integration test for this syntax checker? See test/flycheck-test.el for examples.

flycheck.el Outdated

(defun flycheck-rebar3-project-root (_checker)
"Return directory where =rebar.config= is located."
(locate-dominating-file buffer-file-name "rebar.config"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does rebar work if rebar.config is missing? If not it needs an :enabled function that checks whether the file is actually present.

flycheck.el Outdated
"An Erlang syntax checker using the rebar3 build tool.

See URL `https://www.rebar3.org'."
:command ("rebar3" "compile")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I presume the syntax checker compiles the entire project? The it needs a :predicate that checks whether the current buffer is saved because in this case Flycheck won't be able to feed the actual contents of the buffer to the checker, so if the buffer is not saved the errors will not be accurate.

@joedevivo
Copy link
Contributor Author

@lunaryorn I just installed today's flycheck build and it's generating some errors:

Compiling file /Users/joe/.emacs.d/elpa/flycheck-20161023.643/flycheck-ert.el at Sun Oct 23 08:44:11 2016
Entering directory ‘/Users/joe/.emacs.d/elpa/flycheck-20161023.643/’

Compiling file /Users/joe/.emacs.d/elpa/flycheck-20161023.643/flycheck.el at Sun Oct 23 08:44:11 2016
flycheck.el:2610:1:Warning: Unused lexical argument ‘cwd’

In flycheck-finish-current-syntax-check:
flycheck.el:2630:20:Warning: reference to free variable ‘working-dir’

In flycheck-handle-idle-change:
flycheck.el:2748:8:Warning: function flycheck-handle-idle-change used to take
    0+ arguments, now takes 0

In end of data:
flycheck.el:9343:1:Warning: the function
    ‘flycheck-syntax-check-current-checker’ is not known to be defined.

Compiling no file at Sun Oct 23 08:44:11 2016

It's not related to this, but I figured you should know

@swsnr
Copy link
Contributor

swsnr commented Oct 23, 2016

@joedevivo Thanks for making me aware, but that's already been fixed in f112d0c. Please don't hijack discussions for unrelated topics. Instead just open a new issue. Thank you.

joedevivo added a commit to joedevivo/flycheck that referenced this pull request Oct 23, 2016
- Still no tests, will take a stab at that next
flycheck.el Outdated
wouldn't be aware of. One such example is the erlang -include
directive. Rebar3 is aware of the context for those includes,
where the standard erlang checker is not. This checker should be
used instead of the erlang checker for all rebar3 projects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks but I didn't mean to clarify that in the docstring, but rather write a comment on the Github issue 😊 Please remove this rather lengthy paragraph again.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Can you please remove this paragraph?

flycheck.el Outdated
:working-directory flycheck-rebar3-project-root)

(defun flycheck-rebar-config-exists-p ()
"Whether there is a rebar.config for the current buffer."
(let* ((executable (flycheck-find-checker-executable 'erlang-rebar3))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why you check that? Are you aware that Flycheck does that automatically?

flycheck.el Outdated
"Whether there is a rebar.config for the current buffer."
(let* ((executable (flycheck-find-checker-executable 'erlang-rebar3))
(config-file (locate-dominating-file buffer-file-name "rebar.config"))
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't let parens hang on the next line.

@joedevivo
Copy link
Contributor Author

I'm happy with this pull request except for one thing. My tests are failing, and it's because the rebar3 tests aren't saving the buffer. I can't figure out how to make it do this. Any suggestion?

@swsnr
Copy link
Contributor

swsnr commented Oct 23, 2016

@joedevivo Can you show the output of the test?

And do we really need all those files? The separate LICENSE is a no-go, in any case.

@joedevivo
Copy link
Contributor Author

@lunaryorn yes sorry, I'll take care of that and set it up so it's just the minimum rebar3 needs to recognize a project.

Here's my error output:

➜  flycheck git:(master) ✗ make LANGUAGE=erlang integ
cask exec emacs -Q --batch -L .  -l maint/flycheck-compile.el -f flycheck/batch-byte-compile flycheck-buttercup.el
cask exec emacs -Q --batch -L .  --load test/flycheck-test --load test/run.el -f flycheck-run-tests-main '(and (tag external-tool) (language erlang))'
Running tests on Emacs 25.1.1, built at 2016-09-17
Running 4 tests (2016-10-23 11:32:02-0700)
Loading erlang-skels...
Test flycheck-define-checker/erlang-rebar3/error backtrace:
  flycheck-ert-should-errors((7 nil error "head mismatch" :checker erl
  apply(flycheck-ert-should-errors (7 nil error "head mismatch" :check
  flycheck-ert-should-syntax-check("language/erlang-rebar3/src/erlang-
  (closure (python-indent-guess-indent-offset js3-mode-show-parse-erro
  ert--run-test-internal([cl-struct-ert--test-execution-info [cl-struc
  ert-run-test([cl-struct-ert-test flycheck-define-checker/erlang-reba
  ert-run-or-rerun-test([cl-struct-ert--stats (and "flycheck-" (and (t
  ert-run-tests((and "flycheck-" (and (tag external-tool) (tag languag
  ert-run-tests-batch((and "flycheck-" (and (tag external-tool) (tag l
  ert-run-tests-batch-and-exit((and "flycheck-" (and (tag external-too
  (let ((selector (car-safe (prog1 argv (setq argv (cdr argv)))))) (if
  flycheck-run-tests-batch-and-exit()
  (let ((debug-on-error t)) (flycheck-run-tests-batch-and-exit))
  (let* ((load-prefer-newer t) (source-directory (locate-dominating-fi
  flycheck-run-tests-main()
  command-line-1(("-L" "." "--load" "test/flycheck-test" "--load" "tes
  command-line()
  normal-top-level()
Test flycheck-define-checker/erlang-rebar3/error condition:
    (ert-test-failed
     ((should
       (equal expected flycheck-current-errors))
      :form
      (equal
       ([cl-struct-flycheck-error #<killed buffer> erlang-rebar3 "/Users/joe/dev/joedevivo/flycheck/test/resources/language/erlang-rebar3/src/erlang-error.erl" 7 nil "head mismatch" error nil])
       nil)
      :value nil :explanation
      (different-types
       ([cl-struct-flycheck-error #<killed buffer> erlang-rebar3 "/Users/joe/dev/joedevivo/flycheck/test/resources/language/erlang-rebar3/src/erlang-error.erl" 7 nil "head mismatch" error nil])
       nil)))
   FAILED  1/4  flycheck-define-checker/erlang-rebar3/error
Test flycheck-define-checker/erlang-rebar3/warning backtrace:
  flycheck-ert-should-errors((6 nil warning "wrong number of arguments
  apply(flycheck-ert-should-errors (6 nil warning "wrong number of arg
  flycheck-ert-should-syntax-check("language/erlang-rebar3/src/erlang-
  (closure (python-indent-guess-indent-offset js3-mode-show-parse-erro
  ert--run-test-internal([cl-struct-ert--test-execution-info [cl-struc
  ert-run-test([cl-struct-ert-test flycheck-define-checker/erlang-reba
  ert-run-or-rerun-test([cl-struct-ert--stats (and "flycheck-" (and (t
  ert-run-tests((and "flycheck-" (and (tag external-tool) (tag languag
  ert-run-tests-batch((and "flycheck-" (and (tag external-tool) (tag l
  ert-run-tests-batch-and-exit((and "flycheck-" (and (tag external-too
  (let ((selector (car-safe (prog1 argv (setq argv (cdr argv)))))) (if
  flycheck-run-tests-batch-and-exit()
  (let ((debug-on-error t)) (flycheck-run-tests-batch-and-exit))
  (let* ((load-prefer-newer t) (source-directory (locate-dominating-fi
  flycheck-run-tests-main()
  command-line-1(("-L" "." "--load" "test/flycheck-test" "--load" "tes
  command-line()
  normal-top-level()
Test flycheck-define-checker/erlang-rebar3/warning condition:
    (ert-test-failed
     ((should
       (equal expected flycheck-current-errors))
      :form
      (equal
       ([cl-struct-flycheck-error #<killed buffer> erlang-rebar3 "/Users/joe/dev/joedevivo/flycheck/test/resources/language/erlang-rebar3/src/erlang-warning.erl" 6 nil "wrong number of arguments in format call" warning nil])
       nil)
      :value nil :explanation
      (different-types
       ([cl-struct-flycheck-error #<killed buffer> erlang-rebar3 "/Users/joe/dev/joedevivo/flycheck/test/resources/language/erlang-rebar3/src/erlang-warning.erl" 6 nil "wrong number of arguments in format call" warning nil])
       nil)))
   FAILED  2/4  flycheck-define-checker/erlang-rebar3/warning
   passed  3/4  flycheck-define-checker/erlang/error
   passed  4/4  flycheck-define-checker/erlang/warning

Ran 4 tests, 2 results as expected, 2 unexpected (2016-10-23 11:32:06-0700)

2 unexpected results:
   FAILED  flycheck-define-checker/erlang-rebar3/error
   FAILED  flycheck-define-checker/erlang-rebar3/warning

make: *** [integ] Error 1

@joedevivo
Copy link
Contributor Author

I don't think I'll be able to act much more on this for the rest of the day, but any suggestions you have on the test front, I'll be happy to try out tonight or tomorrow, as well as finishing up the other recommendations here.

Thanks for taking the time today

@swsnr
Copy link
Contributor

swsnr commented Oct 23, 2016

Me neither, I'll take a look at the test stuff tomorrow (my time 😉)

flycheck.el Outdated
buffer-files)
; If buffer-files is nil, it just means we didn't use
; any temp files to compile this
(not buffer-files))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this or condition to make the tests pass. Since I wasn't building with any temporary files, buffer-files was always coming through nil, so seq-some would always be false. This resulted in no errors making it back to the assertion. It's weird that this worked fine in real world usage.

@joedevivo
Copy link
Contributor Author

Confirming it still works in regular usage

@joedevivo joedevivo force-pushed the master branch 2 times, most recently from fdb2f2f to c4190ab Compare October 25, 2016 01:16
joedevivo added a commit to joedevivo/flycheck-rebar3 that referenced this pull request Oct 30, 2016
flycheck.el Outdated
0
(string-match
"\\(/_build/[^/]+/lib\\|/_checkouts\\)"
rebarconfig)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Can you illustrate what this substring is supposed to do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A rebar3 project will check dependencies out into a _build/<profile_name>/lib folder. Your dependency will have .erl files, and you may want to open them in emacs to review what they're doing. If you do, flycheck will try and build that rebar3 project, because it will satisfy the checker.

Let's look at a real world example. https://github.com/joedevivo/chatterbox

Chatterbox has src/*.erl and we'll wan't those to work as the checker was already defined.

When I build chatterbox, it pulls dependencies into _build/default/lib, but also _build/test/lib which lets me include specific dependencies that I don't want bundled with the release, they're just there to test. If I open up any file in _build/*/lib/*/src/*.erl, it shouldn't try and compile that project on its own. That would wind up building _build/<profile>/lib/<dependency>/_build/<profile>/lib/<dependency_of_the_first_depencency> and so on. This regex will match places that rebar checks things out to, and helps us make sure we're only building the parent project.

_checkouts is a little different. Chatterbox is coupled to another repo I maintain: https://github.com/joedevivo/hpack. The development is done in tandem, and I can work on a master version of hpack by checking it out to _checkouts.

I hope this clarifies what that regex is doing here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo I see, but I'm not convinced that a regex is the right tool to use here, and I do not like string substitutions over pathnames. That's just inherently fragile—for instance your current regex obviously breaks on windows pathnames.

How about the following algorithm instead:

  1. Find the nearest project-directory containing rebar.config file with locate-dominating-file
  2. From that file, find the nearest directory that contains a _build directory with locate-dominating-file. If none exists return project-directory as the final working directory.
  3. If one exists let-bind it to default-directory and then recursively call flycheck-rebar3-project-root again to restart the search for the top-most rebar project directory.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like it. The issue with step 2 is that I need to look for _build or _checkouts; however, there's an even better solution. We can just keep looking for rebar.config. Every rebar3 project needs one, so a recursive call to locate-dominating-file would be enough. I've rust run into one snag: A recursive call to locate-dominating-file finds the one in ., so I need the recursive call to run on the parent directory, and I just can't figure out the function to give me the parent-dir, do you know how to do that? Thanks for the elisp lesson :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to push with a solution using (expand-file-name ".." possibly-nested-project-dir)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Mmh, I'm not sure whether that's not too eager: Is there no reason why anyone would ever nest two proper rebar projects under a top-level project? Would you never use "nested" projects with rebar?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chances are, if flycheck encounters this then it's a mistake on the part of the user. Something got built in a way it wasn't supposed to, or some artifact of some build survived somewhere it shouldn't have. No matter the case, the top rebar.config it can find is always the right answer. I think something less eager would still work 90% of the time, so if we're concerned about speed we could opt for something like that.

There's no nesting of projects with rebar. If you are doing something like, there's a way to structure your source so it will build multiple applications, but if you did that, it would still be done with a single rebar.config file and the applications would be bundled together into a single release artifact.

The closest thing to what I think you're looking for would be if you had two rebar3 projects, and a third than included both of them as dependencies, but that's already covered.

Did that clear it up?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Yes, absolutely, thank you very much for taking the time to explain.

I'll take another look at the implementation, but maybe not before tomorrow.

Also thanks for bearing with me, for your patience with all my questions and remarks. It's a pleasure to review a pull request like this, thanks a lot!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're welcome! I'm happy to give back, and it's been fun learning more about elisp.

"language/erlang/rebar3/_checkouts/dependency/src/dependency.erl" 'erlang-mode)
(should (not (file-exists-p
(flycheck-ert-resource-filename
"language/erlang/rebar3/_build/default/lib/dependency/_build")))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's this assertion for? What does it test? Why is it important this this file/directory does not exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the comment above about the regex, this assertion is testing that when we open a buffer for a dependency, it doesn't build the dependency as if it were a standalone project. If it did, it would create that _build directory, so we're asserting that it doesn't.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Can you add a comment that explains this above this assertion? E.g.

Ensure that the dependency file wasn't build as standalone project which would create a separate _build directory

would be sufficient (please wrap it to 80 characters though :) )

flycheck.el Outdated
:command ("rebar3" "compile")
:error-parser
(lambda (output checker buffer)
(flycheck-parse-with-patterns (ansi-color-filter-apply output) checker buffer))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a little comment here that explains why we need to filter colours manually, and include a link to this pull request, so that we can easily find the discussion again when we look at this code in future.

flycheck.el Outdated
@@ -79,6 +79,7 @@
(require 'help-mode) ; `define-button-type'
(require 'find-func) ; `find-function-regexp-alist'
(require 'json) ; `flycheck-parse-tslint'
(require 'ansi-color) ; strip ansi color from command output
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this require into the body of the rebar3 :error-parser function. That'll break the build due to a byte compiler warning, which we can then fix together.

joedevivo added a commit to joedevivo/flycheck that referenced this pull request Oct 30, 2016
As expected, there's a compilation error

```
In toplevel form:
flycheck.el:9377:1:Error: the function ‘ansi-color-filter-apply’ might not be defined at runtime.
make: *** [flycheck.elc] Error 1
```
@joedevivo
Copy link
Contributor Author

@lunaryorn I pushed up the changes, and yes, now there's a compile error.

flycheck.el Outdated
;; relevant disucssion can be found
;; https://github.com/flycheck/flycheck/pull/1144
(require 'ansi-color)
(flycheck-parse-with-patterns (ansi-color-filter-apply output) checker buffer))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Thanks for the explanatory comment.

Now, to fix the compiler warning use the following as argument to flycheck-parse-with-patterns:

(and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))

The fboundp guard is entirely redundant, because we know that (require 'ansi-color) brings that function in scope, but the byte compiler can't make that link. However, the fboundp guard convinces it that we're only calling the function when it's defined and thus removes the warning.

Ugly, but works, and much evil is achieved 😎

"language/erlang/rebar3/_checkouts/dependency/src/dependency.erl" 'erlang-mode)
(should (not (file-exists-p
(flycheck-ert-resource-filename
"language/erlang/rebar3/_build/default/lib/dependency/_build")))))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo Can you add a comment that explains this above this assertion? E.g.

Ensure that the dependency file wasn't build as standalone project which would create a separate _build directory

would be sufficient (please wrap it to 80 characters though :) )

flycheck.el Outdated
@@ -6920,6 +6920,41 @@ See URL `http://www.erlang.org/'."
(error line-start (file-name) ":" line ": " (message) line-end))
:modes erlang-mode)

(defun flycheck-rebar3-project-root (&optional _checker)
"Return directory where =rebar.config= is located."
(let* ((rebarconfig (locate-dominating-file buffer-file-name "rebar.config"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, the name of this variable is wrong, I think. Afaik locate-dominating-file returns the directory containing the file, not the path to the file itself, so the variable doesn't actually contain the path to the rebar configuration file but rather the project directory.

So I guess project-directory is the better name here isn't it?

flycheck.el Outdated
0
(string-match
"\\(/_build/[^/]+/lib\\|/_checkouts\\)"
rebarconfig)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joedevivo I see, but I'm not convinced that a regex is the right tool to use here, and I do not like string substitutions over pathnames. That's just inherently fragile—for instance your current regex obviously breaks on windows pathnames.

How about the following algorithm instead:

  1. Find the nearest project-directory containing rebar.config file with locate-dominating-file
  2. From that file, find the nearest directory that contains a _build directory with locate-dominating-file. If none exists return project-directory as the final working directory.
  3. If one exists let-bind it to default-directory and then recursively call flycheck-rebar3-project-root again to restart the search for the top-most rebar project directory.

What do you think?

Copy link
Contributor

@swsnr swsnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the long delay, had a unexpectedly busy week.

I overlooked a markup issue in the docstrings which needs to be fixed, and I'm not yet happy with the code that finds the project root. I think it can be simplified, maybe with a single while loop that traverses upwards until there's no project root directory anymore.

flycheck.el Outdated
@@ -6920,6 +6920,49 @@ See URL `http://www.erlang.org/'."
(error line-start (file-name) ":" line ": " (message) line-end))
:modes erlang-mode)

(defun locate-rebar3-project-root (file-name)
"Return directory where the root =rebar.config= for the source FILE-NAME is located."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that you're using org-mode syntax in docstrings, i.e. =…=. However docstrings are not in Org syntax; please go over all docstrings and remove all occurrences of this syntax.

Also, I think you can shorten the summary of this function and instead write a more comprehensive docstring, e.g.

Find the top-most rebar project root for source FILE-NAME.

A project root directory is any directory containing a rebar.config file.  
Find the top-most directory to move out of any nested dependencies.

FILE-NAME is a source file for which to find the project.

Return the absolute path to the directory.

The first line of docstrings should be very brief as it's used in many listing with limited space, e.g. apropos, so it's better to write a short summary line and a more verbose docstring.

flycheck.el Outdated
(locate-dominating-file
(expand-file-name ".." possibly-nested-project-dir)
"rebar.config")
nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been thinking about whether we could simplify this code, to only call locate-dominating-file once. Would that be possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully the new implementation looks good.

flycheck.el Outdated
@@ -80,7 +80,6 @@
(require 'find-func) ; `find-function-regexp-alist'
(require 'json) ; `flycheck-parse-tslint'


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accident

flycheck.el Outdated
(locate-rebar3-project-root (directory-file-name current-dir)
file-name
(cons (contains-rebar-config current-dir) acc))
)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't let parenthesis hang on a line on their own. Always join with the code before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@swsnr
Copy link
Contributor

swsnr commented Nov 14, 2016

@joedevivo Ok, there are two minor stylistic issues left, but other than that I think we're ready now.

Would you like to join Flycheck as part of a new Erlang team to take care of Erlang support in Flycheck? That'd really help us to maintain proper support for Erlang.

@joedevivo
Copy link
Contributor Author

Done. Would you like me to squash the commits?

I'm happy to keep working on Erlang support as the need arises :D

@swsnr
Copy link
Contributor

swsnr commented Nov 17, 2016

@joedevivo Yup, please squash your commits.

Thanks for joining us, I'll invite you to the team tonight, and approve the review. Then you'll be able to merge this PR yourself 👍

Meanwhile browse through our Contributor's Guide and our Maintainer's Guide 😊

@joedevivo
Copy link
Contributor Author

@lunaryorn I squashed the commits a few days ago, but forgot to let you know. sorry about that.

@joedevivo
Copy link
Contributor Author

@lunaryorn hey, I haven't gotten the team invite, do you mind sending again?

@Simplify
Copy link
Member

Simplify commented May 8, 2017

@cpitclaudel Can you take look at this PR? I'll like to have it in Flycheck.

@joedevivo Sorry about delay. Are you still willing to support Erlang in Flycheck?

flycheck.el Outdated
@@ -6920,6 +6921,62 @@ See URL `http://www.erlang.org/'."
(error line-start (file-name) ":" line ": " (message) line-end))
:modes erlang-mode)

(defun contains-rebar-config (dir-name)
"Return DIR-NAME if DIR-NAME/rebar.config exists, nil otherwise."
(if (file-exists-p (expand-file-name "rebar.config" dir-name))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be when or and instead of if

flycheck.el Outdated
(if (file-exists-p (expand-file-name "rebar.config" dir-name))
dir-name nil))

(defun locate-rebar3-project-root (file-name &optional prev-file-name acc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be essentially locate-dominating-file, but looking for the topmost file. Why is that needed?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first rebar.config it finds isn't necessarily the project root. This function is actually slightly wrong though. It should use "\\(/_build/[^/]+/lib\\|/_checkouts\\|/apps\\)"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clearer, any Erlang application in a project could have a rebar.config of its own, while there will also be a top level rebar.config. So this just makes sure that the file we are using isn't a sub-app or dependency of the project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. You might want to explore how a dependency works, but that buffer might think it's the main project without this. Then it would try and fetch the dependencies dependencies, which have already been fetched by the root project.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tsloughter as implemented, this should catch all of those things. I assume that the critique here is that it might catch more than it should?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpitclaudel, @tsloughter is one of the authors of rebar3, so I'll defer to his judgement on if this needs further modification. Or, as I hope, that it's good enough for now, we can get this merged, and then come back and make small tweaks as needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tsloughter Thanks, that's what I meant by looking for the topmost file.

flycheck.el Outdated

Return the absolute path to the directory"
(if (string= file-name prev-file-name)
(car (seq-drop-while (lambda (x) (not x)) acc))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for seq-drop-while here; it should be enough to use (remove nil …)

flycheck.el Outdated
;; rebar3 outputs ANSI terminal colors, which don't match up with
;; :error-patterns, so we strip those color codes from the output
;; here before passing it along to the default behavior. The
;; relevant disucssion can be found
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foundfound at

flycheck.el Outdated
;; https://github.com/flycheck/flycheck/pull/1144
(require 'ansi-color)
(flycheck-parse-with-patterns
(and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks suspicious. Wouldn't ansi-color-filter-apply always be bound, due to the require above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really understand this either. @lunaryorn told me to add this here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only comment I left outstanding, maybe you'll have a better context for this after reading the comment I mentioned and we can go from there

flycheck.el Outdated
(error line-start
(file-name) ":" line ": " (message) line-end))
:modes erlang-mode
:enabled (lambda () (flycheck-rebar3-project-root))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to η-expand the flycheck-rebar3-project-root (you can drop the lambda).

flycheck.el Outdated
(file-name) ":" line ": " (message) line-end))
:modes erlang-mode
:enabled (lambda () (flycheck-rebar3-project-root))
:predicate (lambda () (flycheck-buffer-saved-p))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

(flycheck-ert-def-checker-test erlang-rebar3 erlang build
(flycheck-ert-should-syntax-check
"language/erlang/rebar3/_checkouts/dependency/src/dependency.erl" 'erlang-mode)
;; Ensure that the dependency file wasn't build as standalone
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildbuilt

logs
_build
.idea
rebar.lock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need all of these?

logs
_build
.idea
rebar.lock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both were generated by rebar3. I reduced them to things these integration tests actually create.

@cpitclaudel
Copy link
Member

I left a few comments — there are some typos, and I'm a bit confused about some parts of the code.

@tsloughter
Copy link

@joedevivo want me to take this over?

@joedevivo
Copy link
Contributor Author

I was going to take a look tomorrow morning. It seems like there's not much left. :D

@tsloughter
Copy link

Ok cool :), had just seen there wasn't much since 2016.

@joedevivo
Copy link
Contributor Author

@cpitclaudel I'm happy to maintain this still

;; rebar3 outputs ANSI terminal colors, which don't match up with
;; :error-patterns, so we strip those color codes from the output
;; here before passing it along to the default behavior. The
;; relevant disucssion can be found at
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disucssion → discussion

;; https://github.com/flycheck/flycheck/pull/1144
(require 'ansi-color)
(flycheck-parse-with-patterns
(and (fboundp 'ansi-color-filter-apply) (ansi-color-filter-apply output))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the idea of this check was to silence the byte-compiler — I'd rather use with-no-warnings, or add a comment about the condition.

flycheck.el Outdated
(if (file-exists-p (expand-file-name "rebar.config" dir-name))
dir-name nil))

(defun locate-rebar3-project-root (file-name &optional prev-file-name acc)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tsloughter Thanks, that's what I meant by looking for the topmost file.

(locate-rebar3-project-root
(directory-file-name current-dir)
file-name
(cons (contains-rebar-config current-dir) acc)))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would help with maintainability if this function was based on locate-dominating-file. Something like this, maybe? (untested):

(defun locate-topmost-dominating-file (file name)
  (let ((result nil)
        (further-up file))
    (while further-up
      (setq further-up (locate-dominating-file further-up name))
      (when further-up
        (setq result further-up)
        (setq further-up (file-name-directory (directory-file-name further-up)))))
    result))

@cpitclaudel cpitclaudel merged commit 9bf7337 into flycheck:master May 22, 2017
@cpitclaudel
Copy link
Member

Thanks a lot. Things look great now, and this PR's discussion thread is starting to look suspiciously long :) Welcome aboard, and thanks for this contribution! Sorry for the long reviewing process.

I left a few comments — it would be great if you could address them in a separate PR. Additionally, it would be nice to ask the rebar3 folks to update the checker to add a flag to disable color coding (or better, they could restrict color codes to TTYs).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants