Skip to content

Commit

Permalink
Merge pull request #3 from lucor/feature/release
Browse files Browse the repository at this point in the history
Adds support for "fyne release"
  • Loading branch information
lucor committed Dec 2, 2020
2 parents e3c1710 + f7bf51c commit b66faed
Show file tree
Hide file tree
Showing 14 changed files with 488 additions and 86 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog - Fyne.io fyne-cross

## Unreleased
- Add support for "fyne release" #3
- Add support for creating packaged .tar.gz bundles on freebsd #6
- Update fyne cli to v1.4.2-0.20201125075943-97ad77d2abe0 (fyne-io#1538 fyne-io#1527)

## [0.9.0]
- Releaseing under project namespace with previous 2.2.1 becoming 0.9.0 in fyne-io namespace

Expand Down
5 changes: 4 additions & 1 deletion README.md
Expand Up @@ -19,7 +19,10 @@ Supported targets are:
- android
- ios

> Note: iOS compilation is supported only on darwin hosts. See [fyne README mobile](https://github.com/fyne-io/fyne/blob/v1.2.4/README-mobile.md#ios) for pre-requisites.
> Note:
> - iOS compilation is supported only on darwin hosts. See [fyne pre-requisites](https://developer.fyne.io/started/#prerequisites) for details.
> - macOS packaging for public distrubution (release mode) is supported only on darwin hosts.
> - windows packaging for public distrubution (release mode) is supported only on windows hosts.
## Requirements

Expand Down
12 changes: 12 additions & 0 deletions docker/CHANGELOG.md
Expand Up @@ -5,6 +5,18 @@ All notable changes to the fyne-cross docker images will be documented in this f
Release cycle won't follow the fyne-cross one, so the images will be tagged using the label
year.month.day along with the latest one.

# Release 20.11.28
- Update fyne cli to v1.4.2-0.20201127180716-f9f91c194737 fyne-io#1609

# Release 20.11.25
- Update fyne cli to v1.4.2-0.20201125075943-97ad77d2abe0 fyne-io#1538

# Release 20.11.23
- Update fyne cli to v1.4.2-0.20201122132119-67b762f56dc0 fyne-io#1527

# Release 20.11.04
- fyne cli updated to v1.4.0

# Archive

These releases occurred in the original namspace, lucor/fyne-cross
Expand Down
2 changes: 1 addition & 1 deletion docker/base/Dockerfile
@@ -1,7 +1,7 @@
# docker cross 1.13.15
ARG DOCKER_CROSS_VERSION=sha256:11a04661d910f74c419623ef7880024694f9151c17578af15e86c45cdf6c8588
# fyne stable branch
ARG FYNE_VERSION=v1.3.3
ARG FYNE_VERSION=f9f91c1947370189c73384fb12ee799b1cf68638

# Build the fyne command utility
FROM dockercore/golang-cross@${DOCKER_CROSS_VERSION} AS fyne
Expand Down
36 changes: 34 additions & 2 deletions internal/command/android.go
Expand Up @@ -42,6 +42,10 @@ func (cmd *Android) Parse(args []string) error {
CommonFlags: commonFlags,
}

flagSet.StringVar(&flags.Keystore, "keystore", "", "The location of .keystore file containing signing information")
flagSet.StringVar(&flags.KeystorePass, "keystore-pass", "", "Password for the .keystore file")
flagSet.StringVar(&flags.KeyPass, "key-pass", "", "Password for the signer's private key, which is needed if the private key is password-protected")

flagSet.Usage = cmd.Usage
flagSet.Parse(args)

Expand Down Expand Up @@ -95,13 +99,33 @@ func (cmd *Android) Run() error {
return err
}

err = fynePackage(ctx)
if ctx.Release {
err = fyneRelease(ctx)
} else {
err = fynePackage(ctx)
}
if err != nil {
return fmt.Errorf("could not package the Fyne app: %v", err)
}

// move the dist package into the "dist" folder
srcFile := volume.JoinPathHost(ctx.WorkDirHost(), ctx.Package, packageName)
// The fyne tool sanitizes the package name to be acceptable as a
// android package name. For details, see:
// https://github.com/fyne-io/fyne/blob/v1.4.0/cmd/fyne/internal/mobile/build_androidapp.go#L297
// To avoid to duplicate the fyne tool sanitize logic here, the location of
// the dist package to move will be detected using a matching pattern
apkFilePattern := volume.JoinPathHost(ctx.WorkDirHost(), ctx.Package, "*.apk")
apks, err := filepath.Glob(apkFilePattern)
if err != nil {
return fmt.Errorf("could not find any apk file matching %q: %v", apkFilePattern, err)
}
if apks == nil {
return fmt.Errorf("could not find any apk file matching %q", apkFilePattern)
}
if len(apks) > 1 {
return fmt.Errorf("multiple apk files matching %q: %v. Please remove and build again", apkFilePattern, apks)
}
srcFile := apks[0]
distFile := volume.JoinPathHost(ctx.DistDirHost(), ctx.ID, packageName)
err = os.MkdirAll(filepath.Dir(distFile), 0755)
if err != nil {
Expand Down Expand Up @@ -142,6 +166,10 @@ Options:
// androidFlags defines the command-line flags for the android command
type androidFlags struct {
*CommonFlags

Keystore string //Keystore represents the location of .keystore file containing signing information
KeystorePass string //Password for the .keystore file
KeyPass string //Password for the signer's private key, which is needed if the private key is password-protected
}

// makeAndroidContext returns the command context for an android target
Expand All @@ -159,6 +187,10 @@ func makeAndroidContext(flags *androidFlags, args []string) (Context, error) {
ctx.OS = androidOS
ctx.ID = androidOS

ctx.Keystore = flags.Keystore
ctx.KeystorePass = flags.KeystorePass
ctx.KeyPass = flags.KeyPass

// set context based on command-line flags
if flags.DockerImage == "" {
ctx.DockerImage = androidImage
Expand Down
116 changes: 116 additions & 0 deletions internal/command/command.go
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"

"github.com/fyne-io/fyne-cross/internal/icon"
"github.com/fyne-io/fyne-cross/internal/log"
Expand Down Expand Up @@ -102,3 +104,117 @@ func prepareIcon(ctx Context) error {
func printUsage(template string, data interface{}) {
log.PrintTemplate(os.Stderr, template, data)
}

// checkFyneBinHost checks if the fyne cli tool is installed on the host
func checkFyneBinHost(ctx Context) (string, error) {
fyne, err := exec.LookPath("fyne")
if err != nil {
return "", fmt.Errorf("missed requirement: fyne. To install: `go get fyne.io/fyne/cmd/fyne` and add $GOPATH/bin to $PATH")
}

if ctx.Debug {
out, err := exec.Command(fyne, "version").Output()
if err != nil {
return fyne, fmt.Errorf("could not get fyne cli %s version: %v", fyne, err)
}
log.Debugf("%s", out)
}

return fyne, nil
}

// fynePackageHost package the application using the fyne cli tool from the host
// Note: at the moment this is used only for the ios builds
func fynePackageHost(ctx Context) error {

fyne, err := checkFyneBinHost(ctx)
if err != nil {
return err
}

args := []string{
"package",
"-os", ctx.OS,
"-name", ctx.Output,
"-icon", volume.JoinPathContainer(ctx.TmpDirHost(), ctx.ID, icon.Default),
"-appID", ctx.AppID,
"-appBuild", ctx.AppBuild,
"-appVersion", ctx.AppVersion,
}

// add tags to command, if any
tags := ctx.Tags
if len(tags) > 0 {
args = append(args, "-tags", fmt.Sprintf("'%s'", strings.Join(tags, ",")))
}

// run the command from the host
fyneCmd := exec.Command(fyne, args...)
fyneCmd.Dir = ctx.WorkDirHost()
fyneCmd.Stdout = os.Stdout
fyneCmd.Stderr = os.Stderr

if ctx.Debug {
log.Debug(fyneCmd)
}

err = fyneCmd.Run()
if err != nil {
return fmt.Errorf("could not package the Fyne app: %v", err)
}
return nil
}

// fyneReleaseHost package and release the application using the fyne cli tool from the host
// Note: at the moment this is used only for the ios and windows builds
func fyneReleaseHost(ctx Context) error {

fyne, err := checkFyneBinHost(ctx)
if err != nil {
return err
}

args := []string{
"release",
"-os", ctx.OS,
"-name", ctx.Output,
"-icon", volume.JoinPathContainer(ctx.TmpDirHost(), ctx.ID, icon.Default),
"-appID", ctx.AppID,
"-appBuild", ctx.AppBuild,
"-appVersion", ctx.AppVersion,
}

// add tags to command, if any
tags := ctx.Tags
if len(tags) > 0 {
args = append(args, "-tags", fmt.Sprintf("'%s'", strings.Join(tags, ",")))
}

switch ctx.OS {
case darwinOS:
args = append(args, "-category", ctx.Category)
case iosOS:
args = append(args, "-certificate", ctx.Certificate)
args = append(args, "-profile", ctx.Profile)
case windowsOS:
args = append(args, "-certificate", ctx.Certificate)
args = append(args, "-developer", ctx.Developer)
args = append(args, "-password", ctx.Password)
}

// run the command from the host
fyneCmd := exec.Command(fyne, args...)
fyneCmd.Dir = ctx.WorkDirHost()
fyneCmd.Stdout = os.Stdout
fyneCmd.Stderr = os.Stderr

if ctx.Debug {
log.Debug(fyneCmd)
}

err = fyneCmd.Run()
if err != nil {
return fmt.Errorf("could not package the Fyne app: %v", err)
}
return nil
}
23 changes: 23 additions & 0 deletions internal/command/context.go
Expand Up @@ -2,9 +2,11 @@ package command

import (
"bytes"
"errors"
"fmt"
"path/filepath"
"runtime"
"strconv"
"strings"

"github.com/fyne-io/fyne-cross/internal/log"
Expand Down Expand Up @@ -41,15 +43,28 @@ type Context struct {
OS string // OS defines the target OS
Tags []string // Tags defines the tags to use

AppBuild string // Build number
AppID string // AppID is the appID to use for distribution
AppVersion string // AppVersion is the version number in the form x, x.y or x.y.z semantic version
CacheEnabled bool // CacheEnabled if true enable go build cache
DockerImage string // DockerImage defines the docker image used to build
Icon string // Icon is the optional icon in png format to use for distribution
Output string // Output is the name output
Package string // Package is the package to build named by the import path as per 'go build'
Release bool // Enable release mode. If true, prepares an application for public distribution
StripDebug bool // StripDebug if true, strips binary output
Debug bool // Debug if true enable debug log
Pull bool // Pull if true attempts to pull a newer version of the docker image

// Release context
Category string //Category represents the category of the app for store listing [macOS]
Certificate string //Certificate represents the name of the certificate to sign the build [iOS, Windows]
Developer string //Developer represents the developer identity for your Microsoft store account [Windows]
Keystore string //Keystore represents the location of .keystore file containing signing information [Android]
KeystorePass string //KeystorePass represents the password for the .keystore file [Android]
KeyPass string //KeyPass represents the assword for the signer's private key, which is needed if the private key is password-protected [Android]
Password string //Password represents the password for the certificate used to sign the build [Windows]
Profile string //Profile represents the name of the provisioning profile for this release build [iOS]
}

// String implements the Stringer interface
Expand All @@ -76,6 +91,7 @@ func makeDefaultContext(flags *CommonFlags, args []string) (Context, error) {
// set context based on command-line flags
ctx := Context{
AppID: flags.AppID,
AppVersion: flags.AppVersion,
CacheEnabled: !flags.NoCache,
DockerImage: flags.DockerImage,
Env: flags.Env,
Expand All @@ -86,8 +102,15 @@ func makeDefaultContext(flags *CommonFlags, args []string) (Context, error) {
Debug: flags.Debug,
Volume: vol,
Pull: flags.Pull,
Release: flags.Release,
}

if flags.AppBuild <= 0 {
return ctx, errors.New("build number should be greater than 0")
}

ctx.AppBuild = strconv.Itoa(flags.AppBuild)

ctx.Package, err = packageFromArgs(args, vol)
if err != nil {
return ctx, err
Expand Down

0 comments on commit b66faed

Please sign in to comment.