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

AdjacentTempDirectory should fail on unwritable directory #6215

Merged
merged 5 commits into from
Feb 8, 2019

Conversation

zooba
Copy link
Contributor

@zooba zooba commented Jan 28, 2019

Fixes #6169
Based on #6225

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

Ping @cjerdonek - are you able to suggest how best to make the temp directory unwritable? Or another way to test that scenario? I'm stuck (more precisely, all my ideas would be Windows specific ;) )

@dstufft
Copy link
Member

dstufft commented Jan 28, 2019

Can you monkeypatch os.makedir?

@cjerdonek
Copy link
Member

@zooba, @dstufft's suggestion sounds good. I was waiting myself to see how you would test that when you made your original comment. :)

@pradyunsg
Copy link
Member

Directly linking to #6169 for a better cross-reference.

@pradyunsg pradyunsg changed the title Fixes #6169: AdjacentTempDirectory should fail on unwritable directory AdjacentTempDirectory should fail on unwritable directory Jan 28, 2019
@YannickJadoul
Copy link
Member

Minor remark/question; sorry if this is not relevant: isn't it weird that pip wants to create a folder in the parent folder of site-packages, so outside of site-packages? Is that folder (i.e., something like .../lib/pythonX.Y) supposed to be writable by pip?

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

@YannickJadoul It shouldn't be trying to create it there - what scenario is causing this?

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

Ah, found it (uninstalling scripts). The fallback needs to be better when this approach fails, but the infrastructure is there - more work incoming!

@pradyunsg pradyunsg added this to the 19.0 milestone Jan 28, 2019
@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

My fallback should also handle the previous problem of hitting the maximum path length limit, though it may create more temporary folders (in most cases I assume two: bin/Scripts and any files installed directly into site-packages)

@YannickJadoul
Copy link
Member

YannickJadoul commented Jan 28, 2019

@zooba I don't think it's just the scripts. Those result in maybe an even bigger problem (since a new folder in the parent folder of bin will be created), but what I was mentioning was linked to removing the .dist-info folder.

Example (using the ancient version of setuptools==18.2 as example because this is what is happining in the cibuildwheel repository, and I know it reproduces what I want to show):

yannick@Athenai:~$ source TEMPENV/bin/activate
(TEMPENV) yannick@Athenai:~$ ls TEMPENV/
bin  include  lib  pip-selfcheck.json
(TEMPENV) yannick@Athenai:~$ pip install setuptools==18.2
Collecting setuptools==18.2
  Using cached https://files.pythonhosted.org/packages/c3/f6/b3224fb53fd3ddebdcc2aafb8f2d3a044a66446c9f17f4e5a24ca03b781b/setuptools-18.2-py2.py3-none-any.whl
Installing collected packages: setuptools
  Found existing installation: setuptools 40.7.0
    Uninstalling setuptools-40.7.0:
      Successfully uninstalled setuptools-40.7.0
Successfully installed setuptools-18.2
(TEMPENV) yannick@Athenai:~$ chmod -w TEMPENV/lib/python3.6/
(TEMPENV) yannick@Athenai:~$ pip install --upgrade setuptools
Collecting setuptools
  Using cached https://files.pythonhosted.org/packages/5b/ac/90c7617bfc48ae1265d2c0cc46aeb0a0d482e00577008d21b64efe9a2006/setuptools-40.7.0-py2.py3-none-any.whl
Installing collected packages: setuptools
  Found existing installation: setuptools 18.2
    Uninstalling setuptools-18.2:
^COperation cancelled by user
(TEMPENV) yannick@Athenai:~$ ls TEMPENV/
bin  -in  include  lib  pip-selfcheck.json
(TEMPENV) yannick@Athenai:~$ ls TEMPENV/-in/
easy_install  easy_install-3.6
(TEMPENV) yannick@Athenai:~$ chmod +w TEMPENV/lib/python3.6/
(TEMPENV) yannick@Athenai:~$ pip install --upgrade -vvv setuptools

[... lots and lots of PyPI links ...]

Installing collected packages: setuptools
  Found existing installation: setuptools 18.2
    Uninstalling setuptools-18.2:
      Created temporary directory: /home/yannick/TEMPENV/~in
      Removing file or directory /home/yannick/TEMPENV/bin/easy_install
      Removing file or directory /home/yannick/TEMPENV/bin/easy_install-3.6
      Created temporary directory: /home/yannick/TEMPENV/lib/python3.6/site-packages/~_pycache__
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/__pycache__/
      Created temporary directory: /home/yannick/TEMPENV/lib/python3.6/site-packages/~markerlib
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/_markerlib/
      Created temporary directory: /home/yannick/TEMPENV/lib/python3.6/-ite-packages
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/easy_install.py
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/pkg_resources/
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/setuptools-18.2.dist-info/
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/setuptools/
      Successfully uninstalled setuptools-18.2

  changing mode of /home/yannick/TEMPENV/bin/easy_install to 755
  changing mode of /home/yannick/TEMPENV/bin/easy_install-3.6 to 755
Successfully installed setuptools-40.7.0
Cleaning up...
Removed build tracker '/tmp/pip-req-tracker-e2lpcqcx'

EDIT: That's a lot of output, but notice the line saying Created temporary directory: /home/yannick/TEMPENV/lib/python3.6/-ite-packages

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

@YannickJadoul Yep, that's the one that I fixed - it's doing that file because of the easy_install.py script, not the dist-info.

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

Okay, my fix doesn't account for ordering of the paths, so it's nearly back to where it was before :( Trying again

@YannickJadoul
Copy link
Member

@zooba Are you sure? I'm pretty sure this package does not contain scripts, and I still get this -ite-packages sibling directory:

Installing collected packages: praat-parselmouth
  Found existing installation: praat-parselmouth 0.2.0
    Uninstalling praat-parselmouth-0.2.0:
      Created temporary directory: /home/yannick/TEMPENV/lib/python3.6/-ite-packages
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/parselmouth.cpython-36m-x86_64-linux-gnu.so
      Removing file or directory /home/yannick/TEMPENV/lib/python3.6/site-packages/praat_parselmouth-0.2.0.dist-info/
      Successfully uninstalled praat-parselmouth-0.2.0

Successfully installed praat-parselmouth-0.3.2

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

The -ite-packages folder is because they have a file in site-packages - a .so in your new case.

The -in folder was from files in bin.

If there's another directory where files may be installed but the directory is not wholly owned by the package, that could also trigger the same thing.

I have a bit more of a fix coming to remove the ordering issues from stash directory creation, but it certainly resolves this issue.

@YannickJadoul
Copy link
Member

@zooba OK, yes, fair enough; my bad. Thanks!

@cjerdonek
Copy link
Member

@zooba Are you fixing two issues now?

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

@cjerdonek The second one was introduced by the fix for the first. Shuffling directories around is considerably more complex once the fallback mechanism is introduced.

@zooba
Copy link
Contributor Author

zooba commented Jan 28, 2019

The CI failures are (going to be) due to some tests failing and timing out, but the logging isn't showing me anything useful. I'm trying to reproduce locally.

@benoit-pierre
Copy link
Member

It's also holding up the queue on AppVeyor... I'll go ahead and cancel the build.

@zooba
Copy link
Contributor Author

zooba commented Jan 29, 2019

The current problem is during one of the rollback tests - it's creating an extra subdirectory for the .dist-info and moving the original .dist-info into it.

Normally this means that the "move" call is recognizing that the source is a file and the destination is a directory and creating the directory, but that isn't the case here (they're both directories). I'll keep looking tomorrow.

@cjerdonek
Copy link
Member

Is there any way to separate the trickier stashing logic from the larger UninstallPathSet class to make the logic simpler to understand and test?

@zooba
Copy link
Contributor Author

zooba commented Jan 29, 2019

@cjerdonek I hope I can make it easier to follow, but ultimately, isn't it the whole point of the UninstallPathSet? The functionality won't be used elsewhere, and it requires creating real directories or else it won't fail to create them (without some serious monkeypatching…).

But I'll try factoring it into its own class and then see whether it's worth it.

@cjerdonek
Copy link
Member

It was just a thought. I was mainly just thinking of the _stash() method and the methods it accesses (and _save_dirs attribute). The change you're making happens to be confined (largely) to that anyways.

@zooba
Copy link
Contributor Author

zooba commented Jan 29, 2019

@cjerdonek I like the idea, so I started it (posted my WIP, which probably won't pass, but will let you see where I'm heading). But now I'm going down a venv rabbithole instead 😖 So I'll get back to this as soon as I fix up the stuff I broke in CPython...

Copy link
Member

@cjerdonek cjerdonek left a comment

Choose a reason for hiding this comment

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

I added a couple minor comments.

Also, re: splitting out, I was only thinking _stash() and _save_dirs, but this looks good, too!

src/pip/_internal/req/req_uninstall.py Show resolved Hide resolved
src/pip/_internal/req/req_uninstall.py Outdated Show resolved Hide resolved
@cjerdonek cjerdonek added C: uninstall The logic for uninstallation of packages type: bugfix labels Jan 30, 2019
Copy link
Member

@pradyunsg pradyunsg left a comment

Choose a reason for hiding this comment

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

Seems OK to me but I'm not sure I'm familiar enough with this to "approve".

.gitignore Show resolved Hide resolved
@pradyunsg
Copy link
Member

@zooba Could you please update this PR?

@BrownTruck
Copy link
Contributor

Hello!

I am an automated bot and I have noticed that this pull request is not currently able to be merged. If you are able to either merge the master branch into this pull request or rebase this pull request against master then it will be eligible for code review and hopefully merging!

@BrownTruck BrownTruck added the needs rebase or merge PR has conflicts with current master label Feb 3, 2019
@pypa-bot pypa-bot removed the needs rebase or merge PR has conflicts with current master label Feb 4, 2019
@zooba
Copy link
Contributor Author

zooba commented Feb 4, 2019

This was just the rebase - I'll get back to finishing the actual PR as soon as I can.

@pradyunsg
Copy link
Member

pradyunsg commented Feb 5, 2019

Thanks @zooba! :)

I'm hoping to get this in for 19.0.2 -- which I plan to release in this week. It'd be ideal if we can get this done ~8th or 9th. :)

@zooba
Copy link
Contributor Author

zooba commented Feb 6, 2019

I don't think I have anything left to do here. Any suggestions?

@pradyunsg
Copy link
Member

@cjerdonek Could you review this?

Copy link
Member

@pradyunsg pradyunsg left a comment

Choose a reason for hiding this comment

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

LGTM

If no one voices any concerns in the next few hours, I'll go ahead and merge this.

@pradyunsg pradyunsg removed the request for review from cjerdonek February 8, 2019 06:22
@cjerdonek
Copy link
Member

@pradyunsg Generally my preference is for a clean commit history (as opposed to fixing mistakes, etc), so I would prefer this to be squashed unless the commits were designed to have a coherent sequence.

@pradyunsg
Copy link
Member

@pradyunsg Generally my preference is for a clean commit history (as opposed to fixing mistakes, etc), so I would prefer this to be squashed unless the commits were designed to have a coherent sequence.

Will do. :)

@pradyunsg pradyunsg merged commit 7eb79b1 into pypa:master Feb 8, 2019
@zooba zooba deleted the issue-6169 branch February 8, 2019 23:40
@pradyunsg
Copy link
Member

Not sure why @zooba is not listed in the authors in 7eb79b1. I squash-merged via the Web UI.

A GitHub bug maybe?

@xavfernandez
Copy link
Member

Not sure why @zooba is not listed in the authors in 7eb79b1. I squash-merged via the Web UI.

It looks like a simple merge happened :)

@pradyunsg
Copy link
Member

Uh. And here I am, genuinely sure that I'd clicked Squash and Merge.

@lock
Copy link

lock bot commented May 29, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot added the auto-locked Outdated issues that have been locked by automation label May 29, 2019
@lock lock bot locked as resolved and limited conversation to collaborators May 29, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
auto-locked Outdated issues that have been locked by automation C: uninstall The logic for uninstallation of packages
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pip install --upgrade stalls at the "uninstalling" phase
10 participants