From 57abee1b3d003b3580c1e9e6a206847936c0e70c Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Wed, 20 Nov 2024 00:26:44 -0500 Subject: [PATCH 1/2] Fix error with Qt GUI --- DEBIAN/edamame-common.control | 2 +- etc/edamame/time_zone_keys.json | 122 +++ usr/bin/edamame.cxx | 2 +- .../edamame/UI/QT_UI/auto_partitioner.py | 766 +----------------- usr/share/edamame/UI/QT_UI/common.py | 108 +-- usr/share/edamame/engine.py | 16 +- usr/share/edamame/installer.py | 4 +- 7 files changed, 136 insertions(+), 884 deletions(-) create mode 100644 etc/edamame/time_zone_keys.json mode change 100755 => 120000 usr/share/edamame/UI/QT_UI/auto_partitioner.py mode change 100755 => 120000 usr/share/edamame/UI/QT_UI/common.py diff --git a/DEBIAN/edamame-common.control b/DEBIAN/edamame-common.control index da6adc9..cb63ee2 100644 --- a/DEBIAN/edamame-common.control +++ b/DEBIAN/edamame-common.control @@ -1,5 +1,5 @@ Package: edamame-common -Version: 2.9.9 +Version: 3.0.0 Maintainer: Thomas Castleman Homepage: https://github.com/drauger-os-development/edamame Section: admin diff --git a/etc/edamame/time_zone_keys.json b/etc/edamame/time_zone_keys.json new file mode 100644 index 0000000..56877c8 --- /dev/null +++ b/etc/edamame/time_zone_keys.json @@ -0,0 +1,122 @@ +{ + "Africa": { + "Egypt": 0, + "Nigeria": 0, + "South Africa": 0, + "Swahili": 0, + "Democratic Republic of the Congo": 0, + "Togo": 0, + "Amharic": 0, + "Morocco": 0, + "Bambara": 0, + "Algeria": 0, + "Cameroon": 0, + "Ghana": 0, + "Wolof": 0, + "Tswana": 0, + "NKo": 0 + }, + "America": { + "Latin America": 0 + }, + "Antarctica": {}, + "Arctic": {}, + "Asia": { + "Chinese": 0, + "Indian": 0, + "Japanese": 0, + "Cambodia": 0, + "Korean": 0, + "Mongolian": 0, + "Nepali": 0, + "Lao": 0, + "Russia": 0, + "Taiwan": 0, + "Pakistan": 0, + "Vietnam": 0, + "Uzbek": 0, + "Thai": 0, + "Turkmen": 0, + "Kazakh": 0, + "Arabic": 1, + "Iraq": 0, + "Syria": 0, + "Azerbaijani": 0, + "Bangla": 0, + "Burmese": 0, + "Dari": 0, + "Dhivehi": 0, + "Dzongkha": 0, + "Hebrew": 0, + "Tajik": 0, + "Kyrgyz": 0, + "Malay": 0, + "Sinhala": 0, + "Persian": 0 + }, + "Atlantic": { + "Icelandic": 0 + }, + "Australia": { + "Australia": 0 + }, + "Brazil": { + "Brazil": 0 + }, + "Canada": { + "Canada": 0 + }, + "Chile": {}, + "Etc": {}, + "Europe": { + "Dutch": 0, + "UK": 0, + "Finnish": 0, + "French": 1, + "German": 0, + "Greek": 0, + "Irish": 0, + "Italian": 0, + "Norwegian": 0, + "Polish": 0, + "Portuguese": 1, + "Spanish": 1, + "Swedish": 0, + "Switzerland": 0, + "Turkish": 0, + "Ukranian": 0, + "Belrusian": 0, + "Croatian": 0, + "Georgian": 0, + "Slovenian": 0, + "Macedonian": 0, + "Czech": 0, + "Danish": 0, + "Albanian": 0, + "Armenian": 0, + "Belgian": 0, + "Bosnian": 0, + "Bulgarian": 0, + "Estonian": 0, + "Faroese": 0, + "Hungarian": 0, + "Latvian": 0, + "Lithuanian": 0, + "Maltese": 0, + "Moldavian": 0, + "Montenegrin": 0, + "Slovak": 0, + "Serbian": 0, + "Romanian": 0 + }, + "Indian": {}, + "Mexico": {}, + "Pacific": { + "Filipino": 0, + "New Zealand": 0, + "Indonesian": 0 + }, + "US": { + "US": 0 + } +} \ No newline at end of file diff --git a/usr/bin/edamame.cxx b/usr/bin/edamame.cxx index 5e7c636..762cfd9 100644 --- a/usr/bin/edamame.cxx +++ b/usr/bin/edamame.cxx @@ -36,7 +36,7 @@ using namespace std; -str VERSION = "2.9.8"; +str VERSION = "3.0.0"; str R = "\033[0;31m"; str G = "\033[0;32m"; str Y = "\033[1;33m"; diff --git a/usr/share/edamame/UI/QT_UI/auto_partitioner.py b/usr/share/edamame/UI/QT_UI/auto_partitioner.py deleted file mode 100755 index d5e5f49..0000000 --- a/usr/share/edamame/UI/QT_UI/auto_partitioner.py +++ /dev/null @@ -1,765 +0,0 @@ -#!shebang -# -*- coding: utf-8 -*- -# -# auto_partitioner.py -# -# Copyright 2024 Thomas Castleman -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# -"""Auto-partition Drive selected for installation""" -import json -import time -import os -import sys -import subprocess -import parted -import psutil -import common - - -def gb_to_bytes(gb): - """Convert GB to Bytes""" - return gb * (10 ** 9) - - -def bytes_to_gb(b): - """Convert Bytes to GB""" - return b / (10 ** 9) - - -def mb_to_bytes(mb): - """Convert MB to Bytes""" - return mb * (10 ** 6) - - -def is_EFI(): - """Get if the current system is using EFI""" - return os.path.isdir("/sys/firmware/efi") - - -def part_to_drive(part): - """Get a drive from a griven partition - This is just an alias for get_drive_path()""" - return get_drive_path(part) - - -# GET DEFAULT CONFIG -LIMITER = gb_to_bytes(32) -PARTITIONING_ENABLED = True - -# get configuration for partitioning -config = { - "partitioning": { - "EFI": { - "EFI": { - "START": 0, - "END": 500 - }, - "ROOT": { - "START": 501, - "END": "40%", - "fs": "btrfs" - }, - "HOME": { - "START": "40%", - "END": "100%", - "fs": "btrfs" - } - }, - "BIOS": { - "ROOT": { - "START": 0, - "END": "40%", - "fs": "ext4" - }, - "HOME": { - "START": "40%", - "END": "100%", - "fs": "btrfs" - } - }, - "GENERAL": { - "min root size": 23000, - "mdswh": 128 - } - } - } - -try: - with open("/etc/edamame/settings.json", "r") as config_file: - config_data = json.load(config_file) -except FileNotFoundError: - config_data = config - - -# check to make sure packager left this block in -if "partitioning" in config_data: - new_config = config_data["partitioning"] -else: - common.eprint("Partitioning settings not found. Cannot partition drives automatically") - PARTITIONING_ENABLED = False - - -if is_EFI(): - try: - new_config = new_config["EFI"] | new_config["GENERAL"] - config = config["partitioning"]["EFI"] | config["partitioning"]["GENERAL"] - except KeyError: - common.eprint("EFI or General partitioning details not defined. Falling back to defaults") - print("EFI or General partitioning details not defined. Falling back to defaults") - new_config = config["partitioning"]["EFI"] | config["partitioning"]["GENERAL"] -else: - try: - new_config = new_config["BIOS"] | new_config["GENERAL"] - config = config["partitioning"]["BIOS"] | config["partitioning"]["GENERAL"] - except KeyError: - common.eprint("BIOS or General partitioning details not defined. Falling back to defaults") - print("BIOS or General partitioning details not defined. Falling back to defaults") - new_config = config["partitioning"]["BIOS"] | config["partitioning"]["GENERAL"] - - - - -# make sure everything is there. If not, substitute in defaults -# we don't use config["partitioning"][] syntax here because -# if we enter any of -# these if-statements, then we are not using the built-in settings. -# In which case, because of the above -# block, if we are using externally sourced settings, then config will -# be pared down for us. And if we -# are using the built-in settings, then we won't enter any of -if "ROOT" not in new_config: - new_config["ROOT"] = config["ROOT"] -if "HOME" not in new_config: - new_config["HOME"] = config["HOME"] -if is_EFI(): - if "EFI" not in new_config: - new_config["EFI"] = config["EFI"] -if "min root size" not in new_config: - new_config["min root size"] = config["min root size"] -if "mdswh" not in new_config: - new_config["mdswh"] = config["mdswh"] -config = new_config - # if not, fall back to internal default - - -def size_of_part(part_path, bytes=False): - """Get the size of the partition at `part_path` - - If `bytes` is True, return size in bytes. - Else, return size in gigabytes. - """ - # Get the root Drive - root = get_drive_path(part_path) - # connect to that drive's partition table - device = parted.getDevice(root) - try: - disk = parted.Disk(device) - except parted._ped.DiskLabelException: - raise OSError(f"NO PARTITION TABLE EXISTS ON { root } ") - # Grab the right partiton - part = disk.getPartitionByPath(part_path) - # get size - size = part.getSize(unit="b") - # size conversion, if necessary - if not bytes: - size = bytes_to_gb(size) - return size - - -def get_drive_path(part_path): - """Get drive path from partition path""" - if ("nvme" in part_path) or ("mmc" in part_path): - try: - output = part_path[:part_path.index("p")] - except ValueError: - # this might be a device with no partitions. - return part_path - else: - count = 0 - for each in part_path: - if not each.isnumeric(): - count+=1 - else: - break - output = part_path[:count] - return output - - -def get_min_root_size(swap=True, ram_size=False, ram_size_unit=True, - bytes=True): - """Get minimum root partition size as bytes - - When `swap' == True, factor in the ideal size of swap file for - the current system's RAM. - - If `ram_size' is not an int or float, RAM of the - current system will be used. - - if `ram_size_unit' is True, `ram_size' should be in GB. When `ram_size_unit' - is False, `ram_size' should be in bytes. - - If `bytes` is True, return size in bytes. - Else, return size in gigabytes. - """ - if swap: - if type(ram_size) not in (int, float): - mem = psutil.virtual_memory().total - else: - if ram_size_unit: - mem = gb_to_bytes(ram_size) - else: - mem = ram_size - swap_amount = round((mem + ((mem / 1024 ** 3) ** 0.5) * 1024 ** 3)) - else: - swap_amount = 0 - min_root_size = swap_amount + (config["min root size"] * (1000 ** 2)) - if not bytes: - min_root_size = bytes_to_gb(min_root_size) - return min_root_size - - -def check_disk_state(): - """Check disk state as registered with lsblk - - Returns data as dictionary - """ - try: - subprocess.check_call(["partprobe"]) - except subprocess.CalledProcessError: - print("`partprobe` failed. Provided info may not be up-to-date.") - time.sleep(0.2) - command = ["lsblk", "--json", "--paths", "--bytes", "--output", - "name,size,type,fstype"] - data = json.loads(subprocess.check_output(command))["blockdevices"] - for each in range(len(data) - 1, -1, -1): - if data[each]["type"] == "loop": - del data[each] - return data - - -def get_fs(part_name: str): - """Get filesystem type for given partition""" - disk = check_disk_state() - for each in disk: - if each["name"] == part_name: - return each["fstype"] - if "children" in each: - for each1 in each["children"]: - if each1["name"] == part_name: - return each1["fstype"] - - -def __mkfs__(device, fs): - """Set partition filesystem""" - # pre-define command - if "ext" in fs: - force = "-F" - else: - force = "-f" - command = ["mkfs", "-t", fs, force, str(device)] - try: - try: - data = subprocess.check_output(command).decode() - except UnicodeDecodeError: - return "" - except subprocess.CalledProcessError as error: - data = error.output.decode() - return data - - -if is_EFI(): - def __mkfs_fat__(device): - """Set partition filesystem to FAT32""" - # pre-define command - command = ["mkfs.fat", "-F", "32", str(device)] - try: - data = subprocess.check_output(command).decode() - except subprocess.CalledProcessError as error: - data = error.output.decode() - return data - - - def __make_efi__(device, start=config["EFI"]["START"], - end=config["EFI"]["END"]): - """Make EFI partition""" - disk = parted.Disk(device) - start_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(start, - "MB", - device.sectorSize), - end=parted.sizeToSectors(start + 10, - "MB", - device.sectorSize)) - end_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(common.real_number(end - 20), - "MB", - device.sectorSize), - end=parted.sizeToSectors(end + 10, - "MB", - device.sectorSize)) - min_size = parted.sizeToSectors(common.real_number((end - start) - 25), - "MB", - device.sectorSize) - max_size = parted.sizeToSectors(common.real_number((end - start) + 20), - "MB", - device.sectorSize) - const = parted.Constraint(startAlign=device.optimumAlignment, - endAlign=device.optimumAlignment, - startRange=start_geo, endRange=end_geo, - minSize=min_size, maxSize=max_size) - geometry = parted.geometry.Geometry(start=start, - length=parted.sizeToSectors(end - start, - "MB", - device.sectorSize), - device=device) - new_part = parted.Partition(disk=disk, - type=parted.PARTITION_NORMAL, - geometry=geometry) - new_part.setFlag(parted.PARTITION_BOOT) - disk.addPartition(partition=new_part, constraint=const) - disk.commit() - time.sleep(0.1) - __mkfs_fat__(new_part.path) - return new_part.path - - -def sectors_to_size(sectors, sector_size): - """Convert number of sectors to sector size""" - return (sectors * sector_size) / 1000 ** 2 - - -def __make_root__(device, start=config["ROOT"]["START"], - end=config["ROOT"]["END"], fs=config["ROOT"]["fs"]): - """Make root partition""" - # __parted__(device, ["mkpart", name, fs, str(start), str(end)]) - size = sectors_to_size(device.length, device.sectorSize) - try: - if start[-1] == "%": - start = int(start[:-1]) / 100 - start = int(size * start) - except TypeError: - pass - try: - if end[-1] == "%": - end = int(end[:-1]) / 100 - end = int(size * end) - except TypeError: - pass - disk = parted.Disk(device) - s_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(common.real_number(start - 20), - "MB", - device.sectorSize), - end=parted.sizeToSectors(start + 20, - "MB", - device.sectorSize)) - e_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(common.real_number(end - 100), - "MB", - device.sectorSize), - end=parted.sizeToSectors(end, "MB", - device.sectorSize)) - min_size = parted.sizeToSectors(common.real_number((end - start) - 250), - "MB", - device.sectorSize) - max_size = parted.sizeToSectors(common.real_number((end - start) + 250), - "MB", - device.sectorSize) - const = parted.Constraint(startAlign=device.optimumAlignment, - endAlign=device.optimumAlignment, - startRange=s_geo, endRange=e_geo, - minSize=min_size, - maxSize=max_size) - geo = parted.geometry.Geometry(start=parted.sizeToSectors(start, "MB", - device.sectorSize), - length=parted.sizeToSectors((end - start), - "MB", - device.sectorSize), - device=device) - new_part = parted.Partition(disk=disk, - type=parted.PARTITION_NORMAL, - geometry=geo) - try: - disk.addPartition(partition=new_part, constraint=const) - except parted._ped.PartitionException: - # Simply use the geometry of the first free space region, if it is big enough - data = disk.getFreeSpaceRegions() - sizes = {} - for each in data: - sizes[each.getSize(unit="b")] = each - sizes_sorted = sorted(sizes) - made = False - for each in range(len(sizes_sorted) - 1, -1, -1): - if sizes[sizes_sorted[each]].getSize(unit="b") >= get_min_root_size(): - s_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(common.real_number(sizes[sizes_sorted[each]].start - 2000), - "MB", - device.sectorSize), - end=parted.sizeToSectors(sizes[sizes_sorted[each]].start + 2000, - "MB", - device.sectorSize)) - e_geo = parted.geometry.Geometry(device=device, - start=parted.sizeToSectors(common.real_number(sizes[sizes_sorted[each]].end - 2000), - "MB", - device.sectorSize), - end=parted.sizeToSectors(sizes[sizes_sorted[each]].end + 2000, "MB", - device.sectorSize)) - min_size = parted.sizeToSectors(common.real_number((sizes[sizes_sorted[each]].end - sizes[sizes_sorted[each]].start) - 2000), - "MB", - device.sectorSize) - max_size = parted.sizeToSectors(common.real_number((sizes[sizes_sorted[each]].end - sizes[sizes_sorted[each]].start) + 2000), - "MB", - device.sectorSize) - const = parted.Constraint(startAlign=device.optimumAlignment, - endAlign=device.optimumAlignment, - startRange=s_geo, endRange=e_geo, - minSize=min_size, - maxSize=max_size) - new_part = parted.Partition(disk=disk, - type=parted.PARTITION_NORMAL, - geometry=sizes[sizes_sorted[each]]) - try: - disk.addPartition(partition=new_part, constraint=const) - except: - break - made = True - break - if not made: - common.eprint("WAS NOT ABLE TO CREATE ROOT PARTITION. LIKELY NOT ENOUGH SPACE FOR ONE.") - common.eprint("INSTALLATION WILL FAIL") - - disk.commit() - time.sleep(0.1) - __mkfs__(new_part.path, fs) - return new_part.path - - -def __make_home__(device, new_start=config["HOME"]["START"], - new_end=config["HOME"]["END"], new_fs=config["HOME"]["fs"]): - """Easy sorta-macro to make a home partiton""" - return __make_root__(device, start=new_start, end=new_end, fs=new_fs) - - -def __generate_return_data__(home, efi, part1, part2, part3): - """Generate return data for wherever we are in the code""" - parts = {} - if efi: - parts["EFI"] = part1 - parts["ROOT"] = part2 - else: - parts["EFI"] = None - parts["ROOT"] = part1 - if home != "MAKE": - parts["HOME"] = home - else: - if efi: - parts["HOME"] = part3 - else: - parts["HOME"] = part2 - return parts - - -def __make_root_boot__(device): - """Make Root partition bootable. - -This ONLY works if the root partition is the only partition on the drive -""" - disk = parted.Disk(device) - partitions = disk.getPrimaryPartitions() - partitions[0].setFlag(parted.PARTITION_BOOT) - disk.commit() - - -def make_part_boot(part_path): - """Make a partition bootable. - - This is useful for ensuring that users make their EFI partiton - (or root partition in the case of BIOS systems) bootable. - - part_path should be set to the path to the partition device file. - So, if a user's EFI partition is the first partition on a SATA or USB - interface, part_path should be: - - /dev/sda1 - - If the user's EFI partition is the 5th partition on the first NVMe drive on - the first NVMe bus: - - /dev/nvme0n1p5 - - etc... - """ - # Get root drive - root = get_drive_path(part_path) - # get Device - device = parted.getDevice(root) - # get entire partition table - disk = parted.Disk(device) - # narrow down to just primary partitions - partitions = disk.getPrimaryPartitions() - # mark designated partition as bootable - try: - if ("nvme" in part_path) or ("mmc" in part_path): - flags = partitions[int(part_path[part_path.index("p") + 1:])].getFlagsAsString().split(", ") - if "boot" not in flags: - partitions[int(part_path[part_path.index("p") + 1:])].setFlag(parted.PARTITION_BOOT) - else: - common.eprint(f"{ part_path } already marked as boot. Not re-marking.") - return - else: - flags = partitions[int(part_path[8:])].getFlagsAsString().split(", ") - if "boot" not in flags: - partitions[int(part_path[8:])].setFlag(parted.PARTITION_BOOT) - else: - common.eprint(f"{ part_path } already marked as boot. Not re-marking.") - return - except IndexError: - return - # We don't have commitment issues here! - disk.commit() - - -def clobber_disk(device): - """Reset drive""" - common.eprint("DELETING PARTITIONS.") - device.clobber() - disk = parted.freshDisk(device, "gpt") - disk.commit() - return disk - - -def delete_part(part_path): - """Delete partiton indicated by path""" - device = parted.getDevice(get_drive_path(part_path)) - disk = parted.Disk(device) - part = disk.getPartitionByPath(part_path) - disk.deletePartition(part) - disk.commit() - - -def partition(root, efi, home, raid_array): - """Partition drive 'root' for Linux installation - -root: needs to be path to installation drive (i.e.: /dev/sda, /dev/nvme0n1) -efi: booleen indicated whether system was booted with UEFI -home: whether to make a home partition, or if one already exists - -Possible values: - None, 'NULL': Do not make a home partition, and one does not exist - 'MAKE': Make a home partition on the installation drive - (some partition path): path to a partition to be used as home directory -""" - # Initial set up for partitioning - common.eprint("\t###\tauto_partioner.py STARTED\t###\t") - part1 = None - part2 = None - part3 = None - if raid_array["raid_type"] not in (None, "OEM"): - if raid_array["raid_type"].lower() == "raid0": - raid_array["raid_type"] = 0 - elif raid_array["raid_type"].lower() == "raid1": - raid_array["raid_type"] = 1 - elif raid_array["raid_type"].lower() == "raid10": - raid_array["raid_type"] = 10 - for each in raid_array["disks"]: - if each in ("1", "2"): - if raid_array["disks"][each] is None: - # Invalid RAID array. Do not create. - raid_array["raid_type"] = None - # We double check this to ensure we are working with valid RAID arrays - if raid_array["raid_type"] is not None: - disks = [] - for each in raid_array["disks"]: - if raid_array["disks"][each] is not None: - disks.append(raid_array["disks"][each]) - raid_array["disks"] = disks - device = parted.getDevice(root) - try: - disk = parted.Disk(device) - except parted._ped.DiskLabelException: - common.eprint("NO PARTITION TABLE EXISTS. MAKING NEW ONE . . .") - disk = parted.freshDisk(device, "gpt") - # sectors_to_size() returns size in MBs, multiply by 1 million to convert to bytes - size = sectors_to_size(device.length, device.sectorSize) * 1000000 - if ((home in ("NULL", "null", - None, "MAKE")) and (raid_array["raid_type"] is None)): - disk = clobber_disk(device) - elif raid_array["raid_type"] is not None: - disk = clobber_disk(device) - common.eprint("CREATING RAID ARRAY") - common.eprint(f"RAID TYPE: {raid_array['raid_type']}") - if not make_raid_array(raid_array["disks"], raid_array["raid_type"]): - common.eprint("INITIAL RAID ARRAY CREATION FAILED. FORCING . . .") - if not make_raid_array(raid_array["disks"], raid_array["raid_type"], - force=True): - common.eprint("FORCED RAID ARRAY CREATION FAILED. BAD DRIVE?") - common.eprint("FALLING BACK TO NO HOME PARTITION.") - home = None - else: - # we know there is a pre-existing home partition - # determine if it is on the same drive and act accordingly - home_drive = get_drive_path(home) - if home_drive == root: - common.eprint("HOME PARTITION EXISTS. NOT DELETING PARTITIONS.") - else: - disk = clobber_disk(device) - if size <= LIMITER: - if efi: - part1 = __make_efi__(device) - part2 = __make_root__(device, end="100%") - else: - part1 = __make_root__(device, start="0%", end="100%") - __make_root_boot__(device) - common.eprint("\t###\tauto_partioner.py CLOSED\t###\t") - return __generate_return_data__(home, efi, part1, part2, part3) - # Handled 16GB drives - # From here until 64GB drives, we want our root partition to be AT LEAST - # 16GB - if home == "MAKE": - # If home == "MAKE", we KNOW there are no partitons because we made a - # new partition table - if size >= gb_to_bytes(config["mdswh"]): - root_end = int((size * 0.35) / (1000 ** 2)) - else: - root_end = get_min_root_size() - if (efi and (part1 is None)): - part1 = __make_efi__(device) - part2 = __make_root__(device, end=root_end) - part3 = __make_home__(device, new_start=root_end) - elif part1 is None: - part1 = __make_root__(device, start="0%", end=root_end) - __make_root_boot__(device) - part2 = __make_home__(device, new_start=root_end) - common.eprint("\t###\tauto_partioner.py CLOSED\t###\t") - return __generate_return_data__(home, efi, part1, part2, part3) - if home in ("NULL", "null", None, "Home Partition", "home partition"): - # If home == any possible 'null' value, - # we KNOW there are no partitons because we made a - # new partition table - if efi: - part1 = __make_efi__(device) - part2 = __make_root__(device, end="100%") - else: - part1 = __make_root__(device, start="0%", end="100%") - __make_root_boot__(device) - common.eprint("\t###\tauto_partioner.py CLOSED\t###\t") - return __generate_return_data__(home, efi, part1, part2, part3) - # This one we need to figure out if the home partiton is on the drive - # we are working on or elsewhere - if root == get_drive_path(home): - # It IS on the same drive. We need to figure out where at and work - # around it - # NOTE: WE NEED TO WORK IN MB ONLY IN THIS SECTION - disk = parted.Disk(device) - data = disk.getFreeSpaceRegions() - sizes = {} - for each in data: - sizes[each.length] = each - sizes_sorted = sorted(sizes) - # Lets make some partitons! - if efi: - for each in sizes_sorted: - if sizes[each].getSize() >= 200: - end = sizes[each].start + parted.sizeToSectors(200, "MB", - device.sectorSize) - end = sectors_to_size(end, device.sectorSize) - part1 = __make_efi__(device, start=sizes[each].start, - end=end) - part2 = __make_root__(device, start=end, - end=sizes[each].end) - break - else: - for each in sizes_sorted: - if sizes[each].getSize() >= 200: - part1 = __make_root__(device, start=sizes[each].start + 1, - end=sizes[each].end - 1) - __make_root_boot__(device) - break - common.eprint("\t###\tauto_partioner.py CLOSED\t###\t") - return __generate_return_data__(home, efi, part1, part2, part3) - # it's elsewhere. We're good. - if efi: - part1 = __make_efi__(device) - part2 = __make_root__(device, end="100%") - else: - part1 = __make_root__(device, start="0%", end="100%") - __make_root_boot__(device) - part3 = home - # Figure out what parts are for what - # Return that data as a dictonary - common.eprint("\t###\tauto_partioner.py CLOSED\t###\t") - return __generate_return_data__(home, efi, part1, part2, part3) - - -def make_raid_array(disks: list, raid_type: int, force=False) -> bool: - """Make BTRFS RAID Array - Supported RAID Types: - RAID0: Minimum 2 drives, max performance, no resiliancey - RAID1: Minimum 2 drives, max resiliancey, minimum performance - RAID5: 3-16 drives, poor resiliancey, great read performance, poor write performance - RAID6: Minimum 4 drives. Medium resiliancey, great read performance, worse write performance - RAID10: Minimum 4 drives, Medium resiliancey, Great performance - - raid_type should be an int indicating the RAID type desired so: - raid_type == 0: use RAID0 - raid_type == 1: use RAID1 - etc. - - Any ints other than 0, 1, 5, 6, and 10 will throw a ValueError - - disks should be a list of the disks desired in the RAID array. A ValueError - will be thrown if the list is too short or too long. - - Returns True if array was successfully completed. False otherwise. - You can then mount the array by calling `mount' on any of the devices in the - disks list. - """ - raid_types_dict = {0: "raid0", - 1: "raid1", - 5: "raid5", - 6: "raid6", - 10: "raid10"} - command = ["mkfs.btrfs", "-d"] - if force: - command.insert(1, "-f") - if raid_type not in raid_types_dict: - raise ValueError(f"'{raid_type}' not a valid BTRFS RAID type") - if raid_type in (0, 1): - if len(disks) < 2: - raise ValueError(f"Not enough disks for RAID{raid_type}") - elif raid_type == 5: - if not 3 <= len(disks) <= 16: - raise ValueError("Not enough/Too many disks for RAID5") - elif raid_type in (6, 10): - if len(disks) < 4: - raise ValueError(f"Not enough disks for RAID{raid_type}") - for each in disks: - if not os.path.exists(each): - raise FileNotFoundError(f"Device not found: {each}") - command.append(raid_types_dict[raid_type]) - if raid_type not in (0, 5, 6): - command.append("-m") - command.append(raid_types_dict[raid_type]) - command = command + disks - try: - subprocess.check_call(command, stderr=sys.stderr.buffer, - stdout=sys.stderr.buffer) - return True - except subprocess.CalledProcessError: - return False diff --git a/usr/share/edamame/UI/QT_UI/auto_partitioner.py b/usr/share/edamame/UI/QT_UI/auto_partitioner.py new file mode 120000 index 0000000..957253b --- /dev/null +++ b/usr/share/edamame/UI/QT_UI/auto_partitioner.py @@ -0,0 +1 @@ +../../auto_partitioner.py \ No newline at end of file diff --git a/usr/share/edamame/UI/QT_UI/common.py b/usr/share/edamame/UI/QT_UI/common.py deleted file mode 100755 index fefe2bb..0000000 --- a/usr/share/edamame/UI/QT_UI/common.py +++ /dev/null @@ -1,107 +0,0 @@ -#!shebang -# -*- coding: utf-8 -*- -# -# common.py -# -# Copyright 2024 Thomas Castleman -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, -# MA 02110-1301, USA. -# -# -"""Common functions and other data for edamame""" -import sys -import os - - -def unique(starting_list): - """Function to get a list down to only unique elements""" - # initialize a null list - # unique_list = [] - # traverse for all elements - # for each in starting_list: - # check if exists in unique_list or not - # if each not in unique_list: - # unique_list.append(each) - # return unique_list - return list(set(starting_list)) - - -def eprint(*args, **kwargs): - """Make it easier for us to print to stderr""" - print(*args, file=sys.stderr, **kwargs) - - -def real_number(num): - """Take an int or float and return an int that is 0 or higher - - This DOES NOT return absolute value. Any negative numbers will return 0. - Passing in anything other than an int or float will raise a TypeError - Valid floats that are passed are truncated, not rounded. - """ - if not isinstance(num, (int, float)): - raise TypeError("Not a valid int or float") - if num >= 0: - return int(num) - return 0 - - -def recursive_mkdir(path): - """ Recursively make directories down a file path - - This function is functionally equivallent to: `mkdir -p {path}' - """ - path = path.split("/") - for each in enumerate(path): - dir = "/".join(path[:each[0] + 1]) - # prevent calling mkdir() on an empty string - if dir != "": - try: - os.mkdir(dir) - except FileExistsError: - pass - -def item_in_list(item, array): - """Check if an item is in a list. This is supposed to be faster than: - - 'item' in 'array' - - This only speeds things up in situations with more than about 10 items in a list - """ - new_arr = set(array) - for each in array: - if item == each: - return True - return False - - -def determine_toolkit(): - """Determine System UI toolkit""" - UI_by_DE = { - "gnome": "GTK", - "xfce": "GTK", - "lxde": "GTK", - "mate": "GTK", - "unity": "GTK", - "cinnamon": "GTK", - "pantheon": "GTK", - "kde": "Qt", - "lxqt": "Qt", - "lomiri": "Qt", - "dde": "Qt", - "deepin": "Qt" - - } - return UI_by_DE[os.environ["XDG_CURRENT_DESKTOP"].lower()] diff --git a/usr/share/edamame/UI/QT_UI/common.py b/usr/share/edamame/UI/QT_UI/common.py new file mode 120000 index 0000000..349c5f0 --- /dev/null +++ b/usr/share/edamame/UI/QT_UI/common.py @@ -0,0 +1 @@ +../../common.py \ No newline at end of file diff --git a/usr/share/edamame/engine.py b/usr/share/edamame/engine.py index 348ae0a..640ef00 100755 --- a/usr/share/edamame/engine.py +++ b/usr/share/edamame/engine.py @@ -72,6 +72,7 @@ def shutdown(boot_time: bool, immersion_obj: dec.Immersion, BOOT_TIME = False immerse = dec.Immersion() +gui = "gtk" if len(sys.argv) > 1: if sys.argv[1] == "--boot-time": # OEM post-install configuration, on-boot installation, and more @@ -93,13 +94,12 @@ def shutdown(boot_time: bool, immersion_obj: dec.Immersion, immerse.enable() elif "--gui=" in sys.argv[1]: gui = sys.argv[1].split("=")[-1] - try: - UI = UI.load_UI(gui.upper()) - except ImportError: - common.eprint(f"FATAL ERROR: GUI METHOD '{gui}' DOES NOT EXIST!") - sys.exit(1) -else: - UI = UI.load_UI("GTK") + +try: + UI = UI.load_UI(gui.upper()) +except ImportError: + common.eprint(f"FATAL ERROR: GUI METHOD '{gui}' DOES NOT EXIST!") + sys.exit(1) MEMCHECK = psutil.virtual_memory().total if (MEMCHECK / 1024 ** 2) < 1024: @@ -219,7 +219,7 @@ def shutdown(boot_time: bool, immersion_obj: dec.Immersion, process = subprocess.Popen(command) pid = process.pid SETTINGS["INTERNET"] = check_internet.has_internet() - installer.install(SETTINGS, CONFIG["local_repo"]) + installer.install(SETTINGS, CONFIG["local_repo"], ui_type=gui) shutil.rmtree("/mnt/repo") common.eprint(f" ### {sys.argv[0]} CLOSED ### ") copy_log_to_disk() diff --git a/usr/share/edamame/installer.py b/usr/share/edamame/installer.py index b832c6d..f47062d 100755 --- a/usr/share/edamame/installer.py +++ b/usr/share/edamame/installer.py @@ -33,7 +33,6 @@ import common import auto_partitioner -UI = UI.load_UI("GTK") def __mount__(device, path_dir): """Mount device at path @@ -58,7 +57,7 @@ def __update__(percentage): progress.write(str(percentage)) -def install(settings, local_repo): +def install(settings: dict, local_repo: str, ui_type: str) -> None: """Begin installation proceidure settings should be a dictionary with the following values: @@ -86,6 +85,7 @@ def install(settings, local_repo): json.loads()["DATA"] to see an example of acceptable settings """ common.eprint(" ### installer.py STARTED ### ") + UI = UI.load_UI(ui_type) work_dir = "/tmp/quick-install_working-dir" # STEP 1: Partion and format the drive ( if needed ) if settings["AUTO_PART"]: From 638d24847e154a64dd15505e9ecd74d1732c0ea6 Mon Sep 17 00:00:00 2001 From: Thomas Castleman Date: Wed, 20 Nov 2024 00:31:37 -0500 Subject: [PATCH 2/2] Minor PEP8 improvements --- usr/share/edamame/installer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/usr/share/edamame/installer.py b/usr/share/edamame/installer.py index f47062d..8812b24 100755 --- a/usr/share/edamame/installer.py +++ b/usr/share/edamame/installer.py @@ -181,7 +181,7 @@ def install(settings: dict, local_repo: str, ui_type: str) -> None: "/mnt/tmp/edamame-progress.log") os.remove("/tmp/edamame-progress.log") os.symlink("/mnt/tmp/edamame-progress.log", - "/tmp/edamame-progress.log") + "/tmp/edamame-progress.log") __update__(32) # STEP 4: Update fstab common.eprint(" ### Updating FSTAB ### ") @@ -253,8 +253,7 @@ def install(settings: dict, local_repo: str, ui_type: str) -> None: common.eprint(" ### SYSTEMD-BOOT NOT CONFIGURED. CORRECTING . . . ### ") check_call(["arch-chroot", "/mnt", "systemd-boot-manager", "-r"]) try: - shutil.rmtree("/mnt/home/" + settings["USERNAME"] + - "/.config/xfce4/panel/launcher-3") + shutil.rmtree(f"/mnt/home/{settings["USERNAME"]}/.config/xfce4/panel/launcher-3") except FileNotFoundError: pass __update__(100)