Skip to content
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
4 changes: 2 additions & 2 deletions docs/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ the root pycache directory:
2. `$HOME/.cache` (non-Windows), the XDG default when `XDG_CACHE_HOME` is
unset, or `LOCALAPPDATA` (Windows).

If such a diretory cannot be found, or created, then `/dev/null` will be used,
which will effectively disable pyc caching.
If `/dev/null` (`NUL` on Windows) is specified, or if a directory cannot be
found or created, then pyc caching will be disabled.

:::{versionchanged} VERSION_NEXT_PATCH
Temporary directories (`TMP`, `TEMP`, `/tmp` and `C:\Temp`) are no longer used.
Expand Down
18 changes: 12 additions & 6 deletions python/private/python_repository.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def _get_pycache_root(rctx):
{type}`path | None` The path to the pycache root, or None if it couldn't
be created.
"""
res = rctx.getenv("RULES_PYTHON_PYCACHE_DIR")
if res and res.lower() in ("/dev/null", "nul"):
return None

os_name = repo_utils.get_platforms_os_name(rctx)
is_windows = os_name == "windows"

Expand All @@ -74,7 +78,6 @@ def _get_pycache_root(rctx):
hash("{}:{}".format(rctx.workspace_root, runtime_hash)),
)

res = rctx.getenv("RULES_PYTHON_PYCACHE_DIR")
if res:
return repo_utils.mkdir(rctx, rctx.path(res).get_child(suffix))

Expand All @@ -100,7 +103,7 @@ def _get_pycache_root(rctx):
return repo_utils.mkdir(rctx, path)

def _create_pycache_symlinks(rctx, logger):
"""Finds all directories with a .py file and creates __pycache__ symlinks.
"""Finds all directories with a .py file and creates __pycache__ entries.

Args:
rctx: {type}`repository_ctx` The repository rule's context object.
Expand All @@ -110,9 +113,6 @@ def _create_pycache_symlinks(rctx, logger):
logger.info(lambda: "pycache root: {}".format(pycache_root))
pycache_root_str = str(pycache_root) if pycache_root else None

os_name = repo_utils.get_platforms_os_name(rctx)
null_device = "NUL" if os_name == "windows" else "/dev/null"

queue = [rctx.path(".")]

# Starlark doesn't support recursion, use a loop with a queue.
Expand Down Expand Up @@ -146,7 +146,13 @@ def _create_pycache_symlinks(rctx, logger):
rctx.symlink(target_dir, pycache_dir)
else:
rctx.delete(pycache_dir)
rctx.symlink(null_device, pycache_dir)

# The intent is to disable pyc generation, which we can't
# entirely do directly. Symlinking to /dev/null makes it point
# to a character device, which can act weird when read or put
# into a zip. A regular file seems to make python skip local pyc
# generation, so use that.
rctx.file(pycache_dir, content = "", executable = False)

def _python_repository_impl(rctx):
if rctx.attr.distutils and rctx.attr.distutils_content:
Expand Down
8 changes: 8 additions & 0 deletions tests/integration/custom_commands_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import pathlib
import unittest

from tests.integration import runner
Expand All @@ -30,6 +31,7 @@ def test_run_build_python_zip_false(self):

# Regression test for https://github.com/bazel-contrib/rules_python/issues/4198
def test_runtime_files_exclude_pycache_symlinks(self):
output_base = pathlib.Path(self.run_bazel("info", "output_base").stdout.strip())
result = self.run_bazel(
"cquery",
"--repo_env=RULES_PYTHON_PYCACHE_DIR=/dev/null",
Expand All @@ -41,6 +43,12 @@ def test_runtime_files_exclude_pycache_symlinks(self):
pycache = [f for f in files if "__pycache__" in f]
self.assertEqual(pycache, [])

os_py = next(f for f in files if f.endswith("/os.py") or f.endswith("\\os.py"))
stdlib_pycache = output_base / pathlib.Path(os_py).parent / "__pycache__"
self.assertFalse(stdlib_pycache.is_symlink())
self.assertFalse(stdlib_pycache.is_dir())
self.assertTrue(stdlib_pycache.is_file())


if __name__ == "__main__":
# Enabling this makes the runner log subprocesses as the test goes along.
Expand Down
Loading