From d787050fa8a82eec26962055829af1f33bd70bbf Mon Sep 17 00:00:00 2001 From: Michael Pardo Date: Mon, 10 Jul 2017 18:03:36 -0400 Subject: [PATCH] Kotlin and general Gradle support. (#745) --- ale_linters/kotlin/kotlinc.vim | 21 ++++++-- autoload/ale/gradle.vim | 54 +++++++++++++++++++ autoload/ale/gradle/init.gradle | 23 ++++++++ .../build-gradle-project/build.gradle | 0 .../src/main/kotlin/dummy.kt | 0 test/gradle-test-files/gradle | 0 .../src/main/kotlin/dummy.kt | 0 .../settings-gradle-project/settings.gradle | 0 .../src/main/kotlin/dummy.kt | 0 .../unwrapped-project/build.gradle | 0 .../unwrapped-project/settings.gradle | 0 .../src/main/kotlin/dummy.kt | 0 .../wrapped-project/build.gradle | 0 .../gradle-test-files/wrapped-project/gradlew | 0 .../wrapped-project/settings.gradle | 0 .../wrapped-project/src/main/kotlin/dummy.kt | 0 .../test_gradle_build_classpath_command.vader | 42 +++++++++++++++ test/test_gradle_find_executable.vader | 31 +++++++++++ test/test_gradle_find_project_root.vader | 35 ++++++++++++ 19 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 autoload/ale/gradle.vim create mode 100644 autoload/ale/gradle/init.gradle create mode 100644 test/gradle-test-files/build-gradle-project/build.gradle create mode 100644 test/gradle-test-files/build-gradle-project/src/main/kotlin/dummy.kt create mode 100755 test/gradle-test-files/gradle create mode 100644 test/gradle-test-files/non-gradle-project/src/main/kotlin/dummy.kt create mode 100644 test/gradle-test-files/settings-gradle-project/settings.gradle create mode 100644 test/gradle-test-files/settings-gradle-project/src/main/kotlin/dummy.kt create mode 100644 test/gradle-test-files/unwrapped-project/build.gradle create mode 100644 test/gradle-test-files/unwrapped-project/settings.gradle create mode 100644 test/gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt create mode 100644 test/gradle-test-files/wrapped-project/build.gradle create mode 100644 test/gradle-test-files/wrapped-project/gradlew create mode 100644 test/gradle-test-files/wrapped-project/settings.gradle create mode 100644 test/gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt create mode 100644 test/test_gradle_build_classpath_command.vader create mode 100644 test/test_gradle_find_executable.vader create mode 100644 test/test_gradle_find_project_root.vader diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim index 525202cf..ebaf4456 100644 --- a/ale_linters/kotlin/kotlinc.vim +++ b/ale_linters/kotlin/kotlinc.vim @@ -12,17 +12,21 @@ let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_fi let s:classpath_sep = has('unix') ? ':' : ';' function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort - " exec maven only if classpath is not set + " exec maven/gradle only if classpath is not set if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# '' return '' else let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') - if !empty(l:pom_path) && executable('mvn') return ale#path#CdString(fnamemodify(l:pom_path, ':h')) \ . 'mvn dependency:build-classpath' endif + let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer) + if !empty(l:classpath_command) + return l:classpath_command + endif + return '' endif endfunction @@ -69,7 +73,7 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') !=# '' let l:kotlinc_opts .= ' -cp ' . ale#Var(a:buffer, 'kotlin_kotlinc_classpath') else - " get classpath from maven + " get classpath from maven/gradle let l:kotlinc_opts .= s:BuildClassPathOption(a:buffer, a:import_paths) endif @@ -78,7 +82,15 @@ function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort let l:fname .= expand(ale#Var(a:buffer, 'kotlin_kotlinc_sourcepath'), 1) . ' ' else " Find the src directory for files in this project. - let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java') + + let l:project_root = ale#gradle#FindProjectRoot(a:buffer) + if !empty(l:project_root) + let l:src_dir = l:project_root + else + let l:src_dir = ale#path#FindNearestDirectory(a:buffer, 'src/main/java') + \ . ' ' . ale#path#FindNearestDirectory(a:buffer, 'src/main/kotlin') + endif + let l:fname .= expand(l:src_dir, 1) . ' ' endif let l:fname .= ale#Escape(expand('#' . a:buffer . ':p')) @@ -155,3 +167,4 @@ call ale#linter#Define('kotlin', { \ 'callback': 'ale_linters#kotlin#kotlinc#Handle', \ 'lint_file': 1, \}) + diff --git a/autoload/ale/gradle.vim b/autoload/ale/gradle.vim new file mode 100644 index 00000000..89b56a82 --- /dev/null +++ b/autoload/ale/gradle.vim @@ -0,0 +1,54 @@ +" Author: Michael Pardo +" Description: Functions for working with Gradle projects. + +let s:script_path = fnamemodify(resolve(expand(':p')), ':h') + +" Given a buffer number, find a Gradle project root. +function! ale#gradle#FindProjectRoot(buffer) abort + let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') + if !empty(l:gradlew_path) + return fnamemodify(l:gradlew_path, ':h') + endif + + let l:settings_path = ale#path#FindNearestFile(a:buffer, 'settings.gradle') + if !empty(l:settings_path) + return fnamemodify(l:settings_path, ':h') + endif + + let l:build_path = ale#path#FindNearestFile(a:buffer, 'build.gradle') + if !empty(l:build_path) + return fnamemodify(l:build_path, ':h') + endif + + return '' +endfunction + +" Given a buffer number, find the path to the executable. +" First search on the path for 'gradlew', if nothing is found, try the global +" command. Returns an empty string if cannot find the executable. +function! ale#gradle#FindExecutable(buffer) abort + let l:gradlew_path = ale#path#FindNearestFile(a:buffer, 'gradlew') + if !empty(l:gradlew_path) + return l:gradlew_path + endif + + if executable('gradle') + return 'gradle' + endif + + return '' +endfunction + +" Given a buffer number, build a command to print the classpath of the root +" project. Returns an empty string if cannot build the command. +function! ale#gradle#BuildClasspathCommand(buffer) abort + let l:executable = ale#gradle#FindExecutable(a:buffer) + let l:project_root = ale#gradle#FindProjectRoot(a:buffer) + + if !empty(l:executable) && !empty(l:project_root) + return ale#path#CdString(l:project_root) + \ . l:executable . ' -I ' . s:script_path . '/gradle/init.gradle -q printClasspath' + endif + + return '' +endfunction diff --git a/autoload/ale/gradle/init.gradle b/autoload/ale/gradle/init.gradle new file mode 100644 index 00000000..fb1db9ee --- /dev/null +++ b/autoload/ale/gradle/init.gradle @@ -0,0 +1,23 @@ +class ClasspathPlugin implements Plugin { + void apply(Project project) { + project.task('printClasspath') { + doLast { + project + .rootProject + .allprojects + .configurations + .flatten() + .findAll { it.name.endsWith('Classpath') } + .collect { it.resolve() } + .flatten() + .unique() + .findAll { it.exists() } + .each { println it } + } + } + } +} + +rootProject { + apply plugin: ClasspathPlugin +} diff --git a/test/gradle-test-files/build-gradle-project/build.gradle b/test/gradle-test-files/build-gradle-project/build.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/build-gradle-project/src/main/kotlin/dummy.kt b/test/gradle-test-files/build-gradle-project/src/main/kotlin/dummy.kt new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/gradle b/test/gradle-test-files/gradle new file mode 100755 index 00000000..e69de29b diff --git a/test/gradle-test-files/non-gradle-project/src/main/kotlin/dummy.kt b/test/gradle-test-files/non-gradle-project/src/main/kotlin/dummy.kt new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/settings-gradle-project/settings.gradle b/test/gradle-test-files/settings-gradle-project/settings.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/settings-gradle-project/src/main/kotlin/dummy.kt b/test/gradle-test-files/settings-gradle-project/src/main/kotlin/dummy.kt new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/unwrapped-project/build.gradle b/test/gradle-test-files/unwrapped-project/build.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/unwrapped-project/settings.gradle b/test/gradle-test-files/unwrapped-project/settings.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt b/test/gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/wrapped-project/build.gradle b/test/gradle-test-files/wrapped-project/build.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/wrapped-project/gradlew b/test/gradle-test-files/wrapped-project/gradlew new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/wrapped-project/settings.gradle b/test/gradle-test-files/wrapped-project/settings.gradle new file mode 100644 index 00000000..e69de29b diff --git a/test/gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt b/test/gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt new file mode 100644 index 00000000..e69de29b diff --git a/test/test_gradle_build_classpath_command.vader b/test/test_gradle_build_classpath_command.vader new file mode 100644 index 00000000..84135268 --- /dev/null +++ b/test/test_gradle_build_classpath_command.vader @@ -0,0 +1,42 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + runtime ale_linters/kotlin/kotlinc.vim + let g:ale_gradle_path = $PATH + +After: + call ale#test#RestoreDirectory() + call ale#linter#Reset() + let $PATH = g:ale_gradle_path + +Execute(Should return 'gradlew' command if project includes gradle wapper): + call ale#test#SetFilename('gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt') + + let g:project_root = '/testplugin/test/gradle-test-files/wrapped-project' + let g:gradle_executable = '/testplugin/test/gradle-test-files/wrapped-project/gradlew' + let g:gradle_init_path = '/testplugin/autoload/ale/gradle/init.gradle' + let g:gradle_options = '-I ' . g:gradle_init_path . ' -q printClasspath' + + + AssertEqual + \ "cd '" . g:project_root . "' && " . g:gradle_executable . " " . g:gradle_options, + \ ale#gradle#BuildClasspathCommand(bufnr('')) + +Execute(Should return 'gradle' command if project does not include gradle wapper): + call ale#test#SetFilename('gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt') + let $PATH .= ':' . g:dir . '/gradle-test-files' + + let g:project_root = '/testplugin/test/gradle-test-files/unwrapped-project' + let g:gradle_executable = 'gradle' + let g:gradle_init_path = '/testplugin/autoload/ale/gradle/init.gradle' + let g:gradle_options = '-I ' . g:gradle_init_path . ' -q printClasspath' + + AssertEqual + \ "cd '" . g:project_root . "' && " . g:gradle_executable . " " . g:gradle_options, + \ ale#gradle#BuildClasspathCommand(bufnr('')) + +Execute(Should return empty string if gradle cannot be executed): + call ale#test#SetFilename('gradle-test-files/non-gradle-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ '', + \ ale#gradle#BuildClasspathCommand(bufnr('')) diff --git a/test/test_gradle_find_executable.vader b/test/test_gradle_find_executable.vader new file mode 100644 index 00000000..2ae2b464 --- /dev/null +++ b/test/test_gradle_find_executable.vader @@ -0,0 +1,31 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + runtime ale_linters/kotlin/kotlinc.vim + let g:ale_gradle_path = $PATH + +After: + call ale#test#RestoreDirectory() + call ale#linter#Reset() + let $PATH = g:ale_gradle_path + +Execute(Should return 'gradlew' if found in parent directory): + call ale#test#SetFilename('gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ g:dir . '/gradle-test-files/wrapped-project/gradlew', + \ ale#gradle#FindExecutable(bufnr('')) + +Execute(Should return 'gradle' if 'gradlew' not found in parent directory): + call ale#test#SetFilename('gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt') + let $PATH .= ':' . g:dir . '/gradle-test-files' + + AssertEqual + \ 'gradle', + \ ale#gradle#FindExecutable(bufnr('')) + +Execute(Should return empty string if 'gradlew' not in parent directory and gradle not in path): + call ale#test#SetFilename('gradle-test-files/unwrapped-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ '', + \ ale#gradle#FindExecutable(bufnr('')) diff --git a/test/test_gradle_find_project_root.vader b/test/test_gradle_find_project_root.vader new file mode 100644 index 00000000..bd1b8d7d --- /dev/null +++ b/test/test_gradle_find_project_root.vader @@ -0,0 +1,35 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + runtime ale_linters/kotlin/kotlinc.vim + +After: + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(Should return directory for 'gradlew' if found in parent directory): + call ale#test#SetFilename('gradle-test-files/wrapped-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ g:dir . '/gradle-test-files/wrapped-project', + \ ale#gradle#FindProjectRoot(bufnr('')) + +Execute(Should return directory for 'settings.gradle' if found in parent directory): + call ale#test#SetFilename('gradle-test-files/settings-gradle-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ g:dir . '/gradle-test-files/settings-gradle-project', + \ ale#gradle#FindProjectRoot(bufnr('')) + +Execute(Should return directory for 'build.gradle' if found in parent directory): + call ale#test#SetFilename('gradle-test-files/build-gradle-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ g:dir . '/gradle-test-files/build-gradle-project', + \ ale#gradle#FindProjectRoot(bufnr('')) + +Execute(Should return empty string if gradle files are not found in parent directory): + call ale#test#SetFilename('gradle-test-files/non-gradle-project/src/main/kotlin/dummy.kt') + + AssertEqual + \ '', + \ ale#gradle#FindProjectRoot(bufnr(''))