-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Experimental
ruff server
now uses local ruff
binaries when availa…
…ble (#443) ## Summary When `experimentalServer` is enabled, the Ruff binary path will be determined in the following order: 1. **`ruff.path`** - if this is set, we take the first path in the list and use that as the executable path. 2. **`sysconfig.get_path("scripts") / RUFF_EXE`** - `RUFF_EXE` is `"ruff.exe"` on windows and `"ruff"` otherwise. 3. **`shutil.which("ruff")`** 4. The bundled binary path, **`./bundled/libs/bin/ruff`**, is used if none of the prior options are available. Before running the binary, we also check to make sure that it's running a compatible version. At the moment, any version after or including `0.3.3` is supported (except for `0.3.4`, since that release had a major bug in the server that broke editor integration). Since `0.3.3` is a rather bare-bones implementation, this minimum supported version will increase as the extension stabilizes. ## Test Plan 1. Run `ruff --version` in your shell. If it's not `ruff 0.3.5` or later, install/upgrade `ruff` and run `ruff --version` again to confirm that the ruff executable in your `PATH` is now `>=0.3.5`. 2. Begin debugging the extension. You should see the following log somewhere in the output: `Configuration file watcher successfully registered`. This should be a confirmation that you're running `ruff >=0.3.5` instead of the embedded `ruff 0.3.3`. 3. Add an entry to `ruff.path` in the extension settings, and pass in a ruff binary not in your `PATH`. A good way to check that you are in fact using this unique binary is by passing in the path to a local debug build after adding an additional log statement in a function like `Server::new`. If this log statement appears in the output, you know that you're using the custom executable provided in `ruff.path`. 4. Now, uninstall the ruff executable that was in your `PATH`. Confirm that no executable exists in your path by running `ruff --version` in your shell - you should get your shell's variant of the `command not found: ruff` error. 5. At this point, the extension should still be using the custom executable you added to `ruff.path`. Now, remove that path so that `ruff.path` is an empty list. The extension should now be using the bundled `v0.3.3` binary (a quick way to check this is making sure no `Configuration file watcher successfully registered` message appears, though you could also confirm this by seeing if the diagnostics show up highlighted in red instead of yellow).
- Loading branch information
1 parent
74c65cb
commit a64505d
Showing
7 changed files
with
168 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import os | ||
import shutil | ||
import site | ||
import subprocess | ||
import sys | ||
import sysconfig | ||
from pathlib import Path | ||
|
||
RUFF_EXE = "ruff.exe" if sys.platform == "win32" else "ruff" | ||
|
||
BUNDLE_DIR = Path(__file__).parent.parent | ||
|
||
|
||
def update_sys_path(path_to_add: str) -> None: | ||
"""Add given path to `sys.path`.""" | ||
if os.path.isdir(path_to_add): | ||
# The `site` module adds the directory at the end, if not yet present; we want | ||
# it to be at the beginning, so that it takes precedence over any other | ||
# installed versions. | ||
sys.path.insert(0, path_to_add) | ||
|
||
# Allow development versions of libraries to be imported. | ||
site.addsitedir(path_to_add) | ||
|
||
|
||
# This is separate from the 'main' entrypoint because we need | ||
# to update the system path _before_ importing `pacakging` | ||
if __name__ == "__main__": | ||
# Ensure that we can import bundled libraries like `packaging` | ||
update_sys_path(os.fspath(BUNDLE_DIR / "libs")) | ||
|
||
|
||
from packaging.specifiers import SpecifierSet | ||
from packaging.version import Version | ||
|
||
# This is subject to change in the future | ||
RUFF_VERSION_REQUIREMENT = SpecifierSet(">=0.3.5") | ||
|
||
|
||
def executable_version(executable: str) -> Version: | ||
"""Return the version of the executable at the given path.""" | ||
output = subprocess.check_output([executable, "--version"]).decode().strip() | ||
version = output.replace("ruff ", "") | ||
return Version(version) | ||
|
||
|
||
def check_compatibility( | ||
executable: str, | ||
requirement: SpecifierSet, | ||
) -> None: | ||
"""Check the executable for compatibility against various version specifiers.""" | ||
version = executable_version(executable) | ||
if not requirement.contains(version, prereleases=True): | ||
message = f"Ruff {requirement} required, but found {version} at {executable}" | ||
raise RuntimeError(message) | ||
|
||
|
||
def find_ruff_bin(fallback: Path) -> Path: | ||
"""Return the ruff binary path.""" | ||
path = Path(sysconfig.get_path("scripts")) / RUFF_EXE | ||
if path.is_file(): | ||
return path | ||
|
||
if sys.version_info >= (3, 10): | ||
user_scheme = sysconfig.get_preferred_scheme("user") | ||
elif os.name == "nt": | ||
user_scheme = "nt_user" | ||
elif sys.platform == "darwin" and sys._framework: | ||
user_scheme = "osx_framework_user" | ||
else: | ||
user_scheme = "posix_user" | ||
|
||
path = Path(sysconfig.get_path("scripts", scheme=user_scheme)) / RUFF_EXE | ||
if path.is_file(): | ||
return path | ||
|
||
path = shutil.which("ruff") | ||
if path: | ||
return path | ||
|
||
return fallback | ||
|
||
|
||
if __name__ == "__main__": | ||
ruff = os.fsdecode( | ||
find_ruff_bin( | ||
Path(BUNDLE_DIR / "libs" / "bin" / RUFF_EXE), | ||
), | ||
) | ||
check_compatibility(ruff, RUFF_VERSION_REQUIREMENT) | ||
completed_process = subprocess.run([ruff, *sys.argv[1:]], check=False) | ||
sys.exit(completed_process.returncode) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ authors = [{ name = "Charlie Marsh", email = "[email protected]" }] | |
maintainers = [{ name = "Charlie Marsh", email = "[email protected]" }] | ||
requires-python = ">=3.7" | ||
license = "MIT" | ||
dependencies = ["packaging>=23.1", "ruff-lsp==0.0.53", "ruff==0.3.3"] | ||
dependencies = ["packaging>=23.1", "ruff-lsp==0.0.53", "ruff==0.3.6"] | ||
|
||
[project.optional-dependencies] | ||
dev = ["mypy==1.2.0", "python-lsp-jsonrpc==1.0.0"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters