diff --git a/cmd/build.go b/cmd/build.go
index 2e0ad36e..b6eff016 100644
--- a/cmd/build.go
+++ b/cmd/build.go
@@ -10,12 +10,16 @@ import (
"runtime"
"strings"
- "github.com/go-flutter-desktop/hover/internal/enginecache"
- "github.com/go-flutter-desktop/hover/internal/log"
- "github.com/go-flutter-desktop/hover/internal/versioncheck"
"github.com/hashicorp/go-version"
"github.com/otiai10/copy"
"github.com/spf13/cobra"
+
+ "github.com/go-flutter-desktop/hover/internal/enginecache"
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/versioncheck"
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "github.com/go-flutter-desktop/hover/cmd/packaging"
)
var dotSlash = string([]byte{'.', filepath.Separator})
@@ -31,8 +35,6 @@ var (
buildDocker bool
)
-const buildPath = "go"
-
const mingwGccBinName = "x86_64-w64-mingw32-gcc"
const clangBinName = "o32-clang"
@@ -49,8 +51,10 @@ func init() {
buildCmd.AddCommand(buildLinuxCmd)
buildCmd.AddCommand(buildLinuxSnapCmd)
buildCmd.AddCommand(buildLinuxDebCmd)
+ buildCmd.AddCommand(buildLinuxAppImageCmd)
buildCmd.AddCommand(buildDarwinCmd)
buildCmd.AddCommand(buildWindowsCmd)
+ buildCmd.AddCommand(buildWindowsMsiCmd)
rootCmd.AddCommand(buildCmd)
}
@@ -63,10 +67,9 @@ var buildLinuxCmd = &cobra.Command{
Use: "linux",
Short: "Build a desktop release for linux",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
- build(projectName, "linux", nil)
+ buildNormal("linux", nil)
},
}
@@ -74,12 +77,15 @@ var buildLinuxSnapCmd = &cobra.Command{
Use: "linux-snap",
Short: "Build a desktop release for linux and package it for snap",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
- assertPackagingFormatInitialized("linux-snap")
+ packaging.AssertPackagingFormatInitialized("linux-snap")
+
+ if !packaging.DockerInstalled() {
+ os.Exit(1)
+ }
- build(projectName, "linux", nil)
- buildLinuxSnap(projectName)
+ buildNormal("linux", nil)
+ packaging.BuildLinuxSnap()
},
}
@@ -87,12 +93,31 @@ var buildLinuxDebCmd = &cobra.Command{
Use: "linux-deb",
Short: "Build a desktop release for linux and package it for deb",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
- assertPackagingFormatInitialized("linux-deb")
+ packaging.AssertPackagingFormatInitialized("linux-deb")
+
+ if !packaging.DockerInstalled() {
+ os.Exit(1)
+ }
+
+ buildNormal("linux", nil)
+ packaging.BuildLinuxDeb()
+ },
+}
+
+var buildLinuxAppImageCmd = &cobra.Command{
+ Use: "linux-appimage",
+ Short: "Build a desktop release for linux and package it for AppImage",
+ Run: func(cmd *cobra.Command, args []string) {
+ assertHoverInitialized()
+ packaging.AssertPackagingFormatInitialized("linux-appimage")
+
+ if !packaging.DockerInstalled() {
+ os.Exit(1)
+ }
- build(projectName, "linux", nil)
- buildLinuxDeb(projectName)
+ buildNormal("linux", nil)
+ packaging.BuildLinuxAppImage()
},
}
@@ -100,10 +125,9 @@ var buildDarwinCmd = &cobra.Command{
Use: "darwin",
Short: "Build a desktop release for darwin",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
- build(projectName, "darwin", nil)
+ buildNormal("darwin", nil)
},
}
@@ -111,52 +135,30 @@ var buildWindowsCmd = &cobra.Command{
Use: "windows",
Short: "Build a desktop release for windows",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
- build(projectName, "windows", nil)
+ buildNormal("windows", nil)
},
}
-func outputDirectoryPath(targetOS string) string {
- outputDirectoryPath, err := filepath.Abs(filepath.Join(buildPath, "build", "outputs", targetOS))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for output directory: %v", err)
- os.Exit(1)
- }
- if _, err := os.Stat(outputDirectoryPath); os.IsNotExist(err) {
- err = os.MkdirAll(outputDirectoryPath, 0775)
- if err != nil {
- log.Errorf("Failed to create output directory %s: %v", outputDirectoryPath, err)
+var buildWindowsMsiCmd = &cobra.Command{
+ Use: "windows-msi",
+ Short: "Build a desktop release for windows and package it for msi",
+ Run: func(cmd *cobra.Command, args []string) {
+ assertHoverInitialized()
+ packaging.AssertPackagingFormatInitialized("windows-msi")
+
+ if !packaging.DockerInstalled() {
os.Exit(1)
}
- }
- return outputDirectoryPath
-}
-func outputBinaryName(projectName string, targetOS string) string {
- var outputBinaryName = projectName
- switch targetOS {
- case "darwin":
- // no special filename
- case "linux":
- // no special filename
- case "windows":
- outputBinaryName += ".exe"
- default:
- log.Errorf("Target platform %s is not supported.", targetOS)
- os.Exit(1)
- }
- return outputBinaryName
-}
-
-func outputBinaryPath(projectName string, targetOS string) string {
- outputBinaryPath := filepath.Join(outputDirectoryPath(targetOS), outputBinaryName(projectName, targetOS))
- return outputBinaryPath
+ buildNormal("windows", nil)
+ packaging.BuildWindowsMsi()
+ },
}
-func dockerBuild(projectName string, targetOS string, vmArguments []string) {
- crossCompilingDir, err := filepath.Abs(filepath.Join(buildPath, "cross-compiling"))
+func buildInDocker(targetOS string, vmArguments []string) {
+ crossCompilingDir, err := filepath.Abs(filepath.Join(build.BuildPath, "cross-compiling"))
err = os.MkdirAll(crossCompilingDir, 0755)
if err != nil {
log.Errorf("Cannot create the cross-compiling directory: %v", err)
@@ -205,9 +207,10 @@ func dockerBuild(projectName string, targetOS string, vmArguments []string) {
log.Errorf("Could not close Dockerfile: %v", err)
os.Exit(1)
}
- log.Infof("A Dockerfile for cross-compiling for %s has been created at %s. You can add it to git.", targetOS, filepath.Join(buildPath, "cross-compiling", targetOS))
+ log.Infof("A Dockerfile for cross-compiling for %s has been created at %s. You can add it to git.", targetOS, filepath.Join(build.BuildPath, "cross-compiling", targetOS))
}
- dockerBuildCmd := exec.Command(dockerBin, "build", "-t", "hover-build-cc", ".")
+ dockerBuildCmd := exec.Command(build.DockerBin, "build", "-t", "hover-build-cc", ".")
+ dockerBuildCmd.Stdout = os.Stdout
dockerBuildCmd.Stderr = os.Stderr
dockerBuildCmd.Dir = crossCompilingDir
err = dockerBuildCmd.Run()
@@ -239,8 +242,8 @@ func dockerBuild(projectName string, targetOS string, vmArguments []string) {
if runtime.GOOS != "windows" {
chownStr = fmt.Sprintf(" && chown %s:%s build/ -R", u.Uid, u.Gid)
}
- args = append(args, "bash", "-c", fmt.Sprintf("%s%s", strings.Join(buildCommand(targetOS, vmArguments, "build/outputs/"+targetOS+"/"+outputBinaryName(projectName, targetOS)), " "), chownStr))
- dockerRunCmd := exec.Command(dockerBin, args...)
+ args = append(args, "bash", "-c", fmt.Sprintf("%s%s", strings.Join(buildCommand(targetOS, vmArguments, "build/outputs/"+targetOS+"/"+build.OutputBinaryName(pubspec.GetPubSpec().Name, targetOS)), " "), chownStr))
+ dockerRunCmd := exec.Command(build.DockerBin, args...)
dockerRunCmd.Stderr = os.Stderr
dockerRunCmd.Stdout = os.Stdout
dockerRunCmd.Dir = crossCompilingDir
@@ -252,7 +255,7 @@ func dockerBuild(projectName string, targetOS string, vmArguments []string) {
log.Infof("Successfully cross-compiled for " + targetOS)
}
-func build(projectName string, targetOS string, vmArguments []string) {
+func buildNormal(targetOS string, vmArguments []string) {
crossCompile = targetOS != runtime.GOOS
buildDocker = crossCompile || buildDocker
@@ -263,21 +266,21 @@ func build(projectName string, targetOS string, vmArguments []string) {
}
if !buildOmitFlutterBundle && !buildOmitEmbedder {
- err := os.RemoveAll(outputDirectoryPath(targetOS))
+ err := os.RemoveAll(build.OutputDirectoryPath(targetOS))
log.Printf("Cleaning the build directory")
if err != nil {
- log.Errorf("Failed to clean output directory %s: %v", outputDirectoryPath(targetOS), err)
+ log.Errorf("Failed to clean output directory %s: %v", build.OutputDirectoryPath(targetOS), err)
os.Exit(1)
}
}
- err := os.MkdirAll(outputDirectoryPath(targetOS), 0775)
+ err := os.MkdirAll(build.OutputDirectoryPath(targetOS), 0775)
if err != nil {
- log.Errorf("Failed to create output directory %s: %v", outputDirectoryPath(targetOS), err)
+ log.Errorf("Failed to create output directory %s: %v", build.OutputDirectoryPath(targetOS), err)
os.Exit(1)
}
- cmdCheckFlutter := exec.Command(flutterBin, "--version")
+ cmdCheckFlutter := exec.Command(build.FlutterBin, "--version")
cmdCheckFlutterOut, err := cmdCheckFlutter.Output()
if err != nil {
log.Warnf("Failed to check your flutter channel: %v", err)
@@ -301,8 +304,8 @@ func build(projectName string, targetOS string, vmArguments []string) {
trackWidgetCreation = "--track-widget-creation"
}
- cmdFlutterBuild := exec.Command(flutterBin, "build", "bundle",
- "--asset-dir", filepath.Join(outputDirectoryPath(targetOS), "flutter_assets"),
+ cmdFlutterBuild := exec.Command(build.FlutterBin, "build", "bundle",
+ "--asset-dir", filepath.Join(build.OutputDirectoryPath(targetOS), "flutter_assets"),
"--target", buildTarget,
trackWidgetCreation,
)
@@ -328,7 +331,7 @@ func build(projectName string, targetOS string, vmArguments []string) {
engineFile = "flutter_engine.dll"
}
- outputEngineFile := filepath.Join(outputDirectoryPath(targetOS), engineFile)
+ outputEngineFile := filepath.Join(build.OutputDirectoryPath(targetOS), engineFile)
err = copy.Copy(
filepath.Join(engineCachePath, engineFile),
outputEngineFile,
@@ -347,7 +350,7 @@ func build(projectName string, targetOS string, vmArguments []string) {
err = copy.Copy(
filepath.Join(engineCachePath, "artifacts", "icudtl.dat"),
- filepath.Join(outputDirectoryPath(targetOS), "icudtl.dat"),
+ filepath.Join(build.OutputDirectoryPath(targetOS), "icudtl.dat"),
)
if err != nil {
log.Errorf("Failed to copy icudtl.dat: %v", err)
@@ -355,11 +358,11 @@ func build(projectName string, targetOS string, vmArguments []string) {
}
err = copy.Copy(
- filepath.Join(buildPath, "assets"),
- filepath.Join(outputDirectoryPath(targetOS), "assets"),
+ filepath.Join(build.BuildPath, "assets"),
+ filepath.Join(build.OutputDirectoryPath(targetOS), "assets"),
)
if err != nil {
- log.Errorf("Failed to copy %s/assets: %v", buildPath, err)
+ log.Errorf("Failed to copy %s/assets: %v", build.BuildPath, err)
os.Exit(1)
}
@@ -375,7 +378,7 @@ func build(projectName string, targetOS string, vmArguments []string) {
}
if buildBranch == "" {
- currentTag, err := versioncheck.CurrentGoFlutterTag(filepath.Join(wd, buildPath))
+ currentTag, err := versioncheck.CurrentGoFlutterTag(filepath.Join(wd, build.BuildPath))
if err != nil {
log.Errorf("%v", err)
os.Exit(1)
@@ -399,7 +402,7 @@ func build(projectName string, targetOS string, vmArguments []string) {
} else {
// when the buildBranch is empty and the currentTag is a release.
// Check if the 'go-flutter' needs updates.
- versioncheck.CheckForGoFlutterUpdate(filepath.Join(wd, buildPath), currentTag)
+ versioncheck.CheckForGoFlutterUpdate(filepath.Join(wd, build.BuildPath), currentTag)
}
} else {
@@ -420,13 +423,13 @@ func build(projectName string, targetOS string, vmArguments []string) {
if crossCompile {
log.Infof("Because %s is not able to compile for %s out of the box, a cross-compiling container is used", runtime.GOOS, targetOS)
}
- dockerBuild(projectName, targetOS, vmArguments)
+ buildInDocker(targetOS, vmArguments)
return
}
- buildCommandString := buildCommand(targetOS, vmArguments, outputBinaryPath(projectName, targetOS))
+ buildCommandString := buildCommand(targetOS, vmArguments, build.OutputBinaryPath(pubspec.GetPubSpec().Name, targetOS))
cmdGoBuild := exec.Command(buildCommandString[0], buildCommandString[1:]...)
- cmdGoBuild.Dir = filepath.Join(wd, buildPath)
+ cmdGoBuild.Dir = filepath.Join(wd, build.BuildPath)
cmdGoBuild.Env = append(os.Environ(),
buildEnv(targetOS, engineCachePath)...,
)
@@ -482,7 +485,7 @@ func buildEnv(targetOS string, engineCachePath string) []string {
}
func buildCommand(targetOS string, vmArguments []string, outputBinaryPath string) []string {
- currentTag, err := versioncheck.CurrentGoFlutterTag(buildPath)
+ currentTag, err := versioncheck.CurrentGoFlutterTag(build.BuildPath)
if err != nil {
log.Errorf("%v", err)
os.Exit(1)
@@ -506,9 +509,9 @@ func buildCommand(targetOS string, vmArguments []string, outputBinaryPath string
" -X github.com/go-flutter-desktop/go-flutter.PlatformVersion=%s "+
" -X github.com/go-flutter-desktop/go-flutter.ProjectName=%s "+
" -X github.com/go-flutter-desktop/go-flutter.ProjectOrganizationName=%s",
- getPubSpec().Version,
+ pubspec.GetPubSpec().Version,
currentTag,
- getPubSpec().Name,
+ pubspec.GetPubSpec().Name,
androidOrganizationName()))
outputCommand := []string{
diff --git a/cmd/common.go b/cmd/common.go
index b36e1b1c..5679b247 100644
--- a/cmd/common.go
+++ b/cmd/common.go
@@ -3,31 +3,26 @@ package cmd
import (
"bufio"
"encoding/xml"
+ "github.com/go-flutter-desktop/hover/internal/log"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
- "github.com/go-flutter-desktop/hover/internal/log"
- "gopkg.in/yaml.v2"
-)
-
-var (
- goBin string
- flutterBin string
- dockerBin string
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "github.com/go-flutter-desktop/hover/internal/build"
)
func initBinaries() {
var err error
goAvailable := false
dockerAvailable := false
- goBin, err = exec.LookPath("go")
+ build.GoBin, err = exec.LookPath("go")
if err == nil {
goAvailable = true
}
- dockerBin, err = exec.LookPath("docker")
+ build.DockerBin, err = exec.LookPath("docker")
if err == nil {
dockerAvailable = true
}
@@ -39,70 +34,25 @@ func initBinaries() {
log.Errorf("Failed to lookup `go` executable. Please install go or add '--docker' to force running in Docker container.\nhttps://golang.org/doc/install")
os.Exit(1)
}
- flutterBin, err = exec.LookPath("flutter")
+ build.FlutterBin, err = exec.LookPath("flutter")
if err != nil {
log.Errorf("Failed to lookup 'flutter' executable. Please install flutter.\nhttps://flutter.dev/docs/get-started/install")
os.Exit(1)
}
}
-// PubSpec basic model pubspec
-type PubSpec struct {
- Name string
- Description string
- Version string
- Author string
- Dependencies map[string]interface{}
-}
-
-var pubspec = PubSpec{}
-
-func getPubSpec() PubSpec {
- {
- if pubspec.Name == "" {
- file, err := os.Open("pubspec.yaml")
- if err != nil {
- if os.IsNotExist(err) {
- log.Errorf("Error: No pubspec.yaml file found.")
- goto Fail
- }
- log.Errorf("Failed to open pubspec.yaml: %v", err)
- os.Exit(1)
- }
- defer file.Close()
-
- err = yaml.NewDecoder(file).Decode(&pubspec)
- if err != nil {
- log.Errorf("Failed to decode pubspec.yaml: %v", err)
- goto Fail
- }
- if _, exists := pubspec.Dependencies["flutter"]; !exists {
- log.Errorf("Missing 'flutter' in pubspec.yaml dependencies list.")
- goto Fail
- }
- }
-
- return pubspec
- }
-
-Fail:
- log.Errorf("This command should be run from the root of your Flutter project.")
- os.Exit(1)
- return PubSpec{}
-}
-
// assertInFlutterProject asserts this command is executed in a flutter project
func assertInFlutterProject() {
- getPubSpec()
+ pubspec.GetPubSpec()
}
func assertHoverInitialized() {
- _, err := os.Stat(buildPath)
+ _, err := os.Stat(build.BuildPath)
if os.IsNotExist(err) {
if hoverMigration() {
return
}
- log.Errorf("Directory '%s' is missing. Please init go-flutter first: %s", buildPath, log.Au().Magenta("hover init"))
+ log.Errorf("Directory '%s' is missing. Please init go-flutter first: %s", build.BuildPath, log.Au().Magenta("hover init"))
os.Exit(1)
}
if err != nil {
@@ -124,7 +74,7 @@ func hoverMigration() bool {
log.Warnf(" Let hover do the migration? ")
if askForConfirmation() {
- err := os.Rename(oldBuildPath, buildPath)
+ err := os.Rename(oldBuildPath, build.BuildPath)
if err != nil {
log.Warnf("Migration failed: %v", err)
return false
diff --git a/cmd/init.go b/cmd/init.go
index 64674ba5..ab5381db 100644
--- a/cmd/init.go
+++ b/cmd/init.go
@@ -7,8 +7,11 @@ import (
"os/exec"
"path/filepath"
- "github.com/go-flutter-desktop/hover/internal/log"
"github.com/spf13/cobra"
+
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
)
func init() {
@@ -29,27 +32,27 @@ var initCmd = &cobra.Command{
var projectPath string
if len(args) == 0 || args[0] == "." {
- projectPath = getPubSpec().Name
+ projectPath = pubspec.GetPubSpec().Name
} else {
projectPath = args[0]
}
- err := os.Mkdir(buildPath, 0775)
+ err := os.Mkdir(build.BuildPath, 0775)
if err != nil {
if os.IsExist(err) {
- log.Errorf("A file or directory named '%s' already exists. Cannot continue init.", buildPath)
+ log.Errorf("A file or directory named '%s' already exists. Cannot continue init.", build.BuildPath)
os.Exit(1)
}
}
- desktopCmdPath := filepath.Join(buildPath, "cmd")
+ desktopCmdPath := filepath.Join(build.BuildPath, "cmd")
err = os.Mkdir(desktopCmdPath, 0775)
if err != nil {
log.Errorf("Failed to create '%s': %v", desktopCmdPath, err)
os.Exit(1)
}
- desktopAssetsPath := filepath.Join(buildPath, "assets")
+ desktopAssetsPath := filepath.Join(build.BuildPath, "assets")
err = os.Mkdir(desktopAssetsPath, 0775)
if err != nil {
log.Errorf("Failed to create '%s': %v", desktopAssetsPath, err)
@@ -59,7 +62,7 @@ var initCmd = &cobra.Command{
copyAsset("app/main.go", filepath.Join(desktopCmdPath, "main.go"))
copyAsset("app/options.go", filepath.Join(desktopCmdPath, "options.go"))
copyAsset("app/icon.png", filepath.Join(desktopAssetsPath, "icon.png"))
- copyAsset("app/gitignore", filepath.Join(buildPath, ".gitignore"))
+ copyAsset("app/gitignore", filepath.Join(build.BuildPath, ".gitignore"))
wd, err := os.Getwd()
if err != nil {
@@ -67,8 +70,8 @@ var initCmd = &cobra.Command{
os.Exit(1)
}
- cmdGoModInit := exec.Command(goBin, "mod", "init", projectPath+"/"+buildPath)
- cmdGoModInit.Dir = filepath.Join(wd, buildPath)
+ cmdGoModInit := exec.Command(build.GoBin, "mod", "init", projectPath+"/"+build.BuildPath)
+ cmdGoModInit.Dir = filepath.Join(wd, build.BuildPath)
cmdGoModInit.Env = append(os.Environ(),
"GO111MODULE=on",
)
@@ -80,8 +83,8 @@ var initCmd = &cobra.Command{
os.Exit(1)
}
- cmdGoModTidy := exec.Command(goBin, "mod", "tidy")
- cmdGoModTidy.Dir = filepath.Join(wd, buildPath)
+ cmdGoModTidy := exec.Command(build.GoBin, "mod", "tidy")
+ cmdGoModTidy.Dir = filepath.Join(wd, build.BuildPath)
log.Printf(cmdGoModTidy.Dir)
cmdGoModTidy.Env = append(os.Environ(),
"GO111MODULE=on",
diff --git a/cmd/packaging.go b/cmd/packaging.go
index a9c1f9b2..bab95b06 100644
--- a/cmd/packaging.go
+++ b/cmd/packaging.go
@@ -1,25 +1,16 @@
package cmd
import (
- "fmt"
- "io/ioutil"
- "os"
- "os/exec"
- "os/user"
- "path/filepath"
- "runtime"
- "strings"
-
- "github.com/go-flutter-desktop/hover/internal/log"
- "github.com/otiai10/copy"
"github.com/spf13/cobra"
-)
-var packagingPath = filepath.Join(buildPath, "packaging")
+ "github.com/go-flutter-desktop/hover/cmd/packaging"
+)
func init() {
initPackagingCmd.AddCommand(initLinuxSnapCmd)
initPackagingCmd.AddCommand(initLinuxDebCmd)
+ initPackagingCmd.AddCommand(initLinuxAppImageCmd)
+ initPackagingCmd.AddCommand(initWindowsMsiCmd)
rootCmd.AddCommand(initPackagingCmd)
}
@@ -32,10 +23,10 @@ var initLinuxSnapCmd = &cobra.Command{
Use: "linux-snap",
Short: "Create configuration files for snap packaging",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
+ packaging.DockerInstalled()
- initLinuxSnap(projectName)
+ packaging.InitLinuxSnap()
},
}
@@ -43,418 +34,31 @@ var initLinuxDebCmd = &cobra.Command{
Use: "linux-deb",
Short: "Create configuration files for deb packaging",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
assertHoverInitialized()
+ packaging.DockerInstalled()
- initLinuxDeb(projectName)
+ packaging.InitLinuxDeb()
},
}
-var linuxPackagingDependencies = []string{"libx11-6", "libxrandr2", "libxcursor1", "libxinerama1"}
-
-func packagingFormatPath(packagingFormat string) string {
- directoryPath, err := filepath.Abs(filepath.Join(packagingPath, packagingFormat))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for %s directory: %v", packagingFormat, err)
- os.Exit(1)
- }
- return directoryPath
-}
-
-func createPackagingFormatDirectory(packagingFormat string) {
- if _, err := os.Stat(packagingFormatPath(packagingFormat)); !os.IsNotExist(err) {
- log.Errorf("A file or directory named '%s' already exists. Cannot continue packaging init for %s.", packagingFormat, packagingFormat)
- os.Exit(1)
- }
- err := os.MkdirAll(packagingFormatPath(packagingFormat), 0775)
- if err != nil {
- log.Errorf("Failed to create %s directory %s: %v", packagingFormat, packagingFormatPath(packagingFormat), err)
- os.Exit(1)
- }
-}
-
-func assertPackagingFormatInitialized(packagingFormat string) {
- if _, err := os.Stat(packagingFormatPath(packagingFormat)); os.IsNotExist(err) {
- log.Errorf("%s is not initialized for packaging. Please init packaging for %s first: %s", packagingFormat, packagingFormat, log.Au().Magenta(fmt.Sprintf("hover init-packaging %s", packagingFormat)))
- os.Exit(1)
- }
-}
-
-func assertCorrectOS(packagingFormat string) {
- if runtime.GOOS != strings.Split(packagingFormat, "-")[0] {
- log.Errorf("%s only works on %s", packagingFormat, strings.Split(packagingFormat, "-")[0])
- os.Exit(1)
- }
-}
-
-func removeDashesAndUnderscores(projectName string) string {
- return strings.ReplaceAll(strings.ReplaceAll(projectName, "-", ""), "_", "")
-}
-
-func printInitFinished(packagingFormat string) {
- log.Infof("go/packaging/%s has been created. You can modify the configuration files and add them to git.", packagingFormat)
- log.Infof("You now can package the %s: %s", strings.Split(packagingFormat, "-")[1], fmt.Sprintf(log.Au().Magenta("hover build %s").String(), packagingFormat))
-}
-
-func getTemporaryBuildDirectory(projectName string, packagingFormat string) string {
- tmpPath, err := ioutil.TempDir("", "hover-build-"+projectName+"-"+packagingFormat)
- if err != nil {
- log.Errorf("Couldn't get temporary build directory: %v", err)
- os.Exit(1)
- }
- return tmpPath
-}
-
-func initLinuxSnap(projectName string) {
- packagingFormat := "linux-snap"
- assertCorrectOS(packagingFormat)
- createPackagingFormatDirectory(packagingFormat)
- snapDirectoryPath := packagingFormatPath(packagingFormat)
-
- snapLocalDirectoryPath, err := filepath.Abs(filepath.Join(snapDirectoryPath, "snap", "local"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for snap local directory: %v", err)
- os.Exit(1)
- }
- err = os.MkdirAll(snapLocalDirectoryPath, 0775)
- if err != nil {
- log.Errorf("Failed to create snap local directory %s: %v", snapDirectoryPath, err)
- os.Exit(1)
- }
-
- snapcraftFilePath, err := filepath.Abs(filepath.Join(snapDirectoryPath, "snap", "snapcraft.yaml"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for snapcraft.yaml file %s: %v", snapcraftFilePath, err)
- os.Exit(1)
- }
-
- snapcraftFile, err := os.Create(snapcraftFilePath)
- if err != nil {
- log.Errorf("Failed to create snapcraft.yaml file %s: %v", snapcraftFilePath, err)
- os.Exit(1)
- }
- snapcraftFileContent := []string{
- "name: " + removeDashesAndUnderscores(projectName),
- "base: core18",
- "version: '" + getPubSpec().Version + "'",
- "summary: " + getPubSpec().Description,
- "description: |",
- " " + getPubSpec().Description,
- "confinement: devmode",
- "grade: devel",
- "apps:",
- " " + removeDashesAndUnderscores(projectName) + ":",
- " command: " + projectName,
- " desktop: local/" + projectName + ".desktop",
- "parts:",
- " desktop:",
- " plugin: dump",
- " source: snap",
- " assets:",
- " plugin: dump",
- " source: assets",
- " app:",
- " plugin: dump",
- " source: build",
- " stage-packages:",
- }
- for _, dependency := range linuxPackagingDependencies {
- snapcraftFileContent = append(snapcraftFileContent, " - "+dependency)
- }
-
- for _, line := range snapcraftFileContent {
- if _, err := snapcraftFile.WriteString(line + "\n"); err != nil {
- log.Errorf("Could not write snapcraft.yaml: %v", err)
- os.Exit(1)
- }
- }
- err = snapcraftFile.Close()
- if err != nil {
- log.Errorf("Could not close snapcraft.yaml: %v", err)
- os.Exit(1)
- }
-
- desktopFilePath, err := filepath.Abs(filepath.Join(snapLocalDirectoryPath, projectName+".desktop"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for desktop file %s: %v", desktopFilePath, err)
- os.Exit(1)
- }
- desktopFile, err := os.Create(desktopFilePath)
- if err != nil {
- log.Errorf("Failed to create desktop file %s: %v", desktopFilePath, err)
- os.Exit(1)
- }
- desktopFileContent := []string{
- "[Desktop Entry]",
- "Encoding=UTF-8",
- "Version=" + getPubSpec().Version,
- "Type=Application",
- "Terminal=false",
- "Exec=/" + projectName,
- "Name=" + projectName,
- "Icon=/icon.png",
- }
-
- for _, line := range desktopFileContent {
- if _, err := desktopFile.WriteString(line + "\n"); err != nil {
- log.Errorf("Could not write %s.desktop: %v", projectName, err)
- os.Exit(1)
- }
- }
- err = desktopFile.Close()
- if err != nil {
- log.Errorf("Could not close %s.desktop: %v", projectName, err)
- os.Exit(1)
- }
-
- printInitFinished(packagingFormat)
-}
-
-func buildLinuxSnap(projectName string) {
- packagingFormat := "linux-snap"
- assertCorrectOS(packagingFormat)
- snapcraftBin, err := exec.LookPath("snapcraft")
- if err != nil {
- log.Errorf("Failed to lookup 'snapcraft' executable. Please install snapcraft.\nhttps://tutorials.ubuntu.com/tutorial/create-your-first-snap#1")
- os.Exit(1)
- }
- tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
- log.Infof("Packaging snap in %s", tmpPath)
-
- err = copy.Copy(filepath.Join(buildPath, "assets"), filepath.Join(tmpPath, "assets"))
- if err != nil {
- log.Errorf("Could not copy assets folder: %v", err)
- os.Exit(1)
- }
- err = copy.Copy(outputDirectoryPath("linux"), filepath.Join(tmpPath, "build"))
- if err != nil {
- log.Errorf("Could not copy build folder: %v", err)
- os.Exit(1)
- }
- err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
- if err != nil {
- log.Errorf("Could not copy packaging configuration folder: %v", err)
- os.Exit(1)
- }
-
- cmdBuildSnap := exec.Command(snapcraftBin)
- cmdBuildSnap.Dir = tmpPath
- cmdBuildSnap.Stdout = os.Stdout
- cmdBuildSnap.Stderr = os.Stderr
- cmdBuildSnap.Stdin = os.Stdin
- err = cmdBuildSnap.Run()
- if err != nil {
- log.Errorf("Failed to package snap: %v", err)
- os.Exit(1)
- }
- outputFilePath := filepath.Join(outputDirectoryPath("linux-snap"), removeDashesAndUnderscores(projectName)+"_"+runtime.GOARCH+".snap")
- err = os.Rename(filepath.Join(tmpPath, removeDashesAndUnderscores(projectName)+"_"+getPubSpec().Version+"_"+runtime.GOARCH+".snap"), outputFilePath)
- if err != nil {
- log.Errorf("Could not move snap file: %v", err)
- os.Exit(1)
- }
- err = os.RemoveAll(tmpPath)
- if err != nil {
- log.Errorf("Could not remove packaging configuration folder: %v", err)
- os.Exit(1)
- }
-}
-
-func initLinuxDeb(projectName string) {
- packagingFormat := "linux-deb"
- assertCorrectOS(packagingFormat)
- author := getPubSpec().Author
- if author == "" {
- log.Warnf("Missing author field in pubspec.yaml")
- u, err := user.Current()
- if err != nil {
- log.Errorf("Couldn't get current user: %v", err)
- os.Exit(1)
- }
- author = u.Username
- log.Printf("Using this username from system instead: %s", author)
- }
- createPackagingFormatDirectory(packagingFormat)
- debDirectoryPath := packagingFormatPath(packagingFormat)
- debDebianDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "DEBIAN"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for DEBIAN directory: %v", err)
- os.Exit(1)
- }
- err = os.MkdirAll(debDebianDirectoryPath, 0775)
- if err != nil {
- log.Errorf("Failed to create DEBIAN directory %s: %v", debDebianDirectoryPath, err)
- os.Exit(1)
- }
-
- binDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "usr", "bin"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for bin directory: %v", err)
- os.Exit(1)
- }
- err = os.MkdirAll(binDirectoryPath, 0775)
- if err != nil {
- log.Errorf("Failed to create bin directory %s: %v", binDirectoryPath, err)
- os.Exit(1)
- }
- applicationsDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "usr", "share", "applications"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for applications directory: %v", err)
- os.Exit(1)
- }
- err = os.MkdirAll(applicationsDirectoryPath, 0775)
- if err != nil {
- log.Errorf("Failed to create applications directory %s: %v", applicationsDirectoryPath, err)
- os.Exit(1)
- }
-
- controlFilePath, err := filepath.Abs(filepath.Join(debDebianDirectoryPath, "control"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for control file %s: %v", controlFilePath, err)
- os.Exit(1)
- }
-
- controlFile, err := os.Create(controlFilePath)
- if err != nil {
- log.Errorf("Failed to create control file %s: %v", controlFilePath, err)
- os.Exit(1)
- }
- controlFileContent := []string{
- "Package: " + removeDashesAndUnderscores(projectName),
- "Architecture: " + runtime.GOARCH,
- "Maintainer: @" + getPubSpec().Author,
- "Priority: optional",
- "Version: " + getPubSpec().Version,
- "Description: " + getPubSpec().Description,
- "Depends: " + strings.Join(linuxPackagingDependencies, ","),
- }
-
- for _, line := range controlFileContent {
- if _, err := controlFile.WriteString(line + "\n"); err != nil {
- log.Errorf("Could not write control file: %v", err)
- os.Exit(1)
- }
- }
- err = controlFile.Close()
- if err != nil {
- log.Errorf("Could not close control file: %v", err)
- os.Exit(1)
- }
-
- binFilePath, err := filepath.Abs(filepath.Join(binDirectoryPath, removeDashesAndUnderscores(projectName)))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for bin file %s: %v", binFilePath, err)
- os.Exit(1)
- }
-
- binFile, err := os.Create(binFilePath)
- if err != nil {
- log.Errorf("Failed to create bin file %s: %v", controlFilePath, err)
- os.Exit(1)
- }
- binFileContent := []string{
- "#!/bin/sh",
- "/usr/lib/" + projectName + "/" + projectName,
- }
- for _, line := range binFileContent {
- if _, err := binFile.WriteString(line + "\n"); err != nil {
- log.Errorf("Could not write bin file: %v", err)
- os.Exit(1)
- }
- }
- err = binFile.Close()
- if err != nil {
- log.Errorf("Could not close bin file: %v", err)
- os.Exit(1)
- }
- err = os.Chmod(binFilePath, 0777)
- if err != nil {
- log.Errorf("Failed to change file permissions for bin file: %v", err)
- os.Exit(1)
- }
-
- desktopFilePath, err := filepath.Abs(filepath.Join(applicationsDirectoryPath, projectName+".desktop"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for desktop file %s: %v", desktopFilePath, err)
- os.Exit(1)
- }
- desktopFile, err := os.Create(desktopFilePath)
- if err != nil {
- log.Errorf("Failed to create desktop file %s: %v", desktopFilePath, err)
- os.Exit(1)
- }
- desktopFileContent := []string{
- "[Desktop Entry]",
- "Encoding=UTF-8",
- "Version=" + getPubSpec().Version,
- "Type=Application",
- "Terminal=false",
- "Exec=/usr/bin/" + projectName,
- "Name=" + projectName,
- "Icon=/usr/lib/" + projectName + "/assets/icon.png",
- }
- for _, line := range desktopFileContent {
- if _, err := desktopFile.WriteString(line + "\n"); err != nil {
- log.Errorf("Could not write %s.desktop file: %v", projectName, err)
- os.Exit(1)
- }
- }
- err = desktopFile.Close()
- if err != nil {
- log.Errorf("Could not close %s.desktop file: %v", projectName, err)
- os.Exit(1)
- }
+var initLinuxAppImageCmd = &cobra.Command{
+ Use: "linux-appimage",
+ Short: "Create configuration files for AppImage packaging",
+ Run: func(cmd *cobra.Command, args []string) {
+ assertHoverInitialized()
+ packaging.DockerInstalled()
- printInitFinished(packagingFormat)
+ packaging.InitLinuxAppImage()
+ },
}
-func buildLinuxDeb(projectName string) {
- packagingFormat := "linux-deb"
- assertCorrectOS(packagingFormat)
- dpkgDebBin, err := exec.LookPath("dpkg-deb")
- if err != nil {
- log.Errorf("Failed to lookup 'dpkg-deb' executable. Please install dpkg-deb.")
- os.Exit(1)
- }
- tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
- log.Infof("Packaging deb in %s", tmpPath)
-
- libDirectoryPath, err := filepath.Abs(filepath.Join(tmpPath, "usr", "lib"))
- if err != nil {
- log.Errorf("Failed to resolve absolute path for bin directory: %v", err)
- os.Exit(1)
- }
- err = copy.Copy(outputDirectoryPath("linux"), filepath.Join(libDirectoryPath, projectName))
- if err != nil {
- log.Errorf("Could not copy build folder: %v", err)
- os.Exit(1)
- }
- err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
- if err != nil {
- log.Errorf("Could not copy packaging configuration folder: %v", err)
- os.Exit(1)
- }
- outputFileName := removeDashesAndUnderscores(projectName) + "_" + runtime.GOARCH + ".deb"
- outputFilePath := filepath.Join(outputDirectoryPath("linux-deb"), outputFileName)
+var initWindowsMsiCmd = &cobra.Command{
+ Use: "windows-msi",
+ Short: "Create configuration files for msi packaging",
+ Run: func(cmd *cobra.Command, args []string) {
+ assertHoverInitialized()
+ packaging.DockerInstalled()
- cmdBuildDeb := exec.Command(dpkgDebBin, "--build", ".", outputFileName)
- cmdBuildDeb.Dir = tmpPath
- cmdBuildDeb.Stdout = os.Stdout
- cmdBuildDeb.Stderr = os.Stderr
- cmdBuildDeb.Stdin = os.Stdin
- err = cmdBuildDeb.Run()
- if err != nil {
- log.Errorf("Failed to package deb: %v", err)
- os.Exit(1)
- }
- err = os.Rename(filepath.Join(tmpPath, outputFileName), outputFilePath)
- if err != nil {
- log.Errorf("Could not move deb file: %v", err)
- os.Exit(1)
- }
- err = os.RemoveAll(tmpPath)
- if err != nil {
- log.Errorf("Could not remove packaging configuration folder: %v", err)
- os.Exit(1)
- }
+ packaging.InitWindowsMsi()
+ },
}
diff --git a/cmd/packaging/linux-appimage.go b/cmd/packaging/linux-appimage.go
new file mode 100644
index 00000000..16821304
--- /dev/null
+++ b/cmd/packaging/linux-appimage.go
@@ -0,0 +1,93 @@
+package packaging
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "github.com/otiai10/copy"
+ "os"
+ "path/filepath"
+)
+
+func InitLinuxAppImage() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-appimage"
+ createPackagingFormatDirectory(packagingFormat)
+ appImageDirectoryPath := packagingFormatPath(packagingFormat)
+ appRunFilePath, err := filepath.Abs(filepath.Join(appImageDirectoryPath, "AppRun"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for AppRun file %s: %v", appRunFilePath, err)
+ os.Exit(1)
+ }
+
+ appRunFile, err := os.Create(appRunFilePath)
+ if err != nil {
+ log.Errorf("Failed to create AppRun file %s: %v", appRunFilePath, err)
+ os.Exit(1)
+ }
+ appRunFileContent := []string{
+ `#!/bin/sh`,
+ `cd "$(dirname "$0")"`,
+ `exec ./build/` + projectName,
+ }
+ for _, line := range appRunFileContent {
+ if _, err := appRunFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write AppRun file: %v", err)
+ os.Exit(1)
+ }
+ }
+ err = appRunFile.Close()
+ if err != nil {
+ log.Errorf("Could not close AppRun file: %v", err)
+ os.Exit(1)
+ }
+ err = os.Chmod(appRunFilePath, 0777)
+ if err != nil {
+ log.Errorf("Failed to change file permissions for AppRun file: %v", err)
+ os.Exit(1)
+ }
+
+ desktopFilePath, err := filepath.Abs(filepath.Join(appImageDirectoryPath, projectName+".desktop"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for desktop file %s: %v", desktopFilePath, err)
+ os.Exit(1)
+ }
+ createLinuxDesktopFile(desktopFilePath, packagingFormat, "", "/build/assets/icon")
+ createDockerfile(packagingFormat)
+
+ printInitFinished(packagingFormat)
+}
+
+func BuildLinuxAppImage() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-appimage"
+ tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
+ log.Infof("Packaging AppImage in %s", tmpPath)
+
+ err := copy.Copy(build.OutputDirectoryPath("linux"), filepath.Join(tmpPath, "build"))
+ if err != nil {
+ log.Errorf("Could not copy build folder: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
+ if err != nil {
+ log.Errorf("Could not copy packaging configuration folder: %v", err)
+ os.Exit(1)
+ }
+
+ outputFileName := projectName + "-x86_64.AppImage"
+ outputFilePath := filepath.Join(build.OutputDirectoryPath("linux-appimage"), outputFileName)
+ runDockerPackaging(tmpPath, packagingFormat, []string{"appimagetool", ".",})
+
+ err = os.Rename(filepath.Join(tmpPath, outputFileName), outputFilePath)
+ if err != nil {
+ log.Errorf("Could not move AppImage file: %v", err)
+ os.Exit(1)
+ }
+ err = os.RemoveAll(tmpPath)
+ if err != nil {
+ log.Errorf("Could not remove temporary build directory: %v", err)
+ os.Exit(1)
+ }
+ printPackagingFinished(packagingFormat)
+}
diff --git a/cmd/packaging/linux-deb.go b/cmd/packaging/linux-deb.go
new file mode 100644
index 00000000..adbbb73e
--- /dev/null
+++ b/cmd/packaging/linux-deb.go
@@ -0,0 +1,166 @@
+package packaging
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/otiai10/copy"
+
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+)
+
+func InitLinuxDeb() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-deb"
+ createPackagingFormatDirectory(packagingFormat)
+ debDirectoryPath := packagingFormatPath(packagingFormat)
+ debDebianDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "DEBIAN"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for DEBIAN directory: %v", err)
+ os.Exit(1)
+ }
+ err = os.MkdirAll(debDebianDirectoryPath, 0775)
+ if err != nil {
+ log.Errorf("Failed to create DEBIAN directory %s: %v", debDebianDirectoryPath, err)
+ os.Exit(1)
+ }
+
+ binDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "usr", "bin"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for bin directory: %v", err)
+ os.Exit(1)
+ }
+ err = os.MkdirAll(binDirectoryPath, 0775)
+ if err != nil {
+ log.Errorf("Failed to create bin directory %s: %v", binDirectoryPath, err)
+ os.Exit(1)
+ }
+ applicationsDirectoryPath, err := filepath.Abs(filepath.Join(debDirectoryPath, "usr", "share", "applications"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for applications directory: %v", err)
+ os.Exit(1)
+ }
+ err = os.MkdirAll(applicationsDirectoryPath, 0775)
+ if err != nil {
+ log.Errorf("Failed to create applications directory %s: %v", applicationsDirectoryPath, err)
+ os.Exit(1)
+ }
+
+ controlFilePath, err := filepath.Abs(filepath.Join(debDebianDirectoryPath, "control"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for control file %s: %v", controlFilePath, err)
+ os.Exit(1)
+ }
+
+ controlFile, err := os.Create(controlFilePath)
+ if err != nil {
+ log.Errorf("Failed to create control file %s: %v", controlFilePath, err)
+ os.Exit(1)
+ }
+ controlFileContent := []string{
+ "Package: " + removeDashesAndUnderscores(projectName),
+ "Architecture: amd64",
+ "Maintainer: @" + getAuthor(),
+ "Priority: optional",
+ "Version: " + pubspec.GetPubSpec().Version,
+ "Description: " + pubspec.GetPubSpec().Description,
+ "Depends: " + strings.Join(linuxPackagingDependencies, ","),
+ }
+
+ for _, line := range controlFileContent {
+ if _, err := controlFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write control file: %v", err)
+ os.Exit(1)
+ }
+ }
+ err = controlFile.Close()
+ if err != nil {
+ log.Errorf("Could not close control file: %v", err)
+ os.Exit(1)
+ }
+
+ binFilePath, err := filepath.Abs(filepath.Join(binDirectoryPath, removeDashesAndUnderscores(projectName)))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for bin file %s: %v", binFilePath, err)
+ os.Exit(1)
+ }
+
+ binFile, err := os.Create(binFilePath)
+ if err != nil {
+ log.Errorf("Failed to create bin file %s: %v", controlFilePath, err)
+ os.Exit(1)
+ }
+ binFileContent := []string{
+ "#!/bin/sh",
+ "/usr/lib/" + projectName + "/" + projectName,
+ }
+ for _, line := range binFileContent {
+ if _, err := binFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write bin file: %v", err)
+ os.Exit(1)
+ }
+ }
+ err = binFile.Close()
+ if err != nil {
+ log.Errorf("Could not close bin file: %v", err)
+ os.Exit(1)
+ }
+ err = os.Chmod(binFilePath, 0777)
+ if err != nil {
+ log.Errorf("Failed to change file permissions for bin file: %v", err)
+ os.Exit(1)
+ }
+
+ desktopFilePath, err := filepath.Abs(filepath.Join(applicationsDirectoryPath, projectName+".desktop"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for desktop file %s: %v", desktopFilePath, err)
+ os.Exit(1)
+ }
+ createLinuxDesktopFile(desktopFilePath, packagingFormat, "/usr/bin/"+projectName, "/usr/lib/"+projectName+"/assets/icon.png")
+ createDockerfile(packagingFormat)
+
+ printInitFinished(packagingFormat)
+}
+
+func BuildLinuxDeb() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-deb"
+ tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
+ log.Infof("Packaging deb in %s", tmpPath)
+
+ libDirectoryPath, err := filepath.Abs(filepath.Join(tmpPath, "usr", "lib"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for lib directory: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(build.OutputDirectoryPath("linux"), filepath.Join(libDirectoryPath, projectName))
+ if err != nil {
+ log.Errorf("Could not copy build folder: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
+ if err != nil {
+ log.Errorf("Could not copy packaging configuration folder: %v", err)
+ os.Exit(1)
+ }
+
+ outputFileName := removeDashesAndUnderscores(projectName) + "_" + runtime.GOARCH + ".deb"
+ outputFilePath := filepath.Join(build.OutputDirectoryPath("linux-deb"), outputFileName)
+ runDockerPackaging(tmpPath, packagingFormat, []string{"dpkg-deb", "--build", ".", outputFileName})
+
+ err = os.Rename(filepath.Join(tmpPath, outputFileName), outputFilePath)
+ if err != nil {
+ log.Errorf("Could not move deb file: %v", err)
+ os.Exit(1)
+ }
+ err = os.RemoveAll(tmpPath)
+ if err != nil {
+ log.Errorf("Could not remove temporary build directory: %v", err)
+ os.Exit(1)
+ }
+ printPackagingFinished(packagingFormat)
+}
diff --git a/cmd/packaging/linux-snap.go b/cmd/packaging/linux-snap.go
new file mode 100644
index 00000000..dd717513
--- /dev/null
+++ b/cmd/packaging/linux-snap.go
@@ -0,0 +1,132 @@
+package packaging
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "os"
+ "path/filepath"
+ "runtime"
+
+ "github.com/otiai10/copy"
+
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+)
+
+func InitLinuxSnap() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-snap"
+ createPackagingFormatDirectory(packagingFormat)
+ snapDirectoryPath := packagingFormatPath(packagingFormat)
+
+ snapLocalDirectoryPath, err := filepath.Abs(filepath.Join(snapDirectoryPath, "snap", "local"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for snap local directory: %v", err)
+ os.Exit(1)
+ }
+ err = os.MkdirAll(snapLocalDirectoryPath, 0775)
+ if err != nil {
+ log.Errorf("Failed to create snap local directory %s: %v", snapDirectoryPath, err)
+ os.Exit(1)
+ }
+
+ snapcraftFilePath, err := filepath.Abs(filepath.Join(snapDirectoryPath, "snap", "snapcraft.yaml"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for snapcraft.yaml file %s: %v", snapcraftFilePath, err)
+ os.Exit(1)
+ }
+
+ snapcraftFile, err := os.Create(snapcraftFilePath)
+ if err != nil {
+ log.Errorf("Failed to create snapcraft.yaml file %s: %v", snapcraftFilePath, err)
+ os.Exit(1)
+ }
+ snapcraftFileContent := []string{
+ "name: " + removeDashesAndUnderscores(projectName),
+ "base: core18",
+ "version: '" + pubspec.GetPubSpec().Version + "'",
+ "summary: " + pubspec.GetPubSpec().Description,
+ "description: |",
+ " " + pubspec.GetPubSpec().Description,
+ "confinement: devmode",
+ "grade: devel",
+ "apps:",
+ " " + removeDashesAndUnderscores(projectName) + ":",
+ " command: " + projectName,
+ " desktop: local/" + projectName + ".desktop",
+ "parts:",
+ " desktop:",
+ " plugin: dump",
+ " source: snap",
+ " assets:",
+ " plugin: dump",
+ " source: assets",
+ " app:",
+ " plugin: dump",
+ " source: build",
+ " stage-packages:",
+ }
+ for _, dependency := range linuxPackagingDependencies {
+ snapcraftFileContent = append(snapcraftFileContent, " - "+dependency)
+ }
+
+ for _, line := range snapcraftFileContent {
+ if _, err := snapcraftFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write snapcraft.yaml: %v", err)
+ os.Exit(1)
+ }
+ }
+ err = snapcraftFile.Close()
+ if err != nil {
+ log.Errorf("Could not close snapcraft.yaml: %v", err)
+ os.Exit(1)
+ }
+
+ desktopFilePath, err := filepath.Abs(filepath.Join(snapLocalDirectoryPath, projectName+".desktop"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for desktop file %s: %v", desktopFilePath, err)
+ os.Exit(1)
+ }
+ createLinuxDesktopFile(desktopFilePath, packagingFormat, "/"+projectName, "/icon.png")
+ createDockerfile(packagingFormat)
+
+ printInitFinished(packagingFormat)
+}
+
+func BuildLinuxSnap() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "linux-snap"
+ tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
+ log.Infof("Packaging snap in %s", tmpPath)
+
+ err := copy.Copy(filepath.Join(build.BuildPath, "assets"), filepath.Join(tmpPath, "assets"))
+ if err != nil {
+ log.Errorf("Could not copy assets folder: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(build.OutputDirectoryPath("linux"), filepath.Join(tmpPath, "build"))
+ if err != nil {
+ log.Errorf("Could not copy build folder: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
+ if err != nil {
+ log.Errorf("Could not copy packaging configuration folder: %v", err)
+ os.Exit(1)
+ }
+
+ outputFileName := removeDashesAndUnderscores(projectName) + "_" + pubspec.GetPubSpec().Version + "_" + runtime.GOARCH + ".snap"
+ outputFilePath := filepath.Join(build.OutputDirectoryPath("linux-snap"), outputFileName)
+ runDockerPackaging(tmpPath, packagingFormat, []string{"snapcraft"})
+
+ err = os.Rename(filepath.Join(tmpPath, outputFileName), outputFilePath)
+ if err != nil {
+ log.Errorf("Could not move snap file: %v", err)
+ os.Exit(1)
+ }
+ err = os.RemoveAll(tmpPath)
+ if err != nil {
+ log.Errorf("Could not remove temporary build directory: %v", err)
+ os.Exit(1)
+ }
+ printPackagingFinished(packagingFormat)
+}
diff --git a/cmd/packaging/linux.go b/cmd/packaging/linux.go
new file mode 100644
index 00000000..cbbcd75e
--- /dev/null
+++ b/cmd/packaging/linux.go
@@ -0,0 +1,41 @@
+package packaging
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "os"
+)
+
+var linuxPackagingDependencies = []string{"libx11-6", "libxrandr2", "libxcursor1", "libxinerama1", "libglu1-mesa", "libgcc1", "libstdc++6", "libtinfo5", "zlib1g"}
+
+func createLinuxDesktopFile(desktopFilePath string, packagingFormat string, exec string, icon string) {
+ desktopFile, err := os.Create(desktopFilePath)
+ if err != nil {
+ log.Errorf("Failed to create %s.desktop %s: %v", pubspec.GetPubSpec().Name, desktopFilePath, err)
+ os.Exit(1)
+ }
+ desktopFileContent := []string{
+ "[Desktop Entry]",
+ "Version=1.0",
+ "Type=Application",
+ "Terminal=false",
+ "Name=" + pubspec.GetPubSpec().Name,
+ "Icon=" + icon,
+ "Categories=",
+ }
+ if exec != "" {
+ desktopFileContent = append(desktopFileContent, "Exec="+exec)
+ }
+
+ for _, line := range desktopFileContent {
+ if _, err := desktopFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write %s.desktop: %v", pubspec.GetPubSpec().Name, err)
+ os.Exit(1)
+ }
+ }
+ err = desktopFile.Close()
+ if err != nil {
+ log.Errorf("Could not close %s.desktop: %v", pubspec.GetPubSpec().Name, err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/packaging/packaging.go b/cmd/packaging/packaging.go
new file mode 100644
index 00000000..ab9cb906
--- /dev/null
+++ b/cmd/packaging/packaging.go
@@ -0,0 +1,183 @@
+package packaging
+
+import (
+ "fmt"
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "os/user"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/go-flutter-desktop/hover/internal/build"
+)
+
+var packagingPath = filepath.Join(build.BuildPath, "packaging")
+
+func packagingFormatPath(packagingFormat string) string {
+ directoryPath, err := filepath.Abs(filepath.Join(packagingPath, packagingFormat))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for %s directory: %v", packagingFormat, err)
+ os.Exit(1)
+ }
+ return directoryPath
+}
+
+func createPackagingFormatDirectory(packagingFormat string) {
+ if _, err := os.Stat(packagingFormatPath(packagingFormat)); !os.IsNotExist(err) {
+ log.Errorf("A file or directory named `%s` already exists. Cannot continue packaging init for %s.", packagingFormat, packagingFormat)
+ os.Exit(1)
+ }
+ err := os.MkdirAll(packagingFormatPath(packagingFormat), 0775)
+ if err != nil {
+ log.Errorf("Failed to create %s directory %s: %v", packagingFormat, packagingFormatPath(packagingFormat), err)
+ os.Exit(1)
+ }
+}
+
+func AssertPackagingFormatInitialized(packagingFormat string) {
+ if _, err := os.Stat(packagingFormatPath(packagingFormat)); os.IsNotExist(err) {
+ log.Errorf("%s is not initialized for packaging. Please run `hover init-packaging %s` first.", packagingFormat, packagingFormat)
+ os.Exit(1)
+ }
+}
+
+func removeDashesAndUnderscores(projectName string) string {
+ return strings.ReplaceAll(strings.ReplaceAll(projectName, "-", ""), "_", "")
+}
+
+func printInitFinished(packagingFormat string) {
+ log.Infof("go/packaging/%s has been created. You can modify the configuration files and add it to git.", packagingFormat)
+ log.Infof("You now can package the %s using `hover build %s`", strings.Split(packagingFormat, "-")[0], packagingFormat)
+}
+
+func printPackagingFinished(packagingFormat string) {
+ log.Infof("Successfully packaged %s", strings.Split(packagingFormat, "-")[1])
+}
+
+func getTemporaryBuildDirectory(projectName string, packagingFormat string) string {
+ tmpPath, err := ioutil.TempDir("", "hover-build-"+projectName+"-"+packagingFormat)
+ if err != nil {
+ log.Errorf("Couldn't get temporary build directory: %v", err)
+ os.Exit(1)
+ }
+ return tmpPath
+}
+
+func DockerInstalled() bool {
+ if build.DockerBin == "" {
+ log.Warnf("To use packaging, Docker needs to be installed.\nhttps://docs.docker.com/install")
+ }
+ return build.DockerBin != ""
+}
+
+func getAuthor() string {
+ author := pubspec.GetPubSpec().Author
+ if author == "" {
+ log.Warnf("Missing author field in pubspec.yaml")
+ u, err := user.Current()
+ if err != nil {
+ log.Errorf("Couldn't get current user: %v", err)
+ os.Exit(1)
+ }
+ author = u.Username
+ log.Printf("Using this username from system instead: %s", author)
+ }
+ return author
+}
+
+func createDockerfile(packagingFormat string) {
+ dockerFilePath, err := filepath.Abs(filepath.Join(packagingFormatPath(packagingFormat), "Dockerfile"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for Dockerfile %s: %v", dockerFilePath, err)
+ os.Exit(1)
+ }
+ dockerFile, err := os.Create(dockerFilePath)
+ if err != nil {
+ log.Errorf("Failed to create Dockerfile %s: %v", dockerFilePath, err)
+ os.Exit(1)
+ }
+ dockerFileContent := []string{}
+ if packagingFormat == "linux-snap" {
+ dockerFileContent = []string{
+ "FROM snapcore/snapcraft",
+ }
+ } else if packagingFormat == "linux-deb" {
+ dockerFileContent = []string{
+ "FROM ubuntu:bionic",
+ }
+ } else if packagingFormat == "linux-appimage" {
+ dockerFileContent = []string{
+ "FROM ubuntu:bionic",
+ "WORKDIR /opt",
+ "RUN apt-get update && \\",
+ "apt-get install libglib2.0-0 curl file -y",
+ "RUN curl -LO https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage && \\",
+ "chmod a+x appimagetool-x86_64.AppImage && \\",
+ "./appimagetool-x86_64.AppImage --appimage-extract && \\",
+ "mv squashfs-root appimagetool && \\",
+ "rm appimagetool-x86_64.AppImage",
+ "ENV PATH=/opt/appimagetool/usr/bin:/opt/linuxdeploy/usr/bin:$PATH",
+ }
+ } else if packagingFormat == "windows-msi" {
+ dockerFileContent = []string{
+ "FROM ubuntu:bionic",
+ "RUN apt-get update && apt-get install wixl -y",
+ }
+ } else {
+ log.Errorf("Tried to create Dockerfile for unknown packaging format %s", packagingFormat)
+ os.Exit(1)
+ }
+
+ for _, line := range dockerFileContent {
+ if _, err := dockerFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write Dockerfile: %v", err)
+ os.Exit(1)
+ }
+ }
+ err = dockerFile.Close()
+ if err != nil {
+ log.Errorf("Could not close Dockerfile: %v", err)
+ os.Exit(1)
+ }
+}
+
+func runDockerPackaging(path string, packagingFormat string, command []string) {
+ dockerBuildCmd := exec.Command(build.DockerBin, "build", "-t", "hover-build-packaging-"+packagingFormat, ".")
+ dockerBuildCmd.Stdout = os.Stdout
+ dockerBuildCmd.Stderr = os.Stderr
+ dockerBuildCmd.Dir = packagingFormatPath(packagingFormat)
+ err := dockerBuildCmd.Run()
+ if err != nil {
+ log.Errorf("Docker build failed: %v", err)
+ os.Exit(1)
+ }
+ u, err := user.Current()
+ if err != nil {
+ log.Errorf("Couldn't get current user: %v", err)
+ os.Exit(1)
+ }
+ args := []string{
+ "run",
+ "-w", "/app",
+ "-v", path + ":/app",
+ }
+ args = append(args, "hover-build-packaging-"+packagingFormat)
+ chownStr := ""
+ if runtime.GOOS != "windows" {
+ chownStr = fmt.Sprintf(" && chown %s:%s * -R", u.Uid, u.Gid)
+ }
+ args = append(args, "bash", "-c", fmt.Sprintf("%s%s", strings.Join(command, " "), chownStr))
+ dockerRunCmd := exec.Command(build.DockerBin, args...)
+ dockerRunCmd.Stderr = os.Stderr
+ dockerRunCmd.Stdout = os.Stdout
+ dockerRunCmd.Dir = path
+ err = dockerRunCmd.Run()
+ if err != nil {
+ log.Errorf("Docker run failed: %v", err)
+ os.Exit(1)
+ }
+}
diff --git a/cmd/packaging/windows-msi.go b/cmd/packaging/windows-msi.go
new file mode 100644
index 00000000..ba590dcd
--- /dev/null
+++ b/cmd/packaging/windows-msi.go
@@ -0,0 +1,265 @@
+package packaging
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/otiai10/copy"
+
+ "github.com/go-flutter-desktop/hover/internal/build"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "github.com/go-flutter-desktop/hover/internal/log"
+)
+
+var directoriesFileContent = []string{}
+var directoryRefsFileContent = []string{}
+var componentRefsFileContent = []string{}
+
+func InitWindowsMsi() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "windows-msi"
+ createPackagingFormatDirectory(packagingFormat)
+ msiDirectoryPath := packagingFormatPath(packagingFormat)
+
+ wxsFilePath, err := filepath.Abs(filepath.Join(msiDirectoryPath, projectName+".wxs"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for %s.wxs file %s: %v", projectName, wxsFilePath, err)
+ os.Exit(1)
+ }
+ wxsFile, err := os.Create(wxsFilePath)
+ if err != nil {
+ log.Errorf("Failed to create %s.wxs file %s: %v", projectName, wxsFilePath, err)
+ os.Exit(1)
+ }
+ wxsFileContent := []string{
+ ``,
+ ``,
+ fmt.Sprintf(` `, pubspec.GetPubSpec().Version, projectName, getAuthor()),
+ ` `,
+ fmt.Sprintf(` `, projectName),
+ ` `,
+ ` `,
+ fmt.Sprintf(` `, projectName),
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ fmt.Sprintf(` `, projectName),
+ fmt.Sprintf(` `, projectName, projectName),
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ fmt.Sprintf(` `, getAuthor(), projectName),
+ ` `,
+ ` `,
+ fmt.Sprintf(` `, projectName),
+ fmt.Sprintf(` `, projectName),
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ` `,
+ ``,
+ }
+
+ for _, line := range wxsFileContent {
+ if _, err := wxsFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write %s.wxs: %v", projectName, err)
+ os.Exit(1)
+ }
+ }
+ err = wxsFile.Close()
+ if err != nil {
+ log.Errorf("Could not close %s.wxs: %v", projectName, err)
+ os.Exit(1)
+ }
+
+ createDockerfile(packagingFormat)
+
+ printInitFinished(packagingFormat)
+}
+
+func BuildWindowsMsi() {
+ projectName := pubspec.GetPubSpec().Name
+ packagingFormat := "windows-msi"
+ tmpPath := getTemporaryBuildDirectory(projectName, packagingFormat)
+ log.Infof("Packaging msi in %s", tmpPath)
+
+ buildDirectoryPath, err := filepath.Abs(filepath.Join(tmpPath, "build"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for build directory: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(build.OutputDirectoryPath("windows"), filepath.Join(buildDirectoryPath))
+ if err != nil {
+ log.Errorf("Could not copy build folder: %v", err)
+ os.Exit(1)
+ }
+ err = copy.Copy(packagingFormatPath(packagingFormat), filepath.Join(tmpPath))
+ if err != nil {
+ log.Errorf("Could not copy packaging configuration folder: %v", err)
+ os.Exit(1)
+ }
+ directoriesFilePath, err := filepath.Abs(filepath.Join(tmpPath, "directories.wxi"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for directories.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ directoriesFile, err := os.Create(directoriesFilePath)
+ if err != nil {
+ log.Errorf("Failed to create directories.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ directoryRefsFilePath, err := filepath.Abs(filepath.Join(tmpPath, "directory_refs.wxi"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for directory_refs.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ directoryRefsFile, err := os.Create(directoryRefsFilePath)
+ if err != nil {
+ log.Errorf("Failed to create directory_refs.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ componentRefsFilePath, err := filepath.Abs(filepath.Join(tmpPath, "component_refs.wxi"))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for component_refs.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ componentRefsFile, err := os.Create(componentRefsFilePath)
+ if err != nil {
+ log.Errorf("Failed to create component_refs.wxi file %s: %v", projectName, err)
+ os.Exit(1)
+ }
+ directoriesFileContent = append(directoriesFileContent, ``)
+ directoryRefsFileContent = append(directoryRefsFileContent, ``, )
+ componentRefsFileContent = append(componentRefsFileContent, ``, )
+ processFiles(filepath.Join(buildDirectoryPath, "flutter_assets"))
+ directoriesFileContent = append(directoriesFileContent, ``)
+ directoryRefsFileContent = append(directoryRefsFileContent, ``, )
+ componentRefsFileContent = append(componentRefsFileContent, ``, )
+
+ for _, line := range directoriesFileContent {
+ if _, err := directoriesFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write directories.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+ }
+ err = directoriesFile.Close()
+ if err != nil {
+ log.Errorf("Could not close directories.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+ for _, line := range directoryRefsFileContent {
+ if _, err := directoryRefsFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write directory_refs.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+ }
+ err = directoryRefsFile.Close()
+ if err != nil {
+ log.Errorf("Could not close directory_refs.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+ for _, line := range componentRefsFileContent {
+ if _, err := componentRefsFile.WriteString(line + "\n"); err != nil {
+ log.Errorf("Could not write component_refs.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+ }
+ err = componentRefsFile.Close()
+ if err != nil {
+ log.Errorf("Could not close component_refs.wxi: %v", projectName, err)
+ os.Exit(1)
+ }
+
+ outputFileName := projectName + ".msi"
+ outputFilePath := filepath.Join(build.OutputDirectoryPath("windows-msi"), outputFileName)
+ runDockerPackaging(tmpPath, packagingFormat, []string{"wixl", "-v", projectName + ".wxs"})
+
+ err = os.Rename(filepath.Join(tmpPath, outputFileName), outputFilePath)
+ if err != nil {
+ log.Errorf("Could not move msi file: %v", err)
+ os.Exit(1)
+ }
+ err = os.RemoveAll(tmpPath)
+ if err != nil {
+ log.Errorf("Could not remove temporary build directory: %v", err)
+ os.Exit(1)
+ }
+
+ printPackagingFinished(packagingFormat)
+}
+
+func processFiles(path string) {
+ files, err := ioutil.ReadDir(path)
+ if err != nil {
+ log.Errorf("Failed to read directory %s: %v", path, err)
+ os.Exit(1)
+ }
+
+ for _, f := range files {
+ p := filepath.Join(path, f.Name())
+ relativePath := strings.Split(strings.Split(p, "flutter_assets"+string(filepath.Separator))[1], string(filepath.Separator))
+ if f.IsDir() {
+ directoriesFileContent = append(directoriesFileContent,
+ ``,
+ )
+ processFiles(p)
+ directoriesFileContent = append(directoriesFileContent,
+ ``,
+ )
+ } else {
+ if len(relativePath) > 1 {
+ directoryRefsFileContent = append(directoryRefsFileContent,
+ ``,
+ )
+ } else {
+ directoryRefsFileContent = append(directoryRefsFileContent,
+ ``,
+ )
+ }
+ directoryRefsFileContent = append(directoryRefsFileContent,
+ ``,
+ ``,
+ ``,
+ ``,
+ )
+ componentRefsFileContent = append(componentRefsFileContent,
+ ``,
+ )
+ }
+ }
+}
diff --git a/cmd/run.go b/cmd/run.go
index 064e2557..b8b4e5d4 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -10,8 +10,11 @@ import (
"regexp"
"runtime"
- "github.com/go-flutter-desktop/hover/internal/log"
"github.com/spf13/cobra"
+
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "github.com/go-flutter-desktop/hover/internal/pubspec"
+ "github.com/go-flutter-desktop/hover/internal/build"
)
var runObservatoryPort string
@@ -20,7 +23,6 @@ func init() {
runCmd.Flags().StringVarP(&buildTarget, "target", "t", "lib/main_desktop.dart", "The main entry-point file of the application.")
runCmd.Flags().StringVarP(&buildBranch, "branch", "b", "", "The 'go-flutter' version to use. (@master or @v0.20.0 for example)")
runCmd.Flags().StringVarP(&buildCachePath, "cache-path", "", "", "The path that hover uses to cache dependencies such as the Flutter engine .so/.dll (defaults to the standard user cache directory)")
- runCmd.Flags().StringVar(&buildOpenGlVersion, "opengl", "3.3", "The OpenGL version specified here is only relevant for external texture plugin (i.e. video_plugin).\nIf 'none' is provided, texture won't be supported. Note: the Flutter Engine still needs a OpenGL compatible context.")
runCmd.Flags().StringVarP(&runObservatoryPort, "observatory-port", "", "50300", "The observatory port used to connect hover to VM services (hot-reload/debug/..)")
runCmd.Flags().BoolVar(&buildOmitEmbedder, "omit-embedder", false, "Don't (re)compile 'go-flutter' source code, useful when only working with Dart code")
runCmd.Flags().BoolVar(&buildOmitFlutterBundle, "omit-flutter", false, "Don't (re)compile the current Flutter project, useful when only working with Golang code (plugin)")
@@ -32,7 +34,7 @@ var runCmd = &cobra.Command{
Use: "run",
Short: "Build and start a desktop release, with hot-reload support",
Run: func(cmd *cobra.Command, args []string) {
- projectName := getPubSpec().Name
+ projectName := pubspec.GetPubSpec().Name
assertHoverInitialized()
// ensure we have something to build
@@ -47,14 +49,14 @@ var runCmd = &cobra.Command{
// forcefully enable --debug (which is not an option for 'hover run')
buildDebug = true
- build(projectName, targetOS, []string{"--observatory-port=" + runObservatoryPort})
+ buildNormal(targetOS, []string{"--observatory-port=" + runObservatoryPort})
log.Infof("Build finished, starting app...")
runAndAttach(projectName, targetOS)
},
}
func runAndAttach(projectName string, targetOS string) {
- cmdApp := exec.Command(dotSlash + filepath.Join(buildPath, "build", "outputs", targetOS, projectName))
+ cmdApp := exec.Command(dotSlash + filepath.Join(build.BuildPath, "build", "outputs", targetOS, projectName))
cmdFlutterAttach := exec.Command("flutter", "attach")
stdoutApp, err := cmdApp.StdoutPipe()
diff --git a/cmd/upgrade.go b/cmd/upgrade.go
index 15ca3a0e..21ba46e3 100644
--- a/cmd/upgrade.go
+++ b/cmd/upgrade.go
@@ -2,6 +2,7 @@ package cmd
import (
"fmt"
+ "github.com/go-flutter-desktop/hover/internal/build"
"os"
"os/exec"
"path/filepath"
@@ -68,8 +69,8 @@ func upgradeGoFlutter(targetOS string, engineCachePath string) (err error) {
buildBranch = "@latest"
}
- cmdGoGetU := exec.Command(goBin, "get", "-u", "github.com/go-flutter-desktop/go-flutter"+buildBranch)
- cmdGoGetU.Dir = filepath.Join(wd, buildPath)
+ cmdGoGetU := exec.Command(build.GoBin, "get", "-u", "github.com/go-flutter-desktop/go-flutter"+buildBranch)
+ cmdGoGetU.Dir = filepath.Join(wd, build.BuildPath)
cmdGoGetU.Env = append(os.Environ(),
"GOPROXY=direct", // github.com/golang/go/issues/32955 (allows '/' in branch name)
"GO111MODULE=on",
@@ -84,8 +85,8 @@ func upgradeGoFlutter(targetOS string, engineCachePath string) (err error) {
return
}
- cmdGoModDownload := exec.Command(goBin, "mod", "download")
- cmdGoModDownload.Dir = filepath.Join(wd, buildPath)
+ cmdGoModDownload := exec.Command(build.GoBin, "mod", "download")
+ cmdGoModDownload.Dir = filepath.Join(wd, build.BuildPath)
cmdGoModDownload.Env = append(os.Environ(),
"GO111MODULE=on",
)
@@ -98,7 +99,7 @@ func upgradeGoFlutter(targetOS string, engineCachePath string) (err error) {
return
}
- currentTag, err := versioncheck.CurrentGoFlutterTag(filepath.Join(wd, buildPath))
+ currentTag, err := versioncheck.CurrentGoFlutterTag(filepath.Join(wd, build.BuildPath))
if err != nil {
log.Errorf("%v", err)
os.Exit(1)
diff --git a/internal/build/binaries.go b/internal/build/binaries.go
new file mode 100644
index 00000000..be21cda8
--- /dev/null
+++ b/internal/build/binaries.go
@@ -0,0 +1,7 @@
+package build
+
+var (
+ GoBin string
+ FlutterBin string
+ DockerBin string
+)
diff --git a/internal/build/build.go b/internal/build/build.go
new file mode 100644
index 00000000..e21bcab7
--- /dev/null
+++ b/internal/build/build.go
@@ -0,0 +1,46 @@
+package build
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "os"
+ "path/filepath"
+)
+
+const BuildPath = "go"
+
+func OutputDirectoryPath(targetOS string) string {
+ outputDirectoryPath, err := filepath.Abs(filepath.Join(BuildPath, "build", "outputs", targetOS))
+ if err != nil {
+ log.Errorf("Failed to resolve absolute path for output directory: %v", err)
+ os.Exit(1)
+ }
+ if _, err := os.Stat(outputDirectoryPath); os.IsNotExist(err) {
+ err = os.MkdirAll(outputDirectoryPath, 0775)
+ if err != nil {
+ log.Errorf("Failed to create output directory %s: %v", outputDirectoryPath, err)
+ os.Exit(1)
+ }
+ }
+ return outputDirectoryPath
+}
+
+func OutputBinaryName(projectName string, targetOS string) string {
+ var outputBinaryName = projectName
+ switch targetOS {
+ case "darwin":
+ // no special filename
+ case "linux":
+ // no special filename
+ case "windows":
+ outputBinaryName += ".exe"
+ default:
+ log.Errorf("Target platform %s is not supported.", targetOS)
+ os.Exit(1)
+ }
+ return outputBinaryName
+}
+
+func OutputBinaryPath(projectName string, targetOS string) string {
+ outputBinaryPath := filepath.Join(OutputDirectoryPath(targetOS), OutputBinaryName(projectName, targetOS))
+ return outputBinaryPath
+}
diff --git a/internal/pubspec/pubspec.go b/internal/pubspec/pubspec.go
new file mode 100644
index 00000000..8e90366b
--- /dev/null
+++ b/internal/pubspec/pubspec.go
@@ -0,0 +1,51 @@
+package pubspec
+
+import (
+ "github.com/go-flutter-desktop/hover/internal/log"
+ "gopkg.in/yaml.v2"
+ "os"
+)
+
+type PubSpec struct {
+ Name string
+ Description string
+ Version string
+ Author string
+ Dependencies map[string]interface{}
+}
+
+var pubspec = PubSpec{}
+
+func GetPubSpec() PubSpec {
+ {
+ if pubspec.Name == "" {
+ file, err := os.Open("pubspec.yaml")
+ if err != nil {
+ if os.IsNotExist(err) {
+ log.Errorf("Error: No pubspec.yaml file found.")
+ goto Fail
+ }
+ log.Errorf("Failed to open pubspec.yaml: %v", err)
+ os.Exit(1)
+ }
+ defer file.Close()
+
+ err = yaml.NewDecoder(file).Decode(&pubspec)
+ if err != nil {
+ log.Errorf("Failed to decode pubspec.yaml: %v", err)
+ goto Fail
+ }
+ if _, exists := pubspec.Dependencies["flutter"]; !exists {
+ log.Errorf("Missing `flutter` in pubspec.yaml dependencies list.")
+ goto Fail
+ }
+ }
+
+ return pubspec
+ }
+
+Fail:
+ log.Errorf("This command should be run from the root of your Flutter project.")
+ os.Exit(1)
+ return PubSpec{}
+}