Skip to content

Commit

Permalink
Merge pull request #643 from rajulkumar/decouple_NFS
Browse files Browse the repository at this point in the history
Add content reader to decouple NFS file reads [RHELDST-26339]
  • Loading branch information
rajulkumar authored Jan 30, 2025
2 parents 5f72570 + fab5c48 commit 60dcca5
Show file tree
Hide file tree
Showing 38 changed files with 387 additions and 2 deletions.
12 changes: 11 additions & 1 deletion src/pushsource/_impl/list_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@

LOG = logging.getLogger("pushsource-ls")

EXCLUDED_ATTRIBUTES = [
"opener",
]


class ItemDumper(yaml.SafeDumper):
# Custom dumper adding support for any types appearing on pushitems
Expand Down Expand Up @@ -77,7 +81,13 @@ def format_python_black(item):


def format_yaml(item):
data = {type(item).__name__: attr.asdict(item, recurse=True)}
data = {
type(item).__name__: attr.asdict(
item,
recurse=True,
filter=lambda attribute, _: attribute.name not in EXCLUDED_ATTRIBUTES,
)
}
return yaml.dump([data], Dumper=ItemDumper)


Expand Down
42 changes: 42 additions & 0 deletions src/pushsource/_impl/model/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
optional,
optional_str,
)
from ..reader import PushItemReader


LOG = logging.getLogger("pushsource")
Expand Down Expand Up @@ -178,6 +179,14 @@ def _default_build_info(self):
doesn't enforce this.
"""

opener = attr.ib(type=callable, default=None, repr=False)
"""The opener, when given a push item, should return a file-like object
suitable for reading this item's bytes. The object can be retrieved from
:meth:`~pushsource.PushItem.content()` method.
.. versionadded:: 2.51.0
"""

def with_checksums(self):
"""Return a copy of this push item with checksums present.
Expand Down Expand Up @@ -248,3 +257,36 @@ def with_checksums(self):
updated_sums[attribute] = hasher.hexdigest()

return attr.evolve(self, **updated_sums)

def content(self):
"""Returns a read-only, non-seekable content of this push item.
For push items representing a single file, content will obtain a stream
for reading that file's bytes.
For example, ``RpmPushItem.content`` can be used to read the content of
an RPM; ``VMIPushItem.content`` can be used to read the content of a VMI
and so on.
Not every type of push item can be read in this way.
For example, a single ``ContainerImagePushItem`` may represent any number
of artifacts making up a container image, to be accessed from a container
image registry in the usual way - not using this method. Other types of
push items such as ``ErratumPushItem`` may be understood as metadata-only
items and do not themselves have any content. For items such as these,
this method will return None.
Returns:
:class:`~io.BufferedReader`
A non-seekable object of the push item content
``None``
If the :attr:`~pushsource.PushItem.opener` in the pushitem is not defined to read
the content.
.. versionadded:: 2.51.0
"""
return (
PushItemReader(self.opener(self), self.src or self.name)
if self.opener
else None
)
9 changes: 9 additions & 0 deletions src/pushsource/_impl/model/comps.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .base import PushItem
from .. import compat_attr as attr
from ..utils.openers import open_src_local


@attr.s()
Expand All @@ -12,3 +13,11 @@ class CompsXmlPushItem(PushItem):
This library does not verify that the referenced file is valid.
"""

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
9 changes: 9 additions & 0 deletions src/pushsource/_impl/model/directory.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .base import PushItem
from .. import compat_attr as attr
from ..utils.openers import open_src_local


@attr.s()
Expand All @@ -9,3 +10,11 @@ class DirectoryPushItem(PushItem):
On a directory push item, the src attribute contains the full path to a directory tree.
It should generally be interpreted as a request to recursively publish that entire directory
tree as-is."""

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
9 changes: 9 additions & 0 deletions src/pushsource/_impl/model/file.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from .base import PushItem
from .. import compat_attr as attr
from .conv import optional_str, convert_maybe
from ..utils.openers import open_src_local


@attr.s()
Expand Down Expand Up @@ -52,3 +53,11 @@ def _check_order(self, _, value):
# - This check will also filter out NaN.
if not -99999 <= value <= 99999:
raise ValueError("display_order must be within range -99999 .. 99999")

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
17 changes: 17 additions & 0 deletions src/pushsource/_impl/model/modulemd.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .base import PushItem
from .. import compat_attr as attr
from ..utils.openers import open_src_local


@attr.s()
Expand All @@ -14,6 +15,14 @@ class ModuleMdPushItem(PushItem):
modulemd stream.
"""

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""


@attr.s()
class ModuleMdSourcePushItem(PushItem):
Expand All @@ -25,3 +34,11 @@ class ModuleMdSourcePushItem(PushItem):
This library does not verify that the referenced file is a valid
modulemd source document.
"""

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
9 changes: 9 additions & 0 deletions src/pushsource/_impl/model/productid.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .base import PushItem
from .conv import convert_maybe, sloppylist
from .. import compat_attr as attr
from ..utils.openers import open_src_local


# Red Hat OID namespace is "1.3.6.1.4.1.2312.9",
Expand Down Expand Up @@ -114,3 +115,11 @@ def _load_products(self, path):
)
result.append(product)
return result

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
9 changes: 9 additions & 0 deletions src/pushsource/_impl/model/rpm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from .base import PushItem
from .conv import optional_str
from .. import compat_attr as attr
from ..utils.openers import open_src_local


@attr.s()
Expand Down Expand Up @@ -32,3 +33,11 @@ class RpmPushItem(PushItem):
.. _ghc-8.4-820200708061905.9edba152: https://koji.fedoraproject.org/koji/buildinfo?buildID=1767200
.. _ghc-8.4.4-74.module_el8+12161+cf1bd7f2: https://koji.fedoraproject.org/koji/buildinfo?buildID=1767130
"""

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Identical to :attr:`~pushsource.PushItem.opener`.
This defaults to reading content as file from :attr:`~pushsource.PushItem.src`
.. versionadded:: 2.51.0
"""
19 changes: 19 additions & 0 deletions src/pushsource/_impl/reader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from io import BufferedReader, SEEK_SET, UnsupportedOperation


class PushItemReader(BufferedReader):
# Internal class to ensure that the file-like content object returned by
# the push items are read-only and non-seekable with a name attribute.
def __init__(self, raw, name, **kwargs):
super(PushItemReader, self).__init__(raw, **kwargs)
self._name = name

@property
def name(self):
return self._name

def seekable(self):
return False

def seek(self, offset, whence=SEEK_SET):
raise UnsupportedOperation(f"Seek unsupported while reading {self.name}")
5 changes: 5 additions & 0 deletions src/pushsource/_impl/utils/openers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def open_src_local(item):
# default opener for the push items
# assumes that the item's 'src' points to the
# locally-accessible file
return open(item.src, "rb")
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-cgw.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ items:
- dest
md5sum: null
name: cgw.yaml
opener: null
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-comps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ items:
dest: []
md5sum: null
name: mycomps.xml
opener: open_src_local
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-dir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ items:
- /destdir
md5sum: null
name: srcdir
opener: open_src_local
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-file.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ items:
display_order: null
md5sum: null
name: custom-filename
opener: open_src_local
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-modulemd-src.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ items:
dest: []
md5sum: null
name: modules.src.txt
opener: open_src_local
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-modulemd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ items:
dest: []
md5sum: null
name: my-best-module
opener: open_src_local
origin: direct
sha256sum: null
signing_key: null
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-productid.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ items:
- repo3
md5sum: null
name: some-cert
opener: open_src_local
origin: direct
products:
- architecture:
Expand Down
1 change: 1 addition & 0 deletions tests/baseline/cases/direct-rpm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ items:
md5sum: null
module_build: null
name: test.rpm
opener: open_src_local
origin: custom-origin
sha256sum: null
signing_key: A1B2C3
Expand Down
Loading

0 comments on commit 60dcca5

Please sign in to comment.