Skip to content

Commit

Permalink
Add content reader to decouple NFS file reads [RHELDST-26339]
Browse files Browse the repository at this point in the history
The API to read content of the push items strongly depends
on their presence as file on NFS or locally-mounted filesystem.
However, with advent of new push item sources, it likely that
the push items might not be stored as a file or be locally available.

Hence, pushitems will have an `opener` that is capable to fetch
the corresponding bits and provide them as `content()`. `Source`
will define the `opener` while creating the pushitems to get the
bit from the specific content source. This will transfer the
responsibility to fetch the content from the consumer that is
using the content/pushitems to the `Source` and corresponding
`pushitem` here, abstracting the reading mechanism from the user
and provide flexibility to fetch from different locations/protocols.
  • Loading branch information
rajulkumar committed Jan 16, 2025
1 parent 62486a0 commit bf47408
Show file tree
Hide file tree
Showing 31 changed files with 318 additions and 2 deletions.
24 changes: 23 additions & 1 deletion src/pushsource/_impl/list_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@

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

EXCLUDED_ATTRIBUTES = [
"_content",
]


def format_python(item):
return repr(item) + ","
Expand All @@ -49,8 +53,26 @@ def format_python_black(item):
return out


def _filter_attributes(attribute, _):
return attribute.alias not in EXCLUDED_ATTRIBUTES


def _callable_to_str(value):
if not callable(value):
return value

return getattr(value, "__name__", repr(value))


def format_yaml(item):
data = {type(item).__name__: attr.asdict(item, recurse=True)}
data = {
type(item).__name__: attr.asdict(
item,
recurse=True,
filter=_filter_attributes,
value_serializer=lambda _self, _field, value: _callable_to_str(value),
)
}
return yaml.dump([data], Dumper=yaml.SafeDumper)


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


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

opener = attr.ib(type=callable, default=open_src_local, repr=False)
"""Callable that gets the content of this push item. The content could be
retrived from `content()` method"""


def with_checksums(self):
"""Return a copy of this push item with checksums present.
Expand Down Expand Up @@ -248,3 +255,12 @@ 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.
Returns:
:class:`~io.BufferedReader`
A non-seekable object of the push item content
"""
return PushItemReader(self.opener(self))
23 changes: 23 additions & 0 deletions src/pushsource/_impl/reader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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=None, **kwargs):
super(PushItemReader, self).__init__(raw, **kwargs)

# Attempt to assign name from the raw object if none is provided
self._name = name or getattr(super(), "name", None)
if not self._name:
raise ValueError("'name' not provided or availble from 'raw' object")

@property
def name(self):
return self._name or super().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: open_src_local
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 bf47408

Please sign in to comment.