feat: initial project commit
commit to push first working snapshot to codeberg
This commit is contained in:
commit
09b1054588
25 changed files with 1405 additions and 0 deletions
315
internal/dependency/dependency.go
Normal file
315
internal/dependency/dependency.go
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
package dependency
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
osinfo "jws/internal/os"
|
||||
"jws/pkg/download"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
"fyne.io/tools"
|
||||
)
|
||||
|
||||
type Dependency struct {
|
||||
Name string
|
||||
Installed bool
|
||||
Icon fyne.Resource
|
||||
}
|
||||
|
||||
func CheckDependencies(dependencies []Dependency) {
|
||||
// Check VSCode
|
||||
dependencies[0].Installed = checkVSCode()
|
||||
|
||||
// Check Docker
|
||||
if runtime.GOOS == "windows" {
|
||||
dependencies[1].Installed = checkDockerDesktop()
|
||||
} else {
|
||||
dependencies[1].Installed = checkDocker()
|
||||
}
|
||||
}
|
||||
|
||||
func checkVSCode() bool {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
_, err := os.Stat(filepath.Join(os.Getenv("LOCALAPPDATA"), "Programs", "Microsoft VS Code", "Code.exe"))
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
_, err = os.Stat(filepath.Join(os.Getenv("ProgramFiles"), "Microsoft VS Code", "Code.exe"))
|
||||
return err == nil
|
||||
case "darwin":
|
||||
_, err := os.Stat("/Applications/Visual Studio Code.app")
|
||||
if err != nil {
|
||||
cmd := tools.CommandInShell("which", "code")
|
||||
return cmd.Run() == nil
|
||||
}
|
||||
return err == nil
|
||||
case "linux":
|
||||
cmd := tools.CommandInShell("which", "code")
|
||||
return cmd.Run() == nil
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func checkDocker() bool {
|
||||
cmd := tools.CommandInShell("which", "docker")
|
||||
return cmd.Run() == nil
|
||||
}
|
||||
|
||||
func checkDockerDesktop() bool {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
_, err := os.Stat(filepath.Join(os.Getenv("ProgramFiles"), "Docker", "Docker", "Docker Desktop.exe"))
|
||||
return err == nil
|
||||
case "darwin":
|
||||
_, err := os.Stat("/Applications/Docker.app")
|
||||
return err == nil
|
||||
case "linux":
|
||||
cmd := tools.CommandInShell("systemctl", "is-active", "docker")
|
||||
output, _ := cmd.Output()
|
||||
return strings.TrimSpace(string(output)) == "active"
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func InstallDependency(index int, sudoPassword string, dependencies []Dependency, mainWindow fyne.Window) {
|
||||
depName := dependencies[index].Name
|
||||
|
||||
var cmd *exec.Cmd
|
||||
var err error
|
||||
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
switch index {
|
||||
case 0: // VSCode
|
||||
cmd = tools.CommandInShell("winget", "install", "-e", "--id",
|
||||
"Microsoft.VisualStudioCode")
|
||||
case 1: // Docker Desktop
|
||||
wslCheckCmd := tools.CommandInShell("wsl", "--status")
|
||||
err := wslCheckCmd.Run()
|
||||
if err != nil {
|
||||
wslInstallCmd := tools.CommandInShell("wsl", "--install")
|
||||
err = wslInstallCmd.Run()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error: installing WSL: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
dialog.ShowInformation("WSL wird installiert", "WSL wird installiert. Bitte warten Sie, bis die Installation abgeschlossen ist und starten Sie die Anwendung neu.", mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
cmd = tools.CommandInShell("winget", "install", "-e", "--id",
|
||||
"Docker.DockerDesktop")
|
||||
}
|
||||
case "darwin":
|
||||
brewCheckCmd := tools.CommandInShell("which", "brew")
|
||||
err := brewCheckCmd.Run()
|
||||
if err != nil {
|
||||
brewInstallCmd := tools.CommandInShell("bin/bash", "-c", "\"$(curl -fsSl https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"")
|
||||
err := brewInstallCmd.Run()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error: installing homebrew falied: %v", err), mainWindow)
|
||||
}
|
||||
}
|
||||
switch index {
|
||||
case 0: // VSCode
|
||||
cmd = tools.CommandInShell("brew", "install", "--cask", "visual-studio-code")
|
||||
case 1: // Docker
|
||||
cmd = tools.CommandInShell("brew", "install", "docker")
|
||||
}
|
||||
case "linux":
|
||||
osInfo, err := osinfo.GetLinuxDistribution()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
dialog.ShowError(fmt.Errorf("error getting OS info: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
var downloadURL, fileName string
|
||||
switch index {
|
||||
case 0: // VSCode
|
||||
switch osInfo.ID {
|
||||
case "debian", "ubuntu", "linuxmint":
|
||||
downloadURL = "https://code.visualstudio.com/sha/download?build=stable&os=linux-deb-x64"
|
||||
fileName = "vscode.deb"
|
||||
case "fedora":
|
||||
downloadURL = "https://code.visualstudio.com/sha/download?build=stable&os=linux-rpm-x64"
|
||||
fileName = "vscode.rpm"
|
||||
default:
|
||||
dialog.ShowInformation("Nicht unterstützt", fmt.Sprintf("Automatische Installation für dieses OS %v nicht verfügbar", osInfo), mainWindow)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
progressBar := widget.NewProgressBar()
|
||||
progressDialog := dialog.NewCustomWithoutButtons("Download in progress", progressBar, mainWindow)
|
||||
|
||||
progressDialog.Show()
|
||||
|
||||
homeDir, _ := os.UserHomeDir()
|
||||
downloadDir := filepath.Join(homeDir, "Downloads")
|
||||
filePath := filepath.Join(downloadDir, fileName)
|
||||
|
||||
err := download.WithProgressBar(downloadURL, filePath, progressBar)
|
||||
progressDialog.Hide()
|
||||
|
||||
if err != nil {
|
||||
dialog.ShowError(err, mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
var installCmd string
|
||||
switch osInfo.ID {
|
||||
case "debian", "ubuntu", "linuxmint":
|
||||
installCmd = fmt.Sprintf("sudo -S dpkg -i %s", filePath)
|
||||
case "fedora":
|
||||
installCmd = fmt.Sprintf("sudo -S dnf install -y %s", filePath)
|
||||
}
|
||||
|
||||
cmd := exec.Command("sh", "-c", installCmd)
|
||||
cmd.Stdin = strings.NewReader(sudoPassword + "\n")
|
||||
|
||||
dialog.ShowInformation("Installation gestartet",
|
||||
"Die Installation von VSCode wurde gestartet.", mainWindow)
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("installation failed:\n%s", output), mainWindow)
|
||||
return
|
||||
} else {
|
||||
dialog.ShowInformation("Erfolg", "VSCode erfolgreich installiert!", mainWindow)
|
||||
CheckDependencies(dependencies)
|
||||
}
|
||||
}()
|
||||
case 1: // Docker
|
||||
go func() {
|
||||
progressBar := widget.NewProgressBar()
|
||||
progressDialog := dialog.NewCustomWithoutButtons("Docker Installation läuft...", progressBar, mainWindow)
|
||||
progressDialog.Show()
|
||||
|
||||
osInfo, err := osinfo.GetLinuxDistribution()
|
||||
if err != nil {
|
||||
progressDialog.Hide()
|
||||
dialog.ShowError(fmt.Errorf("error getting os infos: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
var commands []string
|
||||
var cleanupCommands []string
|
||||
var totalSteps int
|
||||
|
||||
switch osInfo.ID {
|
||||
case "ubuntu", "linuxmint", "debian":
|
||||
// Ubuntu/Debian Commands
|
||||
distroPath := "ubuntu"
|
||||
codeName := "$(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\")"
|
||||
if osInfo.ID == "debian" {
|
||||
distroPath = "debian"
|
||||
codeName = "$(. /etc/os-release && echo \"$VERSION_CODENAME\")"
|
||||
}
|
||||
arch := "$(dpkg --print-architecture)"
|
||||
|
||||
commands = []string{
|
||||
"apt-get update",
|
||||
"apt-get install -y wget",
|
||||
fmt.Sprintf("wget -qO- https://download.docker.com/linux/%s/dists/%s/pool/stable/%s/ | grep -oP 'href=\"\\K[^\"]*(?=.*deb)' | xargs -I{} wget https://download.docker.com/linux/%s/dists/%s/pool/stable/%s/{}",
|
||||
distroPath, codeName, arch, distroPath, codeName, arch),
|
||||
"dpkg -i ./containerd.io*.deb docker-ce*.deb docker-ce-cli*.deb docker-buildx-plugin*.deb docker-compose-plugin*.deb",
|
||||
"apt-get install -f -y",
|
||||
"service docker start",
|
||||
}
|
||||
|
||||
cleanupCommands = []string{
|
||||
"rm -rf ./containerd.io*.deb ./docker-ce*.deb ./docker-ce-cli*.deb ./docker-buildx-plugin*.deb ./docker-compose-plugin*.deb",
|
||||
"apt-get autoremove -y",
|
||||
"apt-get clean",
|
||||
}
|
||||
|
||||
totalSteps = len(commands) + len(cleanupCommands)
|
||||
|
||||
case "fedora":
|
||||
// Fedora Commands
|
||||
fedoraVer := "$(rpm -E %fedora)"
|
||||
commands = []string{
|
||||
"dnf install -y wget",
|
||||
fmt.Sprintf("wget https://download.docker.com/linux/fedora/%s/x86_64/stable/Packages/containerd-*.rpm docker-*.rpm docker-ce-*.rpm", fedoraVer),
|
||||
"dnf install -y ./*.rpm",
|
||||
"systemctl enable --now docker",
|
||||
}
|
||||
|
||||
cleanupCommands = []string{
|
||||
"rm -rf ./containerd-*.rpm ./docker-*.rpm ./docker-ce-*.rpm",
|
||||
"dnf autoremove -y",
|
||||
"dnf clean all",
|
||||
}
|
||||
|
||||
totalSteps = len(commands) + len(cleanupCommands)
|
||||
|
||||
default:
|
||||
progressDialog.Hide()
|
||||
dialog.ShowInformation("not supported", "Automatic Docker installation not supported for your OS.", mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
progressStep := 1.0 / float64(totalSteps)
|
||||
currentProgress := 0.0
|
||||
|
||||
for _, cmd := range commands {
|
||||
command := exec.Command("sudo", "-S", "sh", "-c", cmd)
|
||||
command.Stdin = strings.NewReader(sudoPassword + "\n")
|
||||
|
||||
if output, err := command.CombinedOutput(); err != nil {
|
||||
progressDialog.Hide()
|
||||
dialog.ShowError(fmt.Errorf("error at %s:\n%s", cmd, output), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
currentProgress += progressStep
|
||||
progressBar.SetValue(currentProgress)
|
||||
}
|
||||
|
||||
for _, cmd := range cleanupCommands {
|
||||
command := exec.Command("sudo", "-S", "sh", "-c", cmd)
|
||||
command.Stdin = strings.NewReader(sudoPassword + "\n")
|
||||
|
||||
if output, err := command.CombinedOutput(); err != nil {
|
||||
progressDialog.Hide()
|
||||
dialog.ShowError(fmt.Errorf("cleanup error at %s:\n%s", cmd, output), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
currentProgress += progressStep
|
||||
progressBar.SetValue(currentProgress)
|
||||
}
|
||||
|
||||
progressDialog.Hide()
|
||||
|
||||
dialog.ShowInformation(
|
||||
"Installation finished",
|
||||
"Docker was succesfully installed! Please re-start your system to let the changes take effect.",
|
||||
mainWindow,
|
||||
)
|
||||
|
||||
CheckDependencies(dependencies)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
if cmd != nil {
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error starting installation process: %v", err), mainWindow)
|
||||
} else {
|
||||
dialog.ShowInformation("Installation started",
|
||||
fmt.Sprintf("Installation of %s was started", depName), mainWindow)
|
||||
}
|
||||
}
|
||||
}
|
||||
92
internal/gui/dependency_screen.go
Normal file
92
internal/gui/dependency_screen.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"jws/internal/dependency"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/layout"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// ShowDependencyScreen displays the dependency check screen
|
||||
func ShowDependencyScreen() {
|
||||
title := widget.NewLabel("check dependencies")
|
||||
title.TextStyle = fyne.TextStyle{Bold: true}
|
||||
title.Alignment = fyne.TextAlignCenter
|
||||
|
||||
description := widget.NewLabel("dependencies needed for dev-environment:")
|
||||
description.Wrapping = fyne.TextWrapWord
|
||||
|
||||
dependencyContainer := container.NewVBox()
|
||||
allInstalled := true
|
||||
|
||||
for i, dep := range dependencies {
|
||||
statusIcon := theme.CancelIcon()
|
||||
statusText := "not installed"
|
||||
|
||||
if dep.Installed {
|
||||
statusIcon = theme.ConfirmIcon()
|
||||
statusText = "installed"
|
||||
} else {
|
||||
allInstalled = false
|
||||
}
|
||||
|
||||
depBox := container.NewHBox(
|
||||
widget.NewIcon(dep.Icon),
|
||||
widget.NewLabel(dep.Name),
|
||||
layout.NewSpacer(),
|
||||
widget.NewIcon(statusIcon),
|
||||
widget.NewLabel(statusText),
|
||||
)
|
||||
|
||||
dependencyContainer.Add(depBox)
|
||||
|
||||
if !dep.Installed {
|
||||
installBtn := widget.NewButton("install", func(i int) func() {
|
||||
return func() {
|
||||
ShowPasswordDialog(i)
|
||||
}
|
||||
}(i))
|
||||
|
||||
depBox = container.NewStack(
|
||||
layout.NewSpacer(),
|
||||
installBtn,
|
||||
)
|
||||
dependencyContainer.Add(depBox)
|
||||
}
|
||||
}
|
||||
|
||||
nextBtn := widget.NewButton("go to projects", func() {
|
||||
if allInstalled {
|
||||
ShowProjectScreen()
|
||||
} else {
|
||||
dialog.ShowInformation("dependencies missing",
|
||||
"Bitte installieren Sie alle erforderlichen Abhängigkeiten, bevor Sie fortfahren.", mainWindow)
|
||||
}
|
||||
})
|
||||
|
||||
nextBtn.Importance = widget.HighImportance
|
||||
|
||||
recheckBtn := widget.NewButton("check again", func() {
|
||||
dependency.CheckDependencies(dependencies)
|
||||
ShowDependencyScreen()
|
||||
})
|
||||
|
||||
buttonContainer := container.New(layout.NewGridLayout(2), recheckBtn, nextBtn)
|
||||
|
||||
paddedButtonContainer := container.NewPadded(buttonContainer)
|
||||
|
||||
description.Alignment = fyne.TextAlignCenter
|
||||
header := container.NewVBox(title, description)
|
||||
content := container.NewBorder(header,
|
||||
paddedButtonContainer,
|
||||
nil,
|
||||
nil,
|
||||
dependencyContainer,
|
||||
)
|
||||
|
||||
mainWindow.SetContent(content)
|
||||
}
|
||||
47
internal/gui/gui.go
Normal file
47
internal/gui/gui.go
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"jws/internal/dependency"
|
||||
"jws/internal/project"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/data/binding"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
var (
|
||||
// Global variables available to the package
|
||||
mainWindow fyne.Window
|
||||
dependencies []dependency.Dependency
|
||||
projects []project.Project
|
||||
projectsFS embed.FS
|
||||
)
|
||||
|
||||
// Init initializes the GUI package with required dependencies
|
||||
func Init(window fyne.Window, deps []dependency.Dependency, projs []project.Project, fs embed.FS) {
|
||||
mainWindow = window
|
||||
dependencies = deps
|
||||
projects = projs
|
||||
projectsFS = fs
|
||||
}
|
||||
|
||||
// ShowPasswordDialog shows a dialog to enter sudo password for installations
|
||||
func ShowPasswordDialog(index int) {
|
||||
password := binding.NewString()
|
||||
entry := widget.NewEntryWithData(password)
|
||||
entry.Password = true
|
||||
|
||||
dialog.NewForm("Sudo Password", "ok", "cancel",
|
||||
[]*widget.FormItem{widget.NewFormItem("password", entry)},
|
||||
func(b bool) {
|
||||
pass, err := password.Get()
|
||||
if err == nil {
|
||||
if b {
|
||||
dependency.InstallDependency(index, pass, dependencies, mainWindow)
|
||||
}
|
||||
}
|
||||
},
|
||||
mainWindow).Show()
|
||||
}
|
||||
91
internal/gui/project_screen.go
Normal file
91
internal/gui/project_screen.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package gui
|
||||
|
||||
import (
|
||||
"jws/internal/project"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/canvas"
|
||||
"fyne.io/fyne/v2/container"
|
||||
"fyne.io/fyne/v2/theme"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
// ShowProjectScreen displays the project selection screen
|
||||
func ShowProjectScreen() {
|
||||
title := widget.NewLabel("Project-Selection")
|
||||
title.TextStyle = fyne.TextStyle{Bold: true}
|
||||
title.Alignment = fyne.TextAlignCenter
|
||||
|
||||
description := widget.NewLabel("Choose a Starter-Project to deploy:")
|
||||
description.Wrapping = fyne.TextWrapWord
|
||||
description.Alignment = fyne.TextAlignCenter
|
||||
|
||||
projectsList := container.NewVBox()
|
||||
|
||||
for i, proj := range projects {
|
||||
projTitle := widget.NewLabel(proj.Name)
|
||||
projTitle.TextStyle = fyne.TextStyle{Bold: true}
|
||||
|
||||
projDesc := widget.NewLabel(proj.Description)
|
||||
projDesc.Wrapping = fyne.TextWrapWord
|
||||
|
||||
deployBtn := widget.NewButton("deploy", func(i int) func() {
|
||||
return func() {
|
||||
project.DeployProject(i, projects, projectsFS, mainWindow)
|
||||
}
|
||||
}(i))
|
||||
deployBtn.Importance = widget.HighImportance
|
||||
|
||||
projectContent := container.NewBorder(
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
container.NewCenter(deployBtn),
|
||||
container.NewVBox(projTitle, projDesc),
|
||||
)
|
||||
|
||||
projectCard := container.NewBorder(
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
container.NewPadded(projectContent),
|
||||
)
|
||||
|
||||
bg := canvas.NewRectangle(theme.Color(theme.ColorNameBackground))
|
||||
|
||||
borderedContainer := container.NewStack(
|
||||
bg,
|
||||
projectCard,
|
||||
)
|
||||
|
||||
spacedContainer := container.NewVBox(
|
||||
borderedContainer,
|
||||
widget.NewSeparator(),
|
||||
)
|
||||
|
||||
projectsList.Add(spacedContainer)
|
||||
}
|
||||
|
||||
backBtn := widget.NewButton("Check Dependecies", func() {
|
||||
ShowDependencyScreen()
|
||||
})
|
||||
|
||||
scrollContainer := container.NewVScroll(projectsList)
|
||||
|
||||
header := container.NewVBox(
|
||||
title,
|
||||
description,
|
||||
widget.NewSeparator(),
|
||||
)
|
||||
|
||||
content := container.NewBorder(
|
||||
header,
|
||||
backBtn, // footer,
|
||||
nil,
|
||||
nil,
|
||||
scrollContainer,
|
||||
)
|
||||
|
||||
mainWindow.SetContent(content)
|
||||
}
|
||||
83
internal/os/osinfo.go
Normal file
83
internal/os/osinfo.go
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
package os
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OS struct {
|
||||
ID string
|
||||
Name string
|
||||
Version string
|
||||
PackageManager string
|
||||
}
|
||||
|
||||
func GetLinuxDistribution() (*OS, error) {
|
||||
_, err := os.Stat("/etc/os-release")
|
||||
if os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("unable to read system information")
|
||||
}
|
||||
|
||||
osRelease, _ := os.ReadFile("/etc/os-release")
|
||||
return parseOsRelease(string(osRelease)), nil
|
||||
}
|
||||
|
||||
func parseOsRelease(osRelease string) *OS {
|
||||
var result OS
|
||||
result.ID = "Unknown"
|
||||
result.Name = "Unknown"
|
||||
result.Version = "Unknown"
|
||||
|
||||
lines := strings.Split(osRelease, "\n")
|
||||
|
||||
for _, line := range lines {
|
||||
splitLine := strings.SplitN(line, "=", 2)
|
||||
if len(splitLine) != 2 {
|
||||
continue
|
||||
}
|
||||
switch splitLine[0] {
|
||||
case "ID":
|
||||
result.ID = strings.ToLower(strings.Trim(splitLine[1], "\""))
|
||||
case "NAME":
|
||||
result.Name = strings.Trim(splitLine[1], "\"")
|
||||
case "VERSION_ID":
|
||||
result.Version = strings.Trim(splitLine[1], "\"")
|
||||
}
|
||||
}
|
||||
err := result.getPackageManager()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (os *OS) getPackageManager() error {
|
||||
switch os.ID {
|
||||
case "debian", "ubuntu", "linuxmint":
|
||||
os.PackageManager = "apt"
|
||||
return nil
|
||||
case "arch":
|
||||
os.PackageManager = "pacman"
|
||||
return nil
|
||||
case "fedora":
|
||||
os.PackageManager = "dnf"
|
||||
return nil
|
||||
default:
|
||||
pmcommands := []string{
|
||||
"apt",
|
||||
"dnf",
|
||||
"pacman",
|
||||
}
|
||||
for _, pmname := range pmcommands {
|
||||
_, err := exec.LookPath(pmname)
|
||||
if err == nil {
|
||||
os.PackageManager = pmname
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("no packagemanager found for os: %s", os.Name)
|
||||
}
|
||||
}
|
||||
127
internal/project/project.go
Normal file
127
internal/project/project.go
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package project
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"fyne.io/fyne/v2"
|
||||
"fyne.io/fyne/v2/dialog"
|
||||
"fyne.io/fyne/v2/widget"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
FolderName string `json:"folderName"`
|
||||
}
|
||||
|
||||
func DeployProject(index int, projects []Project, projectsFS embed.FS, mainWindow fyne.Window) {
|
||||
project := projects[index]
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error getting home directory: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
projectPath := filepath.Join(homeDir, "Projects", project.FolderName)
|
||||
|
||||
confirmDialog := dialog.NewConfirm(
|
||||
"deploying project",
|
||||
fmt.Sprintf("the project '%s' will be deployed to '%s' and opend in VS Code. Continue?", project.Name, projectPath),
|
||||
func(ok bool) {
|
||||
if ok {
|
||||
progress := widget.NewProgressBar()
|
||||
progressDiag := dialog.NewCustomWithoutButtons("project will be deployed", progress, mainWindow)
|
||||
|
||||
progressDiag.Show()
|
||||
|
||||
go func() {
|
||||
defer progressDiag.Hide()
|
||||
|
||||
progress.SetValue(0.1)
|
||||
err := os.MkdirAll(projectPath, 0755)
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error creating directory: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
progress.SetValue(0.3)
|
||||
err = CopyEmbeddedProject(projectsFS, project.FolderName, projectPath)
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error copying project files: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
|
||||
progress.SetValue(0.7)
|
||||
|
||||
var openCmd *exec.Cmd
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
openCmd = exec.Command("code", projectPath)
|
||||
case "darwin":
|
||||
openCmd = exec.Command("open", "-a", "Visual Studio Code", projectPath)
|
||||
case "linux":
|
||||
openCmd = exec.Command("code", projectPath)
|
||||
}
|
||||
|
||||
if openCmd != nil {
|
||||
progress.SetValue(0.9)
|
||||
err = openCmd.Run()
|
||||
if err != nil {
|
||||
dialog.ShowError(fmt.Errorf("error opening VS Code: %v", err), mainWindow)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
progress.SetValue(1.0)
|
||||
|
||||
dialog.ShowInformation("project deployed",
|
||||
fmt.Sprintf("the project '%s' was successfully deployed and opend in VS Code.\n\n"+
|
||||
"Path: %s\n\n"+
|
||||
"Application can be started with Docker Compose.",
|
||||
project.Name, projectPath), mainWindow)
|
||||
}()
|
||||
}
|
||||
},
|
||||
mainWindow,
|
||||
)
|
||||
confirmDialog.Show()
|
||||
}
|
||||
|
||||
func CopyEmbeddedProject(projectsFS embed.FS, projectFolder string, targetPath string) error {
|
||||
sourcePath := fmt.Sprintf("projects/%s", projectFolder)
|
||||
|
||||
return fs.WalkDir(projectsFS, sourcePath, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
relPath, err := filepath.Rel(sourcePath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
destPath := filepath.Join(targetPath, relPath)
|
||||
|
||||
if d.IsDir() {
|
||||
return os.MkdirAll(destPath, 0755)
|
||||
}
|
||||
|
||||
data, err := projectsFS.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(destPath, data, 0644)
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue