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

[FIX] Make package resolve request respect case sensitivity -- Windows #689

Merged
merged 5 commits into from
Aug 15, 2019
Merged

[FIX] Make package resolve request respect case sensitivity -- Windows #689

merged 5 commits into from
Aug 15, 2019

Conversation

lambdaclan
Copy link
Contributor

@lambdaclan lambdaclan commented Aug 8, 2019

Description

[Relates to issue #685]

Windows file systems are not case sensitive

Unlike Linux and Unix file systems, Windows paths are not case sensitive this means that requests to resolve packages via rez-env using the wrong case will go through and resolve successfully. This can cause potential issues on other platforms where using the same name with a different case for a package is valid.

This is not a Python issue as the path check to the package directory returns True since Windows ignores case sensitivity in path names.

Issue

The root of the issue occurs at src/rezplugins/package_repository/filesystem.py
where the following check takes place

 if os.path.isdir(os.path.join(self.location, name)):

with location being the packages directories and name the requested package - this on Windows regardless of the case the name is using will return True if the names match.

Considered equal

rez-env 3dsmax-2018
rez-env 3DSmax-2018
rez-env 3dsMAX-2018
rez-env 3dSmAx-2018

The issue goes through multiple channels and can be intercepted in a few places for example
src/rez/resolved_context.py where the request takes place

self._package_requests = []        
for req in package_requests: - # name can also be checked here for case-sensitivity            
    if isinstance(req, basestring):               
        req = PackageRequest(req)            
    self._package_requests.append(req)

Windows - Case insensitive file system

win_case_01

Linux - Case sensitive file system

win_case_02

Solution

This PR solves the issue by ensuring that the requested package exists as a directory in the
any of the packages directories. This is achieved through the use of os.listdir which does give you the directory contents with their actual cases.

In an attempt to get the same error message as case-sensitive systems, the fix has been added to src/rez/packages.py file in the get (package) families function. Failure to detect the package during to wrong case will return zero entries resulting in the expected flow.

See #689 (review)

Breakdown

  • Add case sensitivity check to package requests

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

I have tried resolving a series of packages using different case. The results (before, after) are outlined below:

Before

2

After

1

Test Configuration:

Changelog

Point release

Source | Diff

Notes

Add case sensitivity check to prevent issues during package resolve for OSes with case insensitive file systems.

Merged pull requests:

  • [FIX] Make package resolve request respect case sensitivity -- Windows #689 (lambdaclan)

Closed issues:

  • Wrong case requests lead to packages resolved twice with different versions #685

Copy link
Contributor

@nerdvegas nerdvegas left a comment

Choose a reason for hiding this comment

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

Unfortunately it can't be the done the way it has been here.

The package repository acts as an abstraction - it hides away the details on how packages are represented and stored. This code is assuming that packages are stored on a filesystem. To that end, this fix must be implemented within the filesystem package repository class.

Further to this - the fix in filesystem repo should only employ use of os.listdir where necessary, and that means 2 things:

  • Only check pkg family name for case sensitive (mistmatched case on the root repo path is fine)
  • Only use listdir if necessary (ie windows) - we should assume it will be more expensive than the associated os.path.exists call.

@lambdaclan
Copy link
Contributor Author

Hello Allan,

Thank you for your feedback. OK got it, I will look into it and make the necessary changes as suggested above.

@nerdvegas
Copy link
Contributor

One more subtlety that should be fixed at the same time:

Since paths on windows are case-insensitive, the filesystem package repo filepath should be lower()ed on windows, so that stuff like the unique repo identifier, and the local path that gets stored into variant handles, doesn't differ if the case differs.

In other words, currently /sw/packages and /sw/Packages would be getting treated as separate package repos, whereas on Windows they're actually the same. So, there's another bug currently present, it just hasn't caused any problems so far (that I'm aware of!).

To keep this clean and explicit, I'd recommend adding a function like get_case_canonical_path (or similar) in utils.filesystem, which would do the lower() in windows, but would return path unchanged on other platforms.

@lambdaclan
Copy link
Contributor Author

Indeed, I had in mind using lower() to make the requested package path correct but that would conflict with packages that are actually case-sensitive such as "PyInstaller" for example. Saying that, lowering the path up to the package location makes sense to avoid package repo mix-up. I will add the fix to this PR as well. Hopefully there are no other edge cases that can causes issues...

@nerdvegas
Copy link
Contributor

Yeah I meant specifically only up to the repo location, to be clear. Package names must be case sensitive regardless of filesystem.

@lambdaclan
Copy link
Contributor Author

lambdaclan commented Aug 14, 2019

Hello Allan, with regards to this

In other words, currently /sw/packages and /sw/Packages would be getting treated as separate package repos, whereas on Windows they're actually the same. So, there's another bug currently present, it just hasn't caused any problems so far (that I'm aware of!).
To keep this clean and explicit, I'd recommend adding a function like get_case_canonical_path (or similar) in utils.filesystem, which would do the lower() in windows but would return path unchanged on other platforms.

If we went ahead and simply lowered the whole path wouldn't that cause other indirect issues? For example by default the packages path is ~/packages and as you mention ~/Packages would be treated the same on Windows but what if we do have a ~/Packages path defined on another platform and then try it to use it on Windows via the same rezconfig or via REZ_PACKAGES_PATH? We should possibly have a warning or something that Windows is case insensitive therefore all package paths will be lowered.

Also what if a totally different path using mixed case is used for example /home/Test/myPackages etc? I mean on Windows it will end up working since it ignores case anyway but should we assume the user is aware of this? The issue becomes more complicated since we are now checking the whole path rather than just Packages vs packages or int vs Int meaning that on Windows there will always be a warning since home dir normally uses mixed case...

This means on Windows check if the package location path is not lowered (contains uppercase) and if not give a warning that on Windows paths with different case are the same. Unless we take for granted that this is common knowledge.

λ  buildrez                                                                                                                                                                                                                                                                                                                                      
installing rez to C:\Users\Joe\.rez...                                                                                                                                                                             
running in C:\Users\Joe\Downloads\rez: c:\users\joe\.rez\scripts\python.exe -m pip install .                                                                                                                       
DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7
Processing c:\users\joe\downloads\rez                                                                                                                                                                              
Building wheels for collected packages: rez                                                                                                                                                                        
  Building wheel for rez (setup.py) ... done                                                                                                                                                                       
  Stored in directory: c:\users\joe\appdata\local\temp\pip-ephem-wheel-cache-ge4cu6\wheels\fe\67\20\54f9154d310485e796588661c36912ff82dfac1784482210d7                                                             
Successfully built rez                                                                                                                                                                                             
Installing collected packages: rez                                                                                                                                                                                 
Successfully installed rez-2.40.1                                                                                                                                                                                  
WARNING: You are using pip version 19.1.1, however version 19.2.1 is available.                                                                                                                                    
You should consider upgrading via the 'python -m pip install --upgrade pip' command.                                                                                                                               
                                                                                                                                                                                                                   
SUCCESS! To activate Rez, add the following path to $PATH:                                                                                                                                                         
C:\Users\Joe\.rez\Scripts\rez                                                                                                                                                                                      
                                                                                                                                                                                                                   
You may also want to source the relevant completion script from:                                                                                                                                                   
C:\Users\Joe\.rez\completion                                                                                                                                                                                       
                                                                                                                                                                                                                   
The process cannot access the file because it is being used by another process.                                                                                                                                    
Binding platform into C:\Users\Joe\packages...                                                                                                                                                                     
###########################################################################
Warning[Mixed case packages path]: Windows paths are case-insensitive, falling from C:\Users3\Joe\packages to c:\users\joe\packages
###########################################################################                                                                                 
Binding arch into C:\Users\Joe\packages...                                                                                                                                                                         
Binding os into C:\Users\Joe\packages...                                                                                                                                                                           
Binding python into C:\Users\Joe\packages...                                                                                                                                                                       
Binding rez into C:\Users\Joe\packages...                                                                                                                                                                          
Binding rezgui into C:\Users\Joe\packages...                                                                                                                                                                       
Binding setuptools into C:\Users\Joe\packages...                                                                                                                                                                   
Binding pip into C:\Users\Joe\packages...                                                                                                                                                                          
                                                                                                                                                                                                                   
Successfully converted the following software found on the current system into Rez packages:                                                                                                                       
                                                                                                                                                                                                                   
PACKAGE     URI                                                                                                                                                                                                    
-------     ---                                                                                                                                                                                                    
arch        c:\users\joe\packages\arch\AMD64\package.py                                                                                                                                                            
os          c:\users\joe\packages\os\windows-10.0.18362\package.py                                                                                                                                                 
pip         c:\users\joe\packages\pip\19.2.1\package.py                                                                                                                                                            
platform    c:\users\joe\packages\platform\windows\package.py                                                                                                                                                      
python      c:\users\joe\packages\python\2.7.16\package.py                                                                                                                                                         
rez         c:\users\joe\packages\rez\2.40.1\package.py                                                                                                                                                            
rezgui      c:\users\joe\packages\rezgui\2.40.1\package.py                                                                                                                                                         
setuptools  c:\users\joe\packages\setuptools\40.6.2\package.py                                                                                                                                                     

@nerdvegas
Copy link
Contributor

nerdvegas commented Aug 14, 2019 via email

@lambdaclan
Copy link
Contributor Author

Sounds good, I will remove the warning then, everything else is implemented as discussed above.

@@ -784,7 +786,16 @@ def _get_families(self):

def _get_family(self, name):
is_valid_package_name(name, raise_error=True)
if os.path.isdir(os.path.join(self.location, name)):
if "Windows" in platform.system():
Copy link
Contributor

Choose a reason for hiding this comment

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

I would simplify:

if os.path.isdir(os.path.join(self.location, name)):
    # force case-sensitive match on pkg family, on case-insensitive platforms
    if "Windows" in platform.system() and name not in os.listdir(self.location):
        return None

@nerdvegas nerdvegas merged commit 36c515b into AcademySoftwareFoundation:master Aug 15, 2019
@nerdvegas
Copy link
Contributor

nerdvegas commented Aug 15, 2019

Please note my changes. I realised there's another case we didn't consider (unversioned packages); it also made sense to abstract case sensitivity into platform_, and remove explicit references to Windows instead.

Ps - Please test!

@lambdaclan lambdaclan deleted the fix/rez-env-case-sensitive-windows branch April 6, 2020 06:37
Sign up for free to 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.

2 participants