Source code for meta_package_manager.managers.pkgit
# Copyright Kevin Deldycke <[email protected]> and contributors.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import annotations
import re
from extra_platforms import LINUX_LIKE
from ..capabilities import search_capabilities, version_not_implemented
from ..manager import PackageManager
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterator
from ..package import Package
[docs]
class Pkgit(PackageManager):
"""pkgit, which compiles and installs packages straight from git repositories.
A package is a git repository the user declares in `~/.config/pkgit/init.lua`,
which pkgit clones and builds through the repository's own `bldit.lua`
recipe. That configuration is the registry: pkgit reaches no catalog of its
own and fronts no other package manager, so it is wrapped on its own terms
rather than declined as a translation layer.
```{note}
The configuration is mandatory, and its absence is what makes an
unconfigured pkgit correctly undetectable: every subcommand, `--version`
included, exits `1` with `cannot run configuration script`, so the version
probe finds nothing and mpm reports the manager unavailable until
`make defconfig` has run.
```
```{caution}
`remove` is deliberately absent. `pkgit --remove <package>` aborts on a
package declared in `init.lua`, with `'repositories' is not a table.`
followed by `PANIC: unprotected error in call to Lua API (attempt to index
a nil value)`, exiting `1` and leaving the package installed. It succeeds
only on a repository pulled in as a build dependency, and even then leaves
the checkout behind so {meth}`installed` keeps reporting it.
```
```{note}
A listing carries no version. pkgit enumerates the directories under its
share tree, one per cloned repository, and a package is whatever `HEAD`
currently points at, so there is nothing to report as an installed version.
Build dependencies are cloned as packages too and appear alongside what was
asked for.
```
Documentation: [pkgit README](https://git.symlinx.net/pkgit/about/).
"""
name = "pkgit"
homepage_url = "https://git.symlinx.net/pkgit"
platforms = LINUX_LIKE
"""`src/files.c` opens with `O_NOFOLLOW` behind no feature-test macro, which
is why the build fails on macOS and the claim stops at Linux.
"""
requirement = ">=1.2.0"
"""The release carrying both the verb set driven here and the listing shape
parsed below: `src/list_pkgs.c` already prints one bare name per line there.
The floor cannot be tighter than that even where it should be. pkgit has not
bumped `VERSION` since the tag, so the 58 commits on top of it report
`1.2.0` too, and no version string separates the two.
"""
_INSTALLED_REGEXP = re.compile(r"^(?P<package_id>\S+)$")
version_regexes = (r"(?P<version>\d+\S*)",)
"""
```{code-block} shell-session
$ pkgit --version
1.2.0
```
"""
@property
def installed(self) -> Iterator[Package]:
"""Fetch installed packages.
```{note}
An empty listing is the honest answer on a machine that has installed
nothing: pkgit exits `0` with `could not open <share tree>` on
`<stderr>` before the directory exists, and reports no package, which is
the same thing.
```
```{code-block} shell-session
$ pkgit --list
git
pkgit
luajit.git
```
"""
output = self.run_cli("--list")
yield from self.parse_regex_lines(self._INSTALLED_REGEXP, output)
[docs]
@search_capabilities(extended_support=False, exact_support=False)
def search(self, query: str, extended: bool, exact: bool) -> Iterator[Package]:
"""Fetch matching packages.
Only the repositories the configuration declares are searched, and the
result is a bare name, so mpm's own refiltering narrows whatever comes
back.
```{caution}
Search does not support extended or exact matching.
```
```{code-block} shell-session
$ pkgit --search pkgit
pkgit
```
"""
output = self.run_cli("--search", query)
yield from self.parse_regex_lines(self._INSTALLED_REGEXP, output)
[docs]
@version_not_implemented
def install(self, package_id: str, version: str | None = None) -> str:
"""Install one package, compiling it from its repository.
```{code-block} shell-session
$ pkgit --install pkgit
```
"""
return self.run_cli("--install", package_id)
[docs]
def upgrade_all_cli(self) -> tuple[str, ...]:
"""Generates the CLI to upgrade all installed packages.
```{caution}
pkgit exits `0` whether or not a repository updated, reporting each
outcome on `<stderr>` instead, so a failed update cannot be told from a
successful one by exit code alone.
```
```{code-block} shell-session
$ pkgit --update
```
"""
return self.build_cli("--update")