diff --git a/.gitignore b/.gitignore index b975044..53f5004 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ go.work.sum # env file .env +unreal-pm + diff --git a/log.go b/log.go new file mode 100644 index 0000000..11602dc --- /dev/null +++ b/log.go @@ -0,0 +1,40 @@ +package main + +import ( + "fmt" + "strings" + + "fyne.io/fyne/v2/widget" +) + +type Logger struct { + logText *widget.Entry + logBuffer []string + logMaxLines int +} + +var globalLogger *Logger; + +func InitLogger(text *widget.Entry, maxLines int) { + globalLogger = &Logger{ + logText: text, + logMaxLines: logMaxLines, + } +} + +func Log(line string) { + if globalLogger == nil { + fmt.Println("Global Logger is nil") + return + } + + globalLogger.log(line) +} + +func (l *Logger) log(line string) { + l.logBuffer = append(l.logBuffer, line) + if len(l.logBuffer) > l.logMaxLines { + l.logBuffer = l.logBuffer[1:] + } + l.logText.SetText(strings.Join(l.logBuffer, "\n")) +} \ No newline at end of file diff --git a/main.go b/main.go index 9cb6970..c4d0324 100644 --- a/main.go +++ b/main.go @@ -1,266 +1,39 @@ package main import ( - "bufio" - "encoding/json" "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "runtime" - "strings" "fyne.io/fyne/v2" "fyne.io/fyne/v2/app" - "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/layout" - "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" ) -type Project struct { - EnginePath string `json:"enginePath"` - ProjectPath string `json:"projectPath"` - ProjectName string `json:"projectName"` - Version string `json:"engineVersion"` -} - const projectsFilePath = "projects.json" -var projectList *fyne.Container -var logText *widget.Entry -var scrollContainer *container.Scroll -var logBuffer []string var logMaxLines = 7 -type hoverableButton struct { - widget.Button - onMouseIn func() - onMouseOut func() -} - -func (h *hoverableButton) MouseIn() { - if h.onMouseIn != nil { - h.onMouseIn() - } -} - -func (h *hoverableButton) MouseOut() { - if h.onMouseOut != nil { - h.onMouseOut() - } -} - -func loadProjects() ([]Project, error) { - file, err := os.ReadFile(projectsFilePath) - - if err != nil { - return nil, err - } - - var projects []Project - if err := json.Unmarshal(file, &projects); err != nil { - return nil, err - } - - return projects, nil -} - -func removeDir(path string) { - err := os.RemoveAll(path) - if err != nil { - log("Can't remove content at " + path) - } else { - log("Removed " + path) - } -} - -func cleanUnrealProject(project Project) { - dirs := []string { - "Binaries", - "DerivedDataCache", - "Intermediate", - "Saved", - "Script", - } - - for _, dir := range dirs { - fullPath := filepath.Join(project.ProjectPath, dir) - removeDir(fullPath) - } - - pluginsPath := filepath.Join(project.ProjectPath, "Plugins") - entries, err := os.ReadDir(pluginsPath) - if err != nil { - return - } - - for _, entry := range entries { - if !entry.IsDir() { - continue - } - - pluginDir := filepath.Join(pluginsPath, entry.Name()) - removeDir(filepath.Join(pluginDir, "Binaries")) - removeDir(filepath.Join(pluginDir, "Intermediate")) - } -} - -func generateUnrealSolution(project Project) { - var buildCmd string - - switch runtime.GOOS { - case "linux": - buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Linux/GenerateProjectFiles.sh"; - case "darwin": - buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" - default: - fmt.Println("Generate Project is not yet supported on Windows") - return - } - - projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" - cmd := exec.Command(buildCmd, projectCmd, "-game") - - logToOutput(cmd) -} - -func buildUnrealSolution(project Project) { - switch runtime.GOOS { - case "linux": - cmd := exec.Command("make", "-C", project.ProjectPath, project.ProjectName) - logToOutput(cmd) - default: - fmt.Println("Build Project is not yet supported on Windows") - return - } -} - -func runUnrealProject(project Project) { - var buildCmd string - - switch runtime.GOOS { - case "linux": - buildCmd = project.EnginePath + "/Engine/Binaries/Linux/UnrealEditor" - case "darwin": - buildCmd = project.EnginePath + "/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor" - default: - buildCmd = project.EnginePath + "/Engine/Binaries/Win64/UnrealEditor.exe" - } - - projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" - cmd := exec.Command(buildCmd, projectCmd) - - logToOutput(cmd) -} - -func logToOutput(cmd *exec.Cmd) { - stdout, err := cmd.StdoutPipe() - if err != nil { - fmt.Println("Error during pipe stdout creation") - } - - stderr, err := cmd.StderrPipe() - if err != nil { - fmt.Println("Error during pipe stderr creation") - } - - if err := cmd.Start(); err != nil { - fmt.Println("Error while loading command") - } - - readPipe := func(reader io.ReadCloser) { - scanner := bufio.NewScanner(reader) - for scanner.Scan() { - line := scanner.Text() - log(line) - } - } - - go readPipe(stdout) - go readPipe(stderr) - - if err := cmd.Wait(); err != nil { - fmt.Println("Error") - } -} - -func log(line string) { - logBuffer = append(logBuffer, line) - if len(logBuffer) > logMaxLines { - logBuffer = logBuffer[1:] - } - - logText.SetText(strings.Join(logBuffer, "\n")) -} - -func newProjectRow(project Project) fyne.CanvasObject { - projectName := project.ProjectName - iconPath := filepath.Join(project.ProjectPath, projectName+".png") - var projectIcon fyne.Resource - - if _, err := os.Stat(iconPath); err == nil { - icon, err := fyne.LoadResourceFromPath(iconPath) - if err == nil { - projectIcon = icon - } - } - if projectIcon == nil { - projectIcon = theme.FileIcon() - } - - icon := canvas.NewImageFromResource(projectIcon) - icon.SetMinSize(fyne.NewSize(48, 48)) - - nameLabel := widget.NewLabel(projectName + " / Unreal Engine " + project.Version) - nameLabel.Alignment = fyne.TextAlignLeading - - // Crée les boutons masqués par défaut - clearButton := widget.NewButton("Clean", func() { - cleanUnrealProject(project) - }) - generateBtn := widget.NewButton("Generate", func() { - generateUnrealSolution(project) - }) - buildBtn := widget.NewButton("Build", func() { - buildUnrealSolution(project) - }) - launchBtn := widget.NewButton("Run", func() { - runUnrealProject(project) - }) - - buttons := container.NewHBox(clearButton, generateBtn, buildBtn, launchBtn) - - // Conteneur principal - row := container.NewHBox( - icon, - nameLabel, - layout.NewSpacer(), - buttons, - ) - - return row -} - func main() { myApp := app.New() myWindow := myApp.NewWindow("Unreal Project Launcher") myWindow.Resize(fyne.NewSize(730, 460)) - projects, err := loadProjects() + projects, err := LoadProjects(projectsFilePath) if err != nil { fmt.Println("Error while loading projects") } - logText = widget.NewMultiLineEntry() + logText := widget.NewMultiLineEntry() logText.SetMinRowsVisible(logMaxLines); + InitLogger(logText, logMaxLines) + + var projectList *fyne.Container + reloadUI := func() { projectList.RemoveAll() for _, project := range projects { - row := newProjectRow(project) + row := NewProjectRow(project) projectList.Add(row) } } @@ -268,7 +41,7 @@ func main() { projectList = container.NewVBox() reloadUI() - scrollContainer = container.NewVScroll(projectList) + scrollContainer := container.NewVScroll(projectList) mainContainer := container.NewBorder(nil, logText, nil, nil, scrollContainer) myWindow.SetContent(mainContainer) diff --git a/ui.go b/ui.go new file mode 100644 index 0000000..8322352 --- /dev/null +++ b/ui.go @@ -0,0 +1,61 @@ +package main + +import ( + "os" + "path/filepath" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" +) + +func NewProjectRow(project Project) fyne.CanvasObject { + projectName := project.ProjectName + iconPath := filepath.Join(project.ProjectPath, projectName+".png") + var projectIcon fyne.Resource + + if _, err := os.Stat(iconPath); err == nil { + icon, err := fyne.LoadResourceFromPath(iconPath) + if err == nil { + projectIcon = icon + } + } + if projectIcon == nil { + projectIcon = theme.FileIcon() + } + + icon := canvas.NewImageFromResource(projectIcon) + icon.SetMinSize(fyne.NewSize(48, 48)) + + nameLabel := widget.NewLabel(projectName + " / Unreal Engine " + project.Version) + nameLabel.Alignment = fyne.TextAlignLeading + + // Crée les boutons masqués par défaut + clearButton := widget.NewButton("Clean", func() { + CleanUnrealProject(project) + }) + generateBtn := widget.NewButton("Generate", func() { + GenerateUnrealSolution(project) + }) + buildBtn := widget.NewButton("Build", func() { + BuildUnrealSolution(project) + }) + launchBtn := widget.NewButton("Run", func() { + RunUnrealProject(project) + }) + + buttons := container.NewHBox(clearButton, generateBtn, buildBtn, launchBtn) + + // Conteneur principal + row := container.NewHBox( + icon, + nameLabel, + layout.NewSpacer(), + buttons, + ) + + return row +} diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..debcc0a --- /dev/null +++ b/utils.go @@ -0,0 +1,153 @@ +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "runtime" +) + +type Project struct { + EnginePath string `json:"enginePath"` + ProjectPath string `json:"projectPath"` + ProjectName string `json:"projectName"` + Version string `json:"engineVersion"` +} + +func LoadProjects(projectFilePath string) ([]Project, error) { + file, err := os.ReadFile(projectsFilePath) + + if err != nil { + return nil, err + } + + var projects []Project + if err := json.Unmarshal(file, &projects); err != nil { + return nil, err + } + + return projects, nil +} + +func removeDir(path string) { + err := os.RemoveAll(path) + if err != nil { + Log("Can't remove content at " + path) + } else { + Log("Removed " + path) + } +} + +func CleanUnrealProject(project Project) { + dirs := []string { + "Binaries", + "DerivedDataCache", + "Intermediate", + "Saved", + "Script", + } + + for _, dir := range dirs { + fullPath := filepath.Join(project.ProjectPath, dir) + removeDir(fullPath) + } + + pluginsPath := filepath.Join(project.ProjectPath, "Plugins") + entries, err := os.ReadDir(pluginsPath) + if err != nil { + return + } + + for _, entry := range entries { + if !entry.IsDir() { + continue + } + + pluginDir := filepath.Join(pluginsPath, entry.Name()) + removeDir(filepath.Join(pluginDir, "Binaries")) + removeDir(filepath.Join(pluginDir, "Intermediate")) + } +} + +func GenerateUnrealSolution(project Project) { + var buildCmd string + + switch runtime.GOOS { + case "linux": + buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Linux/GenerateProjectFiles.sh"; + case "darwin": + buildCmd = project.EnginePath + "/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh" + default: + fmt.Println("Generate Project is not yet supported on Windows") + return + } + + projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" + cmd := exec.Command(buildCmd, projectCmd, "-game") + + logToOutput(cmd) +} + +func BuildUnrealSolution(project Project) { + switch runtime.GOOS { + case "linux": + cmd := exec.Command("make", "-C", project.ProjectPath, project.ProjectName) + logToOutput(cmd) + default: + fmt.Println("Build Project is not yet supported on Windows") + return + } +} + +func RunUnrealProject(project Project) { + var buildCmd string + + switch runtime.GOOS { + case "linux": + buildCmd = project.EnginePath + "/Engine/Binaries/Linux/UnrealEditor" + case "darwin": + buildCmd = project.EnginePath + "/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor" + default: + buildCmd = project.EnginePath + "/Engine/Binaries/Win64/UnrealEditor.exe" + } + + projectCmd := project.ProjectPath + "/" + project.ProjectName + ".uproject" + cmd := exec.Command(buildCmd, projectCmd) + + logToOutput(cmd) +} + +func logToOutput(cmd *exec.Cmd) { + stdout, err := cmd.StdoutPipe() + if err != nil { + fmt.Println("Error during pipe stdout creation") + } + + stderr, err := cmd.StderrPipe() + if err != nil { + fmt.Println("Error during pipe stderr creation") + } + + if err := cmd.Start(); err != nil { + fmt.Println("Error while loading command") + } + + readPipe := func(reader io.ReadCloser) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + line := scanner.Text() + Log(line) + } + } + + go readPipe(stdout) + go readPipe(stderr) + + if err := cmd.Wait(); err != nil { + fmt.Println("Error") + } +} \ No newline at end of file