| @@ -53,8 +53,8 @@ from itertools import islice | |||
| 53 | 53 | ||
| 54 | 54 | ||
| 55 | 55 | def chunks(lst, n): | |
| 56 | - | iterator = iter(lst) | |
| 57 | - | return list(iter(lambda: list(islice(iterator, n)), [])) | |
| 56 | + | for i in range(0, len(lst), n): | |
| 57 | + | yield lst[i : i + n] # Генератор вместо списка | |
| 58 | 58 | ||
| 59 | 59 | ||
| 60 | 60 | async def get_artifacts( | |
| @@ -80,6 +80,14 @@ async def get_artifacts( | |||
| 80 | 80 | page_size=10, | |
| 81 | 81 | limit=10, | |
| 82 | 82 | ) | |
| 83 | + | ||
| 84 | + | # нет артефактов | |
| 85 | + | if not artifacts: | |
| 86 | + | # если страница была неполной, то возвращаем результат | |
| 87 | + | if rim_page_number == page_number: | |
| 88 | + | return artifacts_page_buffer.get_filled() | |
| 89 | + | break | |
| 90 | + | ||
| 83 | 91 | for artifact in artifacts: | |
| 84 | 92 | # массив тэгов | |
| 85 | 93 | tags = [] | |
| @@ -93,26 +101,28 @@ async def get_artifacts( | |||
| 93 | 101 | ) | |
| 94 | 102 | # засовываем в список | |
| 95 | 103 | tags.append(artifact_name) | |
| 96 | - | print(f"Tags {tags}") | |
| 97 | - | print(f"Buffer: {artifacts_page_buffer.get_filled()}") | |
| 98 | - | print(f"RIM page number: {rim_page_number}") | |
| 99 | - | # режем на порции | |
| 104 | + | # print(f"Tags {tags}") | |
| 105 | + | # print(f"Buffer: {artifacts_page_buffer.get_filled()}") | |
| 106 | + | # print( | |
| 107 | + | # f"RIM page number: {rim_page_number}, length: {len(artifacts_page_buffer.get_filled())}" | |
| 108 | + | # ) | |
| 100 | 109 | for portion in chunks(tags, page_size): | |
| 101 | - | # если достигли нужной страницы или получили пустышку от Harbor | |
| 102 | - | if rim_page_number == page_number: | |
| 103 | - | # возвращаем страницы | |
| 104 | - | return artifacts_page_buffer.get_filled() | |
| 105 | - | # буфер страницы заполняется | |
| 110 | + | # загружаем порцию в буфер | |
| 106 | 111 | artifacts_page_buffer.load(portion) | |
| 107 | - | # если в накопителе тэгов не исчерпались элементы | |
| 108 | - | if artifacts_page_buffer.filled_size() == page_size: | |
| 109 | - | # увеличиваем счетчик страниц RIM | |
| 112 | + | # Проверяем после каждой порции | |
| 113 | + | if ( | |
| 114 | + | artifacts_page_buffer.filled_size() >= page_size | |
| 115 | + | and rim_page_number == page_number | |
| 116 | + | ): | |
| 117 | + | return artifacts_page_buffer.get_filled() | |
| 118 | + | # Считаем полные страницы RIM | |
| 119 | + | if artifacts_page_buffer.filled_size() >= page_size: | |
| 120 | + | # увеличиваем счетчик страниц в RIM | |
| 110 | 121 | rim_page_number += 1 | |
| 111 | - | # исчерпали все артефакты | |
| 112 | - | if len(artifacts) == 0: | |
| 113 | - | return artifacts_page_buffer.get_filled() | |
| 114 | 122 | # увеличиваем счетчик страниц Harbor | |
| 115 | 123 | harbor_page_number += 1 | |
| 124 | + | # не страниц, или указана несуществующая страница | |
| 125 | + | return [] | |
| 116 | 126 | ||
| 117 | 127 | ||
| 118 | 128 | async def main(): | |
| @@ -135,12 +145,18 @@ async def main(): | |||
| 135 | 145 | rbuf.load([1, 2, 3, 4]) | |
| 136 | 146 | print(rbuf.get_filled()) | |
| 137 | 147 | # tests | |
| 138 | - | project_name = "sbis-hlha" | |
| 139 | - | repository_name = "charts/sbis-docker-dispatcher" | |
| 140 | - | artifacts = await get_artifacts(client, project_name, repository_name, 1, 21) | |
| 141 | - | print(artifacts) | |
| 142 | - | print(len(artifacts)) | |
| 148 | + | # project_name = "sbis-hlha" | |
| 149 | + | # repository_name = "charts/sbis-docker-dispatcher" | |
| 150 | + | project_name = "corp-base" | |
| 151 | + | repository_name = "platform/centos" | |
| 152 | + | artifacts1 = set(await get_artifacts(client, project_name, repository_name, 1, 6)) | |
| 153 | + | print(artifacts1) | |
| 154 | + | print(len(artifacts1)) | |
| 155 | + | artifacts2 = set(await get_artifacts(client, project_name, repository_name, 2, 6)) | |
| 156 | + | print(artifacts2) | |
| 157 | + | print(len(artifacts2)) | |
| 158 | + | print(artifacts1 - artifacts2) | |
| 143 | 159 | ||
| 144 | 160 | ||
| 145 | 161 | if __name__ == "__main__": | |
| 146 | - | asyncio.run(main()) | |
| 162 | + | asyncio.run(main()) | |
aquafire / harbor_paginate.py
Last active 6 months ago
aquafire revised this gist 10 months ago · b410cc2
1 file changed, 39 insertions, 23 deletions
aquafire revised this gist 10 months ago · 408bdab
1 file changed, 146 insertions
| @@ -0,0 +1,146 @@ | |||
| 1 | + | import asyncio | |
| 2 | + | from typing import Any, List | |
| 3 | + | ||
| 4 | + | from harborapi import HarborAsyncClient | |
| 5 | + | ||
| 6 | + | ||
| 7 | + | class AccumulatingBuffer: | |
| 8 | + | def __init__(self, capacity: int): | |
| 9 | + | if capacity <= 0: | |
| 10 | + | raise ValueError("Capacity must be positive") | |
| 11 | + | self.capacity = capacity | |
| 12 | + | self.buf = [None] * capacity | |
| 13 | + | self.count = 0 # Фактически заполненные слоты | |
| 14 | + | ||
| 15 | + | def load(self, elements: List[Any]) -> None: | |
| 16 | + | """Добавляет элементы: в свободное место - в конец, при полном - перезапись с начала""" | |
| 17 | + | L = len(elements) | |
| 18 | + | if L > self.capacity: | |
| 19 | + | raise IndexError(f"Elements ({L}) exceed capacity ({self.capacity})") | |
| 20 | + | ||
| 21 | + | if self.count + L <= self.capacity: | |
| 22 | + | # Есть свободное место - добавляем в конец | |
| 23 | + | for i, elem in enumerate(elements): | |
| 24 | + | self.buf[self.count + i] = elem | |
| 25 | + | self.count += L | |
| 26 | + | # Затираем оставшееся место | |
| 27 | + | for i in range(self.count, self.capacity): | |
| 28 | + | self.buf[i] = None | |
| 29 | + | else: | |
| 30 | + | # Буфер полон - перезаписываем с начала | |
| 31 | + | for i, elem in enumerate(elements): | |
| 32 | + | self.buf[i] = elem | |
| 33 | + | self.count = L | |
| 34 | + | # Затираем остаток | |
| 35 | + | for i in range(L, self.capacity): | |
| 36 | + | self.buf[i] = None | |
| 37 | + | ||
| 38 | + | def get_filled(self) -> List[Any]: | |
| 39 | + | """Возвращает только непустые элементы""" | |
| 40 | + | return [x for x in self.buf[: self.count] if x is not None] | |
| 41 | + | ||
| 42 | + | def size(self) -> int: | |
| 43 | + | return self.count | |
| 44 | + | ||
| 45 | + | def filled_size(self) -> int: | |
| 46 | + | return len(self.get_filled()) | |
| 47 | + | ||
| 48 | + | def free_space(self) -> int: | |
| 49 | + | return self.capacity - self.count | |
| 50 | + | ||
| 51 | + | ||
| 52 | + | from itertools import islice | |
| 53 | + | ||
| 54 | + | ||
| 55 | + | def chunks(lst, n): | |
| 56 | + | iterator = iter(lst) | |
| 57 | + | return list(iter(lambda: list(islice(iterator, n)), [])) | |
| 58 | + | ||
| 59 | + | ||
| 60 | + | async def get_artifacts( | |
| 61 | + | client: HarborAsyncClient, | |
| 62 | + | project_name: str, | |
| 63 | + | repository_name: str, | |
| 64 | + | page_number: int, | |
| 65 | + | page_size: int, | |
| 66 | + | ): | |
| 67 | + | # номер страницы с артефактами в Harbor | |
| 68 | + | harbor_page_number = 1 | |
| 69 | + | # номер страницы с артефактами в RIM | |
| 70 | + | rim_page_number = 1 | |
| 71 | + | # выделяем буфер под "страницу" артефактов | |
| 72 | + | artifacts_page_buffer = AccumulatingBuffer(page_size) | |
| 73 | + | # начинаем считываение | |
| 74 | + | while True: | |
| 75 | + | # считываем из Harbor артефакты и загружаем их в буфер | |
| 76 | + | artifacts = await client.get_artifacts( | |
| 77 | + | project_name=project_name, | |
| 78 | + | repository_name=repository_name, | |
| 79 | + | page=harbor_page_number, | |
| 80 | + | page_size=10, | |
| 81 | + | limit=10, | |
| 82 | + | ) | |
| 83 | + | for artifact in artifacts: | |
| 84 | + | # массив тэгов | |
| 85 | + | tags = [] | |
| 86 | + | # если есть тэги | |
| 87 | + | if artifact.tags: | |
| 88 | + | # перебираем все ссылки на тэги | |
| 89 | + | for tag_reference in artifact.tags: | |
| 90 | + | # формируем имя | |
| 91 | + | artifact_name = ( | |
| 92 | + | f"{project_name}/{repository_name}:{tag_reference.name}" | |
| 93 | + | ) | |
| 94 | + | # засовываем в список | |
| 95 | + | tags.append(artifact_name) | |
| 96 | + | print(f"Tags {tags}") | |
| 97 | + | print(f"Buffer: {artifacts_page_buffer.get_filled()}") | |
| 98 | + | print(f"RIM page number: {rim_page_number}") | |
| 99 | + | # режем на порции | |
| 100 | + | for portion in chunks(tags, page_size): | |
| 101 | + | # если достигли нужной страницы или получили пустышку от Harbor | |
| 102 | + | if rim_page_number == page_number: | |
| 103 | + | # возвращаем страницы | |
| 104 | + | return artifacts_page_buffer.get_filled() | |
| 105 | + | # буфер страницы заполняется | |
| 106 | + | artifacts_page_buffer.load(portion) | |
| 107 | + | # если в накопителе тэгов не исчерпались элементы | |
| 108 | + | if artifacts_page_buffer.filled_size() == page_size: | |
| 109 | + | # увеличиваем счетчик страниц RIM | |
| 110 | + | rim_page_number += 1 | |
| 111 | + | # исчерпали все артефакты | |
| 112 | + | if len(artifacts) == 0: | |
| 113 | + | return artifacts_page_buffer.get_filled() | |
| 114 | + | # увеличиваем счетчик страниц Harbor | |
| 115 | + | harbor_page_number += 1 | |
| 116 | + | ||
| 117 | + | ||
| 118 | + | async def main(): | |
| 119 | + | registry_url = "-" | |
| 120 | + | registry_login = "-" | |
| 121 | + | registry_password = "-" | |
| 122 | + | client = HarborAsyncClient( | |
| 123 | + | url=registry_url + "/api/v2.0", | |
| 124 | + | username=registry_login, | |
| 125 | + | secret=registry_password, | |
| 126 | + | # ограничение по количеству количества записей о соединениях хранимых клиентом | |
| 127 | + | max_logs=0, | |
| 128 | + | verify=False, # TODO: remove them ? | |
| 129 | + | ) | |
| 130 | + | rbuf = AccumulatingBuffer(10) | |
| 131 | + | rbuf.load([]) | |
| 132 | + | print(rbuf.get_filled()) | |
| 133 | + | rbuf.load([1, 2, 3, 4, 5, 6, 7, 8, 9]) | |
| 134 | + | print(rbuf.get_filled()) | |
| 135 | + | rbuf.load([1, 2, 3, 4]) | |
| 136 | + | print(rbuf.get_filled()) | |
| 137 | + | # tests | |
| 138 | + | project_name = "sbis-hlha" | |
| 139 | + | repository_name = "charts/sbis-docker-dispatcher" | |
| 140 | + | artifacts = await get_artifacts(client, project_name, repository_name, 1, 21) | |
| 141 | + | print(artifacts) | |
| 142 | + | print(len(artifacts)) | |
| 143 | + | ||
| 144 | + | ||
| 145 | + | if __name__ == "__main__": | |
| 146 | + | asyncio.run(main()) | |