-
Notifications
You must be signed in to change notification settings - Fork 681
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
pip resource: support non-default pip locations, such as virtualenvs #2097
Conversation
sorry. Forgot DCO. I'll amend the commit |
Signed-off-by: Anthony Shaw <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. I've got some inline comments, also, an added test case would be awesome, too (https://github.com/chef/inspec/blob/master/test/unit/resources/pip_test.rb)
lib/resources/pip.rb
Outdated
" | ||
|
||
def initialize(package_name) | ||
def initialize(package_name, virtualenv_path=nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] I think virtualenv_path
is a bit confusing here: From looking at this, I'd expect that I was to put /path/to/virtualenv
in there, not /path/to/virtualenv/bin/pip
. No idea what's the best approach, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed. pip_path
would make sense. OR having it test for the existence of @virtualenv_path
+ /bin/pip
before executing.
lib/resources/pip.rb
Outdated
@@ -75,7 +81,7 @@ def pip_cmd | |||
return nil | |||
end | |||
end | |||
pipcmd || 'pip' | |||
pipcmd = @virtualenv_path.nil? ? 'pip' : @virtualenv_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nit] I think to keep the logic that was there before -- this would maybe better be something like this:
pipcmd || @virtualenv_path || 'pip'
So, the order of precedence would be: if the pip
is found (windows), take that. Otherwise, take @virtualenv_path
; fall back to 'pip'.
Makes me wonder if this shouldn't be like this, then:
@virtualenv_path || pipcmd || 'pip'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@srenatus I updated it. let me know if the new one makes more sense? I'm new to this so feel free to [nit]
lib/resources/pip.rb
Outdated
@@ -75,7 +81,7 @@ def pip_cmd | |||
return nil | |||
end | |||
end | |||
pipcmd || 'pip' | |||
@virtualenv_path.nil? ? pipcmd || 'pip' : @virtualenv_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if @virtualenv_path
is nil, @virtualenv_path.nil?
is true. However, @virtualenv_path
will also be understood as "falsy" by ruby, so that line is equivalent to
@virtualenv_path || pipcmd || 'pip'
Signed-off-by: Anthony Shaw <[email protected]>
@srenatus decided to solve both problems. it now works with a directory (and adds /bin/pip to the path) and then the flow through logic is cleaner as well describe pip('django') do
it { should be_installed }
its('version') { should eq('1.10.5')}
end
describe pip('django', '/Users/anthonyshaw/repo/wayfinder/wayfinder/') do
it { should be_installed }
its('version') { should eq('1.11.4')}
end
describe pip('django', '/Users/anthonyshaw/repo/wayfinder/wayfinder/bin/pip') do
it { should be_installed }
its('version') { should eq('1.11.4')}
end Gives
|
@tonybaloney I'm not one of @chef/inspec-maintainers, but I'm sure they'd appreciate an added testcase or two? 😉 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tonybaloney welcome to the InSpec community and congratulations on your first contribution!
I've left you some suggestions in an effort to streamline the resource and provide better error messaging to our users.
As @srenatus mentioned, we should definitely add a test for when a user provides a custom pip path. The process would look something like this:
- Add a test that invokes a resource with a custom pip path - maybe test for django this time instead of jinja2 currently tested for? It would go around here: https://github.com/chef/inspec/blob/master/test/unit/resources/pip_test.rb#L14
- Add a mock for the non-standard pip location (see https://github.com/chef/inspec/blob/master/test/helper.rb#L205 for an example)
- Add the mock data for the non-standard pip call. Make it different than the existing pip mock so we're 100% certain the right thing is being tested (see https://github.com/chef/inspec/blob/master/test/unit/mock/cmd/pip-show-jinja2 for an example, maybe name it "non-standard-pip-show-django"
I'd love to help you with the tests if you have any questions or concerns about them. Just let me know.
Again, THANK YOU for contributing to InSpec! It's great to have you.
lib/resources/pip.rb
Outdated
" | ||
|
||
def initialize(package_name) | ||
def initialize(package_name, virtualenv_path = nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's change this variable to pip_path
since you can technically install pip in a "non-PATH" location without using a virtualenv, and the examples given are actually paths to an actual pip
command, not the top-level directory of the virtualenv.
lib/resources/pip.rb
Outdated
@package_name = package_name | ||
@virtualenv_path = virtualenv_path |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above for my comment re: virtualenv_path
. Instead, I think we should set an instance variable that contains the validated path to pip
, and change the #pip_cmd
method name to be clearer... maybe resolve_pip_path
?
So, assuming you take my advice to change the argument name to pip_path
above, it would look something like this:
@pip_cmd = resolve_pip_path(pip_path)
return skip_resource "pip not found" if @pip_cmd.nil?
... and then resolve_pip_path
would change a bit to support that. Does that make sense?
lib/resources/pip.rb
Outdated
@@ -57,7 +64,14 @@ def to_s | |||
def pip_cmd | |||
# Pip is not on the default path for Windows, therefore we do some logic | |||
# to find the binary on Windows | |||
if inspec.os.windows? | |||
if !@virtualenv_path.nil? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a real good first attempt, @tonybaloney! I think it's a better user experience to just assume the user is going to give us a path to pip
directory rather than adding logic to test if the path is a dir and then assume it's a virtualenv.
How about logic like this:
- if user gave us a pip path, verify it exists, return nil if it doesn't, otherwise return what they gave us
- if on windows, run the powershell to find the full pip path. Return nil if we can't find anything
- Otherwise, assume it's just "pip", check to see if it exists with command('pip').exist?... return 'pip' if it does, return nil if it doesn't
Then, in initialize
, we can call skip_resource
if pip_cmd returns nil with helpful error messaging.
Signed-off-by: Anthony Shaw <[email protected]>
Signed-off-by: Anthony Shaw <[email protected]>
Signed-off-by: Anthony Shaw <[email protected]>
Signed-off-by: Anthony Shaw <[email protected]>
Signed-off-by: Anthony Shaw <[email protected]>
Signed-off-by: Anthony Shaw <[email protected]>
@adamleff those changes have all been done. However the tests are failing, I think it's because it's checking for the existence of either these fake files and, the pip command which probably isn't on the Docker image. Or I may have made some other mistake |
Signed-off-by: Adam Leff <[email protected]>
@tonybaloney thanks for your patience! I just pushed up a commit to your branch to do a bit of refactoring in order to solve your unit test dilemma. Here's what happened... the logic in The way I found this was to use the
... this will run only the unit tests located in Please take a look at the commit I sent up and let me know if you have any questions. Basically, I moved some of the default handling back up to If it looks good to you, and you're OK with it, I'll give this another review and we can work on getting this merged. Thank you again for your help with this pull request! |
Signed-off-by: Anthony Shaw <[email protected]>
all makes sense. I'll do some more reading before the next change |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super work, @tonybaloney! Thank you for your contribution, and congratulations on your first pull request to InSpec! Welcome to the community 🙂
Once another maintainer reviews and approves, we'll merge this in!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing work @tonybaloney thank you so much!! 😁
#2459) Signed-off-by: Markus Grobelin <[email protected]>
Fixes #516
Implements optional path to pip executable (like when virtualenv is used) instead of using system PATH.
Tested by installing newer version of Django in virtualenv and testing for it
Before:
After