Скрипт Python для установки пакетов aur
Я пытаюсь сделать скрипт на python для установки пакетов aur, таких как google-chrome, sublime-text и т. Д., Для новой версии arch linux. Я могу просто клонировать URL-адрес git, но у меня проблемы с использованием программы makepkg. Я не могу запустить скрипт как sudo, потому что makepkg не разрешает полномочия sudo, потому что это может привести к повреждению системы, но мне нужны полномочия sudo для установки его с помощью pacman. Я опубликую то, что у меня есть для этой функции, и я буду очень признателен, если кто-нибудь сможет мне помочь. (заранее извиняюсь, если это глупый вопрос или ответ прост, но я потратил пару часов на Google и не смог найти ответ)
def clone_and_makepkg(package_name, aur_folder_path, password):
git_url = "https://aur.archlinux.org/" + package_name + ".git"
new_package_path = os.path.join(aur_folder_path, package_name)
print("Cloning " + git_url + " to " + new_package_path)
Popen(["git", "clone", git_url, new_package_path]).wait()
os.chdir(new_package_path)
1 ответ
Вариант 1. Выполнение сценария от имени пользователя, повышение привилегий для пользователя root pacman -U
Я думаю, что это плохая идея. Скриптам немного неловко читать пароли и довольно долго тащить их через небезопасную память, потому что в конце они хотят выполнить что-то как root. Если вы настаиваете, это, однако, будет работать аналогично варианту 2.
Вариант 2. Выполнение скрипта от имени пользователя root, демонтирование подпроцессов для пользователя git clone
а также makepkg
Ты можешь использовать subprocess.Popen
"s preexec_fn
вариант, который делает, согласно help(subprocess.Popen)
:
preexec_fn: (только POSIX) Объект, вызываемый в дочернем процессе непосредственно перед выполнением дочернего процесса.
Единственная сложность в этом - передать аргументы. Если бы нам не нужно было этого делать, мы могли бы просто указать функцию (os.setuid
) как preexec_fn
вариант в Popen()
вызов конструктора. К сожалению, тогда он будет выполнен, когда мы определим подпроцесс, а не когда мы запустим его как задумано. Поэтому мы бы в конечном итоге демонтировать мастер-процесс.
Итак, мы должны определить небольшую функцию-обертку:
def demote():
os.setuid(1000)
и затем можем определить наш подпроцесс:
process = Popen(["git", "clone", git_url, new_package_path], preexec_fn=demote)
process.wait()
Конечно, это не очень хороший способ сделать это - жестко запрограммировать uid и все. Если мы хотим demote()
принять аргументы, однако, мы вернулись на круги своя. Таким образом, мы должны сделать это немного сложнее и определить вложенную функцию (функцию внутри функции), где внешняя вызывается для определения подпроцесса, принимает аргументы, определяет uid и gid и возвращает внутреннюю функцию, которая применяет понижение. Звучит сложно? Строго говоря, вам не нужно этого делать, но, скажем, мы хотим быть гибкими, так что мы здесь:
def demote(user_uid, user_gid):
def apply_demotion():
os.setgid(user_gid)
os.setuid(user_uid)
return apply_demotion
Второй вариант заключается в использовании su -c (command) (user)
который может быть вызван из Python с помощью os.system()
функция:
os.system("su -c makepkg " + user)
Вы, вероятно, захотите запустить оба git clone
и makepkg
Команда с тем же методом для согласованности.
Рабочий пример
import os
from subprocess import Popen
import glob
def clone_and_makepkg(package_name, aur_folder_path="/tmp/build/", uid=1000, gid=1000):
"""prepare urls and paths"""
git_url = "https://aur.archlinux.org/" + package_name + ".git"
new_package_path = os.path.join(aur_folder_path, package_name)
"""ensure the build directory exists and user has correct privileges to work there"""
if not os.path.exists(aur_folder_path):
os.mkdir(aur_folder_path)
os.chmod(aur_folder_path, 0o777)
"""perform git clone"""
print("Cloning " + git_url + " to " + new_package_path)
Popen(["git", "clone", git_url, new_package_path], preexec_fn=demote(uid, gid)).wait()
"""change to make directory"""
os.chdir(new_package_path)
"""run makepkg"""
Popen("makepkg", preexec_fn=demote(uid, gid)).wait()
"""collect built packages"""
built_packages = glob.glob(new_package_path + os.sep + "*.pkg.tar.xz")
"""install each package"""
for package in built_packages:
print("Installing package {}".format(package))
os.system("pacman -U " + package + " --noconfirm")
def demote(user_uid, user_gid):
def apply_demotion():
os.setgid(user_gid)
os.setuid(user_uid)
return apply_demotion
if __name__ == "__main__":
"""Example call. Will install package 3to2 (This example does not have any further dependencies
except for python. Which is evidently already installed. So this example is hassle-free. For
examples with dependencies, you may want to find a way to deal with those in the script.)"""
clone_and_makepkg(package_name="3to2")