distroscript 0.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.
@@ -0,0 +1,544 @@
1
+ Metadata-Version: 2.4
2
+ Name: distroscript
3
+ Version: 0.1.0
4
+ Summary: Generate Bash installation scripts from a declarative YAML config for multiple Linux distros
5
+ Project-URL: Homepage, https://github.com/RaniAgus/distroscript
6
+ Project-URL: Repository, https://github.com/RaniAgus/distroscript
7
+ License: BSD 3-Clause License
8
+
9
+ Copyright (c) 2025, Agustin Ranieri
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright notice, this
15
+ list of conditions and the following disclaimer.
16
+
17
+ 2. Redistributions in binary form must reproduce the above copyright notice,
18
+ this list of conditions and the following disclaimer in the documentation
19
+ and/or other materials provided with the distribution.
20
+
21
+ 3. Neither the name of the copyright holder nor the names of its
22
+ contributors may be used to endorse or promote products derived from
23
+ this software without specific prior written permission.
24
+
25
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
29
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
+ License-File: LICENSE
36
+ Requires-Python: >=3.10
37
+ Requires-Dist: jsonschema
38
+ Requires-Dist: pyyaml
39
+ Description-Content-Type: text/markdown
40
+
41
+ # distroscript
42
+
43
+ Generate installation scripts for various Linux distributions based on a
44
+ declarative YAML configuration file.
45
+
46
+ ```txt
47
+ distroscript.py [-h] --os OS [--out OUT] config_path
48
+
49
+ Generate installation scripts from YAML config.
50
+
51
+ positional arguments:
52
+ config_path Path to the YAML configuration file.
53
+
54
+ options:
55
+ -h, --help show this help message and exit
56
+ --os OS Target operating system (e.g., 'ubuntu', 'fedora').
57
+ --out OUT Output shell script file path (optional, defaults to stdout).
58
+ ```
59
+
60
+ > [!NOTE]
61
+ > For now, only `fedora` is fully supported, but I plan to add support for
62
+ > `ubuntu`, `popos` and `mint` in the future.
63
+
64
+ ## Dependencies
65
+
66
+ - Ubuntu / Debian
67
+
68
+ ```bash
69
+ sudo apt-get install python3 python3-pyyaml python3-jsonschema
70
+ ```
71
+
72
+ - Fedora / Red Hat / CentOS
73
+
74
+ ```bash
75
+ sudo dnf install python3 python3-pyyaml python3-jsonschema
76
+ ```
77
+
78
+ - MacOS
79
+
80
+ ```bash
81
+ brew install python3 pyyaml jsonschema
82
+ ```
83
+
84
+ ## Schema Validation
85
+
86
+ The configuration files are validated against a JSON Schema specification (`src/schema.json`)
87
+ that defines the structure and constraints for all supported package types and their properties.
88
+
89
+ The validation happens automatically after reading the YAML file and before processing begins.
90
+ If validation fails, the script will exit with a detailed error message showing:
91
+ - The path to the invalid field
92
+ - A description of what's wrong
93
+
94
+ This helps catch configuration errors early, such as:
95
+ - Missing required fields (e.g., `url` for tar packages)
96
+ - Invalid package type names
97
+ - Incorrect property types (e.g., string instead of array)
98
+ - Unsupported properties for a given package type
99
+
100
+ ## Basic Usage
101
+
102
+ The YAML configuration file should defines the packages to be installed as a
103
+ key, and it's value is a list of methods to install the package in different
104
+ packaging systems.
105
+
106
+ Example:
107
+
108
+ ```yaml
109
+ git:
110
+ - type: apt
111
+ packages:
112
+ - git
113
+ - type: dnf
114
+ packages:
115
+ - git
116
+ ```
117
+
118
+ Then, when generating the installation script, the output will depend on the
119
+ `--os` argument provided.
120
+
121
+ For example, for `--os fedora`, the generated script will use `dnf` to install
122
+ `git`:
123
+
124
+ ```txt
125
+ > distroscript.py --os fedora config.yaml
126
+ #!/bin/bash
127
+
128
+ sudo dnf install -y git
129
+ ```
130
+
131
+ For `--os ubuntu`, it will use `apt`:
132
+
133
+ ```txt
134
+ > distroscript.py --os ubuntu config.yaml
135
+ #!/bin/bash
136
+
137
+ sudo apt-get install -y git
138
+ ```
139
+
140
+ ## Features by Example
141
+
142
+ Below are simple examples for each major feature.
143
+
144
+ ### 1. Install a package with different methods per OS
145
+
146
+ - By declaring multiple methods under the same package:
147
+
148
+ ```yaml
149
+ git:
150
+ - type: apt
151
+ packages: [git]
152
+ - type: dnf
153
+ packages: [git]
154
+ ```
155
+
156
+ > [!TIP]
157
+ > When `packages` is not included, the package name is assumed to be the same as the key:
158
+ >
159
+ > ```yaml
160
+ > git:
161
+ > - type: apt
162
+ > - type: dnf
163
+ > ```
164
+
165
+ > [!TIP]
166
+ > When declaring a simple string, it is expanded as the `type` property:
167
+ >
168
+ > ```yaml
169
+ > git:
170
+ > - apt
171
+ > - dnf
172
+ > ```
173
+
174
+ ### 2. Add dependencies between packages
175
+
176
+ - By declaring another package:
177
+
178
+ ```yaml
179
+ pip:
180
+ - type: apt
181
+ packages:
182
+ - python3-pip
183
+ depends_on:
184
+ - zsh
185
+
186
+ zsh: [apt]
187
+ ```
188
+
189
+ - By inlining the dependency as another **Package**:
190
+
191
+ ```yaml
192
+ pip:
193
+ - type: apt
194
+ packages: [python3-pip]
195
+ depends_on:
196
+ - type: apt
197
+ packages: [zsh]
198
+ ```
199
+
200
+ > [!WARNING]
201
+ > If dependency is not declared, distroscript will output a TODO comment, so
202
+ > the user can manually add it to the configuration file later if needed.
203
+
204
+ ### 3. Run commands before or after install
205
+
206
+ - All packages could define `pre_install` and `post_install` steps as a list
207
+ of **Commands** to be executed before or after the installation.
208
+
209
+ ```yaml
210
+ zsh:
211
+ - type: apt
212
+ pre_install: [...]
213
+ post_install: [...]
214
+ ```
215
+
216
+ - Type `shell` inlines the content into the destination script:
217
+
218
+ ```yml
219
+ zsh:
220
+ - type: apt
221
+ post_install:
222
+ - type: shell
223
+ content: |
224
+ chsh -s "$(which zsh)" "$USER"
225
+ ```
226
+
227
+ > [!TIP]
228
+ > It's the default in case we provide a simple string:
229
+ >
230
+ > ```yaml
231
+ > zsh:
232
+ > - type: apt
233
+ > post_install: |
234
+ > chsh -s "$(which zsh)" "$USER"
235
+ > ```
236
+
237
+ - Type `tee` writes content to a file, useful to add desktop entries or config files:
238
+
239
+ ```yaml
240
+ kazam:
241
+ - type: pip
242
+ post_install:
243
+ - type: tee
244
+ destination: "$HOME/.local/share/applications/kazam.desktop"
245
+ content: |
246
+ [Desktop Entry]
247
+ Name=Kazam
248
+ Exec=kazam
249
+ ...
250
+ ```
251
+
252
+ > [!TIP]
253
+ > By default, it overwrites the file, but if `append: true` is set, it appends
254
+ > to the file so existing content is preserved:
255
+ >
256
+ > ```yaml
257
+ > zsh:
258
+ > - type: apt
259
+ > post_install:
260
+ > - type: tee
261
+ > destination: "$HOME/.zshrc"
262
+ > append: true
263
+ > content: |
264
+ > # pip
265
+ > export PATH="$HOME/.local/bin:$PATH"
266
+ > ```
267
+
268
+ > [!TIP]
269
+ > You can also specify `sudo: true` to write the file to a destination that
270
+ > requires elevated permissions:
271
+ >
272
+ > ```yaml
273
+ > dnf-automatic:
274
+ > - type: dnf
275
+ > post_install:
276
+ > - type: tee
277
+ > destination: /etc/dnf/automatic.conf
278
+ > sudo: true
279
+ > content: |
280
+ > [commands]
281
+ > apply_updates=True
282
+ > ```
283
+
284
+ > [!TIP]
285
+ > You can specify `mkdir: true` to create the destination directory before writing
286
+ > the file:
287
+ >
288
+ > ```yaml
289
+ > kazam:
290
+ > - type: pip
291
+ > post_install:
292
+ > - type: tee
293
+ > destination: "$HOME/.local/share/applications/kazam.desktop"
294
+ > mkdir: true
295
+ > content: |
296
+ > [Desktop Entry]
297
+ > Name=Kazam
298
+ > Exec=kazam
299
+ > ...
300
+ > ```
301
+
302
+ ### 4. Install from Flatpak, Snap, Pip, Tar, Zip, GitHub, File, Shell, or AppImage
303
+
304
+ For these types, if specified `--os` does not include the required command, it
305
+ will be included as a dependency, as if we declared it in `depends_on` as
306
+ a single string.
307
+
308
+ This allows the user to provide an installation method for the package manager
309
+ itself if needed.
310
+
311
+ **Flatpak:**
312
+
313
+ ```yaml
314
+ kdenlive:
315
+ - type: flatpak
316
+ packages: [org.kde.kdenlive]
317
+ # depends_on: [flatpak] # Added implicitly if running on an OS without flatpak pre-installed
318
+ ```
319
+
320
+ **Snap:**
321
+
322
+ ```yaml
323
+ code:
324
+ - type: snapd
325
+ packages: [code]
326
+ classic: true # Optional: adds the --classic flag
327
+ # depends_on: [snapd] # Added implicitly if running on an OS without snapd pre-installed
328
+ ```
329
+
330
+ **Pip:**
331
+
332
+ ```yaml
333
+ yt-dlp:
334
+ - type: pip
335
+ packages: ["yt-dlp[default]"]
336
+ # depends_on: [pip] # Added implicitly if running on an OS without pip pre-installed
337
+ ```
338
+
339
+ **Tar:**
340
+
341
+ ```yaml
342
+ go:
343
+ - type: tar
344
+ url: "https://go.dev/dl/go1.20.5.linux-amd64.tar.gz"
345
+ destination: /usr/local
346
+ sudo: true # Optional: use sudo to extract to destination
347
+ ```
348
+
349
+ **Zip:**
350
+
351
+ ```yaml
352
+ jetbrains-nf:
353
+ - type: zip
354
+ url: "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.0.2/JetBrainsMono.zip"
355
+ destination: /usr/share/fonts/JetBrainsMonoNerdFont
356
+ sudo: true # Optional: use sudo to extract to destination
357
+ ```
358
+
359
+ **GitHub:**
360
+
361
+ ```yaml
362
+ cspec:
363
+ - type: github
364
+ repository: mumuki/cspec
365
+ install: |
366
+ make
367
+ sudo make install
368
+ ```
369
+
370
+ **File:**
371
+
372
+ ```yaml
373
+ doctest:
374
+ - type: file
375
+ url: https://raw.githubusercontent.com/doctest/doctest/v2.4.12/doctest/doctest.h
376
+ destination: /usr/local/include/doctest/doctest.h
377
+ sudo: true # Optional: use sudo to write to destination
378
+ silent: true # Optional: suppress output after download
379
+ executable: false # Optional: make the file executable after download
380
+ ```
381
+
382
+ **Shell:**
383
+
384
+ - By providing an url:
385
+
386
+ ```yaml
387
+ rust:
388
+ - type: shell
389
+ url: https://sh.rustup.rs
390
+ shell: bash # Optional: specify the shell to use (default: bash).
391
+ # Will be added as a dependency if not preinstalled in the target OS.
392
+ ```
393
+
394
+ - By providing an inline script:
395
+
396
+ ```yaml
397
+ oh-my-zsh:
398
+ - type: shell
399
+ script: |
400
+ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
401
+ shell: zsh # Optional: specify the shell to use (default: bash).
402
+ # Will be added as a dependency if not preinstalled in the target OS.
403
+ ```
404
+
405
+ **AppImage:**
406
+
407
+ ```yaml
408
+ duckstation:
409
+ - type: appimage
410
+ url: https://github.com/stenzek/duckstation/releases/download/latest/DuckStation-x64.AppImage
411
+ name: DuckStation
412
+ icon_name: org.duckstation.DuckStation
413
+ categories:
414
+ - Game
415
+ - Emulator
416
+ ```
417
+
418
+ AppImages are downloaded to `$HOME/.local/bin/`, a desktop entry is created in
419
+ `$HOME/.local/share/applications/`, and icons are extracted automatically when `icon_name` is specified.
420
+
421
+ > [!NOTE]
422
+ > AppImage packages require the `url` field. The `name`, `icon_name`, and `categories` fields are optional.
423
+ > The `name` field defaults to the package name, `icon_name` enables desktop icon extraction when provided,
424
+ > and `categories` defaults to "Application".
425
+
426
+ ### 5. Use custom flags for package managers
427
+
428
+ ```yaml
429
+ gh:
430
+ - type: dnf
431
+ flags:
432
+ - "--repo gh-cli"
433
+ pre_install: |
434
+ sudo dnf config-manager addrepo --from-repofile=https://cli.github.com/packages/rpm/gh-cli.repo
435
+
436
+ gleam:
437
+ - type: dnf
438
+ copr: frostyx/gleam
439
+ pre_install: |
440
+ sudo dnf copr enable frostyx/gleam -y
441
+ ```
442
+
443
+ > [!TIP]
444
+ > For `dnf`, you can also specify `repo`, `repofile` and/or `copr` properties:
445
+ >
446
+ > ```yaml
447
+ > gh:
448
+ > - type: dnf
449
+ > repo: gh-cli
450
+ > repofile: https://cli.github.com/packages/rpm/gh-cli.repo
451
+ >
452
+ > gleam:
453
+ > - type: dnf
454
+ > copr: frostyx/gleam
455
+ > ```
456
+
457
+ ### 6. Add desktop entries or config files
458
+
459
+ ```yaml
460
+ kazam:
461
+ - type: pip
462
+ post_install:
463
+ - type: tee
464
+ destination: "$HOME/.local/share/applications/kazam.desktop"
465
+ content: |
466
+ [Desktop Entry]
467
+ Name=Kazam
468
+ Exec=kazam
469
+ ...
470
+ ```
471
+
472
+ ### 7. Merging multiple packages to a single install command
473
+
474
+ If multiple packages use the same installation method and are not codependant,
475
+ they will be merged into a single command to optimize the installation process.
476
+
477
+ ```yaml
478
+ jq: [apt]
479
+
480
+ htop: [apt]
481
+
482
+ zsh: [apt]
483
+
484
+ pip:
485
+ - type: apt
486
+ packages: [python3-pip]
487
+ depends_on: [zsh]
488
+ ```
489
+
490
+ Output:
491
+
492
+ ```bash
493
+ #!/bin/bash
494
+
495
+ sudo apt-get install -y jq htop zsh
496
+
497
+ sudo apt-get install -y python3-pip
498
+ ```
499
+
500
+ ### 8. Combine everything for complex setups
501
+
502
+ ```yaml
503
+ docker:
504
+ - type: dnf
505
+ packages:
506
+ - docker
507
+ - docker-ce
508
+ - docker-ce-cli
509
+ - containerd.io
510
+ - docker-buildx-plugin
511
+ - docker-compose-plugin
512
+ repofile: https://download.docker.com/linux/fedora/docker-ce.repo
513
+ depends_on:
514
+ - type: dnf
515
+ packages: [dnf5-plugins]
516
+ post_install: |
517
+ sudo systemctl enable --now docker
518
+ sudo groupadd -f docker
519
+ sudo usermod -aG docker "$USER"
520
+ ```
521
+
522
+ Output:
523
+
524
+ ```bash
525
+ #!/bin/bash
526
+
527
+ sudo dnf install -y dnf5-plugins docker docker-ce docker-ce-cli \
528
+ containerd.io docker-buildx-plugin docker-compose-plugin
529
+
530
+ sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
531
+
532
+ sudo systemctl enable --now docker
533
+ sudo groupadd -f docker
534
+ sudo usermod -aG docker "$USER"
535
+ ```
536
+
537
+ ## License
538
+
539
+ This project is licensed under the BSD 3-Clause License. See the
540
+ [LICENSE](LICENSE) file for details.
541
+
542
+ ## Author
543
+
544
+ Agustin Ranieri - [@RaniAgus](https://github.com/RaniAgus)
@@ -0,0 +1,7 @@
1
+ distroscript.py,sha256=4sifs7tsVwuXKJAaOHxRKETgePmVDQkiN6nASKEQQnY,36837
2
+ schema.json,sha256=fmWCV6RvhZYPO5k9dL4-qxve5oVOSB6-d8yUN1n688A,12407
3
+ distroscript-0.1.0.dist-info/METADATA,sha256=s9aZyN6FhIk6i-6Uyeu8IJBQcBL65r0oTC4cPJHstdI,13214
4
+ distroscript-0.1.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
5
+ distroscript-0.1.0.dist-info/entry_points.txt,sha256=oFs-eZYR_X8Myw4qjEQEhJ8ozfbd4BfZ-4sRVDx8y1Q,51
6
+ distroscript-0.1.0.dist-info/licenses/LICENSE,sha256=OwosxeMZBKbs6r5qh0FkkJjiPL03gYPLgvrQio1lgQo,1502
7
+ distroscript-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ distroscript = distroscript:_cli
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, Agustin Ranieri
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.