Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build a gallium tool to build and bundle projects #15

Open
ernesto-jimenez opened this issue Sep 28, 2016 · 6 comments
Open

Build a gallium tool to build and bundle projects #15

ernesto-jimenez opened this issue Sep 28, 2016 · 6 comments

Comments

@ernesto-jimenez
Copy link
Contributor

ernesto-jimenez commented Sep 28, 2016

The project has a couple of important requirements:

  1. Running runtime.LockOSThread and gallium.Loop on the main function
  2. Bundling the binary for certain features to work. e.g: the menu example only works when run from a bundle.

Instead of having people create their own main files, it might be helpful to have a CLI to manage both compilation and bundling.

The UX would be something like this:

github.com/alexflint/gallium/examples/menu/menu.go

package menu

import (
    "os"

    "github.com/alexflint/gallium"
)

type app struct {}

func New() gallium.Starter {
    return &app{}
}

func (*app) Start(app *gallium.App) {
    app.SetMenu([]gallium.Menu{
        {
            Title: "menudemo",
            Entries: []gallium.MenuEntry{
                gallium.MenuItem{
                    Title:    "Quit",
                    Shortcut: "cmd+q",
                    OnClick:  func() { os.Exit(0) },
                },
            },
        }
    })
}

Building the application

$ gallium build github.com/alexflint/gallium/examples/menu

As part of the build, it will create a temporary main package with a main.go file from a template similar to this:

// AUTOGENERATED CODE
// NEVER EDIT MANUALLY
package main

import (
    "runtime"

    "github.com/alexflint/gallium"
    p "{{ .TargetPackage }}"
)

func main() {
    runtime.LockOSThread()
    app := p.New()
    gallium.Loop(os.Args, app.Start())
}

Once generated, it will build the binary and bundle it and produce a ready menu.app.

Beyond not having to deal with thread locking and initialising the loop, we can check whether the returned satisfies other gallium interfaces to build more elaborate main files.

  • DefaultMenus() []gallium.Menu returning the default menu for the app
  • Config() gallium.Config could return information used to setup your app or your bundle. Would probably have some information like the one contained in cordova's (phonegap) config.xml.

The CLI could also evolve to offer other features:

$ gallium new           # creates a default app ready to be used with `gallium build`
$ gallium generate menu # generates all the boilerplate to return a new menu
$ gallium sign Menu.app # signs Menu.app for distribution

It should also have a command to generate all the Go code needed to build and bundle the app with within the same repo. Everything that would be required to build the app without the cli, so it can be committed to the repo.

@alexflint
Copy link
Owner

I like this proposal a lot. I think a unified gallium tool makes a lot of sense, and I think over time we will have a number of different gallium-specific tasks as you point out, and I agree it will be much better to have a unified tool with a unified interface rather than a collection of different tools. I'm not 100% convinced about code generation, though. I worry that if we encourage users to check the generated code into their vcs then it will be difficult to make API changes since we'll have to somehow update generated code to talk to the new APIs, and I worry that if we encourage users not to check the generated code into their vcs then external tools, like ssa and so forth won't work.

I wonder if the solution is to just have what you described as gallium new - ie a boilerplate generator - and then let users modify and manage the code on their own from there. There could be gallium new --menus to generate boilerplate with a menu system, gallium new --statusbar to generate boilerplate with a status bar icon, and so forth. Users who wanted to structure their code in a different way could then simply work from the docs and write everything themselves.

Thanks for writing this up! Are you thinking of working on this?

@ernesto-jimenez
Copy link
Contributor Author

@alexflint great!

I'm definitely up for working on this :)

I'm not 100% convinced about code generation, though. I worry that if we encourage users to check the generated code into their vcs then it will be difficult to make API changes since we'll have to somehow update generated code to talk to the new APIs,

Checking-in generated code would actually be better for API changes than asking users to code the main package themselves.

We would generate the code with a big comment saying they must never edit it by hand.

The idea is to allow them to build and bundle the app regardless of whether they have the gallium app installed or with version they have installed. If they wanted to upgrade gallium, they would need to re-generate the code.

and I worry that if we encourage users not to check the generated code into their vcs then external tools, like ssa and so forth won't work.

My worry about keeping the generated code outside of the repo is reproducible builds. I would like somebody to checkout my gallium-based app and be able to build it regardless of whether they have the gallium app installed.

I wonder if the solution is to just have what you described as gallium new - ie a boilerplate generator - and then let users modify and manage the code on their own from there. There could be gallium new --menus to generate boilerplate with a menu system, gallium new --statusbar to generate boilerplate with a status bar icon, and so forth.

There's two different things here in my opinion:

  • bootstrapping an app from a template (similar to Rails Application Templates: rails new blog -m http://example.com/template.rb)
  • generating boilerplate code (similar to cobra add and rails generate)

Users who wanted to structure their code in a different way could then simply work from the docs and write everything themselves.

That would always be a possibility, yes.

@joeblew99
Copy link

i disagree here.

I feel that codegen is for much later, and there is little point doing it until the actual code is working.
First get the code working, where you write code against the common API.

Then if you do want to do codegen, dont reinvent the wheel. Use goa.
https://github.com/goadesign/goa
Its a proper DSL driven Code Generator.
I have to say though for menus and other stuff, its just easier to write some code against an API.

@ernesto-jimenez
Copy link
Contributor Author

@joeblew99 generating the main automatically would actually help while working out the APIs, since we can regenerate the templated main as gallium evolves instead of having people amend the main they wrote manually when they have to upgrade.

When talking about codegen here I'm referring to templated code, rather than DSLs. You would write code against an API rather than a DSL.

Regarding goa. It has a very different scope, since it is a DSL for microservices. I'm talking about something different here.

@joeblew99
Copy link

@ernesto-jimenez thanks for the answer.

so can you point me to an example of where we DO or WOULD gen the main ?. I think i generalised in my answer, and now i want to see the exact context. Curious :)

@joeblew99
Copy link

thanks @ernesto-jimenez

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants