-
-
Notifications
You must be signed in to change notification settings - Fork 181
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
Experimental compiler refactor #133
Changes from all commits
3f17926
6f1228b
63ca7c3
bfa0057
51ba9b4
c9bb8eb
49fe21d
17eb829
052c67f
eadc9ba
2c58e0c
0fe7501
7d0effc
2bdcd81
ea60e27
07ffda0
af7df88
a67a2ab
c891eed
b961507
0fa3d8d
a6fbe32
38e7afc
6817a12
e91d392
7f327e5
c123ddb
4c4b459
84c6a24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,7 +50,7 @@ example.hn.watch: | |
# Go | ||
## | ||
|
||
GO_SOURCE := ./internal/... ./package/... ./runtime/... | ||
GO_SOURCE := ./internal/... ./package/... ./framework/... | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to combine |
||
|
||
go.tools: | ||
@ go install \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package app | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. app is the new entrypoint into the program. In the previous bud, there was a generated |
||
import ( | ||
"context" | ||
_ "embed" | ||
|
||
"github.com/livebud/bud/framework" | ||
"github.com/livebud/bud/package/di" | ||
"github.com/livebud/bud/package/overlay" | ||
|
||
"github.com/livebud/bud/internal/gotemplate" | ||
"github.com/livebud/bud/package/gomod" | ||
) | ||
|
||
//go:embed app.gotext | ||
var template string | ||
|
||
var generator = gotemplate.MustParse("framework/app/app.gotext", template) | ||
|
||
func Generate(state *State) ([]byte, error) { | ||
return generator.Generate(state) | ||
} | ||
|
||
func New(injector *di.Injector, module *gomod.Module, flag *framework.Flag) *Generator { | ||
return &Generator{flag, injector, module} | ||
} | ||
|
||
type Generator struct { | ||
flag *framework.Flag | ||
injector *di.Injector | ||
module *gomod.Module | ||
} | ||
|
||
func (g *Generator) GenerateFile(ctx context.Context, fsys overlay.F, file *overlay.File) error { | ||
state, err := Load(fsys, g.injector, g.module, g.flag) | ||
if err != nil { | ||
return err | ||
} | ||
code, err := Generate(state) | ||
if err != nil { | ||
return err | ||
} | ||
file.Data = code | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package main | ||
|
||
{{- if $.Imports }} | ||
|
||
import ( | ||
{{- range $import := $.Imports }} | ||
{{$import.Name}} "{{$import.Path}}" | ||
{{- end }} | ||
) | ||
{{- end }} | ||
|
||
func main() { | ||
os.Exit(run(context.Background(), os.Args[1:]...)) | ||
} | ||
|
||
// Run the cli | ||
func run(ctx context.Context, args ...string) int { | ||
if err := parse(ctx, args...); err != nil { | ||
if errors.Is(err, context.Canceled) { | ||
return 0 | ||
} | ||
console.Error(err.Error()) | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
|
||
// Parse the arguments | ||
func parse(ctx context.Context, args ...string) error { | ||
cli := commander.New("bud") | ||
app := new(App) | ||
cli.Flag("listen", "address to listen to").String(&app.Listen).Default(":3000") | ||
cli.Flag("log", "filter logs with a pattern").Short('L').String(&app.Log).Default("info") | ||
cli.Run(app.Run) | ||
return cli.Parse(ctx, args) | ||
} | ||
|
||
// App command | ||
type App struct { | ||
Listen string | ||
Log string | ||
} | ||
|
||
// logger creates a structured log that supports filtering | ||
func (a *App) logger() (log.Interface, error) { | ||
handler, err := filter.Load(console.New(os.Stderr), a.Log) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return log.New(handler), nil | ||
} | ||
|
||
// Run your app | ||
func (a *App) Run(ctx context.Context) error { | ||
log, err := a.logger() | ||
if err != nil { | ||
return err | ||
} | ||
budClient, err := budclient.Try(os.Getenv("BUD_LISTEN")) | ||
if err != nil { | ||
return err | ||
} | ||
{{- if $.Provider.Variable "github.com/livebud/bud/package/gomod.*Module" }} | ||
// Load the module dependency | ||
module, err := gomod.Find(".") | ||
if err != nil { | ||
return err | ||
} | ||
{{- end }} | ||
// Load the web server | ||
webServer, err := loadWeb( | ||
{{/* Order matters. Ordered by package name */}} | ||
{{- if $.Provider.Variable "context.Context" }}ctx,{{ end }} | ||
{{- if $.Provider.Variable "github.com/livebud/bud/package/budclient.Client" }}budClient,{{ end }} | ||
{{- if $.Provider.Variable "github.com/livebud/bud/package/gomod.*Module" }}module,{{ end }} | ||
{{- if $.Provider.Variable "github.com/livebud/bud/package/log.Interface" }}log,{{ end }} | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
// Inform bud that we're ready | ||
budClient.Publish("app:ready", nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The bud client talks to the server during |
||
// Start serving requests | ||
log.Debug("app: listening on", "listen", a.Listen) | ||
return webServer.Serve(ctx, a.Listen) | ||
} | ||
|
||
{{ $.Provider.Function }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package app_test | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/livebud/bud/internal/cli/testcli" | ||
"github.com/livebud/bud/internal/is" | ||
"github.com/livebud/bud/internal/testdir" | ||
) | ||
|
||
func TestWelcome(t *testing.T) { | ||
is := is.New(t) | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
dir := t.TempDir() | ||
td := testdir.New(dir) | ||
is.NoErr(td.Write(ctx)) | ||
cli := testcli.New(dir) | ||
is.NoErr(td.NotExists("bud/app")) | ||
app, err := cli.Start(ctx, "run") | ||
is.NoErr(err) | ||
res, err := app.Get("/") | ||
is.NoErr(err) | ||
is.Equal(res.Status(), 200) | ||
is.In(res.Body().String(), "Hey Bud") | ||
is.In(res.Body().String(), "Hey Bud") // should work multiple times | ||
is.Equal(app.Stdout(), "") | ||
is.Equal(app.Stderr(), "") | ||
is.NoErr(td.Exists("bud/app")) | ||
is.NoErr(app.Close()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer necessary! There's no more spawning of a v8server when using
bud run
. Instead we've combined this with an internal local "bud server", that handles server-side rendering, hot reloads, and bundling client-side files.This bud server is only run with
bud run
, when youbud build
v8 is bundled, there's no hot reloads and all client-side files are pre-build and embedded.