mirror of
https://gitlab.com/dslackw/slpkg.git
synced 2024-12-28 09:58:21 +01:00
306 lines
10 KiB
Python
306 lines
10 KiB
Python
#!/usr/bin/python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import time
|
|
import subprocess
|
|
|
|
from pathlib import Path
|
|
from collections import OrderedDict
|
|
from multiprocessing import Process, cpu_count
|
|
|
|
from slpkg.checksum import Md5sum
|
|
from slpkg.configs import Configs
|
|
from slpkg.queries import SBoQueries
|
|
from slpkg.utilities import Utilities
|
|
from slpkg.dialog_box import DialogBox
|
|
from slpkg.dependencies import Requires
|
|
from slpkg.downloader import Downloader
|
|
from slpkg.views.views import ViewMessage
|
|
from slpkg.progress_bar import ProgressBar
|
|
from slpkg.models.models import LogsDependencies
|
|
from slpkg.models.models import session as Session
|
|
|
|
|
|
class Slackbuilds:
|
|
""" Download build and install the SlackBuilds. """
|
|
|
|
def __init__(self, slackbuilds: list, flags: list, install: bool):
|
|
self.slackbuilds = slackbuilds
|
|
self.flags = flags
|
|
self.install = install
|
|
self.session = Session
|
|
self.utils = Utilities()
|
|
self.dialog = DialogBox()
|
|
self.configs = Configs
|
|
self.colors = self.configs.colour
|
|
self.color = self.colors()
|
|
self.cyan = self.color['cyan']
|
|
self.red = self.color['red']
|
|
self.yellow = self.color['yellow']
|
|
self.endc = self.color['endc']
|
|
self.install_order = []
|
|
self.dependencies = []
|
|
self.sbos = {}
|
|
self.progress = ProgressBar()
|
|
self.stderr = None
|
|
self.stdout = None
|
|
|
|
def execute(self):
|
|
""" Starting build or install the slackbuilds. """
|
|
self.creating_dictionary()
|
|
|
|
if '--resolve-off' not in self.flags:
|
|
self.creating_dependencies_for_build()
|
|
|
|
self.creating_main_for_build()
|
|
|
|
self.view_before_build()
|
|
|
|
start = time.time()
|
|
self.download_slackbuilds_and_build()
|
|
elapsed_time = time.time() - start
|
|
|
|
self.utils.finished_time(elapsed_time)
|
|
|
|
def creating_dictionary(self):
|
|
""" Dictionary with the main slackbuilds and dependencies. """
|
|
for sbo in self.slackbuilds:
|
|
self.sbos[sbo] = Requires(sbo).resolve()
|
|
|
|
def creating_dependencies_for_build(self):
|
|
""" List with the dependencies. """
|
|
for deps in self.sbos.values():
|
|
for dep in deps:
|
|
|
|
# Checks if the package was installed and skipped.
|
|
if ('--skip-installed' in self.flags and
|
|
self.utils.is_installed(dep)):
|
|
continue
|
|
|
|
if dep in self.slackbuilds:
|
|
self.slackbuilds.remove(dep)
|
|
|
|
self.dependencies.append(dep)
|
|
|
|
# Remove duplicate packages and keeps the order.
|
|
dependencies = list(OrderedDict.fromkeys(self.dependencies))
|
|
|
|
if dependencies:
|
|
self.dependencies = self.choose_dependencies(dependencies)
|
|
|
|
self.install_order.extend(self.dependencies)
|
|
|
|
def choose_dependencies(self, dependencies: list):
|
|
""" Choose packages for install. """
|
|
height = 10
|
|
width = 70
|
|
list_height = 0
|
|
choices = []
|
|
title = ' Choose dependencies you want to install '
|
|
|
|
for package in dependencies:
|
|
status = True
|
|
repo_ver = SBoQueries(package).version()
|
|
installed = self.utils.is_installed(package)
|
|
|
|
if installed:
|
|
status = False
|
|
|
|
choices += [(package, repo_ver, status)]
|
|
|
|
text = f'There are {len(choices)} dependencies:'
|
|
|
|
code, tags = self.dialog.checklist(text, title, height, width,
|
|
list_height, choices, dependencies)
|
|
|
|
if not code:
|
|
return dependencies
|
|
|
|
os.system('clear')
|
|
|
|
return tags
|
|
|
|
def creating_main_for_build(self):
|
|
""" List with the main slackbuilds. """
|
|
[self.install_order.append(main) for main in self.sbos.keys()]
|
|
|
|
def view_before_build(self):
|
|
""" View slackbuilds before proceed. """
|
|
view = ViewMessage(self.flags)
|
|
|
|
if self.install:
|
|
view.install_packages(self.slackbuilds, self.dependencies)
|
|
else:
|
|
view.build_packages(self.slackbuilds, self.dependencies)
|
|
|
|
del self.dependencies # no more needed
|
|
|
|
view.question()
|
|
|
|
def download_slackbuilds_and_build(self):
|
|
""" Downloads files and sources and starting the build. """
|
|
for sbo in self.install_order:
|
|
|
|
package = self.utils.is_installed(sbo)
|
|
|
|
if not package or package and '--reinstall' in self.flags or not self.install:
|
|
file = f'{sbo}{self.configs.sbo_tar_suffix}'
|
|
|
|
self.utils.remove_file_if_exists(self.configs.tmp_slpkg, file)
|
|
self.utils.remove_folder_if_exists(self.configs.build_path, sbo)
|
|
|
|
location = SBoQueries(sbo).location()
|
|
url = f'{self.configs.sbo_repo_url}/{location}/{file}'
|
|
|
|
down_sbo = Downloader(self.configs.tmp_slpkg, url)
|
|
down_sbo.download()
|
|
|
|
self.utils.untar_archive(self.configs.tmp_slpkg, file, self.configs.build_path)
|
|
|
|
self.patch_sbo_tag(sbo)
|
|
|
|
sources = SBoQueries(sbo).sources()
|
|
self.download_sources(sbo, sources)
|
|
|
|
self.build_the_script(self.configs.build_path, sbo)
|
|
|
|
if self.install:
|
|
|
|
pkg = self.creating_package_for_install(sbo)
|
|
self.install_package(pkg)
|
|
|
|
if '--resolve-off' not in self.flags:
|
|
self.logging_installed_dependencies(sbo)
|
|
else:
|
|
version = self.utils.split_installed_pkg(package)[1]
|
|
print(f'[ Skipping ] {sbo}-{version} (already installed)')
|
|
|
|
def patch_sbo_tag(self, sbo):
|
|
""" Patching SBo TAG from the configuration file. """
|
|
sbo_script = Path(self.configs.build_path, sbo, f'{sbo}.SlackBuild')
|
|
|
|
if sbo_script.is_file():
|
|
with open(sbo_script, 'r', encoding='utf-8') as f:
|
|
lines = f.readlines()
|
|
|
|
with open(sbo_script, 'w') as script:
|
|
for line in lines:
|
|
if line.startswith('TAG=$'):
|
|
line = f'TAG=${{TAG:-{self.configs.sbo_repo_tag}}}\n'
|
|
script.write(line)
|
|
|
|
def logging_installed_dependencies(self, name: str):
|
|
""" Logging installed dependencies and used for remove. """
|
|
exist = self.session.query(LogsDependencies.name).filter(
|
|
LogsDependencies.name == name).first()
|
|
|
|
requires = Requires(name).resolve()
|
|
|
|
# Update the dependencies if exist else create it.
|
|
if exist:
|
|
self.session.query(
|
|
LogsDependencies).filter(
|
|
LogsDependencies.name == name).update(
|
|
{LogsDependencies.requires: ' '.join(requires)})
|
|
|
|
elif requires:
|
|
deps = LogsDependencies(name=name, requires=' '.join(requires))
|
|
self.session.add(deps)
|
|
self.session.commit()
|
|
|
|
def install_package(self, package: str):
|
|
""" Install the packages that before created in the tmp directory. """
|
|
pkg = self.utils.split_installed_pkg(package)[0]
|
|
|
|
execute = self.configs.installpkg
|
|
if ('--reinstall' in self.flags and
|
|
self.utils.is_installed(pkg)):
|
|
execute = self.configs.reinstall
|
|
|
|
message = f'{self.cyan}Installing{self.endc}'
|
|
command = f'{execute} {self.configs.tmp_path}/{package}'
|
|
self.multi_process(command, package, message)
|
|
|
|
def creating_package_for_install(self, name: str):
|
|
""" Creating a list with all the finished packages for
|
|
installation. """
|
|
version = SBoQueries(name).version()
|
|
|
|
packages = []
|
|
pkg = f'{name}-{version}'
|
|
|
|
for package in os.listdir(self.configs.tmp_path):
|
|
if pkg in package and self.configs.sbo_repo_tag in package:
|
|
packages.append(package)
|
|
|
|
return max(packages)
|
|
|
|
def build_the_script(self, path: str, name: str):
|
|
""" Run the .SlackBuild script. """
|
|
folder = f'{Path(path, name)}/'
|
|
execute = f'{folder}./{name}.SlackBuild'
|
|
|
|
# Change to root privileges
|
|
os.chown(folder, 0, 0)
|
|
for file in os.listdir(folder):
|
|
os.chown(f'{folder}{file}', 0, 0)
|
|
|
|
if '--jobs' in self.flags:
|
|
self.set_makeflags()
|
|
|
|
message = f'{self.red}Build{self.endc}'
|
|
self.multi_process(execute, name, message)
|
|
|
|
@staticmethod
|
|
def set_makeflags():
|
|
""" Set number of processors. """
|
|
os.environ['MAKEFLAGS'] = f'-j {cpu_count()}'
|
|
|
|
def download_sources(self, name: str, sources: list):
|
|
""" Download the sources. """
|
|
path = Path(self.configs.build_path, name)
|
|
checksums = SBoQueries(name).checksum()
|
|
|
|
for source, checksum in zip(sources, checksums):
|
|
down_source = Downloader(path, source)
|
|
down_source.download()
|
|
|
|
md5sum = Md5sum(self.flags)
|
|
md5sum.check(path, source, checksum, name)
|
|
|
|
def multi_process(self, command, filename, message):
|
|
|
|
if self.configs.view_mode == 'new':
|
|
self.stderr = subprocess.DEVNULL
|
|
self.stdout = subprocess.DEVNULL
|
|
|
|
# Starting multiprocessing
|
|
p1 = Process(target=self.process, args=(command,))
|
|
p2 = Process(target=self.progress.bar, args=(f'[ {message} ]', filename))
|
|
|
|
p1.start()
|
|
p2.start()
|
|
|
|
# Wait until process 1 finish
|
|
p1.join()
|
|
|
|
# Terminate process 2 if process 1 finished
|
|
if not p1.is_alive():
|
|
print(f'{self.yellow} Done{self.endc}', end='')
|
|
p2.terminate()
|
|
|
|
# Wait until process 2 finish
|
|
p2.join()
|
|
|
|
# Restore the terminal cursor
|
|
print('\x1b[?25h')
|
|
else:
|
|
self.process(command)
|
|
|
|
def process(self, command):
|
|
""" Processes execution. """
|
|
output = subprocess.call(command, shell=True,
|
|
stderr=self.stderr, stdout=self.stdout)
|
|
if output > 0:
|
|
raise SystemExit(output)
|