') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); fix: correctly obtain relative path required for the venv created by `--bootstrap_impl=script` by chowder · Pull Request #2439 · bazel-contrib/rules_python · GitHub
Skip to content

fix: correctly obtain relative path required for the venv created by --bootstrap_impl=script - #2439

Merged
rickeylev merged 12 commits into
bazel-contrib:mainfrom
chowder:fix-bootstrap-venv-symlink
Nov 25, 2024
Merged

fix: correctly obtain relative path required for the venv created by --bootstrap_impl=script#2439
rickeylev merged 12 commits into
bazel-contrib:mainfrom
chowder:fix-bootstrap-venv-symlink

Conversation

@chowder

@chowderchowder commented Nov 23, 2024

Copy link
Copy Markdown
Contributor

Computing the relative path from the venv interpreter to the underlying interpreter was
incorrectly using the actual interpreter's directory depth, not the venv interpreter's
directory depth, when computing the distance from the venv interpreter to the runfiles root.
The net effect is the correct relative path would only be computed for binaries with
the same directory depth as the actual interpreter (e.g. 2).

This went undetected in CI because the tests for this logic just happen to have the
same directory depth as the actual interpreter used.

To fix, compute the relative path to the runfiles root using the venv interpreter
directory. Also added a test in a more nested directory to test this case.

Along the way:

  • Change relative path computation to compute a minimum relative path.
  • Fix the internals to pass a runfiles-root relative path, not main-repo relative path,
    for the actual interpreter, as intended.

Fixes#2169

@chowder
chowder marked this pull request as draft November 23, 2024 20:12
@ewianda

ewianda commented Nov 24, 2024

Copy link
Copy Markdown
Contributor

The following rules were tested and validated:

  • py_binary
  • py_test
  • py_console_script
  • [] rules_oci Python image

@chowderchowder changed the title fix: correctly count the escapes required for the venv created by --bootstrap_impl=scriptfix: correctly obtain relative path required for the venv created by --bootstrap_impl=scriptNov 24, 2024

@rickeylevrickeylev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ah, hah. I'm guessing the reason this worked in CI is the path depth of the test programs was the same as the path depth of the underlying interpreter? 😂

Thanks for the PR!

The relative path logic looks overly complicated, though? All it has to do is calculate how many up-escapes are needed to get from the {prefix}.venv/bin/python3 location to the runfiles root, then append the ../-stripped value of the actual interpreter to that.

I think the ../ prefixed part of e.g. runtime.interpreter.short_path (or any .short_path) is there in lieu of external/, and represents "go up one dir from the main repo" (because its referring to some external repo).

@chowder

chowder commented Nov 24, 2024

Copy link
Copy Markdown
ContributorAuthor

Yeah it's kinda complicated (don't like it) - I wasn't sure what were all the edge cases here, so writing it generically was the only way I knew how to do it.

Would something like this suffice?

venv_bin_dir=paths.dirname(interpreter.short_path)
ifvenv_bin_dir.startswith("../"):
escapes=venv_bin_dir.count("/") -1else:
escapes=venv_bin_dir.count("/") +1parent="/".join([".."] *escapes)
rel_path=parent+"/"+interpreter_actual_pathctx.actions.symlink(output=interpreter, target_path=rel_path)

(Wouldn't support a py_binary using a python binary checked into the main repo as a toolchain, unless we prepend the workspace name to interpreter_actual_path where it doesn't lead with ../)

Happy for you to replace this with whatever you see fit too. :)

@rickeylev
rickeylev marked this pull request as ready for review November 25, 2024 00:19
@rickeylev

Copy link
Copy Markdown
Collaborator

would something like this suffice

Yes, it should. I pushed a change that basically did that -- compute the relative path between two runfiles-root-relative paths instead of main-repo-relative paths. I kept the relative_path function since I like that it will compute a minimum relative-path.

I also pushed a test to reproduce the problem. It creates a test in a much more deeply nested directory than where the actual interpreter is. As well as some other cleanup.

@rickeylev

Copy link
Copy Markdown
Collaborator

I wasn't sure what were all the edge cases here

I think you got them all, so good job 🙂 . That short_path is a main-repo relative path, and gets ../ prepended for external things is the main edge case. The code was a bit confusing because it said it was passing runfiles-root-relative paths around, but it actually wasn't (interpreter_actual_path was the plain short_path value, which then got fixed up later), and the some later code was papering over that. I went and fixed that.

… update real examples to use runfiles-root relative paths
Comment threadpython/private/py_executable_bazel.bzl
Comment threadtests/bootstrap_impls/venv_relative_path_tests.bzl Outdated
@rickeylev

Copy link
Copy Markdown
Collaborator

The CI failure is due to bazel-contrib/bazel_features#82, so I'll force-merge past it.

@rickeylev

Copy link
Copy Markdown
Collaborator

Ah, actually, I don't think I can force-merge because I'm not an admin. I'll ask about getting admin back. Otherwise, we can just switch the "upcoming bazel" CI to 8rc2 instead of 8rc3

@chowder

Copy link
Copy Markdown
ContributorAuthor

@rickeylev Thanks for the changes. :)

@rickeylev
rickeylev merged commit 438b12e into bazel-contrib:mainNov 25, 2024
@ewianda

Copy link
Copy Markdown
Contributor

Apologies. Just noticed that rules_pkg is failing

 File "/home/ewianda/.cache/bazel/_bazel_ewianda/00aeeab5df0e41ab9e87aa07d33c6a73/sandbox/linux-sandbox/43/execroot/_main/bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/rules_pkg~/pkg/private/tar/build_tar.runfiles/_main/../rules_pkg~/pkg/private/tar/build_tar.py", line 486, in <module>
main()
File "/home/ewianda/.cache/bazel/_bazel_ewianda/00aeeab5df0e41ab9e87aa07d33c6a73/sandbox/linux-sandbox/43/execroot/_main/bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/rules_pkg~/pkg/private/tar/build_tar.runfiles/_main/../rules_pkg~/pkg/private/tar/build_tar.py", line 477, in main
output.add_manifest_entry(entry, file_attributes)
File "/home/ewianda/.cache/bazel/_bazel_ewianda/00aeeab5df0e41ab9e87aa07d33c6a73/sandbox/linux-sandbox/43/execroot/_main/bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/rules_pkg~/pkg/private/tar/build_tar.runfiles/_main/../rules_pkg~/pkg/private/tar/build_tar.py", line 342, in add_manifest_entry
self.add_file(entry.src, entry.dest, **attrs)
File "/home/ewianda/.cache/bazel/_bazel_ewianda/00aeeab5df0e41ab9e87aa07d33c6a73/sandbox/linux-sandbox/43/execroot/_main/bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/rules_pkg~/pkg/private/tar/build_tar.runfiles/_main/../rules_pkg~/pkg/private/tar/build_tar.py", line 111, in add_file
self.tarfile.add_file(
File "/home/ewianda/.cache/bazel/_bazel_ewianda/00aeeab5df0e41ab9e87aa07d33c6a73/sandbox/linux-sandbox/43/execroot/_main/bazel-out/k8-opt-exec-ST-d57f47055a04/bin/external/rules_pkg~/pkg/private/tar/build_tar.runfiles/rules_pkg~/pkg/private/tar/tar_writer.py", line 251, in add_file
with open(file_content, 'rb') as f:
^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'bazel-out/k8-fastbuild/bin/external/rules_pkg~/pkg/private/tar/_build_tar.venv/bin/python3'

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

plain invocation of python subprocess doesn't inherit sys.path for bootstrap_impl=script

4 participants

@chowder@ewianda@rickeylev@aignas