Documentation ¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var DarwinBundleTask = &packagingTask{ packagingFormatName: "darwin-bundle", templateFiles: map[string]string{ "darwin-bundle/Info.plist.tmpl": "{{.applicationName}} {{.version}}.app/Contents/Info.plist.tmpl", }, executableFiles: []string{}, flutterBuildOutputDirectory: "{{.applicationName}} {{.version}}.app/Contents/MacOS", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { outputFileName := fmt.Sprintf("%s %s.app", applicationName, version) err := os.MkdirAll(filepath.Join(tmpPath, outputFileName, "Contents", "Resources"), 0755) if err != nil { return "", err } pngFile, err := os.Open(filepath.Join(tmpPath, outputFileName, "Contents", "MacOS", "assets", "icon.png")) if err != nil { return "", err } defer pngFile.Close() srcImg, _, err := image.Decode(pngFile) if err != nil { return "", err } icnsFile, err := os.Create(filepath.Join(tmpPath, outputFileName, "Contents", "Resources", "icon.icns")) if err != nil { return "", err } defer icnsFile.Close() err = icns.Encode(icnsFile, srcImg) if err != nil { return "", err } return outputFileName, nil }, requiredTools: map[string]map[string]string{ "linux": {}, "darwin": {}, "windows": {}, }, }
DarwinBundleTask packaging for darwin as bundle
View Source
var DarwinDmgTask = &packagingTask{ packagingFormatName: "darwin-dmg", dependsOn: map[*packagingTask]string{ DarwinBundleTask: "dmgdir", }, packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { outputFileName := fmt.Sprintf("%s %s.dmg", applicationName, version) cmdLn := exec.Command("ln", "-sf", "/Applications", "dmgdir/Applications") cmdLn.Dir = tmpPath cmdLn.Stdout = os.Stdout cmdLn.Stderr = os.Stderr err := cmdLn.Run() if err != nil { return "", err } appBundleOriginalPath := filepath.Join(tmpPath, "dmgdir", fmt.Sprintf("%s %s.app", applicationName, version)) appBundleFinalPath := filepath.Join(tmpPath, "dmgdir", fmt.Sprintf("%s.app", applicationName)) err = os.Rename(appBundleOriginalPath, appBundleFinalPath) if err != nil { return "", err } var cmdCreateBundle *exec.Cmd switch os := runtime.GOOS; os { case "darwin": cmdCreateBundle = exec.Command("hdiutil", "create", "-volname", packageName, "-srcfolder", "dmgdir", "-ov", "-format", "UDBZ", outputFileName) case "linux": cmdCreateBundle = exec.Command("mkisofs", "-V", packageName, "-D", "-R", "-apple", "-no-pad", "-o", outputFileName, "dmgdir") } cmdCreateBundle.Dir = tmpPath cmdCreateBundle.Stdout = os.Stdout cmdCreateBundle.Stderr = os.Stderr err = cmdCreateBundle.Run() if err != nil { return "", err } return outputFileName, nil }, skipAssertInitialized: true, requiredTools: map[string]map[string]string{ "linux": { "ln": "Install ln from your package manager", "mkisofs": "Install mkisofs from your package manager. Some distros ship genisoimage which is a fork of mkisofs. Create a symlink for it like this: ln -s $(which genisoimage) /usr/bin/mkisofs", }, "darwin": { "ln": "Install ln from your package manager", "hdiutil": "Install hdiutil from your package manager", }, }, }
DarwinDmgTask packaging for darwin as dmg
View Source
var DarwinPkgTask = &packagingTask{ packagingFormatName: "darwin-pkg", dependsOn: map[*packagingTask]string{ DarwinBundleTask: "flat/root/Applications", }, templateFiles: map[string]string{ "darwin-pkg/PackageInfo.tmpl": "flat/base.pkg/PackageInfo.tmpl", "darwin-pkg/Distribution.tmpl": "flat/Distribution.tmpl", }, packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { outputFileName := fmt.Sprintf("%s %s.pkg", applicationName, version) payload, err := os.OpenFile(filepath.Join(tmpPath, "flat", "base.pkg", "Payload"), os.O_RDWR|os.O_CREATE, 0755) if err != nil { return "", err } appBundleOriginalPath := filepath.Join(tmpPath, "flat", "root", "Applications", fmt.Sprintf("%s %s.app", applicationName, version)) appBundleFinalPath := filepath.Join(tmpPath, "flat", "root", "Applications", fmt.Sprintf("%s.app", applicationName)) err = os.Rename(appBundleOriginalPath, appBundleFinalPath) if err != nil { return "", err } cmdFind := exec.Command("find", ".") cmdFind.Dir = filepath.Join(tmpPath, "flat", "root") cmdCpio := exec.Command("cpio", "-o", "--format", "odc", "--owner", "0:80") cmdCpio.Dir = filepath.Join(tmpPath, "flat", "root") cmdGzip := exec.Command("gzip", "-c") cmdCpio.Stdin, err = cmdFind.StderrPipe() if err != nil { return "", err } cmdGzip.Stdin, err = cmdCpio.StderrPipe() if err != nil { return "", err } cmdGzip.Stdout = payload err = cmdGzip.Start() if err != nil { return "", err } err = cmdCpio.Start() if err != nil { return "", err } err = cmdFind.Run() if err != nil { return "", err } err = cmdCpio.Wait() if err != nil { return "", err } err = cmdGzip.Wait() if err != nil { return "", err } err = payload.Close() if err != nil { return "", err } var cmdMkbom *exec.Cmd switch os := runtime.GOOS; os { case "darwin": cmdMkbom = exec.Command("mkbom", filepath.Join("flat", "root"), filepath.Join("flat", "base.pkg", "Payload")) case "linux": cmdMkbom = exec.Command("mkbom", "-u", "0", "-g", "80", filepath.Join("flat", "root"), filepath.Join("flat", "base.pkg", "Payload")) } cmdMkbom.Dir = tmpPath cmdMkbom.Stdout = os.Stdout cmdMkbom.Stderr = os.Stderr err = cmdMkbom.Run() if err != nil { return "", nil } var files []string err = filepath.Walk(filepath.Join(tmpPath, "flat"), func(path string, info os.FileInfo, err error) error { relativePath, err := filepath.Rel(filepath.Join(tmpPath, "flat"), path) if err != nil { return err } files = append(files, relativePath) return nil }) if err != nil { return "", errors.Wrap(err, "failed to iterate over ") } cmdXar := exec.Command("xar", append([]string{"--compression", "none", "-cf", filepath.Join("..", outputFileName)}, files...)...) cmdXar.Dir = filepath.Join(tmpPath, "flat") cmdXar.Stdout = os.Stdout cmdXar.Stderr = os.Stderr err = cmdXar.Run() if err != nil { return "", errors.Wrap(err, "failed to run xar") } return outputFileName, nil }, requiredTools: map[string]map[string]string{ "linux": { "find": "Install find from your package manager", "cpio": "Install cpio from your package manager", "gzip": "Install gzip from your package manager", "mkbom": "Install bomutils from your package manager or from https://github.com/hogliux/bomutils", "xar": "Install xar from your package manager or from https://github.com/mackyle/xar", }, "darwin": { "find": "Install find from your package manager", "cpio": "Install cpio from your package manager", "gzip": "Install gzip from your package manager", "mkbom": "Install bomutils from your package manager or from https://github.com/hogliux/bomutils", "xar": "Install xar from your package manager or from https://github.com/mackyle/xar", }, }, }
DarwinPkgTask packaging for darwin as pkg
View Source
var LinuxAppImageTask = &packagingTask{ packagingFormatName: "linux-appimage", templateFiles: map[string]string{ "linux-appimage/AppRun.tmpl": "AppRun.tmpl", "linux/app.desktop.tmpl": "{{.packageName}}.desktop.tmpl", }, executableFiles: []string{ ".", "AppRun", "{{.packageName}}.desktop", }, linuxDesktopFileIconPath: "{{.packageName}}", flutterBuildOutputDirectory: "build", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { sourceIconPath := filepath.Join(tmpPath, "build", "assets", "icon.png") iconDir := filepath.Join(tmpPath, "usr", "share", "icons", "hicolor", "256x256", "apps") if _, err := os.Stat(iconDir); os.IsNotExist(err) { err = os.MkdirAll(iconDir, 0755) if err != nil { log.Errorf("Failed to create icon dir: %v", err) os.Exit(1) } } err := copy.Copy(sourceIconPath, filepath.Join(tmpPath, fmt.Sprintf("%s.png", packageName))) if err != nil { log.Errorf("Failed to copy icon root dir: %v", err) os.Exit(1) } err = copy.Copy(sourceIconPath, filepath.Join(iconDir, fmt.Sprintf("%s.png", packageName))) if err != nil { log.Errorf("Failed to copy icon dir: %v", err) os.Exit(1) } cmdAppImageTool := exec.Command("appimagetool", ".") cmdAppImageTool.Dir = tmpPath cmdAppImageTool.Stdout = os.Stdout cmdAppImageTool.Stderr = os.Stderr cmdAppImageTool.Env = append( os.Environ(), "ARCH=x86_64", fmt.Sprintf("VERSION=%s", version), ) err = cmdAppImageTool.Run() if err != nil { return "", err } return fmt.Sprintf("%s-%s-x86_64.AppImage", strings.ReplaceAll(applicationName, " ", "_"), version), nil }, requiredTools: map[string]map[string]string{ "linux": { "appimagetool": "Install appimagetool from your package manager or from https://github.com/AppImage/AppImageKit#appimagetool-usage", }, }, }
LinuxAppImageTask packaging for linux as AppImage
View Source
var LinuxDebTask = &packagingTask{ packagingFormatName: "linux-deb", templateFiles: map[string]string{ "linux-deb/control.tmpl": "DEBIAN/control.tmpl", "linux/bin.tmpl": "usr/bin/{{.executableName}}.tmpl", "linux/app.desktop.tmpl": "usr/share/applications/{{.executableName}}.desktop.tmpl", }, executableFiles: []string{ "usr/bin/{{.executableName}}", "usr/share/applications/{{.executableName}}.desktop", }, linuxDesktopFileExecutablePath: "/usr/lib/{{.packageName}}/{{.executableName}}", linuxDesktopFileIconPath: "/usr/lib/{{.packageName}}/assets/icon.png", flutterBuildOutputDirectory: "usr/lib/{{.packageName}}", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { outputFileName := fmt.Sprintf("%s_%s_amd64.deb", packageName, version) cmdDpkgDeb := exec.Command("dpkg-deb", "--build", ".", outputFileName) cmdDpkgDeb.Dir = tmpPath cmdDpkgDeb.Stdout = os.Stdout cmdDpkgDeb.Stderr = os.Stderr err := cmdDpkgDeb.Run() if err != nil { return "", err } return outputFileName, nil }, requiredTools: map[string]map[string]string{ "linux": { "dpkg-deb": "You need to be on Debian, Ubuntu or another distro that uses apt/dpkg as package manager to use this. Installing dpkg on other distros is hard and dangerous.", }, }, }
LinuxDebTask packaging for linux as deb
View Source
var LinuxPkgTask = &packagingTask{ packagingFormatName: "linux-pkg", templateFiles: map[string]string{ "linux-pkg/PKGBUILD.tmpl": "PKGBUILD.tmpl", "linux/bin.tmpl": "src/usr/bin/{{.executableName}}.tmpl", "linux/app.desktop.tmpl": "src/usr/share/applications/{{.executableName}}.desktop.tmpl", }, executableFiles: []string{ "src/usr/bin/{{.executableName}}", "src/usr/share/applications/{{.executableName}}.desktop", }, linuxDesktopFileExecutablePath: "/usr/lib/{{.packageName}}/{{.executableName}}", linuxDesktopFileIconPath: "/usr/lib/{{.packageName}}/assets/icon.png", flutterBuildOutputDirectory: "src/usr/lib/{{.packageName}}", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { extension := ".pkg.tar.xz" cmdMakepkg := exec.Command("makepkg") cmdMakepkg.Dir = tmpPath cmdMakepkg.Stdout = os.Stdout cmdMakepkg.Stderr = os.Stderr cmdMakepkg.Env = append(os.Environ(), fmt.Sprintf("PKGEXT=%s", extension)) err := cmdMakepkg.Run() if err != nil { return "", err } return fmt.Sprintf("%s-%s-%s-x86_64%s", packageName, version, release, extension), nil }, requiredTools: map[string]map[string]string{ "linux": { "makepkg": "You need to be on Arch Linux or another distro that uses pacman as package manager to use this. Installing makepkg on other distros is hard and dangerous.", }, }, }
LinuxPkgTask packaging for linux as pacman pkg
View Source
var LinuxRpmTask = &packagingTask{ packagingFormatName: "linux-rpm", templateFiles: map[string]string{ "linux-rpm/app.spec.tmpl": "SPECS/{{.packageName}}.spec.tmpl", "linux/bin.tmpl": "BUILDROOT/{{.packageName}}-{{.version}}-{{.release}}.x86_64/usr/bin/{{.executableName}}.tmpl", "linux/app.desktop.tmpl": "BUILDROOT/{{.packageName}}-{{.version}}-{{.release}}.x86_64/usr/share/applications/{{.executableName}}.desktop.tmpl", }, executableFiles: []string{ "BUILDROOT/{{.packageName}}-{{.version}}-{{.release}}.x86_64/usr/bin/{{.executableName}}", "BUILDROOT/{{.packageName}}-{{.version}}-{{.release}}.x86_64/usr/share/applications/{{.executableName}}.desktop", }, linuxDesktopFileExecutablePath: "/usr/lib/{{.packageName}}/{{.executableName}}", linuxDesktopFileIconPath: "/usr/lib/{{.packageName}}/assets/icon.png", flutterBuildOutputDirectory: "BUILD/{{.packageName}}-{{.version}}-{{.release}}.x86_64/usr/lib/{{.packageName}}", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { cmdRpmbuild := exec.Command("rpmbuild", "--define", fmt.Sprintf("_topdir %s", tmpPath), "--define", "_unpackaged_files_terminate_build 0", "-ba", fmt.Sprintf("./SPECS/%s.spec", packageName)) cmdRpmbuild.Dir = tmpPath cmdRpmbuild.Stdout = os.Stdout cmdRpmbuild.Stderr = os.Stderr err := cmdRpmbuild.Run() if err != nil { return "", err } return fmt.Sprintf("RPMS/x86_64/%s-%s-%s.x86_64.rpm", packageName, version, release), nil }, requiredTools: map[string]map[string]string{ "linux": { "rpmbuild": "You need to be on Red Hat Linux or another distro that uses rpm as package manager to use this. Installing rpmbuild on other distros is hard and dangerous.", }, }, }
LinuxRpmTask packaging for linux as rpm
View Source
var LinuxSnapTask = &packagingTask{ packagingFormatName: "linux-snap", templateFiles: map[string]string{ "linux-snap/snapcraft.yaml.tmpl": "snap/snapcraft.yaml.tmpl", "linux/app.desktop.tmpl": "snap/local/{{.executableName}}.desktop.tmpl", }, linuxDesktopFileExecutablePath: "/{{.executableName}}", linuxDesktopFileIconPath: "/icon.png", flutterBuildOutputDirectory: "build", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { cmdSnapcraft := exec.Command("snapcraft") cmdSnapcraft.Dir = tmpPath cmdSnapcraft.Stdout = os.Stdout cmdSnapcraft.Stderr = os.Stderr err := cmdSnapcraft.Run() if err != nil { return "", err } return fmt.Sprintf("%s_%s_amd64.snap", packageName, version), nil }, requiredTools: map[string]map[string]string{ "linux": { "snapcraft": "Install snapd from your package manager or from https://snapcraft.io/docs/installing-snapd", }, }, }
LinuxSnapTask packaging for linux as snap
View Source
var WindowsMsiTask = &packagingTask{ packagingFormatName: "windows-msi", templateFiles: map[string]string{ "windows-msi/app.wxs.tmpl": "{{.packageName}}.wxs.tmpl", }, flutterBuildOutputDirectory: "build", packagingFunction: func(tmpPath, applicationName, packageName, executableName, version, release string) (string, error) { outputFileName := fmt.Sprintf("%s %s.msi", applicationName, version) iconPngFile, err := os.Open(filepath.Join(tmpPath, "build", "assets", "icon.png")) if err != nil { return "", err } pngImage, err := png.Decode(iconPngFile) if err != nil { return "", err } err = iconPngFile.Close() if err != nil { return "", err } iconIcoFile, err := os.Create(filepath.Join(tmpPath, "build", "assets", "icon.ico")) if err != nil { return "", err } err = ico.Encode(iconIcoFile, pngImage) if err != nil { return "", err } err = iconIcoFile.Close() if err != nil { return "", err } switch runtime.GOOS { case "windows": cmdCandle := exec.Command("candle", fmt.Sprintf("%s.wxs", packageName)) cmdCandle.Dir = tmpPath cmdCandle.Stdout = os.Stdout cmdCandle.Stderr = os.Stderr err = cmdCandle.Run() if err != nil { return "", err } cmdLight := exec.Command("light", fmt.Sprintf("%s.wixobj", packageName), "-sval") cmdLight.Dir = tmpPath cmdLight.Stdout = os.Stdout cmdLight.Stderr = os.Stderr err = cmdLight.Run() if err != nil { return "", err } err = os.Rename(filepath.Join(tmpPath, fmt.Sprintf("%s.msi", packageName)), filepath.Join(tmpPath, outputFileName)) if err != nil { return "", err } case "linux": cmdWixl := exec.Command("wixl", "-v", fmt.Sprintf("%s.wxs", packageName), "-o", outputFileName) cmdWixl.Dir = tmpPath cmdWixl.Stdout = os.Stdout cmdWixl.Stderr = os.Stderr err = cmdWixl.Run() if err != nil { return "", err } default: panic("should be unreachable") } return outputFileName, nil }, requiredTools: map[string]map[string]string{ "windows": { "candle": "Install the WiX Toolset from https://wixtoolset.org/releases/", }, "linux": { "wixl": "Install msitools from your package manager or from https://wiki.gnome.org/msitools/", }, }, generateInitFiles: func(packageName, path string) { err := ioutil.WriteFile( filepath.Join(path, "upgrade-code.txt"), []byte(fmt.Sprintf("%s\n# This GUID is your upgrade code and ensures that you can properly update your app.\n# Don't change it.", uuid.New())), 0755, ) if err != nil { log.Errorf("Failed to create `upgrade-code.txt` file: %v", err) os.Exit(1) } }, extraTemplateData: func(packageName, path string) map[string]string { data, err := ioutil.ReadFile(filepath.Join(path, "upgrade-code.txt")) if err != nil { log.Errorf("Failed to read `go/packaging/windows-msi/upgrade-code.txt`: %v", err) if os.IsNotExist(err) { log.Errorf("Please re-init windows-msi to generate the `go/packaging/windows-msi/upgrade-code.txt`") log.Errorf("or put a GUID from https://www.guidgen.com/ into a new `go/packaging/windows-msi/upgrade-code.txt` file.") } os.Exit(1) } guid := strings.Split(string(data), "\n")[0] return map[string]string{ "upgradeCode": guid, "pathSeparator": string(os.PathSeparator), } }, generateBuildFiles: func(packageName, tmpPath string) { 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", packageName, err) os.Exit(1) } directoriesFile, err := os.Create(directoriesFilePath) if err != nil { log.Errorf("Failed to create directories.wxi file %s: %v", packageName, 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", packageName, err) os.Exit(1) } directoryRefsFile, err := os.Create(directoryRefsFilePath) if err != nil { log.Errorf("Failed to create directory_refs.wxi file %s: %v", packageName, 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", packageName, err) os.Exit(1) } componentRefsFile, err := os.Create(componentRefsFilePath) if err != nil { log.Errorf("Failed to create component_refs.wxi file %s: %v", packageName, err) os.Exit(1) } directoriesFileContent = append(directoriesFileContent, "<Include>") directoryRefsFileContent = append(directoryRefsFileContent, "<Include>") componentRefsFileContent = append(componentRefsFileContent, "<Include>") windowsMsiProcessFiles(filepath.Join(tmpPath, "build")) directoriesFileContent = append(directoriesFileContent, "</Include>") directoryRefsFileContent = append(directoryRefsFileContent, "</Include>") componentRefsFileContent = append(componentRefsFileContent, "</Include>") for _, line := range directoriesFileContent { if _, err := directoriesFile.WriteString(line + "\n"); err != nil { log.Errorf("Could not write directories.wxi: %v", packageName, err) os.Exit(1) } } err = directoriesFile.Close() if err != nil { log.Errorf("Could not close directories.wxi: %v", packageName, 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", packageName, err) os.Exit(1) } } err = directoryRefsFile.Close() if err != nil { log.Errorf("Could not close directory_refs.wxi: %v", packageName, 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", packageName, err) os.Exit(1) } } err = componentRefsFile.Close() if err != nil { log.Errorf("Could not close component_refs.wxi: %v", packageName, err) os.Exit(1) } }, }
WindowsMsiTask packaging for windows as msi
Functions ¶
This section is empty.
Types ¶
type Task ¶
type Task interface { Name() string Init() IsInitialized() bool AssertInitialized() Pack(buildVersion string, mode build.Mode) IsSupported() bool AssertSupported() }
Task contains all configuration options for a given packaging method. TODO: Rename to something that suits it more? Mabe Executor?
var NoopTask Task = &noopTask{}
Click to show internal directories.
Click to hide internal directories.