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

Fix coursier cache path logic for https://github.com/bazelbuild/rules_jvm_external/issues/417 #419

Merged
merged 1 commit into from
Jun 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 33 additions & 20 deletions coursier.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,20 @@ sh_binary(
def _is_verbose(repository_ctx):
return bool(repository_ctx.os.environ.get("RJE_VERBOSE"))

def _is_windows(os_name):
return os_name.find("windows") != -1
def _is_windows(repository_ctx):
return repository_ctx.os.name.find("windows") != -1

def _is_linux(os_name):
return os_name.find("linux") != -1
def _is_linux(repository_ctx):
return repository_ctx.os.name.find("linux") != -1

def _is_macos(os_name):
return os_name.find("mac") != -1
def _is_macos(repository_ctx):
return repository_ctx.os.name.find("mac") != -1

def _is_file(repository_ctx, path):
return repository_ctx.which("test") and repository_ctx.execute(["test", "-f", path]).return_code == 0

def _is_directory(repository_ctx, path):
return repository_ctx.which("test") and repository_ctx.execute(["test", "-d", path]).return_code == 0

# The representation of a Windows path when read from the parsed Coursier JSON
# is delimited by 4 back slashes. Replace them with 1 forward slash.
Expand All @@ -76,8 +82,7 @@ def _relativize_and_symlink_file(repository_ctx, absolute_path):
# We assume that coursier uses the default cache location
# TODO(jin): allow custom cache locations
absolute_path_parts = absolute_path.split(get_coursier_cache_or_default(
repository_ctx.os.environ,
repository_ctx.os.name,
repository_ctx,
repository_ctx.attr.use_unsafe_shared_cache or repository_ctx.attr.name.startswith("unpinned_"),
))
if len(absolute_path_parts) != 2:
Expand Down Expand Up @@ -126,7 +131,7 @@ def _windows_check(repository_ctx):
#
# On Windows, run msys once to bootstrap it
# https://github.com/bazelbuild/rules_jvm_external/issues/53
if (_is_windows(repository_ctx.os.name)):
if (_is_windows(repository_ctx)):
bash = repository_ctx.os.environ.get("BAZEL_SH")
if (bash == None):
fail("Please set the BAZEL_SH environment variable to the path of MSYS2 bash. " +
Expand Down Expand Up @@ -228,7 +233,7 @@ def get_home_netrc_contents(repository_ctx):
if "HOME" in repository_ctx.os.environ:
if not repository_ctx.os.name.startswith("windows"):
netrcfile = "%s/.netrc" % (repository_ctx.os.environ["HOME"],)
if repository_ctx.which("test") and repository_ctx.execute(["test", "-f", netrcfile]).return_code == 0:
if _is_file(repository_ctx, netrcfile):
return repository_ctx.read(netrcfile)
return ""

Expand Down Expand Up @@ -470,24 +475,33 @@ def _deduplicate_artifacts(dep_tree):
# Get the path to the cache directory containing Coursier-downloaded artifacts.
#
# This method is public for testing.
def get_coursier_cache_or_default(os_env, os_name, use_unsafe_shared_cache):
def get_coursier_cache_or_default(repository_ctx, use_unsafe_shared_cache):
# If we're not using the unsafe shared cache use 'external/<this repo>/v1/'.
# 'v1' is the current version of the Coursier cache.
if not use_unsafe_shared_cache:
return "v1"

os_env = repository_ctx.os.environ
coursier_cache_env_var = os_env.get("COURSIER_CACHE")
if coursier_cache_env_var:
# This is an absolute path.
return coursier_cache_env_var

# locations from https://get-coursier.io/docs/2.0.0-RC5-3/cache.html#default-location
if _is_windows(os_name):
return "%s/Coursier/cache/v1" % os_env.get("LOCALAPPDATA").replace("\\", "/")
elif _is_macos(os_name):
return "%s/Library/Caches/Coursier/v1" % os_env.get("HOME")
else:
return "%s/.cache/coursier/v1" % os_env.get("HOME")
# cache locations from https://get-coursier.io/docs/2.0.0-RC5-3/cache.html#default-location
# Use linux as the default cache directory
default_cache_dir = "%s/.cache/coursier/v1" % os_env.get("HOME")
if _is_windows(repository_ctx):
default_cache_dir = "%s/Coursier/cache/v1" % os_env.get("LOCALAPPDATA").replace("\\", "/")
elif _is_macos(repository_ctx):
default_cache_dir = "%s/Library/Caches/Coursier/v1" % os_env.get("HOME")

# Logic based on # https://github.com/coursier/coursier/blob/f48c1c6b01ac5b720e66e06cf93587b21d030e8c/modules/paths/src/main/java/coursier/paths/CoursierPaths.java#L60
if _is_directory(repository_ctx, default_cache_dir):
return default_cache_dir
elif _is_directory(repository_ctx, "%s/.coursier" % os_env.get("HOME")):
return "%s/.coursier/cache/v1" % os_env.get("HOME")

return default_cache_dir

def make_coursier_dep_tree(
repository_ctx,
Expand Down Expand Up @@ -552,8 +566,7 @@ def make_coursier_dep_tree(
environment = {}
if not use_unsafe_shared_cache and not repository_ctx.attr.name.startswith("unpinned_"):
coursier_cache_location = get_coursier_cache_or_default(
repository_ctx.os.environ,
repository_ctx.os.name,
repository_ctx,
use_unsafe_shared_cache,
)
cmd.extend(["--cache", coursier_cache_location]) # Download into $output_base/external/$maven_repo_name/v1
Expand Down
89 changes: 73 additions & 16 deletions tests/unit/coursier_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -363,62 +363,119 @@ def _mock_repo_path(path):
else:
return "/mockroot/" + path

def _mock_which(path):
return False

def _get_coursier_cache_or_default_disabled_test(ctx):
env = unittest.begin(ctx)
mock_environ = {
"COURSIER_CACHE": _mock_repo_path("/does/not/matter")
}
mock_repository_ctx = struct(
os = struct(
environ = {
"COURSIER_CACHE": _mock_repo_path("/does/not/matter")
},
name = "linux",
),
which = _mock_which
)
asserts.equals(
env,
"v1",
get_coursier_cache_or_default(mock_environ, "linux", False)
get_coursier_cache_or_default(mock_repository_ctx, False)
)
return unittest.end(env)

get_coursier_cache_or_default_disabled_test = add_test(_get_coursier_cache_or_default_disabled_test)

def _get_coursier_cache_or_default_enabled_with_default_location_linux_test(ctx):
env = unittest.begin(ctx)
mock_environ = {
"HOME": "/home/testuser"
}
mock_repository_ctx = struct(
os = struct(
environ = {
"HOME": "/home/testuser"
},
name = "linux",
),
which = _mock_which
)
asserts.equals(
env,
"/home/testuser/.cache/coursier/v1",
get_coursier_cache_or_default(mock_environ, "linux", True)
get_coursier_cache_or_default(mock_repository_ctx, True)
)
return unittest.end(env)

get_coursier_cache_or_default_enabled_with_default_location_linux_test = add_test(_get_coursier_cache_or_default_enabled_with_default_location_linux_test)

def _get_coursier_cache_or_default_enabled_with_default_location_mac_test(ctx):
env = unittest.begin(ctx)
mock_environ = {
"HOME": "/Users/testuser"
}
mock_repository_ctx = struct(
os = struct(
environ = {
"HOME": "/Users/testuser"
},
name = "mac",
),
which = _mock_which
)
asserts.equals(
env,
"/Users/testuser/Library/Caches/Coursier/v1",
get_coursier_cache_or_default(mock_environ, "mac", True)
get_coursier_cache_or_default(mock_repository_ctx, True)
)
return unittest.end(env)

get_coursier_cache_or_default_enabled_with_default_location_mac_test = add_test(_get_coursier_cache_or_default_enabled_with_default_location_mac_test)

def _get_coursier_cache_or_default_enabled_with_custom_location_test(ctx):
env = unittest.begin(ctx)
mock_environ = {
"COURSIER_CACHE": _mock_repo_path("/custom/location")
}
mock_repository_ctx = struct(
os = struct(
environ = {
"COURSIER_CACHE": _mock_repo_path("/custom/location")
},
name = "linux",
),
which = _mock_which
)
asserts.equals(
env,
"/custom/location",
get_coursier_cache_or_default(mock_environ, "linux", True)
get_coursier_cache_or_default(mock_repository_ctx, True)
)
return unittest.end(env)

get_coursier_cache_or_default_enabled_with_custom_location_test = add_test(_get_coursier_cache_or_default_enabled_with_custom_location_test)

def _mock_which_true(path):
return True

def _mock_execute(args):
if args[-1] == "/Users/testuser/Library/Caches/Coursier/v1":
return struct(return_code = 1)
else:
return struct(return_code = 0)

def _get_coursier_cache_or_default_enabled_with_home_dot_coursier_directory_test(ctx):
env = unittest.begin(ctx)
mock_repository_ctx = struct(
os = struct(
environ = {
"HOME": "/Users/testuser"
},
name = "mac",
),
which = _mock_which_true,
execute = _mock_execute,
)
asserts.equals(
env,
"/Users/testuser/.coursier/cache/v1",
get_coursier_cache_or_default(mock_repository_ctx, True)
)
return unittest.end(env)

get_coursier_cache_or_default_enabled_with_home_dot_coursier_directory_test = add_test(_get_coursier_cache_or_default_enabled_with_home_dot_coursier_directory_test)

def coursier_test_suite():
unittest.suite(
"coursier_tests",
Expand Down