remove old unused code
This commit is contained in:
parent
675083fb19
commit
bd8f67decc
7 changed files with 0 additions and 886 deletions
|
@ -21,13 +21,4 @@ func Tui() {
|
|||
|
||||
// New WIP Tui
|
||||
pages.Welcome()
|
||||
/*
|
||||
// Make a blank model to keep our state in
|
||||
m := NewModel()
|
||||
|
||||
// Start the program with the model
|
||||
p := tea.NewProgram(m, tea.WithAltScreen())
|
||||
_, err = p.Run()
|
||||
errorcheck.ErrorCheck(err, "Failed to initialize UI")
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -1,126 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
||||
"github.com/HikariKnight/quickpassthrough/pkg/command"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
|
||||
// If we are not done
|
||||
if m.focused != INSTALL && m.focused != DONE {
|
||||
// Setup keybindings
|
||||
switch msg.String() {
|
||||
case "ctrl+c", "q":
|
||||
// Exit when user presses Q or CTRL+C
|
||||
return m, tea.Quit
|
||||
|
||||
case "enter":
|
||||
if m.width != 0 {
|
||||
// Process the selected item, if the return value is true then exit alt screen
|
||||
if !m.processSelection() {
|
||||
return m, tea.ExitAltScreen
|
||||
}
|
||||
}
|
||||
case "ctrl+z", "backspace":
|
||||
// Go backwards in the model
|
||||
if m.focused > 0 && m.focused != DONE {
|
||||
m.focused--
|
||||
return m, nil
|
||||
} else {
|
||||
// If we are at the beginning, just exit
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we are done then handle keybindings a bit differently
|
||||
// Setup keybindings for authDialog
|
||||
switch msg.String() {
|
||||
case "ctrl+z":
|
||||
// Since we have no QuickEmu support, skip the usb controller configuration
|
||||
m.focused = VIDEO
|
||||
|
||||
case "ctrl+c":
|
||||
// Exit when user presses CTRL+C
|
||||
return m, tea.Quit
|
||||
|
||||
case "enter":
|
||||
// If we are on the INSTALL dialog
|
||||
if m.focused == INSTALL && m.authDialog.Value() != "" {
|
||||
// Write to logger
|
||||
logger.Printf("Getting authentication token by elevating with sudo once")
|
||||
|
||||
// Elevate with sudo
|
||||
command.Elevate(
|
||||
base64.StdEncoding.EncodeToString(
|
||||
[]byte(
|
||||
m.authDialog.Value(),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
// Write to logger
|
||||
logger.Printf("Attempting to free hash from memory")
|
||||
|
||||
// Blank the password field
|
||||
m.authDialog.SetValue("")
|
||||
|
||||
fmt.Println(titleStyle.Render("Working... Application frozen until done, check debug.log for progress"))
|
||||
|
||||
// Start installation and send the password to the command
|
||||
m.install()
|
||||
|
||||
// Move to the DONE dialog
|
||||
m.focused = DONE
|
||||
|
||||
// Exit the alt screen as the output on the done dialog needs to be scrollable
|
||||
return m, tea.ClearScreen
|
||||
|
||||
} else {
|
||||
// Quit the application if we are on a different view
|
||||
return m, tea.Quit
|
||||
}
|
||||
}
|
||||
|
||||
// Issue an UI update
|
||||
m.authDialog, cmd = m.authDialog.Update(msg)
|
||||
return m, cmd
|
||||
}
|
||||
case tea.WindowSizeMsg:
|
||||
if m.width == 0 {
|
||||
// Initialize the static lists and make sure the content
|
||||
// does not extend past the screen
|
||||
m.initLists(msg.Width, msg.Height)
|
||||
|
||||
} else {
|
||||
// Else we are loaded and will update the sizing on the fly
|
||||
m.height = msg.Height
|
||||
m.width = msg.Width
|
||||
|
||||
// TODO: Find a better way to resize widgets when word wrapping happens
|
||||
// BUG: currently breaks the UI rendering if word wrapping happens in some cases...
|
||||
views := len(m.lists)
|
||||
if msg.Width > 83 {
|
||||
for i := 0; i < views; i++ {
|
||||
m.lists[i].SetSize(m.width-m.offsetx[i], m.height-m.offsety[i])
|
||||
// Update the styles with the correct width
|
||||
dialogStyle = dialogStyle.Width(m.width)
|
||||
listStyle = listStyle.Width(m.width)
|
||||
titleStyle = titleStyle.Width(m.width - 4)
|
||||
choiceStyle = choiceStyle.Width(m.width)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run another update loop
|
||||
m.lists[m.focused], cmd = m.lists[m.focused].Update(msg)
|
||||
return m, cmd
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
||||
"github.com/HikariKnight/quickpassthrough/internal/configs"
|
||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
||||
"github.com/HikariKnight/quickpassthrough/pkg/command"
|
||||
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
|
||||
"github.com/HikariKnight/quickpassthrough/pkg/uname"
|
||||
)
|
||||
|
||||
// This function processes the enter event
|
||||
func (m *model) processSelection() bool {
|
||||
switch m.focused {
|
||||
case GPUS:
|
||||
// Gets the selected item
|
||||
selectedItem := m.lists[m.focused].SelectedItem()
|
||||
|
||||
// Gets the IOMMU group of the selected item
|
||||
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
|
||||
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
|
||||
|
||||
// Add the gpu group to our model (this is so we can grab the vbios details later)
|
||||
m.gpu_group = iommu_group
|
||||
|
||||
// Get all the gpu devices and related devices (same device id or in the same group)
|
||||
items := iommuList2ListItem(getIOMMU("-grr", "-i", m.gpu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
||||
|
||||
// Add the devices to the list
|
||||
m.lists[GPU_GROUP].SetItems(items)
|
||||
|
||||
// Change focus to next index
|
||||
m.focused++
|
||||
|
||||
case GPU_GROUP:
|
||||
// Get the config
|
||||
config := configs.GetConfig()
|
||||
|
||||
// Get the vbios path
|
||||
m.vbios_path = getIOMMU("-g", "-i", m.gpu_group, "--rom")[0]
|
||||
|
||||
// Generate the VBIOS dumper script once the user has selected a GPU
|
||||
configs.GenerateVBIOSDumper(m.vbios_path)
|
||||
|
||||
// Get the device ids for the selected gpu using ls-iommu
|
||||
m.gpu_IDs = getIOMMU("-gr", "-i", m.gpu_group, "--id")
|
||||
|
||||
// If the kernel_args file already exists
|
||||
if fileio.FileExist(config.Path.CMDLINE) {
|
||||
// Delete it as we will have to make a new one anyway
|
||||
err := os.Remove(config.Path.CMDLINE)
|
||||
errorcheck.ErrorCheck(err, fmt.Sprintf("Could not remove %s", config.Path.CMDLINE))
|
||||
}
|
||||
|
||||
// Write initial kernel_arg file
|
||||
configs.Set_Cmdline(m.gpu_IDs)
|
||||
|
||||
// Change focus to the next view
|
||||
m.focused++
|
||||
|
||||
case USB:
|
||||
// Gets the selected item
|
||||
selectedItem := m.lists[m.focused].SelectedItem()
|
||||
|
||||
// Gets the IOMMU group of the selected item
|
||||
iommu_group_regex := regexp.MustCompile(`(\d{1,3})`)
|
||||
iommu_group := iommu_group_regex.FindString(selectedItem.(item).desc)
|
||||
|
||||
// Get the USB controllers in the selected iommu group
|
||||
items := iommuList2ListItem(getIOMMU("-ur", "-i", iommu_group, "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
||||
|
||||
// Add the items to the list
|
||||
m.lists[USB_GROUP].SetItems(items)
|
||||
|
||||
// Change focus to next index
|
||||
m.focused++
|
||||
|
||||
case USB_GROUP:
|
||||
m.focused++
|
||||
|
||||
case VBIOS:
|
||||
// This is just an OK Dialog
|
||||
m.focused++
|
||||
|
||||
case VIDEO:
|
||||
// This is a YESNO Dialog
|
||||
// Gets the selected item
|
||||
selectedItem := m.lists[m.focused].SelectedItem()
|
||||
|
||||
// Get our config struct
|
||||
config := configs.GetConfig()
|
||||
|
||||
// If user selected yes then
|
||||
if selectedItem.(item).title == "YES" {
|
||||
// Add disable VFIO video to the config
|
||||
configs.DisableVFIOVideo(1)
|
||||
} else {
|
||||
// Add disable VFIO video to the config
|
||||
configs.DisableVFIOVideo(0)
|
||||
}
|
||||
|
||||
// If we have files for modprobe
|
||||
if fileio.FileExist(config.Path.MODPROBE) {
|
||||
// Configure modprobe
|
||||
configs.Set_Modprobe(m.gpu_IDs)
|
||||
}
|
||||
|
||||
// If we have a folder for dracut
|
||||
if fileio.FileExist(config.Path.DRACUT) {
|
||||
// Configure dracut
|
||||
configs.Set_Dracut()
|
||||
}
|
||||
|
||||
// If we have a mkinitcpio.conf file
|
||||
if fileio.FileExist(config.Path.MKINITCPIO) {
|
||||
configs.Set_Mkinitcpio()
|
||||
}
|
||||
|
||||
// Configure grub2 here as we can make the config without sudo
|
||||
if config.Bootloader == "grub2" {
|
||||
// Write to logger
|
||||
logger.Printf("Configuring grub2 manually")
|
||||
configs.Configure_Grub2()
|
||||
}
|
||||
|
||||
// Go to the next view
|
||||
//m.focused++
|
||||
|
||||
// Because we have no QuickEmu support yet, just skip USB Controller configuration
|
||||
m.focused = INSTALL
|
||||
return true
|
||||
|
||||
case INTRO:
|
||||
// This is an OK Dialog
|
||||
// Create the config folder and the files related to this system
|
||||
configs.InitConfigs()
|
||||
|
||||
// Go to the next view
|
||||
m.focused++
|
||||
|
||||
case DONE:
|
||||
// Return true so that the application will exit nicely
|
||||
return true
|
||||
}
|
||||
|
||||
// Return false as we are not done
|
||||
return false
|
||||
}
|
||||
|
||||
// This function starts the install process
|
||||
// It takes 1 auth string as variable
|
||||
func (m *model) install() {
|
||||
// Get the config
|
||||
config := configs.GetConfig()
|
||||
|
||||
// Make a stringlist to keep the output to show the user
|
||||
var output []string
|
||||
|
||||
// Based on the bootloader, setup the configuration
|
||||
if config.Bootloader == "kernelstub" {
|
||||
// Write to logger
|
||||
logger.Printf("Configuring systemd-boot using kernelstub")
|
||||
|
||||
// Configure kernelstub
|
||||
output = append(output, configs.Set_KernelStub())
|
||||
|
||||
} else if config.Bootloader == "grubby" {
|
||||
// Write to logger
|
||||
logger.Printf("Configuring bootloader using grubby")
|
||||
|
||||
// Configure kernelstub
|
||||
output = append(output, configs.Set_Grubby())
|
||||
|
||||
} else if config.Bootloader == "grub2" {
|
||||
// Write to logger
|
||||
logger.Printf("Configuring grub2 manually")
|
||||
grub_output, _ := configs.Set_Grub2()
|
||||
output = append(output, grub_output...)
|
||||
|
||||
} else {
|
||||
kernel_args := fileio.ReadFile(config.Path.CMDLINE)
|
||||
logger.Printf("Unsupported bootloader, please add the below line to your bootloaders kernel arguments\n%s", kernel_args)
|
||||
}
|
||||
|
||||
// A lot of linux systems support modprobe along with their own module system
|
||||
// So copy the modprobe files if we have them
|
||||
modprobeFile := fmt.Sprintf("%s/vfio.conf", config.Path.MODPROBE)
|
||||
if fileio.FileExist(modprobeFile) {
|
||||
// Copy initramfs-tools module to system
|
||||
output = append(output, configs.CopyToSystem(modprobeFile, "/etc/modprobe.d/vfio.conf"))
|
||||
}
|
||||
|
||||
// Copy the config files for the system we have
|
||||
initramfsFile := fmt.Sprintf("%s/modules", config.Path.INITRAMFS)
|
||||
dracutFile := fmt.Sprintf("%s/vfio.conf", config.Path.DRACUT)
|
||||
if fileio.FileExist(initramfsFile) {
|
||||
// Copy initramfs-tools module to system
|
||||
output = append(output, configs.CopyToSystem(initramfsFile, "/etc/initramfs-tools/modules"))
|
||||
|
||||
// Copy the modules file to /etc/modules
|
||||
output = append(output, configs.CopyToSystem(config.Path.ETCMODULES, "/etc/modules"))
|
||||
|
||||
// Write to logger
|
||||
logger.Printf("Executing: sudo update-initramfs -u")
|
||||
|
||||
// Update initramfs
|
||||
output = append(output, "Executed: sudo update-initramfs -u\nSee debug.log for detailed output")
|
||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "update-initramfs", "-u")
|
||||
|
||||
cmd_out = append(cmd_out, cmd_err...)
|
||||
|
||||
// Write to logger
|
||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
||||
} else if fileio.FileExist(dracutFile) {
|
||||
// Copy dracut config to /etc/dracut.conf.d/vfio
|
||||
output = append(output, configs.CopyToSystem(dracutFile, "/etc/dracut.conf.d/vfio"))
|
||||
|
||||
// Get systeminfo
|
||||
sysinfo := uname.New()
|
||||
|
||||
// Write to logger
|
||||
logger.Printf("Executing: sudo dracut -f -v --kver %s", sysinfo.Release)
|
||||
|
||||
// Update initramfs
|
||||
output = append(output, fmt.Sprintf("Executed: sudo dracut -f -v --kver %s\nSee debug.log for detailed output", sysinfo.Release))
|
||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "dracut", "-f", "-v", "--kver", sysinfo.Release)
|
||||
|
||||
cmd_out = append(cmd_out, cmd_err...)
|
||||
|
||||
// Write to logger
|
||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
||||
} else if fileio.FileExist(config.Path.MKINITCPIO) {
|
||||
// Copy dracut config to /etc/dracut.conf.d/vfio
|
||||
output = append(output, configs.CopyToSystem(config.Path.MKINITCPIO, "/etc/mkinitcpio.conf"))
|
||||
|
||||
// Write to logger
|
||||
logger.Printf("Executing: sudo mkinitcpio -P")
|
||||
|
||||
// Update initramfs
|
||||
output = append(output, "Executed: sudo mkinitcpio -P\nSee debug.log for detailed output")
|
||||
cmd_out, cmd_err, _ := command.RunErr("sudo", "mkinitcpio", "-P")
|
||||
|
||||
cmd_out = append(cmd_out, cmd_err...)
|
||||
|
||||
// Write to logger
|
||||
logger.Printf(strings.Join(cmd_out, "\n"))
|
||||
}
|
||||
|
||||
m.installOutput = output
|
||||
m.focused++
|
||||
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/HikariKnight/quickpassthrough/internal/configs"
|
||||
"github.com/HikariKnight/quickpassthrough/pkg/fileio"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
func (m model) View() string {
|
||||
if m.width != 0 {
|
||||
title := ""
|
||||
view := ""
|
||||
switch m.focused {
|
||||
case INTRO:
|
||||
title = dialogStyle.Render(
|
||||
fmt.Sprint(
|
||||
titleStyle.MarginLeft(0).Render("Welcome to QuickPassthrough!"),
|
||||
"\n\n",
|
||||
"This script is meant to make it easier to setup GPU passthrough for\n",
|
||||
"Qemu based systems. WITH DIFFERENT 2 GPUS ON THE HOST SYSTEM\n",
|
||||
"However due to the complexity of GPU passthrough\n",
|
||||
"This script assumes you know how to do (or have done) the following.\n\n",
|
||||
"* You have already enabled IOMMU, VT-d, SVM and/or AMD-v\n inside your UEFI/BIOS advanced settings.\n",
|
||||
"* Know how to edit your bootloader\n",
|
||||
"* Have a bootloader timeout of at least 3 seconds to access the menu\n",
|
||||
"* Enable & Configure kernel modules\n",
|
||||
"* Have a backup/snapshot of your system in case the script causes your\n system to be unbootable\n\n",
|
||||
"By continuing you accept that I am not liable if your system\n",
|
||||
"becomes unbootable, as you will be asked to verify the files generated",
|
||||
),
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case GPUS:
|
||||
title = titleStyle.MarginLeft(2).Render(
|
||||
"Select a GPU to check the IOMMU groups of",
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case GPU_GROUP:
|
||||
title = titleStyle.Render(
|
||||
fmt.Sprint(
|
||||
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
|
||||
"This list should only contain items related to your GPU.",
|
||||
),
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case USB:
|
||||
title = titleStyle.Render(
|
||||
"[OPTIONAL]: Select a USB Controller to check the IOMMU groups of",
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case USB_GROUP:
|
||||
title = titleStyle.Render(
|
||||
fmt.Sprint(
|
||||
"Press ENTER/RETURN to set up all these devices for passthrough.\n",
|
||||
"This list should only contain the USB controller you want to use.",
|
||||
),
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case VBIOS:
|
||||
// Get the program directory
|
||||
exe, _ := os.Executable()
|
||||
scriptdir := filepath.Dir(exe)
|
||||
|
||||
// If we are using go run use the working directory instead
|
||||
if strings.Contains(scriptdir, "/tmp/go-build") {
|
||||
scriptdir, _ = os.Getwd()
|
||||
}
|
||||
|
||||
text := dialogStyle.Render(
|
||||
fmt.Sprint(
|
||||
"Based on your GPU selection, a vbios extraction script has been generated for your convenience.\n",
|
||||
"Passing a VBIOS rom to the card used for passthrough is required for some cards, but not all.\n",
|
||||
"Some cards also requires you to patch your VBIOS romfile, check online if this is neccessary for your card!\n",
|
||||
"The VBIOS will be read from:\n",
|
||||
fmt.Sprintf(
|
||||
"%s\n\n",
|
||||
m.vbios_path,
|
||||
),
|
||||
"The script to extract the vbios has to be run as sudo and without a displaymanager running for proper dumping!\n",
|
||||
"\n",
|
||||
"You can run the script with:\n",
|
||||
fmt.Sprintf(
|
||||
"%s/utils/dump_vbios.sh",
|
||||
scriptdir,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
title = fmt.Sprintf(text, m.vbios_path, scriptdir)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case VIDEO:
|
||||
title = dialogStyle.Render(
|
||||
fmt.Sprint(
|
||||
"Disabling video output in Linux for the card you want to use in a VM\n",
|
||||
"will make it easier to successfully do the passthrough without issues.\n",
|
||||
"\n",
|
||||
"Do you want to force disable video output in linux on this card?",
|
||||
),
|
||||
)
|
||||
|
||||
view = listStyle.Render(m.lists[m.focused].View())
|
||||
|
||||
case INSTALL:
|
||||
title = dialogStyle.Render(
|
||||
fmt.Sprint(
|
||||
"The configuration files have been generated and are\n",
|
||||
"located inside the \"config\" folder\n",
|
||||
"\n",
|
||||
"* The \"kernel_args\" file contains kernel arguments that your bootloader needs\n",
|
||||
"* The \"quickemu\" folder contains files that might be\n useable for quickemu in the future\n",
|
||||
"* The files inside the \"etc\" folder must be copied to your system.\n",
|
||||
" NOTE: Verify that these files are correctly formated/edited!\n",
|
||||
"* Once all files have been copied, you need to update your bootloader and rebuild\n",
|
||||
" your initramfs using the tools to do so by your system.\n",
|
||||
"\n",
|
||||
"This program can do this for you, however the program will have to\n",
|
||||
"type your password to sudo using STDIN, to avoid using STDIN press CTRL+C\n",
|
||||
"and copy the files, update your bootloader and rebuild your initramfs manually.\n",
|
||||
"If you want to go back and change something, press CTRL+Z\n",
|
||||
"\nNOTE: A backup of the original files from the first run can be found in the backup folder",
|
||||
),
|
||||
)
|
||||
|
||||
view = m.authDialog.View()
|
||||
|
||||
case WORKING:
|
||||
title = titleStyle.Render("Applying configurations!")
|
||||
view = ""
|
||||
|
||||
m.authDialog.Update(tea.KeyEnter)
|
||||
tea.Batch()
|
||||
|
||||
case DONE:
|
||||
title = titleStyle.Render("Applied configurations!")
|
||||
|
||||
view = dialogStyle.Render(fmt.Sprintf("%s\n\nPress Enter to Exit.", strings.Join(m.installOutput, "\n")))
|
||||
|
||||
// If the bootloader is unknown/unsupported
|
||||
config := configs.GetConfig()
|
||||
if config.Bootloader == "unknown" {
|
||||
// Change the view to reflect that
|
||||
view = dialogStyle.Render(fmt.Sprintf("%s\n\nI do not have a good way to reliably edit your bootloader!\nPlease add: %s\nTo your bootloaders kernel arguments.\nPress Enter to Exit.", strings.Join(m.installOutput, "\n"), fileio.ReadFile(config.Path.CMDLINE)))
|
||||
}
|
||||
}
|
||||
//return listStyle.SetString(fmt.Sprintf("%s\n\n", title)).Render(m.lists[m.focused].View())
|
||||
return lipgloss.JoinVertical(lipgloss.Left, fmt.Sprintf("%s\n%s\n", title, view))
|
||||
} else {
|
||||
return "Loading..."
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/user"
|
||||
|
||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
)
|
||||
|
||||
// Make a status type
|
||||
type status int
|
||||
|
||||
// List item struct
|
||||
type item struct {
|
||||
title, desc string
|
||||
}
|
||||
|
||||
// Functions needed for item struct
|
||||
func (i item) Title() string { return i.title }
|
||||
func (i item) Description() string { return i.desc }
|
||||
func (i item) FilterValue() string { return i.title }
|
||||
|
||||
// Main Model
|
||||
type model struct {
|
||||
fetched []bool
|
||||
lists []list.Model
|
||||
gpu_group string
|
||||
gpu_IDs []string
|
||||
vbios_path string
|
||||
focused status
|
||||
offsetx []int
|
||||
offsety []int
|
||||
width int
|
||||
height int
|
||||
authDialog textinput.Model
|
||||
installOutput []string
|
||||
}
|
||||
|
||||
// Consts used to navigate the main model
|
||||
const (
|
||||
INTRO status = iota
|
||||
GPUS
|
||||
GPU_GROUP
|
||||
VBIOS
|
||||
VIDEO
|
||||
USB
|
||||
USB_GROUP
|
||||
INSTALL
|
||||
WORKING
|
||||
DONE
|
||||
)
|
||||
|
||||
func NewModel() *model {
|
||||
// Get the username
|
||||
user, err := user.Current()
|
||||
errorcheck.ErrorCheck(err, "Error getting username")
|
||||
username := user.Username
|
||||
|
||||
// Create the auth input and focus it
|
||||
authInput := textinput.New()
|
||||
authInput.EchoMode = textinput.EchoPassword
|
||||
authInput.Prompt = fmt.Sprintf("\n[sudo] password for %s: ", username)
|
||||
authInput.Focus()
|
||||
|
||||
// Create a blank model and return it
|
||||
return &model{
|
||||
authDialog: authInput,
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *model) initLists(width, height int) {
|
||||
defaultList := list.New([]list.Item{}, list.NewDefaultDelegate(), 0, 10)
|
||||
choiceList := list.New([]list.Item{}, choiceDelegate{}, 0, 7)
|
||||
|
||||
// Disable features we wont need
|
||||
defaultList.SetShowTitle(false)
|
||||
defaultList.SetFilteringEnabled(false)
|
||||
defaultList.SetSize(m.width, m.height)
|
||||
choiceList.SetShowTitle(false)
|
||||
choiceList.SetFilteringEnabled(false)
|
||||
|
||||
// Add height and width to our model so we can use it later
|
||||
m.width = width
|
||||
m.height = height
|
||||
|
||||
m.lists = []list.Model{
|
||||
choiceList,
|
||||
defaultList,
|
||||
defaultList,
|
||||
choiceList,
|
||||
choiceList,
|
||||
defaultList,
|
||||
defaultList,
|
||||
choiceList,
|
||||
choiceList,
|
||||
choiceList,
|
||||
}
|
||||
|
||||
// Configure offsets for sizing
|
||||
m.offsetx = []int{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
}
|
||||
m.offsety = []int{
|
||||
18, 2, 3, 13, 5, 2, 3, 12, 0, 0,
|
||||
}
|
||||
|
||||
// Update the styles with the correct width
|
||||
dialogStyle = dialogStyle.Width(m.width)
|
||||
listStyle = listStyle.Width(m.width)
|
||||
titleStyle = titleStyle.Width(m.width - 4)
|
||||
choiceStyle = choiceStyle.Width(m.width)
|
||||
|
||||
// Make m.fetched and set all values to FALSE
|
||||
m.fetched = []bool{}
|
||||
for range m.lists {
|
||||
m.fetched = append(m.fetched, false)
|
||||
}
|
||||
|
||||
// Set INTRO to the focused view
|
||||
m.focused = INTRO
|
||||
|
||||
// Init INTRO choices
|
||||
items := []list.Item{
|
||||
item{title: "CONTINUE"},
|
||||
}
|
||||
//m.lists[INTRO].SetHeight(5)
|
||||
m.lists[INTRO].SetItems(items)
|
||||
m.lists[INTRO].SetSize(m.width-m.offsetx[INTRO], m.height-m.offsety[INTRO])
|
||||
|
||||
// Init GPU list
|
||||
items = iommuList2ListItem(getIOMMU("-g", "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
||||
m.lists[GPUS].SetItems(items)
|
||||
m.lists[GPUS].SetSize(m.width-m.offsetx[GPUS], m.height-m.offsety[GPUS])
|
||||
m.fetched[GPUS] = true
|
||||
|
||||
// Setup the initial GPU_GROUP list
|
||||
// The content in this list is generated from the selected choice from the GPU view
|
||||
m.lists[GPU_GROUP].SetSize(m.width-m.offsetx[GPU_GROUP], m.height-m.offsety[GPU_GROUP])
|
||||
|
||||
// Init USB Controller list
|
||||
items = iommuList2ListItem(getIOMMU("-u", "-F", "vendor:,prod_name,optional_revision:,device_id"))
|
||||
m.lists[USB].SetItems(items)
|
||||
m.lists[USB].SetSize(m.width-m.offsetx[USB], m.height-m.offsety[USB])
|
||||
m.fetched[USB] = true
|
||||
|
||||
// Setup the initial USB_GROUP list
|
||||
// The content in this list is generated from the selected choice from the USB view
|
||||
m.lists[USB_GROUP].SetSize(m.width-m.offsetx[USB_GROUP], m.height-m.offsety[USB_GROUP])
|
||||
|
||||
// Init VBIOS choices
|
||||
items = []list.Item{
|
||||
item{title: "OK"},
|
||||
}
|
||||
m.lists[VBIOS].SetItems(items)
|
||||
m.lists[VBIOS].SetSize(m.width-m.offsetx[VBIOS], m.height-m.offsety[VBIOS])
|
||||
|
||||
// Init VIDEO disable choises
|
||||
items = []list.Item{
|
||||
item{title: "YES"},
|
||||
item{title: "NO"},
|
||||
}
|
||||
m.lists[VIDEO].SetItems(items)
|
||||
m.lists[VIDEO].SetSize(m.width-m.offsetx[VIDEO], m.height-m.offsety[VIDEO])
|
||||
|
||||
// Init DONE choises
|
||||
items = []list.Item{
|
||||
item{title: "WAITING"},
|
||||
}
|
||||
m.lists[WORKING].SetItems(items)
|
||||
m.lists[WORKING].SetSize(m.width-m.offsetx[WORKING], m.height-m.offsety[WORKING])
|
||||
|
||||
// Init DONE choises
|
||||
items = []list.Item{
|
||||
item{title: "FINISH"},
|
||||
}
|
||||
m.lists[DONE].SetItems(items)
|
||||
m.lists[DONE].SetSize(m.width-m.offsetx[DONE], m.height-m.offsety[DONE])
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
var (
|
||||
titleStyle = lipgloss.NewStyle().
|
||||
Background(lipgloss.Color("#5F5FD7")).
|
||||
Foreground(lipgloss.Color("#FFFFFF")).
|
||||
PaddingLeft(2).PaddingRight(2)
|
||||
helpStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color(241))
|
||||
listStyle = lipgloss.NewStyle().
|
||||
PaddingLeft(2).
|
||||
PaddingRight(2)
|
||||
choiceStyle = lipgloss.NewStyle().
|
||||
PaddingLeft(4).
|
||||
PaddingRight(4)
|
||||
selectedChoiceStyle = lipgloss.NewStyle().
|
||||
PaddingLeft(2).
|
||||
Foreground(lipgloss.Color("170"))
|
||||
dialogStyle = lipgloss.NewStyle().
|
||||
PaddingLeft(2)
|
||||
)
|
||||
|
||||
// Choice delegate (for our dialog boxes)
|
||||
type choiceDelegate struct{}
|
||||
|
||||
func (d choiceDelegate) Height() int { return 1 }
|
||||
func (d choiceDelegate) Spacing() int { return 0 }
|
||||
func (d choiceDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
|
||||
func (d choiceDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
|
||||
i, ok := listItem.(item)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
str := i.title
|
||||
|
||||
fn := choiceStyle.Render
|
||||
if index == m.Index() {
|
||||
fn = func(s ...string) string {
|
||||
return selectedChoiceStyle.Render("| " + strings.Join(s, " "))
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(w, fn(str))
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
package internal
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/HikariKnight/ls-iommu/pkg/errorcheck"
|
||||
"github.com/HikariKnight/quickpassthrough/internal/logger"
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func getIOMMU(args ...string) []string {
|
||||
var stdout, stderr bytes.Buffer
|
||||
// Write to logger
|
||||
logger.Printf("Executing: utils/ls-iommu %s\n", strings.Join(args, " "))
|
||||
|
||||
// Configure the ls-iommu command
|
||||
cmd := exec.Command("utils/ls-iommu", args...)
|
||||
cmd.Stderr = &stderr
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
// Execute the command
|
||||
err := cmd.Run()
|
||||
|
||||
// Generate the correct iommu string for the system
|
||||
var iommu_args string
|
||||
cpuinfo := cpuid.CPU
|
||||
// Write the argument based on which cpu the user got
|
||||
switch cpuinfo.VendorString {
|
||||
case "AuthenticAMD":
|
||||
iommu_args = "iommu=pt amd_iommu=on"
|
||||
case "GenuineIntel":
|
||||
iommu_args = "iommu=pt intel_iommu=on"
|
||||
}
|
||||
|
||||
// If ls-iommu returns an error then IOMMU is disabled
|
||||
errorcheck.ErrorCheck(err,
|
||||
fmt.Sprintf(
|
||||
"IOMMU disabled in either UEFI/BIOS or in bootloader!\n"+
|
||||
"For your bootloader, make sure you have added the kernel arguments:\n"+
|
||||
"%s",
|
||||
iommu_args,
|
||||
),
|
||||
)
|
||||
|
||||
// Read the output
|
||||
var items []string
|
||||
output, _ := io.ReadAll(&stdout)
|
||||
|
||||
// Write to logger
|
||||
logger.Printf("ls-iommu query returned\n%s", string(output))
|
||||
|
||||
// Parse the output line by line
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(output)))
|
||||
for scanner.Scan() {
|
||||
// Write the objects into the list
|
||||
items = append(items, scanner.Text())
|
||||
}
|
||||
|
||||
// Return our list of items
|
||||
return items
|
||||
}
|
||||
|
||||
func iommuList2ListItem(stringList []string) []list.Item {
|
||||
// Make the []list.Item struct
|
||||
items := []list.Item{}
|
||||
|
||||
deviceID := regexp.MustCompile(`\[[a-f0-9]{4}:[a-f0-9]{4}\]\s+`)
|
||||
// Parse the output line by line
|
||||
for _, v := range stringList {
|
||||
// Get the current line and split by :
|
||||
objects := strings.Split(v, ": ")
|
||||
|
||||
// Write the objects into the list
|
||||
items = append(items, item{title: deviceID.ReplaceAllString(objects[2], ""), desc: fmt.Sprintf("%s: %s: DeviceID: %s", objects[0], objects[1], objects[3])})
|
||||
}
|
||||
|
||||
// Return our list of items
|
||||
return items
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue