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
104
README.md
Normal file
104
README.md
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
# JakartaEE & Spring Boot Starter
|
||||||
|
|
||||||
|
This application is a GUI tool developed in Go using the Fyne framework (v2.5.4). It helps users set up a development environment for JakartaEE and Spring Boot projects by checking and installing necessary dependencies, and then allowing users to deploy starter projects.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- *Dependency Check*: Verifies the installation of required tools (Visual Studio Code and Docker).
|
||||||
|
|
||||||
|
- *Automatic Installation*: Offers to install missing dependencies on supported platforms.
|
||||||
|
|
||||||
|
- *Project Selection*: Provides a list of starter projects for JakartaEE and Spring Boot.
|
||||||
|
|
||||||
|
- *Project Deployment*: Allows users to deploy selected projects and open them in Visual Studio Code with dev containers.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Go 1.23 or later
|
||||||
|
|
||||||
|
- Fyne v2.5.4
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Option 1: Download Pre-built Binary
|
||||||
|
|
||||||
|
Go to the Releases page of this repository.
|
||||||
|
|
||||||
|
Download the appropriate binary for your operating system.
|
||||||
|
|
||||||
|
### Option 2: Build from Source
|
||||||
|
|
||||||
|
- Clone the repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yourusername/jakartaee-springboot-starter.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Navigate to the project directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd jakartaee-springboot-starter
|
||||||
|
```
|
||||||
|
|
||||||
|
Install dependencies:
|
||||||
|
|
||||||
|
The list of dependencies required for the development of Fyne Apps can be found at “https://docs.fyne.io/started/”.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
Build the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go build
|
||||||
|
```
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the application:
|
||||||
|
|
||||||
|
If you downloaded a pre-built binary:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./jakartaee-springboot-starter
|
||||||
|
```
|
||||||
|
|
||||||
|
or by double-clicking the excutable.
|
||||||
|
|
||||||
|
If you built from source:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./jakartaee-springboot-starter
|
||||||
|
```
|
||||||
|
|
||||||
|
The application will launch a GUI window where you can:
|
||||||
|
|
||||||
|
1. Check and install dependencies (Visual Studio Code and Docker).
|
||||||
|
2. Select a starter project from the available options.
|
||||||
|
3. Deploy the selected project and open it in Visual Studio Code.
|
||||||
|
|
||||||
|
Project Structure
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
- main.go: Contains the entire application logic, including GUI setup, dependency checking, and project deployment.
|
||||||
|
- projects/: Directory containing starter project templates.
|
||||||
|
- projects.json: Configuration file for additional plugin projects.
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
To add new starter projects:
|
||||||
|
|
||||||
|
1. Create a new project template in the projects/ directory.
|
||||||
|
2. Add the project details to the projects.json file.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||||
|
|
||||||
|
License
|
||||||
|
[Insert your chosen license here]
|
||||||
|
|
||||||
|
## Acknowledgments
|
||||||
|
|
||||||
|
- Fyne: https://fyne.io/
|
||||||
|
- JakartaEE: https://jakarta.ee/
|
||||||
|
- Spring Boot: https://spring.io/projects/spring-boot
|
||||||
2
cmd/jws/FyneApp.toml
Normal file
2
cmd/jws/FyneApp.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
[Details]
|
||||||
|
Build = 4
|
||||||
BIN
cmd/jws/Icon.png
Normal file
BIN
cmd/jws/Icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
113
cmd/jws/main.go
Normal file
113
cmd/jws/main.go
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
// cmd/jws/main.go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"embed"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"jws/internal/dependency"
|
||||||
|
"jws/internal/gui"
|
||||||
|
"jws/internal/project"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2"
|
||||||
|
"fyne.io/fyne/v2/app"
|
||||||
|
"fyne.io/fyne/v2/dialog"
|
||||||
|
"fyne.io/fyne/v2/theme"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed all:projects
|
||||||
|
var projectsFS embed.FS
|
||||||
|
|
||||||
|
var (
|
||||||
|
dependencies []dependency.Dependency
|
||||||
|
projects []project.Project
|
||||||
|
mainWindow fyne.Window
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a := app.New()
|
||||||
|
mainWindow = a.NewWindow("JakartaEE & Spring Boot Starter")
|
||||||
|
mainWindow.Resize(fyne.NewSize(600, 600))
|
||||||
|
mainWindow.SetFixedSize(true)
|
||||||
|
|
||||||
|
// Initialize dependencies
|
||||||
|
dependencies = []dependency.Dependency{
|
||||||
|
{Name: "Visual Studio Code", Installed: false, Icon: theme.DocumentIcon()},
|
||||||
|
{Name: "Docker", Installed: false, Icon: theme.MediaPlayIcon()},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard projects
|
||||||
|
standartProjects := []project.Project{
|
||||||
|
{
|
||||||
|
Name: "JakartaEE Todo-App mit Servlet",
|
||||||
|
Description: "Eine Todo-Anwendung mit Jakarta Servlet und\nPostgreSQL-Datenbank.",
|
||||||
|
FolderName: "jakarta-servlet-todo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "JakartaEE Todo-App mit JSP",
|
||||||
|
Description: "Eine Todo-Anwendung mit Jakarta Server Pages und PostgreSQL-Datenbank.",
|
||||||
|
FolderName: "jakarta-jsp-todo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "JakartaEE Todo-App als REST-API",
|
||||||
|
Description: "Eine Todo-Anwendung als REST-API mit JakartaEE und PostgreSQL-Datenbank.",
|
||||||
|
FolderName: "jakarta-rest-todo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Spring Boot Todo-App als Microservice",
|
||||||
|
Description: "Eine Todo-Anwendung als Microservice mit Spring Boot und PostgreSQL-Datenbank.",
|
||||||
|
FolderName: "spring-boot-todo",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load additional projects from projects.json
|
||||||
|
pluginProjects, err := loadProjects("projects.json")
|
||||||
|
if err != nil {
|
||||||
|
dialog.ShowError(fmt.Errorf("error loading projects: %v", err), mainWindow)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
projects = append(standartProjects, pluginProjects...)
|
||||||
|
|
||||||
|
// Initialize GUI package
|
||||||
|
gui.Init(mainWindow, dependencies, projects, projectsFS)
|
||||||
|
|
||||||
|
// Check dependencies
|
||||||
|
dependency.CheckDependencies(dependencies)
|
||||||
|
allInstalled := true
|
||||||
|
for _, dep := range dependencies {
|
||||||
|
if !dep.Installed {
|
||||||
|
allInstalled = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show appropriate screen
|
||||||
|
if allInstalled {
|
||||||
|
gui.ShowProjectScreen()
|
||||||
|
} else {
|
||||||
|
gui.ShowDependencyScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.ShowAndRun()
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadProjects(filePath string) ([]project.Project, error) {
|
||||||
|
file, err := os.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return []project.Project{}, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("error opening JSON-file: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var projects []project.Project
|
||||||
|
decoder := json.NewDecoder(file)
|
||||||
|
if err := decoder.Decode(&projects); err != nil {
|
||||||
|
return nil, fmt.Errorf("error decoding JSON-file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return projects, nil
|
||||||
|
}
|
||||||
0
cmd/jws/projects/jakarta-jsp-todo/pom.xml
Normal file
0
cmd/jws/projects/jakarta-jsp-todo/pom.xml
Normal file
0
cmd/jws/projects/jakarta-rest-todo/pom.xml
Normal file
0
cmd/jws/projects/jakarta-rest-todo/pom.xml
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM mcr.microsoft.com/devcontainers/java:1-21-bullseye
|
||||||
|
|
||||||
|
ARG INSTALL_MAVEN="false"
|
||||||
|
ARG MAVEN_VERSION=""
|
||||||
|
|
||||||
|
ARG INSTALL_GRADLE="false"
|
||||||
|
ARG GRADLE_VERSION=""
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get upgrade -y && \
|
||||||
|
apt-get install -y \
|
||||||
|
git
|
||||||
|
|
||||||
|
RUN if [ "${INSTALL_MAVEN}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install maven \"${MAVEN_VERSION}\""; fi \
|
||||||
|
&& if [ "${INSTALL_GRADLE}" = "true" ]; then su vscode -c "umask 0002 && . /usr/local/sdkman/bin/sdkman-init.sh && sdk install gradle \"${GRADLE_VERSION}\""; fi
|
||||||
|
|
||||||
|
RUN mkdir -p /workspaces/${localWorkspaceFolderBasename} && chown -R vscode:vscode /workspaces/${localWorkspaceFolderBasename}
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/bash"]
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"name": "Jakarta EE Todo App & PostgreSQL",
|
||||||
|
"dockerComposeFile": "docker-compose.yml",
|
||||||
|
"service": "app",
|
||||||
|
"workspaceFolder": "/workspaces",
|
||||||
|
"extensions": ["vscjava.vscode-java-pack", "redhat.vscode-xml"],
|
||||||
|
"forwardPorts": [9080],
|
||||||
|
"remoteUser": "vscode"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
container_name: javadev
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
POSTGRES_HOSTNAME: postgresdb
|
||||||
|
volumes:
|
||||||
|
- ..:/workspace
|
||||||
|
command: sleep infinity
|
||||||
|
network_mode: service:db
|
||||||
|
stdin_open: true
|
||||||
|
|
||||||
|
db:
|
||||||
|
container_name: postgresdb
|
||||||
|
image: postgres:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
environment:
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_DB: postgres
|
||||||
49
cmd/jws/projects/jakarta-servlet-todo/pom.xml
Normal file
49
cmd/jws/projects/jakarta-servlet-todo/pom.xml
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.example</groupId>
|
||||||
|
<artifactId>jakarta-servlet-todo</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<jakartaee.version>10.0.0</jakartaee.version>
|
||||||
|
<hibernate.version>6.0.0.Final</hibernate.version>
|
||||||
|
<postgresql.version>42.3.1</postgresql.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jakarta.platform</groupId>
|
||||||
|
<artifactId>jakarta.jakartaee-api</artifactId>
|
||||||
|
<version>${jakartaee.version}</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate.orm</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>${hibernate.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>${postgresql.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<version>3.3.2</version>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.example.dao;
|
||||||
|
|
||||||
|
import com.example.model.Todo;
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TodoDAO {
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void create(Todo todo) {
|
||||||
|
em.persist(todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Todo> findAll() {
|
||||||
|
return em.createQuery("SELECT t FROM Todo t", Todo.class).getResultList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void update(Todo todo) {
|
||||||
|
em.merge(todo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void delete(Long id) {
|
||||||
|
Todo todo = em.find(Todo.class, id);
|
||||||
|
if (todo != null) {
|
||||||
|
em.remove(todo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package com.example.model;
|
||||||
|
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "todos")
|
||||||
|
public class Todo {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private boolean completed;
|
||||||
|
|
||||||
|
// Getter und Setter
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCompleted() {
|
||||||
|
return completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompleted(boolean completed) {
|
||||||
|
this.completed = completed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
package com.example.servlet;
|
||||||
|
|
||||||
|
import com.example.dao.TodoDAO;
|
||||||
|
import com.example.model.Todo;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.annotation.WebServlet;
|
||||||
|
import jakarta.servlet.http.HttpServlet;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@WebServlet("/todos")
|
||||||
|
public class TodoServlet extends HttpServlet {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TodoDAO todoDAO;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
List<Todo> todos = todoDAO.findAll();
|
||||||
|
req.setAttribute("todos", todos);
|
||||||
|
req.getRequestDispatcher("/index.jsp").forward(req, resp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
String title = req.getParameter("title");
|
||||||
|
boolean completed = "on".equals(req.getParameter("completed"));
|
||||||
|
|
||||||
|
Todo todo = new Todo();
|
||||||
|
todo.setTitle(title);
|
||||||
|
todo.setCompleted(completed);
|
||||||
|
|
||||||
|
todoDAO.create(todo);
|
||||||
|
resp.sendRedirect(req.getContextPath() + "/todos");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
|
||||||
|
<persistence-unit name="todoPU">
|
||||||
|
<class>com.example.model.Todo</class>
|
||||||
|
<properties>
|
||||||
|
<property name="jakarta.persistence.jdbc.driver" value="org.postgresql.Driver"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.url" value="jdbc:postgresql://db:5432/tododb"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.user" value="todouser"/>
|
||||||
|
<property name="jakarta.persistence.jdbc.password" value="todopass"/>
|
||||||
|
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
|
||||||
|
<property name="hibernate.hbm2ddl.auto" value="update"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
|
||||||
|
</persistence>
|
||||||
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||||
|
version="4.0">
|
||||||
|
|
||||||
|
<display-name>JakartaEE Todo App</display-name>
|
||||||
|
|
||||||
|
</web-app>
|
||||||
|
|
||||||
0
cmd/jws/projects/spring-boot-todo/pom.xml
Normal file
0
cmd/jws/projects/spring-boot-todo/pom.xml
Normal file
40
go.mod
Normal file
40
go.mod
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
module jws
|
||||||
|
|
||||||
|
go 1.23.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
fyne.io/fyne/v2 v2.6.0-alpha1
|
||||||
|
fyne.io/tools v1.0.0-alpha1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
fyne.io/systray v1.11.0 // indirect
|
||||||
|
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/fredbi/uri v1.1.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||||
|
github.com/fyne-io/gl-js v0.1.0 // indirect
|
||||||
|
github.com/fyne-io/glfw-js v0.1.0 // indirect
|
||||||
|
github.com/fyne-io/image v0.1.0 // indirect
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
|
||||||
|
github.com/go-text/render v0.2.0 // indirect
|
||||||
|
github.com/go-text/typesetting v0.2.1 // indirect
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 // indirect
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.5.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/rymdport/portal v0.3.0 // indirect
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
||||||
|
github.com/stretchr/testify v1.10.0 // indirect
|
||||||
|
github.com/yuin/goldmark v1.7.8 // indirect
|
||||||
|
golang.org/x/image v0.24.0 // indirect
|
||||||
|
golang.org/x/net v0.25.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
golang.org/x/text v0.22.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
76
go.sum
Normal file
76
go.sum
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
fyne.io/fyne/v2 v2.6.0-alpha1 h1:ALx1JJDdCYQpm5RS7CIK9bam9H7hddSDuRy/fyj9pb8=
|
||||||
|
fyne.io/fyne/v2 v2.6.0-alpha1/go.mod h1:Bzv2yK+ncZ8LJbHKjyJJpEAFlbs6oulHgKm04ObOqA8=
|
||||||
|
fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg=
|
||||||
|
fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs=
|
||||||
|
fyne.io/tools v1.0.0-alpha1 h1:350eF+LVPbIHNgYPCoP04yCsQSFQ3aupATx33ClZjZk=
|
||||||
|
fyne.io/tools v1.0.0-alpha1/go.mod h1:7gcHTl85tD/yLcGcU2bJGECAwSVAWrr99Ngmgrz/s54=
|
||||||
|
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||||
|
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||||
|
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||||
|
github.com/fredbi/uri v1.1.0 h1:OqLpTXtyRg9ABReqvDGdJPqZUxs8cyBDOMXBbskCaB8=
|
||||||
|
github.com/fredbi/uri v1.1.0/go.mod h1:aYTUoAXBOq7BLfVJ8GnKmfcuURosB1xyHDIfWeC/iW4=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/fyne-io/gl-js v0.1.0 h1:8luJzNs0ntEAJo+8x8kfUOXujUlP8gB3QMOxO2mUdpM=
|
||||||
|
github.com/fyne-io/gl-js v0.1.0/go.mod h1:ZcepK8vmOYLu96JoxbCKJy2ybr+g1pTnaBDdl7c3ajI=
|
||||||
|
github.com/fyne-io/glfw-js v0.1.0 h1:RGGMmVjcsG17Oifl3X2UJ5vH3PgS4B1UY3ASeN5BXbI=
|
||||||
|
github.com/fyne-io/glfw-js v0.1.0/go.mod h1:Ri6te7rdZtBgBpxLW19uBpp3Dl6K9K/bRaYdJ22G8Jk=
|
||||||
|
github.com/fyne-io/image v0.1.0 h1:Vm2TQJ2PWGHCf3jYi1/XroaNNMu+GfI/O2QpSbZd4XQ=
|
||||||
|
github.com/fyne-io/image v0.1.0/go.mod h1:xrfYBh6yspc+KjkgdZU/ifUC9sPA5Iv7WYUBzQKK7JM=
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
|
||||||
|
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
|
||||||
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
|
github.com/go-text/render v0.2.0 h1:LBYoTmp5jYiJ4NPqDc2pz17MLmA3wHw1dZSVGcOdeAc=
|
||||||
|
github.com/go-text/render v0.2.0/go.mod h1:CkiqfukRGKJA5vZZISkjSYrcdtgKQWRa2HIzvwNN5SU=
|
||||||
|
github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
|
||||||
|
github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
|
||||||
|
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
|
||||||
|
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||||
|
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y=
|
||||||
|
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08 h1:wMeVzrPO3mfHIWLZtDcSaGAe2I4PW9B/P5nMkRSwCAc=
|
||||||
|
github.com/jeandeaual/go-locale v0.0.0-20241217141322-fcc2cadd6f08/go.mod h1:ZDXo8KHryOWSIqnsb/CiDq7hQUYryCgdVnxbj8tDG7o=
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25 h1:YLvr1eE6cdCqjOe972w/cYF+FjW34v27+9Vo5106B4M=
|
||||||
|
github.com/jsummers/gobmp v0.0.0-20230614200233-a9de23ed2e25/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||||
|
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.5.1 h1:IxtPxYsR9Gp60cGXjfuR/llTqV8aYMsC472zD0D1vHk=
|
||||||
|
github.com/nicksnyder/go-i18n/v2 v2.5.1/go.mod h1:DrhgsSDZxoAfvVrBVLXoxZn/pN5TXqaDbq7ju94viiQ=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
|
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||||
|
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rymdport/portal v0.3.0 h1:QRHcwKwx3kY5JTQcsVhmhC3TGqGQb9LFghVNUy8AdB8=
|
||||||
|
github.com/rymdport/portal v0.3.0/go.mod h1:kFF4jslnJ8pD5uCi17brj/ODlfIidOxlgUDTO5ncnC4=
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c h1:km8GpoQut05eY3GiYWEedbTT0qnSxrCjsVbb7yKY1KE=
|
||||||
|
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c/go.mod h1:cNQ3dwVJtS5Hmnjxy6AgTPd0Inb3pW05ftPSX7NZO7Q=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||||
|
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||||
|
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||||
|
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||||
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
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)
|
||||||
|
})
|
||||||
|
}
|
||||||
60
pkg/download/download.go
Normal file
60
pkg/download/download.go
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
package download
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"fyne.io/fyne/v2/widget"
|
||||||
|
)
|
||||||
|
|
||||||
|
func WithProgressBar(downloadURL, filePath string, progressBar *widget.ProgressBar) error {
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 15 * time.Minute,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Get(downloadURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("download failed: %v", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create file: %v", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
contentLength := resp.ContentLength
|
||||||
|
if contentLength <= 0 {
|
||||||
|
return fmt.Errorf("invalid content length")
|
||||||
|
}
|
||||||
|
|
||||||
|
progressBar.Max = float64(contentLength)
|
||||||
|
|
||||||
|
buffer := make([]byte, 4096)
|
||||||
|
var totalBytes int64
|
||||||
|
|
||||||
|
for {
|
||||||
|
n, readErr := resp.Body.Read(buffer)
|
||||||
|
if n > 0 {
|
||||||
|
totalBytes += int64(n)
|
||||||
|
progressBar.SetValue(float64(totalBytes))
|
||||||
|
|
||||||
|
if _, writeErr := file.Write(buffer[:n]); writeErr != nil {
|
||||||
|
return fmt.Errorf("error writing to file: %v", writeErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if readErr == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if readErr != nil {
|
||||||
|
return fmt.Errorf("download aborted: %v", readErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue