miketheprogrammer / go-thrust

Cross Platform UI Kit powered by Blink/V8/Chromium Content Lib
MIT License
445 stars 34 forks source link

Single binary distribution concept #60

Closed everclear closed 8 years ago

everclear commented 8 years ago

Hi Mike,

Firstly, congrats on a creating a great package.

I seen a couple of mentions about bundling thrust with the go executable within the closed issues.

I've created a proof of concept on Linux, which should be easy to replicate on Windows.

Basically, you append the thrust zip to the go binary, then adjust the offset.

go build basic_webserver_app.go
cat thrust-v0.7.6-linux-x64.zip >> basic_webserver_app
zip -A basic_webserver_app

In helper_linux.go i've imported github.com/kardianos/osext to get the path of the running exe, then simply unzipped that.

func prepareExecutable() error {
    exe, err := osext.Executable()
    if err != nil {
        return err
    }
        // if exe contains archive
           return unzip(exe, GetThrustDirectory())
        // else
              // downloadFromUrl()
}

I think this concept maybe a good idea to implementing properly, but I appreciated that there would be a few issues to consider first. Let me know your views.

miketheprogrammer commented 8 years ago

Awesome concept, unfortunately my ability to type and code is severely hindered by an injury. If you would like to submit a PR that works, and examples, i would love to merge it.

tehbilly commented 8 years ago

Oh no, @miketheprogrammer! Did you try not getting hurt? :D

@everclear I've bundled assets like this with go applications before, simply to have a purely standalone application in a single file. It's a pretty big hassle on Windows, though. The biggest drawback I really see to it is that you can't go run the application without additional checking (or build constraints).

What I ended up doing with my application internally was defaulting to the XDG Base Directory spec, with no special case for Windows.

So, in pseudo-code (as I'm totally being naughty and githubbing from work):

assetDir := filepath.Join(xdg.CacheDir(), "go-thrust")

if !dirExists(assetDir) {
  // Make directory
  // Download release
  // Validate, extract, carry on
} else if !fileExists(filepath.Join(assetDir, "thrust", "thrust_shell") {
  // Zip file there? Looks like the version we want? Extract it and carry on
  // No zip file? Bah! Download release, extract, carry on
} else {
  // If you're super paranoid you can do some checking here
  // Or maybe check for a newer release in the background while... carrying on
}

Since the thrust shell is essentially a runtime component that's decoupled from your app, there's really no harm in having that as part of the first run logic. Or on-startup checks. Etc. Github for Desktop, Chrome, a lot of applications work this way nowadays. This also provides the ability to test across different releases without creating a new build for each, either by setting the XDG environment variables, or using version flags. Whatevs.

Thoughts? Personally, I like having a small app that's all mine. And releasing updates regularly. If you mash all the bits and bytes together you're going to have to download the entire thrust runtime to get updates to your application, even when thrust itself has nothing new.

ghost commented 8 years ago

@everclear's solution also work in Windows.

miketheprogrammer commented 8 years ago

Let's look into it then. Can someone submit a pr

@everclear https://github.com/everclear's solution also work in Windows.

— Reply to this email directly or view it on GitHub https://github.com/miketheprogrammer/go-thrust/issues/60#issuecomment-148985183 .

rrohrer commented 8 years ago

It would be awesome to have this built in. I essentially did that with go-bindata in my app:

func extractAssets(provisioner *appProvisioner) error {
    assetList := provisioner.AssetList()
    for i := range assetList {

        // root is the install root that the assets get unpacked to.
        var root string

        // assetName is the name of the asset bound by go-bindata.
        assetName := assetList[i]

        // check whether its going to the binary dir for thrust or general asset
        // directory.
        if strings.Contains(assetName, "thrust/") {
            root = provisioner.ThrustBinDir
            assetName = strings.Replace(assetName, "thrust/", "", 1)
        } else {
            root = provisioner.AssetRoot
        }

        outputFileName := filepath.Join(root, assetName)

        // decompress the asset into memory
        asset, err := provisioner.GetAsset(assetList[i])
        if nil != err {
            return err
        }

        // make sure the folder is created.
        outputPath, _ := filepath.Split(outputFileName)
        err = os.MkdirAll(outputPath, os.ModeDir)
        if nil != err {
            return err
        }

        // write the asset out.
        err = ioutil.WriteFile(outputFileName, asset, os.ModePerm)
        if nil != err {
            return err
        }
    }
    return nil
}
tooolbox commented 8 years ago

Any closer on this? :D

rrohrer commented 8 years ago

AFIAK Thrust is halted until further notice. :'(

I made something similar using electron that I have go bindings for. https://github.com/rrohrer/electroncontrol and https://github.com/rrohrer/go-electroncontrol.

It's not as complete as Thrust, but it works with the default build of electron + it's at least robust enough to ship the app that my company made with it. (basic desktop app doing nothing too fancy).

There are currently some Windows specific hacks in go-electronshell but it's actually easier to do it the 'right' cross-platform way. Windows just... isn't the best.

miketheprogrammer commented 8 years ago

I have just gotten back into golang at work. I am too injured to work on this at home but will try to work some cycles in at work On Feb 7, 2016 4:42 AM, "Ryan Rohrer" notifications@github.com wrote:

AFIAK Thrust is halted until further notice. :'(

I made something similar using electron that I have go bindings for. https://github.com/rrohrer/electronshell and https://github.com/rrohrer/go-electronshell.

It's not as complete as Thrust, but it works with the default build of electron + it's at least robust enough to ship the app that my company made with it. (basic desktop app doing nothing too fancy).

There are currently some Windows specific hacks in go-electronshell but it's actually easier to do it the 'right' cross-platform way. Windows just... isn't the best.

— Reply to this email directly or view it on GitHub https://github.com/miketheprogrammer/go-thrust/issues/60#issuecomment-180984155 .

rrohrer commented 8 years ago

Awesome!

miketheprogrammer commented 8 years ago

omg ... i freakin did it. after a year away from GoLang. I did the go-bindata you suggested. It was incredibly easy.

type SingleBinaryThrustProvisioner struct{}

/*
NewSingleBinaryThrustProvisioner instantiates an SingleBinaryThrustProvisioner
*/
//go:generate go-bindata -pkg $GOPACKAGE -o vendor.go vendor/
func NewSingleBinaryThrustProvisioner() SingleBinaryThrustProvisioner {
    return SingleBinaryThrustProvisioner{}
}

/*
Provisions a thrust environment based on settings.
*/
func (sbtp SingleBinaryThrustProvisioner) Provision() error {
    err := sbtp.extractToPath(base+"/$V", thrustVersion)
    if err != nil {
        return err
    }
    return Bootstrap()
}

func (sbtp SingleBinaryThrustProvisioner) extractToPath(filepath, version string) error {
    fileName := strings.Replace(filepath, "$V", version, 1)
    data, err := Asset("vendor/thrust-v0.7.6-darwin-x64.zip")
    if err != nil {
        fmt.Println("Error accessing thrust bindata")
        return err
    }
    fmt.Println("No error accessing thrust bindata")
    fmt.Println("Writing to", fileName)
    err = ioutil.WriteFile(fileName, data, os.ModePerm)
    if nil != err {
        return err
    }
    return unzipExecutable(fileName)
}
miketheprogrammer commented 8 years ago

I will test later and publish soon

tooolbox commented 8 years ago

Looks promising!! :D

miketheprogrammer commented 8 years ago

Resolved #67