pyproject-appimage 3.0__tar.gz → 4.0__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyproject-appimage
3
- Version: 3.0
3
+ Version: 4.0
4
4
  Summary: Generate AppImages from your Python projects
5
5
  Author-email: JakobDev <jakobdev@gmx.de>
6
6
  License: BSD-2-Clause
@@ -24,6 +24,9 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
+ Requires-Dist: requests
28
+ Requires-Dist: desktop-entry-lib
29
+ Requires-Dist: tomli; python_version < "3.11"
27
30
 
28
31
  # pyproject-appimage
29
32
 
@@ -56,11 +59,15 @@ The following options can be used in your pyproject.toml:
56
59
  | rename-icon | string | Give your Icon another name inside the AppImage |
57
60
  | desktop-entry | string | The path to your .desktop file |
58
61
  | rename-desktop-entry | string | Give your .desktop file another name inside the AppImage |
62
+ | gettext-desktop-entry | bool | If your .desktop file should be translated using gettest |
59
63
  | appstream | string | The path to your AppStream file |
60
64
  | rename-appstream | string | Give your AppStream file another name inside the AppImage |
65
+ | gettext-appstream | bool | If your AppStream file should be translated using gettest |
66
+ | gettext-directory | string | The path to your gettext directory |
61
67
  | python-version | string | The Python version that is used. Default is your current version. Can be overwritten with the cli. |
62
68
  | updateinformation | string | The [update information](https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information)
63
69
  | compression | string | The Squashfs compression
70
+ | additional-packages | list of strins | A list of packages that should also be installed
64
71
 
65
72
  Note: All paths are relativ to your project directory
66
73
 
@@ -86,6 +93,9 @@ options:
86
93
  -v, --version Prints the version and exit
87
94
  ```
88
95
 
96
+ ## Projects using pyproject-appimage
97
+ * [jdNBTExplorer](https://codeberg.org/JakobDev/jdNBTExplorer)
98
+
89
99
  [pyproject-appimage is of course also available as AppImage](https://codeberg.org/JakobDev/pyproject-appimage/releases/latest)
90
100
 
91
101
  pyproject-appimage is based [on the work of niess](https://github.com/niess/python-appimage)
@@ -29,11 +29,15 @@ The following options can be used in your pyproject.toml:
29
29
  | rename-icon | string | Give your Icon another name inside the AppImage |
30
30
  | desktop-entry | string | The path to your .desktop file |
31
31
  | rename-desktop-entry | string | Give your .desktop file another name inside the AppImage |
32
+ | gettext-desktop-entry | bool | If your .desktop file should be translated using gettest |
32
33
  | appstream | string | The path to your AppStream file |
33
34
  | rename-appstream | string | Give your AppStream file another name inside the AppImage |
35
+ | gettext-appstream | bool | If your AppStream file should be translated using gettest |
36
+ | gettext-directory | string | The path to your gettext directory |
34
37
  | python-version | string | The Python version that is used. Default is your current version. Can be overwritten with the cli. |
35
38
  | updateinformation | string | The [update information](https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information)
36
39
  | compression | string | The Squashfs compression
40
+ | additional-packages | list of strins | A list of packages that should also be installed
37
41
 
38
42
  Note: All paths are relativ to your project directory
39
43
 
@@ -59,6 +63,9 @@ options:
59
63
  -v, --version Prints the version and exit
60
64
  ```
61
65
 
66
+ ## Projects using pyproject-appimage
67
+ * [jdNBTExplorer](https://codeberg.org/JakobDev/jdNBTExplorer)
68
+
62
69
  [pyproject-appimage is of course also available as AppImage](https://codeberg.org/JakobDev/pyproject-appimage/releases/latest)
63
70
 
64
71
  pyproject-appimage is based [on the work of niess](https://github.com/niess/python-appimage)
@@ -28,26 +28,30 @@ classifiers = [
28
28
  ]
29
29
  dependencies = [
30
30
  "requests",
31
+ "desktop-entry-lib",
31
32
  "tomli; python_version < '3.11'"
32
33
  ]
33
34
  dynamic = ["version"]
34
35
 
35
- [tool.setuptools.dynamic]
36
- version = { file = "pyproject_appimage/version.txt" }
37
-
38
- [project.scripts]
39
- pyproject-appimage = "pyproject_appimage:main"
40
-
41
- [tool.setuptools.package-data]
42
- pyproject_appimage = ["version.txt", "default.png", "default.desktop"]
43
-
44
36
  [project.urls]
45
37
  Downloads = "https://codeberg.org/JakobDev/pyproject-appimage/releases"
46
38
  Issues = "https://codeberg.org/JakobDev/pyproject-appimage/issues"
47
39
  Source = "https://codeberg.org/JakobDev/pyproject-appimage"
48
40
  Donation = "https://ko-fi.com/jakobdev"
49
41
 
42
+ [tool.setuptools.package-dir]
43
+ pyproject_appimage = "pyproject_appimage"
44
+
45
+ [tool.setuptools.dynamic]
46
+ version = { file = "pyproject_appimage/version.txt" }
47
+
48
+ [tool.setuptools.package-data]
49
+ pyproject_appimage = ["version.txt", "default.png"]
50
+
51
+ [project.scripts]
52
+ pyproject-appimage = "pyproject_appimage:main"
53
+
50
54
  [tool.pyproject-appimage]
51
55
  script = "pyproject-appimage"
52
56
  output = "pyproject-appimage.AppImage"
53
- python-version ="3.11"
57
+ python-version ="3.12"
@@ -1,4 +1,5 @@
1
1
  from typing import Optional, Any, TypedDict
2
+ import desktop_entry_lib
2
3
  import subprocess
3
4
  import argparse
4
5
  import requests
@@ -34,6 +35,18 @@ PyprojectDict = TypedDict("PyprojectDict", {
34
35
  }, total=False)
35
36
 
36
37
 
38
+ def read_pyproject_file(path: str) -> dict[str, Any]:
39
+ with open(path, "rb") as f:
40
+ try:
41
+ return toml_load(f)
42
+ except Exception as ex:
43
+ if len(ex.args) == 1:
44
+ print("Error while parsing " + os.path.join(args.project_dir, "pyproject.toml") + f": {ex.args[0]}", file=sys.stderr)
45
+ else:
46
+ print("Error while parsing " + os.path.join(args.project_dir, "pyproject.toml"), file=sys.stderr)
47
+ sys.exit(1)
48
+
49
+
37
50
  def check_key(project_dir: str, pyproject: PyprojectDict, key: str, error_list: list[str], checks: list[str]) -> None:
38
51
  if key not in pyproject:
39
52
  if "required" in checks:
@@ -50,6 +63,13 @@ def check_key(project_dir: str, pyproject: PyprojectDict, key: str, error_list:
50
63
  if "bool" in checks:
51
64
  if not isinstance(pyproject[key], bool):
52
65
  error_list.append(f"\"{key}\" must be a bool")
66
+ if "string-list" in checks:
67
+ if not isinstance(pyproject[key], list):
68
+ error_list.append(f"\"{key}\" must be a list of strings")
69
+ else:
70
+ for i in pyproject[key]:
71
+ if not isinstance(i, str):
72
+ error_list.append(f"\"{key}\" must be a list of strings")
53
73
 
54
74
 
55
75
  def check_pyproject(project_dir: str, pyproject: PyprojectDict) -> None:
@@ -69,6 +89,7 @@ def check_pyproject(project_dir: str, pyproject: PyprojectDict) -> None:
69
89
  check_key(project_dir, pyproject, "output", error_list, ["string"])
70
90
  check_key(project_dir, pyproject, "updateinformation", error_list, ["string"])
71
91
  check_key(project_dir, pyproject, "compression", error_list, ["string"])
92
+ check_key(project_dir, pyproject, "additional-packages", error_list, ["string-list"])
72
93
 
73
94
  if ("gettext-desktop-entry" in pyproject or "gettext-appstream" in pyproject) and not "gettext-directory" in pyproject:
74
95
  error_list.append("\"gettext-directory\" must be set when using gettext")
@@ -122,6 +143,84 @@ def get_icon_size(work_dir: str, icon_path: str) -> tuple[int, int]:
122
143
  return (int(width), int(height))
123
144
 
124
145
 
146
+ def handle_icon(project_dir: str, work_dir: str, app_root: str, pyproject: PyprojectDict) -> None:
147
+ if "icon" not in pyproject:
148
+ shutil.copyfile(os.path.join(os.path.dirname(__file__), "default.png"), os.path.join(app_root, ".DirIcon"))
149
+ shutil.copyfile(os.path.join(os.path.dirname(__file__), "default.png"), os.path.join(app_root, "pyproject-appimage-default.png"))
150
+ return
151
+
152
+ icon_path = os.path.join(project_dir, pyproject["icon"])
153
+
154
+ if icon_path.endswith(".png"):
155
+ shutil.copyfile(icon_path, os.path.join(app_root, ".DirIcon"))
156
+ else:
157
+ # If a Icon is not PNG, convert it
158
+ if icon_path.endswith(".svg"):
159
+ # https://stackoverflow.com/a/55370062
160
+ subprocess.run([get_image_magick_command(work_dir), "-background", "none", icon_path, "PNG:" + os.path.join(app_root, ".DirIcon")], check=True)
161
+ else:
162
+ subprocess.run([get_image_magick_command(work_dir), icon_path, "PNG:" + os.path.join(app_root, ".DirIcon")], check=True)
163
+
164
+ if "rename-icon" in pyproject:
165
+ icon_name = pyproject["rename-icon"]
166
+ else:
167
+ icon_name = os.path.basename(pyproject["icon"])
168
+
169
+ shutil.copyfile(icon_path, os.path.join(app_root, icon_name))
170
+
171
+ if icon_name.endswith(".svg"):
172
+ icon_dir = os.path.join(app_root, "usr", "share", "icons", "hicolor", "scalable", "apps")
173
+ else:
174
+ icon_size = get_icon_size(work_dir, os.path.join(app_root, icon_name))
175
+ icon_dir = os.path.join(app_root, "usr", "share", "icons", "hicolor", f"{icon_size[0]}x{icon_size[1]}", "apps")
176
+
177
+ if not os.path.isdir(icon_dir):
178
+ os.makedirs(icon_dir)
179
+
180
+ shutil.copyfile(os.path.join(app_root, icon_name), os.path.join(icon_dir, icon_name))
181
+
182
+
183
+ def create_desktop_entry(project_dir: str, app_root: str, pyproject: PyprojectDict) -> None:
184
+ full_pyproject = read_pyproject_file(os.path.join(project_dir, "pyproject.toml"))
185
+
186
+ entry = desktop_entry_lib.DesktopEntry()
187
+
188
+ if "project" in full_pyproject:
189
+ entry.Name.default_text = full_pyproject["project"].get("name", "App")
190
+ if "description" in full_pyproject["project"]:
191
+ entry.Comment.default_text = full_pyproject["project"]["description"]
192
+ else:
193
+ entry.Name.default_text = "App"
194
+
195
+ entry.Icon = "pyproject-appimage-default"
196
+ entry.Exec = pyproject["script"]
197
+
198
+ entry.Categories.append("Utility")
199
+
200
+ entry.write_file(os.path.join(app_root, "pyproject-appimage-default.desktop"))
201
+
202
+
203
+ def handle_desktop_entry(project_dir: str, app_root: str, pyproject: PyprojectDict) -> None:
204
+ if "desktop-entry" not in pyproject:
205
+ create_desktop_entry(project_dir, app_root, pyproject)
206
+ return
207
+
208
+ desktop_source_path = os.path.join(project_dir, pyproject["desktop-entry"])
209
+ desktop_dest_path = os.path.join(app_root, pyproject.get("rename-desktop-entry", os.path.basename(pyproject["desktop-entry"])))
210
+
211
+ if pyproject.get("gettext-desktop-entry", False):
212
+ subprocess.run(["msgfmt", "--desktop", "--template", desktop_source_path, "-d", os.path.join(project_dir, pyproject["gettext-directory"]), "-o", desktop_dest_path], check=True)
213
+ else:
214
+ shutil.copyfile(desktop_source_path, desktop_dest_path)
215
+
216
+ desktop_share_dir = os.path.join(app_root, "usr", "share", "applications")
217
+
218
+ if not os.path.isdir(desktop_share_dir):
219
+ os.makedirs(desktop_share_dir)
220
+
221
+ shutil.copyfile(desktop_dest_path, os.path.join(desktop_share_dir, os.path.basename(desktop_dest_path)))
222
+
223
+
125
224
  def build_appimage(project_dir: str, work_dir: str, pyproject: PyprojectDict, args: argparse.Namespace) -> None:
126
225
  if args.python_version is not None:
127
226
  python_version = args.python_version
@@ -164,52 +263,9 @@ def build_appimage(project_dir: str, work_dir: str, pyproject: PyprojectDict, ar
164
263
 
165
264
  os.symlink(os.path.join("usr", "bin", pyproject["script"]), os.path.join(app_root, "AppRun"))
166
265
 
167
- if "icon" in pyproject:
168
- if pyproject["icon"].endswith(".png"):
169
- shutil.copyfile(os.path.join(project_dir, pyproject["icon"]), os.path.join(app_root, os.path.basename(pyproject["icon"])))
170
- else:
171
- # If a Icon is not PNG, convert it
172
- subprocess.run([get_image_magick_command(work_dir), os.path.join(project_dir, pyproject["icon"]), "PNG:" + os.path.join(app_root, os.path.basename(pyproject["icon"]))], check=True)
266
+ handle_icon(project_dir, work_dir, app_root, pyproject)
173
267
 
174
- if "rename-icon" in pyproject:
175
- os.rename(os.path.join(app_root, os.path.basename(pyproject["icon"])), os.path.join(app_root, pyproject["rename-icon"]))
176
- icon_name = pyproject["rename-icon"]
177
- else:
178
- icon_name = os.path.basename(pyproject["icon"])
179
-
180
- shutil.copyfile(os.path.join(app_root, icon_name), os.path.join(app_root, ".DirIcon"))
181
-
182
- if icon_name.endswith(".svg"):
183
- icon_dir = os.path.join(app_root, "usr", "share", "icons", "hicolor", "scalable", "apps")
184
- else:
185
- icon_size = get_icon_size(work_dir, os.path.join(app_root, icon_name))
186
- icon_dir = os.path.join(app_root, "usr", "share", "icons", "hicolor", f"{icon_size[0]}x{icon_size[1]}", "apps")
187
-
188
- if not os.path.isdir(icon_dir):
189
- os.makedirs(icon_dir)
190
-
191
- shutil.copyfile(os.path.join(app_root, icon_name), os.path.join(icon_dir, icon_name))
192
- else:
193
- shutil.copyfile(os.path.join(os.path.dirname(__file__), "default.png"), os.path.join(app_root, ".DirIcon"))
194
-
195
- if "desktop-entry" in pyproject:
196
- desktop_source_path = os.path.join(project_dir, pyproject["desktop-entry"])
197
- desktop_dest_path = os.path.join(app_root, pyproject.get("rename-desktop-entry", os.path.basename(pyproject["desktop-entry"])))
198
-
199
- if pyproject.get("gettext-desktop-entry", False):
200
- subprocess.run(["msgfmt", "--desktop", "--template", desktop_source_path, "-d", os.path.join(project_dir, pyproject["gettext-directory"]), "-o", desktop_dest_path], check=True)
201
- else:
202
- shutil.copyfile(desktop_source_path, desktop_dest_path)
203
-
204
- desktop_share_dir = os.path.join(app_root, "usr", "share", "applications")
205
-
206
- if not os.path.isdir(desktop_share_dir):
207
- os.makedirs(desktop_share_dir)
208
-
209
- shutil.copyfile(desktop_dest_path, os.path.join(desktop_share_dir, os.path.basename(desktop_dest_path)))
210
- else:
211
- shutil.copyfile(os.path.join(os.path.dirname(__file__), "default.desktop"), os.path.join(app_root, "App.desktop"))
212
- os.symlink(".DirIcon", os.path.join(app_root, "Icon.png"))
268
+ handle_desktop_entry(project_dir, app_root, pyproject)
213
269
 
214
270
  if "appstream" in pyproject:
215
271
  appstream_path = os.path.join(app_root, "usr", "share", "metainfo")
@@ -229,6 +285,9 @@ def build_appimage(project_dir: str, work_dir: str, pyproject: PyprojectDict, ar
229
285
  else:
230
286
  shutil.copyfile(appstream_source_path, appstream_dest_path)
231
287
 
288
+ if "additional-packages" in pyproject:
289
+ subprocess.run([os.path.join(app_root, "usr", "bin", "pip"), "install"] + pyproject["additional-packages"], check=True)
290
+
232
291
  if args.output is not None:
233
292
  output = args.output
234
293
  elif "output" in pyproject:
@@ -249,6 +308,7 @@ def build_appimage(project_dir: str, work_dir: str, pyproject: PyprojectDict, ar
249
308
  imagetool_cmd.append("--comp")
250
309
  imagetool_cmd.append(pyproject["compression"])
251
310
 
311
+ imagetool_cmd.append("--no-appstream")
252
312
  imagetool_cmd.append(app_root)
253
313
  imagetool_cmd.append(output)
254
314
 
@@ -284,7 +344,7 @@ def get_toml_section(data: dict[str, Any], name: str) -> Optional[dict[str, Any]
284
344
  return current_data
285
345
 
286
346
 
287
- def main():
347
+ def main() -> None:
288
348
  parser = argparse.ArgumentParser()
289
349
  parser.add_argument("--output", help="Sets the putput filename")
290
350
  parser.add_argument("--project-dir", help="Sets the project dir", default=os.getcwd())
@@ -310,15 +370,7 @@ def main():
310
370
  print(os.path.join(args.project_dir, "pyproject.toml") + " does not exists", file=sys.stderr)
311
371
  sys.exit(1)
312
372
 
313
- with open(os.path.join(args.project_dir, "pyproject.toml"), "rb") as f:
314
- try:
315
- data = toml_load(f)
316
- except Exception as ex:
317
- if len(ex.args) == 1:
318
- print("Error while parsing " + os.path.join(args.project_dir, "pyproject.toml") + f": {ex.args[0]}", file=sys.stderr)
319
- else:
320
- print("Error while parsing " + os.path.join(args.project_dir, "pyproject.toml"), file=sys.stderr)
321
- sys.exit(1)
373
+ data = read_pyproject_file(os.path.join(args.project_dir, "pyproject.toml"))
322
374
 
323
375
  pyproject = get_toml_section(data, PYPROJECT_SECTION)
324
376
 
@@ -340,7 +392,7 @@ def main():
340
392
  pass
341
393
 
342
394
  try:
343
- build_appimage(args.project_dir, args.work_dir, pyproject, args)
395
+ build_appimage(args.project_dir, os.path.abspath(args.work_dir), pyproject, args)
344
396
  except subprocess.CalledProcessError as ex:
345
397
  print("Error while running " + str(ex.cmd), file=sys.stderr)
346
398
  sys.exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pyproject-appimage
3
- Version: 3.0
3
+ Version: 4.0
4
4
  Summary: Generate AppImages from your Python projects
5
5
  Author-email: JakobDev <jakobdev@gmx.de>
6
6
  License: BSD-2-Clause
@@ -24,6 +24,9 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
24
24
  Requires-Python: >=3.9
25
25
  Description-Content-Type: text/markdown
26
26
  License-File: LICENSE
27
+ Requires-Dist: requests
28
+ Requires-Dist: desktop-entry-lib
29
+ Requires-Dist: tomli; python_version < "3.11"
27
30
 
28
31
  # pyproject-appimage
29
32
 
@@ -56,11 +59,15 @@ The following options can be used in your pyproject.toml:
56
59
  | rename-icon | string | Give your Icon another name inside the AppImage |
57
60
  | desktop-entry | string | The path to your .desktop file |
58
61
  | rename-desktop-entry | string | Give your .desktop file another name inside the AppImage |
62
+ | gettext-desktop-entry | bool | If your .desktop file should be translated using gettest |
59
63
  | appstream | string | The path to your AppStream file |
60
64
  | rename-appstream | string | Give your AppStream file another name inside the AppImage |
65
+ | gettext-appstream | bool | If your AppStream file should be translated using gettest |
66
+ | gettext-directory | string | The path to your gettext directory |
61
67
  | python-version | string | The Python version that is used. Default is your current version. Can be overwritten with the cli. |
62
68
  | updateinformation | string | The [update information](https://github.com/AppImage/AppImageSpec/blob/master/draft.md#update-information)
63
69
  | compression | string | The Squashfs compression
70
+ | additional-packages | list of strins | A list of packages that should also be installed
64
71
 
65
72
  Note: All paths are relativ to your project directory
66
73
 
@@ -86,6 +93,9 @@ options:
86
93
  -v, --version Prints the version and exit
87
94
  ```
88
95
 
96
+ ## Projects using pyproject-appimage
97
+ * [jdNBTExplorer](https://codeberg.org/JakobDev/jdNBTExplorer)
98
+
89
99
  [pyproject-appimage is of course also available as AppImage](https://codeberg.org/JakobDev/pyproject-appimage/releases/latest)
90
100
 
91
101
  pyproject-appimage is based [on the work of niess](https://github.com/niess/python-appimage)
@@ -3,7 +3,6 @@ README.md
3
3
  pyproject.toml
4
4
  pyproject_appimage/__init__.py
5
5
  pyproject_appimage/__main__.py
6
- pyproject_appimage/default.desktop
7
6
  pyproject_appimage/default.png
8
7
  pyproject_appimage/version.txt
9
8
  pyproject_appimage.egg-info/PKG-INFO
@@ -1,4 +1,5 @@
1
1
  requests
2
+ desktop-entry-lib
2
3
 
3
4
  [:python_version < "3.11"]
4
5
  tomli
@@ -1,6 +0,0 @@
1
- [Desktop Entry]
2
- Name=App
3
- Type=Application
4
- Exec=AppRun
5
- Icon=Icon
6
- Categories=Development;