Source code for meta_package_manager.managers.sun_tools
# Copyright Kevin Deldycke <kevin@deldycke.com> 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 SOLARIS
from ..manager import PackageManager
TYPE_CHECKING = False
if TYPE_CHECKING:
from collections.abc import Iterator
from ..package import Package
[docs]
class Sun_Tools(PackageManager):
"""Solaris' legacy System V Release 4 packaging tools.
Documentation:
- [`pkgadd(1M)` man page](https://docs.oracle.com/cd/E26502_01/html/E29031/pkgadd-1m.html)
- [`pkgrm(1M)` man page](https://docs.oracle.com/cd/E26502_01/html/E29031/pkgrm-1m.html)
The suite spans several binaries: `pkginfo` (the read-only query tool, used as
the main CLI), `pkgadd` and `pkgrm`.
```{note}
SVR4 packages come from local media or datastream files, not a network
repository: there is no catalog to search, refresh or diff against, and
`pkgadd` installs a specific local artifact rather than resolving a name.
Only `installed` and `remove` are therefore implemented; Solaris 11's
modern repository-based interface is IPS (`pkg`), a different manager.
```
"""
maintenance_note = (
"The SVR4 packaging commands are legacy, superseded by IPS since Solaris 11, "
"but still shipped and supported on [Oracle Solaris 11.4]"
"(https://docs.oracle.com/cd/E37838_01/html/E61051/pkgsvr4.html), whose "
"support runs through 2037."
)
name = "Solaris SVR4 package tools"
homepage_url = "https://docs.oracle.com/cd/E86824_01/html/E54763/pkginfo-1.html"
# No `logo`, and there never will be: Oracle's marks were pulled from Simple
# Icons, so do not file a request, and do not vendor one by hand:
# https://github.com/simple-icons/simple-icons/issues/11441
platforms = SOLARIS
default_sudo = True
cli_names = ("pkginfo",)
# pkgrm lives in /usr/sbin, which is not always on a regular user's PATH.
cli_search_path = ("/usr/sbin",)
version_cli = "uname"
"""None of the SVR4 tools has a version flag: `pkginfo -v` matches a package
*version* and `pkgadd`/`pkgrm` only take `-v` as verbose. The suite ships
with the base system, so its version is the OS release reported by `uname -r`
(`5.11` on Solaris 11).
"""
version_cli_options = ("-r",)
version_regexes = (r"(?P<version>[\d.]+)",)
"""
```{code-block} shell-session
$ uname -r
5.11
```
"""
_PKGINFO_FIELD_REGEXP = re.compile(
r"^\s*(?P<field>PKGINST|VERSION|STATUS):\s+(?P<value>.+?)\s*$",
)
@property
def installed(self) -> Iterator[Package]:
"""Fetch installed packages.
Plain `pkginfo` prints no version column (only category, package instance
and name), so the long `-l` listing is parsed instead: each package is a
multi-line block carrying `PKGINST:`, `VERSION:` and `STATUS:` fields.
Only completely-installed packages are yielded.
```{code-block} shell-session
$ pkginfo -l
PKGINST: SUNWcar
NAME: Core Architecture, (Root)
CATEGORY: system
ARCH: i386.i86pc
VERSION: 11.10.0,REV=2005.01.21.16.34
BASEDIR: /
VENDOR: Oracle Corporation
STATUS: completely installed
```
"""
output = self.run_cli("-l")
package_id = None
version = None
complete = False
for line in output.splitlines():
match = self._PKGINFO_FIELD_REGEXP.match(line)
if not match:
continue
field, value = match.group("field"), match.group("value")
if field == "PKGINST":
# A new block starts: flush the previous one.
if package_id and complete:
yield self.package(id=package_id, installed_version=version)
package_id = value
version = None
complete = False
elif field == "VERSION":
version = value
elif field == "STATUS":
complete = value.startswith("completely installed")
if package_id and complete:
yield self.package(id=package_id, installed_version=version)
[docs]
def remove(self, package_id: str) -> str:
"""Remove one package.
`-n` runs non-interactively: pkgrm exits instead of prompting, so a
removal requiring interaction (like a dependency confirmation) fails fast
rather than hanging mpm's subprocess.
```{code-block} shell-session
$ sudo pkgrm -n SUNWzlib
```
"""
pkgrm_path = self.sibling_cli("pkgrm")
return self.run_cli(
"-n",
package_id,
override_cli_path=pkgrm_path,
sudo=True,
)