Compare commits
No commits in common. "v0.0.1" and "master" have entirely different histories.
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
liberapay: lure
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -1,2 +1,5 @@
|
||||
/lure
|
||||
/dist/
|
||||
/lure-api-server
|
||||
/cmd/lure-api-server/lure-api-server
|
||||
/dist/
|
||||
/internal/config/version.txt
|
||||
|
@ -6,60 +6,90 @@ builds:
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
binary: lure
|
||||
ldflags:
|
||||
- -X go.elara.ws/lure/internal/config.Version={{.Version}}
|
||||
goos:
|
||||
- linux
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm
|
||||
- 386
|
||||
- arm64
|
||||
- arm
|
||||
- riscv64
|
||||
archives:
|
||||
- replacements:
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
arm64: aarch64
|
||||
- name_template: >-
|
||||
{{- .ProjectName}}-
|
||||
{{- .Version}}-
|
||||
{{- .Os}}-
|
||||
{{- if .Arch | eq "amd64"}}x86_64
|
||||
{{- else if .Arch | eq "386"}}i386
|
||||
{{- else if .Arch | eq "arm64"}}aarch64
|
||||
{{- else }}{{ .Arch }}{{ end -}}
|
||||
files:
|
||||
- scripts/completion/*
|
||||
nfpms:
|
||||
- id: lure
|
||||
file_name_template: '{{.PackageName}}-{{.Version}}-{{.Os}}-{{.Arch}}'
|
||||
package_name: linux-user-repository
|
||||
file_name_template: >-
|
||||
{{- .PackageName}}-
|
||||
{{- .Version}}-
|
||||
{{- .Os}}-
|
||||
{{- if .Arch | eq "amd64"}}x86_64
|
||||
{{- else if .Arch | eq "386"}}i386
|
||||
{{- else if .Arch | eq "arm64"}}aarch64
|
||||
{{- else }}{{ .Arch }}{{ end -}}
|
||||
description: "Linux User REpository"
|
||||
replacements:
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
arm64: aarch64
|
||||
homepage: 'https://gitea.arsenm.dev/Arsen6331/lure'
|
||||
maintainer: 'Arsen Musyaelyan <arsen@arsenm.dev>'
|
||||
homepage: 'https://lure.sh'
|
||||
maintainer: 'Elara Musayelyan <elara@elara.ws>'
|
||||
license: GPLv3
|
||||
formats:
|
||||
- apk
|
||||
- deb
|
||||
- rpm
|
||||
- archlinux
|
||||
provides:
|
||||
- linux-user-repository
|
||||
conflicts:
|
||||
- linux-user-repository
|
||||
recommends:
|
||||
- aria2
|
||||
contents:
|
||||
- src: scripts/completion/bash
|
||||
dst: /usr/share/bash-completion/completions/lure
|
||||
- src: scripts/completion/zsh
|
||||
dst: /usr/share/zsh/site-functions/_lure
|
||||
aurs:
|
||||
- name: lure-bin
|
||||
homepage: 'https://gitea.arsenm.dev/Arsen6331/lure'
|
||||
- name: linux-user-repository-bin
|
||||
homepage: 'https://lure.sh'
|
||||
description: "Linux User REpository"
|
||||
maintainers:
|
||||
- 'Arsen Musyaelyan <arsen@arsenm.dev>'
|
||||
- 'Elara Musayelyan <elara@elara.ws>'
|
||||
license: GPLv3
|
||||
private_key: '{{ .Env.AUR_KEY }}'
|
||||
git_url: 'ssh://aur@aur.archlinux.org/lure-bin.git'
|
||||
git_url: 'ssh://aur@aur.archlinux.org/linux-user-repository-bin.git'
|
||||
provides:
|
||||
- lure
|
||||
- linux-user-repository
|
||||
conflicts:
|
||||
- lure
|
||||
- linux-user-repository
|
||||
depends:
|
||||
- sudo
|
||||
- pacman
|
||||
optdepends:
|
||||
- 'aria2: for downloading torrent sources'
|
||||
package: |-
|
||||
# binaries
|
||||
install -Dm755 "./lure" "${pkgdir}/usr/bin/lure"
|
||||
install -Dm755 ./lure "${pkgdir}/usr/bin/lure"
|
||||
|
||||
# completions
|
||||
install -Dm755 ./scripts/completion/bash ${pkgdir}/usr/share/bash-completion/completions/lure
|
||||
install -Dm755 ./scripts/completion/zsh ${pkgdir}/usr/share/zsh/site-functions/_lure
|
||||
release:
|
||||
gitea:
|
||||
owner: Arsen6331
|
||||
owner: lure
|
||||
name: lure
|
||||
gitea_urls:
|
||||
api: 'https://gitea.arsenm.dev/api/v1/'
|
||||
download: 'https://gitea.arsenm.dev'
|
||||
api: 'https://gitea.elara.ws/api/v1/'
|
||||
download: 'https://gitea.elara.ws'
|
||||
skip_tls_verify: false
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
|
9
.woodpecker.yml
Normal file
9
.woodpecker.yml
Normal file
@ -0,0 +1,9 @@
|
||||
platform: linux/amd64
|
||||
pipeline:
|
||||
release:
|
||||
image: goreleaser/goreleaser
|
||||
commands:
|
||||
- goreleaser release
|
||||
secrets: [ gitea_token, aur_key ]
|
||||
when:
|
||||
event: tag
|
20
Makefile
Normal file
20
Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
PREFIX ?= /usr/local
|
||||
GIT_VERSION = $(shell git describe --tags )
|
||||
|
||||
lure:
|
||||
CGO_ENABLED=0 go build -ldflags="-X 'go.elara.ws/lure/internal/config.Version=$(GIT_VERSION)'"
|
||||
|
||||
clean:
|
||||
rm -f lure
|
||||
|
||||
install: lure installmisc
|
||||
install -Dm755 lure $(DESTDIR)$(PREFIX)/bin/lure
|
||||
|
||||
installmisc:
|
||||
install -Dm755 scripts/completion/bash $(DESTDIR)$(PREFIX)/share/bash-completion/completions/lure
|
||||
install -Dm755 scripts/completion/zsh $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_lure
|
||||
|
||||
uninstall:
|
||||
rm -f /usr/local/bin/lure
|
||||
|
||||
.PHONY: install clean uninstall installmisc lure
|
88
README.md
88
README.md
@ -1,75 +1,77 @@
|
||||
<img src="assets/logo.png" alt="LURE Logo" width="200">
|
||||
|
||||
# LURE (Linux User REpository)
|
||||
|
||||
[](https://goreportcard.com/report/go.arsenm.dev/lure)
|
||||
[](https://goreportcard.com/report/go.elara.ws/lure)
|
||||
[](https://ci.elara.ws/lure/lure)
|
||||
[](https://archive.softwareheritage.org/browse/origin/?origin_url=https://gitea.elara.ws/lure/lure.git)
|
||||
[](https://aur.archlinux.org/packages/linux-user-repository-bin/)
|
||||
|
||||
LURE is intended to bring the AUR to all distros. It is currently in an ***alpha*** state and may not be stable. It can download a repository, build packages in it using a bash script similar to [PKGBUILD](https://wiki.archlinux.org/title/PKGBUILD), and then install them using your system package manager.
|
||||
LURE is a distro-agnostic build system for Linux, similar to the [AUR](https://wiki.archlinux.org/title/Arch_User_Repository). It is currently in **beta**. Most major bugs have been fixed, and most major features have been added. LURE is ready for general use, but may still break or change occasionally.
|
||||
|
||||
LURE is written in pure Go and has zero dependencies after it's built. The only things LURE needs are a command for privilege elevation such as `sudo`, `doas`, etc. as well as a supported package manager. Currently, LURE supports `apt`, `pacman`, `apk`, `dnf`, `yum`, and `zypper`. If a supported package manager exists on your system, it will be detected and used automatically.
|
||||
LURE is written in pure Go and has zero dependencies after building. The only things LURE requires are a command for privilege elevation such as `sudo`, `doas`, etc. as well as a supported package manager. Currently, LURE supports `apt`, `pacman`, `apk`, `dnf`, `yum`, and `zypper`. If a supported package manager exists on your system, it will be detected and used automatically.
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
Binary releases are not provided currently. They will be provided once I have time to set up a CI pipeline.
|
||||
### Install script
|
||||
|
||||
To install LURE, you'll need Go 1.18 or newer. Once installed, clone this repo and run `go build` inside, and then run `sudo install -Dm755 lure /usr/local/bin`.
|
||||
The LURE install script will automatically download and install the appropriate LURE package on your system. To use it, simply run the following command:
|
||||
|
||||
```bash
|
||||
curl -fsSL lure.sh/install | bash
|
||||
```
|
||||
|
||||
**IMPORTANT**: This will download and run the script from https://lure.sh/install. Please look through any script you download from the internet (including this one) before running it.
|
||||
|
||||
### Packages
|
||||
|
||||
Distro packages and binary archives are provided at the latest Gitea release: https://gitea.elara.ws/lure/lure/releases/latest
|
||||
|
||||
LURE is also available on the AUR as [linux-user-repository-bin](https://aur.archlinux.org/packages/linux-user-repository-bin)
|
||||
|
||||
### Building from source
|
||||
|
||||
To build LURE from source, you'll need Go 1.18 or newer. Once Go is installed, clone this repo and run:
|
||||
|
||||
```shell
|
||||
sudo make install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Why?
|
||||
|
||||
The AUR is an amazing feature, and it's one of the main reasons I use Arch on all my daily driver devices. It is really simple while providing really useful functionality. I feel such a solution shouldn't be stuck in only a single distro, so I made LURE.
|
||||
|
||||
Like the AUR, it uses simple bash build scripts, but it doesn't depend on bash being installed at all. It uses an embedded, pure Go implementation of bash instead. Similarly, it uses Git to download the repos and sources, but doesn't depend on Git being installed.
|
||||
|
||||
This means it's really easy to deploy LURE on any distro that it has support for and on any CPU architecture. It also supports and automatically detects many package managers, so it's not limited to just `pacman`.
|
||||
LURE was created because packaging software for multiple Linux distros can be difficult and error-prone, and installing those packages can be a nightmare for users unless they're available in their distro's official repositories. It automates the process of building and installing unofficial packages.
|
||||
|
||||
---
|
||||
|
||||
## Distro Overrides
|
||||
## Documentation
|
||||
|
||||
Allowing LURE to run on different distros provides some challenges. For example, some distros use different names for their packages. This is solved using distro overrides. Any variable or function used in a LURE build script may be overridden based on distro and CPU architecture. The way you do this is by appending the distro and/or architecture to the end of the name. For example, [ITD](https://gitea.arsenm.dev/Arsen6331/itd) depends on the `pactl` command as well as DBus and BlueZ. These are named somewhat differently on different distros. For ITD, I use the following for the dependencies:
|
||||
The documentation for LURE is in the [docs](docs) directory in this repo.
|
||||
|
||||
```bash
|
||||
deps=('dbus' 'bluez' 'pulseaudio-utils')
|
||||
deps_arch=('dbus' 'bluez' 'libpulse')
|
||||
deps_opensuse=('dbus-1' 'bluez' 'pulseaudio-utils')
|
||||
```
|
||||
---
|
||||
|
||||
Appending `arch` and `opensuse` to the end causes LURE to use the appropriate array based on the distro. If on Arch Linux, it will use `deps_arch`. If on OpenSUSE, it will use `deps_opensuse`, and if on anything else, it will use `deps`.
|
||||
## Web Interface
|
||||
|
||||
Names are checked in the following order:
|
||||
|
||||
- $name_$architecture_$distro
|
||||
- $name_$distro
|
||||
- $name_$architecture
|
||||
- $name
|
||||
|
||||
Distro detection is performed by reading the `/usr/lib/os-release` and `/etc/os-release` files.
|
||||
LURE has an open source web interface, licensed under the AGPLv3 (https://gitea.elara.ws/lure/lure-web), and it's available at https://lure.sh/.
|
||||
|
||||
---
|
||||
|
||||
## Repositories
|
||||
|
||||
Unlike the AUR, LURE supports using multiple repos. Also unlike the AUR, LURE's repos are a single git repo containing all the build scripts. Inside each LURE repo, there should be a separate directory for each package containing a `lure.sh` script, which is a PKGBUILD-like build script for LURE. The default repository is hosted on Github: https://github.com/Arsen6331/lure-repo.
|
||||
LURE's repos are git repositories that contain a directory for each package, with a `lure.sh` file inside. The `lure.sh` file tells LURE how to build the package and information about it. `lure.sh` scripts are similar to the AUR's PKGBUILD scripts.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
## Acknowledgements
|
||||
|
||||
As mentioned before, LURE has zero dependencies after it's built. All functionality that could be pure Go is pure Go. Thanks to the following packages for making this possible:
|
||||
Thanks to the following projects for making LURE possible:
|
||||
|
||||
- Bash: https://github.com/mvdan/sh
|
||||
- Git: https://github.com/go-git/go-git
|
||||
- Archiver: https://github.com/mholt/archiver
|
||||
- nfpm: https://github.com/goreleaser/nfpm
|
||||
|
||||
---
|
||||
|
||||
## Planned Features
|
||||
|
||||
- Source patching via .patch files
|
||||
- Binary releases using goreleaser + CI
|
||||
- Automated install script
|
||||
- Automated docker-based testing tool
|
||||
- Web interface for repos
|
||||
- https://github.com/mvdan/sh
|
||||
- https://github.com/go-git/go-git
|
||||
- https://github.com/mholt/archiver
|
||||
- https://github.com/goreleaser/nfpm
|
||||
- https://github.com/charmbracelet/bubbletea
|
||||
- https://gitlab.com/cznic/sqlite
|
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
489
build.go
489
build.go
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2022 Arsen Musayelyan
|
||||
* Copyright (C) 2023 Elara Musayelyan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -19,447 +19,82 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
_ "github.com/goreleaser/nfpm/v2/apk"
|
||||
_ "github.com/goreleaser/nfpm/v2/arch"
|
||||
_ "github.com/goreleaser/nfpm/v2/deb"
|
||||
_ "github.com/goreleaser/nfpm/v2/rpm"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/sys/cpu"
|
||||
|
||||
"github.com/goreleaser/nfpm/v2"
|
||||
"github.com/goreleaser/nfpm/v2/files"
|
||||
"go.arsenm.dev/lure/distro"
|
||||
"go.arsenm.dev/lure/download"
|
||||
"go.arsenm.dev/lure/internal/shutils/decoder"
|
||||
"go.arsenm.dev/lure/manager"
|
||||
"mvdan.cc/sh/v3/expand"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
"mvdan.cc/sh/v3/syntax"
|
||||
"lure.sh/lure/internal/config"
|
||||
"lure.sh/lure/internal/osutils"
|
||||
"lure.sh/lure/internal/types"
|
||||
"lure.sh/lure/pkg/build"
|
||||
"lure.sh/lure/pkg/loggerctx"
|
||||
"lure.sh/lure/pkg/manager"
|
||||
"lure.sh/lure/pkg/repos"
|
||||
)
|
||||
|
||||
// BuildVars represents the script variables required
|
||||
// to build a package
|
||||
type BuildVars struct {
|
||||
Name string `sh:"name,required"`
|
||||
Version string `sh:"version,required"`
|
||||
Release int `sh:"release,required"`
|
||||
Epoch uint `sh:"epoch"`
|
||||
Description string `sh:"desc"`
|
||||
Homepage string `sh:"homepage"`
|
||||
Architectures []string `sh:"architectures"`
|
||||
Licenses []string `sh:"license"`
|
||||
Provides []string `sh:"provides"`
|
||||
Conflicts []string `sh:"conflicts"`
|
||||
Depends []string `sh:"deps"`
|
||||
BuildDepends []string `sh:"build_deps"`
|
||||
Replaces []string `sh:"replaces"`
|
||||
Sources []string `sh:"sources"`
|
||||
Checksums []string `sh:"checksums"`
|
||||
Backup []string `sh:"backup"`
|
||||
Scripts Scripts `sh:"scripts"`
|
||||
}
|
||||
|
||||
type Scripts struct {
|
||||
PreInstall string `sh:"preinstall"`
|
||||
PostInstall string `sh:"postinstall"`
|
||||
PreRemove string `sh:"preremove"`
|
||||
PostRemove string `sh:"postinstall"`
|
||||
PreUpgrade string `sh:"preupgrade"`
|
||||
PostUpgrade string `sh:"postupgrade"`
|
||||
PreTrans string `sh:"pretrans"`
|
||||
PostTrans string `sh:"posttrans"`
|
||||
}
|
||||
|
||||
func buildCmd(c *cli.Context) error {
|
||||
script := c.String("script")
|
||||
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect supported package manager on system").Send()
|
||||
}
|
||||
|
||||
_, pkgNames, err := buildPackage(c.Context, script, mgr)
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).Send()
|
||||
}
|
||||
|
||||
log.Info("Package(s) built successfully").Any("names", pkgNames).Send()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPackage(ctx context.Context, script string, mgr manager.Manager) ([]string, []string, error) {
|
||||
info, err := distro.ParseOSRelease(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if distID, ok := os.LookupEnv("LURE_DISTRO"); ok {
|
||||
info.ID = distID
|
||||
}
|
||||
|
||||
fl, err := os.Open(script)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
file, err := syntax.NewParser().Parse(fl, "lure.sh")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fl.Close()
|
||||
|
||||
env := genBuildEnv(info)
|
||||
|
||||
runner, err := interp.New(
|
||||
interp.Env(expand.ListEnviron(env...)),
|
||||
interp.StdIO(os.Stdin, os.Stdout, os.Stderr),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = runner.Run(ctx, file)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dec := decoder.New(info, runner)
|
||||
|
||||
var vars BuildVars
|
||||
err = dec.DecodeVars(&vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
log.Info("Building package").Str("name", vars.Name).Str("version", vars.Version).Send()
|
||||
|
||||
baseDir := filepath.Join(cacheDir, "pkgs", vars.Name)
|
||||
srcdir := filepath.Join(baseDir, "src")
|
||||
pkgdir := filepath.Join(baseDir, "pkg")
|
||||
|
||||
err = os.RemoveAll(baseDir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(srcdir, 0o755)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(pkgdir, 0o755)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(vars.BuildDepends) > 0 {
|
||||
log.Info("Installing build dependencies").Send()
|
||||
installPkgs(ctx, vars.BuildDepends, mgr)
|
||||
}
|
||||
|
||||
var builtDeps, builtNames, repoDeps []string
|
||||
if len(vars.Depends) > 0 {
|
||||
log.Info("Installing dependencies").Send()
|
||||
|
||||
scripts, notFound := findPkgs(vars.Depends)
|
||||
for _, script := range scripts {
|
||||
pkgPaths, pkgNames, err := buildPackage(ctx, script, mgr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
builtDeps = append(builtDeps, pkgPaths...)
|
||||
builtNames = append(builtNames, pkgNames...)
|
||||
builtNames = append(builtNames, filepath.Base(filepath.Dir(script)))
|
||||
}
|
||||
repoDeps = notFound
|
||||
}
|
||||
|
||||
log.Info("Downloading sources").Send()
|
||||
|
||||
err = getSources(ctx, srcdir, &vars)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = setDirVars(ctx, runner, srcdir, pkgdir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fn, ok := dec.GetFunc("build")
|
||||
if ok {
|
||||
log.Info("Executing build()").Send()
|
||||
|
||||
err = fn(ctx, srcdir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
fn, ok = dec.GetFunc("package")
|
||||
if ok {
|
||||
log.Info("Executing package()").Send()
|
||||
|
||||
err = fn(ctx, srcdir)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
uniq(
|
||||
&repoDeps,
|
||||
&builtDeps,
|
||||
&builtNames,
|
||||
)
|
||||
|
||||
pkgInfo := &nfpm.Info{
|
||||
Name: vars.Name,
|
||||
Description: vars.Description,
|
||||
Arch: runtime.GOARCH,
|
||||
Version: vars.Version,
|
||||
Release: strconv.Itoa(vars.Release),
|
||||
Epoch: strconv.FormatUint(uint64(vars.Epoch), 10),
|
||||
Homepage: vars.Homepage,
|
||||
License: strings.Join(vars.Licenses, ", "),
|
||||
Overridables: nfpm.Overridables{
|
||||
Depends: append(repoDeps, builtNames...),
|
||||
var buildCmd = &cli.Command{
|
||||
Name: "build",
|
||||
Usage: "Build a local package",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "script",
|
||||
Aliases: []string{"s"},
|
||||
Value: "lure.sh",
|
||||
Usage: "Path to the build script",
|
||||
},
|
||||
}
|
||||
&cli.StringFlag{
|
||||
Name: "package",
|
||||
Aliases: []string{"p"},
|
||||
Usage: "Name of the package to build and its repo (example: default/go-bin)",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "clean",
|
||||
Aliases: []string{"c"},
|
||||
Usage: "Build package from scratch even if there's an already built package available",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
ctx := c.Context
|
||||
log := loggerctx.From(ctx)
|
||||
|
||||
setScripts(&vars, pkgInfo, filepath.Dir(script))
|
||||
script := c.String("script")
|
||||
if c.String("package") != "" {
|
||||
script = filepath.Join(config.GetPaths(ctx).RepoDir, c.String("package"), "lure.sh")
|
||||
}
|
||||
|
||||
if slices.Contains(vars.Architectures, "all") {
|
||||
pkgInfo.Arch = "all"
|
||||
}
|
||||
err := repos.Pull(ctx, config.Config(ctx).Repos)
|
||||
if err != nil {
|
||||
log.Fatal("Error pulling repositories").Err(err).Send()
|
||||
}
|
||||
|
||||
if pkgInfo.Arch == "arm" {
|
||||
pkgInfo.Arch = checkARMVariant()
|
||||
}
|
||||
mgr := manager.Detect()
|
||||
if mgr == nil {
|
||||
log.Fatal("Unable to detect a supported package manager on the system").Send()
|
||||
}
|
||||
|
||||
contents := []*files.Content{}
|
||||
filepath.Walk(pkgdir, func(path string, fi os.FileInfo, err error) error {
|
||||
trimmed := strings.TrimPrefix(path, pkgdir)
|
||||
pkgPaths, _, err := build.BuildPackage(ctx, types.BuildOpts{
|
||||
Script: script,
|
||||
Manager: mgr,
|
||||
Clean: c.Bool("clean"),
|
||||
Interactive: c.Bool("interactive"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("Error building package").Err(err).Send()
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
f, err := os.Open(path)
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal("Error getting working directory").Err(err).Send()
|
||||
}
|
||||
|
||||
for _, pkgPath := range pkgPaths {
|
||||
name := filepath.Base(pkgPath)
|
||||
err = osutils.Move(pkgPath, filepath.Join(wd, name))
|
||||
if err != nil {
|
||||
return err
|
||||
log.Fatal("Error moving the package").Err(err).Send()
|
||||
}
|
||||
|
||||
_, err = f.Readdirnames(1)
|
||||
if err != io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
Type: "dir",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
},
|
||||
})
|
||||
|
||||
f.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
link, err := os.Readlink(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
contents = append(contents, &files.Content{
|
||||
Source: link,
|
||||
Destination: trimmed,
|
||||
Type: "symlink",
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
fileContent := &files.Content{
|
||||
Source: path,
|
||||
Destination: trimmed,
|
||||
FileInfo: &files.ContentFileInfo{
|
||||
MTime: fi.ModTime(),
|
||||
Mode: fi.Mode(),
|
||||
Size: fi.Size(),
|
||||
},
|
||||
}
|
||||
|
||||
if slices.Contains(vars.Backup, trimmed) {
|
||||
fileContent.Type = "config|noreplace"
|
||||
}
|
||||
|
||||
contents = append(contents, fileContent)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
pkgInfo.Overridables.Contents = contents
|
||||
|
||||
pkgFormat := mgr.Format()
|
||||
if format, ok := os.LookupEnv("LURE_PKG_FORMAT"); ok {
|
||||
pkgFormat = format
|
||||
}
|
||||
|
||||
packager, err := nfpm.Get(pkgFormat)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pkgName := packager.ConventionalFileName(pkgInfo)
|
||||
pkgPath := filepath.Join(baseDir, pkgName)
|
||||
|
||||
pkgPaths := append(builtDeps, pkgPath)
|
||||
pkgNames := append(builtNames, vars.Name)
|
||||
|
||||
pkgFile, err := os.Create(pkgPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = packager.Package(pkgInfo, pkgFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
uniq(&pkgPaths, &pkgNames)
|
||||
|
||||
return pkgPaths, pkgNames, nil
|
||||
}
|
||||
|
||||
func genBuildEnv(info *distro.OSRelease) []string {
|
||||
env := os.Environ()
|
||||
env = append(
|
||||
env,
|
||||
"DISTRO_NAME="+info.Name,
|
||||
"DISTRO_PRETTY_NAME="+info.PrettyName,
|
||||
"DISTRO_ID="+info.ID,
|
||||
"DISTRO_BUILD_ID="+info.BuildID,
|
||||
|
||||
"ARCH="+runtime.GOARCH,
|
||||
"NCPU="+strconv.Itoa(runtime.NumCPU()),
|
||||
)
|
||||
|
||||
return env
|
||||
}
|
||||
|
||||
func getSources(ctx context.Context, srcdir string, bv *BuildVars) error {
|
||||
if len(bv.Sources) != len(bv.Checksums) {
|
||||
log.Fatal("The checksums array must be the same length as sources")
|
||||
}
|
||||
|
||||
for i, src := range bv.Sources {
|
||||
opts := download.GetOptions{
|
||||
SourceURL: src,
|
||||
Destination: srcdir,
|
||||
EncloseGit: true,
|
||||
}
|
||||
|
||||
if bv.Checksums[i] != "SKIP" {
|
||||
checksum, err := hex.DecodeString(bv.Checksums[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
opts.SHA256Sum = checksum
|
||||
}
|
||||
|
||||
err := download.Get(ctx, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setDirVars sets srcdir and pkgdir. It's a very hacky way of doing so,
|
||||
// but setting the runner's Env and Vars fields doesn't seem to work.
|
||||
func setDirVars(ctx context.Context, runner *interp.Runner, srcdir, pkgdir string) error {
|
||||
cmd := "srcdir='" + srcdir + "'\npkgdir='" + pkgdir + "'\n"
|
||||
fl, err := syntax.NewParser().Parse(strings.NewReader(cmd), "vars")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runner.Run(ctx, fl)
|
||||
}
|
||||
|
||||
// checkARMVariant checks which variant of ARM lure is running
|
||||
// on, by using the same detection method as Go itself
|
||||
func checkARMVariant() string {
|
||||
armEnv := os.Getenv("LURE_ARM_VARIANT")
|
||||
// ensure value has "arm" prefix, such as arm5 or arm6
|
||||
if strings.HasPrefix(armEnv, "arm") {
|
||||
return armEnv
|
||||
}
|
||||
|
||||
if cpu.ARM.HasVFPv3 {
|
||||
return "arm7"
|
||||
} else if cpu.ARM.HasVFP {
|
||||
return "arm6"
|
||||
} else {
|
||||
return "arm5"
|
||||
}
|
||||
}
|
||||
|
||||
func setScripts(vars *BuildVars, info *nfpm.Info, scriptDir string) {
|
||||
if vars.Scripts.PreInstall != "" {
|
||||
info.Scripts.PreInstall = filepath.Join(scriptDir, vars.Scripts.PreInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostInstall != "" {
|
||||
info.Scripts.PostInstall = filepath.Join(scriptDir, vars.Scripts.PostInstall)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreRemove != "" {
|
||||
info.Scripts.PreRemove = filepath.Join(scriptDir, vars.Scripts.PreRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostRemove != "" {
|
||||
info.Scripts.PostRemove = filepath.Join(scriptDir, vars.Scripts.PostRemove)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
info.APK.Scripts.PreUpgrade = filepath.Join(scriptDir, vars.Scripts.PreUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostUpgrade != "" {
|
||||
info.ArchLinux.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
info.APK.Scripts.PostUpgrade = filepath.Join(scriptDir, vars.Scripts.PostUpgrade)
|
||||
}
|
||||
|
||||
if vars.Scripts.PreTrans != "" {
|
||||
info.RPM.Scripts.PreTrans = filepath.Join(scriptDir, vars.Scripts.PreTrans)
|
||||
}
|
||||
|
||||
if vars.Scripts.PostTrans != "" {
|
||||
info.RPM.Scripts.PostTrans = filepath.Join(scriptDir, vars.Scripts.PostTrans)
|
||||
}
|
||||
}
|
||||
|
||||
func uniq(ss ...*[]string) {
|
||||
for _, s := range ss {
|
||||
slices.Sort(*s)
|
||||
*s = slices.Compact(*s)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
125
config.go
125
config.go
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* LURE - Linux User REpository
|
||||
* Copyright (C) 2022 Arsen Musayelyan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"go.arsenm.dev/lure/manager"
|
||||
)
|
||||
|
||||
var (
|
||||
cacheDir string
|
||||
cfgPath string
|
||||
config Config
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
RootCmd string `toml:"rootCmd"`
|
||||
Repos []Repo `toml:"repo"`
|
||||
}
|
||||
|
||||
type Repo struct {
|
||||
Name string `toml:"name"`
|
||||
URL string `toml:"url"`
|
||||
}
|
||||
|
||||
var defaultConfig = Config{
|
||||
RootCmd: "sudo",
|
||||
Repos: []Repo{
|
||||
{
|
||||
Name: "default",
|
||||
URL: "https://github.com/Arsen6331/lure-repo.git",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
cfg, cache, err := makeDirs()
|
||||
if err != nil {
|
||||
log.Fatal("Error creating directories").Err(err).Send()
|
||||
}
|
||||
cacheDir = cache
|
||||
|
||||
cfgPath = filepath.Join(cfg, "lure.toml")
|
||||
|
||||
cfgFl, err := os.Open(cfgPath)
|
||||
if err != nil {
|
||||
log.Fatal("Error opening config file").Err(err).Send()
|
||||
}
|
||||
defer cfgFl.Close()
|
||||
|
||||
err = toml.NewDecoder(cfgFl).Decode(&config)
|
||||
if err != nil {
|
||||
log.Fatal("Error decoding config file").Err(err).Send()
|
||||
}
|
||||
|
||||
manager.DefaultRootCmd = config.RootCmd
|
||||
}
|
||||
|
||||
func makeDirs() (string, string, error) {
|
||||
cfgDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
baseCfgPath := filepath.Join(cfgDir, "lure")
|
||||
|
||||
err = os.MkdirAll(baseCfgPath, 0o755)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
cfgPath := filepath.Join(baseCfgPath, "lure.toml")
|
||||
|
||||
if _, err := os.Stat(cfgPath); err != nil {
|
||||
cfgFl, err := os.Create(cfgPath)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
err = toml.NewEncoder(cfgFl).Encode(&defaultConfig)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
cfgFl.Close()
|
||||
}
|
||||
|
||||
cacheDir, err := os.UserCacheDir()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
baseCachePath := filepath.Join(cacheDir, "lure")
|
||||
|
||||
err = os.MkdirAll(filepath.Join(baseCachePath, "repo"), 0o755)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
err = os.MkdirAll(filepath.Join(baseCachePath, "pkgs"), 0o755)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return baseCfgPath, baseCachePath, nil
|
||||
}
|
8
docs/README.md
Normal file
8
docs/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# LURE Docs
|
||||
|
||||
- [Configuration](configuration.md)
|
||||
- [Usage](usage.md)
|
||||
- [Packages](packages)
|
||||
- [Build Scripts](packages/build-scripts.md)
|
||||
- [Package Conventions](packages/conventions.md)
|
||||
- [Adding Packages to LURE's repo](packages/adding-packages.md)
|
44
docs/configuration.md
Normal file
44
docs/configuration.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Configuration
|
||||
|
||||
This page describes the configuration of LURE
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Config file](#config-file)
|
||||
- [rootCmd](#rootcmd)
|
||||
- [repo](#repo)
|
||||
|
||||
---
|
||||
|
||||
## File locations
|
||||
|
||||
| Path | Description
|
||||
| --: | :--
|
||||
| ~/.config/lure/lure.toml | Config file
|
||||
| ~/.cache/lure/pkgs | here the packages are built and stored
|
||||
| ~/.cache/lure/repo | here are the git repos with all the `lure.sh` files
|
||||
| | Example: `~/.cache/lure/repo/default/itd-bin/lure.sh`
|
||||
|
||||
---
|
||||
|
||||
## Config file
|
||||
|
||||
### rootCmd
|
||||
|
||||
The `rootCmd` field in the config specifies which command should be used for privilege elevation. The default value is `sudo`.
|
||||
|
||||
### repo
|
||||
|
||||
The `repo` array in the config specifies which repos are added to LURE. Each repo must have a name and URL. A repo looks like this in the config:
|
||||
|
||||
```toml
|
||||
[[repo]]
|
||||
name = 'default'
|
||||
url = 'https://github.com/Elara6331/lure-repo.git'
|
||||
```
|
||||
|
||||
The `default` repo is added by default. Any amount of repos may be added.
|
||||
|
||||
---
|
5
docs/packages/README.md
Normal file
5
docs/packages/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# LURE Docs > Packages
|
||||
|
||||
- [Build Scripts](build-scripts.md)
|
||||
- [Package Conventions](conventions.md)
|
||||
- [Adding Packages to LURE's repo](adding-packages.md)
|
27
docs/packages/adding-packages.md
Normal file
27
docs/packages/adding-packages.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Adding Packages to LURE's repo
|
||||
|
||||
## Requirements
|
||||
|
||||
- `go` (1.18+)
|
||||
- `git`
|
||||
- `lure-analyzer`
|
||||
- `go install go.elara.ws/lure-repo-bot/cmd/lure-analyzer@latest`
|
||||
- `shfmt`
|
||||
- May be available in distro repos
|
||||
- `go install mvdan.cc/sh/v3/cmd/shfmt@latest`
|
||||
|
||||
---
|
||||
|
||||
## How to test a package
|
||||
|
||||
To test packages you can first create [a `lure.sh` shell file](./build-scripts.md) and then run the `lure build` comand to build the local `lure.sh` file into a package for your distro (more info about the `build` command [here](./usage.md#build)). You can then install this file to your distro and test it.
|
||||
|
||||
## How to submit a package
|
||||
|
||||
LURE's repo is hosted on Github at https://github.com/Elara6331/lure-repo. In it, there are multiple directories each containing a `lure.sh` file. In order to add a package to LURE's repo, simply create a PR with a [build script](./build-scripts.md) and place it in a directory with the same name as the package.
|
||||
|
||||
Upon submitting the PR, [lure-repo-bot](https://github.com/Elara6331/lure-repo-bot) will pull your PR and analyze it, providing suggestions for fixes as review comments. If there are no problems, the bot will approve your changes. If there are issues, re-request review from the bot after you've finished applying the fixes and it will automatically review the PR again.
|
||||
|
||||
All scripts submitted to the LURE repo should be formatted with `shfmt`. If they are not properly formatted, Github Actions will add suggestions in the "Files Changed" tab of the PR.
|
||||
|
||||
Once your PR is merged, LURE will pull the changed repo and your package will be available for people to install.
|
499
docs/packages/build-scripts.md
Normal file
499
docs/packages/build-scripts.md
Normal file
@ -0,0 +1,499 @@
|
||||
# LURE Build Scripts
|
||||
|
||||
LURE uses build scripts similar to the AUR's PKGBUILDs. This is the documentation for those scripts.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Distro Overrides](#distro-overrides)
|
||||
- [Variables](#variables)
|
||||
- [name](#name)
|
||||
- [version](#version)
|
||||
- [release](#release)
|
||||
- [epoch](#epoch)
|
||||
- [desc](#desc)
|
||||
- [homepage](#homepage)
|
||||
- [maintainer](#maintainer)
|
||||
- [architectures](#architectures)
|
||||
- [licenses](#licenses)
|
||||
- [provides](#provides)
|
||||
- [conflicts](#conflicts)
|
||||
- [deps](#deps)
|
||||
- [build_deps](#build_deps)
|
||||
- [opt_deps](#opt_deps)
|
||||
- [replaces](#replaces)
|
||||
- [sources](#sources)
|
||||
- [checksums](#checksums)
|
||||
- [backup](#backup)
|
||||
- [scripts](#scripts)
|
||||
- [Functions](#functions)
|
||||
- [prepare](#prepare)
|
||||
- [version](#version-1)
|
||||
- [build](#build)
|
||||
- [package](#package)
|
||||
- [Environment Variables](#environment-variables)
|
||||
- [DISTRO_NAME](#distro_name)
|
||||
- [DISTRO_PRETTY_NAME](#distro_pretty_name)
|
||||
- [DISTRO_ID](#distro_id)
|
||||
- [DISTRO_VERSION_ID](#distro_version_id)
|
||||
- [ARCH](#arch)
|
||||
- [NCPU](#ncpu)
|
||||
- [Helper Commands](#helper-commands)
|
||||
- [install-binary](#install-binary)
|
||||
- [install-systemd](#install-systemd)
|
||||
- [install-systemd-user](#install-systemd-user)
|
||||
- [install-config](#install-config)
|
||||
- [install-license](#install-license)
|
||||
- [install-completion](#install-completion)
|
||||
- [install-manual](#install-manual)
|
||||
- [install-desktop](#install-desktop)
|
||||
- [install-library](#install-library)
|
||||
- [git-version](#git-version)
|
||||
|
||||
---
|
||||
|
||||
## Distro Overrides
|
||||
|
||||
Allowing LURE to run on different distros provides some challenges. For example, some distros use different names for their packages. This is solved using distro overrides. Any variable or function used in a LURE build script may be overridden based on distro and CPU architecture. The way you do this is by appending the distro and/or architecture to the end of the name. For example, [ITD](https://gitea.elara.ws/Elara6331/itd) depends on the `pactl` command as well as DBus and BlueZ. These are named somewhat differently on different distros. For ITD, I use the following for the dependencies:
|
||||
|
||||
```bash
|
||||
deps=('dbus' 'bluez' 'pulseaudio-utils')
|
||||
deps_arch=('dbus' 'bluez' 'libpulse')
|
||||
deps_opensuse=('dbus-1' 'bluez' 'pulseaudio-utils')
|
||||
```
|
||||
|
||||
Appending `arch` and `opensuse` to the end causes LURE to use the appropriate array based on the distro. If on Arch Linux, it will use `deps_arch`. If on OpenSUSE, it will use `deps_opensuse`, and if on anything else, it will use `deps`.
|
||||
|
||||
Names are checked in the following order:
|
||||
|
||||
- $name_$architecture_$distro
|
||||
- $name_$distro
|
||||
- $name_$architecture
|
||||
- $name
|
||||
|
||||
Distro detection is performed by reading the `/usr/lib/os-release` and `/etc/os-release` files.
|
||||
|
||||
### Like distros
|
||||
|
||||
Inside the `os-release` file, there is a list of "like" distros. LURE takes this into account. For example, if a script contains `deps_debian` but not `deps_ubuntu`, Ubuntu builds will use `deps_debian` because Ubuntu is based on debian.
|
||||
|
||||
Most specificity is preferred, so if both `deps_debian` and `deps_ubuntu` is provided, Ubuntu and all Ubuntu-based distros will use `deps_ubuntu` while Debian and all Debian-based distros
|
||||
that are not Ubuntu-based will use `deps_debian`.
|
||||
|
||||
Like distros are disabled when using the `LURE_DISTRO` environment variable.
|
||||
|
||||
## Variables
|
||||
|
||||
Any variables marked with `(*)` are required
|
||||
|
||||
### name (*)
|
||||
|
||||
The `name` variable contains the name of the package described by the script.
|
||||
|
||||
### version (*)
|
||||
|
||||
The `version` variable contains the version of the package. This should be the same as the version used by the author upstream.
|
||||
|
||||
Versions are compared using the [rpmvercmp](https://fedoraproject.org/wiki/Archive:Tools/RPM/VersionComparison) algorithm.
|
||||
|
||||
### release (*)
|
||||
|
||||
The `release` number is meant to differentiate between different builds of the same package version, such as if the script is changed but the version stays the same. The `release` must be an integer.
|
||||
|
||||
### epoch
|
||||
|
||||
The `epoch` number forces the package to be considered newer than versions with a lower epoch. It is meant to be used if the versioning scheme can't be used to determine which package is newer. Its use is discouraged and it should only be used if necessary. The `epoch` must be a positive integer.
|
||||
|
||||
### desc
|
||||
|
||||
The `desc` field contains the description for the package. It should not contain any newlines.
|
||||
|
||||
### homepage
|
||||
|
||||
The `homepage` field contains the URL to the website of the project packaged by this script.
|
||||
|
||||
### maintainer
|
||||
|
||||
The `maintainer` field contains the name and email address of the person maintaining the package. Example:
|
||||
|
||||
```text
|
||||
Elara Musayelyan <elara@elara.ws>
|
||||
```
|
||||
|
||||
While LURE does not require this field to be set, Debian has deprecated unset maintainer fields, and may disallow their use in `.deb` packages in the future.
|
||||
|
||||
### architectures
|
||||
|
||||
The `architectures` array contains all the architectures that this package supports. These match Go's GOARCH list, except for a few differences.
|
||||
|
||||
The `all` architecture will be translated to the proper term for the packaging format. For example, it will be changed to `noarch` if building a `.rpm`, or `any` if building an Arch package.
|
||||
|
||||
Since multiple variations of the `arm` architecture exist, the following values should be used:
|
||||
|
||||
`arm5`: armv5
|
||||
`arm6`: armv6
|
||||
`arm7`: armv7
|
||||
|
||||
LURE will attempt to detect which variant your system is using by checking for the existence of various CPU features. If this yields the wrong result or if you simply want to build for a different variant, the `LURE_ARM_VARIANT` variable should be set to the ARM variant you want. Example:
|
||||
|
||||
```shell
|
||||
LURE_ARM_VARIANT=arm5 lure install ...
|
||||
```
|
||||
|
||||
### licenses
|
||||
|
||||
The `licenses` array contains the licenses used by this package. In order to standardize license names, values should be [SPDX Identifiers](https://spdx.org/licenses/) such as `Apache-2.0`, `MIT`, and `GPL-3.0-only`. If the project uses a license that is not standardized in SPDX, use the value `Custom`. If the project has multiple nonstandard licenses, include `Custom` as many times as there are nonstandard licenses.
|
||||
|
||||
### provides
|
||||
|
||||
The `provides` array specifies what features the package provides. For example, if two packages build `ffmpeg` with different build flags, they should both have `ffmpeg` in the `provides` array.
|
||||
|
||||
### conflicts
|
||||
|
||||
The `conflicts` array contains names of packages that conflict with the one built by this script. If two different packages contain the executable for `ffmpeg`, they cannot be installed at the same time, so they conflict. The `provides` array will also be checked, so this array generally contains the same values as `provides`.
|
||||
|
||||
### deps
|
||||
|
||||
The `deps` array contains the dependencies for the package. LURE repos will be checked first, and if the packages exist there, they will be built and installed. Otherwise, they will be installed from the system repos by your package manager.
|
||||
|
||||
### build_deps
|
||||
|
||||
The `build_deps` array contains the dependencies that are required to build the package. They will be installed before the build starts. Similarly to the `deps` array, LURE repos will be checked first.
|
||||
|
||||
### opt_deps
|
||||
|
||||
The `opt_deps` array contains optional dependencies for the package. A description can be added after ": ", but it's not required.
|
||||
|
||||
```bash
|
||||
opt_deps_arch=(
|
||||
'git: Download git repositories'
|
||||
'aria2: Download files'
|
||||
)
|
||||
```
|
||||
|
||||
### replaces
|
||||
|
||||
The `replaces` array contains the packages that are replaced by this package. Generally, if package managers find a package with a `replaces` field set, they will remove the listed package(s) and install that one instead. This is only useful if the packages are being stored in a repo for your package manager.
|
||||
|
||||
### sources
|
||||
|
||||
The `sources` array contains URLs which are downloaded into `$srcdir` before the build starts.
|
||||
|
||||
If the URL provided is an archive or compressed file, it will be extracted. To disable this, add the `~archive=false` query parameter. Example:
|
||||
|
||||
Extracted:
|
||||
```text
|
||||
https://example.com/archive.tar.gz
|
||||
```
|
||||
|
||||
Not extracted:
|
||||
```text
|
||||
https://example.com/archive.tar.gz?~archive=false
|
||||
```
|
||||
|
||||
If the URL scheme starts with `git+`, the source will be downloaded as a git repo. The git download mode supports multiple parameters:
|
||||
|
||||
- `~rev`: Specify which revision of the repo to check out.
|
||||
- `~depth`: Specify what depth should be used when cloning the repo. Must be an integer.
|
||||
- `~name`: Specify the name of the directory into which the git repo should be cloned.
|
||||
- `~recursive`: If set to true, submodules will be cloned recursively. It is false by default.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
git+https://gitea.elara.ws/Elara6331/itd?~rev=resource-loading&~depth=1
|
||||
```
|
||||
|
||||
```text
|
||||
git+https://gitea.elara.ws/lure/lure?~rev=v0.0.1&~recursive=true
|
||||
```
|
||||
|
||||
### checksums
|
||||
|
||||
The `checksums` array must be the same length as the `sources` array. It contains checksums for the source files. The files are checked against the checksums and the build fails if they don't match.
|
||||
|
||||
By default, checksums are expected to be sha256. To change the algorithm, add it before the hash with a colon in between. For example, `md5:bc0c6f5dcd06bddbca9a0163e4c9f2e1`. The following algorithms are currently supported: `sha256`, `sha224`, `sha512`, `sha384`, `sha1`, and `md5`.
|
||||
|
||||
To skip the check for a particular source, set the corresponding checksum to `SKIP`.
|
||||
|
||||
### backup
|
||||
|
||||
The `backup` array contains files that should be backed up when upgrading and removing. The exact behavior of this depends on your package manager. All files within this array must be full destination paths. For example, if there's a config called `config` in `/etc` that you want to back up, you'd set it like so:
|
||||
|
||||
```bash
|
||||
backup=('/etc/config')
|
||||
```
|
||||
|
||||
### scripts
|
||||
|
||||
The `scripts` variable contains a Bash associative array that specifies the location of various scripts relative to the build script. Example:
|
||||
|
||||
```bash
|
||||
scripts=(
|
||||
['preinstall']='preinstall.sh'
|
||||
['postinstall']='postinstall.sh'
|
||||
['preremove']='preremove.sh'
|
||||
['postremove']='postremove.sh'
|
||||
['preupgrade']='preupgrade.sh'
|
||||
['postupgrade']='postupgrade.sh'
|
||||
['pretrans']='pretrans.sh'
|
||||
['posttrans']='posttrans.sh'
|
||||
)
|
||||
```
|
||||
|
||||
Note: The quotes are required due to limitations with the bash parser used.
|
||||
|
||||
The `preupgrade` and `postupgrade` scripts are only available in `.apk` and Arch Linux packages.
|
||||
|
||||
The `pretrans` and `posttrans` scripts are only available in `.rpm` packages.
|
||||
|
||||
The rest of the scripts are available in all packages.
|
||||
|
||||
---
|
||||
|
||||
## Functions
|
||||
|
||||
This section documents user-defined functions that can be added to build scripts. Any functions marked with `(*)` are required.
|
||||
|
||||
All functions are executed in the `$srcdir` directory
|
||||
|
||||
### version
|
||||
|
||||
The `version()` function updates the `version` variable. This allows for automatically deriving the version from sources. This is most useful for git packages, which usually don't need to be changed, so their `version` variable stays the same.
|
||||
|
||||
An example of using this for git:
|
||||
|
||||
```bash
|
||||
version() {
|
||||
cd "$srcdir/itd"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
```
|
||||
|
||||
The AUR equivalent is the [`pkgver()` function](https://wiki.archlinux.org/title/VCS_package_guidelines#The_pkgver()_function)
|
||||
|
||||
### prepare
|
||||
|
||||
The `prepare()` function is meant to prepare the sources for building and packaging. This is the function in which patches should be applied, for example, by the `patch` command, and where tools like `go generate` should be executed.
|
||||
|
||||
### build
|
||||
|
||||
The `build()` function is where the package is actually built. Use the same commands that would be used to manually compile the software. Often, this function is just one line:
|
||||
|
||||
```bash
|
||||
build() {
|
||||
make
|
||||
}
|
||||
```
|
||||
|
||||
### package (*)
|
||||
|
||||
The `package()` function is where the built files are placed into the directory that will be used by LURE to build the package.
|
||||
|
||||
Any files that should be installed on the filesystem should go in the `$pkgdir` directory in this function. For example, if you have a binary called `bin` that should be placed in `/usr/bin` and a config file called `bin.cfg` that should be placed in `/etc`, the `package()` function might look like this:
|
||||
|
||||
```bash
|
||||
package() {
|
||||
install -Dm755 bin ${pkgdir}/usr/bin/bin
|
||||
install -Dm644 bin.cfg ${pkgdir}/etc/bin.cfg
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
LURE exposes several values as environment variables for use in build scripts.
|
||||
|
||||
### DISTRO_NAME
|
||||
|
||||
The `DISTRO_NAME` variable is the name of the distro as defined in its `os-release` file.
|
||||
|
||||
For example, it's set to `Fedora Linux` in a Fedora 36 docker image
|
||||
|
||||
### DISTRO_PRETTY_NAME
|
||||
|
||||
The `DISTRO_PRETTY_NAME` variable is the "pretty" name of the distro as defined in its `os-release` file.
|
||||
|
||||
For example, it's set to `Fedora Linux 36 (Container Image)` in a Fedora 36 docker image
|
||||
|
||||
### DISTRO_ID
|
||||
|
||||
The `DISTRO_ID` variable is the identifier of the distro as defined in its `os-release` file. This is the same as what LURE uses for overrides.
|
||||
|
||||
For example, it's set to `fedora` in a Fedora 36 docker image
|
||||
|
||||
### DISTRO_ID_LIKE
|
||||
|
||||
The `DISTRO_ID_LIKE` variable contains identifiers of similar distros to the one running, separated by spaces.
|
||||
|
||||
For example, it's set to `opensuse suse` in an OpenSUSE Tumbleweed docker image and `rhel fedora` in a CentOS 8 docker image.
|
||||
|
||||
### DISTRO_VERSION_ID
|
||||
|
||||
The `DISTRO_VERSION_ID` variable is the version identifier of the distro as defined in its `os-release` file.
|
||||
|
||||
For example, it's set to `36` in a Fedora 36 docker image and `11` in a Debian Bullseye docker image
|
||||
|
||||
### ARCH
|
||||
|
||||
The `ARCH` variable is the architecture of the machine running the script. It uses the same naming convention as the values in the `architectures` array
|
||||
|
||||
### NCPU
|
||||
|
||||
The `NCPU` variable is the amount of CPUs available on the machine running the script. It will be set to `8` on a quad core machine with hyperthreading, for example.
|
||||
|
||||
---
|
||||
|
||||
## Helper Commands
|
||||
|
||||
LURE provides various commands to help packagers create proper cross-distro packages. These commands should be used wherever possible instead of doing the tasks manually.
|
||||
|
||||
### install-binary
|
||||
|
||||
`install-binary` accepts 1-2 arguments. The first argument is the binary you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-binary ./itd
|
||||
install-binary ./itd itd-2
|
||||
```
|
||||
|
||||
### install-systemd
|
||||
|
||||
`install-systemd` installs regular systemd system services (see `install-systemd-user` for user services)
|
||||
|
||||
It accepts 1-2 arguments. The first argument is the service you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-systemd ./syncthing@.service
|
||||
install-systemd-user ./syncthing@.service sync-thing@.service
|
||||
```
|
||||
|
||||
### install-systemd-user
|
||||
|
||||
`install-systemd-user` installs systemd user services (services like `itd` meant to be started with `--user`).
|
||||
|
||||
It accepts 1-2 arguments. The first argument is the service you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-systemd-user ./itd.service
|
||||
install-systemd-user ./itd.service infinitime-daemon.service
|
||||
```
|
||||
|
||||
### install-config
|
||||
|
||||
`install-config` installs configuration files into the `/etc` directory
|
||||
|
||||
It accepts 1-2 arguments. The first argument is the config you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-config ./itd.toml
|
||||
install-config ./itd.example.toml itd.toml
|
||||
```
|
||||
|
||||
### install-license
|
||||
|
||||
`install-license` installs a license file
|
||||
|
||||
It accepts 1-2 arguments. The first argument is the config you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-license ./LICENSE itd/LICENSE
|
||||
```
|
||||
|
||||
### install-completion
|
||||
|
||||
`install-completion` installs shell completions
|
||||
|
||||
It currently supports `bash`, `zsh`, and `fish`
|
||||
|
||||
Completions are read from stdin, so they can either be piped in or retrieved from files
|
||||
|
||||
Two arguments are required for this function. The first one is the name of the shell and the second is the name of the completion.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
./k9s completion fish | install-completion fish k9s
|
||||
install-completion bash k9s <./k9s/completions/k9s.bash
|
||||
```
|
||||
|
||||
### install-manual
|
||||
|
||||
`install-manual` installs manpages. It accepts a single argument, which is the path to the manpage.
|
||||
|
||||
The install path will be determined based on the number at the end of the filename. If a number cannot be extracted, an error will be returned.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-manual ./man/strelaysrv.1
|
||||
install-manual ./mdoc.7
|
||||
```
|
||||
|
||||
### install-desktop
|
||||
|
||||
`install-desktop` installs desktop files for applications. It accepts 1-2 arguments. The first argument is the config you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-desktop ./${name}/share/admc.desktop
|
||||
install-desktop ./${name}/share/admc.desktop admc-app.desktop
|
||||
```
|
||||
|
||||
### install-library
|
||||
|
||||
`install-library` installs shared and static libraries to the correct location.
|
||||
|
||||
This is the most important helper as it contains logic to figure out where to install libraries based on the target distro and CPU architecture. It should almost always be used to install all libraries.
|
||||
|
||||
It accepts 1-2 arguments. The first argument is the config you'd like to install. The second is the filename that should be used.
|
||||
|
||||
If the filename argument is not provided, tha name of the input file will be used.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
install-library ./${name}/build/libadldap.so
|
||||
```
|
||||
|
||||
### git-version
|
||||
|
||||
`git-version` returns a version number based on the git revision of a repository.
|
||||
|
||||
If an argument is provided, it will be used as the path to the repo. Otherwise, the current directory will be used.
|
||||
|
||||
The version number will be the amount of revisions, a dot, and the short hash of the current revision. For example: `118.e4b8348`.
|
||||
|
||||
The AUR's convention includes an `r` at the beginning of the version number. This is ommitted because some distros expect the version number to start with a digit.
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
git-version
|
||||
git-version "$srcdir/itd"
|
||||
```
|
36
docs/packages/conventions.md
Normal file
36
docs/packages/conventions.md
Normal file
@ -0,0 +1,36 @@
|
||||
# Package Conventions
|
||||
|
||||
## General
|
||||
|
||||
Packages should have the name(s) of what they contain in their `provides` and `conflicts` arrays. That way, they can be installed by users without needing to know the full package name. For example, there are two LURE packages for ITD: `itd-bin`, and `itd-git`. Both of them have provides and conflicts arrays specifying the two commands they install: `itd`, and `itctl`. This means that if a user wants to install ITD, they simply have to type `lure in itd` and LURE will prompt them for which one they want to install.
|
||||
|
||||
## Binary packages
|
||||
|
||||
Packages that install download and install precompiled binaries should have a `-bin` suffix.
|
||||
|
||||
## Git packages
|
||||
|
||||
Packages that build and install programs from source code cloned directly from Git should have a `-git` suffix.
|
||||
|
||||
The versions of these packages should consist of the amount of revisions followed by the current revision, separated by a period. For example: `183.80187b0`. Note that unlike the AUR, there is no `r` at the beginning. This is because some package managers refuse to install packages whose version numbers don't start with a digit.
|
||||
|
||||
This version number can be obtained using the following command:
|
||||
|
||||
```bash
|
||||
printf "%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
```
|
||||
|
||||
The `version()` function for such packages should use the LURE-provided `git-version` helper command, like so:
|
||||
|
||||
```bash
|
||||
version() {
|
||||
cd "$srcdir/$name"
|
||||
git-version
|
||||
}
|
||||
```
|
||||
|
||||
This uses LURE's embedded Git implementation, which ensures that the user doesn't need Git installed on their system in order to install `-git` packages.
|
||||
|
||||
## Other packages
|
||||
|
||||
Packages that download sources for a specific version of a program should not have any suffix, even if those sources are downloaded from Git.
|
209
docs/usage.md
Normal file
209
docs/usage.md
Normal file
@ -0,0 +1,209 @@
|
||||
# Usage
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Commands](#commands)
|
||||
- [install](#install)
|
||||
- [remove](#remove)
|
||||
|