c2cciutils 1.8.0.dev63__py3-none-any.whl → 1.8.0.dev68__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.

Potentially problematic release.


This version of c2cciutils might be problematic. Click here for more details.

c2cciutils/publish.py DELETED
@@ -1,451 +0,0 @@
1
- """The publishing functions."""
2
-
3
- import argparse
4
- import datetime
5
- import glob
6
- import os
7
- import pickle # nosec
8
- import re
9
- import subprocess # nosec
10
- import sys
11
- import uuid
12
- from typing import Optional
13
-
14
- import ruamel.yaml
15
- import tomllib
16
- from google.auth.transport.requests import Request
17
- from google.oauth2.credentials import Credentials
18
- from google_auth_oauthlib.flow import InstalledAppFlow
19
- from googleapiclient.discovery import build
20
-
21
- import c2cciutils.configuration
22
-
23
-
24
- class GoogleCalendar:
25
- """Interact with the Google Calendar API."""
26
-
27
- # pylint: disable=too-many-instance-attributes
28
- def __init__(self) -> None:
29
- """Initialize."""
30
- self.scopes = ["https://www.googleapis.com/auth/calendar"] # in fact it is better to hard-code this
31
- self.credentials_pickle_file = os.environ.get("TMP_CREDS_FILE", f"/tmp/{uuid.uuid4()}.pickle") # noqa: S108 # nosec
32
- self.credentials_json_file = os.environ.get(
33
- "GOOGLE_CREDS_JSON_FILE", "~/google-credentials-c2cibot.json"
34
- ) # used to refresh the refresh_token or to initialize the credentials the first time
35
- self.calendar_id = os.environ.get(
36
- "GOOGLE_CALENDAR_ID", c2cciutils.gopass("gs/ci/google_calendar/calendarId")
37
- )
38
- self.token = os.environ.get("GOOGLE_TOKEN", c2cciutils.gopass("gs/ci/google_calendar/token"))
39
- self.token_uri = os.environ.get(
40
- "GOOGLE_TOKEN_URI", c2cciutils.gopass("gs/ci/google_calendar/token_uri")
41
- )
42
- self.refresh_token = os.environ.get(
43
- "GOOGLE_REFRESH_TOKEN",
44
- c2cciutils.gopass("gs/ci/google_calendar/refresh_token"),
45
- )
46
- self.client_id = os.environ.get(
47
- "GOOGLE_CLIENT_ID", c2cciutils.gopass("gs/ci/google_calendar/client_id")
48
- )
49
- self.client_secret = os.environ.get(
50
- "GOOGLE_CLIENT_SECRET",
51
- c2cciutils.gopass("gs/ci/google_calendar/client_secret"),
52
- )
53
-
54
- self.creds: Credentials = self.init_calendar_service()
55
- self._update_creds()
56
- self.service = build("calendar", "v3", credentials=self.creds)
57
-
58
- def init_calendar_service(self) -> Credentials: # type: ignore
59
- """Initialize the calendar service."""
60
- # The file token pickle stores the user's access and refresh tokens, and is
61
- # created automatically when the authorization flow completes for the first
62
- # time.
63
- if os.path.exists(self.credentials_pickle_file):
64
- with open(self.credentials_pickle_file, "rb") as token:
65
- creds = pickle.load(token) # noqa: S301 # nosec
66
- # If there are no (valid) credentials available, let the user log in.
67
- if not creds or not creds.valid: # pylint: disable=possibly-used-before-assignment
68
- if creds and creds.expired and creds.refresh_token:
69
- creds.refresh(Request()) # type: ignore
70
- else:
71
- if self.token:
72
- creds = Credentials( # type: ignore
73
- self.token,
74
- refresh_token=self.refresh_token,
75
- token_uri=self.token_uri,
76
- client_id=self.client_id,
77
- client_secret=self.client_secret,
78
- scopes=self.scopes,
79
- )
80
- else:
81
- flow = InstalledAppFlow.from_client_secrets_file(self.credentials_json_file, self.scopes)
82
- creds = flow.run_local_server(port=0)
83
- self.refresh_token = creds
84
-
85
- # Save the credentials for the next run
86
- with open(self.credentials_pickle_file, "wb") as token:
87
- pickle.dump(creds, token)
88
-
89
- def _update_creds(self) -> None:
90
- """Update the credentials."""
91
- self.client_id = self.creds.client_id
92
- self.client_secret = self.creds.client_secret
93
- self.token = self.creds.token
94
- self.token_uri = self.creds.token_uri
95
- self.refresh_token = self.creds.refresh_token
96
-
97
- def print_all_calendars(self) -> None:
98
- """Print all calendar events."""
99
- # list all the calendars that the user has access to.
100
- # used to debug credentials
101
- print("Getting list of calendars")
102
- calendars_result = self.service.calendarList().list().execute() # pylint: disable=no-member
103
-
104
- calendars = calendars_result.get("items", [])
105
-
106
- if not calendars:
107
- print("::error::No calendars found.")
108
- for calendar in calendars:
109
- summary = calendar["summary"]
110
- event_id = calendar["id"]
111
- primary = "Primary" if calendar.get("primary") else ""
112
- print(f"{summary}\t{event_id}\t{primary}")
113
-
114
- def print_latest_events(self, time_min: Optional[datetime.datetime] = None) -> None:
115
- """
116
- Print latest events.
117
-
118
- Arguments:
119
- time_min: The time to be considered.
120
-
121
- """
122
- now = datetime.datetime.utcnow()
123
- if not time_min:
124
- time_min = datetime.datetime.utcnow() - datetime.timedelta(days=30)
125
- events_result = (
126
- self.service.events() # pylint: disable=no-member
127
- .list(
128
- calendarId=self.calendar_id,
129
- timeMin=time_min.isoformat() + "Z",
130
- timeMax=now.isoformat() + "Z",
131
- singleEvents=True,
132
- orderBy="startTime",
133
- )
134
- .execute()
135
- )
136
- events = events_result.get("items", [])
137
-
138
- if not events:
139
- print("::error::No upcoming events found.")
140
- for event in events:
141
- start = event["start"].get("dateTime", event["start"].get("date"))
142
- print(start, event["summary"])
143
-
144
- def create_event(
145
- self,
146
- summary: str = f"dummy/image:{datetime.datetime.now().isoformat()}",
147
- description: str = "description",
148
- ) -> None:
149
- """
150
- Create a calendar event.
151
-
152
- Arguments:
153
- summary: The event summary
154
- description: The event description
155
-
156
- """
157
- now = datetime.datetime.now()
158
- start = now.isoformat()
159
- end = (now + datetime.timedelta(minutes=15)).isoformat()
160
- body = {
161
- "summary": summary,
162
- "description": description,
163
- "start": {"dateTime": start, "timeZone": "Europe/Zurich"},
164
- "end": {"dateTime": end, "timeZone": "Europe/Zurich"},
165
- }
166
-
167
- event_result = self.service.events().insert(calendarId=self.calendar_id, body=body).execute() # pylint: disable=no-member
168
- print(f"Created event with id: {event_result['id']}")
169
-
170
- def save_credentials_to_gopass(self) -> None:
171
- """Save the calendar credentials to gopass."""
172
- objects_to_save = {
173
- "gs/ci/google_calendar/calendarId": self.calendar_id,
174
- "gs/ci/google_calendar/token": self.token,
175
- "gs/ci/google_calendar/token_uri": self.token_uri,
176
- "gs/ci/google_calendar/refresh_token": self.refresh_token,
177
- "gs/ci/google_calendar/client_id": self.client_id,
178
- "gs/ci/google_calendar/client_secret": self.client_secret,
179
- }
180
- for key, secret in objects_to_save.items():
181
- assert secret is not None
182
- c2cciutils.gopass_put(secret, key)
183
-
184
- def __del__(self) -> None:
185
- """Delete the credentials file."""
186
- if os.path.exists(self.credentials_pickle_file):
187
- os.remove(self.credentials_pickle_file)
188
-
189
-
190
- def main_calendar() -> None:
191
- """Run the calendar main function."""
192
- parser = argparse.ArgumentParser(
193
- description="Interact with google API for the Docker publishing calendar"
194
- )
195
- parser.add_argument(
196
- "--refresh-gopass-credentials",
197
- action="store_true",
198
- help="Refresh the credentials in gopass using google API",
199
- )
200
- parser.add_argument(
201
- "--show-events-since",
202
- help="show the calendar events since a date in 'YYYY-mm-dd' format",
203
- type=lambda s: datetime.datetime.strptime(s, "%Y-%m-%d"),
204
- )
205
- parser.add_argument(
206
- "--create-test-event",
207
- action="store_true",
208
- help="Create a dummy event to check that the calendar settings are correct",
209
- )
210
- args = parser.parse_args()
211
-
212
- if args.show_events_since or args.refresh_gopass_credentials or args.create_test_event:
213
- google_calendar = GoogleCalendar()
214
- else:
215
- parser.print_help()
216
-
217
- if args.show_events_since:
218
- google_calendar.print_latest_events( # pylint: disable=possibly-used-before-assignment
219
- args.show_events_since
220
- )
221
-
222
- if args.refresh_gopass_credentials:
223
- google_calendar.save_credentials_to_gopass()
224
-
225
- if args.create_test_event:
226
- google_calendar.create_event()
227
-
228
-
229
- def pip(
230
- package: c2cciutils.configuration.PublishPypiPackage, version: str, version_type: str, publish: bool
231
- ) -> bool:
232
- """
233
- Publish to pypi.
234
-
235
- Arguments:
236
- version: The version that will be published
237
- version_type: Describe the kind of release we do: rebuild (specified using --type), version_tag,
238
- version_branch, feature_branch, feature_tag (for pull request)
239
- publish: If False only check the package
240
- package: The package configuration
241
-
242
- """
243
- print(f"::group::{'Publishing' if publish else 'Checking'} '{package.get('path')}' to pypi")
244
- sys.stdout.flush()
245
- sys.stderr.flush()
246
-
247
- try:
248
- env = {}
249
- env["VERSION"] = version
250
- env["VERSION_TYPE"] = version_type
251
- full_repo = c2cciutils.get_repository()
252
- full_repo_split = full_repo.split("/")
253
- master_branch, _ = c2cciutils.get_master_branch(full_repo_split)
254
- is_master = master_branch == version
255
- env["IS_MASTER"] = "TRUE" if is_master else "FALSE"
256
-
257
- cwd = os.path.abspath(package.get("path", "."))
258
-
259
- dist = os.path.join(cwd, "dist")
260
- if not os.path.exists(dist):
261
- os.mkdir(dist)
262
- if os.path.exists(os.path.join(cwd, "setup.py")):
263
- cmd = ["python3", "./setup.py", "egg_info", "--no-date"]
264
- cmd += (
265
- ["--tag-build=dev" + datetime.datetime.now().strftime("%Y%m%d%H%M%S")]
266
- if version_type in ("version_branch", "rebuild")
267
- else []
268
- )
269
- cmd.append("bdist_wheel")
270
- else:
271
- if not os.path.exists(dist):
272
- os.mkdir(dist)
273
- cmd = ["pip", "wheel", "--no-deps", "--wheel-dir=dist", "."]
274
- if os.path.exists(os.path.join(cwd, "pyproject.toml")):
275
- use_poetry = False
276
- if "build_command" not in package:
277
- with open(os.path.join(cwd, "pyproject.toml"), "rb") as project_file:
278
- pyproject = tomllib.load(project_file)
279
- re_splitter = re.compile(r"[<>=]+")
280
- for requirement in pyproject.get("build-system", {}).get("requires", []):
281
- requirement_split = re_splitter.split(requirement)
282
- if requirement_split[0] in ("poetry", "poetry-core"):
283
- use_poetry = True
284
- break
285
- subprocess.run(
286
- ["pip", "install", *pyproject.get("build-system", {}).get("requires", [])], check=True
287
- )
288
- if use_poetry:
289
- freeze = subprocess.run(["pip", "freeze"], check=True, stdout=subprocess.PIPE)
290
- for freeze_line in freeze.stdout.decode("utf-8").split("\n"):
291
- if freeze_line.startswith("poetry-") or freeze_line.startswith("poetry="):
292
- print(freeze_line)
293
- env_bash = " ".join([f"{key}={value}" for key, value in env.items()])
294
- print(f"Run in {cwd}: {env_bash} poetry build")
295
- sys.stdout.flush()
296
- sys.stderr.flush()
297
- subprocess.run(["poetry", "build"], cwd=cwd, env={**os.environ, **env}, check=True)
298
- cmd = []
299
- if cmd:
300
- cmd = package.get("build_command", cmd)
301
- subprocess.check_call(cmd, cwd=cwd, env=env)
302
- cmd = ["twine"]
303
- cmd += ["upload", "--verbose", "--disable-progress-bar"] if publish else ["check"]
304
- cmd += glob.glob(os.path.join(cwd, "dist/*.whl"))
305
- cmd += glob.glob(os.path.join(cwd, "dist/*.tar.gz"))
306
- subprocess.check_call(cmd)
307
- print("::endgroup::")
308
- except subprocess.CalledProcessError as exception:
309
- print(f"Error: {exception}")
310
- print("::endgroup::")
311
- print("::error::With error")
312
- return False
313
- return True
314
-
315
-
316
- def docker(
317
- config: c2cciutils.configuration.PublishDockerRepository,
318
- name: str,
319
- image_config: c2cciutils.configuration.PublishDockerImage,
320
- tag_src: str,
321
- dst_tags: list[str],
322
- images_full: list[str],
323
- ) -> bool:
324
- """
325
- Publish to a Docker registry.
326
-
327
- config is like:
328
- server: # The server fqdn
329
-
330
- image_config is like:
331
- name: # The image name
332
-
333
- Arguments:
334
- config: The publishing config
335
- name: The repository name, just used to print messages
336
- image_config: The image config
337
- tag_src: The source tag (usually latest)
338
- dst_tags: Publish using the provided tags
339
- images_full: The list of published images (with tag), used to build the dispatch event
340
-
341
- """
342
- print(
343
- f"::group::Publishing {image_config['name']} to the server {name} using the tags {', '.join(dst_tags)}"
344
- )
345
- sys.stdout.flush()
346
- sys.stderr.flush()
347
-
348
- try:
349
- new_images_full = []
350
- if "server" in config:
351
- for tag in dst_tags:
352
- subprocess.run(
353
- [
354
- "docker",
355
- "tag",
356
- f"{image_config['name']}:{tag_src}",
357
- f"{config['server']}/{image_config['name']}:{tag}",
358
- ],
359
- check=True,
360
- )
361
- new_images_full.append(f"{config['server']}/{image_config['name']}:{tag}")
362
- else:
363
- for tag in dst_tags:
364
- if tag_src != tag:
365
- subprocess.run(
366
- [
367
- "docker",
368
- "tag",
369
- f"{image_config['name']}:{tag_src}",
370
- f"{image_config['name']}:{tag}",
371
- ],
372
- check=True,
373
- )
374
- new_images_full.append(f"{image_config['name']}:{tag}")
375
-
376
- for image in new_images_full:
377
- subprocess.run(["docker", "push", image], check=True)
378
- images_full += new_images_full
379
-
380
- print("::endgroup::")
381
- except subprocess.CalledProcessError as exception:
382
- print(f"Error: {exception}")
383
- print("::endgroup::")
384
- print("::error::With error")
385
- return False
386
- return True
387
-
388
-
389
- def helm(folder: str, version: str, owner: str, repo: str, commit_sha: str, token: str) -> bool:
390
- """
391
- Publish to pypi.
392
-
393
- Arguments:
394
- folder: The folder to be published
395
- version: The version that will be published
396
- owner: The GitHub repository owner
397
- repo: The GitHub repository name
398
- commit_sha: The sha of the current commit
399
- token: The GitHub token
400
-
401
- """
402
- print(f"::group::Publishing Helm chart from '{folder}' to GitHub release")
403
- sys.stdout.flush()
404
- sys.stderr.flush()
405
-
406
- try:
407
- yaml_ = ruamel.yaml.YAML()
408
- with open(os.path.join(folder, "Chart.yaml"), encoding="utf-8") as open_file:
409
- chart = yaml_.load(open_file)
410
- chart["version"] = version
411
- with open(os.path.join(folder, "Chart.yaml"), "w", encoding="utf-8") as open_file:
412
- yaml_.dump(chart, open_file)
413
- for index, dependency in enumerate(chart.get("dependencies", [])):
414
- if dependency["repository"].startswith("https://"):
415
- subprocess.run(["helm", "repo", "add", str(index), dependency["repository"]], check=True)
416
-
417
- subprocess.run(["cr", "package", folder], check=True)
418
- subprocess.run(
419
- [
420
- "cr",
421
- "upload",
422
- f"--owner={owner}",
423
- f"--git-repo={repo}",
424
- f"--commit={commit_sha}",
425
- "--release-name-template={{ .Version }}",
426
- f"--token={token}",
427
- ],
428
- check=True,
429
- )
430
- if not os.path.exists(".cr-index"):
431
- os.mkdir(".cr-index")
432
- subprocess.run(
433
- [
434
- "cr",
435
- "index",
436
- f"--owner={owner}",
437
- f"--git-repo={repo}",
438
- f"--charts-repo=https://{owner}.github.io/{repo}",
439
- "--push",
440
- "--release-name-template={{ .Version }}",
441
- f"--token={token}",
442
- ],
443
- check=True,
444
- )
445
- print("::endgroup::")
446
- except subprocess.CalledProcessError as exception:
447
- print(f"Error: {exception}")
448
- print("::endgroup::")
449
- print("::error::With error")
450
- return False
451
- return True
@@ -1,50 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema",
3
- "$id": "https://raw.githubusercontent.com/camptocamp/tilecloud-chain/master/tilecloud_chain/schema.json",
4
- "title": "Applications configuration",
5
- "description": "All the applications configuration",
6
- "type": "object",
7
- "definitions": {},
8
- "additionalProperties": {
9
- "title": "Application configuration",
10
- "description": "An application configuration",
11
- "type": "object",
12
- "properties": {
13
- "url-pattern": {
14
- "title": "URL pattern",
15
- "description": "URL pattern, to be used for files that didn't come from GitHub release, available arguments: {version}",
16
- "type": "string"
17
- },
18
- "type": {
19
- "title": "The type of file",
20
- "description": "The type of file",
21
- "type": "string",
22
- "enum": ["tar"]
23
- },
24
- "get-file-name": {
25
- "title": "The filename to get",
26
- "description": "The name of the file to get in the GitHub release",
27
- "type": "string"
28
- },
29
- "to-file-name": {
30
- "title": "The created tile name",
31
- "description": "The name of the final tile we will create",
32
- "type": "string"
33
- },
34
- "tar-file-name": {
35
- "title": "The tile name to get in the tar file",
36
- "type": "string"
37
- },
38
- "finish-commands": {
39
- "title": "The commands to run after the tile creation",
40
- "type": "array",
41
- "items": {
42
- "type": "array",
43
- "items": {
44
- "type": "string"
45
- }
46
- }
47
- }
48
- }
49
- }
50
- }
@@ -1,103 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """The clean main function."""
4
-
5
- import argparse
6
- import json
7
- import os
8
- import sys
9
- from typing import cast
10
-
11
- import requests
12
- import yaml
13
-
14
- import c2cciutils
15
-
16
-
17
- def clean(image: str, tag: str, token: str) -> None:
18
- """
19
- Delete an image from Docker hub.
20
-
21
- Arguments:
22
- image: The image name that should be deleted (<organization>/<name>)
23
- tag: The tag that should be deleted
24
- token: The token used to be authenticated on Docker hub
25
-
26
- """
27
- print(f"Delete image '{image}:{tag}'.")
28
-
29
- response = requests.head(
30
- f"https://hub.docker.com/v2/repositories/{image}/tags/{tag}/",
31
- headers={"Authorization": "JWT " + token},
32
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
33
- )
34
- if response.status_code == 404:
35
- return
36
- if not response.ok:
37
- print(f"Error checking image '{image}:{tag}' status.")
38
- print(response.text)
39
- sys.exit(1)
40
-
41
- response = requests.delete(
42
- f"https://hub.docker.com/v2/repositories/{image}/tags/{tag}/",
43
- headers={"Authorization": "JWT " + token},
44
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
45
- )
46
- if not response.ok:
47
- print("::error::Error on deleting tag: " + tag)
48
- print(response.text)
49
- sys.exit(1)
50
-
51
-
52
- def main() -> None:
53
- """Run the main function."""
54
- parser = argparse.ArgumentParser(
55
- description=(
56
- "Clean the Docker images on Docker Hub for the branch we delete "
57
- "(get from the GitHub event information)."
58
- )
59
- )
60
- parser.parse_args()
61
-
62
- username = (
63
- os.environ["DOCKERHUB_USERNAME"]
64
- if "DOCKERHUB_USERNAME" in os.environ
65
- else c2cciutils.gopass("gs/ci/dockerhub/username")
66
- )
67
- password = (
68
- os.environ["DOCKERHUB_PASSWORD"]
69
- if "DOCKERHUB_PASSWORD" in os.environ
70
- else c2cciutils.gopass("gs/ci/dockerhub/password")
71
- )
72
- token = requests.post(
73
- "https://hub.docker.com/v2/users/login/",
74
- headers={"Content-Type": "application/json"},
75
- data=json.dumps(
76
- {
77
- "username": username,
78
- "password": password,
79
- }
80
- ),
81
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
82
- ).json()["token"]
83
-
84
- with open(os.environ["GITHUB_EVENT_PATH"], encoding="utf-8") as event_file:
85
- event = json.loads(event_file.read())
86
- print(yaml.dump(event))
87
- ref = str(event["number"]) if "pull_request" in event else event["ref"]
88
-
89
- ref = ref.replace("/", "_")
90
-
91
- config = c2cciutils.get_config()
92
-
93
- docker_config = cast(
94
- c2cciutils.configuration.PublishDockerConfig,
95
- config.get("publish", {}).get("docker", {}) if config.get("publish", {}).get("docker", False) else {},
96
- )
97
- for image in docker_config.get("images", []):
98
- for tag in image.get("tags", []):
99
- clean(image["name"], tag.format(version=ref), token)
100
-
101
-
102
- if __name__ == "__main__":
103
- main()
@@ -1,33 +0,0 @@
1
- import argparse
2
-
3
- import yaml
4
-
5
- import c2cciutils.lib.docker
6
-
7
-
8
- def main() -> None:
9
- """Dump the actual versions of packages in image to file ci/dpkg-versions.yaml."""
10
- argparser = argparse.ArgumentParser(
11
- description="Dump the actual versions of packages in image to file ci/dpkg-versions.yaml."
12
- )
13
- argparser.add_argument("--distribution", help="The default distribution code to be used")
14
- argparser.add_argument("--release", help="The default release version to be used")
15
- argparser.add_argument("images", help="The image to check", nargs="+")
16
- args = argparser.parse_args()
17
-
18
- versions_config, _ = c2cciutils.lib.docker.get_versions_config()
19
- for image in args.images:
20
- _, versions_image = c2cciutils.lib.docker.get_dpkg_packages_versions(
21
- image,
22
- default_distribution=args.distribution,
23
- default_release=args.release,
24
- )
25
- versions_config[image] = {k: str(v) for k, v in versions_image.items()}
26
-
27
- with open("ci/dpkg-versions.yaml", "w", encoding="utf-8") as versions_file:
28
- versions_file.write("# See repository list: https://repology.org/repositories/statistics\n\n")
29
- versions_file.write(yaml.dump(versions_config, Dumper=yaml.SafeDumper, default_flow_style=False))
30
-
31
-
32
- if __name__ == "__main__":
33
- main()
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
-
4
- import argparse
5
- import configparser
6
- import json
7
-
8
-
9
- def main() -> None:
10
- """Run the command."""
11
- parser = argparse.ArgumentParser(
12
- description="""Output packages with versions from Pipfile.lock in Pipfile format (similar to pip freeze).
13
- Useful to pin all the dependency in the Pipfile, on stabilization branch to be able to upgrade one package that have a security issue."""
14
- )
15
- parser.add_argument("--packages", action="store_true", help="Output only the packages section")
16
- parser.add_argument("--dev-packages", action="store_true", help="Output only the dev-packages section")
17
- parser.add_argument("--pipfile", default="Pipfile", help="The base Pipfile filename")
18
- args = parser.parse_args()
19
-
20
- packages = {}
21
- dev_packages = {}
22
-
23
- with open(args.pipfile + ".lock", encoding="utf-8") as pipfilelock_file:
24
- pipfilelock = json.loads(pipfilelock_file.read())
25
- for pkg, pkg_config in pipfilelock["default"].items():
26
- packages[pkg] = pkg_config["version"]
27
- for pkg, pkg_config in pipfilelock["develop"].items():
28
- dev_packages[pkg] = pkg_config["version"]
29
-
30
- config = configparser.ConfigParser()
31
- config.read(args.pipfile)
32
-
33
- if args.packages or not args.packages and not args.dev_packages:
34
- print("[packages]")
35
- print("# Lock dependencies")
36
- for pkg, version in packages.items():
37
- if pkg not in config["packages"] and f'"{pkg}"' not in config["packages"]:
38
- quote = '"' if "." in pkg else ""
39
- print(f'{quote}{pkg}{quote} = "{version}"')
40
-
41
- if args.packages and args.dev_packages or not args.packages and not args.dev_packages:
42
- print()
43
-
44
- if args.dev_packages or not args.packages and not args.dev_packages:
45
- print("[dev-packages]")
46
- print("# Lock dependencies")
47
- for pkg, version in dev_packages.items():
48
- if pkg not in config["dev-packages"] and f'"{pkg}"' not in config["dev-packages"]:
49
- quote = '"' if "." in pkg else ""
50
- print(f'{quote}{pkg}{quote} = "{version}"')
51
-
52
-
53
- if __name__ == "__main__":
54
- main()