Skip to content

Replace Pacman() syscall logic with libalpm#2787

Closed
Torxed wants to merge 7 commits intoarchlinux:masterfrom
Torxed:rework-pacman-logic
Closed

Replace Pacman() syscall logic with libalpm#2787
Torxed wants to merge 7 commits intoarchlinux:masterfrom
Torxed:rework-pacman-logic

Conversation

@Torxed
Copy link
Copy Markdown
Member

@Torxed Torxed commented Nov 8, 2024

PR Description:

This PR will enable us to do three things:

  • Move away from running pacman -XYZ via system calls, and instead rely on libalpm directly, via pyalpm.
  • We can do package search efficiently, meaning we can replace:
    def package_search(package: str) -> PackageSearch:
    """
    Finds a specific package via the package database.
    It makes a simple web-request, which might be a bit slow.
    """
    # TODO UPSTREAM: Implement bulk search, either support name=X&name=Y or split on space (%20 or ' ')
    # TODO: utilize pacman cache first, upstream second.
    response = _make_request(BASE_URL_PKG_SEARCH, {'name': package})
    if response.code != 200:
    raise PackageError(f"Could not locate package: [{response.code}] {response}")
    data = response.read().decode('UTF-8')
    json_data = json.loads(data)
    return PackageSearch.from_json(json_data)

    Allowing us to do local searches, and let pacman deal with databases and searching.
    This simplifies custom mirrors and allowing us to search against them too.
  • One less thing that requires root privileges

Some thoughts

I decided to use a context manager approach, as it allows us to choose between interacting against system-wide pacman data - but during context creation also decide if we want a temporary pacman data structure.

That way we can do:

with Pacman(temporary=True, servers=['http://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch', 'http://ftp.acc.umu.se/mirror/archlinux/$repo/os/$arch']) as pacman:
	print(pacman.search('nano'))

To not collide with system-wide pacman, and perform searches and syncs independently and irregards if existing pacman is executing.

With this we can remove:

pacman_db_lock = Path('/var/lib/pacman/db.lck')
if pacman_db_lock.exists():
warn(_('Pacman is already running, waiting maximum 10 minutes for it to terminate.'))
started = time.time()
while pacman_db_lock.exists():
time.sleep(0.25)
if time.time() - started > (60 * 10):
error(_('Pre-existing pacman lock never exited. Please clean up any existing pacman sessions before using archinstall.'))
exit(1)

And if we want to interact with pacman system wide, we simply just do:

with Pacman() as pacman:
	pacman.sync()
	pacman.install("vim")

I'm sure we could achieve the same thing with using only __init__ and some if/else.
But for some reason this felt like a logical thing to do, especially since all pacman operations are "transaction based", meaning we need to create a lock file while doing operations - and then remove the lock file once we're done.

And if libalpm/pacman crashes during an operation, we need a way to do easy cleanup and remove said lock file.

@Torxed Torxed closed this by deleting the head repository Apr 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant