Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Pacman() syscall logic with libalpm #2787

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

Torxed
Copy link
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.

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