import asyncio from typing import Any, List from harborapi import HarborAsyncClient class AccumulatingBuffer: def __init__(self, capacity: int): if capacity <= 0: raise ValueError("Capacity must be positive") self.capacity = capacity self.buf = [None] * capacity self.count = 0 # Фактически заполненные слоты def load(self, elements: List[Any]) -> None: """Добавляет элементы: в свободное место - в конец, при полном - перезапись с начала""" L = len(elements) if L > self.capacity: raise IndexError(f"Elements ({L}) exceed capacity ({self.capacity})") if self.count + L <= self.capacity: # Есть свободное место - добавляем в конец for i, elem in enumerate(elements): self.buf[self.count + i] = elem self.count += L # Затираем оставшееся место for i in range(self.count, self.capacity): self.buf[i] = None else: # Буфер полон - перезаписываем с начала for i, elem in enumerate(elements): self.buf[i] = elem self.count = L # Затираем остаток for i in range(L, self.capacity): self.buf[i] = None def get_filled(self) -> List[Any]: """Возвращает только непустые элементы""" return [x for x in self.buf[: self.count] if x is not None] def size(self) -> int: return self.count def filled_size(self) -> int: return len(self.get_filled()) def free_space(self) -> int: return self.capacity - self.count from itertools import islice def chunks(lst, n): iterator = iter(lst) return list(iter(lambda: list(islice(iterator, n)), [])) async def get_artifacts( client: HarborAsyncClient, project_name: str, repository_name: str, page_number: int, page_size: int, ): # номер страницы с артефактами в Harbor harbor_page_number = 1 # номер страницы с артефактами в RIM rim_page_number = 1 # выделяем буфер под "страницу" артефактов artifacts_page_buffer = AccumulatingBuffer(page_size) # начинаем считываение while True: # считываем из Harbor артефакты и загружаем их в буфер artifacts = await client.get_artifacts( project_name=project_name, repository_name=repository_name, page=harbor_page_number, page_size=10, limit=10, ) for artifact in artifacts: # массив тэгов tags = [] # если есть тэги if artifact.tags: # перебираем все ссылки на тэги for tag_reference in artifact.tags: # формируем имя artifact_name = ( f"{project_name}/{repository_name}:{tag_reference.name}" ) # засовываем в список tags.append(artifact_name) print(f"Tags {tags}") print(f"Buffer: {artifacts_page_buffer.get_filled()}") print(f"RIM page number: {rim_page_number}") # режем на порции for portion in chunks(tags, page_size): # если достигли нужной страницы или получили пустышку от Harbor if rim_page_number == page_number: # возвращаем страницы return artifacts_page_buffer.get_filled() # буфер страницы заполняется artifacts_page_buffer.load(portion) # если в накопителе тэгов не исчерпались элементы if artifacts_page_buffer.filled_size() == page_size: # увеличиваем счетчик страниц RIM rim_page_number += 1 # исчерпали все артефакты if len(artifacts) == 0: return artifacts_page_buffer.get_filled() # увеличиваем счетчик страниц Harbor harbor_page_number += 1 async def main(): registry_url = "-" registry_login = "-" registry_password = "-" client = HarborAsyncClient( url=registry_url + "/api/v2.0", username=registry_login, secret=registry_password, # ограничение по количеству количества записей о соединениях хранимых клиентом max_logs=0, verify=False, # TODO: remove them ? ) rbuf = AccumulatingBuffer(10) rbuf.load([]) print(rbuf.get_filled()) rbuf.load([1, 2, 3, 4, 5, 6, 7, 8, 9]) print(rbuf.get_filled()) rbuf.load([1, 2, 3, 4]) print(rbuf.get_filled()) # tests project_name = "sbis-hlha" repository_name = "charts/sbis-docker-dispatcher" artifacts = await get_artifacts(client, project_name, repository_name, 1, 21) print(artifacts) print(len(artifacts)) if __name__ == "__main__": asyncio.run(main())