feat: dnf module (#377)
Co-authored-by: xyny <60004820+xynydev@users.noreply.github.com> Co-authored-by: Gerald Pinder <gmpinder@gmail.com> Co-authored-by: certifiedfoolio <156134535+cherry-os@users.noreply.github.com> Co-authored-by: xyny <git@xyny.anonaddy.me> Co-authored-by: somebody once told me <156134535+certifiedfoolio@users.noreply.github.com> Co-authored-by: franute <franute@gmail.com>
This commit is contained in:
parent
d12d657371
commit
fef0f17870
13 changed files with 1712 additions and 4 deletions
|
|
@ -7,7 +7,7 @@ let images = ls modules | each { |moduleDir|
|
||||||
cd $moduleDir.name
|
cd $moduleDir.name
|
||||||
|
|
||||||
# module is unversioned
|
# module is unversioned
|
||||||
if ($"($moduleDir.name | path basename).sh" | path exists) {
|
if (glob $"($moduleDir.name | path basename).{sh,nu}" | any { path exists }) {
|
||||||
|
|
||||||
print $"(ansi cyan)Found(ansi reset) (ansi cyan_bold)unversioned(ansi reset) (ansi cyan)module:(ansi reset) ($moduleDir.name | path basename)"
|
print $"(ansi cyan)Found(ansi reset) (ansi cyan_bold)unversioned(ansi reset) (ansi cyan)module:(ansi reset) ($moduleDir.name | path basename)"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ mkdir ./modules-latest
|
||||||
ls modules | each { |moduleDir|
|
ls modules | each { |moduleDir|
|
||||||
|
|
||||||
# module is unversioned
|
# module is unversioned
|
||||||
if ($"($moduleDir.name)/($moduleDir.name | path basename).sh" | path exists) {
|
if (glob $"($moduleDir.name)/($moduleDir.name | path basename).{sh,nu}" | any { path exists }) {
|
||||||
|
|
||||||
print $"(ansi cyan)Found(ansi reset) (ansi cyan_bold)unversioned(ansi reset) (ansi cyan)module:(ansi reset) ($moduleDir.name | path basename)"
|
print $"(ansi cyan)Found(ansi reset) (ansi cyan_bold)unversioned(ansi reset) (ansi cyan)module:(ansi reset) ($moduleDir.name | path basename)"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/gschema-overrides/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/gschema-overrides/module.yml",
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/justfiles/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/justfiles/module.yml",
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/rpm-ostree/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/rpm-ostree/module.yml",
|
||||||
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/dnf/module.yml",
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/kargs/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/kargs/module.yml",
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/initramfs/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/initramfs/module.yml",
|
||||||
"https://raw.githubusercontent.com/blue-build/modules/main/modules/script/module.yml",
|
"https://raw.githubusercontent.com/blue-build/modules/main/modules/script/module.yml",
|
||||||
|
|
|
||||||
265
modules/dnf/README.md
Normal file
265
modules/dnf/README.md
Normal file
|
|
@ -0,0 +1,265 @@
|
||||||
|
# **`dnf` Module**
|
||||||
|
|
||||||
|
The `dnf` module offers pseudo-declarative package and repository management using [`dnf5`](https://github.com/rpm-software-management/dnf).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
This module is capable of:
|
||||||
|
|
||||||
|
- Repository Management
|
||||||
|
- Enabling/disabling COPR repos
|
||||||
|
- Adding repo files via url or local files
|
||||||
|
- Removing repos by specifying the repo name
|
||||||
|
- Automatically cleaning up any repos added in the module
|
||||||
|
- Adding keys for repos via url or local files
|
||||||
|
- Adding non-free repos like `rpmfusion` and `negativo17`
|
||||||
|
- Package Management
|
||||||
|
- Installing packages from RPM urls, local RPM files, or package repositories
|
||||||
|
- Installing packages from a specific repository
|
||||||
|
- Removing packages
|
||||||
|
- Replacing installed packages with versions from another repository
|
||||||
|
- Optfix
|
||||||
|
- Setup symlinks to `/opt/` to allow certain packages to install
|
||||||
|
|
||||||
|
## Repository Management
|
||||||
|
|
||||||
|
### Add Repository Files
|
||||||
|
|
||||||
|
- Add repos from
|
||||||
|
- any `https://` or `http://` URL
|
||||||
|
- any `.repo` files located in `./files/dnf/` of your image repo
|
||||||
|
- If the OS version is included in the file name or URL, you can substitute it with the `%OS_VERSION%` magic string
|
||||||
|
- The version is gathered from the `VERSION_ID` field of `/usr/lib/os-release`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
files:
|
||||||
|
- https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||||
|
- custom-file.repo # file path for /files/dnf/custom-file.repo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add COPR Repositories
|
||||||
|
|
||||||
|
- [COPR](https://copr.fedorainfracloud.org/) contains software repositories maintained by fellow Fedora users
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
copr:
|
||||||
|
- atim/starship
|
||||||
|
- trixieua/mutter-patched
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disable/Enable Repositories
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
files:
|
||||||
|
add:
|
||||||
|
- repo1
|
||||||
|
- repo2
|
||||||
|
remove:
|
||||||
|
- repo3
|
||||||
|
copr:
|
||||||
|
enable:
|
||||||
|
- ryanabx/cosmic-epoch
|
||||||
|
disable:
|
||||||
|
- kylegospo/oversteer
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Repository Keys
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
keys:
|
||||||
|
- https://example.com/repo-1.asc
|
||||||
|
- key2.asc
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Non-free Repositories
|
||||||
|
|
||||||
|
This allows you to add a commonly used non-free repository.
|
||||||
|
You can choose between [negativo17](https://negativo17.org/) and [rpmfusion](https://rpmfusion.org/).
|
||||||
|
Your choice will also disable the opposite repository if it was already enabled.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
nonfree: negativo17
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
There is currently only one option that can be specified in the repository management section.
|
||||||
|
|
||||||
|
- `cleanup` automatically cleans up repositories added in this section
|
||||||
|
- Disabled by default
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
cleanup: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Package Management
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
#### Packages from Any Repository
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
install:
|
||||||
|
packages:
|
||||||
|
- package-1
|
||||||
|
- package-2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Packages from URL or File
|
||||||
|
|
||||||
|
- If the OS version is included in the file name or URL, you can substitute it with the `%OS_VERSION%` magic string
|
||||||
|
- The version is gathered from the `VERSION_ID` field of `/usr/lib/os-release`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
install:
|
||||||
|
packages:
|
||||||
|
- https://example.com/package-%OS_VERSION%.rpm
|
||||||
|
- custom-file.rpm # install files/dnf/custom-file.rpm from the image repository
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Packages from Specific Repositories
|
||||||
|
|
||||||
|
- Set `repo` to the name of the RPM repository, not the name or URL of the repo file
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
install:
|
||||||
|
packages:
|
||||||
|
- repo: copr:copr.fedorainfracloud.org:custom-user:custom-repo
|
||||||
|
packages:
|
||||||
|
- package-1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Package Groups
|
||||||
|
|
||||||
|
- See list of all package groups by running `dnf5 group list --hidden` on a live system
|
||||||
|
- Set the option `with-optional` to `true` to enable installation of optional packages in package groups
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
group-install:
|
||||||
|
with-optional: true
|
||||||
|
packages:
|
||||||
|
- de-package-1
|
||||||
|
- wm-package-2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Replace Packages
|
||||||
|
- You can specify one or more packages that will be swapped from another repo
|
||||||
|
- This process uses `distro-sync` to perform this operation
|
||||||
|
- All packages not specifying `old:` and `new:` will be swapped in a single transaction
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
replace:
|
||||||
|
- from-repo: copr:copr.fedorainfracloud.org:custom-user:custom-repo
|
||||||
|
packages:
|
||||||
|
- package-1
|
||||||
|
```
|
||||||
|
|
||||||
|
- If a package has a different name in another repo, you can use the `old:` and `new:` properties
|
||||||
|
- This process uses `swap` to perform this operation for each set
|
||||||
|
- This process is ran before `distro-sync`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
replace:
|
||||||
|
- from-repo: repo-1
|
||||||
|
packages:
|
||||||
|
- old: old-package-2
|
||||||
|
new: new-package-2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
The following options can specified in the package installation, group installation, and package replacement sections.
|
||||||
|
|
||||||
|
- `install-weak-deps` enables installation of the weak dependencies of RPMs
|
||||||
|
- Enabled by default
|
||||||
|
- Corresponds to the [`--setopt=install_weak_deps=True` / `--setopt=install_weak_deps=False`](https://dnf5.readthedocs.io/en/latest/dnf5.conf.5.html#install-weak-deps-options-label) flag
|
||||||
|
- `skip-unavailable` enables skipping packages unavailable in repositories without erroring out
|
||||||
|
- Disabled by default
|
||||||
|
- Corresponds to the [`--skip-unavailable`](https://dnf5.readthedocs.io/en/latest/commands/install.8.html#options) flag
|
||||||
|
- `skip-broken` enables skipping broken packages without erroring out
|
||||||
|
- Disabled by default
|
||||||
|
- Corresponds to the [`--skip-broken`](https://dnf5.readthedocs.io/en/latest/commands/install.8.html#options) flag
|
||||||
|
- `allow-erasing` allows removing packages in case of dependency problems during package installation
|
||||||
|
- Disabled by default
|
||||||
|
- Corresponds to the [`--allowerasing`](https://dnf5.readthedocs.io/en/latest/commands/install.8.html#options) flag
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
install:
|
||||||
|
skip-unavailable: true
|
||||||
|
packages:
|
||||||
|
...
|
||||||
|
group-install:
|
||||||
|
skip-broken: true
|
||||||
|
packages:
|
||||||
|
...
|
||||||
|
replace:
|
||||||
|
- from-repo: repo-1
|
||||||
|
allow-erasing: true
|
||||||
|
packages:
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Removing
|
||||||
|
|
||||||
|
#### Packages
|
||||||
|
|
||||||
|
- You can set the `auto-remove` option to `false` to only remove the specific package and leave unused dependencies
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
remove:
|
||||||
|
auto-remove: false
|
||||||
|
packages:
|
||||||
|
- package-1
|
||||||
|
- package-2
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Package Groups
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
group-remove:
|
||||||
|
packages:
|
||||||
|
- de-package-2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Optfix
|
||||||
|
|
||||||
|
- Optfix is a script used to work around problems with certain packages that install into `/opt/`
|
||||||
|
- These issues are caused by Fedora Atomic storing `/opt/` at the location `/var/opt/` by default, while `/var/` is only writeable on a live system
|
||||||
|
- The script works around these issues by moving the folder to `/usr/lib/opt/` and creating the proper symlinks at runtime
|
||||||
|
- Specify a list of folders inside `/opt/`
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
type: dnf
|
||||||
|
optfix:
|
||||||
|
- brave.com
|
||||||
|
- foldername
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
|
||||||
|
Replacing the kernel with the `dnf` module is not done cleanly at the moment & some remaints of old kernel will be present.
|
||||||
|
Please use the `rpm-ostree` module for this purpose until this `dnf` behavior is fixed.
|
||||||
|
|
||||||
|
## Note
|
||||||
|
|
||||||
|
This documentation page uses the installation of the Brave Browser as an example of a package that required a custom repository, with a custom key, and an optfix configuration to install properly. This is not an official endorsement of the Brave Browser by the BlueBuild project.
|
||||||
11
modules/dnf/bluebuild-optfix.service
Normal file
11
modules/dnf/bluebuild-optfix.service
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Unit]
|
||||||
|
Description=Create symbolic links for directories in /usr/lib/opt/ to /var/opt/
|
||||||
|
After=multi-user.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/libexec/bluebuild/optfix.sh
|
||||||
|
RemainAfterExit=no
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
84
modules/dnf/dnf-repoinfo
Executable file
84
modules/dnf/dnf-repoinfo
Executable file
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# convert the output of dnf repoinfo into json
|
||||||
|
|
||||||
|
repo_id="$1"
|
||||||
|
repo_info=$(dnf repoinfo -q "$repo_id")
|
||||||
|
|
||||||
|
echo "["
|
||||||
|
echo " {"
|
||||||
|
|
||||||
|
repo_id_val=$(echo "$repo_info" | grep -oP "^Repo-id *: *\K.*")
|
||||||
|
if [ -n "$repo_id_val" ]; then
|
||||||
|
echo " \"id\":\"$repo_id_val\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_name=$(echo "$repo_info" | grep -oP "^Repo-name *: *\K.*")
|
||||||
|
if [ -n "$repo_name" ]; then
|
||||||
|
echo " \"name\":\"$repo_name\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_status=$(echo "$repo_info" | grep -oP "^Repo-status *: *\K.*")
|
||||||
|
if [ -n "$repo_status" ]; then
|
||||||
|
if [[ "$repo_status" == "enabled" ]]; then
|
||||||
|
echo " \"is_enabled\":true,"
|
||||||
|
else
|
||||||
|
echo " \"is_enabled\":false,"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_revision=$(echo "$repo_info" | grep -oP "^Repo-revision *: *\K.*")
|
||||||
|
if [ -n "$repo_revision" ]; then
|
||||||
|
echo " \"revision\":\"$repo_revision\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_updated=$(echo "$repo_info" | grep -oP "^Repo-updated *: *\K.*")
|
||||||
|
if [ -n "$repo_updated" ]; then
|
||||||
|
echo " \"updated\":\"$repo_updated\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_available_pkgs=$(echo "$repo_info" | grep -oP "^Repo-available-pkgs *: *\K.*")
|
||||||
|
if [ -n "$repo_available_pkgs" ]; then
|
||||||
|
echo " \"available-pkgs\":$repo_available_pkgs,"
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_pkgs=$(echo "$repo_info" | grep -oP "^Repo-pkgs *: *\K.*")
|
||||||
|
if [ -n "$repo_pkgs" ]; then
|
||||||
|
echo " \"pkgs\":$repo_pkgs,"
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_size=$(echo "$repo_info" | grep -oP "^Repo-size *: *\K.*")
|
||||||
|
if [ -n "$repo_size" ]; then
|
||||||
|
echo " \"size\":\"$repo_size\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_metalink=$(echo "$repo_info" | grep -oP "^Repo-metalink *: *\K.*")
|
||||||
|
if [ -n "$repo_metalink" ]; then
|
||||||
|
echo " \"metalink\":\"$repo_metalink\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
updated=$(echo "$repo_info" | grep -oP "^Updated *: *\K.*")
|
||||||
|
if [ -n "$updated" ]; then
|
||||||
|
echo " \"updated\":\"$updated\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_baseurl=$(echo "$repo_info" | grep -oP "^Repo-baseurl *: *\K.*")
|
||||||
|
if [ -n "$repo_baseurl" ]; then
|
||||||
|
echo " \"baseurl\":\"$repo_baseurl\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_expire=$(echo "$repo_info" | grep -oP "^Repo-expire *: *\K.*")
|
||||||
|
if [ -n "$repo_expire" ]; then
|
||||||
|
echo " \"expire\":\"$repo_expire\","
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_filename=$(echo "$repo_info" | grep -oP "^Repo-filename *: *\K.*")
|
||||||
|
if [ -n "$repo_filename" ]; then
|
||||||
|
echo " \"repo_file_path\":\"$repo_filename\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$(tail -c 2 <<< "$(echo "$repo_info")" | head -c 1)" == "," ]]; then
|
||||||
|
sed -i '$ s/,$//'
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " }"
|
||||||
|
echo "]"
|
||||||
29
modules/dnf/dnf-repolist
Executable file
29
modules/dnf/dnf-repolist
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# convert the output of dnf repolist into json
|
||||||
|
|
||||||
|
output=$(dnf repolist -q --all 2>/dev/null)
|
||||||
|
lines=$(echo "$output" | tail -n +3)
|
||||||
|
|
||||||
|
echo "["
|
||||||
|
|
||||||
|
echo "$lines" | while read -r line; do
|
||||||
|
repo_id=$(echo "$line" | awk '{print $1}')
|
||||||
|
status=$(echo "$line" | awk '{print $NF}')
|
||||||
|
repo_name=$(echo "$line" | awk '{$1=""; $NF=""; print $0}' | sed -e 's/^ *//g' -e 's/ *$//g')
|
||||||
|
|
||||||
|
if [ "$status" = "enabled" ]; then
|
||||||
|
status=true
|
||||||
|
else
|
||||||
|
status=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF
|
||||||
|
{
|
||||||
|
"id":"$repo_id",
|
||||||
|
"name":"$repo_name",
|
||||||
|
"is_enabled":$status
|
||||||
|
},
|
||||||
|
EOF
|
||||||
|
done | sed '$s/},/}/'
|
||||||
|
|
||||||
|
echo "]"
|
||||||
690
modules/dnf/dnf.nu
Normal file
690
modules/dnf/dnf.nu
Normal file
|
|
@ -0,0 +1,690 @@
|
||||||
|
#!/usr/bin/env nu
|
||||||
|
|
||||||
|
use dnf_interface.nu *
|
||||||
|
|
||||||
|
const NEGATIVO = 'negativo17'
|
||||||
|
const NEGATIVO_URL = 'https://negativo17.org/repos/fedora-negativo17.repo'
|
||||||
|
const RPMFUSION = 'rpmfusion'
|
||||||
|
|
||||||
|
# Handle adding/removing repo files and COPR repos.
|
||||||
|
#
|
||||||
|
# This command returns an object containing the repos
|
||||||
|
# that were added to allow for cleaning up afterwards.
|
||||||
|
def repos [$repos: record]: nothing -> record {
|
||||||
|
let repos = $repos
|
||||||
|
| default [] keys
|
||||||
|
|
||||||
|
let cleanup_repos = match $repos.files? {
|
||||||
|
# Add repos if it's a list
|
||||||
|
[..$files] => {
|
||||||
|
add_repos ($files | default [])
|
||||||
|
}
|
||||||
|
# Add and remove repos
|
||||||
|
{
|
||||||
|
add: [..$add]
|
||||||
|
remove: [..$remove]
|
||||||
|
} => {
|
||||||
|
let repos = add_repos ($add | default [])
|
||||||
|
remove_repos ($remove | default [])
|
||||||
|
$repos
|
||||||
|
}
|
||||||
|
# Add repos
|
||||||
|
{ add: [..$add] } => {
|
||||||
|
add_repos ($add | default [])
|
||||||
|
}
|
||||||
|
# Remove repos
|
||||||
|
{ remove: [..$remove] } => {
|
||||||
|
remove_repos ($remove | default [])
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
_ => []
|
||||||
|
}
|
||||||
|
|
||||||
|
let cleanup_coprs = match $repos.copr? {
|
||||||
|
# Enable repos if it's a list
|
||||||
|
[..$coprs] => {
|
||||||
|
add_coprs ($coprs | default [])
|
||||||
|
}
|
||||||
|
# Enable and disable repos
|
||||||
|
{
|
||||||
|
enable: [..$enable]
|
||||||
|
disable: [..$disable]
|
||||||
|
} => {
|
||||||
|
let coprs = add_coprs ($enable | default [])
|
||||||
|
disable_coprs ($disable | default [])
|
||||||
|
$coprs
|
||||||
|
}
|
||||||
|
# Enable repos
|
||||||
|
{ enable: [..$enable] } => {
|
||||||
|
add_coprs ($enable | default [])
|
||||||
|
}
|
||||||
|
# Disable repos
|
||||||
|
{ disable: [..$disable] } => {
|
||||||
|
disable_coprs ($disable | default [])
|
||||||
|
[]
|
||||||
|
}
|
||||||
|
_ => []
|
||||||
|
}
|
||||||
|
|
||||||
|
nonfree_repos $repos.nonfree?
|
||||||
|
add_keys $repos.keys
|
||||||
|
|
||||||
|
{
|
||||||
|
copr: $cleanup_coprs
|
||||||
|
files: $cleanup_repos
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup nonfree repos for rpmfusion or negativo17-multimedia.
|
||||||
|
def nonfree_repos [repo_type?: string]: nothing -> list<string> {
|
||||||
|
match $repo_type {
|
||||||
|
$repo if $repo == $RPMFUSION => {
|
||||||
|
disable_negativo
|
||||||
|
enable_rpmfusion
|
||||||
|
}
|
||||||
|
$repo if $repo == $NEGATIVO => {
|
||||||
|
disable_rpmfusion
|
||||||
|
enable_negativo
|
||||||
|
}
|
||||||
|
null => [],
|
||||||
|
_ => {
|
||||||
|
error make {
|
||||||
|
msg: $"The only valid values are '($NEGATIVO)' and '($RPMFUSION)'"
|
||||||
|
label: {
|
||||||
|
text: 'Passed in value'
|
||||||
|
span: (metadata $repo_type).span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable rpmfusion repos
|
||||||
|
#
|
||||||
|
# See https://rpmfusion.org/Configuration
|
||||||
|
def enable_rpmfusion []: nothing -> nothing {
|
||||||
|
const CISCO_REPO = 'fedora-cisco-openh264'
|
||||||
|
|
||||||
|
print $'(ansi green)Enabling rpmfusion repos(ansi reset)'
|
||||||
|
|
||||||
|
mut repos = []
|
||||||
|
|
||||||
|
if (^rpm -q rpmfusion-free-release | complete).exit_code != 0 {
|
||||||
|
$repos = $repos | append $'https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-($env.OS_VERSION).noarch.rpm'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (^rpm -q rpmfusion-nonfree-release | complete).exit_code != 0 {
|
||||||
|
$repos = $repos | append $'https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-($env.OS_VERSION).noarch.rpm'
|
||||||
|
}
|
||||||
|
|
||||||
|
install_pkgs { packages: $repos }
|
||||||
|
|
||||||
|
print $"(ansi green)Enabling '(ansi cyan)($CISCO_REPO)(ansi green)' repo for RPMFusion compatibility(ansi reset)"
|
||||||
|
dnf config-manager setopt [$'($CISCO_REPO).enabled=1']
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable rpmfusion repos
|
||||||
|
def disable_rpmfusion []: nothing -> nothing {
|
||||||
|
print $'(ansi green)Removing rpmfusion repos(ansi reset)'
|
||||||
|
|
||||||
|
mut repos = []
|
||||||
|
|
||||||
|
if (^rpm -q rpmfusion-free-release | complete).exit_code == 0 {
|
||||||
|
$repos = $repos | append 'rpmfusion-free-release'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (^rpm -q rpmfusion-nonfree-release | complete).exit_code == 0 {
|
||||||
|
$repos = $repos | append 'rpmfusion-nonfree-release'
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_pkgs { packages: $repos }
|
||||||
|
}
|
||||||
|
|
||||||
|
def negativo_repo_list []: nothing -> list<path> {
|
||||||
|
dnf repo list
|
||||||
|
| find negativo17
|
||||||
|
| get id
|
||||||
|
| ansi strip
|
||||||
|
| par-each {|repo|
|
||||||
|
dnf repo info $repo --all
|
||||||
|
}
|
||||||
|
| flatten
|
||||||
|
| get id
|
||||||
|
| uniq
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable negativo17-multimedia repos
|
||||||
|
def enable_negativo []: nothing -> nothing {
|
||||||
|
print $'(ansi green)Enabling negativo17 repos(ansi reset)'
|
||||||
|
|
||||||
|
let current_repo_list = negativo_repo_list
|
||||||
|
|
||||||
|
if ($current_repo_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Cleaning up existing negativo17 repos(ansi reset)'
|
||||||
|
remove_repos $current_repo_list
|
||||||
|
}
|
||||||
|
add_repos [$NEGATIVO_URL]
|
||||||
|
|
||||||
|
dnf repo list
|
||||||
|
| find negativo17
|
||||||
|
| get id
|
||||||
|
| ansi strip
|
||||||
|
| each {|id|
|
||||||
|
[$'($id).enabled=1' $'($id).priority=90']
|
||||||
|
}
|
||||||
|
| flatten
|
||||||
|
| dnf config-manager setopt $in
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable negativo17-multimedia repos
|
||||||
|
def disable_negativo []: nothing -> nothing {
|
||||||
|
print $'(ansi green)Disabling negativo17 repos(ansi reset)'
|
||||||
|
|
||||||
|
remove_repos (negativo_repo_list)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adds a list of repo files for `dnf` to use
|
||||||
|
# for installing packages.
|
||||||
|
#
|
||||||
|
# Returns a list of IDs of the repos added
|
||||||
|
def add_repos [$repos: list]: nothing -> list<string> {
|
||||||
|
if ($repos | is-not-empty) {
|
||||||
|
print $'(ansi green)Adding repositories:(ansi reset)'
|
||||||
|
|
||||||
|
# Substitute %OS_VERSION% & remove newlines/whitespaces from all repo entries
|
||||||
|
let repos = $repos
|
||||||
|
| each {
|
||||||
|
str replace --all '%OS_VERSION%' $env.OS_VERSION
|
||||||
|
| str trim
|
||||||
|
}
|
||||||
|
$repos
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
for $repo in $repos {
|
||||||
|
let repo_path = [$env.CONFIG_DIRECTORY dnf $repo] | path join
|
||||||
|
let repo = if ($repo | str starts-with 'https://') or ($repo | str starts-with 'http://') {
|
||||||
|
print $"Adding repository URL: (ansi cyan)'($repo)'(ansi reset)"
|
||||||
|
$repo
|
||||||
|
} else if ($repo | str ends-with '.repo') and ($repo_path | path exists) {
|
||||||
|
print $"Adding repository file: (ansi cyan)'($repo_path)'(ansi reset)"
|
||||||
|
$repo_path
|
||||||
|
} else {
|
||||||
|
return (error make {
|
||||||
|
msg: $"(ansi red)Unrecognized repo (ansi cyan)'($repo)'(ansi reset)"
|
||||||
|
label: {
|
||||||
|
span: (metadata $repo).span
|
||||||
|
text: 'Found in config'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dnf config-manager addrepo --from-repofile $repo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get a list of paths of all new repo files added
|
||||||
|
let repo_files = $repos
|
||||||
|
| each {|repo|
|
||||||
|
[/ etc yum.repos.d ($repo | path basename)] | path join
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get a list of info for every repo installed
|
||||||
|
let repo_info = dnf repo list
|
||||||
|
| get id
|
||||||
|
| par-each {|repo|
|
||||||
|
dnf repo info $repo
|
||||||
|
}
|
||||||
|
| flatten
|
||||||
|
|
||||||
|
# Return the IDs of all repos that were added
|
||||||
|
let repo_ids = $repo_info
|
||||||
|
| filter {|repo|
|
||||||
|
$repo.repo_file_path in $repo_files
|
||||||
|
}
|
||||||
|
| get id
|
||||||
|
|
||||||
|
$repo_ids
|
||||||
|
| each {
|
||||||
|
print $'Enabling repo (ansi cyan)($in)(ansi reset)'
|
||||||
|
$'($in).enabled=1'
|
||||||
|
}
|
||||||
|
| dnf config-manager setopt $in
|
||||||
|
|
||||||
|
$repo_ids
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove a list of repos. The list must be the IDs of the repos.
|
||||||
|
def remove_repos [$repos: list]: nothing -> nothing {
|
||||||
|
if ($repos | is-not-empty) {
|
||||||
|
print $'(ansi green)Removing repositories:(ansi reset)'
|
||||||
|
let repos = $repos | str trim
|
||||||
|
$repos
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
$repos
|
||||||
|
| par-each {|repo|
|
||||||
|
dnf repo info $repo --all
|
||||||
|
}
|
||||||
|
| flatten
|
||||||
|
| get repo_file_path
|
||||||
|
| uniq
|
||||||
|
| each {|file|
|
||||||
|
print $"Removing repo file '(ansi cyan)($file)(ansi reset)'"
|
||||||
|
rm -f $file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Enable a list of COPR repos. The COPR repo ID has a '/' in the name.
|
||||||
|
#
|
||||||
|
# This will error if a COPR repo ID is invalid.
|
||||||
|
def add_coprs [$copr_repos: list]: nothing -> list<string> {
|
||||||
|
if ($copr_repos | is-not-empty) {
|
||||||
|
print $'(ansi green)Adding COPR repositories:(ansi reset)'
|
||||||
|
$copr_repos
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
for $copr in $copr_repos {
|
||||||
|
print $"Adding COPR repository: (ansi cyan)'($copr)'(ansi reset)"
|
||||||
|
dnf copr enable $copr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$copr_repos
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable a list of COPR repos. The COPR repo ID has a '/' in the name.
|
||||||
|
#
|
||||||
|
# This will error if a COPR repo ID is invalid.
|
||||||
|
def disable_coprs [$copr_repos: list]: nothing -> nothing {
|
||||||
|
if ($copr_repos | is-not-empty) {
|
||||||
|
print $'(ansi green)Disabling COPR repositories:(ansi reset)'
|
||||||
|
$copr_repos
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
for $copr in $copr_repos {
|
||||||
|
print $"Disabling COPR repository: (ansi cyan)'($copr)'(ansi reset)"
|
||||||
|
dnf copr disable $copr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add a list of keys for integrity checking repos.
|
||||||
|
def add_keys [$keys: list]: nothing -> nothing {
|
||||||
|
if ($keys | is-not-empty) {
|
||||||
|
print $'(ansi green)Adding keys:(ansi reset)'
|
||||||
|
let keys = $keys
|
||||||
|
| str replace --all '%OS_VERSION%' $env.OS_VERSION
|
||||||
|
| str trim
|
||||||
|
| each {|key|
|
||||||
|
let key = if ($key | str starts-with 'https://') or ($key | str starts-with 'http://') {
|
||||||
|
$key
|
||||||
|
} else {
|
||||||
|
[$env.CONFIG_DIRECTORY dnf $key] | path join
|
||||||
|
}
|
||||||
|
print $'- (ansi cyan)($key)(ansi reset)'
|
||||||
|
$key
|
||||||
|
}
|
||||||
|
|
||||||
|
for $key in $keys {
|
||||||
|
let key = $key
|
||||||
|
| str replace --all '%OS_VERSION%' $env.OS_VERSION
|
||||||
|
| str trim
|
||||||
|
|
||||||
|
try {
|
||||||
|
^rpm --import $key
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup /opt directory symlinks to allow certain packages to install.
|
||||||
|
#
|
||||||
|
# Each entry must be the directory name that the application expects
|
||||||
|
# to install into /opt. A systemd unit will be installed to setup
|
||||||
|
# symlinks on boot of the OS.
|
||||||
|
def run_optfix [$optfix_pkgs: list]: nothing -> nothing {
|
||||||
|
const LIB_EXEC_DIR = '/usr/libexec/bluebuild'
|
||||||
|
const SYSTEMD_DIR = '/etc/systemd/system'
|
||||||
|
const MODULE_DIR = '/tmp/modules/dnf'
|
||||||
|
const LIB_OPT_DIR = '/usr/lib/opt'
|
||||||
|
const VAR_OPT_DIR = '/var/opt'
|
||||||
|
const OPTFIX_SCRIPT = 'optfix.sh'
|
||||||
|
const SERV_UNIT = 'bluebuild-optfix.service'
|
||||||
|
|
||||||
|
if ($optfix_pkgs | is-not-empty) {
|
||||||
|
if not ($LIB_EXEC_DIR | path join $OPTFIX_SCRIPT | path exists) {
|
||||||
|
mkdir $LIB_EXEC_DIR
|
||||||
|
cp ($MODULE_DIR | path join $OPTFIX_SCRIPT) $'($LIB_EXEC_DIR)/'
|
||||||
|
|
||||||
|
try {
|
||||||
|
^chmod +x $'($LIB_EXEC_DIR | path join $OPTFIX_SCRIPT)'
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if not ($SYSTEMD_DIR | path join $SERV_UNIT | path exists) {
|
||||||
|
cp ($MODULE_DIR | path join $SERV_UNIT) $'($SYSTEMD_DIR)/'
|
||||||
|
|
||||||
|
try {
|
||||||
|
^systemctl enable $SERV_UNIT
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"(ansi green)Creating symlinks to fix packages that install to /opt:(ansi reset)"
|
||||||
|
$optfix_pkgs
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir $VAR_OPT_DIR
|
||||||
|
try {
|
||||||
|
^ln -snf $VAR_OPT_DIR /opt
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for $opt in $optfix_pkgs {
|
||||||
|
let lib_dir = [$LIB_OPT_DIR $opt] | path join
|
||||||
|
let var_opt_dir = [$VAR_OPT_DIR $opt] | path join
|
||||||
|
|
||||||
|
mkdir $lib_dir
|
||||||
|
|
||||||
|
try {
|
||||||
|
^ln -sf $lib_dir $var_opt_dir
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
print $"Created symlinks for '(ansi cyan)($opt)(ansi reset)'"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove group packages.
|
||||||
|
def group_remove [remove: record]: nothing -> nothing {
|
||||||
|
let remove_list = $remove
|
||||||
|
| default [] packages
|
||||||
|
| get packages
|
||||||
|
|
||||||
|
if ($remove_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Removing group packages:(ansi reset)'
|
||||||
|
$remove_list
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
dnf group remove $remove_list
|
||||||
|
} catch {
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install group packages.
|
||||||
|
def group_install [install: record]: nothing -> nothing {
|
||||||
|
let install = $install
|
||||||
|
| default false with-optional
|
||||||
|
| default [] packages
|
||||||
|
let install_list = $install
|
||||||
|
| get packages
|
||||||
|
| each { str trim }
|
||||||
|
|
||||||
|
if ($install_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Installing group packages:(ansi reset)'
|
||||||
|
$install_list
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
(dnf
|
||||||
|
group
|
||||||
|
install
|
||||||
|
--opts $install
|
||||||
|
$install_list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove packages.
|
||||||
|
def remove_pkgs [remove: record]: nothing -> nothing {
|
||||||
|
let remove = $remove
|
||||||
|
| default [] packages
|
||||||
|
| default true auto-remove
|
||||||
|
|
||||||
|
if ($remove.packages | is-not-empty) {
|
||||||
|
print $'(ansi green)Removing packages:(ansi reset)'
|
||||||
|
$remove.packages
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
dnf remove --opts $remove $remove.packages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install packages.
|
||||||
|
#
|
||||||
|
# You can specify a list of packages to install, and you can
|
||||||
|
# specify a list of packages for a specific repo to install.
|
||||||
|
def install_pkgs [install: record]: nothing -> nothing {
|
||||||
|
let install = $install
|
||||||
|
| default [] packages
|
||||||
|
|
||||||
|
# Gather lists of the various ways a package is installed
|
||||||
|
# to report back to the user.
|
||||||
|
let install_list = $install.packages
|
||||||
|
| filter {|pkg|
|
||||||
|
($pkg | describe) == 'string'
|
||||||
|
}
|
||||||
|
| str replace --all '%OS_VERSION%' $env.OS_VERSION
|
||||||
|
| str trim
|
||||||
|
let http_list = $install_list
|
||||||
|
| filter {|pkg|
|
||||||
|
($pkg | str starts-with 'https://') or ($pkg | str starts-with 'http://')
|
||||||
|
}
|
||||||
|
let local_list = $install_list
|
||||||
|
| each {|pkg|
|
||||||
|
[$env.CONFIG_DIRECTORY dnf $pkg] | path join
|
||||||
|
}
|
||||||
|
| filter {|pkg|
|
||||||
|
($pkg | path exists)
|
||||||
|
}
|
||||||
|
let normal_list = $install_list
|
||||||
|
| filter {|pkg|
|
||||||
|
not (
|
||||||
|
($pkg | str starts-with 'https://') or ($pkg | str starts-with 'http://')
|
||||||
|
) and not (
|
||||||
|
[$env.CONFIG_DIRECTORY dnf $pkg]
|
||||||
|
| path join
|
||||||
|
| path exists
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($install_list | is-not-empty) {
|
||||||
|
if ($http_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Installing packages directly from URL:(ansi reset)'
|
||||||
|
$http_list
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($local_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Installing local packages:(ansi reset)'
|
||||||
|
$local_list
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($normal_list | is-not-empty) {
|
||||||
|
print $'(ansi green)Installing packages:(ansi reset)'
|
||||||
|
$normal_list
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(dnf
|
||||||
|
install
|
||||||
|
--opts $install
|
||||||
|
([
|
||||||
|
$http_list
|
||||||
|
$local_list
|
||||||
|
$normal_list
|
||||||
|
] | flatten))
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get all the entries that have a repo specified.
|
||||||
|
let repo_install_list = $install.packages
|
||||||
|
| filter {|pkg|
|
||||||
|
'repo' in $pkg and 'packages' in $pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
for $repo_install in $repo_install_list {
|
||||||
|
let repo = $repo_install.repo
|
||||||
|
let packages = $repo_install.packages
|
||||||
|
|
||||||
|
print $'(ansi green)Installing packages from repo (ansi cyan)($repo)(ansi green):(ansi reset)'
|
||||||
|
$packages
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
(dnf
|
||||||
|
install
|
||||||
|
--repoid
|
||||||
|
$repo
|
||||||
|
--opts $repo_install
|
||||||
|
--global-opts $install
|
||||||
|
$packages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Perform a replace operation for a list of packages that
|
||||||
|
# you want to replace from a specific repo.
|
||||||
|
def replace_pkgs [replace_list: list]: nothing -> nothing {
|
||||||
|
let check = {|item|
|
||||||
|
'old' in $item and 'new' in $item
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($replace_list | is-not-empty) {
|
||||||
|
for $replacement in $replace_list {
|
||||||
|
let replacement = $replacement
|
||||||
|
| default [] packages
|
||||||
|
|
||||||
|
if ($replacement.packages | is-not-empty) {
|
||||||
|
let has_from_repo = 'from-repo' in $replacement
|
||||||
|
|
||||||
|
if not $has_from_repo {
|
||||||
|
return (error make {
|
||||||
|
msg: $"(ansi red)A value is expected in key 'from-repo'(ansi reset)"
|
||||||
|
label: {
|
||||||
|
span: (metadata $replacement).span
|
||||||
|
text: "Checks for 'from-repo' property"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let from_repo = $replacement
|
||||||
|
| get from-repo
|
||||||
|
|
||||||
|
let swap_packages = $replacement.packages
|
||||||
|
| filter $check
|
||||||
|
let sync_packages = $replacement.packages
|
||||||
|
| filter {
|
||||||
|
not (do $check $in)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($swap_packages | is-not-empty) {
|
||||||
|
print $"(ansi green)Swapping packages from '(ansi cyan)($from_repo)(ansi green)':(ansi reset)"
|
||||||
|
$swap_packages
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in.old)(ansi green) -> (ansi cyan)($in.new)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
for $pkg_pair in $swap_packages {
|
||||||
|
(dnf
|
||||||
|
swap
|
||||||
|
--opts $pkg_pair
|
||||||
|
--global-opts $replacement
|
||||||
|
$pkg_pair.old
|
||||||
|
$pkg_pair.new)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sync_packages | is-not-empty) {
|
||||||
|
print $"(ansi green)Replacing packages from '(ansi cyan)($from_repo)(ansi green)':(ansi reset)"
|
||||||
|
$sync_packages
|
||||||
|
| each {
|
||||||
|
print $'- (ansi cyan)($in)(ansi reset)'
|
||||||
|
}
|
||||||
|
|
||||||
|
(dnf
|
||||||
|
distro-sync
|
||||||
|
--opts $replacement
|
||||||
|
--repo $from_repo
|
||||||
|
$sync_packages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def main [config: string]: nothing -> nothing {
|
||||||
|
let config = $config
|
||||||
|
| from json
|
||||||
|
| default {} repos
|
||||||
|
| default {} group-remove
|
||||||
|
| default {} group-install
|
||||||
|
| default {} remove
|
||||||
|
| default {} install
|
||||||
|
| default [] optfix
|
||||||
|
| default [] replace
|
||||||
|
let should_cleanup = $config.repos
|
||||||
|
| default false cleanup
|
||||||
|
| get cleanup
|
||||||
|
|
||||||
|
dnf version
|
||||||
|
|
||||||
|
let cleanup_repos = repos $config.repos
|
||||||
|
|
||||||
|
dnf makecache
|
||||||
|
|
||||||
|
run_optfix $config.optfix
|
||||||
|
group_remove $config.group-remove
|
||||||
|
group_install $config.group-install
|
||||||
|
remove_pkgs $config.remove
|
||||||
|
install_pkgs $config.install
|
||||||
|
replace_pkgs $config.replace
|
||||||
|
|
||||||
|
if $should_cleanup {
|
||||||
|
print $'(ansi green)Cleaning up added repos(ansi reset)'
|
||||||
|
remove_repos $cleanup_repos.files
|
||||||
|
disable_coprs $cleanup_repos.copr
|
||||||
|
|
||||||
|
match $config.repos.nonfree? {
|
||||||
|
$repo if $repo == $RPMFUSION => {
|
||||||
|
disable_rpmfusion
|
||||||
|
}
|
||||||
|
$repo if $repo == $NEGATIVO => {
|
||||||
|
disable_negativo
|
||||||
|
}
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
print $'(ansi green)Finished cleaning up repos(ansi reset)'
|
||||||
|
}
|
||||||
|
}
|
||||||
159
modules/dnf/dnf.tsp
Normal file
159
modules/dnf/dnf.tsp
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
import "@typespec/json-schema";
|
||||||
|
using TypeSpec.JsonSchema;
|
||||||
|
|
||||||
|
@jsonSchema("/modules/dnf-latest.json")
|
||||||
|
model DnfModuleLatest {
|
||||||
|
...DnfModuleV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@jsonSchema("/modules/dnf-v1.json")
|
||||||
|
model DnfModuleV1 {
|
||||||
|
/**
|
||||||
|
* The dnf module offers pseudo-declarative package and repository management using dnf.
|
||||||
|
* https://blue-build.org/reference/modules/dnf/
|
||||||
|
*/
|
||||||
|
type: "dnf" | "dnf@v1" | "dnf@latest";
|
||||||
|
|
||||||
|
/** List of links to .repo files to download into /etc/yum.repos.d/. */
|
||||||
|
repos?: Repo;
|
||||||
|
|
||||||
|
/** List of folder names under /opt/ to enable for installing into. */
|
||||||
|
optfix?: Array<string>;
|
||||||
|
|
||||||
|
/** Configuration of RPM groups removal. */
|
||||||
|
`group-remove`?: GroupRemove;
|
||||||
|
|
||||||
|
/** Configuration of RPM groups install. */
|
||||||
|
`group-install`?: GroupInstall;
|
||||||
|
|
||||||
|
/** Configuration of RPM packages removal. */
|
||||||
|
remove?: Remove;
|
||||||
|
|
||||||
|
/** Configuration of RPM packages install. */
|
||||||
|
install?: Install;
|
||||||
|
|
||||||
|
/** List of configurations for replacing packages from another repo. */
|
||||||
|
replace?: Array<Replace>;
|
||||||
|
}
|
||||||
|
|
||||||
|
model Repo {
|
||||||
|
/** Cleans up the repos added in the same step after packages are installed. */
|
||||||
|
cleanup?: boolean = false;
|
||||||
|
|
||||||
|
/** List of paths or URLs to .repo files to import */
|
||||||
|
files?: Array<string> | RepoFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of COPR project repos to add.
|
||||||
|
* You can also specify 2 lists
|
||||||
|
* instead to 'enable' or 'disable' COPR repos.
|
||||||
|
*/
|
||||||
|
copr?: Array<string> | RepoCopr;
|
||||||
|
|
||||||
|
/** List of links to key files to import for installing from custom repositories. */
|
||||||
|
keys?: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable one of the nonfree repos.
|
||||||
|
*
|
||||||
|
* This allows you to enable one of the nonfree repos.
|
||||||
|
* However, only one can be enabled at a time so if one
|
||||||
|
* is enabled, the other will be disabled if it is already enabled.
|
||||||
|
*/
|
||||||
|
nonfree?: "negativo17" | "rpmfusion";
|
||||||
|
}
|
||||||
|
|
||||||
|
model RepoFiles {
|
||||||
|
/** List of repo files/URLs to add. */
|
||||||
|
add?: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of repos to disable.
|
||||||
|
* This must be the ID of the repo
|
||||||
|
* as seen in `dnf5 repolist`.
|
||||||
|
*/
|
||||||
|
remove?: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
model RepoCopr {
|
||||||
|
/** List of COPR repos to enable */
|
||||||
|
enable?: Array<string>;
|
||||||
|
|
||||||
|
/** List of COPR repos to disable */
|
||||||
|
disable?: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
model Install {
|
||||||
|
/** List of RPM packages to install. */
|
||||||
|
packages: Array<string | InstallRepo>;
|
||||||
|
|
||||||
|
...InstallCommon;
|
||||||
|
}
|
||||||
|
|
||||||
|
model InstallRepo {
|
||||||
|
/** The repo to use when installing packages */
|
||||||
|
repo: string;
|
||||||
|
|
||||||
|
/** List of RPM packages to install. */
|
||||||
|
packages: Array<string>;
|
||||||
|
|
||||||
|
...InstallCommon;
|
||||||
|
}
|
||||||
|
|
||||||
|
model Remove {
|
||||||
|
/** List of RPM packages to remove. */
|
||||||
|
packages: Array<string>;
|
||||||
|
|
||||||
|
/** Whether to remove unused dependencies during removal operation. */
|
||||||
|
`auto-remove`?: boolean = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
model Replace {
|
||||||
|
/** URL to the source COPR repo for the new packages. */
|
||||||
|
`from-repo`: string;
|
||||||
|
|
||||||
|
/** List of packages to replace using packages from the defined repo. */
|
||||||
|
packages: Array<string | Swap>;
|
||||||
|
|
||||||
|
...InstallCommon;
|
||||||
|
}
|
||||||
|
|
||||||
|
model Swap {
|
||||||
|
/** The package to be replaced. */
|
||||||
|
old: string;
|
||||||
|
|
||||||
|
/** The package to replace with. */
|
||||||
|
new: string;
|
||||||
|
|
||||||
|
/** Whether to allow erasing (removal) of packages in case of dependency problems. */
|
||||||
|
`allow-erasing`?: boolean = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
model GroupInstall {
|
||||||
|
/** List of RPM groups to install. */
|
||||||
|
packages: Array<string>;
|
||||||
|
|
||||||
|
/** Include optional packages from group. */
|
||||||
|
`with-optional`?: boolean = false;
|
||||||
|
|
||||||
|
...InstallCommon;
|
||||||
|
}
|
||||||
|
|
||||||
|
model GroupRemove {
|
||||||
|
/** List of RPM groups to remove. */
|
||||||
|
packages: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
model InstallCommon {
|
||||||
|
/** Whether to install weak dependencies. */
|
||||||
|
`install-weak-deps`?: boolean = true;
|
||||||
|
|
||||||
|
/** Whether to continue with the install if there are no packages available in the repository. */
|
||||||
|
`skip-unavailable`?: boolean = false;
|
||||||
|
|
||||||
|
/** Whether to continue with the install if there are broken packages. */
|
||||||
|
`skip-broken`?: boolean = false;
|
||||||
|
|
||||||
|
/** Whether to allow erasing (removal) of packages in case of dependency problems. */
|
||||||
|
`allow-erasing`?: boolean = false;
|
||||||
|
}
|
||||||
394
modules/dnf/dnf_interface.nu
Normal file
394
modules/dnf/dnf_interface.nu
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
export def "dnf install" [
|
||||||
|
--opts: record
|
||||||
|
--global-opts: record
|
||||||
|
--repoid: string
|
||||||
|
packages: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path
|
||||||
|
-y
|
||||||
|
($opts | weak_arg --global-config $global_opts)
|
||||||
|
install
|
||||||
|
...(if $repoid != null {
|
||||||
|
[--repoid $repoid]
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
})
|
||||||
|
...($opts | install_args --global-config $global_opts)
|
||||||
|
...$packages)
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf remove" [
|
||||||
|
--opts: record
|
||||||
|
packages: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
mut args = []
|
||||||
|
|
||||||
|
if not $opts.auto-remove {
|
||||||
|
$args = $args | append '--no-autoremove'
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path
|
||||||
|
-y
|
||||||
|
remove
|
||||||
|
...($args)
|
||||||
|
...($packages))
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf config-manager addrepo" [
|
||||||
|
--from-repofile: string
|
||||||
|
]: nothing -> nothing {
|
||||||
|
check_dnf_plugins
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
match $dnf.command {
|
||||||
|
"dnf4" => {
|
||||||
|
^dnf4 -v -y config-manager --add-repo $from_repofile
|
||||||
|
}
|
||||||
|
"dnf5" => {
|
||||||
|
(^dnf5
|
||||||
|
-y
|
||||||
|
config-manager
|
||||||
|
addrepo
|
||||||
|
--create-missing-dir
|
||||||
|
--overwrite
|
||||||
|
--from-repofile $from_repofile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf config-manager setopt" [
|
||||||
|
opts: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
check_dnf_plugins
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
match $dnf.command {
|
||||||
|
"dnf4" => {
|
||||||
|
(^dnf4
|
||||||
|
-y
|
||||||
|
config-manager
|
||||||
|
--save
|
||||||
|
...($opts
|
||||||
|
| each {|opt|
|
||||||
|
[--setopt $opt]
|
||||||
|
}
|
||||||
|
| flatten))
|
||||||
|
}
|
||||||
|
"dnf5" => {
|
||||||
|
^dnf5 -y config-manager setopt ...($opts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf copr enable" [copr: string]: nothing -> nothing {
|
||||||
|
check_dnf_plugins
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
^$dnf.path -y copr enable ($copr | check_copr)
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf copr disable" [copr: string]: nothing -> nothing {
|
||||||
|
check_dnf_plugins
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
^$dnf.path -y copr disable ($copr | check_copr)
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf swap" [
|
||||||
|
--opts: record
|
||||||
|
--global-opts: record
|
||||||
|
old: string
|
||||||
|
new: string
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path
|
||||||
|
-y
|
||||||
|
swap
|
||||||
|
...($opts | install_args --global-config $global_opts 'allow-erasing')
|
||||||
|
$old
|
||||||
|
$new)
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf distro-sync" [
|
||||||
|
--opts: record
|
||||||
|
--repo: string
|
||||||
|
packages: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path
|
||||||
|
-y
|
||||||
|
($opts | weak_arg)
|
||||||
|
distro-sync
|
||||||
|
...($opts | install_args)
|
||||||
|
--repo $repo
|
||||||
|
...($packages))
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf group install" [
|
||||||
|
--opts: record
|
||||||
|
packages: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
mut args = $opts | install_args
|
||||||
|
|
||||||
|
if $opts.with-optional {
|
||||||
|
$args = $args | append '--with-optional'
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path
|
||||||
|
-y
|
||||||
|
($opts | weak_arg)
|
||||||
|
group
|
||||||
|
install
|
||||||
|
...($args)
|
||||||
|
...($packages))
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf group remove" [
|
||||||
|
packages: list
|
||||||
|
]: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
(^$dnf.path -y group remove ...($packages))
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf repo list" []: nothing -> list {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
match $dnf.command {
|
||||||
|
"dnf4" => {
|
||||||
|
^/tmp/modules/dnf/dnf-repolist | from json
|
||||||
|
}
|
||||||
|
"dnf5" => {
|
||||||
|
^dnf5 repo list --all --json | from json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf repo info" [
|
||||||
|
repo: string
|
||||||
|
--all
|
||||||
|
]: nothing -> record {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
match $dnf.command {
|
||||||
|
"dnf4" => {
|
||||||
|
^/tmp/modules/dnf/dnf-repoinfo $repo | from json
|
||||||
|
}
|
||||||
|
"dnf5" => {
|
||||||
|
(^dnf5
|
||||||
|
-y
|
||||||
|
repo
|
||||||
|
info
|
||||||
|
$repo
|
||||||
|
...(if $all {
|
||||||
|
[--all]
|
||||||
|
} else {
|
||||||
|
[]
|
||||||
|
})
|
||||||
|
--json)
|
||||||
|
| from json
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf makecache" []: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
try {
|
||||||
|
^$dnf.path makecache --refresh
|
||||||
|
} catch {|e|
|
||||||
|
print $'($e.msg)'
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export def "dnf version" []: nothing -> record {
|
||||||
|
let dnf = which dnf4 dnf5
|
||||||
|
|
||||||
|
if ("dnf5" in ($dnf | get command)) {
|
||||||
|
$dnf | filter { $in.command == "dnf5" } | first
|
||||||
|
} else if ("dnf4" in ($dnf | get command)) {
|
||||||
|
$dnf | filter { $in.command == "dnf4" } | first
|
||||||
|
} else {
|
||||||
|
return (error make {
|
||||||
|
msg: $"(ansi red)ERROR: Main dependency '(ansi cyan)dnf5/dnf4(ansi red)' is not installed. Install '(ansi cyan)dnf5/dnf4(ansi red)' before using this module to solve this error.(ansi reset)"
|
||||||
|
label: {
|
||||||
|
span: (metadata $dnf).span
|
||||||
|
text: 'Checks for dnf5/dnf4'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build up args to use on `dnf`
|
||||||
|
def install_args [
|
||||||
|
--global-config: record
|
||||||
|
...filter: string
|
||||||
|
]: record -> list<string> {
|
||||||
|
let opts = $in | default {}
|
||||||
|
let global_config = $global_config | default {}
|
||||||
|
let install = $opts
|
||||||
|
| default (
|
||||||
|
$global_config.skip-unavailable?
|
||||||
|
| default false
|
||||||
|
) skip-unavailable
|
||||||
|
| default (
|
||||||
|
$global_config.skip-broken?
|
||||||
|
| default false
|
||||||
|
) skip-broken
|
||||||
|
| default (
|
||||||
|
$global_config.allow-erasing?
|
||||||
|
| default false
|
||||||
|
) allow-erasing
|
||||||
|
mut args = []
|
||||||
|
let check_filter = {|arg|
|
||||||
|
let arg_exists = ($arg in $install)
|
||||||
|
if ($filter | is-empty) {
|
||||||
|
$arg_exists and ($install | get $arg)
|
||||||
|
} else {
|
||||||
|
$arg_exists and ($arg in $filter) and ($install | get $arg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do $check_filter 'skip-unavailable') {
|
||||||
|
$args = $args | append '--skip-unavailable'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do $check_filter 'skip-broken') {
|
||||||
|
$args = $args | append '--skip-broken'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do $check_filter 'allow-erasing') {
|
||||||
|
$args = $args | append '--allowerasing'
|
||||||
|
}
|
||||||
|
|
||||||
|
$args
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate a weak deps argument
|
||||||
|
def weak_arg [
|
||||||
|
--global-config: record
|
||||||
|
]: record -> string {
|
||||||
|
let opts = $in | default {}
|
||||||
|
let global_config = $global_config | default {}
|
||||||
|
let install = $opts
|
||||||
|
| default (
|
||||||
|
$global_config.install-weak-deps?
|
||||||
|
| default true
|
||||||
|
) install-weak-deps
|
||||||
|
|
||||||
|
if $install.install-weak-deps {
|
||||||
|
'--setopt=install_weak_deps=True'
|
||||||
|
} else {
|
||||||
|
'--setopt=install_weak_deps=False'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handles installing necessary plugins for repo management.
|
||||||
|
def check_dnf_plugins []: nothing -> nothing {
|
||||||
|
let dnf = dnf version
|
||||||
|
|
||||||
|
match $dnf.command {
|
||||||
|
"dnf4" => {
|
||||||
|
if (^rpm -q dnf-plugins-core | complete).exit_code != 0 {
|
||||||
|
print $'(ansi yellow1)Required dnf4 plugins are not installed. Installing plugins(ansi reset)'
|
||||||
|
|
||||||
|
dnf install [dnf-plugins-core]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"dnf5" => {
|
||||||
|
if (^rpm -q dnf5-plugins | complete).exit_code != 0 {
|
||||||
|
print $'(ansi yellow1)Required dnf5 plugins are not installed. Installing plugins(ansi reset)'
|
||||||
|
|
||||||
|
dnf install [dnf5-plugins]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Checks to see if the string passed in is
|
||||||
|
# a COPR repo string. Will error if it isn't
|
||||||
|
def check_copr []: string -> string {
|
||||||
|
let is_copr = ($in | split row / | length) == 2
|
||||||
|
|
||||||
|
if not $is_copr {
|
||||||
|
return (error make {
|
||||||
|
msg: $"(ansi red)The string '(ansi cyan)($in)(ansi red)' is not recognized as a COPR repo(ansi reset)"
|
||||||
|
label: {
|
||||||
|
span: (metadata $is_copr).span
|
||||||
|
text: 'Checks if string is a COPR repo'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
$in
|
||||||
|
}
|
||||||
|
|
||||||
47
modules/dnf/module.yml
Normal file
47
modules/dnf/module.yml
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
name: dnf
|
||||||
|
shortdesc: The dnf module offers pseudo-declarative package and repository management using dnf.
|
||||||
|
example: |
|
||||||
|
type: dnf
|
||||||
|
repos:
|
||||||
|
cleanup: true # clean up added repos after module is done
|
||||||
|
files:
|
||||||
|
- https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo
|
||||||
|
- fury.repo
|
||||||
|
copr:
|
||||||
|
- atim/starship
|
||||||
|
- trixieua/mutter-patched
|
||||||
|
keys:
|
||||||
|
- https://brave-browser-rpm-release.s3.brave.com/brave-core.asc
|
||||||
|
nonfree: rpmfusion
|
||||||
|
optfix: # performs symlinking for `/opt/` to allow certain packages to install
|
||||||
|
- Tabby # needed because tabby installs into `/opt/Tabby/`
|
||||||
|
- brave.com
|
||||||
|
install:
|
||||||
|
skip-unavailable: true # skip unavailable packages
|
||||||
|
packages:
|
||||||
|
- repo: brave-browser
|
||||||
|
packages:
|
||||||
|
- brave-browser
|
||||||
|
- starship
|
||||||
|
- https://github.com/Eugeny/tabby/releases/download/v1.0.209/tabby-1.0.209-linux-x64.rpm
|
||||||
|
- kubectl.rpm
|
||||||
|
remove:
|
||||||
|
packages:
|
||||||
|
- firefox
|
||||||
|
- firefox-langpacks
|
||||||
|
replace:
|
||||||
|
- from-repo: copr:copr.fedorainfracloud.org:trixieua:mutter-patched
|
||||||
|
skip-unavailable: true # skip unavailable packages
|
||||||
|
packages:
|
||||||
|
- mutter
|
||||||
|
- mutter-common
|
||||||
|
- gdm
|
||||||
|
group-install:
|
||||||
|
with-optional: true # install optional packages from group
|
||||||
|
packages:
|
||||||
|
- cosmic-desktop
|
||||||
|
- cosmic-desktop-apps
|
||||||
|
- window-managers
|
||||||
|
group-remove:
|
||||||
|
packages:
|
||||||
|
- development-tools
|
||||||
27
modules/dnf/optfix.sh
Normal file
27
modules/dnf/optfix.sh
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SOURCE_DIR="/usr/lib/opt"
|
||||||
|
TARGET_DIR="/var/opt"
|
||||||
|
|
||||||
|
# Ensure the target directory exists
|
||||||
|
mkdir -p "$TARGET_DIR"
|
||||||
|
|
||||||
|
# Loop through directories in the source directory
|
||||||
|
for dir in "$SOURCE_DIR/"*/; do
|
||||||
|
if [ -d "$dir" ]; then
|
||||||
|
# Get the base name of the directory
|
||||||
|
dir_name=$(basename "$dir")
|
||||||
|
|
||||||
|
# Check if the symlink already exists in the target directory
|
||||||
|
if [ -L "$TARGET_DIR/$dir_name" ]; then
|
||||||
|
echo "Symlink already exists for $dir_name, skipping."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the symlink
|
||||||
|
ln -s "$dir" "$TARGET_DIR/$dir_name"
|
||||||
|
echo "Created symlink for $dir_name"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
@ -60,7 +60,8 @@ if [[ ${#OPTFIX[@]} -gt 0 ]]; then
|
||||||
echo "Creating symlinks to fix packages that install to /opt"
|
echo "Creating symlinks to fix packages that install to /opt"
|
||||||
# Create symlink for /opt to /var/opt since it is not created in the image yet
|
# Create symlink for /opt to /var/opt since it is not created in the image yet
|
||||||
mkdir -p "/var/opt"
|
mkdir -p "/var/opt"
|
||||||
ln -fs "/var/opt" "/opt"
|
ln -fs "/var/opt" "/opt"
|
||||||
|
|
||||||
|
|
||||||
# Create symlinks for each directory specified in recipe.yml
|
# Create symlinks for each directory specified in recipe.yml
|
||||||
for OPTPKG in "${OPTFIX[@]}"; do
|
for OPTPKG in "${OPTFIX[@]}"; do
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue