[build] resolve symlinks and build the wheel in py:local_dev#17789
[build] resolve symlinks and build the wheel in py:local_dev#17789titusfortner wants to merge 3 commits into
Conversation
PR Summary by QodoFix py:local_dev staging by building wheel outputs and dereferencing symlinks
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
11 rules 1.
|
70f3e69 to
ba77862
Compare
|
Code review by qodo was updated up to the latest commit ba77862 |
| if arguments[:all] == 'all' | ||
| dirs = Dir.children(bazel_bin) | ||
| files = [] | ||
| else | ||
| bidi_src = "#{bazel_bin}/common/bidi" | ||
| bidi_dest = "#{lib_path}/common/bidi" | ||
| if Dir.exist?(bidi_src) | ||
| FileUtils.mkdir_p(bidi_dest) | ||
| Dir.children(bidi_src).sort.each do |entry| | ||
| src = File.join(bidi_src, entry) | ||
| dest = File.join(bidi_dest, entry) | ||
| next unless File.file?(src) || File.symlink?(src) | ||
|
|
||
| resolved_src = File.symlink?(src) ? File.realpath(src) : src | ||
| FileUtils.rm_f(dest) | ||
| FileUtils.cp(resolved_src, dest) | ||
| end | ||
| end | ||
| dirs = %w[common/bidi common/devtools] | ||
| files = %w[ | ||
| remote/getAttribute.js remote/isDisplayed.js remote/findElements.js | ||
| common/mutation-listener.js common/bidi-mutation-listener.js | ||
| common/linux/selenium-manager common/macos/selenium-manager common/windows/selenium-manager.exe | ||
| firefox/webdriver_prefs.json | ||
| ] | ||
| end | ||
|
|
||
| %w[common/devtools common/linux common/macos common/windows].each do |dir| | ||
| src = "#{bazel_bin}/#{dir}" | ||
| dest = "#{lib_path}/#{dir}" | ||
| next unless Dir.exist?(src) | ||
| dirs.each do |dir| | ||
| src_dir = "#{bazel_bin}/#{dir}" | ||
| dest_dir = "#{lib_path}/#{dir}" | ||
|
|
||
| FileUtils.rm_rf(dest) | ||
| FileUtils.cp_r(src, dest) | ||
| end | ||
| FileUtils.rm_rf(dest_dir) | ||
| # Restore any git tracked files in the directory we just deleted | ||
| SeleniumRake.git.checkout_file('HEAD', dest_dir) unless SeleniumRake.git.ls_files(dest_dir).empty? | ||
|
|
||
| %w[getAttribute.js isDisplayed.js findElements.js].each do |atom| | ||
| dest = "#{lib_path}/remote/#{atom}" | ||
| FileUtils.rm_f(dest) | ||
| FileUtils.cp("#{bazel_bin}/remote/#{atom}", dest) | ||
| # Copy each file individually to resolve Bazel's cache symlinks | ||
| Dir.glob(File.join(src_dir, '**', '*')).each do |src| | ||
| next unless File.file?(src) | ||
|
|
||
| dest = File.join(dest_dir, src.delete_prefix("#{src_dir}/")) | ||
| FileUtils.mkdir_p(File.dirname(dest)) | ||
| FileUtils.cp(File.realpath(src), dest) | ||
| end | ||
| end | ||
|
|
||
| files.each do |file| | ||
| dest = "#{lib_path}/#{file}" | ||
| FileUtils.mkdir_p(File.dirname(dest)) | ||
| FileUtils.rm_f(dest) | ||
| FileUtils.cp(File.realpath("#{bazel_bin}/#{file}"), dest) | ||
| end |
There was a problem hiding this comment.
1. Local edits can be lost 🐞 Bug ☼ Reliability
py:local_dev deletes destination paths and (when tracked files exist) restores them from HEAD via checkout_file without checking for local modifications, so running it can silently discard in-progress work. In all mode, this applies to generated output directories like common/ and remote/, which are tracked source trees in py/selenium/webdriver/.
Agent Prompt
## Issue description
`py:local_dev` removes and overwrites paths under `py/selenium/webdriver` (and in `all` mode, potentially large tracked source directories) without verifying those paths have no uncommitted or untracked changes. This can result in silent loss of developer changes.
## Issue Context
The task now uses `rm_rf`/`rm_f` plus `SeleniumRake.git.checkout_file('HEAD', ...)` and `cp` to repopulate from `bazel-bin`. This should refuse to run when any destination path it will touch is dirty.
## Fix Focus Areas
- Add a preflight “dirty path” guard that checks **both tracked modifications and untracked files** for every destination path that will be removed/overwritten; abort with a clear message listing offending paths.
- Prefer using the existing `git` gem instance (`SeleniumRake.git`) to query status, rather than shelling out.
### Suggested implementation outline
1. Build `dest_paths`:
- For dirs: `dest_dir = "#{lib_path}/#{dir}"`
- For files: `dest = "#{lib_path}/#{file}"`
2. Compute dirtiness:
- Tracked changes under path
- Untracked files under path
3. `abort(...)` before performing any `rm_rf`/`rm_f`.
## Fix Focus Areas (code pointers)
- rake_tasks/python.rake[68-111]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
There was a problem hiding this comment.
First with these updates, we probably don't need to use the all argument right now. It's kind of an escape hatch for when the task is out of date.
Second, this is only run by committers manually so think it's reasonable to expect them to only do this when they're working tree is in a good state without having to warn and abort.
There was a problem hiding this comment.
I'm going to ask the primary users of this task what they want to see
|
Code review by qodo was updated up to the latest commit 6603661 |
🔗 Related Issues
💥 What does this PR do?
Fixes
py:local_devso it stages real generated content into the source tree instead of leaving broken links behind.It built
//py:selenium, apy_librarywithsrcs = [], which materializes nothing intobazel-bin— the task then copied whatever residue happened to be there. It now builds//py:selenium-wheel, whose packaging action forces the generated sources onto disk.It also copied with
cp_r, which preserves the symlinksbazel-binleaves into the Bazel cache — including the threeselenium-managerbinaries. Abazel cleanturned those into dangling links that failed at runtime, looking like a Selenium bug. The task now resolves every symlink to real content.🔧 Implementation Notes
The copy is now a single loop over the generated directories: each is cleared, repopulated from
bazel-bin(resolving symlinks), and then its git-tracked files are restored — the generated paths are all git-ignored, so the tracked files in those directories are exactly the hand-written ones that share them. It refuses to run if any of those directories have uncommitted changes, rather than silently discarding them.allruns the same loop over every generated directory instead of a separate bulk copy.🤖 AI assistance
🔄 Types of changes