Skip to content

Commit

Permalink
fix: resolve local dependency path on \*nix correctly
Browse files Browse the repository at this point in the history
This PR addresses the issue with resolving the local path as a uri. It took mixed usage of `os.path` and `pathlib.Path` to get it right on both Windows and Linux. Part of the issue was how in Windows and \*nix systems based on what the uri is pointing to the number of slashes after file:// can be 2 or 3! I was expecting it to always be 3 which would return `home/user/...` instead of `/home/user/...`. The first one is considered an absolute path and the second one is relative! That's the main reason that it was failing. I also took the opportunity to clean the code a little bit.

resolves #266
  • Loading branch information
mostaphaRoudsari committed Feb 18, 2021
1 parent 5903723 commit baf3997
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 26 deletions.
35 changes: 25 additions & 10 deletions queenbee/base/request.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,40 @@
import pathlib
import os
import pathlib
import platform
from urllib import request
from typing import Union, Dict
from .basemodel import BaseModel
from typing import Dict

USER_AGENT_STRING = 'Queenbee'


def get_uri(url):
"""Resolve uri for urls and local files."""

if url.startswith('file:///'):
if url.startswith('file://'):
return url.replace('\\', '/')
elif url.startswith('http://') or url.startswith('https://'):
return url

# a local file
# a local file but is not formatted as local url
pre = 'file:///' if platform.system() == 'Windows' else 'file://'
return resolve_local_source(pre + url)


def resolve_local_source(path, as_uri=True):
"""Get an absolute path for a file:// or file:/// path.
Apparently both of them are used: https://en.wikipedia.org/wiki/File_URI_scheme
"""
sep = 'file:///' if platform.system() == 'Windows' else 'file://'

try:
uri = pathlib.Path(os.path.abspath(url)).as_uri()
except ValueError:
uri = url
rel_path = path.split(sep)[1]
except IndexError:
raise ValueError('Invalid local path: {path}')

abs_path = os.path.abspath(rel_path)

uri = pathlib.Path(abs_path).as_uri() if as_uri \
else pathlib.Path(abs_path).as_posix()

return uri

Expand All @@ -46,7 +61,7 @@ def make_request(url: str, auth_header: Dict[str, str] = {}) -> str:
Returns:
str: [description]
"""
if auth_header == None:
if auth_header is None:
auth_header = {}

auth_header.update({
Expand Down
2 changes: 1 addition & 1 deletion queenbee/config/repositories.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RepositoryReference(BaseModel):

@validator('path')
def remote_or_local(cls, v):
"""Determine whether the path is local or remote (ie: http)"""
"""Format local uri as needed (ie: file:///)"""
return get_uri(v)

def fetch(self, auth_header: Dict[str, str] = {}) -> 'RepositoryIndex':
Expand Down
12 changes: 4 additions & 8 deletions queenbee/recipe/dependency.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""Queenbee dependency class."""
import os
from typing import Dict
from enum import Enum
from pydantic import Field, constr


from ..base.basemodel import BaseModel
from ..base.request import make_request, urljoin
from ..base.request import make_request, urljoin, resolve_local_source


class DependencyKind(str, Enum):
Expand Down Expand Up @@ -94,12 +94,8 @@ def _fetch_index(self, auth_header: Dict[str, str] = {}):
"""
from ..repository.index import RepositoryIndex

if self.source.startswith('file:///'):
rel_path = self.source.split('file:///')[1]

abs_path = os.path.join(os.getcwd(), rel_path, 'index.json')

url = f'file:///{abs_path}'
if self.source.startswith('file:'):
url = resolve_local_source(self.source) + '/index.json'
else:
url = urljoin(self.source, 'index.json')

Expand Down
14 changes: 7 additions & 7 deletions queenbee/repository/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from ..plugin import Plugin
from ..recipe import Recipe, BakedRecipe

from ..base.request import make_request, urljoin
from ..base.request import make_request, urljoin, resolve_local_source
from ..base.metadata import MetaData


Expand Down Expand Up @@ -242,7 +242,10 @@ def from_package(cls, package_path: str):
Returns:
PackageVersion -- A package version object
"""
file_path = os.path.normpath(os.path.abspath(package_path)).replace('\\', '/')
if package_path.startswith('file:'):
file_path = resolve_local_source(package_path, as_uri=False)
else:
file_path = package_path.replace('\\', '/')

with open(file_path, 'rb') as f:
filebytes = BytesIO(f.read())
Expand All @@ -254,11 +257,8 @@ def from_package(cls, package_path: str):
def fetch_package(self, source_url: str = None, verify_digest: bool = True,
auth_header: Dict[str, str] = {}) -> 'PackageVersion':
if source_url.startswith('file:'):
source_path = source_url.split('file:///')[1]
if os.path.isabs(source_path):
package_path = os.path.join(source_path, self.url)
else:
package_path = os.path.join(os.getcwd(), source_path, self.url)
source_path = resolve_local_source(source_url)
package_path = os.path.join(source_path, self.url)

return self.from_package(package_path)

Expand Down

0 comments on commit baf3997

Please sign in to comment.