shipit-cli 0.8.0__py3-none-any.whl → 0.9.1__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.
shipit/cli.py CHANGED
@@ -305,7 +305,7 @@ class DockerBuilder:
305
305
  image_name,
306
306
  command,
307
307
  *(extra_args or []),
308
- _env=os.environ, # Pass the current environment variables to the Docker client
308
+ _env={"DOCKER_BUILDKIT": "1", **os.environ}, # Pass the current environment variables to the Docker client
309
309
  _out=write_stdout,
310
310
  _err=write_stderr,
311
311
  )
@@ -370,7 +370,8 @@ RUN chmod {oct(mode)[2:]} {path.absolute()}
370
370
  base_path = self.docker_path
371
371
  shutil.rmtree(base_path, ignore_errors=True)
372
372
  base_path.mkdir(parents=True, exist_ok=True)
373
- self.docker_file_contents = "FROM debian:trixie-slim AS build\n"
373
+ self.docker_file_contents = "# syntax=docker/dockerfile:1.7-labs\n"
374
+ self.docker_file_contents += "FROM debian:trixie-slim AS build\n"
374
375
 
375
376
  self.docker_file_contents += """
376
377
  RUN apt-get update \\
@@ -378,6 +379,8 @@ RUN apt-get update \\
378
379
  build-essential gcc make autoconf libtool bison \\
379
380
  dpkg-dev pkg-config re2c locate \\
380
381
  libmariadb-dev libmariadb-dev-compat libpq-dev \\
382
+ libvips-dev default-libmysqlclient-dev libmagickwand-dev \\
383
+ libicu-dev libxml2-dev libxslt-dev \\
381
384
  sudo curl ca-certificates \\
382
385
  && rm -rf /var/lib/apt/lists/*
383
386
 
@@ -435,7 +438,11 @@ RUN curl https://mise.run | sh
435
438
  else:
436
439
  raise Exception(f"Asset {step.source} does not exist")
437
440
  else:
438
- self.docker_file_contents += f"COPY {step.source} {step.target}\n"
441
+ if step.ignore:
442
+ exclude = " \\\n" +" \\\n".join([f" --exclude={ignore}" for ignore in step.ignore]) + " \\\n "
443
+ else:
444
+ exclude = ""
445
+ self.docker_file_contents += f"COPY{exclude} {step.source} {step.target}\n"
439
446
  elif isinstance(step, EnvStep):
440
447
  env_vars = " ".join(
441
448
  [f"{key}={value}" for key, value in step.variables.items()]
@@ -538,9 +545,10 @@ class LocalBuilder:
538
545
  exe = shutil.which(program, path=PATH)
539
546
  if not exe:
540
547
  raise Exception(f"Program is not installed: {program}")
541
- cmd = sh.Command(exe) # "grep"
548
+ cmd = sh.Command("bash") # "grep"
542
549
  result = cmd(
543
- *parts[1:],
550
+ "-c",
551
+ command_line,
544
552
  _env={**env, "PATH": PATH},
545
553
  _cwd=build_path,
546
554
  _out=write_stdout,
@@ -1,37 +1,226 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
4
+ import yaml
3
5
  from pathlib import Path
4
- from typing import Dict, Optional
6
+ from typing import Dict, Optional, Any, Set
7
+ from enum import Enum
8
+ from semantic_version import Version, NpmSpec
9
+
5
10
 
6
11
  from .base import (
7
12
  DetectResult,
8
13
  DependencySpec,
9
14
  Provider,
10
15
  _exists,
11
- _has_dependency,
12
16
  MountSpec,
13
17
  ServiceSpec,
14
18
  VolumeSpec,
15
19
  CustomCommands,
16
20
  )
21
+ from .staticfile import StaticFileProvider
22
+
23
+
24
+ class PackageManager(Enum):
25
+ NPM = "npm"
26
+ PNPM = "pnpm"
27
+ YARN = "yarn"
28
+ BUN = "bun"
29
+
30
+ def as_dependency(self, path) -> DependencySpec:
31
+ dep_name = {
32
+ PackageManager.NPM: "npm",
33
+ PackageManager.PNPM: "pnpm",
34
+ PackageManager.YARN: "yarn",
35
+ PackageManager.BUN: "bun",
36
+ }[self]
37
+
38
+ default_version = None
39
+ if self == PackageManager.PNPM:
40
+ lockfile = path / self.lockfile()
41
+ lockfile_version = self.pnpm_lockfile_version(lockfile)
42
+ if lockfile_version:
43
+ if lockfile_version.startswith("5."):
44
+ default_version = "7"
45
+ elif lockfile_version.startswith("6."):
46
+ default_version = "8"
47
+
48
+ return DependencySpec(
49
+ dep_name,
50
+ env_var=f"SHIPIT_{dep_name.upper()}_VERSION",
51
+ default_version=default_version,
52
+ )
53
+
54
+ def lockfile(self) -> str:
55
+ return {
56
+ PackageManager.NPM: "package-lock.json",
57
+ PackageManager.PNPM: "pnpm-lock.yaml",
58
+ PackageManager.YARN: "yarn.lock",
59
+ PackageManager.BUN: "bun.lockb",
60
+ }[self]
61
+
62
+ @classmethod
63
+ def pnpm_lockfile_version(cls, lockfile: Path) -> Optional[str]:
64
+ if not lockfile.exists():
65
+ return None
66
+ # Read line by line and return the lockfileVersion
67
+ with open(lockfile, "r") as f:
68
+ for line in f:
69
+ if "lockfileVersion" in line:
70
+ try:
71
+ config = yaml.safe_load(line)
72
+ version = config.get("lockfileVersion")
73
+ assert isinstance(version, (str, bytes))
74
+ return version
75
+ except:
76
+ pass
77
+ return None
78
+
79
+ def install_command(self, has_lockfile: bool = False) -> str:
80
+ return {
81
+ PackageManager.NPM: f"npm {'ci' if has_lockfile else 'install'}",
82
+ PackageManager.PNPM: f"pnpm install{' --frozen-lockfile' if has_lockfile else ''}",
83
+ PackageManager.YARN: f"yarn install{' --frozen-lockfile' if has_lockfile else ''}",
84
+ PackageManager.BUN: f"bun install{' --no-save' if has_lockfile else ''}",
85
+ }[self]
86
+
87
+ def run_command(self, command: str) -> str:
88
+ return {
89
+ PackageManager.NPM: f"npm run {command}",
90
+ PackageManager.PNPM: f"pnpm run {command}",
91
+ PackageManager.YARN: f"yarn run {command}",
92
+ PackageManager.BUN: f"bun run {command}",
93
+ }[self]
94
+
95
+ def run_execute_command(self, command: str) -> str:
96
+ return {
97
+ PackageManager.NPM: f"npx {command}",
98
+ PackageManager.PNPM: f"pnpx {command}",
99
+ PackageManager.YARN: f"ypx {command}",
100
+ PackageManager.BUN: f"bunx {command}",
101
+ }[self]
102
+
103
+
104
+ class StaticGenerator(Enum):
105
+ ASTRO = "astro"
106
+ VITE = "vite"
107
+ NEXT = "next"
108
+ GATSBY = "gatsby"
109
+ DOCUSAURUS = "docusaurus"
110
+ SVELTE = "svelte"
111
+ REMIX = "remix"
112
+ NUXT_OLD = "nuxt"
113
+ NUXT_V3 = "nuxt3"
114
+ REMIX_OLD = "remix-old"
115
+ REMIX_V2 = "remix-v2"
17
116
 
18
117
 
19
- class NodeStaticProvider:
118
+ class NodeStaticProvider(StaticFileProvider):
119
+ package_manager: PackageManager
120
+ package_json: Optional[Dict[str, Any]]
121
+ extra_dependencies: Set[str]
122
+
20
123
  def __init__(self, path: Path, custom_commands: CustomCommands):
21
- self.path = path
22
- self.custom_commands = custom_commands
124
+ super().__init__(path, custom_commands)
125
+ if (path / "package-lock.json").exists():
126
+ self.package_manager = PackageManager.NPM
127
+ elif (path / "pnpm-lock.yaml").exists():
128
+ self.package_manager = PackageManager.PNPM
129
+ elif (path / "yarn.lock").exists():
130
+ self.package_manager = PackageManager.YARN
131
+ elif (path / "bun.lockb").exists():
132
+ self.package_manager = PackageManager.BUN
133
+ else:
134
+ self.package_manager = PackageManager.PNPM
135
+
136
+ self.package_json = self.parse_package_json(path)
137
+
138
+ if self.has_dependency(self.package_json, "gatsby"):
139
+ self.static_generator = StaticGenerator.GATSBY
140
+ elif self.has_dependency(self.package_json, "astro"):
141
+ self.static_generator = StaticGenerator.ASTRO
142
+ elif self.has_dependency(self.package_json, "@docusaurus/core"):
143
+ self.static_generator = StaticGenerator.DOCUSAURUS
144
+ elif self.has_dependency(self.package_json, "svelte"):
145
+ self.static_generator = StaticGenerator.SVELTE
146
+ elif self.has_dependency(
147
+ self.package_json, "@remix-run/dev", "1"
148
+ ) or self.has_dependency(self.package_json, "@remix-run/dev", "0"):
149
+ self.static_generator = StaticGenerator.REMIX_OLD
150
+ elif self.has_dependency(self.package_json, "@remix-run/dev"):
151
+ self.static_generator = StaticGenerator.REMIX_V2
152
+ elif self.has_dependency(self.package_json, "vite"):
153
+ self.static_generator = StaticGenerator.VITE
154
+ elif self.has_dependency(self.package_json, "next"):
155
+ self.static_generator = StaticGenerator.NEXT
156
+ elif self.has_dependency(self.package_json, "nuxt", "2") or self.has_dependency(
157
+ self.package_json, "nuxt", "1"
158
+ ):
159
+ self.static_generator = StaticGenerator.NUXT_OLD
160
+ elif self.has_dependency(self.package_json, "nuxt"):
161
+ self.static_generator = StaticGenerator.NUXT_V3
162
+
163
+ # if self.has_dependency(self.package_json, "sharp"):
164
+ # self.extra_dependencies.add("libvips")
165
+
166
+ @classmethod
167
+ def parse_package_json(cls, path: Path) -> Optional[Dict[str, Any]]:
168
+ package_json_path = path / "package.json"
169
+ if not package_json_path.exists():
170
+ return None
171
+ try:
172
+ package_json = json.loads(package_json_path.read_text())
173
+ assert isinstance(package_json, dict), (
174
+ "package.json must be a valid JSON object"
175
+ )
176
+ return package_json
177
+ except Exception:
178
+ return None
179
+
180
+ @classmethod
181
+ def has_dependency(
182
+ cls,
183
+ package_json: Optional[Dict[str, Any]],
184
+ dep: str,
185
+ version: Optional[str] = None,
186
+ ) -> bool:
187
+ if not package_json:
188
+ return False
189
+ for section in ("dependencies", "devDependencies", "peerDependencies"):
190
+ dep_section = package_json.get(section, {})
191
+ if dep in dep_section:
192
+ if version:
193
+ try:
194
+ constraint = NpmSpec(dep_section[dep])
195
+ return Version(version) in constraint
196
+ except Exception:
197
+ pass
198
+ else:
199
+ return True
200
+ return False
23
201
 
24
202
  @classmethod
25
203
  def name(cls) -> str:
26
204
  return "node-static"
27
205
 
28
206
  @classmethod
29
- def detect(cls, path: Path, custom_commands: CustomCommands) -> Optional[DetectResult]:
30
- pkg = path / "package.json"
31
- if not pkg.exists():
207
+ def detect(
208
+ cls, path: Path, custom_commands: CustomCommands
209
+ ) -> Optional[DetectResult]:
210
+ package_json = cls.parse_package_json(path)
211
+ if not package_json:
32
212
  return None
33
- static_generators = ["astro", "vite", "next", "nuxt"]
34
- if any(_has_dependency(pkg, dep) for dep in static_generators):
213
+ static_generators = [
214
+ "astro",
215
+ "vite",
216
+ "next",
217
+ "nuxt",
218
+ "gatsby",
219
+ "svelte",
220
+ "@docusaurus/core",
221
+ "@remix-run/dev",
222
+ ]
223
+ if any(cls.has_dependency(package_json, dep) for dep in static_generators):
35
224
  return DetectResult(cls.name(), 40)
36
225
  return None
37
226
 
@@ -45,6 +234,8 @@ class NodeStaticProvider:
45
234
  return "staticsite"
46
235
 
47
236
  def dependencies(self) -> list[DependencySpec]:
237
+ package_manager_dep = self.package_manager.as_dependency(self.path)
238
+ package_manager_dep.use_in_build = True
48
239
  return [
49
240
  DependencySpec(
50
241
  "node",
@@ -52,37 +243,97 @@ class NodeStaticProvider:
52
243
  default_version="22",
53
244
  use_in_build=True,
54
245
  ),
55
- DependencySpec("npm", use_in_build=True),
246
+ package_manager_dep,
56
247
  DependencySpec("static-web-server", use_in_serve=True),
57
248
  ]
58
249
 
59
250
  def declarations(self) -> Optional[str]:
60
251
  return None
61
252
 
253
+ def get_output_dir(self) -> str:
254
+ if self.static_generator == StaticGenerator.NEXT:
255
+ return "out"
256
+ elif self.static_generator in [
257
+ StaticGenerator.ASTRO,
258
+ StaticGenerator.VITE,
259
+ StaticGenerator.NUXT_OLD,
260
+ StaticGenerator.NUXT_V3,
261
+ StaticGenerator.REMIX_V2,
262
+ ]:
263
+ return "dist"
264
+ elif self.static_generator == StaticGenerator.GATSBY:
265
+ return "public"
266
+ elif self.static_generator == StaticGenerator.REMIX_OLD:
267
+ return "build/client"
268
+ elif self.static_generator in [
269
+ StaticGenerator.DOCUSAURUS,
270
+ StaticGenerator.SVELTE,
271
+ ]:
272
+ return "build"
273
+ else:
274
+ return "dist"
275
+
276
+ def get_build_command(self) -> bool:
277
+ if not self.package_json:
278
+ return False
279
+ build_command = self.package_json.get("scripts", {}).get("build")
280
+ if build_command:
281
+ return self.package_manager.run_command("build")
282
+ if self.static_generator == StaticGenerator.GATSBY:
283
+ return self.package_manager.run_execute_command("gatsby build")
284
+ if self.static_generator == StaticGenerator.ASTRO:
285
+ return self.package_manager.run_execute_command("astro build")
286
+ elif self.static_generator == StaticGenerator.REMIX_OLD:
287
+ return self.package_manager.run_execute_command("remix-ssg build")
288
+ elif self.static_generator == StaticGenerator.REMIX_V2:
289
+ return self.package_manager.run_execute_command("vite build")
290
+ elif self.static_generator == StaticGenerator.DOCUSAURUS:
291
+ return self.package_manager.run_execute_command("docusaurus build")
292
+ elif self.static_generator == StaticGenerator.SVELTE:
293
+ return self.package_manager.run_execute_command("svelte-kit build")
294
+ elif self.static_generator == StaticGenerator.VITE:
295
+ return self.package_manager.run_execute_command("vite build")
296
+ elif self.static_generator == StaticGenerator.NEXT:
297
+ return self.package_manager.run_execute_command("next export")
298
+ elif self.static_generator == StaticGenerator.NUXT_V3:
299
+ return self.package_manager.run_execute_command("nuxi generate")
300
+ elif self.static_generator == StaticGenerator.NUXT_OLD:
301
+ return self.package_manager.run_execute_command("nuxt generate")
302
+ return False
303
+
62
304
  def build_steps(self) -> list[str]:
63
- output_dir = "dist" if (self.path / "dist").exists() else "public"
305
+ output_dir = self.get_output_dir()
306
+ get_build_command = self.get_build_command()
307
+ lockfile = self.package_manager.lockfile()
308
+ has_lockfile = (self.path / lockfile).exists()
309
+ install_command = self.package_manager.install_command(
310
+ has_lockfile=has_lockfile
311
+ )
312
+ input_files = ["package.json"]
313
+ if has_lockfile:
314
+ input_files.append(lockfile)
315
+ inputs_install_files = ", ".join([f'"{file}"' for file in input_files])
316
+
64
317
  return [
65
- "run(\"npm install\", inputs=[\"package.json\", \"package-lock.json\"], group=\"install\")",
66
- "copy(\".\", \".\", ignore=[\"node_modules\", \".git\"])",
67
- f"run(\"npm run build\", outputs=[\"{output_dir}\"], group=\"build\")",
68
- f"run(\"cp -R {output_dir}/* {{}}/\".format(app[\"build\"]))",
318
+ 'workdir(temp["build"])',
319
+ # 'run("npx corepack enable", inputs=["package.json"], group="install")',
320
+ f'run("{install_command}", inputs=[{inputs_install_files}], group="install")',
321
+ 'copy(".", ".", ignore=["node_modules", ".git"])',
322
+ f'run("{get_build_command}", outputs=["{output_dir}"], group="build")',
323
+ f'run("cp -R {output_dir}/* {{}}/".format(app["build"]))',
69
324
  ]
70
325
 
71
326
  def prepare_steps(self) -> Optional[list[str]]:
72
327
  return None
73
328
 
74
- def commands(self) -> Dict[str, str]:
75
- output_dir = "dist" if (self.path / "dist").exists() else "public"
76
- return {"start": f'"static-web-server --root /app/{output_dir}"'}
77
-
78
329
  def mounts(self) -> list[MountSpec]:
79
- return [MountSpec("app")]
330
+ return [MountSpec("temp"), *super().mounts()]
80
331
 
81
332
  def volumes(self) -> list[VolumeSpec]:
82
333
  return []
83
334
 
84
335
  def env(self) -> Optional[Dict[str, str]]:
85
336
  return None
86
-
337
+
87
338
  def services(self) -> list[ServiceSpec]:
88
339
  return []
@@ -16,7 +16,7 @@ def providers() -> list[type[Provider]]:
16
16
  # Order matters: more specific providers first
17
17
  return [
18
18
  LaravelProvider,
19
- GatsbyProvider,
19
+ # GatsbyProvider,
20
20
  HugoProvider,
21
21
  MkdocsProvider,
22
22
  PythonProvider,
@@ -19,6 +19,8 @@ from .base import (
19
19
 
20
20
  class StaticFileProvider:
21
21
  config: Optional[dict] = None
22
+ path: Path
23
+ custom_commands: CustomCommands
22
24
 
23
25
  def __init__(self, path: Path, custom_commands: CustomCommands):
24
26
  self.path = path
shipit/version.py CHANGED
@@ -1,5 +1,5 @@
1
1
  __all__ = ["version", "version_info"]
2
2
 
3
3
 
4
- version = "0.8.0"
5
- version_info = (0, 8, 0, "final", 0)
4
+ version = "0.9.1"
5
+ version_info = (0, 9, 1, "final", 0)
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shipit-cli
3
- Version: 0.8.0
4
- Summary: Add your description here
3
+ Version: 0.9.1
4
+ Summary: Shipit CLI is the best way to build, serve and deploy your projects anywhere.
5
5
  Project-URL: homepage, https://wasmer.io
6
6
  Project-URL: repository, https://github.com/wasmerio/shipit
7
7
  Project-URL: Changelog, https://github.com/wasmerio/shipit/changelog
@@ -10,6 +10,7 @@ Requires-Dist: dotenv>=0.9.9
10
10
  Requires-Dist: pyyaml>=6.0.2
11
11
  Requires-Dist: requests>=2.32.5
12
12
  Requires-Dist: rich>=14.1.0
13
+ Requires-Dist: semantic-version>=2.10.0
13
14
  Requires-Dist: sh>=2.2.2
14
15
  Requires-Dist: starlark-pyo3>=2025.1
15
16
  Requires-Dist: tomlkit>=0.13.3
@@ -1,8 +1,8 @@
1
1
  shipit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- shipit/cli.py,sha256=wfHNLe0Pe0uheeiFuWQi3DFlUA86oTN8-mojaKxru94,58696
2
+ shipit/cli.py,sha256=NMZ6xSLq8MlV9yT3FLi9XZ5IBw2IMppoPna_vl9LK1Y,59170
3
3
  shipit/generator.py,sha256=W4MynSFwId4PRWWrF0R3NsANye_Zv8TwXCUXai94pW0,6553
4
4
  shipit/procfile.py,sha256=GlfdwzFUr0GWGKaaiXlLKNFInWaRNMy_wN14UEyU_5Q,2974
5
- shipit/version.py,sha256=tLXsjc9rJ1_Aj9p3fPQjFAv5Eanmo1dQaEiaHbiBSwY,95
5
+ shipit/version.py,sha256=lVDUJez84exvM3cupsLPLkgwODb6keB_FDCxjb0ObkA,95
6
6
  shipit/assets/php/php.ini,sha256=f4irndAjB4GuuouEImRkNV22Q-yw1KqR-43jAMDw730,2531
7
7
  shipit/assets/wordpress/install.sh,sha256=fJkVeGAw_dj-ywmQipAWRjaz57sayD6F0OFvZKMIKug,669
8
8
  shipit/assets/wordpress/wp-config.php,sha256=IdGQoeg8E89JiqwxO2i8WnGMzmhNWgRz80X6lbU5GXc,4134
@@ -11,13 +11,13 @@ shipit/providers/gatsby.py,sha256=kzfS-z040GaJ0a9u2_6S6K-ykGSX2yPG17VpjUWBOBA,23
11
11
  shipit/providers/hugo.py,sha256=l3IZ14LGYc3wQ7Uk0iQMDNN9Syd1G4HPzm0ePCGFyzE,1808
12
12
  shipit/providers/laravel.py,sha256=2rCuOi2kC5OYQfAG7C0NMhG7KEgzfudwUT_CvVFz4hM,3031
13
13
  shipit/providers/mkdocs.py,sha256=mDJpT3rzYAr5Vw-yt5fCpV0QgBZyksn9MrkPd4nzROU,2200
14
- shipit/providers/node_static.py,sha256=QVUTTZbvUGtj2yT9WTbGmuM30rJzejnp76crIqSGA7o,2564
14
+ shipit/providers/node_static.py,sha256=1eWjhcrKZF8DE9EwlEXwFYrbD2AkeabZjIo1_BocWJk,12335
15
15
  shipit/providers/php.py,sha256=BSOqS3UhABoe_ued8aXtyn0KdqWbOCq6VV2ehtoBlmk,3547
16
16
  shipit/providers/python.py,sha256=kQpaaQi8ajHM_SFk2xI5lRIeOc6PXSKumb-Tv_5n6m0,20954
17
- shipit/providers/registry.py,sha256=lHUViVuPJf1OIZD8I_NTX4LP7E3Uo5-MmLfarmAA_cM,729
18
- shipit/providers/staticfile.py,sha256=BxZ7Z8dN0tAd-s8_m-NPgqJrVSvKwxCd-us-hCanL1E,2626
17
+ shipit/providers/registry.py,sha256=JCuQaYTvJcWK1nS-om9TIQgGW6pT5BuNLIRzChLLFWE,731
18
+ shipit/providers/staticfile.py,sha256=F4thEuihDW-h5DO-lotrjSdHYWzoXofQPpsAgWonvpY,2677
19
19
  shipit/providers/wordpress.py,sha256=Wjc1fgFburewlf4hQ2ZmxTQko_SHQW-8jrDukzKx0Gs,3019
20
- shipit_cli-0.8.0.dist-info/METADATA,sha256=p_XVn3jE5BNj2JQm_5-xBqszHGjdZYb2me6Ur0BOgTk,523
21
- shipit_cli-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
- shipit_cli-0.8.0.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
23
- shipit_cli-0.8.0.dist-info/RECORD,,
20
+ shipit_cli-0.9.1.dist-info/METADATA,sha256=i8nzdCcT8qJFNNazduiVP1afqfxv1g2rlyCpDfCTcXQ,615
21
+ shipit_cli-0.9.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
22
+ shipit_cli-0.9.1.dist-info/entry_points.txt,sha256=7AE1NjSrHaSDfbfsRRO50KKnHFTbB0Imsccd1WynzAQ,72
23
+ shipit_cli-0.9.1.dist-info/RECORD,,