#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jun  1 14:53:13 2024

@author: fatih
"""

import os
import shutil
import subprocess
from configparser import ConfigParser
from datetime import datetime
from pathlib import Path
from shutil import rmtree

import distro


def main():
    def create_dir(dir_path):
        try:
            Path(dir_path).mkdir(parents=True, exist_ok=True)
            return True
        except:
            print("{} : {}".format("mkdir error", dir_path))
            print("pardus-update: mkdir error: {}".format(dir_path), file=logfile)
            return False

    logdir = "/usr/share/pardus/pardus-update/log"
    backupdir = "/usr/share/pardus/pardus-update/backup"

    configdir = "/etc/pardus/"
    configfile = "pardus-update.conf"
    config = ConfigParser(strict=False)

    now = datetime.now().strftime("%Y.%m.%d.%H.%M")
    logfile_path = os.path.join(logdir, "{}.log".format(now))
    create_dir(backupdir)
    create_dir(logdir)
    logfile = open(logfile_path, "a")

    def apt_clean():
        rmtree("/var/lib/apt/lists/", ignore_errors=True)
        subprocess.call(["apt", "clean"],
                        env={**os.environ, 'DEBIAN_FRONTEND': 'noninteractive'}, stderr=logfile, stdout=logfile)

    def fixbroken():
        subprocess.call(["apt", "install", "--fix-broken", "-yq"],
                        env={**os.environ, 'DEBIAN_FRONTEND': 'noninteractive'}, stderr=logfile, stdout=logfile)

    def dpkgconfigure():
        subprocess.call(["dpkg", "--configure", "-a"],
                        env={**os.environ, 'DEBIAN_FRONTEND': 'noninteractive'}, stderr=logfile, stdout=logfile)

    def update():
        subprocess.call(["apt", "update"],
                        env={**os.environ, 'DEBIAN_FRONTEND': 'noninteractive'}, stderr=logfile, stdout=logfile)

    def set_real_sources():
        found = True
        source = ""
        major = distro.major_version()
        codename = distro.codename().lower()

        print("pardus-update: DISTRO: {} {}".format(codename, major), file=logfile)

        if codename == "ondokuz":
            source = "### The Official Pardus Package Repositories ###\n\n" \
                     "deb http://depo.pardus.org.tr/pardus ondokuz main contrib non-free\n" \
                     "# deb-src http://depo.pardus.org.tr/pardus ondokuz main contrib non-free\n\n" \
                     "deb http://depo.pardus.org.tr/guvenlik ondokuz main contrib non-free\n" \
                     "# deb-src http://depo.pardus.org.tr/guvenlik ondokuz main contrib non-free\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        elif codename == "yirmibir":
            source = "### The Official Pardus Package Repositories ###\n\n" \
                     "deb http://depo.pardus.org.tr/pardus yirmibir main contrib non-free\n" \
                     "# deb-src http://depo.pardus.org.tr/pardus yirmibir main contrib non-free\n\n" \
                     "deb http://depo.pardus.org.tr/guvenlik yirmibir main contrib non-free\n" \
                     "# deb-src http://depo.pardus.org.tr/guvenlik yirmibir main contrib non-free\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        elif codename == "yirmiuc":
            source = "### The Official Pardus Package Repositories ###\n\n" \
                     "## Pardus\n" \
                     "deb http://depo.pardus.org.tr/pardus yirmiuc main contrib non-free non-free-firmware\n" \
                     "# deb-src http://depo.pardus.org.tr/pardus yirmiuc main contrib non-free non-free-firmware\n\n" \
                     "## Pardus Deb\n" \
                     "deb http://depo.pardus.org.tr/pardus yirmiuc-deb main contrib non-free non-free-firmware\n" \
                     "# deb-src http://depo.pardus.org.tr/pardus yirmiuc-deb main contrib non-free non-free-firmware\n\n" \
                     "## Pardus Security Deb\n" \
                     "deb http://depo.pardus.org.tr/guvenlik yirmiuc-deb main contrib non-free non-free-firmware\n" \
                     "# deb-src http://depo.pardus.org.tr/guvenlik yirmiuc-deb main contrib non-free non-free-firmware\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        elif codename == "etap":
            if major == "19":
                source = "### The Official Pardus Package Repositories ###\n\n" \
                         "deb http://19.depo.pardus.org.tr/etap ondokuz main contrib non-free\n" \
                         "# deb-src http://19.depo.pardus.org.tr/etap ondokuz main contrib non-free\n\n" \
                         "deb http://19.depo.pardus.org.tr/etap-guvenlik ondokuz main contrib non-free\n" \
                         "# deb-src http://19.depo.pardus.org.tr/etap-guvenlik ondokuz main contrib non-free\n\n" \
                         "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
            else:
                found = False
        elif codename == "bookworm":
            source = "### The Official Debian Package Repositories ###\n\n" \
                     "deb http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware\n" \
                     "# deb-src http://deb.debian.org/debian bookworm main contrib non-free non-free-firmware\n\n" \
                     "deb http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware\n" \
                     "# deb-src http://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        elif codename == "bullseye":
            source = "### The Official Debian Package Repositories ###\n\n" \
                     "deb http://deb.debian.org/debian bullseye main contrib non-free\n" \
                     "# deb-src http://deb.debian.org/debian bullseye main contrib non-free\n\n" \
                     "deb http://deb.debian.org/debian-security bullseye-security main contrib non-free\n" \
                     "# deb-src http://deb.debian.org/debian-security bullseye-security main contrib non-free\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        elif codename == "buster":
            source = "### The Official Debian Package Repositories ###\n\n" \
                     "deb http://deb.debian.org/debian buster main contrib non-free\n" \
                     "# deb-src http://deb.debian.org/debian buster main contrib non-free\n\n" \
                     "deb http://deb.debian.org/debian-security buster/updates main contrib non-free\n" \
                     "# deb-src http://deb.debian.org/debian-security buster/updates main contrib non-free\n\n" \
                     "### This section generated by Pardus Auto Upgrade at " + str(now) + " ###\n"
        else:
            found = False

        if found:
            # backup original sources.list and log
            shutil.copy2("/etc/apt/sources.list", os.path.join(backupdir, "{}-sources.list".format(now)))
            with open("/etc/apt/sources.list", "r") as sources_list_file:
                print("### {} (old) ###".format("/etc/apt/sources.list"), file=logfile)
                print(sources_list_file.read() + "\n", file=logfile)

            # write real sources to sources.list file
            sfile = open("/etc/apt/sources.list", "w")
            sfile.write(source)
            sfile.flush()
            sfile.close()

            # log new sources.list file
            with open("/etc/apt/sources.list", "r") as new_sources_list_file:
                print("### {} (new) ###".format("/etc/apt/sources.list"), file=logfile)
                print(new_sources_list_file.read() + "\n", file=logfile)

    def set_custom_sources(sources_path):
        if sources_path is not None:

            # use new sources for /etc/apt/sources.list
            if os.path.isfile(sources_path):
                with open("/etc/apt/sources.list", "r") as sources_list_file:
                    print("### {} (old) ###".format("/etc/apt/sources.list"), file=logfile)
                    print(sources_list_file.read() + "\n", file=logfile)

                with open(sources_path, "r") as sources_file:
                    print("### {} (new) ###".format(sources_path), file=logfile)
                    print(sources_file.read() + "\n", file=logfile)

                shutil.copy2("/etc/apt/sources.list", os.path.join(backupdir, "{}-sources.list".format(now)))
                shutil.copy2(sources_path, "/etc/apt/sources.list")
            else:
                print("{} file not exists!".format(sources_path), file=logfile)

    def add_sourcesd(sourcesd_path):
        if sourcesd_path is not None:

            # add new sources to /etc/apt/sources.list.d/
            if os.path.isfile(sourcesd_path):

                with open(sourcesd_path, "r") as sourcesd_file:
                    print("### {} (new) ###".format(sourcesd_path), file=logfile)
                    print(sourcesd_file.read() + "\n", file=logfile)
                shutil.copy2(sourcesd_path, "/etc/apt/sources.list.d/")
            else:
                print("{} file not exists!".format(sourcesd_path), file=logfile)

    def disable_sourcesd_list():
        # comment line /etc/apt/sources.list.d/*.list
        sdir = "/etc/apt/sources.list.d"
        if os.path.isdir(sdir):
            slistd = os.listdir(sdir)
            for slist in slistd:
                commented = ""
                if slist.endswith(".list"):
                    try:
                        shutil.copy2(os.path.join(sdir, slist),
                                     os.path.join(backupdir, "{}-{}".format(now, slist)))
                        with open(os.path.join(sdir, slist), "r") as sread:
                            print("### {} ###".format(slist), file=logfile)
                            for line in sread.readlines():
                                print(line, file=logfile)
                                if line.strip().startswith("deb"):
                                    comment = line.replace("deb ", "#deb ")
                                else:
                                    comment = line
                                commented += comment
                            print("\n", file=logfile)
                        with open(os.path.join(sdir, slist), "w") as swrite:
                            swrite.writelines(commented)
                            swrite.flush()
                            swrite.close()
                    except Exception as e:
                        print("{}".format(e))
                        print("pardus-update: {}".format(e), file=logfile)

    def control_fixes():
        if fix is not None and fix:
            dpkgconfigure()
            fixbroken()

    def upgrade(dpkg_conf_string):
        dpkg_conf_list = dpkg_conf_string.split(" ")

        subprocess.call(["apt", "full-upgrade", "-yq"] + dpkg_conf_list,
                        env={**os.environ, 'DEBIAN_FRONTEND': 'noninteractive'}, stderr=logfile, stdout=logfile)

    config.read(configdir + configfile)
    fix = False
    dpkg_conf = "-o Dpkg::Options::=--force-confnew"
    use_real_sources = False
    custom_sources_path = None
    custom_sourcesd_path = None
    disable_sourcesd = False

    if config.has_option("Upgrade", "use_real_sources"):
        try:
            use_real_sources = config.getboolean('Upgrade', 'use_real_sources')
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if config.has_option("Upgrade", "custom_sources_path"):
        try:
            custom_sources_path = config.get('Upgrade', 'custom_sources_path').strip('"')
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if config.has_option("Upgrade", "custom_sourcesd_path"):
        try:
            custom_sourcesd_path = config.get('Upgrade', 'custom_sourcesd_path').strip('"')
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if config.has_option("Upgrade", "disable_sourcesd"):
        try:
            disable_sourcesd = config.getboolean('Upgrade', 'disable_sourcesd')
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if config.has_option("Upgrade", "dpkg_conf"):
        try:
            dpkgconf = config.get('Upgrade', 'dpkg_conf').strip('"')
            if dpkgconf == "old":
                dpkg_conf = "-o Dpkg::Options::=--force-confold"
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if config.has_option("Upgrade", "fix"):
        try:
            fix = config.getboolean('Upgrade', 'fix')
        except Exception as e:
            print("{}".format(e))
            print("pardus-update: {}".format(e), file=logfile)

    if use_real_sources:
        set_real_sources()
    else:
        if custom_sources_path is not None:
            set_custom_sources(custom_sources_path)

    if disable_sourcesd:
        disable_sourcesd_list()

    if custom_sourcesd_path is not None:
        add_sourcesd(custom_sourcesd_path)

    # apt_clean()
    update()
    control_fixes()
    upgrade(dpkg_conf)
    logfile.flush()
    logfile.close()


if __name__ == "__main__":
    main()
