Compare commits

...

89 Commits

Author SHA1 Message Date
Christian Heusel
36ece44b12 chore(release): version v1.1.0 2024-02-08 01:31:00 +01:00
Levente Polyak
fc05ea19d9 fix(build): allow unstable repositories to override repo target
This works around the fact that we are currently not auto detecting
unstable repository targets while providing a stability layer option on
the subcommand. Soften the --repo option rules by allowing unstable
repositories to use that flag for building and releasing against the
unstable repositories.

This will be replaced in the near future by proper integration of target
repository auto-detection that in aware of unstable repositories while
providing a unstable stability layer options.

Component: pkgctl build
Component: pkgctl release
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-02-08 01:21:40 +01:00
Levente Polyak
3ecba314fc feat(build): consolidate repo flags in build and release subcommand
Previously the behavior was inconsistent and not fully fulfilling its
purpose of only using --repo once when initially pushing a new and
unknown package to the official repositories.

Consolidate the behavior by only allowing to use --repo during the
initial packaging and disallow any subsequent usage. The expected user
experience is to subsequently use --testing or --staging to influence
the auto-detection of the build target. This avoids any kind of human
error which leads to releasing core packages to extra-testing by
accident.

Furthermore, allow the build subcommand to automatically fallback to
extra as the default stable repository target which greatly improves the
usability for AUR or local override builds.

Fixes #193
Fixes #191

Component: pkgctl build
Component: pkgctl release
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-02-08 00:52:20 +01:00
Christian Heusel
5042dcaeb4 feat(build): allow to test-install the built packages
This change introduces the new --install-to-host flag to pkgctl build,
which can be used with one of the modes 'all' or 'auto'. Depending on
the mode either all or just already installed packages are installed to
the host system.

BREAKING CHANGE: the --install flag is renamed to --install-to-chroot
to avoid confusion with the newly introduced flag.

Component: pkgctl build
Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-02-06 19:38:50 +01:00
Levente Polyak
67fdb58758 feat(search): add status spinner to long running GitLab calls
This helps people to be slightly more patient as the progress status
update includes the current percentage.

Component: pkgctl search
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-02-06 17:37:17 +01:00
Carl Smedstad
eabb1a9313 fix(doc): Correct typo in version check error message
Change 'none pkgbase' to 'non-pkgbase' as the sentence refers sections
that are not the pkgbase section, rather than an empty pkgbase section
or something of that sort that could be misconstrued by using the word
'none'.

Component: pkgctl version check
2024-02-05 12:25:18 +01:00
Carl Smedstad
a7a2f25fb0 fix(version): Handle pkgbase with '.' correctly
For pkgbases with '.' in the name, the TOML-section must be wrapped in
double quotes in order for it not to be parsed as a supersection and a
subsection. This case was not properly handled by checks for if the
TOML-file contains a pkgbase section, and for if the TOML-file contains
superfluous sections. Address this by handling optional double quotes in
the greps related to said checks.

This was discovered in the AUR package ruby-cool.io and the issue can be
reproduced with the following minimal PKGBUILD and .nvchecker.toml file:

    $ cat PKGBUILD
    pkgname=ruby-cool.io
    pkgver=1.8.0
    $ cat .nvchecker.toml
    ["ruby-cool.io"]
    source = "gems"
    gems = "cool.io"

Before the fix:

    $ pkgctl version check
    Failure
     x ruby-cool.io: missing pkgbase section in .nvchecker.toml: ruby-cool.io

After the fix:

    $ pkgctl version check
    GEN lib/version/check.sh
    Out-of-date
     ✓ ruby-cool.io: current version 1.8.0 is latest

Component: pkgctl version check
2024-02-05 12:25:18 +01:00
Jelle van der Waa
800cf9b56b fix(version): fix typo never should be newer
Component: pkgctl version check
Component: pkgctl version update
2024-02-05 11:54:55 +01:00
Levente Polyak
4d72f4560c doc(version): extensively revamp documentation for version subcommands
Enhanced and overhauled the documentation for the 'version' subcommand.
The improvements include comprehensive details on the subcommand's
behavior, usage, and a variety of scenarios it handles.

Added a central section within the pkgctl-version manpage that documents
the nvchecker configuration and rules.

Component: pkgctl version
Singled-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-22 19:45:16 +01:00
Levente Polyak
e3edf25554 feat(version): use exit code for check to indicate out-of-date versions
It can be handy to have an exit code that allows better status
indication or chaining.

On exit, return one of the following codes:

- 0: Normal exit condition, all checked versions are up-to-date
- 1: Unknown cause of failure
- 2: Normal exit condition, but there are out-of-date versions
- 3: Failed to run some version checks

Component: pkgctl version check
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-22 19:45:10 +01:00
Levente Polyak
b258bb3b7c feat(version): add verbose option to display up-to-date versions
Sometimes it can be desired to get a results for each entry even if the
current version is up-to-date. Add a --verbose option to print this
optional detail.

Component: pkgctl version check
Component: pkgctl version upgrade
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-22 19:45:04 +01:00
Levente Polyak
08ece1640b feat(version): add spinner while checking upstream versions
It may take quite some time to check a lot of upstream versions.
However, we still want to nicely group the results together. To avoid
just showing a static status message it makes much more sense to show a
dynamic spinner with a summary of the progress.

Component: pkgctl version check
Component: pkgctl version upgrade
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-22 19:44:57 +01:00
Levente Polyak
fedfc80ca1 feat(term): add terminal utils to handle a dynamic spinner
The spinner uses a status file that can be used to dynamically update
the message. The spinner itself buffers the output in a frame buffer
variable before flushing a frame in one go.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-22 19:44:51 +01:00
Levente Polyak
66e83c950c feat(version): pretty print and group together version check results
Collect all check results in arrays and pretty print the results after
grouping them together based on out-of-date, up-to-date and failures.
Print a summary that shows a brief statistic about the results when
processing multiple check items.

Component: pkgctl version check
Component: pkgctl version upgrade
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-21 23:28:29 +01:00
Levente Polyak
96f39525bf feat(version): support nvchecker keyfile from user config home
This adds support for global keyfile from the user config home
XDG_CONFIG_HOME which allows to set tokens for GitHub and GitLab for
certain nvchecker configuration.

When ~/.config/nvchecker/keyfile.toml exists, it will automatically be
appended as keyfile of the local .nvchecker.toml file.

Component: pkgctl version check
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-21 23:28:29 +01:00
Levente Polyak
03d5c928cf fix(version): add error handling to version check subcommand
Add defensive programming to the execution chain of the version check
subcommand for graceful error handling of subprocesses as well as errors
returned from nvchecker itself indicated in the returned JSON.

Furthermore this fixes a bug when processing multiple packages where the
pkgbase variable is stuck for subsequent packages that do not declare a
pkgbase variable itself.

Component: pkgctl version check
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-21 23:28:29 +01:00
Christian Heusel
6054c869e1 feat(upgrade): introduce the version upgrade subcommand
This subcommand applies the detected upstream version upgrades to a
PKGBUILD.

Component: pkgctl version upgrade
Co-authored-by: Levente Polyak <anthraxx@archlinux.org>
Signed-off-by: Christian Heusel <christian@heusel.eu>
2024-01-21 23:28:29 +01:00
Christian Heusel
313c5b4d32 chore(check): factor out function to get upstream version
Component: pkgctl version check
Signed-off-by: Christian Heusel <christian@heusel.eu>
2024-01-21 23:28:28 +01:00
Christian Heusel
db8c157eea chore(build): factor out functions to modify PKGBUILDs
Component: pkgctl build
Signed-off-by: Christian Heusel <christian@heusel.eu>
2024-01-21 23:28:28 +01:00
Levente Polyak
343a2b5d4c chore(search): correct typo in optional dependency bat 2024-01-18 19:38:42 +01:00
Levente Polyak
7a8f0eb47e fix(doc): correct typo in optional dependency bat
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-18 03:02:18 +01:00
Jelle van der Waa
e6f7aa395f feat(version): introduce version check subcommand
The version subcommand handles pkgver related commands, the first
subcommand being `check`. Check runs nvchecker if a `.nvchecker.toml`
file exists and compares the current pkgver with the latest release.

Introduces nvchecker as optional dependency which has to be installed in
order to use this particular subcommand.

BREAKING CHANGE: formerly pkgctl version would output the version of the
pkgctl tool, now it is used as a version related subcommand.

Fixes #140

Component: pkgctl version
Component: pkgctl version check
Co-authored-by: Christian Heusel <christian@heusel.eu>
2024-01-10 19:44:15 +01:00
Levente Polyak
e413b65df3 fix(build): re-source the PKGBUILD to update changed values
During certain operations like --edit, --pkgver etc the PKGBUILD
may change since last sourced. If a modified checksum of the PKGBUILD
is detected, re-source it before processing.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-10 00:14:20 +01:00
Levente Polyak
ef04960b98 feat(build): update srcinfo file after build
The srcinfo file is essentially a representation of the current build
recipes, hence generate an up to date version by adding it as secondary
build artifact to the build process.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-10 00:14:14 +01:00
Levente Polyak
d210079037 feat(util): add library function to generate source packages 2024-01-10 00:14:08 +01:00
Levente Polyak
b264c7f1c7 feat(util): parallelize srcinfo generation
Heavily improve the runtime of huge split packages, by creating an own
parallelized high level implementation of the makepkg low level building
blocks for srcinfo generation.

This reduces the runtine to generate the srcinfo file for thunderbird
from 24 seconds down to 1 second.
2024-01-10 00:14:01 +01:00
Christian Heusel
2b8033b911 feat(aur): add subcommand to drop a package from the repos to the AUR
Add an aur command to interact with the Arch User Repository including
the drop-from-repo subommand which allows to drop packages from the
official repository to the Arch User Repository in one go.

Related to #143

Component: pkgctl aur drop-from-repo
Co-authored-by: Levente Polyak <anthraxx@archlinux.org>
Signed-off-by: Christian Heusel <christian@heusel.eu>
2024-01-09 23:47:45 +01:00
Levente Polyak
8f45c65830 fix(completion): support subcommands that have multiple dashes
Dashes are not supported in function names and underscores were not
automatically translated. Replace all dashes of the current completion
token, if it is an arg which allows subcommands to use underscores
instead of dashes to declare their completion handlers.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-07 19:32:30 +01:00
Levente Polyak
d0dc0e1a32 feat(search): add optional plain output formatting
This allows to run the search command without bats, which is not used in
the default pretty output format.

Component: pkgctl search
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-07 02:38:42 +01:00
Levente Polyak
0e538cf498 fix(util): open lock file in append mode to avoid overwriting files
Previously if we opened a lock on an existing file with useful content
we overwrote it with an empty file. This is obviously not desired, hence
open the file handle in append mode preserving its content.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-07 02:38:34 +01:00
Jelle van der Waa
4673ad6c89 feat(search): add subcommand to search across the packaging group
Search for an expression across the GitLab packaging group. To use a
filter, include it in your query. You may use wildcards (*) to use glob
matching. Available filters for the blobs scope: path, extension.

Every usage of the search command must be authenticated. Consult the
'pkgctl auth' command to authenticate with GitLab or view the
authentication status.

This command uses bats for pretty printing the results including line
numbers and syntax highlighting.

Component: pkgctl search
Co-authored-by: Christian Heusel <christian@heusel.eu>
Co-authored-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-07 02:35:18 +01:00
Levente Polyak
78dd150996 chore(offload-build): deprecate in favor of pkgctl build --offload
Emit a warning when offload-build is invoked to warn about future
removal.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-05 01:07:39 +01:00
Levente Polyak
4425913e4f chore(build): use more intuitive update-checksums option for humans
The philosophy of our CLI is to provide options that better match human
expectations in an intuitive way rather than mimic wording of previous
tools with abbreviation.

Component: pkgctl build
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2024-01-05 01:01:52 +01:00
Levente Polyak
2a1e8aebaf chore(make): suppress output when copying git hooks directory 2023-12-19 20:27:01 +01:00
Levente Polyak
3933f20001 fix(cliff): trim fix separator before checking merge request id
The fix separator contains a whitespace, which made the check never
match. We now trim the separator before checking, making it resilient
against any kind of spaces.

Fixes b7984c6073
2023-12-19 20:06:26 +01:00
Levente Polyak
0f14d630bc feat(cliff): add label for breaking changes to changelog 2023-12-19 20:06:26 +01:00
Levente Polyak
d00a2b9890 feat(configure): ship default ignore via exclude
BREAKING CHANGE: Increments the repo spec version which requires to
reconfigure all existing packaging repo clones.

Fixes #129

Component: pkgctl repo configure
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-12-19 20:06:26 +01:00
Christian Heusel
c2d73d73ae fix(commitpkg): prefer core.editor over $EDITOR and $VISUAL
This is done to closer mimick the behaviour of git here, as it prefers
core.editor setting over the other editor options as per git-var(1):

> The order of preference is the $GIT_EDITOR environment variable, then
> core.editor configuration, then $VISUAL, then $EDITOR, and then the
> default chosen at compile time, which is usually vi.

Fixes #192
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-12-03 22:02:13 +01:00
Levente Polyak
f2cafa3cb0 feat(clone): speedup maintainer and universe clone query
There is a single endpoint now to list all pkgbases and their current
maintainers. Use this endpoint for speeding up the clone of all packages
of a maintainer by only issuing a single API call.

Component: pkgctl repo clone
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-12-03 21:51:59 +01:00
Jan Alexander Steffens (heftig)
c356995dc1 feat(config): Add -z pack-relative-relocs to LDFLAGS
This moves relative relocations from the `.rela.dyn` section into a new
`.relr.dyn` section with a significantly more compact encoding,
supported since glibc 2.36, GNU Binutils 2.38 and LLVM 15.

This can reduce the size of libraries a lot, e.g. the installed size of
`libphonenumber` dropped from about 17 MB to 7 MB.

For more info, see
https://gitlab.archlinux.org/archlinux/rfcs/-/merge_requests/23.

Signed-off-by: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
2023-12-03 20:11:24 +01:00
Jan Alexander Steffens (heftig)
1535a69af6 chore(config): Use one -Wl in LDFLAGS per logical flag
This will separate logical flags with whitespace and make it easier to
split the flags across multiple lines.

Signed-off-by: Jan Alexander Steffens (heftig) <heftig@archlinux.org>
2023-12-03 20:11:21 +01:00
Christian Heusel
9a356eae82 feat(web): implement option to print the URL instead of opening it
In certain situations, users may encounter limitations when unable to
utilize xdg-open (e.g., when connected to an Arch machine via SSH).
Consequently, this commit introduces the option to simply print the
repository link to copy or click on it.

Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-11-26 18:23:17 +01:00
kpcyrd
ae14c246b8 feat(makerepropkg): Add option to skip running check for speedup
Add -n to allow running makepkg with --nocheck. This is useful to reduce
the time required to reproduce a package, as they should not depend on
running the check function for being reproducible.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-11-26 16:48:15 +01:00
Levente Polyak
cc369e86d2 feat(makechrootpkg): add option to interactively inspect the chroot
Implement the -x option for makechrootpkg which allows to get an
interactive shell in the chroot after building the package. Useful to
ease the debugging of a package build.

Depending on the argument, the interactive shell is either always
spawned or only when an error occurred during build.

This option is also forwarded from `pkgctl build` via the `--inspect`
flag.

Component: pkgctl build
Component: makechrootpkg
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-11-26 01:28:20 +01:00
David Runge
c9de6a18b9 fix(make): Specify GITLAB_HOST for glab to avoid default host confusion
Specify the upstream instance hostname for glab using the `GITLAB_HOST`
environment variable.
Without it `glab` will use whatever is set as host using the `host`
key in its configuration and silently break the links of all uploaded
assets.

Signed-off-by: David Runge <dvzrv@archlinux.org>
2023-11-24 22:27:14 +01:00
Christian Heusel
9f8ca5df1a chore(release): nicely format multiple "Component:" trailers
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-11-24 02:32:02 +01:00
Christian Heusel
7825f9fb02 chore(docs): correct the manpage for pkgctl db update
Turns out the manpages of pkgctl db update and pkgctl db move were just switched without having the page title adjusted.
Fixing the initial error therefore turned out to create the same problem for the manpage of pkgctl db update, which this commit re-fixes.

Fixes: 5e3ab4b321 ("chore(docs): correct the manpage for pkgctl db move")
Fixes: f834fc4700 ("db: command for Pacman database modification like update, move etc")
Fixes #195
Component: pkgctl db update
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-11-24 02:17:10 +01:00
Christian Heusel
b7984c6073 chore(release): allow fixes tags without cluttering the changelog
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-11-20 15:10:48 +01:00
Christian Heusel
5e3ab4b321 chore(docs): correct the manpage for pkgctl db move
So far the manpage for pkgctl db move seemed to be a copy of the pkgctl db update manpage
which caused an error upon install as the move page was not created.
Instead compiling this manpage overwrote the one for pkgctl db update
which this commit fixes.

Fixes: f834fc4700 ("db: command for Pacman database modification like update, move etc")
Fixes #195
Component: pkgctl db move
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-11-20 15:10:41 +01:00
Christian Heusel
e7b82f36ef feat(build): add --updpkgsums option
This is useful so people who update patches etc. can update their checksums on building.
The functionality itself was already implemented for --pkgver, but was not available separately.

Fixes #168
Component: pkgctl build
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-11-20 15:00:21 +01:00
Orhun Parmaksız
4d7364ed1b fix(cliff): update the tag_pattern to use regex 2023-10-31 16:55:14 +01:00
Levente Polyak
e0ab20d05c fix(build): use correct variable to reference available architectures
The referenced places were missing in a previous refactoring commit and
hence broke the build command in multiple ways.

Fixes 0669315821
2023-10-17 23:23:36 +02:00
Antonio Rojas
5cbe9ad612 fix(build): allow using --install and --offload simultaneously
Don't take the full (local) path of the package to install when using
--offload.

Fixes #194
Component: pkgctl build
2023-10-14 00:00:52 +02:00
Christian Heusel
6f106e7cd6 chore: refactor loop variable name
Component: pkgctl build
Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-10-02 11:37:06 +02:00
Christian Heusel
0669315821 chore: refactor variable names in valid-{tags,repos}.sh
Even though the variables in these files are globablly used they have a weirdly local sounding name.
This commit fixes this by refactoring all usages throughout our codebase.

Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-10-02 11:29:03 +02:00
Levente Polyak
a6d43aca01 chore(release): streamline release make target with git-cliff and glab
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-27 01:12:53 +02:00
Levente Polyak
02bc8bfbc0 chore(release): version v1.0.4 2023-09-27 00:38:17 +02:00
Levente Polyak
f632659563 fix(clone): ssh connection may require user input (key unlocking etc)
Anything that requires user input (such as a key unlock or hostkey
verify) will block the terminal and wait for input which will never
come.

When cloning or configuring a repo via ssh we therefore initially
connect to gitlab to warm the connection.

Afterwards users are expected to either have setup a ssh ControlMaster
or use something like a ssh agent.

Fixes #148

Component: pkgctl repo clone/configure

Co-Authored-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-26 22:44:58 +02:00
Christian Heusel
7e41adf00b chore: add a config file for git cliff
This is done so that the generated changelog carries more information
(i.e. the scope of the change).

Co-Authored-by: Levente Polyak <anthraxx@archlinux.org>
Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-26 21:13:08 +02:00
Levente Polyak
a316b50f88 fix(makepkg.conf): use breezy for the bzr protocol in makepkg.conf
Pacman does not resolve provides for the protocol packages, hence we
need to switch to the new package name for bzr.

Related-to: https://gitlab.archlinux.org/pacman/pacman/-/merge_requests/78
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-19 01:32:22 +02:00
Levente Polyak
547961681a fix(pkgctl): avoid pacman db dependency checks during repo detection
By default the sync operation enables dependency checks during the
preparation of the transaction. This isn't necessary for the print
option, but is done nevertheless, which leads to issues for example
during soname dependency problems. The result is a none functional
automatic repo detection.

Fix this by explicitly disabling dependency version checks. We specify
this option twice to skip all dependency checks.

Fixes #189

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-10 00:03:42 +02:00
Jelle van der Waa
8190a22480 feat(release): always generate a .SRCINFO file on release
When releasing a package always generate a .SRCINFO file so we can build
tooling based upon these files instead of having to parse bash in a
non-bash language.

Some tests have shown around 30 seconds or generating the metadata on
packages like thunderbird. The implementation in makepkg becomes semi
slow for some split packages that provide a huge number of individual
packages, but it seems reasonably fast so we can instead have a uniform
state of always providing .SRCINFO files.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-09-04 23:41:00 +02:00
Christian Heusel
f31ea3a48e fix(build): fix repo detection for special chars in package name
Currently we used grep -E, in a way that special characters in the
package name such as the '+' in 'ls++' also became part of the regex.

This commit switches this to become a literal string matching using awk.

Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-08-27 17:08:23 +02:00
Christian Heusel
9f7808c26e fix(build): installing packages into the chroot fails for relative links
As the relative links are relative to the pkgctl invocations PWD and not
necessarily relative to the location where makechrootpkg is invoked from
this fails unexpectedly.

This commit fixes this by just using the full path when passing the
location to makechrootpkg.

Fixes https://gitlab.archlinux.org/archlinux/devtools/-/issues/181

Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-08-27 16:55:50 +02:00
Jan Alexander Steffens (heftig)
5f4fd52e38 feat(arch-nspawn): Use a unique scope name instead of --keep-unit
`--keep-unit` is really only for use in services like
`systemd-nspawn@.service`.

The parameter was added in commit 000ea6c7bb because
systemd-nspawn defaults the name of the machine (and thus the generated
scope) to the name of the working directory, which is not unique. Thus
spawning a container from `archbuild/extra-x86_64/foo` while
`archbuild/testing-x86_64/foo` is already running would fail.

We can avoid the unit conflict by giving the container a unique machine
name. Creating a scope also allows us to place the container in a slice
hierarchy for resource control.
2023-07-21 19:41:22 +02:00
Jan Alexander Steffens (heftig)
1b25190176 chore(arch-nspawn): Simplify args construction for systemd-nspawn 2023-07-21 19:41:22 +02:00
Christian Heusel
030e6af880 chore: fix spelling mistake packge -> package
it seems like the mistake was copied to a few locations, this commit
fixes it.

Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-07-06 15:30:49 +02:00
Levente Polyak
662d6c5274 fix(make): use correct version variable for release target 2023-07-05 18:45:54 +02:00
Levente Polyak
3de03e8b1f chore(release): version v1.0.3 2023-07-05 18:36:07 +02:00
Christian Heusel
720b7c9b05 chore(build): skip invalid architectures on autodetection
This is done so that pkgctl can be better used to build aur packages
which can have arch=(...) settings for which we do not have a clean
chroot builder.

Signed-off-by: Christian Heusel <christian@heusel.eu>
2023-07-05 18:17:32 +02:00
Christian Heusel
0ea7e9e0e5 chore(doc): fix spelling typo in pkgrel detection
Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-06-18 01:01:11 +02:00
Christian Heusel
be5f54c95c fix(commitpkg): ensure the PKGBUILD is version controlled
Early exit in case the PKGBUILD is not yet properly under version
control, which can happen for freshly initialized repositories.
Furthermore print an appropriate error message including a hint how to
resolve this.

Fixes #154
Fixes #167

Signed-off-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-06-17 23:02:36 +02:00
Levente Polyak
5c6e13a672 chore(doc): add missing dependency on fakeroot
We need fakeroot to trick pacman into updating a fresh pacman database
for an unprivileged user.
2023-06-08 00:31:35 +02:00
Levente Polyak
a07df0beea chore(release): version v1.0.2 2023-05-28 01:22:09 +02:00
Levente Polyak
c7d627165f chore(release): adjust Makefile for new release schema
Ask for the next release version and automatically create a signed tag.
Furthermore add a simple release target to call glab for uploading the
required artifacts.
2023-05-28 01:21:40 +02:00
Antonio Rojas
e47035e74d chore(build): improve error wording if no package repo could be detected
Not being in any official repo does not necessarily mean this is a new
package. One could simply be building an AUR or custom local package.
Make the message less confusing in such case.
2023-05-27 22:18:04 +02:00
Daniel M. Capella
9b11b16a7e chore(doc): remove duplicate subcommand from example help text 2023-05-27 21:44:09 +02:00
Levente Polyak
3283b2ca59 fix(commitpkg): only force existing files to be under version control
Before porting commitpkg to Git, the code has checked the SVN status for
none commited files. During the port this has changed by straight
checking for any passed files if they were under version control or not.

In general the whole logic is very brittle as variables are searched by
regex and directly passed to eval while ignoring any function scoping.
This leads to missing files when they reference the $pkgname inside a
package function but also provide wrong ones when eval simply returns
the first $pkgname while ignoring and function scopes.

In the future this should completely be replaces by .SRCINFO processing.

Fixes #145

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-27 01:53:45 +02:00
Toolybird
71cb9e97bb fix(archroot): preserve original args for check_root before discarding
arch-nspawn, mkarchroot, makerepropkg all call "shift" after getopts
processing. Save the original args and pass on to check_root to prevent
options being discarded.

Fixes 41d4624879
Fixes #149

Signed-off-by: Toolybird <toolybird@tuta.io>
Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-26 01:06:14 +02:00
Levente Polyak
1b808b8e32 chore(release): version v1.0.1 2023-05-24 03:19:26 +02:00
Chih-Hsuan Yen
e4c40a9802 fix(completion): incorporate repo layout into offload-build completion
Use new repo names for build targets. This follows /usr/bin/*-build
links other than x86_64_v3 ones.
2023-05-24 03:06:03 +02:00
Levente Polyak
a08bc2acf4 feature(clone): add protocol option to force cloning over HTTPS
This is a rather quick and simple implementation to override the current
logic and force clone with HTTPS. Allowing to explicitly clone over HTTPS
is currently required to unblock reproducible builds where no ssh keys
and GitLab user accounts are set up as of now. Hence this quick solution
comes into play to mitigate the regression on reproducible builds
builders.

Revisit the overall auto detection and protocol logic approach for a
later release related to some ideas floating around in pending
merge-requests.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-24 02:50:08 +02:00
Morten Linderud
f11cb9018e feature(commitpkg): auto generate .SRCINFO if present
This currently makes .SRCINFO files opt-in and helps to keep the file up
to date if already present.

Signed-off-by: Morten Linderud <foxboron@archlinux.org>
2023-05-23 03:03:39 +02:00
Jan Alexander Steffens (heftig)
d759eadb50 fix(diffpkg): Fix scoping of DIFFOPTIONS when comparing split pkgs
`diff_pkgs` needs to use a local variable for its options, otherwise
they will accumulate for each package diffed.

Whem comparing split packages this lead to earlier mutated DIFFOPTIONS
containing too many labels which resulted in a failure.
2023-05-23 02:20:03 +02:00
Jan Alexander Steffens (heftig)
1c399778f9 fix(commitpkg): reliably check tree status regardless of configuration
Check git status --porcelain, not --short.

`--short` is influenced by user configuration like `status.branch`
making it non-empty even on a clean tree. Use `--porcelain` to avoid
this.
2023-05-23 01:47:00 +02:00
Levente Polyak
edc14ef19c Version 1.0.0 2023-05-21 12:25:44 +02:00
Levente Polyak
6ce666a166 feature(parallel): run up to N jobs in parallel for repo clone/configure
Run up to N jobs in parallel. By default the number of jobs is equal to the
number of available processing units. For sequential processing this option
needs to be passed with 1.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-20 16:12:45 +02:00
Levente Polyak
bf61b8472a chore(archroot): force build chroot recreation to adapt new configs
Bumping the chroot version will result in the chroots checking against
the local version and force recreation in case they do not match.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-20 15:11:16 +02:00
Levente Polyak
80a8cdcba2 chore(git): use default ssh port 22 url scheme
We only need to specifically use ssh:// protocol prefix if we want to
specify a special port. As we moved to support pulling directly over
port 22 from out GitLab instance we can change the url scheme to the
simple variant.

Signed-off-by: Levente Polyak <anthraxx@archlinux.org>
2023-05-20 12:20:36 +02:00
75 changed files with 3006 additions and 247 deletions

View File

@@ -1,6 +1,6 @@
SHELL=/bin/bash
V=20230307
V=1.1.0
BUILDTOOLVER ?= $(V)
PREFIX = /usr/local
@@ -16,6 +16,7 @@ LIBRARY_SRC = $(call rwildcard,src/lib,*.sh)
LIBRARY = $(addprefix $(BUILDDIR)/,$(patsubst src/%,%,$(patsubst %.in,%,$(LIBRARY_SRC))))
MAKEPKG_CONFIGS=$(wildcard config/makepkg/*)
PACMAN_CONFIGS=$(wildcard config/pacman/*)
GIT_CONFIGS = $(wildcard config/git/*)
SETARCH_ALIASES = $(wildcard config/setarch-aliases.d/*)
MANS = $(addprefix $(BUILDDIR)/,$(patsubst %.asciidoc,%,$(wildcard doc/man/*.asciidoc)))
@@ -97,9 +98,12 @@ $(BUILDDIR)/doc/man/%: doc/man/%.asciidoc doc/asciidoc.conf doc/man/include/foot
@a2x --no-xmllint --asciidoc-opts="-f doc/asciidoc.conf" -d manpage -f manpage --destination-dir=$(BUILDDIR)/doc/man -a pkgdatadir=$(DATADIR) $<
conf:
@install -d $(BUILDDIR)/makepkg.conf.d $(BUILDDIR)/pacman.conf.d
@install -d $(BUILDDIR)/makepkg.conf.d
@cp -a $(MAKEPKG_CONFIGS) $(BUILDDIR)/makepkg.conf.d
@install -d $(BUILDDIR)/pacman.conf.d
@cp -a $(PACMAN_CONFIGS) $(BUILDDIR)/pacman.conf.d
@install -d $(BUILDDIR)/git.conf.d
@cp -a $(GIT_CONFIGS) $(BUILDDIR)/git.conf.d
clean:
rm -rf $(BUILDDIR)
@@ -112,6 +116,7 @@ install: all
install -m0755 ${BINPROGS} $(DESTDIR)$(PREFIX)/bin
install -dm0755 $(DESTDIR)$(DATADIR)/lib
cp -ra $(BUILDDIR)/lib/* $(DESTDIR)$(DATADIR)/lib
cp -a $(BUILDDIR)/git.conf.d -t $(DESTDIR)$(DATADIR)
for conf in $(notdir $(MAKEPKG_CONFIGS)); do install -Dm0644 $(BUILDDIR)/makepkg.conf.d/$$conf $(DESTDIR)$(DATADIR)/makepkg.conf.d/$${conf##*/}; done
for conf in $(notdir $(PACMAN_CONFIGS)); do install -Dm0644 $(BUILDDIR)/pacman.conf.d/$$conf $(DESTDIR)$(DATADIR)/pacman.conf.d/$${conf##*/}; done
for a in ${SETARCH_ALIASES}; do install -m0644 $$a -t $(DESTDIR)$(DATADIR)/setarch-aliases.d; done
@@ -129,6 +134,7 @@ uninstall:
for f in $(notdir $(BINPROGS)); do rm -f $(DESTDIR)$(PREFIX)/bin/$$f; done
for f in $(notdir $(LIBRARY)); do rm -f $(DESTDIR)$(DATADIR)/lib/$$f; done
rm -rf $(DESTDIR)$(DATADIR)/lib
rm -rf $(DESTDIR)$(DATADIR)/git.conf.d
for conf in $(notdir $(MAKEPKG_CONFIGS)); do rm -f $(DESTDIR)$(DATADIR)/makepkg.conf.d/$${conf##*/}; done
for conf in $(notdir $(PACMAN_CONFIGS)); do rm -f $(DESTDIR)$(DATADIR)/pacman.conf.d/$${conf##*/}; done
for f in $(notdir $(SETARCH_ALIASES)); do rm -f $(DESTDIR)$(DATADIR)/setarch-aliases.d/$$f; done
@@ -145,19 +151,23 @@ uninstall:
$(DESTDIR)$(DATADIR)/pacman.conf.d \
$(DESTDIR)$(DATADIR)
TODAY=$(shell date +"%Y%m%d")
tag:
@sed -E "s|^V=[0-9]{8}|V=$(TODAY)|" -i Makefile
@git commit --gpg-sign --message "Version $(TODAY)" Makefile
@git tag --sign --message "Version $(TODAY)" $(TODAY)
git cliff --strip=all --unreleased
@echo "current version: v$(V)"
@read -r -p "tag version: v" VERSION && \
sed -E "s|^V=.+|V=$$VERSION|" -i Makefile && \
git commit --gpg-sign --message "chore(release): version v$$VERSION" Makefile && \
git tag --sign --message "Version v$$VERSION" v$$VERSION
release: dist
git push --tags origin master
git cliff --version >/dev/null
GITLAB_HOST=gitlab.archlinux.org glab release create v$(V) devtools-$(V).tar.gz* --milestone v$(V) --notes-file <(git cliff --strip=all --latest)
dist:
git archive --format=tar --prefix=devtools-$(V)/ $(V) | gzip > devtools-$(V).tar.gz
git archive --format=tar --prefix=devtools-$(V)/ v$(V) | gzip > devtools-$(V).tar.gz
gpg --detach-sign --use-agent devtools-$(V).tar.gz
upload:
scp devtools-$(V).tar.gz devtools-$(V).tar.gz.sig repos.archlinux.org:/srv/ftp/other/devtools/
check: $(BINPROGS_SRC) $(LIBRARY_SRC) contrib/completion/bash/devtools.in config/makepkg/x86_64.conf contrib/makepkg/PKGBUILD.proto
shellcheck $^

View File

@@ -23,6 +23,34 @@ will automatically build the project and proxy all calls to the local build dire
./test/bin/pkgctl --help
```
### Commit messages
All commits must follow [conventional commits](https://www.conventionalcommits.org).
The following groups are allowed:
- chore
- feat
- fix
- doc
- perf
- test
To override the scope for the changelog entry use the `Component:` trailer.
Example:
```
feat(db): yay mega cool feature
Very long and useful description.
Fixes #1
Fixes #2
Component: pkgctl db remove
```
## Releasing
1. bump the version in the Makefile
@@ -42,6 +70,7 @@ will automatically build the project and proxy all calls to the local build dire
- binutils
- coreutils
- diffutils
- fakeroot
- findutils
- grep
- jq
@@ -57,6 +86,11 @@ will automatically build the project and proxy all calls to the local build dire
- mercurial
- subversion
### Optional Dependencies
- bat (pretty printing)
- nvchecker (version checking)
### Development Dependencies
- asciidoc

45
cliff.toml Normal file
View File

@@ -0,0 +1,45 @@
[changelog]
header = "# Changelog\n\n"
body = """
{%- if version -%}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{%- else -%}
## [unreleased]
{%- endif %}
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits | sort(attribute="message") %}
- {% set component = commit.footers | filter(attribute="token", value="Component") | map(attribute="value") | join(sep=", ") %}
{%- if component %}{{ component }}: {% elif commit.scope %}{{ commit.scope }}: {% endif %}
{{- commit.message | upper_first }}
{%- if commit.breaking %} (breaking){% endif %}
{%- set fixes = commit.footers | filter(attribute="token", value="Fixes") %}
{%- for fix in fixes %}{% if fix.separator|trim == '#' %}{{ fix.separator }}{{ fix.value }}{% endif %}{% endfor %}
{%- endfor %}
{% endfor %}
"""
footer = ""
# remove the leading and trailing whitespaces from the template
trim = true
[git]
# allow only conventional commits
# https://www.conventionalcommits.org
conventional_commits = true
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^chore\\(release\\): version", skip = true},
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^doc", group = "Documentation"},
{ message = "^perf", group = "Performance"},
{ message = "^test", group = "Testing"},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ body = ".*security", group = "Security"},
]
# filter out the commits that are not matched by commit parsers
filter_commits = false
# regex for matching git tags
tag_pattern = "^v[0-9]+\\.[0-9]+\\.[0-9]+.*"

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1 @@
#!/bin/sh

View File

@@ -0,0 +1,28 @@
/pkg
/src
/*/
!/keys/
/*.log
/*.tar.*
/*.tar
/*.tgz
/*.zst
/*.gz
/*.xz
/*.bz2
/*.zip
/*.xpi
/*.jar
/*.whl
/*.war
/*.deb
/*.ttf
/*.dat
/*.iso
/*.asc
/*.sig
/*.signature
/*.sign
/*.SHA256SUMS
/*.sha256

View File

@@ -25,7 +25,7 @@ DLAGENTS=('file::/usr/bin/curl -qgC - -o %o %u'
#-- The package required by makepkg to download VCS sources
# Format: 'protocol::package'
VCSCLIENTS=('bzr::bzr'
VCSCLIENTS=('bzr::breezy'
'fossil::fossil'
'git::git'
'hg::mercurial'
@@ -44,7 +44,8 @@ CFLAGS="-march=x86-64 -mtune=generic -O2 -pipe -fno-plt -fexceptions \
-Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security \
-fstack-clash-protection -fcf-protection"
CXXFLAGS="$CFLAGS -Wp,-D_GLIBCXX_ASSERTIONS"
LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
LDFLAGS="-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now \
-Wl,-z,pack-relative-relocs"
LTOFLAGS="-flto=auto"
RUSTFLAGS=""
#-- Make Flags: change this for DistCC/SMP systems

View File

@@ -25,7 +25,7 @@ DLAGENTS=('file::/usr/bin/curl -qgC - -o %o %u'
#-- The package required by makepkg to download VCS sources
# Format: 'protocol::package'
VCSCLIENTS=('bzr::bzr'
VCSCLIENTS=('bzr::breezy'
'fossil::fossil'
'git::git'
'hg::mercurial'
@@ -44,7 +44,8 @@ CFLAGS="-march=x86-64-v3 -mtune=generic -O2 -pipe -fno-plt -fexceptions \
-Wp,-D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security \
-fstack-clash-protection -fcf-protection"
CXXFLAGS="$CFLAGS -Wp,-D_GLIBCXX_ASSERTIONS"
LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"
LDFLAGS="-Wl,-O1 -Wl,--sort-common -Wl,--as-needed -Wl,-z,relro -Wl,-z,now \
-Wl,-z,pack-relative-relocs"
LTOFLAGS="-flto=auto"
RUSTFLAGS=""
#-- Make Flags: change this for DistCC/SMP systems

View File

@@ -3,12 +3,18 @@
# SPDX-License-Identifier: GPL-3.0-or-later
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/valid-build-install.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-build-install.sh
# shellcheck source=src/lib/valid-tags.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
# shellcheck source=src/lib/valid-repos.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
# shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh
# shellcheck source=src/lib/valid-search.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh
_binary_arch=${_arch[*]:0:-1}
_binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1}
_colors=(never always auto)
@@ -24,6 +30,7 @@ _makechrootpkg_args=(
-n
-T
-U
-x
)
_makechrootpkg_args_d_opts() { _filedir -d; }
_makechrootpkg_args_D_opts() { _filedir -d; }
@@ -31,6 +38,7 @@ _makechrootpkg_args_r_opts() { _filedir -d; }
_makechrootpkg_args_I_opts() { _filedir '*.pkg.tar.*'; }
_makechrootpkg_args_l_opts() { _filedir -d; }
_makechrootpkg_args_U_opts() { :; }
_makechrootpkg_args_x_opts() { _devtools_completions_inspect; }
_makechrootpkg() { __devtools_complete _makechrootpkg; }
complete -F _makechrootpkg makechrootpkg
@@ -38,6 +46,7 @@ complete -F _makechrootpkg makechrootpkg
_makerepropkg_args=(
-h
-d
-n
-c
-M
)
@@ -128,12 +137,14 @@ complete -F _offload_build offload-build
_pkgctl_cmds=(
aur
auth
build
db
diff
release
repo
search
version
)
_pkgctl_args=(
@@ -169,10 +180,14 @@ _pkgctl_build_args=(
-o --offload
-c --clean
-w --worker
--inspect
-I --install-to-chroot
-i --install-to-host
--pkgver
--pkgrel
--rebuild
--update-checksums
-e --edit
-r --release
@@ -185,11 +200,19 @@ _pkgctl_build_args__arch_opts() { _devtools_completions_arch; }
_pkgctl_build_args__repo_opts() { _devtools_completions_repo; }
_pkgctl_build_args__worker_opts() { :; }
_pkgctl_build_args_w_opts() { _pkgctl_build_args__worker_opts; }
_pkgctl_build_args__inspect_opts() { _devtools_completions_inspect; }
_pkgctl_build_args__pkgver_opts() { :; }
_pkgctl_build_args__pkgrel_opts() { :; }
_pkgctl_build_args__install_to_host_opts() { _pkgctl_build_completions_install_mode; }
_pkgctl_build_args_i_opts() { _pkgctl_build_args__install_to_host_opts; }
_pkgctl_build_args__install_to_chroot_opts() { _makechrootpkg_args_I_opts; }
_pkgctl_build_args_I_opts() { _pkgctl_build_args__install_to_chroot_opts; }
_pkgctl_build_args__message_opts() { :; }
_pkgctl_build_args_m_opts() { _pkgctl_build_args__message_opts; }
_pkgctl_build_opts() { _filedir -d; }
_pkgctl_build_completions_install_mode() {
mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_BUILD_INSTALL[*]}" -- "$cur")
}
_pkgctl_db_cmds=(
@@ -253,6 +276,17 @@ _pkgctl_release_args__repo_opts() { _devtools_completions_repo; }
_pkgctl_release_args_r_opts() { _pkgctl_release_args__repo_opts; }
_pkgctl_release_opts() { _filedir -d; }
_pkgctl_aur_cmds=(
drop-from-repo
)
_pkgctl_aur_drop_from_repo_args=(
--no-disown
-f --force
-h --help
)
_pkgctl_aur_drop_from_repo_opts() { _filedir -d; }
_pkgctl_repo_cmds=(
clone
@@ -265,20 +299,30 @@ _pkgctl_repo_cmds=(
_pkgctl_repo_clone_args=(
-m --maintainer
--protocol
--switch
-u --unprivileged
--universe
-j --jobs
-h --help
)
_pkgctl_repo_clone_args__maintainer_opts() { :; }
_pkgctl_repo_clone_args_m_opts() { _pkgctl_repo_clone_args__maintainer_opts; }
_pkgctl_repo_clone_args__protocol_opts() { _devtools_completions_protocol; }
_pkgctl_repo_clone_args__switch_opts() { :; }
_pkgctl_repo_clone_args__jobs_opts() { :; }
_pkgctl_repo_clone_args_j_opts() { _pkgctl_repo_clone_args__jobs_opts; }
_pkgctl_repo_clone_opts() { _devtools_completions_all_packages; }
_pkgctl_repo_configure_args=(
--protocol
-j --jobs
-h --help
)
_pkgctl_repo_configure_args__protocol_opts() { _devtools_completions_protocol; }
_pkgctl_repo_configure_args__jobs_opts() { :; }
_pkgctl_repo_configure_args_j_opts() { _pkgctl_repo_clone_args__jobs_opts; }
_pkgctl_repo_configure_opts() { _filedir -d; }
@@ -287,7 +331,6 @@ _pkgctl_repo_create_args=(
-h --help
)
_pkgctl_repo_switch_args=(
--discard-changes
-f --force
@@ -305,13 +348,44 @@ _pkgctl_repo_switch_opts() {
fi
}
_pkgctl_version_cmds=(
check
upgrade
)
_pkgctl_version_check_args=(
-v --verbose
-h --help
)
_pkgctl_version_check_opts() { _filedir -d; }
_pkgctl_version_upgrade_args=(
-v --verbose
-h --help
)
_pkgctl_version_upgrade_opts() { _filedir -d; }
_pkgctl_repo_web_args=(
--print
-h --help
)
_pkgctl_repo_web_opts() { _filedir -d; }
_pkgctl_search_args=(
--no-default-filter
--json
-F --format
-N --no-line-number
-h --help
)
_pkgctl_search_opts() { :; }
_pkgctl_search_args__format_opts() { _devtools_completions_search_format; }
_pkgctl_search_args_F_opts() { _devtools_completions_search_format; }
_pkgctl_diff_args=(
-l --list
-d --diffoscope
@@ -345,18 +419,27 @@ _devtools_completions_color() {
mapfile -t COMPREPLY < <(compgen -W "${_colors[*]}" -- "$cur")
}
_devtools_completions_arch() {
mapfile -t COMPREPLY < <(compgen -W "${_arch[*]}" -- "$cur")
mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_ARCHES[*]}" -- "$cur")
}
_devtools_completions_repo() {
local optional=${1:-}
mapfile -t COMPREPLY < <(compgen -W "${optional} ${_repos[*]}" -- "$cur")
mapfile -t COMPREPLY < <(compgen -W "${optional} ${DEVTOOLS_VALID_REPOS[*]}" -- "$cur")
}
_devtools_completions_build_repo() {
mapfile -t COMPREPLY < <(compgen -W "${_build_repos[*]}" -- "$cur")
mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_BUILDREPOS[*]}" -- "$cur")
}
_devtools_completions_all_packages() {
mapfile -t COMPREPLY < <(compgen -W "$(pacman -Sql)" -- "$cur")
}
_devtools_completions_protocol() {
mapfile -t COMPREPLY < <(compgen -W "https" -- "$cur")
}
_devtools_completions_inspect() {
mapfile -t COMPREPLY < <(compgen -W "${DEVTOOLS_VALID_INSPECT_MODES[*]}" -- "$cur")
}
_devtools_completions_search_format() {
mapfile -t COMPREPLY < <(compgen -W "${valid_search_output_format[*]}" -- "$cur")
}
__devtools_complete() {
local service=$1

View File

@@ -3,12 +3,18 @@
# SPDX-License-Identifier: GPL-3.0-or-later
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/valid-build-install.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-build-install.sh
# shellcheck source=src/lib/valid-tags.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
# shellcheck source=src/lib/valid-repos.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
# shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh
# shellcheck source=src/lib/valid-search.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh
_binary_arch=${_arch[*]:0:-1}
_binary_arch=${DEVTOOLS_VALID_ARCHES[*]:0:-1}
_colors=(never always auto)
_archbuild_args=(
@@ -36,17 +42,20 @@ _pkgctl_auth_status_args=(
_pkgctl_build_args=(
"--arch=[Specify architectures to build for (disables auto-detection)]:arch:($_arch[*])"
"--repo=[Specify a target repository (disables auto-detection)]:repo:($_repos[*])"
"--repo=[Specify a target repository (disables auto-detection)]:repo:($DEVTOOLS_VALID_REPOS[*])"
'(-s --staging)'{-s,--staging}'[Build against the staging counterpart of the auto-detected repo]'
'(-t --testing)'{-t,--testing}'[Build against the testing counterpart of the auto-detected repo]'
'(-o --offload)'{-o,--offload}'[Build on a remote server and transfer artifacts afterwards]'
'(-c --clean)'{-c,--clean}'[Recreate the chroot before building]'
'(-I --install)'{-I,--install}'[Install a package into the working copy of the chroot]:target:_files -g "*.pkg.tar.*(.)"'
"--inspect[Spawn an interactive shell to inspect the chroot (never, always, failure)]:inspect:($DEVTOOLS_VALID_INSPECT_MODES[*])"
'(-I --install-to-chroot)'{-I,--install-to-chroot}'[Install a package to the working copy of the chroot]:target:_files -g "*.pkg.tar.*(.)"'
'(-i --install-to-host)'{-i,--install-to-host}"[Install the built packages to the host system]:mode:($DEVTOOLS_VALID_BUILD_INSTALL[*])"
'(-w --worker)'{-w,--worker}'[Name of the worker slot, useful for concurrent builds (disables auto-detection)]:slot:'
'--nocheck[Do not run the check() function in the PKGBUILD]'
'--pkgver=[Set pkgver, reset pkgrel and update checksums]:pkgver:'
'--pkgrel=[Set pkgrel to a given value]:pkgrel:'
'--rebuild[Increment the pkgrel variable]'
'--update-checksums[Force computation and update of the checksums (disables auto-detection)]'
'(-e --edit)'{-e,--edit}'[Edit the PKGBUILD before building]'
'(-r --release)'{-r,--release}'[Automatically commit, tag and release after building]'
'(-m --message=)'{-m,--message=}"[Use the given <msg> as the commit message]:message:"
@@ -64,15 +73,15 @@ _pkgctl_db_cmds=(
_pkgctl_db_move_args=(
'(-h --help)'{-h,--help}'[Display usage]'
"1:src-repo:($_repos[*])"
"2:target-repo:($_repos[*])"
"1:src-repo:($DEVTOOLS_VALID_REPOS[*])"
"2:target-repo:($DEVTOOLS_VALID_REPOS[*])"
'*:pkgbase:_devtools_completions_all_packages'
)
_pkgctl_db_remove_args=(
'(-a --arch=)'{-a,--arch=}"[Override the architecture (disables auto-detection)]:arch:($_arch[*])"
'(-h --help)'{-h,--help}'[Display usage]'
"1:repo:($_repos[*])"
"1:repo:($DEVTOOLS_VALID_REPOS[*])"
'*:pkgbase:_devtools_completions_all_packages'
)
@@ -82,7 +91,7 @@ _pkgctl_db_update_args=(
_pkgctl_release_args=(
'(-m --message=)'{-m,--message=}"[Use the given <msg> as the commit message]:message:"
'(-r --repo=)'{-r,--repo=}"[Specify a target repository (disables auto-detection)]:repo:($_repos[*])"
'(-r --repo=)'{-r,--repo=}"[Specify a target repository for new packages]:repo:($DEVTOOLS_VALID_REPOS[*])"
'(-s --staging)'{-s,--staging}'[Release to the staging counterpart of the auto-detected repo]'
'(-t --testing)'{-t,--testing}'[Release to the testing counterpart of the auto-detected repo]'
'(-u --db-update)'{-u,--db-update}'[Automatically update the pacman database after uploading]'
@@ -90,6 +99,18 @@ _pkgctl_release_args=(
'*:git_dir:_files -/'
)
_pkgctl_aur_cmds=(
"pkgctl aur command"
"drop-from-repo[Drop a package from the official repository to the AUR]"
)
_pkgctl_aur_drop_from_repo_args=(
'(-f --force)'{-f,--force}'[Force push to the AUR overwriting the remote repository]'
'--no-disown[Do not disown the package on the AUR]'
'(-h --help)'{-h,--help}'[Display usage]'
'*:git_dir:_files -/'
)
_pkgctl_repo_cmds=(
"pkgctl repo command"
"clone[Clone a package repository]"
@@ -108,13 +129,17 @@ _pkgctl_repo_switch_args=(
_pkgctl_repo_clone_args=(
'(-m --maintainer=)'{-m,--maintainer=}'[Clone all packages of the named maintainer]:maintainer:'
'--protocol[Clone the repository over https]:proto:(https)'
'--switch=[Switch the current working tree to a specified version]'
'--universe[Clone all existing packages, useful for cache warming]'
'(-j --jobs)'{-j,--jobs}'[Run up to N jobs in parallel (default: number of processing units)]:jobs:'
'(-h --help)'{-h,--help}'[Display usage]'
'*:packages:_devtools_completions_all_packages'
)
_pkgctl_repo_configure_args=(
'--protocol[Configure remote url to use https]:proto:(https)'
'(-j --jobs)'{-j,--jobs}'[Run up to N jobs in parallel (default: number of processing units)]:jobs:'
'(-h --help)'{-h,--help}'[Display usage]'
'*:git_dir:_files -/'
)
@@ -126,10 +151,20 @@ _pkgctl_repo_create_args=(
)
_pkgctl_repo_web_args=(
'--print[Print the url instead of opening it with xdg-open]'
'(-h --help)'{-h,--help}'[Display usage]'
'*:git_dir:_files -/'
)
_pkgctl_search_args=(
'--no-default-filter[Do not apply default filter (like -path:keys/pgp/*.asc)]'
'--json[Enable printing results in JSON]'
'(-F --format)'{-F,--format}"[Controls the formatting of the results]:format:($valid_search_output_format[*])"
'(-N --no-line-number)'{-N,--no-line-number}"[Don't show line numbers when formatting results]"
'(-h --help)'{-h,--help}'[Display usage]'
'1:query'
)
_arch_nspawn_args=(
'-C[Location of a pacman config file]:pacman_config:_files -g "*.conf(.)"'
'-M[Location of a makepkg config file]:makepkg_config:_files -g "*.conf(.)"'
@@ -142,14 +177,14 @@ _arch_nspawn_args=(
_archrelease_args=(
'-f[Force release without checks]'
"*:arch:($_tags[*])"
"*:arch:($DEVTOOLS_VALID_TAGS[*])"
)
_commitpkg_args=(
'-f[Force release without checks]'
'-s[Target repo server]'
'-l[Set bandwidth limit]:limit'
"-a[Release to a specific architecture only]:arch:($_arch[*])"
"-a[Release to a specific architecture only]:arch:($DEVTOOLS_VALID_ARCHES[*])"
'1:commit_msg'
)
@@ -185,6 +220,7 @@ _makechrootpkg_args=(
'-n[Run namcap on the package]'
'-T[Build in a temporary directory]'
'-U[Run makepkg as a specified user]:makepkg_user'
"-x[Spawn an interactive shell to inspect the chroot (never, always, failure)]:inspect:($DEVTOOLS_VALID_INSPECT_MODES[*])"
)
_mkarchroot_args=(
@@ -208,12 +244,12 @@ _sogrep_args=(
'(-v --verbose)'{-v,--verbose}'[Show matched links in addition to pkgname]'
'(-r --refresh)'{-r,--refresh}'[Refresh the links databases]'
'(-h --help)'{-h,--help}'[Display usage]'
'1:repo:(all $_repos[*])'
'1:repo:(all $DEVTOOLS_VALID_REPOS[*])'
'2:libname'
)
_offload_build_args=(
'(-r --repo)'{-r,--repo}'[Build against a specific repository]:repo:($_build_repos[*])'
'(-r --repo)'{-r,--repo}'[Build against a specific repository]:repo:($DEVTOOLS_VALID_BUILDREPOS[*])'
'(-a --arch)'{-a,--arch}'[Build against a specific architecture]:arch:(${_binary_arch[*]})'
'(-s --server)'{-s,--server}'[Offload to a specific Build server]:server:'
'(-h --help)'{-h,--help}'[Display usage]'
@@ -221,6 +257,7 @@ _offload_build_args=(
_makerepropkg_args=(
'-d[Run diffoscope if the package is unreproducible]'
'-n[Do not run the check() function in the PKGBUILD]'
'-c[Set pacman cache]:pacman_cache:_files -/'
'-M[Location of a makepkg config file]:makepkg_config:_files -g "*.conf(.)"'
'-h[Display usage]'
@@ -235,13 +272,15 @@ _devtools_completions_all_packages() {
_pkgctl_cmds=(
"pkgctl command"
"aur[Interact with the Arch User Repository (AUR)]"
"auth[Authenticate with services like GitLab]"
"build[Build packages inside a clean chroot]"
"db[Pacman database modification for packge update, move etc]"
"db[Pacman database modification for package update, move etc]"
"diff[Compare package files using different modes]"
"release[Release step to commit, tag and upload build artifacts]"
"repo[Manage Git packaging repositories and their configuration]"
"version[Show pkgctl version information]"
"search[Search for an expression across the GitLab packaging group]"
"version[Check and manage package versions against upstream]"
)
_pkgctl_args=(
@@ -249,8 +288,22 @@ _pkgctl_args=(
'(-h --help)'{-h,--help}'[Display usage]'
)
_pkgctl_version_args=(
_pkgctl_version_cmds=(
"pkgctl version command"
"check[Compares local package versions against upstream versions]"
"upgrade[Adjust the PKGBUILD to match the latest upstream version]"
)
_pkgctl_version_check_args=(
'(-v --verbose)'{-v,--verbose}'[Display results including up-to-date versions]'
'(-h --help)'{-h,--help}'[Display usage]'
'*:git_dir:_files -/'
)
_pkgctl_version_upgrade_args=(
'(-v --verbose)'{-v,--verbose}'[Display results including up-to-date versions]'
'(-h --help)'{-h,--help}'[Display usage]'
'*:git_dir:_files -/'
)
_pkgctl_diff_args=("${_diffpkg_args[@]}")
@@ -272,7 +325,7 @@ _handle_subcommands() {
fi
;;
args)
local service_sub=${service_name}_$line[1]
local service_sub=${service_name}_${line[1]//-/_}
if typeset -p ${service_sub}_args &> /dev/null; then
local cmd_args=${service_sub}_args[@]
_arguments -s "${(P)cmd_args}"

View File

@@ -73,4 +73,8 @@ Options
*-U*::
Run makepkg as a specified user
*-x* <when>::
Inspect chroot after build, possible modes are 'never' (default), 'always' or 'failure'
include::include/footer.asciidoc[]

View File

@@ -42,6 +42,9 @@ Options
*-d*::
If packages are not reproducible, compare them using diffoscope.
*-n*::
Do not run the check() function in the PKGBUILD.
*-c*::
Set the pacman cache directory.

View File

@@ -0,0 +1,41 @@
pkgctl-aur-drop-from-repo(1)
============================
Name
----
pkgctl-aur-drop-from-repo - Drop a package from the official repository to the AUR
Synopsis
--------
pkgctl aur drop-from-repo [OPTIONS] [PATH]...
Description
-----------
Drops a specified package from the official repositories to the Arch User
Repository.
This command requires a local Git clone of the package repository. It
reconfigures the repository for AUR compatibility and pushes it to the
AUR. Afterwards, the package is removed from the official repository.
By default, the package is automatically disowned in the AUR.
Options
-------
*--no-disown*::
Do not disown the package on the AUR
*-f, --force*::
Force push to the AUR overwriting the remote repository
*-h, --help*::
Show a help text
See Also
--------
linkman:pkgctl-db-remove[1]
include::include/footer.asciidoc[]

View File

@@ -0,0 +1,37 @@
pkgctl-aur(1)
=============
Name
----
pkgctl-aur - Interact with the Arch User Repository (AUR)
Synopsis
--------
pkgctl aur [OPTIONS] [SUBCOMMAND]
Description
-----------
Provides a suite of tools designed for managing and interacting with the Arch
User Repository (AUR). It simplifies various tasks related to AUR, including
importing repositories, managing packages, and transitioning packages between
the official repositories and the AUR.
Options
-------
*-h, --help*::
Show a help text
Subcommands
-----------
pkgctl aur drop-from-repo::
Drop a package from the official repository to the AUR
See Also
--------
linkman:pkgctl-aur-drop-from-repo[1]
include::include/footer.asciidoc[]

View File

@@ -21,7 +21,10 @@ Build Options
Specify architectures to build for (disables auto-detection)
*--repo* 'REPO'::
Specify a target repository (disables auto-detection)
Specify target repository for new packages not in any official repo.
Fallback to `'extra'` when building packages that are not present in any
official repository yet. Using this option is disallowed if the package is
already released, as it would circumvent the auto-detection safeguard.
*-s, --staging*::
Build against the staging counterpart of the auto-detected repo
@@ -35,8 +38,9 @@ Build Options
*-c, --clean*::
Recreate the chroot before building
*-I, --install* 'FILE'::
Install a package into the working copy of the chroot
*--inspect* 'WHEN'::
Spawn an interactive shell to inspect the chroot after building. Useful to ease the debugging of a package build. +
Possible values for 'WHEN' are `'never'`, `'always'` or `'failure'`
*-w, --worker* 'SLOT'::
Name of the worker slot, useful for concurrent builds. By default the slot
@@ -47,6 +51,17 @@ Build Options
*--nocheck*::
Do not run the check() function in the PKGBUILD
Install Options
---------------
*-I, --install-to-chroot* 'FILE'::
Install a package to the working copy of the chroot
*-i, --install-to-host* 'MODE'::
Install the built packages to the host system. Useful when one wants to verify that the package works as intended.
* When 'MODE' is 'all', this installs all built packages
* When 'MODE' is 'auto', this installs all built packages which are currently installed
PKGBUILD Options
----------------
@@ -59,6 +74,13 @@ PKGBUILD Options
*--rebuild*::
Increment the current pkgrel variable
*--update-checksums*::
Force computation and update of the checksums by disabling auto-detection. +
Should only be used in special circumstances, like when adding new patch
files to the source array. During regular packaging operations, checksums
are either automatically updated when upgrading a package using `--pkgver`
or should remain immutable during rebuilds.
*-e, --edit*::
Edit the PKGBUILD before building

View File

@@ -3,17 +3,16 @@ pkgctl-db-move(1)
Name
----
pkgctl-db-update - Update the binary repository as final release step
pkgctl-db-move - Move packages between binary repositories.
Synopsis
--------
pkgctl db update [OPTIONS]
pkgctl db move [OPTIONS] [SOURCE_REPO] [TARGET_REPO] [PKGBASE]...
Description
-----------
Update the pacman database as final release step for packages that
have been transfered and staged on 'repos.archlinux.org'.
Move packages between binary repositories i.e. from 'extra-testing' to 'extra'.
Options
-------

View File

@@ -1,18 +1,19 @@
pkgctl-db-move(1)
pkgctl-db-update(1)
=================
Name
----
pkgctl-db-move - Move packages between binary repositories
pkgctl-db-update - Update the binary repository as final release step
Synopsis
--------
pkgctl db move [OPTIONS] [SOURCE_REPO] [TARGET_REPO] [PKGBASE]...
pkgctl db update [OPTIONS]
Description
-----------
Move packages between pacman repositories.
Update the pacman database as final release step for packages that
have been transfered and staged on 'repos.archlinux.org'.
Options
-------

View File

@@ -27,7 +27,9 @@ Options
Use the given <msg> as the commit message
*-r, --repo* 'REPO'::
Specify a target repository (disables auto-detection)
Specify target repository for new packages not in any official repo.
Using this option is disallowed if the package is already released, as it
would circumvent the auto-detection safeguard.
*-s, --staging*::
Build against the staging counterpart of the auto-detected repo

View File

@@ -25,6 +25,9 @@ Options
*-m, --maintainer* 'NAME'::
Clone all packages of the named maintainer
*--protocol* 'https'::
Clone the repository over https
*--universe*::
Clone all existing packages, useful for cache warming
@@ -32,6 +35,11 @@ Options
Switch to a specified version. The working tree and the index are updated to
match the version.
*-j, --jobs* 'N'::
Run up to N jobs in parallel. By default the number of jobs is equal to the
number of available processing units. For sequential processing this option
needs to be passed with 1.
*-h, --help*::
Show a help text

View File

@@ -22,9 +22,19 @@ The remote protocol is automatically determined from the author email
address by choosing SSH for all official packager identities and
read-only HTTPS otherwise.
Git default excludes and hooks are applied to the configured repo.
Options
-------
*--protocol* 'https'::
Configure remote url to use https
*-j, --jobs* 'N'::
Run up to N jobs in parallel. By default the number of jobs is equal to the
number of available processing units. For sequential processing this option
needs to be passed with 1.
*-h, --help*::
Show a help text

View File

@@ -18,6 +18,9 @@ no arguments, open the package cloned in the current working directory.
Options
-------
*--print*::
Print the url instead of opening it with xdg-open
*-h, --help*::
Show a help text

View File

@@ -0,0 +1,71 @@
pkgctl-search(1)
================
Name
----
pkgctl-search - Search for an expression across the GitLab packaging group
Synopsis
--------
pkgctl search [OPTIONS] QUERY
Description
-----------
Search for an expression across the GitLab packaging group.
To use a filter, include it in your query. You may use wildcards (*) to
use glob matching.
Available filters for the blobs scope: path, extension
Every usage of the search command must be authenticated. Consult the
`'pkgctl auth'` command to authenticate with GitLab or view the authentication
status.
Search Tips
-----------
Syntax Description Example
───────────────────────────────────────
" Exact search "gem sidekiq"
~ Fuzzy search J~ Doe
| Or display | banner
+ And display +banner
- Exclude display -banner
* Partial bug error 50*
\ Escape \*md
# Issue ID #23456
! Merge request !23456
Options
-------
*-h, --help*::
Show a help text
Filter Options
--------------
*--no-default-filter*::
Do not apply default filter (like -path:keys/pgp/*.asc)
Output Options
--------------
*--json*::
Enable printing in JSON; Shorthand for `'--format json'`
*-F, --format* 'FORMAT'::
Controls the formatting of the results; `FORMAT` is `'pretty'`, `'plain'`,
or `'json'` (default `pretty`)
*-N, --no-line-number*::
Don't show line numbers when formatting results
See Also
--------
linkman:pkgctl-auth[1]
include::include/footer.asciidoc[]

View File

@@ -0,0 +1,66 @@
pkgctl-version-check(1)
=======================
Name
----
pkgctl-version-check - Compares local package versions against upstream
Synopsis
--------
pkgctl version check [OPTIONS] [PKGBASE...]
Description
-----------
Compares the versions of packages in the local packaging repository against
their latest upstream versions.
Upon execution, it generates a grouped list that provides detailed insights
into each package's status. For each package, it displays the current local
version alongside the latest version available upstream.
Outputs a summary of up-to-date packages, out-of-date packages, and any check
failures.
This simplifies the maintenance of PKGBUILD files, reducing the manual effort
required to track version changes from upstream sources.
Configuration
-------------
Uses linkman:nvchecker[1] and a `.nvchecker.toml` file located alongside the
PKGBUILD. Refer to the configuration section in linkman:pkgctl-version[1].
Options
-------
*-v, --verbose*::
Display results including up-to-date versions
*-h, --help*::
Show a help text
Exit Codes
----------
On exit, return one of the following codes:
*0*::
Normal exit condition, all checked versions are up-to-date
*1*::
Unknown cause of failure
*2*::
Normal exit condition, but there are out-of-date versions
*3*::
Failed to run some version checks
See Also
--------
linkman:pkgctl-version[1]
linkman:nvchecker[1]
include::include/footer.asciidoc[]

View File

@@ -0,0 +1,50 @@
pkgctl-version-upgrade(1)
=========================
Name
----
pkgctl-version-upgrade - Adjust the PKGBUILD to match the latest upstream version
Synopsis
--------
pkgctl version upgrade [OPTIONS] [PKGBASE...]
Description
-----------
Streamlines the process of keeping PKGBUILD files up-to-date with the latest
upstream versions.
Upon execution, it automatically adjusts the PKGBUILD file, ensuring that the
pkgver field is set to match the latest version available from the upstream
source. In addition to updating the pkgver, this command also resets the pkgrel
to 1.
Outputs a summary of upgraded packages, up-to-date packages, and any check
failures.
This simplifies the maintenance of PKGBUILD files, reducing the manual effort
required to track and implement version changes from upstream sources.
Configuration
-------------
Uses linkman:nvchecker[1] and a `.nvchecker.toml` file located alongside the
PKGBUILD. Refer to the configuration section in linkman:pkgctl-version[1].
Options
-------
*-v, --verbose*::
Display results including up-to-date versions
*-h, --help*::
Show a help text
See Also
--------
linkman:pkgctl-version[1]
linkman:nvchecker[1]
include::include/footer.asciidoc[]

View File

@@ -3,16 +3,38 @@ pkgctl-version(1)
Name
----
pkgctl-version - Show pkgctl version information
pkgctl-version - Check and manage package versions against upstream
Synopsis
--------
pkgctl version [OPTIONS]
pkgctl version [OPTIONS] [SUBCOMMAND]
Description
-----------
Shows the current version information of pkgctl.
Commands related to package versions, including checks for outdated packages.
Uses linkman:nvchecker[1] and a `.nvchecker.toml` file located alongside the
PKGBUILD.
Configuration
-------------
The `.nvchecker.toml` file must contain a section that matches the
package's pkgbase. The pkgbase section within the `.nvchecker.toml` file
specifies the source and method for checking the latest version of the
corresponding package.
For detailed information on the various configuration options available for the
`.nvchecker.toml` file, refer to the configuration files section in
linkman:nvchecker[1]. This documentation provides insights into the possible
options that can be utilized to customize the version checking process.
To supply GitHub or GitLab tokens to nvchecker, a `keyfile.toml` should be
placed in the `$XDG_CONFIG_HOME`/nvchecker` directory. This keyfile is
used for providing the necessary authentication tokens required for
accessing the GitHub or GitLab API.
Options
-------
@@ -20,4 +42,19 @@ Options
*-h, --help*::
Show a help text
Subcommands
-----------
pkgctl version check::
Compares local package versions against upstream
pkgctl version upgrade::
Adjust the PKGBUILD to match the latest upstream version
See Also
--------
linkman:pkgctl-version-check[1]
linkman:pkgctl-version-upgrade[1]
include::include/footer.asciidoc[]

View File

@@ -26,6 +26,9 @@ Options
Subcommands
-----------
pkgctl aur::
Interact with the Arch User Repository
pkgctl auth::
Authenticate with services like GitLab
@@ -33,7 +36,7 @@ pkgctl build::
Build packages inside a clean chroot
pkgctl db::
Pacman database modification for packge update, move etc
Pacman database modification for package update, move etc
pkgctl diff::
Compare package files using different modes
@@ -44,18 +47,23 @@ pkgctl release::
pkgctl repo::
Manage Git packaging repositories and their configuration
pkgctl search::
Search for an expression across the GitLab packaging group
pkgctl version::
Show pkgctl version information
Check and manage package versions against upstream
See Also
--------
linkman:pkgctl-aur[1]
linkman:pkgctl-auth[1]
linkman:pkgctl-build[1]
linkman:pkgctl-db[1]
linkman:pkgctl-diff[1]
linkman:pkgctl-release[1]
linkman:pkgctl-repo[1]
linkman:pkgctl-search[1]
linkman:pkgctl-version[1]
include::include/footer.asciidoc[]

View File

@@ -16,7 +16,6 @@ umask 0022
working_dir=''
files=()
mount_args=()
usage() {
echo "Usage: ${0##*/} [options] working-dir [systemd-nspawn arguments]"
@@ -32,6 +31,9 @@ usage() {
exit 1
}
# save all args for check_root
orig_args=("$@")
while getopts 'hC:M:c:f:s' arg; do
case "$arg" in
C) pac_conf="$OPTARG" ;;
@@ -46,13 +48,23 @@ done
shift $((OPTIND - 1))
(( $# < 1 )) && die 'You must specify a directory.'
check_root "" "${BASH_SOURCE[0]}" "$@"
check_root "" "${BASH_SOURCE[0]}" "${orig_args[@]}"
working_dir=$(readlink -f "$1")
shift 1
[[ -z $working_dir ]] && die 'Please specify a working directory.'
nspawn_args=(
--quiet
--directory="$working_dir"
--setenv="PATH=/usr/local/sbin:/usr/local/bin:/usr/bin"
--register=no
--slice="devtools-$(systemd-escape "${SUDO_USER:-$USER}")"
--machine="arch-nspawn-$$"
--as-pid2
)
if (( ${#cache_dirs[@]} == 0 )); then
mapfile -t cache_dirs < <(pacman-conf --config "${pac_conf:-$working_dir/etc/pacman.conf}" CacheDir)
fi
@@ -80,10 +92,10 @@ while read -r line; do
done
done < <(pacman-conf --config "${pac_conf:-$working_dir/etc/pacman.conf}" --repo-list)
mount_args+=("--bind=${cache_dirs[0]//:/\\:}")
nspawn_args+=(--bind="${cache_dirs[0]//:/\\:}")
for cache_dir in "${cache_dirs[@]:1}"; do
mount_args+=("--bind-ro=${cache_dir//:/\\:}")
nspawn_args+=(--bind-ro="${cache_dir//:/\\:}")
done
# {{{ functions
@@ -126,9 +138,4 @@ else
set_arch="${CARCH}"
fi
exec ${CARCH:+setarch "$set_arch"} systemd-nspawn -q \
-D "$working_dir" \
-E "PATH=/usr/local/sbin:/usr/local/bin:/usr/bin" \
--register=no --keep-unit --as-pid2 \
"${mount_args[@]}" \
"$@"
exec ${CARCH:+setarch "$set_arch"} systemd-nspawn "${nspawn_args[@]}" "$@"

View File

@@ -35,7 +35,7 @@ fi
# validate repo is really repo-arch
if [[ -z $FORCE ]]; then
for tag in "$@"; do
if ! in_array "$tag" "${_tags[@]}"; then
if ! in_array "$tag" "${DEVTOOLS_VALID_TAGS[@]}"; then
die "archrelease: Invalid tag: '%s' (use -f to force release)" "$tag"
fi
done

View File

@@ -5,9 +5,13 @@
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/util/srcinfo.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/srcinfo.sh
source /usr/share/makepkg/util/util.sh
set -eo pipefail
check_pkgbuild_validity() {
# shellcheck source=contrib/makepkg/PKGBUILD.proto
@@ -70,6 +74,12 @@ if ! repo_spec=$(git config --local devtools.version) || [[ ${repo_spec} != "${G
exit 1
fi
if ! repo_variant=$(git config --local devtools.variant) || [[ ${repo_variant} != canonical ]]; then
error "cannot release from a repository with none canonical specs (%s), try:" "${repo_variant:-development}"
msg2 'pkgctl repo configure'
exit 1
fi
if [[ "$(git symbolic-ref --short HEAD)" != main ]]; then
die 'must be run from the main branch'
fi
@@ -111,7 +121,7 @@ if (( ${#validpgpkeys[@]} != 0 )); then
fi
# find files which should be under source control
needsversioning=()
needsversioning=(PKGBUILD)
for s in "${source[@]}"; do
[[ $s != *://* ]] && needsversioning+=("$s")
done
@@ -129,6 +139,10 @@ done
# assert that they really are controlled by git
if (( ${#needsversioning[*]} )); then
for file in "${needsversioning[@]}"; do
# skip none existing files
if [[ ! -f "${file}" ]]; then
continue
fi
if ! git ls-files --error-unmatch "$file"; then
die "%s is not under version control" "$file"
fi
@@ -173,7 +187,12 @@ done
# check for PKGBUILD standards
check_pkgbuild_validity
if [[ -n $(git status --short --untracked-files=no) ]]; then
# auto generate .SRCINFO
# shellcheck disable=SC2119
write_srcinfo_file
git add --force .SRCINFO
if [[ -n $(git status --porcelain --untracked-files=no) ]]; then
stat_busy 'Staging files'
for f in $(git ls-files --modified); do
git add "$f"
@@ -194,14 +213,14 @@ if [[ -n $(git status --short --untracked-files=no) ]]; then
echo "$msgtemplate" > "$msgfile"
if [[ -n $GIT_EDITOR ]]; then
$GIT_EDITOR "$msgfile" || die
elif giteditor=$(git config --get core.editor); then
$giteditor "$msgfile" || die
elif [[ -n $VISUAL ]]; then
$VISUAL "$msgfile" || die
elif [[ -n $EDITOR ]]; then
$EDITOR "$msgfile" || die
elif giteditor=$(git config --get core.editor); then
$giteditor "$msgfile" || die
else
die "No usable editor found (tried \$GIT_EDITOR, \$VISUAL, \$EDITOR, git config [core.editor])."
die "No usable editor found (tried \$GIT_EDITOR, git config [core.editor], \$VISUAL, \$EDITOR)."
fi
[[ -s $msgfile ]] || die
stat_busy 'Committing changes'

View File

@@ -215,7 +215,8 @@ diff_pkgs() {
[[ -f $oldpkg ]] || die "No such file: %s" "${oldpkg}"
[[ -f $newpkg ]] || die "No such file: %s" "${newpkg}"
DIFFOPTIONS+=(--label "${oldpkg}" --label "${newpkg}")
local -a diffoptions
diffoptions=("${DIFFOPTIONS[@]}" --label "${oldpkg}" --label "${newpkg}")
if (( TARLIST )); then
tar_list "$oldpkg" > "$TMPDIR/old"
@@ -236,7 +237,7 @@ diff_pkgs() {
# Resolve dynamic auto width one we know the content to diff
if [[ $DIFFWIDTH == --width=auto ]]; then
AUTOLENGTH=$(file_diff_columns "$TMPDIR/old" "$TMPDIR/new")
DIFFOPTIONS+=("--width=${AUTOLENGTH}")
diffoptions+=("--width=${AUTOLENGTH}")
fi
# Print a header for side-by-side view as it lacks labels
@@ -244,7 +245,7 @@ diff_pkgs() {
printf -- "--- %s\n+++ %s\n" "${oldpkg}" "${newpkg}"
fi
diff "${DIFFOPTIONS[@]}" "$TMPDIR/old" "$TMPDIR/new"
diff "${diffoptions[@]}" "$TMPDIR/old" "$TMPDIR/new"
fi
if (( DIFFOSCOPE )); then

57
src/lib/api/archweb.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_API_ARCHWEB_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_API_ARCHWEB_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
set -e
set -o pipefail
archweb_query_all_packages() {
[[ -z ${WORKDIR:-} ]] && setup_workdir
stat_busy "Query all released packages"
mapfile -t pkgbases < <(
curl --location --show-error --no-progress-meter --fail --retry 3 --retry-delay 3 \
"${PKGBASE_MAINTAINER_URL}" 2> "${WORKDIR}/error" \
| jq --raw-output --exit-status 'keys[]' 2> "${WORKDIR}/error"
)
if ! wait $!; then
stat_failed
print_workdir_error
return 1
fi
stat_done
printf "%s\n" "${pkgbases[@]}"
return 0
}
archweb_query_maintainer_packages() {
local maintainer=$1
[[ -z ${WORKDIR:-} ]] && setup_workdir
stat_busy "Query maintainer packages"
mapfile -t pkgbases < <(
curl --location --show-error --no-progress-meter --fail --retry 3 --retry-delay 3 \
"${PKGBASE_MAINTAINER_URL}" 2> "${WORKDIR}/error" \
| jq --raw-output --exit-status '. as $parent | keys[] | select(. as $key | $parent[$key] | index("'"${maintainer}"'"))' 2> "${WORKDIR}/error"
)
if ! wait $!; then
stat_failed
print_workdir_error
return 1
fi
stat_done
printf "%s\n" "${pkgbases[@]}"
return 0
}

View File

@@ -13,13 +13,63 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/config.sh
set -e
graphql_api_call() {
local outfile=$1
local request=$2
local node_type=$3
local data=$4
local hasNextPage cursor
# empty token
if [[ -z "${GITLAB_TOKEN}" ]]; then
msg_error " api call failed: No token provided"
return 1
fi
[[ -z ${WORKDIR:-} ]] && setup_workdir
api_workdir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-gitlab-api.XXXXXXXXXX)
# normalize graphql data and prepare query
data="${data//\"/\\\"}"
data='{
"query": "'"${data}"'"
}'
data="${data//$'\t'/ }"
data="${data//$'\n'/}"
cursor=""
hasNextPage=true
while [[ ${hasNextPage} == true ]]; do
data=$(sed -E 's|after: \\"[a-zA-Z0-9]*\\"|after: \\"'"${cursor}"'\\"|' <<< "${data}")
result="${api_workdir}/result.${cursor}"
if ! curl --request "${request}" \
--url "https://${GITLAB_HOST}/api/graphql" \
--header "Authorization: Bearer ${GITLAB_TOKEN}" \
--header "Content-Type: application/json" \
--data "${data}" \
--output "${result}" \
--silent; then
msg_error " api call failed: $(cat "${outfile}")"
return 1
fi
hasNextPage=$(jq --raw-output ".data | .${node_type} | .pageInfo | .hasNextPage" < "${result}")
cursor=$(jq --raw-output ".data | .${node_type} | .pageInfo | .endCursor" < "${result}")
cp "${result}" "${api_workdir}/tmp"
jq ".data.${node_type}.nodes" "${api_workdir}/tmp" > "${result}"
done
jq --slurp add "${api_workdir}"/result.* > "${outfile}"
return 0
}
gitlab_api_call() {
local outfile=$1
local request=$2
local endpoint=$3
local data=${4:-}
local error
# empty token
if [[ -z "${GITLAB_TOKEN}" ]]; then
@@ -38,27 +88,113 @@ gitlab_api_call() {
return 1
fi
if ! gitlab_check_api_errors "${outfile}"; then
return 1
fi
return 0
}
gitlab_api_call_paged() {
local outfile=$1
local status_file=$2
local request=$3
local endpoint=$4
local data=${5:-}
local result header
# empty token
if [[ -z "${GITLAB_TOKEN}" ]]; then
msg_error " api call failed: No token provided"
return 1
fi
[[ -z ${WORKDIR:-} ]] && setup_workdir
api_workdir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-gitlab-api.XXXXXXXXXX)
tmp_file=$(mktemp --tmpdir="${api_workdir}" spinner.tmp.XXXXXXXXXX)
local next_page=1
local total_pages=1
while [[ -n "${next_page}" ]]; do
percentage=$(( 100 * next_page / total_pages ))
printf "📡 Querying GitLab: %s/%s [%s] %%spinner%%" \
"${BOLD}${next_page}" "${total_pages}" "${percentage}%${ALL_OFF}" \
> "${tmp_file}"
mv "${tmp_file}" "${status_file}"
result="${api_workdir}/result.${next_page}"
header="${api_workdir}/header"
if ! curl --request "${request}" \
--get \
--url "https://${GITLAB_HOST}/api/v4/${endpoint}&per_page=100&page=${next_page}" \
--header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \
--header "Content-Type: application/json" \
--data-urlencode "${data}" \
--dump-header "${header}" \
--output "${result}" \
--silent; then
msg_error " api call failed: $(cat "${result}")"
return 1
fi
if ! gitlab_check_api_errors "${result}"; then
return 1
fi
next_page=$(grep "x-next-page" "${header}" | tr -d '\r' | awk '{ print $2 }')
total_pages=$(grep "x-total-pages" "${header}" | tr -d '\r' | awk '{ print $2 }')
done
jq --slurp add "${api_workdir}"/result.* > "${outfile}"
return 0
}
gitlab_check_api_errors() {
local file=$1
local error
# search API only returns an array, no errors
if [[ $(jq --raw-output 'type' < "${file}") == "array" ]]; then
return 0
fi
# check for general purpose api error
if error=$(jq --raw-output --exit-status '.error' < "${outfile}"); then
if error=$(jq --raw-output --exit-status '.error' < "${file}"); then
msg_error " api call failed: ${error}"
return 1
fi
# check for api specific error messages
if ! jq --raw-output --exit-status '.id' < "${outfile}" >/dev/null; then
if jq --raw-output --exit-status '.message | keys[]' < "${outfile}" &>/dev/null; then
if ! jq --raw-output --exit-status '.id' < "${file}" >/dev/null; then
if jq --raw-output --exit-status '.message | keys[]' < "${file}" &>/dev/null; then
while read -r error; do
msg_error " api call failed: ${error}"
done < <(jq --raw-output --exit-status '.message|to_entries|map("\(.key) \(.value[])")[]' < "${outfile}")
elif error=$(jq --raw-output --exit-status '.message' < "${outfile}"); then
done < <(jq --raw-output --exit-status '.message|to_entries|map("\(.key) \(.value[])")[]' < "${file}")
elif error=$(jq --raw-output --exit-status '.message' < "${file}"); then
msg_error " api call failed: ${error}"
fi
return 1
fi
return 0
}
graphql_check_api_errors() {
local file=$1
local error
# early exit if we do not have errors
if ! jq --raw-output --exit-status '.errors[]' < "${file}" &>/dev/null; then
return 0
fi
# check for api specific error messages
while read -r error; do
msg_error " api call failed: ${error}"
done < <(jq --raw-output --exit-status '.errors[].message' < "${file}")
return 1
}
gitlab_api_get_user() {
local outfile username
@@ -81,6 +217,23 @@ gitlab_api_get_user() {
return 0
}
gitlab_api_get_project_name_mapping() {
local query=$1
local outfile
[[ -z ${WORKDIR:-} ]] && setup_workdir
outfile=$(mktemp --tmpdir="${WORKDIR}" pkgctl-gitlab-api.XXXXXXXXXX)
# query user details
if ! graphql_api_call "${outfile}" POST projects "${query}"; then
msg_warn " Invalid token provided?"
exit 1
fi
cat "${outfile}"
return 0
}
# Convert arbitrary project names to GitLab valid path names.
#
# GitLab has several limitations on project and group names and also maintains
@@ -130,3 +283,22 @@ gitlab_api_create_project() {
printf "%s" "${path}"
return 0
}
# TODO: parallelize
# https://docs.gitlab.com/ee/api/search.html#scope-blobs
gitlab_api_search() {
local search=$1
local status_file=$2
local outfile
[[ -z ${WORKDIR:-} ]] && setup_workdir
outfile=$(mktemp --tmpdir="${WORKDIR}" pkgctl-gitlab-api.XXXXXXXXXX)
if ! gitlab_api_call_paged "${outfile}" "${status_file}" GET "/groups/archlinux%2fpackaging%2fpackages/search?scope=blobs" "search=${search}"; then
return 1
fi
cat "${outfile}"
return 0
}

View File

@@ -4,7 +4,7 @@
:
# shellcheck disable=2034
CHROOT_VERSION='v4'
CHROOT_VERSION='v5'
##
# usage : check_root $keepenv

65
src/lib/aur.sh Normal file
View File

@@ -0,0 +1,65 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_AUR_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_AUR_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
set -eo pipefail
pkgctl_aur_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [COMMAND] [OPTIONS]
Interact with the Arch User Repository (AUR).
Provides a suite of tools designed for managing and interacting with the Arch
User Repository (AUR). It simplifies various tasks related to AUR, including
importing repositories, managing packages, and transitioning packages between
the official repositories and the AUR.
COMMANDS
drop-from-repo Drop a package from the official repository to the AUR
OPTIONS
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} drop-from-repo libfoo
_EOF_
}
pkgctl_aur() {
if (( $# < 1 )); then
pkgctl_aur_usage
exit 0
fi
# option checking
while (( $# )); do
case $1 in
-h|--help)
pkgctl_aur_usage
exit 0
;;
drop-from-repo)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/aur/drop-from-repo.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/aur/drop-from-repo.sh
pkgctl_aur_drop_from_repo "$@"
exit 0
;;
-*)
die "invalid argument: %s" "$1"
;;
*)
die "invalid command: %s" "$1"
;;
esac
done
}

View File

@@ -0,0 +1,166 @@
#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_AUR_DROP_FROM_REPO_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_AUR_DROP_FROM_REPO_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/db/remove.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/db/remove.sh
# shellcheck source=src//lib/util/pacman.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/pacman.sh
source /usr/share/makepkg/util/message.sh
set -eo pipefail
pkgctl_aur_drop_from_repo_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS] [PATH]...
Drops a specified package from the official repositories to the Arch
User Repository.
This command requires a local Git clone of the package repository. It
reconfigures the repository for AUR compatibility and pushes it to the
AUR. Afterwards, the package is removed from the official repository.
By default, the package is automatically disowned in the AUR.
OPTIONS
--no-disown Do not disown the package on the AUR
-f, --force Force push to the AUR overwriting the remote repository
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} foo
$ ${COMMAND} --no-disown --force
_EOF_
}
pkgctl_aur_drop_from_repo() {
# options
local paths=()
local DISOWN=1
local FORCE=0
# variables
local path realpath pkgbase pkgrepo remote_url
while (( $# )); do
case $1 in
-h|--help)
pkgctl_aur_drop_from_repo_usage
exit 0
;;
--no-disown)
DISOWN=0
shift
;;
-f|--force)
FORCE=1
shift
;;
--)
shift
break
;;
-*)
die "Invalid argument: %s" "$1"
;;
*)
paths=("$@")
break
;;
esac
done
# check if invoked without any path from within a packaging repo
if (( ${#paths[@]} == 0 )); then
if [[ -f PKGBUILD ]]; then
paths=(".")
else
pkgctl_aur_drop_from_repo_usage
exit 1
fi
fi
for path in "${paths[@]}"; do
if ! realpath=$(realpath -e "${path}"); then
die "No such directory: ${path}"
fi
pkgbase=$(basename "${realpath}")
pkgbase=${pkgbase%.git}
if [[ ! -d "${path}/.git" ]]; then
die "Not a Git repository: ${path}"
fi
pushd "${path}" >/dev/null
if [[ ! -f PKGBUILD ]]; then
die 'PKGBUILD not found in %s' "${path}"
fi
msg "Dropping ${pkgbase} to the AUR"
remote_url="${AUR_URL_SSH}:${pkgbase}.git"
if ! git remote add origin "${remote_url}" &>/dev/null; then
git remote set-url origin "${remote_url}"
fi
# move the main branch to master
if [[ $(git symbolic-ref --quiet --short HEAD) == main ]]; then
git branch --move master
git config branch.master.merge refs/heads/master
git remote set-head origin master
fi
# auto generate .SRCINFO if not already present
if [[ -z "$(git ls-tree -r HEAD --name-only .SRCINFO)" ]]; then
stat_busy 'Generating .SRCINFO'
makepkg --printsrcinfo > .SRCINFO
stat_done
git add --force -- .SRCINFO
git commit --quiet --message "Adding .SRCINFO" -- .SRCINFO
fi
msg "Pushing ${pkgbase} to the AUR"
if (( FORCE )); then
AUR_OVERWRITE=1 \
GIT_SSH_COMMAND="ssh -o SendEnv=AUR_OVERWRITE" \
git push --force origin master
else
git push origin master
fi
if (( DISOWN )); then
msg "Disowning ${pkgbase} on the AUR"
# shellcheck disable=SC2029
ssh "${AUR_URL_SSH}" disown "${pkgbase}"
fi
# auto-detection of the repo to remove from
if ! pkgrepo=$(get_pacman_repo_from_pkgbuild PKGBUILD); then
die 'Failed to get pacman repo'
fi
msg "Deleting ${pkgbase} from the official repository"
if [[ -z "${pkgrepo}" ]]; then
warning 'Did not find %s in any repository, please delete manually' "${pkgbase}"
else
msg2 " repo: ${pkgrepo}"
pkgctl_db_remove "${pkgrepo}" "${pkgbase}"
fi
popd >/dev/null
done
}

View File

@@ -14,18 +14,25 @@ source "${_DEVTOOLS_LIBRARY_DIR}"/lib/db/update.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/release.sh
# shellcheck source=src/lib/util/git.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/git.sh
# shellcheck source=src/lib/util/srcinfo.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/srcinfo.sh
# shellcheck source=src/lib/util/pacman.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/pacman.sh
# shellcheck source=src/lib/util/pkgbuild.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/pkgbuild.sh
# shellcheck source=src/lib/valid-build-install.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-build-install.sh
# shellcheck source=src/lib/valid-repos.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-repos.sh
# shellcheck source=src/lib/valid-tags.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-tags.sh
# shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh
source /usr/share/makepkg/util/config.sh
source /usr/share/makepkg/util/message.sh
set -e
set -o pipefail
set -eo pipefail
pkgctl_build_usage() {
@@ -42,19 +49,24 @@ pkgctl_build_usage() {
BUILD OPTIONS
--arch ARCH Specify architectures to build for (disables auto-detection)
--repo REPO Specify a target repository (disables auto-detection)
--repo REPO Specify target repository for new packages not in any official repo
-s, --staging Build against the staging counterpart of the auto-detected repo
-t, --testing Build against the testing counterpart of the auto-detected repo
-o, --offload Build on a remote server and transfer artifacts afterwards
-c, --clean Recreate the chroot before building
-I, --install FILE Install a package into the working copy of the chroot
--inspect WHEN Spawn an interactive shell to inspect the chroot (never, always, failure)
-w, --worker SLOT Name of the worker slot, useful for concurrent builds (disables automatic names)
--nocheck Do not run the check() function in the PKGBUILD
INSTALL OPTIONS
-I, --install-to-chroot FILE Install a package to the working copy of the chroot
-i, --install-to-host MODE Install the built package to the host system, possible modes are 'all' and 'auto'
PKGBUILD OPTIONS
--pkgver=PKGVER Set pkgver, reset pkgrel and update checksums
--pkgrel=PKGREL Set pkgrel to a given value
--rebuild Increment the current pkgrel variable
--update-checksums Force computation and update of the checksums (disables auto-detection)
-e, --edit Edit the PKGBUILD before building
RELEASE OPTIONS
@@ -77,8 +89,7 @@ pkgctl_build_check_option_group_repo() {
local repo=$2
local testing=$3
local staging=$4
if ( (( testing )) && (( staging )) ) ||
( [[ $repo =~ ^.*-(staging|testing)$ ]] && ( (( testing )) || (( staging )) )); then
if [[ -n "${repo}" ]] || (( testing )) || (( staging )); then
die "The argument '%s' cannot be used with one or more of the other specified arguments" "${option}"
exit 1
fi
@@ -104,7 +115,7 @@ pkgctl_build() {
exit 1
fi
local UPDPKGSUMS=0
local UPDATE_CHECKSUMS=0
local EDIT=0
local REBUILD=0
local OFFLOAD=0
@@ -112,6 +123,7 @@ pkgctl_build() {
local TESTING=0
local RELEASE=0
local DB_UPDATE=0
local INSTALL_TO_HOST=none
local REPO=
local PKGVER=
@@ -124,12 +136,13 @@ pkgctl_build() {
local MAKECHROOT_OPTIONS=()
local RELEASE_OPTIONS=()
local MAKEPKG_OPTIONS=()
local INSTALL_HOST_PACKAGES=()
local WORKER=
local WORKER_SLOT=
# variables
local path pkgbase pkgrepo source
local _arch path pkgbase pkgrepo source pkgbuild_checksum current_checksum
while (( $# )); do
case $1 in
@@ -139,18 +152,18 @@ pkgctl_build() {
;;
--repo)
(( $# <= 1 )) && die "missing argument for %s" "$1"
REPO="${2}"
pkgctl_build_check_option_group_repo '--repo' "${REPO}" "${TESTING}" "${STAGING}"
REPO="${2}"
shift 2
;;
--arch)
(( $# <= 1 )) && die "missing argument for %s" "$1"
if [[ ${2} == all ]]; then
BUILD_ARCH=("${_arch[@]::${#_arch[@]}-1}")
BUILD_ARCH=("${DEVTOOLS_VALID_ARCHES[@]::${#DEVTOOLS_VALID_ARCHES[@]}-1}")
elif [[ ${2} == any ]]; then
BUILD_ARCH=("${_arch[0]}")
BUILD_ARCH=("${DEVTOOLS_VALID_ARCHES[0]}")
elif ! in_array "${2}" "${BUILD_ARCH[@]}"; then
if ! in_array "${2}" "${_arch[@]}"; then
if ! in_array "${2}" "${DEVTOOLS_VALID_ARCHES[@]}"; then
die 'invalid architecture: %s' "${2}"
fi
BUILD_ARCH+=("${2}")
@@ -161,7 +174,7 @@ pkgctl_build() {
pkgctl_build_check_option_group_ver '--pkgver' "${PKGVER}" "${PKGREL}" "${REBUILD}"
PKGVER="${1#*=}"
PKGREL=1
UPDPKGSUMS=1
UPDATE_CHECKSUMS=1
shift
;;
--pkgrel=*)
@@ -169,6 +182,10 @@ pkgctl_build() {
PKGREL="${1#*=}"
shift
;;
--update-checksums)
UPDATE_CHECKSUMS=1
shift
;;
--rebuild)
# shellcheck source=src/lib/util/git.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/git.sh
@@ -185,23 +202,35 @@ pkgctl_build() {
shift
;;
-s|--staging)
STAGING=1
pkgctl_build_check_option_group_repo '--staging' "${REPO}" "${TESTING}" "${STAGING}"
STAGING=1
shift
;;
-t|--testing)
TESTING=1
pkgctl_build_check_option_group_repo '--testing' "${REPO}" "${TESTING}" "${STAGING}"
TESTING=1
shift
;;
-c|--clean)
BUILD_OPTIONS+=("-c")
shift
;;
-I|--install)
-I|--install-to-chroot)
(( $# <= 1 )) && die "missing argument for %s" "$1"
MAKECHROOT_OPTIONS+=("-I" "$2")
warning 'installing packages into the chroot may break reproducible builds, use with caution!'
if (( OFFLOAD )); then
MAKECHROOT_OPTIONS+=("-I" "$2")
else
MAKECHROOT_OPTIONS+=("-I" "$(realpath "$2")")
fi
warning 'installing packages to the chroot may break reproducible builds, use with caution!'
shift 2
;;
-i|--install-to-host)
(( $# <= 1 )) && die "missing argument for %s" "$1"
if ! in_array "$2" "${DEVTOOLS_VALID_BUILD_INSTALL[@]}"; then
die 'invalid install mode: %s' "${2}"
fi
INSTALL_TO_HOST=$2
shift 2
;;
--nocheck)
@@ -209,6 +238,14 @@ pkgctl_build() {
warning 'not running checks is disallowed for official packages, except for bootstrapping. Please rebuild after bootstrapping is completed!'
shift
;;
--inspect)
(( $# <= 1 )) && die "missing argument for %s" "$1"
if ! in_array "${2}" "${DEVTOOLS_VALID_INSPECT_MODES[@]}"; then
die "Invalid inspect mode: %s" "${2}"
fi
MAKECHROOT_OPTIONS+=("-x" "${2}")
shift 2
;;
-r|--release)
# shellcheck source=src/lib/release.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/release.sh
@@ -274,7 +311,7 @@ pkgctl_build() {
if [[ -z ${REPO} ]]; then
update_pacman_repo_cache
# Check valid repos if not resolved dynamically
elif ! in_array "${REPO}" "${_repos[@]}"; then
elif ! in_array "${REPO}" "${DEVTOOLS_VALID_REPOS[@]}"; then
die "Invalid repository target: %s" "${REPO}"
fi
@@ -290,18 +327,32 @@ pkgctl_build() {
. ./PKGBUILD
pkgbase=${pkgbase:-$pkgname}
pkgrepo=${REPO}
pkgbuild_checksum=$(b2sum PKGBUILD | awk '{print $1}')
msg "Building ${pkgbase}"
# auto-detection of build target
if [[ -z ${pkgrepo} ]]; then
if ! pkgrepo=$(get_pacman_repo_from_pkgbuild PKGBUILD); then
die 'failed to get pacman repo'
fi
if [[ -z "${pkgrepo}" ]]; then
die 'unknown repo, please specify --repo for new packages'
# auto-detect target repository
if ! repo=$(get_pacman_repo_from_pkgbuild PKGBUILD); then
die 'Failed to query pacman repo'
fi
# fail if an existing package specifies --repo
if [[ -n "${repo}" ]] && [[ -n ${pkgrepo} ]]; then
# allow unstable to use --repo
if [[ ${pkgrepo} == *unstable ]]; then
repo=${pkgrepo}
else
die 'Using --repo for packages that exist in official repositories is disallowed'
fi
fi
# assign auto-detected target repository
if [[ -n ${repo} ]]; then
pkgrepo=${repo}
# fallback to extra for unreleased packages
elif [[ -z ${pkgrepo} ]]; then
pkgrepo=extra
fi
# special cases to resolve final build target
if (( TESTING )); then
pkgrepo="${pkgrepo}-testing"
@@ -316,9 +367,15 @@ pkgctl_build() {
BUILD_ARCH=("")
elif (( ${#BUILD_ARCH[@]} == 0 )); then
if in_array any "${arch[@]}"; then
BUILD_ARCH=("${_arch[0]}")
BUILD_ARCH=("${DEVTOOLS_VALID_ARCHES[0]}")
else
BUILD_ARCH+=("${arch[@]}")
for _arch in "${arch[@]}"; do
if in_array "${_arch}" "${DEVTOOLS_VALID_ARCHES[@]}"; then
BUILD_ARCH+=("$_arch")
else
warning 'invalid architecture, not building for: %s' "${_arch}"
fi
done
fi
fi
@@ -329,7 +386,7 @@ pkgctl_build() {
# increment pkgrel on rebuild
if (( REBUILD )); then
# try to figure out of pkgrel has been changed
# try to figure out if pkgrel has been changed
if ! old_pkgrel=$(git_diff_tree HEAD PKGBUILD | grep --perl-regexp --only-matching --max-count=1 '^-pkgrel=\K\w+'); then
old_pkgrel=${pkgrel}
fi
@@ -346,20 +403,14 @@ pkgctl_build() {
# update pkgver
if [[ -n ${PKGVER} ]]; then
if [[ $(type -t pkgver) == function ]]; then
# TODO: check if die or warn, if we provide _commit _gitcommit setter maybe?
warning 'setting pkgver variable has no effect if the PKGBUILD has a pkgver() function'
fi
msg "Bumping pkgver to ${PKGVER}"
grep --extended-regexp --quiet --max-count=1 "^pkgver=${pkgver}$" PKGBUILD || die "Non-standard pkgver declaration"
sed --regexp-extended "s|^(pkgver=)${pkgver}$|\1${PKGVER}|g" -i PKGBUILD
pkgbuild_set_pkgver "${PKGVER}"
fi
# update pkgrel
if [[ -n ${PKGREL} ]]; then
msg "Bumping pkgrel to ${PKGREL}"
grep --extended-regexp --quiet --max-count=1 "^pkgrel=${pkgrel}$" PKGBUILD || die "Non-standard pkgrel declaration"
sed --regexp-extended "s|^(pkgrel=)${pkgrel}$|\1${PKGREL}|g" -i PKGBUILD
pkgbuild_set_pkgrel "${PKGREL}"
fi
# edit PKGBUILD
@@ -381,10 +432,18 @@ pkgctl_build() {
# update checksums if any sources are declared
if (( UPDPKGSUMS )) && (( ${#source[@]} >= 1 )); then
if (( UPDATE_CHECKSUMS )) && (( ${#source[@]} >= 1 )); then
updpkgsums
fi
# re-source the PKGBUILD if it changed
current_checksum="$(b2sum PKGBUILD | awk '{print $1}')"
if [[ ${pkgbuild_checksum} != "${current_checksum}" ]]; then
pkgbuild_checksum=${current_checksum}
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. ./PKGBUILD
fi
# execute build
for arch in "${BUILD_ARCH[@]}"; do
if [[ -n $arch ]]; then
@@ -402,6 +461,38 @@ pkgctl_build() {
fi
done
# re-source the PKGBUILD if it changed
current_checksum="$(b2sum PKGBUILD | awk '{print $1}')"
if [[ ${pkgbuild_checksum} != "${current_checksum}" ]]; then
pkgbuild_checksum=${current_checksum}
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. ./PKGBUILD
fi
# auto generate .SRCINFO
# shellcheck disable=SC2119
write_srcinfo_file
# test-install (some of) the produced packages
if [[ ${INSTALL_TO_HOST} == auto ]] || [[ ${INSTALL_TO_HOST} == all ]]; then
# shellcheck disable=2119
load_makepkg_config
# this is inspired by print_all_package_names from libmakepkg
local version pkg_architecture pkg pkgfile
version=$(get_full_version)
for pkg in "${pkgname[@]}"; do
pkg_architecture=$(get_pkg_arch "$pkg")
pkgfile=$(realpath "$(printf "%s/%s-%s-%s%s\n" "${PKGDEST:-.}" "$pkg" "$version" "$pkg_architecture" "$PKGEXT")")
# check if we install all packages or if the (split-)package is already installed
if [[ ${INSTALL_TO_HOST} == all ]] || ( [[ ${INSTALL_TO_HOST} == auto ]] && pacman -Qq -- "$pkg" &>/dev/null ); then
INSTALL_HOST_PACKAGES+=("$pkgfile")
fi
done
fi
# release the build
if (( RELEASE )); then
pkgctl_release --repo "${pkgrepo}" "${RELEASE_OPTIONS[@]}"
@@ -412,6 +503,12 @@ pkgctl_build() {
popd >/dev/null
done
# install all collected packages to the host system
if (( ${#INSTALL_HOST_PACKAGES[@]} )); then
msg "Installing built packages to the host system"
sudo pacman -U -- "${INSTALL_HOST_PACKAGES[@]}"
fi
# update the binary package repo db as last action
if (( RELEASE )) && (( DB_UPDATE )); then
# shellcheck disable=2119

22
src/lib/cache.sh Normal file
View File

@@ -0,0 +1,22 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_CACHE_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_CACHE_SH=1
set -e
readonly XDG_DEVTOOLS_CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/devtools"
get_cache_file() {
local filename=$1
local path="${XDG_DEVTOOLS_CACHE_DIR}/${filename}"
mkdir --parents -- "$(dirname -- "$path")"
if [[ ! -f ${path} ]]; then
touch -- "${path}"
fi
printf '%s' "${path}"
}

View File

@@ -13,7 +13,7 @@ set +u +o posix
$DEVTOOLS_INCLUDE_COMMON_SH
# Avoid any encoding problems
export LANG=C
export LANG=C.UTF-8
# Set buildtool properties
export BUILDTOOL=devtools
@@ -22,19 +22,24 @@ export BUILDTOOLVER=@buildtoolver@
# Set common properties
export PACMAN_KEYRING_DIR=/etc/pacman.d/gnupg
export GITLAB_HOST=gitlab.archlinux.org
export GIT_REPO_SPEC_VERSION=1
export GIT_REPO_SPEC_VERSION=2
export GIT_PACKAGING_NAMESPACE=archlinux/packaging/packages
export GIT_PACKAGING_NAMESPACE_ID=11323
export GIT_PACKAGING_URL_SSH="ssh://git@${GITLAB_HOST}/${GIT_PACKAGING_NAMESPACE}"
export GIT_PACKAGING_URL_SSH="git@${GITLAB_HOST}:${GIT_PACKAGING_NAMESPACE}"
export GIT_PACKAGING_URL_HTTPS="https://${GITLAB_HOST}/${GIT_PACKAGING_NAMESPACE}"
export PACKAGING_REPO_RELEASE_HOST=repos.archlinux.org
export PKGBASE_MAINTAINER_URL=https://archlinux.org/packages/pkgbase-maintainer
export AUR_URL_SSH=aur@aur.archlinux.org
# check if messages are to be printed using color
if [[ -t 2 && "$TERM" != dumb ]]; then
if [[ -t 2 && "$TERM" != dumb ]] || [[ ${DEVTOOLS_COLOR} == always ]]; then
colorize
PURPLE="$(tput setaf 5)"
DARK_GREEN="$(tput setaf 2)"
UNDERLINE="$(tput smul)"
else
# shellcheck disable=2034
declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW=''
declare -gr ALL_OFF='' BOLD='' BLUE='' GREEN='' RED='' YELLOW='' PURPLE='' DARK_GREEN='' UNDERLINE=''
fi
stat_busy() {
@@ -53,6 +58,11 @@ stat_done() {
printf "${BOLD}done${ALL_OFF}\n" >&2
}
stat_failed() {
# shellcheck disable=2059
printf "${BOLD}${RED}failed${ALL_OFF}\n" >&2
}
msg_success() {
local msg=$1
local padding
@@ -77,6 +87,15 @@ msg_warn() {
printf "%s %s\n" "${padding}${YELLOW}!${ALL_OFF}" "${msg}" >&2
}
print_workdir_error() {
if [[ ! -f "${WORKDIR}"/error ]]; then
return
fi
while read -r LINE; do
error '%s' "${LINE}"
done < "${WORKDIR}/error"
}
_setup_workdir=false
setup_workdir() {
[[ -z ${WORKDIR:-} ]] && WORKDIR=$(mktemp -d --tmpdir "${0##*/}.XXXXXXXXXX")
@@ -89,6 +108,7 @@ cleanup() {
if [[ -n ${WORKDIR:-} ]] && $_setup_workdir; then
rm -rf "$WORKDIR"
fi
tput cnorm >&2
exit "${1:-0}"
}
@@ -120,7 +140,7 @@ lock() {
# Only reopen the FD if it wasn't handed to us
if ! [[ "/dev/fd/$1" -ef "$2" ]]; then
mkdir -p -- "$(dirname -- "$2")"
eval "exec $1>"'"$2"'
eval "exec $1>>"'"$2"'
fi
if ! flock -n "$1"; then

View File

@@ -15,7 +15,7 @@ pkgctl_db_usage() {
cat <<- _EOF_
Usage: ${COMMAND} [COMMAND] [OPTIONS]
Pacman database modification for packge update, move etc
Pacman database modification for package update, move etc
COMMANDS
move Move packages between pacman repositories

View File

@@ -35,7 +35,7 @@ pkgctl_release_usage() {
OPTIONS
-m, --message MSG Use the given <msg> as the commit message
-r, --repo REPO Specify a target repository (disables auto-detection)
-r, --repo REPO Specify target repository for new packages not in any official repo
-s, --staging Release to the staging counterpart of the auto-detected repo
-t, --testing Release to the testing counterpart of the auto-detected repo
-u, --db-update Automatically update the pacman database after uploading
@@ -43,8 +43,8 @@ pkgctl_release_usage() {
EXAMPLES
$ ${COMMAND}
$ ${COMMAND} --repo core-testing --message 'libyay 0.42 rebuild' libfoo libbar
$ ${COMMAND} --staging --db-update libfoo
$ ${COMMAND} --staging --message 'libyay 0.42 rebuild' libfoo libbar
$ ${COMMAND} --repo extra --db-update new-package
_EOF_
}
@@ -126,7 +126,7 @@ pkgctl_release() {
if [[ -z ${REPO} ]]; then
update_pacman_repo_cache
# Check valid repos if not resolved dynamically
elif ! in_array "${REPO}" "${_repos[@]}"; then
elif ! in_array "${REPO}" "${DEVTOOLS_VALID_REPOS[@]}"; then
die "Invalid repository target: %s" "${REPO}"
fi
@@ -134,15 +134,27 @@ pkgctl_release() {
pushd "${path}" >/dev/null
pkgbase=$(basename "${path}")
if [[ -n ${REPO} ]]; then
# auto-detect target repository
if ! repo=$(get_pacman_repo_from_pkgbuild PKGBUILD); then
die 'Failed to query pacman repo'
fi
# fail if an existing package specifies --repo
if [[ -n "${repo}" ]] && [[ -n ${REPO} ]]; then
# allow unstable to use --repo
if [[ ${REPO} == *unstable ]]; then
repo=${REPO}
else
die 'Using --repo for packages that exist in official repositories is disallowed'
fi
fi
# fail if a new package does not specify --repo
if [[ -z "${repo}" ]]; then
if [[ -z ${REPO} ]]; then
die 'Specify --repo for packages that do not yet exist in official repositories'
fi
repo=${REPO}
else
if ! repo=$(get_pacman_repo_from_pkgbuild PKGBUILD); then
die 'Failed to get pacman repo'
fi
if [[ -z "${repo}" ]]; then
die 'Unknown repo, please specify --repo for new packages'
fi
fi
if (( TESTING )); then

View File

@@ -8,14 +8,19 @@ DEVTOOLS_INCLUDE_REPO_CLONE_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/api/archweb.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/archweb.sh
# shellcheck source=src/lib/api/gitlab.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/gitlab.sh
# shellcheck source=src/lib/repo/configure.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/repo/configure.sh
# shellcheck source=src/lib/util/git.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/git.sh
source /usr/share/makepkg/util/message.sh
set -e
set -o pipefail
pkgctl_repo_clone_usage() {
@@ -26,14 +31,16 @@ pkgctl_repo_clone_usage() {
Clone Git packaging repositories from the canonical namespace.
The configure command is subsequently invoked to synchronize the distro
specs and makepkg.conf settings. The unprivileged option can be used
specs and makepkg.conf settings. The protocol option can be used
for cloning packaging repositories without SSH access using read-only
HTTPS.
OPTIONS
-m, --maintainer=NAME Clone all packages of the named maintainer
--protocol https Clone the repository over https
--switch VERSION Switch the current working tree to a specified version
--universe Clone all existing packages, useful for cache warming
-j, --jobs N Run up to N jobs in parallel (default: $(nproc))
-h, --help Show this help text
EXAMPLES
@@ -50,14 +57,17 @@ pkgctl_repo_clone() {
fi
# options
local protocol=ssh
local GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_SSH}
local CLONE_ALL=0
local MAINTAINER=
local VERSION=
local CONFIGURE_OPTIONS=()
local pkgbases
local jobs=
jobs=$(nproc)
# variables
local command=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
local project_path
while (( $# )); do
@@ -66,11 +76,23 @@ pkgctl_repo_clone() {
pkgctl_repo_clone_usage
exit 0
;;
-u|--unprivileged)
--protocol=https)
GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS}
protocol=https
CONFIGURE_OPTIONS+=("$1")
shift
;;
--protocol)
(( $# <= 1 )) && die "missing argument for %s" "$1"
if [[ $2 == https ]]; then
GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS}
else
die "unsupported protocol: %s" "$2"
fi
protocol="$2"
CONFIGURE_OPTIONS+=("$1" "$2")
shift 2
;;
-m|--maintainer)
(( $# <= 1 )) && die "missing argument for %s" "$1"
MAINTAINER="$2"
@@ -97,6 +119,11 @@ pkgctl_repo_clone() {
CLONE_ALL=1
shift
;;
-j|--jobs)
(( $# <= 1 )) && die "missing argument for %s" "$1"
jobs=$2
shift 2
;;
--)
shift
break
@@ -113,33 +140,41 @@ pkgctl_repo_clone() {
# Query packages of a maintainer
if [[ -n ${MAINTAINER} ]]; then
stat_busy "Query packages"
max_pages=$(curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name&maintainer=${MAINTAINER}" | jq -r '.num_pages')
if [[ ! ${max_pages} =~ ([[:digit:]]) ]]; then
stat_done
warning "found no packages for maintainer ${MAINTAINER}"
exit 0
mapfile -t pkgbases < <(archweb_query_maintainer_packages "${MAINTAINER}")
if ! wait $!; then
die "Failed to query maintainer packages"
fi
mapfile -t pkgbases < <(for page in $(seq "${max_pages}"); do
curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name&maintainer=${MAINTAINER}&page=${page}" | jq -r '.results[].pkgbase'
stat_progress
done | sort --unique)
stat_done
fi
# Query all released packages
if (( CLONE_ALL )); then
stat_busy "Query all released packages"
max_pages=$(curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name" | jq -r '.num_pages')
if [[ ! ${max_pages} =~ ([[:digit:]]) ]]; then
stat_done
die "failed to query packages"
mapfile -t pkgbases < <(archweb_query_all_packages)
if ! wait $!; then
die "Failed to query all packages"
fi
mapfile -t pkgbases < <(for page in $(seq "${max_pages}"); do
curl --silent --location --fail --retry 3 --retry-delay 3 "https://archlinux.org/packages/search/json/?sort=name&page=${page}" | jq -r '.results[].pkgbase'
stat_progress
done | sort --unique)
stat_done
fi
# parallelization
if [[ ${jobs} != 1 ]] && (( ${#pkgbases[@]} > 1 )); then
# force colors in parallel if parent process is colorized
if [[ -n ${BOLD} ]]; then
export DEVTOOLS_COLOR=always
fi
# assign command options
if [[ -n "${VERSION}" ]]; then
command+=" --switch '${VERSION}'"
fi
# warm up ssh connection as it may require user input (key unlock, hostkey verification etc)
if [[ ${protocol} == ssh ]]; then
git_warmup_ssh_connection
fi
if ! parallel --bar --jobs "${jobs}" "${command}" ::: "${pkgbases[@]}"; then
die 'Failed to clone some packages, please check the output'
exit 1
fi
exit 0
fi
for pkgbase in "${pkgbases[@]}"; do
@@ -147,7 +182,9 @@ pkgctl_repo_clone() {
msg "Cloning ${pkgbase} ..."
project_path=$(gitlab_project_name_to_path "${pkgbase}")
remote_url="${GIT_REPO_BASE_URL}/${project_path}.git"
git clone --origin origin "${remote_url}" "${pkgbase}"
if ! git clone --origin origin "${remote_url}" "${pkgbase}"; then
die 'failed to clone %s' "${pkgbase}"
fi
else
warning "Skip cloning ${pkgbase}: Directory exists"
fi

View File

@@ -10,11 +10,14 @@ _DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/api/gitlab.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/gitlab.sh
# shellcheck source=src/lib/util/git.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/git.sh
source /usr/share/makepkg/util/config.sh
source /usr/share/makepkg/util/message.sh
set -e
shopt -s nullglob
pkgctl_repo_configure_usage() {
@@ -32,11 +35,15 @@ pkgctl_repo_configure_usage() {
address by choosing SSH for all official packager identities and
read-only HTTPS otherwise.
Git default excludes and hooks are applied to the configured repo.
OPTIONS
--protocol https Configure remote url to use https
-j, --jobs N Run up to N jobs in parallel (default: $(nproc))
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} configure *
$ ${COMMAND} *
_EOF_
}
@@ -93,10 +100,14 @@ pkgctl_repo_configure() {
local GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_HTTPS}
local official=0
local proto=https
local proto_force=0
local jobs=
jobs=$(nproc)
local paths=()
# variables
local path realpath pkgbase remote_url project_path
local -r command=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
local path realpath pkgbase remote_url project_path hook
local PACKAGER GPGKEY packager_name packager_email
while (( $# )); do
@@ -105,6 +116,24 @@ pkgctl_repo_configure() {
pkgctl_repo_configure_usage
exit 0
;;
--protocol=https)
proto_force=1
shift
;;
--protocol)
(( $# <= 1 )) && die "missing argument for %s" "$1"
if [[ $2 == https ]]; then
proto_force=1
else
die "unsupported protocol: %s" "$2"
fi
shift 2
;;
-j|--jobs)
(( $# <= 1 )) && die "missing argument for %s" "$1"
jobs=$2
shift 2
;;
--)
shift
break
@@ -143,8 +172,10 @@ pkgctl_repo_configure() {
fi
if is_packager_email_official "${packager_email}"; then
official=1
proto=ssh
GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_SSH}
if (( ! proto_force )); then
proto=ssh
GIT_REPO_BASE_URL=${GIT_PACKAGING_URL_SSH}
fi
fi
fi
@@ -157,10 +188,27 @@ pkgctl_repo_configure() {
msg2 "protocol: ${YELLOW}${proto}${ALL_OFF}"
fi
# parallelization
if [[ ${jobs} != 1 ]] && (( ${#paths[@]} > 1 )); then
if [[ -n ${BOLD} ]]; then
export DEVTOOLS_COLOR=always
fi
# warm up ssh connection as it may require user input (key unlock, hostkey verification etc)
if [[ ${proto} == ssh ]]; then
git_warmup_ssh_connection
fi
if ! parallel --bar --jobs "${jobs}" "${command}" ::: "${paths[@]}"; then
die 'Failed to configure some packages, please check the output'
exit 1
fi
exit 0
fi
for path in "${paths[@]}"; do
if ! realpath=$(realpath -e "${path}"); then
error "No such directory: ${path}"
continue
die "No such directory: ${path}"
fi
pkgbase=$(basename "${realpath}")
@@ -168,8 +216,7 @@ pkgctl_repo_configure() {
msg "Configuring ${pkgbase}"
if [[ ! -d "${path}/.git" ]]; then
error "Not a Git repository: ${path}"
continue
die "Not a Git repository: ${path}"
fi
pushd "${path}" >/dev/null
@@ -186,7 +233,15 @@ pkgctl_repo_configure() {
git config branch.main.merge refs/heads/main
fi
# configure spec version and variant to avoid using development hooks in production
git config devtools.version "${GIT_REPO_SPEC_VERSION}"
if [[ ${_DEVTOOLS_LIBRARY_DIR} == /usr/share/devtools ]]; then
git config devtools.variant canonical
else
warning "Configuring with development version of pkgctl, do not use this repo in production"
git config devtools.variant development
fi
git config pull.rebase true
git config branch.autoSetupRebase always
git config branch.main.remote origin
@@ -213,6 +268,18 @@ pkgctl_repo_configure() {
git config user.signingKey "${GPGKEY}"
fi
# set default git exclude
mkdir -p .git/info
ln -sf "${_DEVTOOLS_LIBRARY_DIR}/git.conf.d/template/info/exclude" \
.git/info/exclude
# set default git hooks
mkdir -p .git/hooks
rm -f .git/hooks/*.sample
for hook in "${_DEVTOOLS_LIBRARY_DIR}"/git.conf.d/template/hooks/*; do
ln -sf "${hook}" ".git/hooks/$(basename "${hook}")"
done
if ! git ls-remote origin &>/dev/null; then
warning "configured remote origin may not exist, run:"
msg2 "pkgctl repo create ${pkgbase}"

View File

@@ -23,16 +23,18 @@ pkgctl_repo_web_usage() {
no arguments, open the package cloned in the current working directory.
OPTIONS
--print Print the url instead of opening it with xdg-open
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} web linux
$ ${COMMAND} linux
_EOF_
}
pkgctl_repo_web() {
local pkgbases=()
local path giturl pkgbase
local path giturl pkgbase url
local mode=open
# option checking
while (( $# )); do
@@ -41,6 +43,10 @@ pkgctl_repo_web() {
pkgctl_repo_web_usage
exit 0
;;
--print)
mode=print
shift
;;
--)
shift
break
@@ -56,7 +62,7 @@ pkgctl_repo_web() {
done
# Check if web mode has xdg-open
if ! command -v xdg-open &>/dev/null; then
if [[ ${mode} == open ]] && ! command -v xdg-open &>/dev/null; then
die "The web command requires 'xdg-open'"
fi
@@ -78,7 +84,18 @@ pkgctl_repo_web() {
fi
for pkgbase in "${pkgbases[@]}"; do
pkgbase=$(basename "${pkgbase}")
path=$(gitlab_project_name_to_path "${pkgbase}")
xdg-open "${GIT_PACKAGING_URL_HTTPS}/${path}"
url="${GIT_PACKAGING_URL_HTTPS}/${path}"
case ${mode} in
open)
xdg-open "${url}"
;;
print)
printf "%s\n" "${url}"
;;
*)
die "Unknown mode: ${mode}"
esac
done
}

308
src/lib/search.sh Normal file
View File

@@ -0,0 +1,308 @@
#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_SEARCH_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_SEARCH_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/cache.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/cache.sh
# shellcheck source=src/lib/api/gitlab.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/api/gitlab.sh
# shellcheck source=src/lib/valid-search.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-search.sh
# shellcheck source=src/lib/util/term.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/term.sh
source /usr/share/makepkg/util/util.sh
source /usr/share/makepkg/util/message.sh
set -eo pipefail
pkgctl_search_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS] QUERY
Search for an expression across the GitLab packaging group.
To use a filter, include it in your query. You may use wildcards (*) to
use glob matching.
Available filters for the blobs scope: path, extension
Every usage of the search command must be authenticated. Consult the
'pkgctl auth' command to authenticate with GitLab or view the
authentication status.
SEARCH TIPS
Syntax Description Example
───────────────────────────────────────
" Exact search "gem sidekiq"
~ Fuzzy search J~ Doe
| Or display | banner
+ And display +banner
- Exclude display -banner
* Partial bug error 50*
\\ Escape \\*md
# Issue ID #23456
! Merge request !23456
OPTIONS
-h, --help Show this help text
FILTER OPTIONS
--no-default-filter Do not apply default filter (like -path:keys/pgp/*.asc)
OUTPUT OPTIONS
--json Enable printing in JSON; Shorthand for '--format json'
-F, --format FORMAT Controls the formatting of the results; FORMAT is 'pretty',
'plain', or 'json' (default: pretty)
-N, --no-line-number Don't show line numbers when formatting results
EXAMPLES
$ ${COMMAND} linux
$ ${COMMAND} --json '"pytest -v" +PYTHONPATH'
_EOF_
}
pkgctl_search_check_option_group_format() {
local option=$1
local output_format=$2
if [[ -n ${output_format} ]]; then
die "The argument '%s' cannot be used with one or more of the other specified arguments" "${option}"
exit 1
fi
return 0
}
pkgctl_search() {
if (( $# < 1 )); then
pkgctl_search_usage
exit 0
fi
# options
local search
local output_format=
local use_default_filter=1
local line_numbers=1
# variables
local bat_style="header,grid"
local default_filter="-path:keys/pgp/*.asc"
local graphql_lookup_batch=200
local output result query entries from until length
local project_name_cache_file project_name_lookup project_ids project_id project_name project_slice
local mapping_output path startline currentline data line
while (( $# )); do
case $1 in
-h|--help)
pkgctl_search_usage
exit 0
;;
--no-default-filter)
use_default_filter=0
shift
;;
--json)
pkgctl_search_check_option_group_format "$1" "${output_format}"
output_format=json
shift
;;
-F|--format)
(( $# <= 1 )) && die "missing argument for %s" "$1"
pkgctl_search_check_option_group_format "$1" "${output_format}"
output_format="${2}"
if ! in_array "${output_format}" "${valid_search_output_format[@]}"; then
die "Unknown output format: %s" "${output_format}"
fi
shift 2
;;
-N|--no-line-number)
line_numbers=0
shift
;;
--)
shift
break
;;
-*)
die "invalid argument: %s" "$1"
;;
*)
break
;;
esac
done
if (( $# == 0 )); then
pkgctl_search_usage
exit 1
fi
# assign search parameter
search="${*}"
if (( use_default_filter )); then
search+=" ${default_filter}"
fi
# assign default output format
if [[ -z ${output_format} ]]; then
output_format=pretty
fi
# check for optional dependencies
if [[ ${output_format} == pretty ]] && ! command -v bat &>/dev/null; then
warning "Failed to find optional dependency 'bat': falling back to plain output"
output_format=plain
fi
# populate line numbers option
if (( line_numbers )); then
bat_style="numbers,${bat_style}"
fi
# call the gitlab search API
status_dir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-gitlab-api.XXXXXXXXXX)
printf "📡 Querying GitLab search API..." > "${status_dir}/status"
term_spinner_start "${status_dir}"
output=$(gitlab_api_search "${search}" "${status_dir}/status")
term_spinner_stop "${status_dir}"
msg_success "Querying GitLab search API"
# collect project ids whose name needs to be looked up
project_name_cache_file=$(get_cache_file gitlab/project_id_to_name)
lock 11 "${project_name_cache_file}" "Locking project name cache"
mapfile -t project_ids < <(
jq --raw-output '[.[].project_id] | unique[]' <<< "${output}" | \
grep --invert-match --file <(awk '{ print $1 }' < "${project_name_cache_file}" ))
# look up project names
tmp_file=$(mktemp --tmpdir="${WORKDIR}" pkgctl-gitlab-api-spinner.tmp.XXXXXXXXXX)
printf "📡 Querying GitLab project names..." > "${status_dir}/status"
term_spinner_start "${status_dir}"
local entries="${#project_ids[@]}"
local until=0
while (( until < entries )); do
from=${until}
until=$(( until + graphql_lookup_batch ))
if (( until > entries )); then
until=${entries}
fi
length=$(( until - from ))
percentage=$(( 100 * until / entries ))
printf "📡 Querying GitLab project names: %s/%s [%s] %%spinner%%" \
"${BOLD}${until}" "${entries}" "${percentage}%${ALL_OFF}" \
> "${tmp_file}"
mv "${tmp_file}" "${status_dir}/status"
project_slice=("${project_ids[@]:${from}:${length}}")
printf -v projects '"gid://gitlab/Project/%s",' "${project_slice[@]}"
query='{
projects(after: "" ids: ['"${projects}"']) {
pageInfo {
startCursor
endCursor
hasNextPage
}
nodes {
id
name
}
}
}'
mapping_output=$(gitlab_api_get_project_name_mapping "${query}")
# update cache
while read -r project_id project_name; do
printf "%s %s\n" "${project_id}" "${project_name}" >> "${project_name_cache_file}"
done < <(jq --raw-output \
'.[] | "\(.id | rindex("/") as $lastSlash | .[$lastSlash+1:]) \(.name)"' \
<<< "${mapping_output}")
done
term_spinner_stop "${status_dir}"
msg_success "Querying GitLab project names"
# read project_id to name mapping from cache
declare -A project_name_lookup=()
while read -r project_id project_name; do
project_name_lookup[${project_id}]=${project_name}
done < "${project_name_cache_file}"
# close project name cache lock
lock_close 11
# output mode JSON
if [[ ${output_format} == json ]]; then
jq --from-file <(
for project_id in $(jq '.[].project_id' <<< "${output}"); do
project_name=${project_name_lookup[${project_id}]}
printf 'map(if .project_id == %s then . + {"project_name": "%s"} else . end) | ' \
"${project_id}" "${project_name}"
done
printf .
) <<< "${output}"
exit 0
fi
# pretty print each result
while read -r result; do
# read properties from search result
mapfile -t data < <(jq --raw-output ".data" <<< "${result}")
{ read -r project_id; read -r path; read -r startline; } < <(
jq --raw-output ".project_id, .path, .startline" <<< "${result}"
)
project_name=${project_name_lookup[${project_id}]}
# remove trailing newline for multiline results
if (( ${#data[@]} > 1 )) && [[ ${data[-1]} == "" ]]; then
unset "data[${#data[@]}-1]"
fi
# output mode plain
if [[ ${output_format} == plain ]]; then
printf "%s%s%s\n" "${PURPLE}" "${project_name}/${path}" "${ALL_OFF}"
currentline=${startline}
for line in "${data[@]}"; do
if (( line_numbers )); then
line="${DARK_GREEN}${currentline}${ALL_OFF}: ${line}"
currentline=$(( currentline + 1 ))
fi
printf "%s\n" "${line}"
done
printf "\n"
continue
fi
# prepend empty lines to match startline
if (( startline > 1 )); then
mapfile -t data < <(
printf '%.0s\n' $(seq 1 "$(( startline - 1 ))")
printf "%s\n" "${data[@]}"
)
fi
bat \
--file-name="${project_name}/${path}" \
--line-range "${startline}:" \
--paging=never \
--force-colorization \
--style "${bat_style}" \
--map-syntax "PKGBUILD:Bourne Again Shell (bash)" \
--map-syntax ".SRCINFO:INI" \
--map-syntax "*install:Bourne Again Shell (bash)" \
--map-syntax "*sysusers*:Bourne Again Shell (bash)" \
--map-syntax "*tmpfiles*:Bourne Again Shell (bash)" \
--map-syntax "*.hook:INI" \
<(printf "%s\n" "${data[@]}")
done < <(jq --compact-output '.[]' <<< "${output}")
}

View File

@@ -7,6 +7,9 @@ DEVTOOLS_INCLUDE_UTIL_GIT_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
git_diff_tree() {
local commit=$1
@@ -22,3 +25,10 @@ git_diff_tree() {
"${commit}" \
-- "${path}"
}
git_warmup_ssh_connection() {
msg 'Establishing ssh connection to git@%s' "${GITLAB_HOST}"
if ! ssh -T "git@${GITLAB_HOST}" >/dev/null; then
die 'Failed to establish ssh connection to git@%s' "${GITLAB_HOST}"
fi
}

35
src/lib/util/makepkg.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_UTIL_MAKEPKG_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_UTIL_MAKEPKG_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/util/srcinfo.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/srcinfo.sh
set -e
makepkg_source_package() {
if (( EUID != 0 )); then
[[ -z ${WORKDIR:-} ]] && setup_workdir
export WORKDIR DEVTOOLS_INCLUDE_COMMON_SH
fakeroot -- bash -$- -c "source '${BASH_SOURCE[0]}' && ${FUNCNAME[0]}"
return
fi
(
export LIBMAKEPKG_LINT_PKGBUILD_SH=1
lint_pkgbuild() { :; }
export LIBMAKEPKG_SRCINFO_SH=1
write_srcinfo() { print_srcinfo; }
set +e -- -F --source
# shellcheck source=/usr/bin/makepkg
source "$(command -v makepkg)"
)
}

View File

@@ -38,13 +38,21 @@ get_pacman_repo_from_pkgbuild() {
return
fi
# update the pacman repo cache if it doesn't exist yet
if [[ ! -d "${_DEVTOOLS_PACMAN_CACHE_DIR}" ]]; then
update_pacman_repo_cache
fi
slock 10 "${_DEVTOOLS_PACMAN_CACHE_DIR}.lock" "Locking pacman database cache"
# query repo of passed pkgname, specify --nodeps twice to skip all dependency checks
mapfile -t repos < <(pacman --config "${_DEVTOOLS_PACMAN_CONF_DIR}/multilib.conf" \
--dbpath "${_DEVTOOLS_PACMAN_CACHE_DIR}" \
-S \
--sync \
--nodeps \
--nodeps \
--print \
--print-format '%n %r' \
"${pkgnames[0]}" | grep -E "^${pkgnames[0]} " | awk '{print $2}'
"${pkgnames[0]}" 2>/dev/null | awk '$1=="'"${pkgnames[0]}"'"{print $2}'
)
lock_close 10

43
src/lib/util/pkgbuild.sh Normal file
View File

@@ -0,0 +1,43 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_UTIL_PKGBUILD_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_UTIL_PKGBUILD_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
source /usr/share/makepkg/util/message.sh
set -e
# set the pkgver variable in a PKGBUILD
# assumes that the pkgbuild is sourced to detect the presence of a pkgver function
pkgbuild_set_pkgver() {
local new_pkgver=$1
local pkgver=${pkgver}
if [[ $(type -t pkgver) == function ]]; then
# TODO: check if die or warn, if we provide _commit _gitcommit setter maybe?
warning 'setting pkgver variable has no effect if the PKGBUILD has a pkgver() function'
fi
if ! grep --extended-regexp --quiet --max-count=1 "^pkgver=${pkgver}$" PKGBUILD; then
die "Non-standard pkgver declaration"
fi
sed --regexp-extended "s|^(pkgver=)${pkgver}$|\1${new_pkgver}|g" --in-place PKGBUILD
}
# set the pkgrel variable in a PKGBUILD
# assumes that the pkgbuild is sourced so pkgrel is present
pkgbuild_set_pkgrel() {
local new_pkgrel=$1
local pkgrel=${pkgrel}
if ! grep --extended-regexp --quiet --max-count=1 "^pkgrel=${pkgrel}$" PKGBUILD; then
die "Non-standard pkgrel declaration"
fi
sed --regexp-extended "s|^(pkgrel=)${pkgrel}$|\1${new_pkgrel}|g" --in-place PKGBUILD
}

69
src/lib/util/srcinfo.sh Normal file
View File

@@ -0,0 +1,69 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_UTIL_SRCINFO_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_UTIL_SRCINFO_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
source /usr/share/makepkg/util/util.sh
source /usr/share/makepkg/srcinfo.sh
set -eo pipefail
print_srcinfo() {
local pkgpath=${1:-.}
local outdir pkg pid
local pids=()
# source the PKGBUILD
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. "${pkgpath}"/PKGBUILD
# run without parallelization for single packages
if (( ${#pkgname[@]} == 1 )); then
write_srcinfo_content
return 0
fi
[[ -z ${WORKDIR:-} ]] && setup_workdir
outdir=$(mktemp --directory --tmpdir="${WORKDIR}" pkgctl-srcinfo.XXXXXXXXXX)
# fork workload for each split pkgname
for pkg in "${pkgname[@]}"; do
(
# deactivate errexit to avoid makepkg abort on grep_function
set +e
srcinfo_write_package "$pkg" > "${outdir}/${pkg}"
)&
pids+=($!)
done
# join workload
for pid in "${pids[@]}"; do
if ! wait "${pid}"; then
return 1
fi
done
# collect output
srcinfo_write_global
for pkg in "${pkgname[@]}"; do
srcinfo_separate_section
cat "${outdir}/${pkg}"
done
}
write_srcinfo_file() {
local pkgpath=${1:-.}
stat_busy 'Generating .SRCINFO'
if ! print_srcinfo "${pkgpath}" > "${pkgpath}"/.SRCINFO; then
error 'Failed to write .SRCINFO file'
return 1
fi
stat_done
}

182
src/lib/util/term.sh Normal file
View File

@@ -0,0 +1,182 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_UTIL_TERM_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_UTIL_TERM_SH=1
set -eo pipefail
readonly PKGCTL_TERM_SPINNER_DOTS=Dots
export PKGCTL_TERM_SPINNER_DOTS
readonly PKGCTL_TERM_SPINNER_DOTS12=Dots12
export PKGCTL_TERM_SPINNER_DOTS12
readonly PKGCTL_TERM_SPINNER_LINE=Line
export PKGCTL_TERM_SPINNER_LINE
readonly PKGCTL_TERM_SPINNER_SIMPLE_DOTS_SCROLLING=SimpleDotsScrolling
export PKGCTL_TERM_SPINNER_SIMPLE_DOTS_SCROLLING
readonly PKGCTL_TERM_SPINNER_TRIANGLE=Triangle
export PKGCTL_TERM_SPINNER_TRIANGLE
readonly PKGCTL_TERM_SPINNER_RANDOM=Random
export PKGCTL_TERM_SPINNER_RANDOM
readonly PKGCTL_TERM_SPINNER_TYPES=(
"${PKGCTL_TERM_SPINNER_DOTS}"
"${PKGCTL_TERM_SPINNER_DOTS12}"
"${PKGCTL_TERM_SPINNER_LINE}"
"${PKGCTL_TERM_SPINNER_SIMPLE_DOTS_SCROLLING}"
"${PKGCTL_TERM_SPINNER_TRIANGLE}"
)
export PKGCTL_TERM_SPINNER_TYPES
term_cursor_hide() {
tput civis >&2
}
term_cursor_show() {
tput cnorm >&2
}
term_cursor_up() {
tput cuu1
}
term_carriage_return() {
tput cr
}
term_erase_line() {
tput el
}
term_erase_lines() {
local lines=$1
local cursor_up erase_line
cursor_up=$(term_cursor_up)
erase_line="$(term_carriage_return)$(term_erase_line)"
local prefix=''
for _ in $(seq 1 "${lines}"); do
printf '%s' "${prefix}${erase_line}"
prefix="${cursor_up}"
done
}
_pkgctl_spinner_type=${PKGCTL_TERM_SPINNER_RANDOM}
term_spinner_set_type() {
_pkgctl_spinner_type=$1
}
# takes a status directory that can be used to dynamically update the spinner
# by writing to the `status` file inside that directory atomically.
# replace the placeholder %spinner% with the currently configured spinner type
term_spinner_start() {
local status_dir=$1
local parent_pid=$$
(
local spinner_type=${_pkgctl_spinner_type}
local spinner_offset=0
local frame_buffer=''
local spinner status_message line
local status_file="${status_dir}/status"
local next_file="${status_dir}/next"
local drawn_file="${status_dir}/drawn"
# assign random spinner type
if [[ ${spinner_type} == "${PKGCTL_TERM_SPINNER_RANDOM}" ]]; then
spinner_type=${PKGCTL_TERM_SPINNER_TYPES[$((RANDOM % ${#PKGCTL_TERM_SPINNER_TYPES[@]}))]}
fi
# select spinner based on the named type
case "${spinner_type}" in
"${PKGCTL_TERM_SPINNER_DOTS}")
spinner=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏")
update_interval=0.08
;;
"${PKGCTL_TERM_SPINNER_DOTS12}")
spinner=("⢀⠀" "⡀⠀" "⠄⠀" "⢂⠀" "⡂⠀" "⠅⠀" "⢃⠀" "⡃⠀" "⠍⠀" "⢋⠀" "⡋⠀" "⠍⠁" "⢋⠁" "⡋⠁" "⠍⠉" "⠋⠉" "⠋⠉" "⠉⠙" "⠉⠙" "⠉⠩" "⠈⢙" "⠈⡙" "⢈⠩" "⡀⢙" "⠄⡙" "⢂⠩" "⡂⢘" "⠅⡘" "⢃⠨" "⡃⢐" "⠍⡐" "⢋⠠" "⡋⢀" "⠍⡁" "⢋⠁" "⡋⠁" "⠍⠉" "⠋⠉" "⠋⠉" "⠉⠙" "⠉⠙" "⠉⠩" "⠈⢙" "⠈⡙" "⠈⠩" "⠀⢙" "⠀⡙" "⠀⠩" "⠀⢘" "⠀⡘" "⠀⠨" "⠀⢐" "⠀⡐" "⠀⠠" "⠀⢀" "⠀⡀")
update_interval=0.08
;;
"${PKGCTL_TERM_SPINNER_LINE}")
spinner=("⎯" "\\" "|" "/")
update_interval=0.13
;;
"${PKGCTL_TERM_SPINNER_SIMPLE_DOTS_SCROLLING}")
spinner=(". " ".. " "..." " .." " ." " ")
update_interval=0.2
;;
"${PKGCTL_TERM_SPINNER_TRIANGLE}")
spinner=("◢" "◣" "◤" "◥")
update_interval=0.05
;;
esac
# hide the cursor while spinning
term_cursor_hide
# run the spinner as long as the parent process didn't terminate
while ps -p "${parent_pid}" &>/dev/null; do
# cache the new status template if it exists
if mv "${status_file}" "${next_file}" &>/dev/null; then
status_message="$(cat "$next_file")"
elif [[ -z "${status_message}" ]]; then
# wait until we either have a new or cached status
sleep 0.05
fi
# fill the frame buffer with the current status
local prefix=''
while IFS= read -r line; do
# replace spinner placeholder
line=${line//%spinner%/${spinner[spinner_offset%${#spinner[@]}]}}
# append the current line to the frame buffer
frame_buffer+="${prefix}${line}"
prefix=$'\n'
done <<< "${status_message}"
# print current frame buffer
echo -n "${frame_buffer}" >&2
mv "${next_file}" "${drawn_file}" &>/dev/null ||:
# setup next frame buffer to clear current content
frame_buffer=$(term_erase_lines "$(awk 'END {print NR}' <<< "${status_message}")")
# advance the spinner animation offset
(( ++spinner_offset ))
# sleep for the spinner update interval
sleep "${update_interval}"
done
)&
_pkgctl_spinner_pid=$!
disown
}
term_spinner_stop() {
local status_dir=$1
local frame_buffer status_file
# kill the spinner process
if ! kill "${_pkgctl_spinner_pid}" > /dev/null 2>&1; then
return 1
fi
unset _pkgctl_spinner_pid
# acquire last drawn status
status_file="${status_dir}/drawn"
if [[ ! -f ${status_file} ]]; then
return 0
fi
# clear terminal based on last status line
frame_buffer=$(term_erase_lines "$(awk 'END {print NR}' < "${status_file}")")
echo -n "${frame_buffer}" >&2
# show the cursor after stopping the spinner
term_cursor_show
}

View File

@@ -0,0 +1,11 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
:
# shellcheck disable=2034
DEVTOOLS_VALID_BUILD_INSTALL=(
none
auto
all
)

10
src/lib/valid-inspect.sh Normal file
View File

@@ -0,0 +1,10 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
# shellcheck disable=2034
DEVTOOLS_VALID_INSPECT_MODES=(
never
always
failure
)

View File

@@ -4,7 +4,7 @@
:
# shellcheck disable=2034
_repos=(
DEVTOOLS_VALID_REPOS=(
core core-staging core-testing
extra extra-staging extra-testing
multilib multilib-staging multilib-testing
@@ -13,8 +13,9 @@ _repos=(
)
# shellcheck disable=2034
_build_repos=(
extra staging testing
DEVTOOLS_VALID_BUILDREPOS=(
core-staging core-testing
extra extra-staging extra-testing
multilib multilib-staging multilib-testing
gnome-unstable
kde-unstable

11
src/lib/valid-search.sh Normal file
View File

@@ -0,0 +1,11 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
:
# shellcheck disable=2034
valid_search_output_format=(
pretty
plain
json
)

View File

@@ -4,13 +4,13 @@
:
# shellcheck disable=2034
_arch=(
DEVTOOLS_VALID_ARCHES=(
x86_64
any
)
# shellcheck disable=2034
_tags=(
DEVTOOLS_VALID_TAGS=(
core-x86_64 core-any
core-staging-x86_64 core-staging-any
core-testing-x86_64 core-testing-any

65
src/lib/version.sh Normal file
View File

@@ -0,0 +1,65 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_VERSION_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_VERSION_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
set -e
pkgctl_version_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [COMMAND] [OPTIONS]
Check and manage package versions against upstream.
COMMANDS
check Compares local package versions against upstream
upgrade Adjust the PKGBUILD to match the latest upstream version
OPTIONS
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} check libfoo linux libbar
_EOF_
}
pkgctl_version() {
if (( $# < 1 )); then
pkgctl_version_usage
exit 0
fi
while (( $# )); do
case $1 in
-h|--help)
pkgctl_version_usage
exit 0
;;
check)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/version/check.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/check.sh
pkgctl_version_check "$@"
exit $?
;;
upgrade)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/version/upgrade.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/upgrade.sh
pkgctl_version_upgrade "$@"
exit $?
;;
*)
die "invalid argument: %s" "$1"
;;
esac
done
}

340
src/lib/version/check.sh Normal file
View File

@@ -0,0 +1,340 @@
#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
[[ -z ${DEVTOOLS_INCLUDE_VERSION_CHECK_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_VERSION_CHECK_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/util/term.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/term.sh
source /usr/share/makepkg/util/message.sh
set -eo pipefail
readonly PKGCTL_VERSION_CHECK_EXIT_UP_TO_DATE=0
export PKGCTL_VERSION_CHECK_EXIT_UP_TO_DATE
readonly PKGCTL_VERSION_CHECK_EXIT_OUT_OF_DATE=2
export PKGCTL_VERSION_CHECK_EXIT_OUT_OF_DATE
readonly PKGCTL_VERSION_CHECK_EXIT_FAILURE=3
export PKGCTL_VERSION_CHECK_EXIT_FAILURE
pkgctl_version_check_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS] [PKGBASE]...
Compares the versions of packages in the local packaging repository against
their latest upstream versions.
Upon execution, it generates a grouped list that provides detailed insights
into each package's status. For each package, it displays the current local
version alongside the latest version available upstream.
Outputs a summary of up-to-date packages, out-of-date packages, and any
check failures.
OPTIONS
-v, --verbose Display results including up-to-date versions
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} neovim vim
_EOF_
}
pkgctl_version_check() {
local pkgbases=()
local verbose=0
local path status_file path pkgbase upstream_version result
local up_to_date=()
local out_of_date=()
local failure=()
local current_item=0
local section_separator=''
local exit_code=${PKGCTL_VERSION_CHECK_EXIT_UP_TO_DATE}
while (( $# )); do
case $1 in
-h|--help)
pkgctl_version_check_usage
exit 0
;;
-v|--verbose)
verbose=1
shift
;;
--)
shift
break
;;
-*)
die "invalid argument: %s" "$1"
;;
*)
pkgbases=("$@")
break
;;
esac
done
if ! command -v nvchecker &>/dev/null; then
die "The \"$_DEVTOOLS_COMMAND\" command requires 'nvchecker'"
fi
# Check if used without pkgbases in a packaging directory
if (( ${#pkgbases[@]} == 0 )); then
if [[ -f PKGBUILD ]]; then
pkgbases=(".")
else
pkgctl_version_check_usage
exit 1
fi
fi
# enable verbose mode when we only have a single item to check
if (( ${#pkgbases[@]} == 1 )); then
verbose=1
fi
# start a terminal spinner as checking versions takes time
status_dir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-version-check-spinner.XXXXXXXXXX)
term_spinner_start "${status_dir}"
for path in "${pkgbases[@]}"; do
pushd "${path}" >/dev/null
if [[ ! -f "PKGBUILD" ]]; then
die "No PKGBUILD found for ${path}"
fi
# update the current terminal spinner status
(( ++current_item ))
pkgctl_version_check_spinner \
"${status_dir}" \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}" \
"${current_item}" \
"${#pkgbases[@]}"
# reset common PKGBUILD variables
unset pkgbase pkgname arch source pkgver pkgrel validpgpkeys
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. ./PKGBUILD
pkgbase=${pkgbase:-$pkgname}
if ! result=$(get_upstream_version); then
result="${BOLD}${pkgbase}${ALL_OFF}: ${result}"
failure+=("${result}")
popd >/dev/null
continue
fi
upstream_version=${result}
if ! result=$(vercmp "${upstream_version}" "${pkgver}"); then
result="${BOLD}${pkgbase}${ALL_OFF}: failed to compare version ${upstream_version} against ${pkgver}"
failure+=("${result}")
popd >/dev/null
continue
fi
if (( result == 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is latest"
up_to_date+=("${result}")
elif (( result < 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is newer than ${DARK_GREEN}${upstream_version}${ALL_OFF}"
up_to_date+=("${result}")
elif (( result > 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: upgrade from version ${PURPLE}${pkgver}${ALL_OFF} to ${DARK_GREEN}${upstream_version}${ALL_OFF}"
out_of_date+=("${result}")
fi
popd >/dev/null
done
# stop the terminal spinner after all checks
term_spinner_stop "${status_dir}"
if (( verbose )) && (( ${#up_to_date[@]} > 0 )); then
printf "%sUp-to-date%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${up_to_date[@]}"; do
msg_success " ${result}"
done
fi
if (( ${#failure[@]} > 0 )); then
exit_code=${PKGCTL_VERSION_CHECK_EXIT_FAILURE}
printf "%sFailure%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${failure[@]}"; do
msg_error " ${result}"
done
fi
if (( ${#out_of_date[@]} > 0 )); then
exit_code=${PKGCTL_VERSION_CHECK_EXIT_OUT_OF_DATE}
printf "%sOut-of-date%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${out_of_date[@]}"; do
msg_warn " ${result}"
done
fi
# Show summary when processing multiple packages
if (( ${#pkgbases[@]} > 1 )); then
printf '%s' "${section_separator}"
pkgctl_version_check_summary \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}"
fi
# return status based on results
return "${exit_code}"
}
get_upstream_version() {
local config=.nvchecker.toml
local output errors upstream_version
local output
local opts=()
local keyfile="${XDG_CONFIG_HOME:-${HOME}/.config}/nvchecker/keyfile.toml"
# check nvchecker config file
if ! errors=$(nvchecker_check_config "${config}"); then
printf "%s" "${errors}"
return 1
fi
# populate keyfile to nvchecker opts
if [[ -f ${keyfile} ]]; then
opts+=(--keyfile "${keyfile}")
fi
if ! output=$(nvchecker --file "${config}" --logger json "${opts[@]}" 2>&1 | \
jq --raw-output 'select(.level != "debug")'); then
printf "failed to run nvchecker: %s" "${output}"
return 1
fi
if ! errors=$(nvchecker_check_error "${output}"); then
printf "%s" "${errors}"
return 1
fi
if ! upstream_version=$(jq --raw-output --exit-status '.version' <<< "${output}"); then
printf "failed to select version from result"
return 1
fi
printf "%s" "${upstream_version}"
return 0
}
nvchecker_check_config() {
local config=$1
local restricted_properties=(keyfile httptoken token)
local property
# check if the config file exists
if [[ ! -f ${config} ]]; then
printf "configuration file not found: %s" "${config}"
return 1
fi
# check if config contains any restricted properties like secrets
for property in "${restricted_properties[@]}"; do
if grep --max-count=1 --quiet "^${property}" < "${config}"; then
printf "restricted property in %s: %s" "${config}" "${property}"
return 1
fi
done
# check if the config contains a pkgbase section
if [[ -n ${pkgbase} ]] && ! grep --max-count=1 --extended-regexp --quiet "^\\[\"?${pkgbase}\"?\\]" < "${config}"; then
printf "missing pkgbase section in %s: %s" "${config}" "${pkgbase}"
return 1
fi
# check if the config contains any section other than pkgbase
if [[ -n ${pkgbase} ]] && property=$(grep --max-count=1 --perl-regexp "^\\[(?!\"?${pkgbase}\"?\\]).+\\]" < "${config}"); then
printf "non-pkgbase section not supported in %s: %s" "${config}" "${property}"
return 1
fi
}
nvchecker_check_error() {
local result=$1
local errors
if ! errors=$(jq --raw-output --exit-status \
'select(.level == "error") | "\(.event)" + if .error then ": \(.error)" else "" end' \
<<< "${result}"); then
return 0
fi
mapfile -t errors <<< "${errors}"
printf "%s\n" "${errors[@]}"
return 1
}
pkgctl_version_check_summary() {
local up_to_date_count=$1
local out_of_date_count=$2
local failure_count=$3
# print nothing if all stats are zero
if (( up_to_date_count == 0 )) && \
(( out_of_date_count == 0 )) && \
(( failure_count == 0 )); then
return 0
fi
# print summary for all none zero stats
printf "%sSummary%s\n" "${BOLD}${UNDERLINE}" "${ALL_OFF}"
if (( up_to_date_count > 0 )); then
msg_success " Up-to-date: ${BOLD}${up_to_date_count}${ALL_OFF}" 2>&1
fi
if (( failure_count > 0 )); then
msg_error " Failure: ${BOLD}${failure_count}${ALL_OFF}" 2>&1
fi
if (( out_of_date_count > 0 )); then
msg_warn " Out-of-date: ${BOLD}${out_of_date_count}${ALL_OFF}" 2>&1
fi
}
pkgctl_version_check_spinner() {
local status_dir=$1
local up_to_date_count=$2
local out_of_date_count=$3
local failure_count=$4
local current=$5
local total=$6
local percentage=$(( 100 * current / total ))
local tmp_file="${status_dir}/tmp"
local status_file="${status_dir}/status"
# print the current summary
pkgctl_version_check_summary \
"${up_to_date_count}" \
"${out_of_date_count}" \
"${failure_count}" > "${tmp_file}"
# print the progress status
printf "📡 Checking: %s/%s [%s] %%spinner%%" \
"${BOLD}${current}" "${total}" "${percentage}%${ALL_OFF}" \
>> "${tmp_file}"
# swap the status file
mv "${tmp_file}" "${status_file}"
}

248
src/lib/version/upgrade.sh Normal file
View File

@@ -0,0 +1,248 @@
#!/bin/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
[[ -z ${DEVTOOLS_INCLUDE_VERSION_UPGRADE_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_VERSION_UPGRADE_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/version/check.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/check.sh
# shellcheck source=src/lib/util/pkgbuild.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/pkgbuild.sh
# shellcheck source=src/lib/util/term.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/term.sh
source /usr/share/makepkg/util/message.sh
set -e
pkgctl_version_upgrade_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS] [PKGBASE]...
Streamlines the process of keeping PKGBUILD files up-to-date with the latest
upstream versions.
Upon execution, it automatically adjusts the PKGBUILD file, ensuring that the
pkgver field is set to match the latest version available from the upstream
source. In addition to updating the pkgver, this command also resets the pkgrel
to 1.
Outputs a summary of upgraded packages, up-to-date packages, and any check
failures.
OPTIONS
-v, --verbose Display results including up-to-date versions
-h, --help Show this help text
EXAMPLES
$ ${COMMAND} neovim vim
_EOF_
}
pkgctl_version_upgrade() {
local path upstream_version result
local pkgbases=()
local verbose=0
local exit_code=0
local current_item=0
while (( $# )); do
case $1 in
-h|--help)
pkgctl_version_upgrade_usage
exit 0
;;
-v|--verbose)
verbose=1
shift
;;
--)
shift
break
;;
-*)
die "invalid argument: %s" "$1"
;;
*)
pkgbases=("$@")
break
;;
esac
done
if ! command -v nvchecker &>/dev/null; then
die "The \"$_DEVTOOLS_COMMAND\" command requires 'nvchecker'"
fi
# Check if used without pkgbases in a packaging directory
if (( ${#pkgbases[@]} == 0 )); then
if [[ -f PKGBUILD ]]; then
pkgbases=(".")
else
pkgctl_version_upgrade_usage
exit 1
fi
fi
# enable verbose mode when we only have a single item to check
if (( ${#pkgbases[@]} == 1 )); then
verbose=1
fi
# start a terminal spinner as checking versions takes time
status_dir=$(mktemp --tmpdir="${WORKDIR}" --directory pkgctl-version-check-spinner.XXXXXXXXXX)
term_spinner_start "${status_dir}"
for path in "${pkgbases[@]}"; do
pushd "${path}" >/dev/null
if [[ ! -f "PKGBUILD" ]]; then
die "No PKGBUILD found for ${path}"
fi
# update the current terminal spinner status
(( ++current_item ))
pkgctl_version_upgrade_spinner \
"${status_dir}" \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}" \
"${current_item}" \
"${#pkgbases[@]}"
# reset common PKGBUILD variables
unset pkgbase pkgname arch source pkgver pkgrel validpgpkeys
# shellcheck source=contrib/makepkg/PKGBUILD.proto
. ./PKGBUILD
pkgbase=${pkgbase:-$pkgname}
if ! result=$(get_upstream_version); then
result="${BOLD}${pkgbase}${ALL_OFF}: ${result}"
failure+=("${result}")
popd >/dev/null
continue
fi
upstream_version=${result}
if ! result=$(vercmp "${upstream_version}" "${pkgver}"); then
result="${BOLD}${pkgbase}${ALL_OFF}: failed to compare version ${upstream_version} against ${pkgver}"
failure+=("${result}")
popd >/dev/null
continue
fi
if (( result == 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is latest"
up_to_date+=("${result}")
elif (( result < 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: current version ${PURPLE}${pkgver}${ALL_OFF} is newer than ${DARK_GREEN}${upstream_version}${ALL_OFF}"
up_to_date+=("${result}")
elif (( result > 0 )); then
result="${BOLD}${pkgbase}${ALL_OFF}: upgraded from version ${PURPLE}${pkgver}${ALL_OFF} to ${DARK_GREEN}${upstream_version}${ALL_OFF}"
out_of_date+=("${result}")
# change the PKGBUILD
pkgbuild_set_pkgver "${upstream_version}"
pkgbuild_set_pkgrel 1
fi
popd >/dev/null
done
# stop the terminal spinner after all checks
term_spinner_stop "${status_dir}"
if (( verbose )) && (( ${#up_to_date[@]} > 0 )); then
printf "%sUp-to-date%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${up_to_date[@]}"; do
msg_success " ${result}"
done
fi
if (( ${#failure[@]} > 0 )); then
exit_code=1
printf "%sFailure%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${failure[@]}"; do
msg_error " ${result}"
done
fi
if (( ${#out_of_date[@]} > 0 )); then
printf "%sUpgraded%s\n" "${section_separator}${BOLD}${UNDERLINE}" "${ALL_OFF}"
section_separator=$'\n'
for result in "${out_of_date[@]}"; do
msg_warn " ${result}"
done
fi
# Show summary when processing multiple packages
if (( ${#pkgbases[@]} > 1 )); then
printf '%s' "${section_separator}"
pkgctl_version_upgrade_summary \
"${#up_to_date[@]}" \
"${#out_of_date[@]}" \
"${#failure[@]}"
fi
# return status based on results
return "${exit_code}"
}
pkgctl_version_upgrade_summary() {
local up_to_date_count=$1
local out_of_date_count=$2
local failure_count=$3
# print nothing if all stats are zero
if (( up_to_date_count == 0 )) && \
(( out_of_date_count == 0 )) && \
(( failure_count == 0 )); then
return 0
fi
# print summary for all none zero stats
printf "%sSummary%s\n" "${BOLD}${UNDERLINE}" "${ALL_OFF}"
if (( up_to_date_count > 0 )); then
msg_success " Up-to-date: ${BOLD}${up_to_date_count}${ALL_OFF}" 2>&1
fi
if (( failure_count > 0 )); then
msg_error " Failure: ${BOLD}${failure_count}${ALL_OFF}" 2>&1
fi
if (( out_of_date_count > 0 )); then
msg_warn " Upgraded: ${BOLD}${out_of_date_count}${ALL_OFF}" 2>&1
fi
}
pkgctl_version_upgrade_spinner() {
local status_dir=$1
local up_to_date_count=$2
local out_of_date_count=$3
local failure_count=$4
local current=$5
local total=$6
local percentage=$(( 100 * current / total ))
local tmp_file="${status_dir}/tmp"
local status_file="${status_dir}/status"
# print the current summary
pkgctl_version_upgrade_summary \
"${up_to_date_count}" \
"${out_of_date_count}" \
"${failure_count}" > "${tmp_file}"
# print the progress status
printf "📡 Upgrading: %s/%s [%s] %%spinner%%" \
"${BOLD}${current}" "${total}" "${percentage}%${ALL_OFF}" \
>> "${tmp_file}"
# swap the status file
mv "${tmp_file}" "${status_file}"
}

View File

@@ -1,47 +0,0 @@
#!/hint/bash
#
# SPDX-License-Identifier: GPL-3.0-or-later
[[ -z ${DEVTOOLS_INCLUDE_VERSION_SH:-} ]] || return 0
DEVTOOLS_INCLUDE_VERSION_SH=1
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
source /usr/share/makepkg/util/message.sh
set -e
pkgctl_version_usage() {
local -r COMMAND=${_DEVTOOLS_COMMAND:-${BASH_SOURCE[0]##*/}}
cat <<- _EOF_
Usage: ${COMMAND} [OPTIONS]
Shows the current version information of pkgctl
OPTIONS
-h, --help Show this help text
_EOF_
}
pkgctl_version_print() {
cat <<- _EOF_
pkgctl @buildtoolver@
_EOF_
}
pkgctl_version() {
while (( $# )); do
case $1 in
-h|--help)
pkgctl_version_usage
exit 0
;;
*)
die "invalid argument: %s" "$1"
;;
esac
done
pkgctl_version_print
}

View File

@@ -8,9 +8,12 @@ _DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/archroot.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/archroot.sh
# shellcheck source=src/lib/valid-inspect.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/valid-inspect.sh
source /usr/share/makepkg/util/config.sh
source /usr/share/makepkg/util/util.sh
shopt -s nullglob
@@ -31,6 +34,8 @@ run_checkpkg=0
temp_chroot=0
tmp_opts="nosuid,nodev,size=50%,nr_inodes=2m"
inspect=never
bindmounts_ro=()
bindmounts_rw=()
@@ -76,6 +81,7 @@ usage() {
echo '-C Run checkpkg on the package'
echo '-T Build in a temporary directory'
echo '-U Run makepkg as a specified user'
echo '-x <when> Inspect chroot after build (never, always, failure)'
exit 1
}
@@ -280,7 +286,7 @@ move_products() {
}
# }}}
while getopts 'hcur:I:l:nCTD:d:U:' arg; do
while getopts 'hcur:I:l:nCTD:d:U:x:' arg; do
case "$arg" in
c) clean_first=1 ;;
D) bindmounts_ro+=("--bind-ro=$OPTARG") ;;
@@ -293,6 +299,7 @@ while getopts 'hcur:I:l:nCTD:d:U:' arg; do
C) run_checkpkg=1 ;;
T) temp_chroot=1; copy+="-$$" ;;
U) makepkg_user="$OPTARG" ;;
x) inspect="$OPTARG" ;;
h|*) usage ;;
esac
done
@@ -314,6 +321,10 @@ else
copydir="$chrootdir/$copy"
fi
if ! in_array "${inspect}" "${DEVTOOLS_VALID_INSPECT_MODES[@]}"; then
die "Invalid inspect mode: %s" "${inspect}"
fi
# Pass all arguments after -- right to makepkg
makepkg_args+=("${@:$OPTIND}")
@@ -368,11 +379,16 @@ download_sources
prepare_chroot
nspawn_build_args=(
--bind="${PWD//:/\\:}:/startdir"
--bind="${SRCDEST//:/\\:}:/srcdest"
--tmpfs="/tmp:${tmp_opts}"
"${bindmounts_ro[@]}"
"${bindmounts_rw[@]}"
)
if arch-nspawn "$copydir" \
--bind="${PWD//:/\\:}:/startdir" \
--bind="${SRCDEST//:/\\:}:/srcdest" \
--tmpfs="/tmp:${tmp_opts}" \
"${bindmounts_ro[@]}" "${bindmounts_rw[@]}" \
"${nspawn_build_args[@]}" \
/chrootbuild "${makepkg_args[@]}"
then
mapfile -t pkgnames < <(sudo -u "$makepkg_user" bash -c 'source PKGBUILD; printf "%s\n" "${pkgname[@]}"')
@@ -382,6 +398,18 @@ else
move_logfiles
fi
if [[ $inspect == always ]] || ( [[ $inspect == failure ]] && (( ret != 0 )) ); then
if (( ret == 0 )); then
msg "Build succeeded, inspecting %s" "$copydir"
else
error "Build failed, inspecting %s" "$copydir"
fi
arch-nspawn "$copydir" \
"${nspawn_build_args[@]}" \
--user=builduser \
--chdir=/build
fi
(( temp_chroot )) && delete_chroot "$copydir" "$copy"
if (( ret != 0 )); then

View File

@@ -22,6 +22,7 @@ declare -a buildenv buildopts installed installpkgs
archiveurl='https://archive.archlinux.org/packages'
buildroot=/var/lib/archbuild/reproducible
diffoscope=0
makepkg_options=()
chroot=$USER
[[ -n ${SUDO_USER:-} ]] && chroot=$SUDO_USER
@@ -116,6 +117,7 @@ For more details see https://reproducible-builds.org/
OPTIONS
-d Run diffoscope if the package is unreproducible
-n Do not run the check() function in the PKGBUILD
-c <dir> Set pacman cache
-M <file> Location of a makepkg config file
-l <chroot> The directory name to use as the chroot namespace
@@ -125,9 +127,13 @@ OPTIONS
__EOF__
}
while getopts 'dM:c:l:h' arg; do
# save all args for check_root
orig_args=("$@")
while getopts 'dnM:c:l:h' arg; do
case "$arg" in
d) diffoscope=1 ;;
n) makepkg_options+=(--nocheck) ;;
M) archroot_args+=(-M "$OPTARG") ;;
c) cache_dirs+=("$OPTARG") ;;
l) chroot="$OPTARG" ;;
@@ -137,7 +143,7 @@ while getopts 'dM:c:l:h' arg; do
done
shift $((OPTIND - 1))
check_root "" "${BASH_SOURCE[0]}" "$@"
check_root "" "${BASH_SOURCE[0]}" "${orig_args[@]}"
[[ -f PKGBUILD ]] || { error "No PKGBUILD in current directory."; exit 1; }
@@ -251,7 +257,7 @@ install -d -o "${SUDO_UID:-$UID}" -g "$(id -g "${SUDO_UID:-$UID}")" "${namespace
arch-nspawn "${namespace}/build" \
--bind="${PWD}:/startdir" \
--bind="${SRCDEST}:/srcdest" \
/chrootbuild -C --noconfirm --log --holdver --skipinteg
/chrootbuild -C --noconfirm --log --holdver --skipinteg "${makepkg_options[@]}"
ret=$?
if (( ${ret} == 0 )); then

View File

@@ -32,6 +32,9 @@ usage() {
exit 1
}
# save all args for check_root
orig_args=("$@")
while getopts 'hUC:M:c:f:s' arg; do
case "$arg" in
U) umode=U ;;
@@ -52,7 +55,7 @@ shift $((OPTIND - 1))
(( $# < 2 )) && die 'You must specify a directory and one or more packages.'
check_root "" "${BASH_SOURCE[0]}" "$@"
check_root "" "${BASH_SOURCE[0]}" "${orig_args[@]}"
working_dir="$(readlink -f "$1")"
shift 1

View File

@@ -6,16 +6,24 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
_DEVTOOLS_LIBRARY_DIR=${_DEVTOOLS_LIBRARY_DIR:-@pkgdatadir@}
# shellcheck source=src/lib/common.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/common.sh
# shellcheck source=src/lib/util/makepkg.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/util/makepkg.sh
source /usr/share/makepkg/util/config.sh
# Deprecation warning
if [[ -z $_DEVTOOLS_COMMAND ]]; then
warning "${0##*/} is deprecated and will be removed. Use 'pkgctl build --offload' instead"
fi
# global defaults suitable for use by Arch staff
repo=extra
arch=x86_64
server=build.archlinux.org
die() { printf "error: $1\n" "${@:2}"; exit 1; }
usage() {
cat <<- _EOF_
Usage: ${BASH_SOURCE[0]##*/} [--repo REPO] [--arch ARCHITECTURE] [--server SERVER] -- [ARCHBUILD_ARGS]
@@ -79,7 +87,7 @@ load_makepkg_config
# transferred, including local sources, install scripts, and changelogs.
export TEMPDIR=$(mktemp -d --tmpdir offload-build.XXXXXXXXXX)
export SRCPKGDEST=${TEMPDIR}
makepkg --source || die "unable to make source package"
makepkg_source_package || die "unable to make source package"
# Temporary cosmetic workaround makepkg if SRCDEST is set somewhere else
# but an empty src dir is created in PWD. Remove once fixed in makepkg.

View File

@@ -19,13 +19,15 @@ usage() {
Unified command-line frontend for devtools.
COMMANDS
aur Interact with the Arch User Repository
auth Authenticate with services like GitLab
build Build packages inside a clean chroot
db Pacman database modification for packge update, move etc
db Pacman database modification for package update, move etc
diff Compare package files using different modes
release Release step to commit, tag and upload build artifacts
repo Manage Git packaging repositories and their configuration
version Show pkgctl version information
search Search for an expression across the GitLab packaging group
version Check and manage package versions against upstream
OPTIONS
-h, --help Show this help text
@@ -37,8 +39,16 @@ if (( $# < 1 )); then
exit 1
fi
pkgctl_version_print() {
cat <<- _EOF_
pkgctl @buildtoolver@
_EOF_
}
export _DEVTOOLS_COMMAND='pkgctl'
setup_workdir
load_devtools_config
# command checking
@@ -48,6 +58,14 @@ while (( $# )); do
usage
exit 0
;;
aur)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/aur.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/aur.sh
pkgctl_aur "$@"
exit 0
;;
build)
_DEVTOOLS_COMMAND+=" $1"
shift
@@ -94,14 +112,28 @@ while (( $# )); do
pkgctl_release "$@"
exit 0
;;
version|--version|-V)
search)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/version/version.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version/version.sh
# shellcheck source=src/lib/release.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/search.sh
pkgctl_search "$@"
exit 0
;;
version)
_DEVTOOLS_COMMAND+=" $1"
shift
# shellcheck source=src/lib/version.sh
source "${_DEVTOOLS_LIBRARY_DIR}"/lib/version.sh
pkgctl_version "$@"
exit 0
;;
--version|-V)
_DEVTOOLS_COMMAND+=" $1"
shift
pkgctl_version_print
exit 0
;;
*)
die "invalid command: %s" "$1"
;;

View File

@@ -31,7 +31,7 @@ recache() {
(( VERBOSE )) && verbosity=--progress-bar
for repo in "${_repos[@]}"; do
for repo in "${DEVTOOLS_VALID_REPOS[@]}"; do
if [[ -n "$SOLINKS_MIRROR" ]]; then
mirror="$SOLINKS_MIRROR"
elif ! mirror="$(set -o pipefail; pacman-conf --repo "$repo" Server 2>/dev/null | head -n1)"; then
@@ -72,7 +72,7 @@ is_outdated_cache() {
# links databases are generated at about the same time every day; we should
# attempt to check for new database files if any of them are over a day old
for repo in "${_repos[@]}"; do
for repo in "${DEVTOOLS_VALID_REPOS[@]}"; do
for arch in "${arches[@]}"; do
local dbpath=${SOCACHE_DIR}/${arch}/${repo}.links.tar.gz
if [[ ! -f ${dbpath} ]] || [[ $(find "${dbpath}" -mtime +0) ]]; then
@@ -85,10 +85,10 @@ is_outdated_cache() {
}
search() {
local repo=$1 arch lib=$2 srepos=("${_repos[@]}")
local repo=$1 arch lib=$2 srepos=("${DEVTOOLS_VALID_REPOS[@]}")
if [[ $repo != all ]]; then
if ! in_array "${repo}" "${_repos[@]}"; then
if ! in_array "${repo}" "${DEVTOOLS_VALID_REPOS[@]}"; then
echo "${BASH_SOURCE[0]##*/}: unrecognized repo '$repo'"
echo "Try '${BASH_SOURCE[0]##*/} --help' for more information."
exit 1