glpkg 1.0.0__py3-none-any.whl → 1.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
gitlab/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from gitlab.packages import Packages
2
2
 
3
- __version__ = "1.0.0"
3
+ __version__ = "1.1.0"
gitlab/cli_handler.py CHANGED
@@ -98,16 +98,20 @@ class CLIHandler:
98
98
  return host, project, name, token_user, token
99
99
 
100
100
  def _download_handler(self, args) -> int:
101
+ ret = 1
101
102
  host, project, name, token_user, token = self._args(args)
102
103
  version = args.version
103
104
  gitlab = Packages(host, token_user, token)
104
105
  package_id = gitlab.get_package_id(project, name, version)
105
- files = gitlab.list_files(project, package_id)
106
- ret = 1
107
- for file in files:
108
- ret = gitlab.download_file(project, name, version, file)
109
- if not ret:
110
- break
106
+ if package_id:
107
+ files = gitlab.list_files(project, package_id)
108
+ for file in files:
109
+ ret = gitlab.download_file(project, name, version, file)
110
+ if ret:
111
+ print("Failed to download file " + file)
112
+ break
113
+ else:
114
+ print("No package " + name + " version " + version + " found!")
111
115
  return ret
112
116
 
113
117
  def _register_list_parser(self, parser):
@@ -134,9 +138,13 @@ class CLIHandler:
134
138
  parser.set_defaults(action=self._upload)
135
139
 
136
140
  def _upload(self, args) -> int:
141
+ ret = 1
137
142
  host, project, name, token_user, token = self._args(args)
138
143
  version = args.version
139
144
  file = args.file
140
- gitlab = Packages(host, token_user, token)
141
- ret = gitlab.upload_file(project, name, version, file)
145
+ if os.path.isfile(file):
146
+ gitlab = Packages(host, token_user, token)
147
+ ret = gitlab.upload_file(project, name, version, file)
148
+ else:
149
+ print("File " + file + " does not exist!")
142
150
  return ret
gitlab/packages.py CHANGED
@@ -1,6 +1,10 @@
1
+ from http.client import HTTPMessage
1
2
  import json
3
+ import logging
2
4
  from urllib import request, parse
3
5
 
6
+ logger = logging.getLogger(__name__)
7
+
4
8
 
5
9
  class Packages:
6
10
  def __init__(self, host: str, token_type: str, token: str):
@@ -14,95 +18,123 @@ class Packages:
14
18
  def project_api_url(self, project: str) -> str:
15
19
  return self.api_url() + "projects/{}/".format(parse.quote_plus(project))
16
20
 
17
- def get_headers(self):
21
+ def get_headers(self) -> dict:
18
22
  headers = {}
19
23
  if self.token_type and self.token:
20
24
  headers = {self.token_type: self.token}
21
25
  return headers
22
26
 
27
+ def _request(self, url: str) -> tuple[int, bytes, HTTPMessage]:
28
+ logger.debug("Requesting " + url)
29
+ req = request.Request(url, headers=self.get_headers())
30
+ with request.urlopen(req) as response:
31
+ return response.status, response.read(), response.headers
32
+
33
+ def _get_next_page(self, headers: HTTPMessage) -> int:
34
+ ret = 0
35
+ if headers:
36
+ next_page = headers.get("x-next-page")
37
+ if next_page:
38
+ ret = int(next_page)
39
+ logger.debug("Response incomplete, next page is " + next_page)
40
+ else:
41
+ logger.debug("Response complete")
42
+ return ret
43
+
44
+ def _build_query(self, arg: str, page: int) -> str:
45
+ query = ""
46
+ if arg or page:
47
+ if page:
48
+ page = "page=" + str(page)
49
+ query = "?{}".format("&".join(filter(None, (arg, page))))
50
+ return query
51
+
52
+ def gl_project_api(self, project: str, path: str, arg: str = None) -> list:
53
+ data = []
54
+ more = True
55
+ page = None
56
+ while more:
57
+ more = False
58
+ query = self._build_query(arg, page)
59
+ url = self.project_api_url(project) + path + query
60
+ status, res_data, headers = self._request(url)
61
+ logger.debug("Response status: " + str(status))
62
+ res_data = json.loads(res_data)
63
+ logger.debug("Response data: " + str(res_data))
64
+ data = data + res_data
65
+ page = self._get_next_page(headers)
66
+ if page:
67
+ more = True
68
+ return data
69
+
23
70
  def list_packages(self, project: str, package_name: str) -> list:
24
71
  packages = []
25
- with request.urlopen(
26
- request.Request(
27
- self.project_api_url(project)
28
- + "packages?package_name="
29
- + parse.quote_plus(package_name),
30
- headers=self.get_headers(),
31
- )
32
- ) as res:
33
- data = res.read()
34
- for package in json.loads(data):
35
- name = parse.unquote(package["name"])
36
- version = parse.unquote(package["version"])
37
- # The GitLab API returns packages that have some match to the filter;
38
- # let's filter out non-exact matches
39
- if package_name != name:
40
- continue
41
- packages.append({"name": name, "version": version})
72
+ logger.debug("Listing packages with name " + package_name)
73
+ data = self.gl_project_api(
74
+ project, "packages", "package_name=" + parse.quote_plus(package_name)
75
+ )
76
+ for package in data:
77
+ name = parse.unquote(package["name"])
78
+ version = parse.unquote(package["version"])
79
+ # GitLab API returns packages that have some match to the filter;
80
+ # let's filter out non-exact matches
81
+ if package_name != name:
82
+ continue
83
+ packages.append({"name": name, "version": version})
42
84
  return packages
43
85
 
44
86
  def list_files(self, project: str, package_id: int) -> list:
45
87
  files = []
46
- with request.urlopen(
47
- request.Request(
48
- self.project_api_url(project)
49
- + "packages/"
50
- + parse.quote_plus(str(package_id))
51
- + "/package_files",
52
- headers=self.get_headers(),
53
- )
54
- ) as x:
55
- data = x.read()
56
- for package in json.loads(
57
- data,
58
- ):
59
- # Only append the filename once to the list of files
60
- # as there's no way to download them separately through
61
- # the API
62
- filename = parse.unquote(package["file_name"])
63
- if filename not in files:
64
- files.append(filename)
88
+ logger.debug("Listing package " + str(package_id) + " files")
89
+ path = "packages/" + parse.quote_plus(str(package_id)) + "/package_files"
90
+ data = self.gl_project_api(project, path)
91
+ for package in data:
92
+ # Only append the filename once to the list of files
93
+ # as there's no way to download them separately through
94
+ # the API
95
+ filename = parse.unquote(package["file_name"])
96
+ if filename not in files:
97
+ files.append(filename)
65
98
  return files
66
99
 
67
100
  def get_package_id(
68
101
  self, project: str, package_name: str, package_version: str
69
102
  ) -> int:
70
103
  id = 0
71
- with request.urlopen(
72
- request.Request(
73
- self.project_api_url(project)
74
- + "packages?package_name="
75
- + parse.quote_plus(package_name)
76
- + "&package_version="
77
- + parse.quote_plus(package_version),
78
- headers=self.get_headers(),
79
- )
80
- ) as res:
81
- data = res.read()
82
- package = json.loads(data)
83
- if len(package) == 1:
84
- package = package.pop()
85
- id = package["id"]
104
+ logger.debug(
105
+ "Fetching package " + package_name + " (" + package_version + ") ID"
106
+ )
107
+ path = "packages"
108
+ arg = (
109
+ "package_name="
110
+ + parse.quote_plus(package_name)
111
+ + "&package_version="
112
+ + parse.quote_plus(package_version)
113
+ )
114
+ data = self.gl_project_api(project, path, arg)
115
+ if len(data) == 1:
116
+ package = data.pop()
117
+ id = package["id"]
86
118
  return id
87
119
 
88
120
  def download_file(
89
121
  self, project: str, package_name: str, package_version: str, file: str
90
122
  ) -> int:
91
123
  ret = 1
92
- with request.urlopen(
93
- request.Request(
94
- self.project_api_url(project)
95
- + "packages/generic/"
96
- + parse.quote_plus(package_name)
97
- + "/"
98
- + parse.quote_plus(package_version)
99
- + "/"
100
- + parse.quote(str(file)),
101
- headers=self.get_headers(),
102
- )
103
- ) as req:
124
+ logger.debug("Downloading file " + file)
125
+ url = (
126
+ self.project_api_url(project)
127
+ + "packages/generic/"
128
+ + parse.quote_plus(package_name)
129
+ + "/"
130
+ + parse.quote_plus(package_version)
131
+ + "/"
132
+ + parse.quote(str(file))
133
+ )
134
+ status, data, _ = self._request(url)
135
+ if status == 200:
104
136
  with open(str(file), "wb") as file:
105
- file.write(req.read())
137
+ file.write(data)
106
138
  ret = 0
107
139
  return ret
108
140
 
@@ -110,21 +142,22 @@ class Packages:
110
142
  self, project: str, package_name: str, package_version: str, file: str
111
143
  ) -> int:
112
144
  ret = 1
145
+ logger.debug("Uploading file " + file)
113
146
  with open(str(file), "rb") as data:
147
+ url = (
148
+ self.project_api_url(project)
149
+ + "packages/generic/"
150
+ + parse.quote_plus(package_name)
151
+ + "/"
152
+ + parse.quote_plus(package_version)
153
+ + "/"
154
+ + parse.quote(str(file))
155
+ )
114
156
  res = request.urlopen(
115
157
  request.Request(
116
- self.project_api_url(project)
117
- + "packages/generic/"
118
- + parse.quote_plus(package_name)
119
- + "/"
120
- + parse.quote_plus(package_version)
121
- + "/"
122
- + parse.quote(str(file)),
123
- method="PUT",
124
- data=data,
125
- headers=self.get_headers(),
158
+ url, method="PUT", data=data, headers=self.get_headers()
126
159
  )
127
160
  )
128
- if res.getcode() == 201: # 201 is created
161
+ if res.status == 201: # 201 is created
129
162
  ret = 0
130
163
  return ret
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: glpkg
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Tool to make GitLab generic package registry operations easy.
5
5
  Author-email: bugproduction <bugproduction@outlook.com>
6
6
  License-Expression: MIT
@@ -124,4 +124,3 @@ The tool is not perfect (yet) and has limitations. The following limitations are
124
124
 
125
125
  - Uploading files must be done one-by-one.
126
126
  - Only project registries are supported for now.
127
- - Pagination is not supported for now - in case you have more than 100 versions of a package, not all will be shown.
@@ -0,0 +1,10 @@
1
+ gitlab/__init__.py,sha256=EsSFZxYgGAL2i0sL5zkoz71JP7XbsWdg_jv_uOqrrXE,60
2
+ gitlab/__main__.py,sha256=88VNY5Qrmn8g0rNcnjKNdN746--0chHsKBMH3PD3Nao,177
3
+ gitlab/cli_handler.py,sha256=6B22RXAtOzVL-mpm7U3OPX1_SSrepQk12cwTG0TI3eU,6102
4
+ gitlab/packages.py,sha256=l9tFEUsHMWF0vtv5ouVB4nvmWrJ4KDaS6f5e1lpjNyk,5683
5
+ glpkg-1.1.0.dist-info/licenses/LICENSE.md,sha256=josGXvZq628dNS0Iru58-DPE7dRpDXzjJxKKT35103g,1065
6
+ glpkg-1.1.0.dist-info/METADATA,sha256=65URv9IMuUo1XnmqKolpuJ12nkjcFKJg8rKMz4XeUIQ,5500
7
+ glpkg-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ glpkg-1.1.0.dist-info/entry_points.txt,sha256=xHPZwx2oShYDZ3AyH7WSIvuhFMssy7QLlQk-JAbje_w,46
9
+ glpkg-1.1.0.dist-info/top_level.txt,sha256=MvIaP8p_Oaf4gO_hXmHkX-5y2deHLp1pe6tJR3ukQ6o,7
10
+ glpkg-1.1.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- gitlab/__init__.py,sha256=BswgrGAgPCau63NFj5mRmAZRbCxBOyZ_sKX1YiLNTxA,60
2
- gitlab/__main__.py,sha256=88VNY5Qrmn8g0rNcnjKNdN746--0chHsKBMH3PD3Nao,177
3
- gitlab/cli_handler.py,sha256=xiLRqA33E0LdvuBSRW8Zn8O_chZX3-tY5umAitCue6Y,5786
4
- gitlab/packages.py,sha256=Aw2Zt3Ok1uA9K8p8kugP3vizvcAxFMDaTQTwC-HH_sI,4431
5
- glpkg-1.0.0.dist-info/licenses/LICENSE.md,sha256=josGXvZq628dNS0Iru58-DPE7dRpDXzjJxKKT35103g,1065
6
- glpkg-1.0.0.dist-info/METADATA,sha256=ujT2mqVYwD0aL9MH45jRwBG9qi8eHgwoiis9X2zzAdI,5617
7
- glpkg-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- glpkg-1.0.0.dist-info/entry_points.txt,sha256=xHPZwx2oShYDZ3AyH7WSIvuhFMssy7QLlQk-JAbje_w,46
9
- glpkg-1.0.0.dist-info/top_level.txt,sha256=MvIaP8p_Oaf4gO_hXmHkX-5y2deHLp1pe6tJR3ukQ6o,7
10
- glpkg-1.0.0.dist-info/RECORD,,
File without changes