Skip to content

Commit

Permalink
Allow inline tables in includes to be similarly functional to the `pa…
Browse files Browse the repository at this point in the history
…ckage` directive.

Unify common logic between WheelBuilder and Builder. Move SDistBuilder logic from Builder to SDistBuilder.
Resolves: #8
  • Loading branch information
kasteph committed Apr 20, 2020
1 parent fc4ae2d commit 5c5fb3f
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 80 deletions.
13 changes: 12 additions & 1 deletion poetry/core/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,18 @@ def create_poetry(self, cwd=None): # type: (Optional[Path]) -> Poetry
package.build = local_config["build"]

if "include" in local_config:
package.include = local_config["include"]
package.include = []

for include in local_config["include"]:
if not isinstance(include, dict):
include = {"path": include}

formats = include.get("format", [])
if formats and not isinstance(formats, list):
formats = [formats]
include["format"] = formats

package.include.append(include)

if "exclude" in local_config:
package.exclude = local_config["exclude"]
Expand Down
44 changes: 36 additions & 8 deletions poetry/core/json/schemas/poetry-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,26 +73,43 @@
],
"properties": {
"include": {
"type": "string",
"description": "What to include in the package."
"$ref": "#/definitions/include-path"
},
"from": {
"type": "string",
"description": "Where the source directory of the package resides."
},
"format": {
"oneOf": [
{"type": "string"},
{"type": "array", "items": {"type": "string"}}
],
"description": "The format(s) for which the package must be included."
"$ref": "#/definitions/package-format"
}
}
}
},
"include": {
"type": "array",
"description": "A list of files and folders to include."
"description": "A list of files and folders to include.",
"items": {
"anyOf": [
{
"$ref": "#/definitions/include-path"
},
{
"type": "object",
"additionalProperties": false,
"required": [
"path"
],
"properties": {
"path": {
"$ref": "#/definitions/include-path"
},
"format": {
"$ref": "#/definitions/package-format"
}
}
}
]
}
},
"exclude": {
"type": "array",
Expand Down Expand Up @@ -190,6 +207,17 @@
"type": "string"
}
},
"include-path": {
"type": "string",
"description": "Path to file or directory to include."
},
"package-format": {
"oneOf": [
{"type": "string", "enum": ["sdist", "wheel"]},
{"type": "array", "items": {"type": "string"}}
],
"description": "The format(s) for which the package must be included."
},
"dependencies": {
"type": "object",
"patternProperties": {
Expand Down
76 changes: 50 additions & 26 deletions poetry/core/masonry/builders/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from poetry.core.vcs import get_vcs

from ..metadata import Metadata
from ..utils.include import IncludeFile
from ..utils.module import Module
from ..utils.package_include import PackageInclude

Expand Down Expand Up @@ -61,11 +62,25 @@ def __init__(

packages.append(p)

includes = []
for i in self._package.include:
formats = i.get("format", [])

if (
formats
and self.format
and self.format not in formats
and not ignore_packages_formats
):
continue

includes.append(i)

self._module = Module(
self._package.name,
self._path.as_posix(),
packages=packages,
includes=self._package.include,
includes=includes,
)
self._meta = Metadata.from_package(self._package)

Expand Down Expand Up @@ -115,58 +130,67 @@ def is_excluded(self, filepath): # type: (Union[str, Path]) -> bool

return False

def find_files_to_add(self, exclude_build=True): # type: (bool) -> list
def find_files_to_add(
self, exclude_build=True
): # type: (bool) -> List[IncludeFile]
"""
Finds all files to add to the tarball
"""
to_add = []

for include in self._module.includes:
include.refresh()
formats = include.formats or ["sdist"]

for file in include.elements:
if "__pycache__" in str(file):
continue

if file.is_dir():
if self.format in formats:
for f in file.glob("**/*"):
included = f.relative_to(self._path)
if (
included not in set([f.path for f in to_add])
and not f.is_dir()
and not self.is_excluded(included)
):
to_add.append(
IncludeFile(path=included, source_root=self._path)
)
continue

file = file.relative_to(self._path)
if isinstance(include, PackageInclude) and all(
[include.source, self.format == "wheel"]
):
source_root = include.base
else:
source_root = self._path

file = file.relative_to(source_root)
include_file = IncludeFile(path=file, source_root=source_root.resolve())

if self.is_excluded(file) and isinstance(include, PackageInclude):
continue

if file.suffix == ".pyc":
continue

if file in to_add:
if file in set([f.path for f in to_add]):
# Skip duplicates
continue

logger.debug(" - Adding: {}".format(str(file)))
to_add.append(file)

# Include project files
logger.debug(" - Adding: pyproject.toml")
to_add.append(Path("pyproject.toml"))

# If a license file exists, add it
for license_file in self._path.glob("LICENSE*"):
logger.debug(" - Adding: {}".format(license_file.relative_to(self._path)))
to_add.append(license_file.relative_to(self._path))

# If a README is specified we need to include it
# to avoid errors
if "readme" in self._poetry.local_config:
readme = self._path / self._poetry.local_config["readme"]
if readme.exists():
logger.debug(" - Adding: {}".format(readme.relative_to(self._path)))
to_add.append(readme.relative_to(self._path))

# If a build script is specified and explicitely required
to_add.append(include_file)

# If a build script is specified and explicitly required
# we add it to the list of files
if self._package.build and not exclude_build:
to_add.append(Path(self._package.build))
to_add.append(
IncludeFile(path=Path(self._package.build), source_root=self._path)
)

return sorted(to_add)
return to_add

def get_metadata_content(self): # type: () -> bytes
content = METADATA_BASE.format(
Expand Down
40 changes: 36 additions & 4 deletions poetry/core/masonry/builders/sdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from poetry.core.utils._compat import to_str

from ..utils.helpers import normalize_file_permissions
from ..utils.include import IncludeFile
from ..utils.package_include import PackageInclude
from .builder import Builder

Expand Down Expand Up @@ -74,10 +75,10 @@ def build(self, target_dir=None): # type: (Path) -> Path

files_to_add = self.find_files_to_add(exclude_build=False)

for relpath in files_to_add:
path = self._path / relpath
for file in files_to_add:
path = file.full_path
tar_info = tar.gettarinfo(
str(path), arcname=pjoin(tar_dir, str(relpath))
str(path), arcname=pjoin(tar_dir, str(file.rel_path))
)
tar_info = self.clean_tarinfo(tar_info)

Expand All @@ -104,7 +105,6 @@ def build(self, target_dir=None): # type: (Path) -> Path
gz.close()

logger.info(" - Built <comment>{}</comment>".format(target.name))

return target

def build_setup(self): # type: () -> bytes
Expand Down Expand Up @@ -301,6 +301,38 @@ def find_nearest_pkg(rel_path):

return pkgdir, sorted(packages), pkg_data

def find_files_to_add(
self, exclude_build=False
): # type: (bool) -> List[IncludeFile]
to_add = super().find_files_to_add(exclude_build)

# Include project files
logger.debug(" - Adding: pyproject.toml")
to_add.append(IncludeFile(path=Path("pyproject.toml"), source_root=self._path))

# If a license file exists, add it
for license_file in self._path.glob("LICENSE*"):
logger.debug(" - Adding: {}".format(license_file.relative_to(self._path)))
to_add.append(
IncludeFile(
path=license_file.relative_to(self._path), source_root=self._path
)
)

# If a README is specified we need to include it
# to avoid errors
if "readme" in self._poetry.local_config:
readme = self._path / self._poetry.local_config["readme"]
if readme.exists():
logger.debug(" - Adding: {}".format(readme.relative_to(self._path)))
to_add.append(
IncludeFile(
path=readme.relative_to(self._path), source_root=self._path
)
)

return sorted(to_add, key=lambda x: x.path)

@classmethod
def convert_dependencies(cls, package, dependencies):
main = []
Expand Down
43 changes: 4 additions & 39 deletions poetry/core/masonry/builders/wheel.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
from ..utils.helpers import escape_name
from ..utils.helpers import escape_version
from ..utils.helpers import normalize_file_permissions
from ..utils.package_include import PackageInclude
from .builder import Builder
from .sdist import SdistBuilder

Expand Down Expand Up @@ -131,47 +130,13 @@ def _run_build_command(self, setup):
[sys.executable, str(setup), "build", "-b", str(self._path / "build")]
)

def _copy_module(self, wheel):

to_add = []

for include in self._module.includes:
if include.formats and "wheel" not in include.formats:
continue

include.refresh()

for file in include.elements:
if "__pycache__" in str(file):
continue

if file.is_dir():
continue

if isinstance(include, PackageInclude) and include.source:
rel_file = file.relative_to(include.base)
else:
rel_file = file.relative_to(self._path)

if self.is_excluded(rel_file.as_posix()) and isinstance(
include, PackageInclude
):
continue

if file.suffix == ".pyc":
continue

if (file, rel_file) in to_add:
# Skip duplicates
continue

logger.debug(" - Adding: {}".format(str(file)))
to_add.append((file, rel_file))
def _copy_module(self, wheel): # type: (zipfile.ZipFile) -> None
to_add = self.find_files_to_add()

# Walk the files and compress them,
# sorting everything so the order is stable.
for full_path, rel_path in sorted(to_add, key=lambda x: x[1]):
self._add_file(wheel, full_path, rel_path)
for file in sorted(to_add, key=lambda x: x.path):
self._add_file(wheel, file.full_path, file.rel_path)

def _write_metadata(self, wheel):
if (
Expand Down
22 changes: 22 additions & 0 deletions poetry/core/masonry/utils/include.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from pathlib import PosixPath
from typing import List
from typing import Optional

Expand Down Expand Up @@ -46,3 +47,24 @@ def refresh(self): # type: () -> Include
self._elements = sorted(list(self._base.glob(self._include)))

return self


class IncludeFile:
def __init__(
self,
path, # type: PosixPath
source_root=None, # type: Optional[PosixPath]
):
self.path = path
self.source_root = source_root or Path(".")

def __repr__(self): # type: () -> str
return str(self.path)

@property
def rel_path(self): # type: () -> PosixPath
return self.path

@property
def full_path(self): # type: () -> PosixPath
return self.source_root / self.path
4 changes: 3 additions & 1 deletion poetry/core/masonry/utils/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ def __init__(self, name, directory=".", packages=None, includes=None):
)

for include in includes:
self._includes.append(Include(self._path, include))
self._includes.append(
Include(self._path, include["path"], formats=include["format"])
)

@property
def name(self): # type: () -> str
Expand Down
Loading

0 comments on commit 5c5fb3f

Please sign in to comment.