packaging

package
v0.1042.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2020 License: BSD-3-Clause Imports: 22 Imported by: 0

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
		}
		cmdPng2icns := exec.Command("png2icns", filepath.Join(outputFileName, "Contents", "Resources", "icon.icns"), filepath.Join(outputFileName, "Contents", "MacOS", "assets", "icon.png"))
		cmdPng2icns.Dir = tmpPath
		cmdPng2icns.Stdout = os.Stdout
		cmdPng2icns.Stderr = os.Stderr
		err = cmdPng2icns.Run()
		if err != nil {
			return "", err
		}
		return outputFileName, nil
	},
	requiredTools: map[string][]string{
		"linux": {"png2icns"},
	},
}

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
		}
		cmdGenisoimage := exec.Command("genisoimage", "-V", packageName, "-D", "-R", "-apple", "-no-pad", "-o", outputFileName, "dmgdir")
		cmdGenisoimage.Dir = tmpPath
		cmdGenisoimage.Stdout = os.Stdout
		cmdGenisoimage.Stderr = os.Stderr
		err = cmdGenisoimage.Run()
		if err != nil {
			return "", err
		}
		return outputFileName, nil
	},
	skipAssertInitialized: true,
	requiredTools: map[string][]string{
		"linux": {"ln", "genisoimage"},
	},
}

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
		}

		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][]string{
		"linux": {"find", "cpio", "gzip", "mkbom", "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][]string{
		"linux": {"appimagetool"},
	},
}

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][]string{
		"linux": {"dpkg-deb"},
	},
}

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) {
		cmdMakepkg := exec.Command("makepkg")
		cmdMakepkg.Dir = tmpPath
		cmdMakepkg.Stdout = os.Stdout
		cmdMakepkg.Stderr = os.Stderr
		err := cmdMakepkg.Run()
		if err != nil {
			return "", err
		}
		return fmt.Sprintf("%s-%s-%s-x86_64.pkg.tar.xz", packageName, version, release), nil
	},
	requiredTools: map[string][]string{
		"linux": {"makepkg"},
	},
}

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][]string{
		"linux": {"rpmbuild"},
	},
}

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][]string{
		"linux": {"snapcraft"},
	},
}

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][]string{
		"windows": {"candle", "light"},
		"linux":   {"wixl"},
	},
	generateInitFiles: func(packageName, path string) {
		b := make([]byte, 16)
		_, err := rand.Read(b)
		if err != nil {
			log.Errorf("Failed to generate GUID: %v", err)
			os.Exit(1)
		}
		upgradeCode := strings.ToUpper(fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]))
		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.", upgradeCode)), 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", "flutter_assets"))
		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)
	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{}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL