From 337a5fbebaee0efe1022f44141911a896a085882 Mon Sep 17 00:00:00 2001 From: Tom Wiesing Date: Thu, 22 Dec 2022 13:49:05 +0100 Subject: [PATCH] pool: Reddo component-like fields --- cmd/server.go | 9 +- internal/dis/component/control/control.go | 7 +- internal/dis/component/control/cron/cron.go | 9 +- internal/dis/component/control/home/cron.go | 24 ++++-- internal/dis/component/control/home/home.go | 5 +- internal/dis/component/control/home/public.go | 4 +- .../dis/component/control/info/components.go | 2 +- internal/dis/component/control/info/index.go | 4 +- internal/dis/component/control/info/info.go | 28 ++++--- .../dis/component/control/info/instance.go | 2 +- internal/dis/component/control/info/socket.go | 4 +- internal/dis/component/control/server.go | 2 +- .../control/static/templates/_anal.html | 22 +++++ internal/dis/component/exporter/backup.go | 4 +- internal/dis/component/exporter/exporter.go | 13 +-- .../component/exporter/extras_pathbuilders.go | 6 +- internal/dis/component/exporter/iface.go | 4 +- .../dis/component/exporter/logger/logger.go | 9 +- internal/dis/component/exporter/prune.go | 2 +- internal/dis/component/exporter/snapshot.go | 2 +- internal/dis/component/instances/instances.go | 15 ++-- internal/dis/component/instances/malt/malt.go | 8 +- internal/dis/component/meta/meta.go | 7 +- internal/dis/component/resolver/prefixes.go | 2 +- internal/dis/component/resolver/resolver.go | 5 +- internal/dis/component/ssh2/server_auth.go | 2 +- internal/dis/component/ssh2/ssh2.go | 4 +- internal/wisski/ingredient/barrel/barrel.go | 7 +- internal/wisski/ingredient/barrel/build.go | 15 ++-- .../wisski/ingredient/barrel/drush/cron.go | 11 +-- .../wisski/ingredient/barrel/drush/drush.go | 9 +- .../wisski/ingredient/barrel/drush/update.go | 13 +-- .../barrel/provisioner/provisioner.go | 8 +- internal/wisski/ingredient/barrel/running.go | 7 +- internal/wisski/ingredient/barrel/ssh/ssh.go | 6 +- internal/wisski/ingredient/info/info.go | 11 +-- internal/wisski/ingredient/info/snapshots.go | 2 - .../ingredient/php/extras/pathbuilder.go | 11 +-- .../wisski/ingredient/php/extras/prefixes.go | 13 +-- .../wisski/ingredient/php/extras/settings.go | 9 +- .../wisski/ingredient/php/extras/stats.go | 7 +- internal/wisski/ingredient/php/php.go | 5 +- internal/wisski/ingredient/php/server.go | 2 +- .../wisski/ingredient/php/users/password.go | 4 +- internal/wisski/ingredient/php/users/users.go | 11 +-- pkg/lazy/pool.go | 5 ++ pkg/lazy/pool_anal.go | 10 +++ pkg/lazy/pool_meta.go | 83 +++++++++++++++---- 48 files changed, 291 insertions(+), 163 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index f960044..0593cc1 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -37,33 +37,32 @@ var errServerListen = exit.Error{ func (s server) Run(context wisski_distillery.Context) error { dis := context.Environment + // if the caller requested a trigger, just trigger the cron tasks if s.Trigger { - context.Println("Triggering Cron Tasks") return dis.Control().Trigger(context.Context, context.Environment.Environment) } - // start the cron tasks { // create a channel for notifications notify, cancel := dis.Cron().Listen(context.Context) defer cancel() // start the cron tasks - context.Printf("Starting cron tasks %s\n", s.Bind) done := dis.Cron().Start(context.Context, notify) defer func() { <-done }() } + // and start the server handler, err := dis.Control().Server(context.Context, context.Stderr) if err != nil { return err } - context.Printf("Listening on %s\n", s.Bind) + zerolog.Ctx(context.Context).Info().Str("bind", s.Bind).Msg("listening") - // make a new listener + // create a new listener listener, err := dis.Still.Environment.Listen("tcp", s.Bind) if err != nil { return errServerListen.Wrap(err) diff --git a/internal/dis/component/control/control.go b/internal/dis/component/control/control.go index 1263e0a..f61ad6c 100644 --- a/internal/dis/component/control/control.go +++ b/internal/dis/component/control/control.go @@ -15,9 +15,10 @@ import ( // Control represents the running control server. type Control struct { component.Base - - Servables []component.Servable - Cronables []component.Cronable + Dependencies struct { + Servables []component.Servable + Cronables []component.Cronable + } } var ( diff --git a/internal/dis/component/control/cron/cron.go b/internal/dis/component/control/cron/cron.go index 9691cc5..952c430 100644 --- a/internal/dis/component/control/cron/cron.go +++ b/internal/dis/component/control/cron/cron.go @@ -16,8 +16,9 @@ import ( type Cron struct { component.Base - - Tasks []component.Cronable + Dependencies struct { + Tasks []component.Cronable + } } // Listen returns a channel that listens for triggers in the current process. @@ -51,11 +52,11 @@ func (control *Cron) Listen(ctx context.Context) (<-chan struct{}, func()) { // Once should not be called concurrently with Cron. func (control *Cron) Once(ctx context.Context) { var wg sync.WaitGroup - wg.Add(len(control.Tasks)) + wg.Add(len(control.Dependencies.Tasks)) zerolog.Ctx(ctx).Info().Time("time", time.Now()).Msg("Starting Cron") - for _, task := range control.Tasks { + for _, task := range control.Dependencies.Tasks { go func(task component.Cronable) { defer wg.Done() diff --git a/internal/dis/component/control/home/cron.go b/internal/dis/component/control/home/cron.go index 223e982..85028aa 100644 --- a/internal/dis/component/control/home/cron.go +++ b/internal/dis/component/control/home/cron.go @@ -8,7 +8,9 @@ import ( type UpdateInstanceList struct { component.Base - Home *Home + Dependencies struct { + Home *Home + } } var ( @@ -20,18 +22,20 @@ func (*UpdateInstanceList) TaskName() string { } func (ul *UpdateInstanceList) Cron(ctx context.Context) error { - names, err := ul.Home.instanceMap(ctx) + names, err := ul.Dependencies.Home.instanceMap(ctx) if err != nil { return err } - ul.Home.instanceNames.Set(names) + ul.Dependencies.Home.instanceNames.Set(names) return nil } type UpdateRedirect struct { component.Base - Home *Home + Dependencies struct { + Home *Home + } } var ( @@ -43,18 +47,20 @@ func (ur *UpdateRedirect) TaskName() string { } func (ur *UpdateRedirect) Cron(ctx context.Context) error { - redirect, err := ur.Home.loadRedirect(ctx) + redirect, err := ur.Dependencies.Home.loadRedirect(ctx) if err != nil { return err } - ur.Home.redirect.Set(&redirect) + ur.Dependencies.Home.redirect.Set(&redirect) return nil } type UpdateHome struct { component.Base - Home *Home + Dependencies struct { + Home *Home + } } var ( @@ -66,11 +72,11 @@ func (ur *UpdateHome) TaskName() string { } func (ur *UpdateHome) Cron(ctx context.Context) error { - bytes, err := ur.Home.homeRender(ctx) + bytes, err := ur.Dependencies.Home.homeRender(ctx) if err != nil { return err } - ur.Home.homeBytes.Set(bytes) + ur.Dependencies.Home.homeBytes.Set(bytes) return nil } diff --git a/internal/dis/component/control/home/home.go b/internal/dis/component/control/home/home.go index 6c4088d..2876a7d 100644 --- a/internal/dis/component/control/home/home.go +++ b/internal/dis/component/control/home/home.go @@ -12,8 +12,9 @@ import ( type Home struct { component.Base - - Instances *instances.Instances + Dependencies struct { + Instances *instances.Instances + } redirect lazy.Lazy[*Redirect] instanceNames lazy.Lazy[map[string]struct{}] diff --git a/internal/dis/component/control/home/public.go b/internal/dis/component/control/home/public.go index 33f1f0f..c8688ca 100644 --- a/internal/dis/component/control/home/public.go +++ b/internal/dis/component/control/home/public.go @@ -13,7 +13,7 @@ import ( ) func (home *Home) instanceMap(ctx context.Context) (map[string]struct{}, error) { - wissKIs, err := home.Instances.All(ctx) + wissKIs, err := home.Dependencies.Instances.All(ctx) if err != nil { return nil, err } @@ -37,7 +37,7 @@ func (home *Home) homeRender(ctx context.Context) ([]byte, error) { context.SelfRedirect = home.Config.SelfRedirect.String() // find all the WissKIs - wissKIs, err := home.Instances.All(ctx) + wissKIs, err := home.Dependencies.Instances.All(ctx) if err != nil { return nil, err } diff --git a/internal/dis/component/control/info/components.go b/internal/dis/component/control/info/components.go index 20db575..14c35cc 100644 --- a/internal/dis/component/control/info/components.go +++ b/internal/dis/component/control/info/components.go @@ -52,7 +52,7 @@ func (info *Info) ingredients(r *http.Request) (cp ingredientsContext, err error cp.Time = time.Now().UTC() // find the instance itself! - instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"]) + instance, err := info.Dependencies.Instances.WissKI(r.Context(), mux.Vars(r)["slug"]) if err == instances.ErrWissKINotFound { return cp, httpx.ErrNotFound } diff --git a/internal/dis/component/control/info/index.go b/internal/dis/component/control/info/index.go index 1188284..3e0b116 100644 --- a/internal/dis/component/control/info/index.go +++ b/internal/dis/component/control/info/index.go @@ -37,7 +37,7 @@ func (info *Info) Status(ctx context.Context, QuickInformation bool) (target sta group.Go(func() error { // list all the instances - all, err := info.Instances.All(ctx) + all, err := info.Dependencies.Instances.All(ctx) if err != nil { return err } @@ -63,7 +63,7 @@ func (info *Info) Status(ctx context.Context, QuickInformation bool) (target sta flags := component.FetcherFlags{ Context: ctx, } - for _, o := range info.Fetchers { + for _, o := range info.Dependencies.Fetchers { o := o group.Go(func() error { return o.Fetch(flags, &target) diff --git a/internal/dis/component/control/info/info.go b/internal/dis/component/control/info/info.go index 07eeb2f..3ab4b02 100644 --- a/internal/dis/component/control/info/info.go +++ b/internal/dis/component/control/info/info.go @@ -16,13 +16,15 @@ import ( type Info struct { component.Base + Dependencies struct { + Fetchers []component.DistilleryFetcher + + Exporter *exporter.Exporter + Instances *instances.Instances + SnapshotsLog *logger.Logger + } Analytics *lazy.PoolAnalytics - Fetchers []component.DistilleryFetcher - - Exporter *exporter.Exporter - Instances *instances.Instances - SnapshotsLog *logger.Logger } var ( @@ -33,7 +35,9 @@ var ( func (*Info) Routes() []string { return []string{"/dis/"} } func (info *Info) Handler(ctx context.Context, route string) (handler http.Handler, err error) { + router := httprouter.New() + { socket := &httpx.WebSocket{ Context: ctx, @@ -47,41 +51,41 @@ func (info *Info) Handler(ctx context.Context, route string) (handler http.Handl // handle everything router.HandlerFunc(http.MethodGet, route, func(w http.ResponseWriter, r *http.Request) { - http.Redirect(w, r, "index", http.StatusTemporaryRedirect) + http.Redirect(w, r, route+"index", http.StatusTemporaryRedirect) }) // add a handler for the index page - router.Handler(http.MethodGet, "index", httpx.HTMLHandler[indexContext]{ + router.Handler(http.MethodGet, route+"index", httpx.HTMLHandler[indexContext]{ Handler: info.index, Template: indexTemplate, }) // add a handler for the component page - router.Handler(http.MethodGet, "components", httpx.HTMLHandler[componentContext]{ + router.Handler(http.MethodGet, route+"components", httpx.HTMLHandler[componentContext]{ Handler: info.components, Template: componentsTemplate, }) // add a handler for the component page - router.Handler(http.MethodGet, "ingredients/{slug}", httpx.HTMLHandler[ingredientsContext]{ + router.Handler(http.MethodGet, route+"ingredients/:slug", httpx.HTMLHandler[ingredientsContext]{ Handler: info.ingredients, Template: ingredientsTemplate, }) // add a handler for the instance page - router.Handler(http.MethodGet, "instance/{slug}", httpx.HTMLHandler[instanceContext]{ + router.Handler(http.MethodGet, route+"instance/:slug", httpx.HTMLHandler[instanceContext]{ Handler: info.instance, Template: instanceTemplate, }) - router.Handler(http.MethodPost, "api/login", httpx.RedirectHandler(func(r *http.Request) (string, int, error) { + router.Handler(http.MethodPost, route+"api/login", httpx.RedirectHandler(func(r *http.Request) (string, int, error) { // parse the form if err := r.ParseForm(); err != nil { return "", 0, err } // get the instance - instance, err := info.Instances.WissKI(r.Context(), r.PostFormValue("slug")) + instance, err := info.Dependencies.Instances.WissKI(r.Context(), r.PostFormValue("slug")) if err != nil { return "", 0, httpx.ErrNotFound } diff --git a/internal/dis/component/control/info/instance.go b/internal/dis/component/control/info/instance.go index cd6a303..0186168 100644 --- a/internal/dis/component/control/info/instance.go +++ b/internal/dis/component/control/info/instance.go @@ -29,7 +29,7 @@ type instanceContext struct { func (info *Info) instance(r *http.Request) (is instanceContext, err error) { // find the instance itself! - instance, err := info.Instances.WissKI(r.Context(), mux.Vars(r)["slug"]) + instance, err := info.Dependencies.Instances.WissKI(r.Context(), mux.Vars(r)["slug"]) if err == instances.ErrWissKINotFound { return is, httpx.ErrNotFound } diff --git a/internal/dis/component/control/info/socket.go b/internal/dis/component/control/info/socket.go index dabc3bd..453b761 100644 --- a/internal/dis/component/control/info/socket.go +++ b/internal/dis/component/control/info/socket.go @@ -23,7 +23,7 @@ type InstanceAction struct { var socketInstanceActions = map[string]InstanceAction{ "snapshot": { HandleInteractive: func(ctx context.Context, info *Info, instance *wisski.WissKI, out io.Writer, params ...string) error { - return info.Exporter.MakeExport( + return info.Dependencies.Exporter.MakeExport( ctx, out, exporter.ExportTask{ @@ -78,7 +78,7 @@ func (info *Info) handleInstanceAction(conn httpx.WebSocketConnection, action In } // resolve the instance - instance, err := info.Instances.WissKI(conn.Context(), string(slug.Bytes)) + instance, err := info.Dependencies.Instances.WissKI(conn.Context(), string(slug.Bytes)) if err != nil { <-conn.WriteText("Instance not found") return diff --git a/internal/dis/component/control/server.go b/internal/dis/component/control/server.go index f9b069b..dfb30b6 100644 --- a/internal/dis/component/control/server.go +++ b/internal/dis/component/control/server.go @@ -17,7 +17,7 @@ func (control *Control) Server(ctx context.Context, progress io.Writer) (*http.S mux := http.NewServeMux() // add all the servable routes! - for _, s := range control.Servables { + for _, s := range control.Dependencies.Servables { for _, route := range s.Routes() { zerolog.Ctx(ctx).Info().Str("component", s.Name()).Str("route", route).Msg("mounting route") handler, err := s.Handler(ctx, route) diff --git a/internal/dis/component/control/static/templates/_anal.html b/internal/dis/component/control/static/templates/_anal.html index bd484fd..ec7160b 100644 --- a/internal/dis/component/control/static/templates/_anal.html +++ b/internal/dis/component/control/static/templates/_anal.html @@ -36,6 +36,17 @@ {{ end }} + {{ range $name, $comp := .DCFields }} + + Component Pointer + + Dependencies/{{ $name }} + + + {{ $comp }} + + + {{ end }} {{ range $name, $iface := .IFields }} Interface Slice @@ -47,6 +58,17 @@ {{ end }} + {{ range $name, $iface := .DIFields }} + + Interface Slice + + Dependencies/{{ $name }} + + + []{{ $iface }} + + + {{ end }} {{ range $name, $sig := $comp.Methods }} diff --git a/internal/dis/component/exporter/backup.go b/internal/dis/component/exporter/backup.go index 1920895..4ce3146 100644 --- a/internal/dis/component/exporter/backup.go +++ b/internal/dis/component/exporter/backup.go @@ -75,7 +75,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp defer done() // create a new status display - backups := exporter.Backupable + backups := exporter.Dependencies.Backupable backup.ComponentErrors = make(map[string]error, len(backups)) // Component backup tasks @@ -125,7 +125,7 @@ func (backup *Backup) run(ctx context.Context, progress io.Writer, exporter *Exp } // list all instances - wissKIs, err := exporter.Instances.All(ctx) + wissKIs, err := exporter.Dependencies.Instances.All(ctx) if err != nil { backup.InstanceListErr = err return nil diff --git a/internal/dis/component/exporter/exporter.go b/internal/dis/component/exporter/exporter.go index ae89e3d..e80830e 100644 --- a/internal/dis/component/exporter/exporter.go +++ b/internal/dis/component/exporter/exporter.go @@ -18,13 +18,14 @@ import ( // Exporter manages snapshots and backups type Exporter struct { component.Base + Dependencies struct { + SQL *sql.SQL + Instances *instances.Instances + ExporterLogger *logger.Logger - SQL *sql.SQL - Instances *instances.Instances - ExporterLogger *logger.Logger - - Snapshotable []component.Snapshotable - Backupable []component.Backupable + Snapshotable []component.Snapshotable + Backupable []component.Backupable + } } // Path returns the path that contains all snapshot related data. diff --git a/internal/dis/component/exporter/extras_pathbuilders.go b/internal/dis/component/exporter/extras_pathbuilders.go index 26591a8..eaa1eff 100644 --- a/internal/dis/component/exporter/extras_pathbuilders.go +++ b/internal/dis/component/exporter/extras_pathbuilders.go @@ -11,7 +11,9 @@ import ( type Pathbuilders struct { component.Base - Instances *instances.Instances + Dependencies struct { + Instances *instances.Instances + } } var ( @@ -24,7 +26,7 @@ func (Pathbuilders) SnapshotName() string { return "pathbuilders" } func (pbs *Pathbuilders) Snapshot(wisski models.Instance, scontext component.StagingContext) error { return scontext.AddDirectory(".", func(ctx context.Context) error { - builders, err := pbs.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil) + builders, err := pbs.Dependencies.Instances.Instance(ctx, wisski).Pathbuilder().GetAll(ctx, nil) if err != nil { return err } diff --git a/internal/dis/component/exporter/iface.go b/internal/dis/component/exporter/iface.go index 5f035ea..ed22ab8 100644 --- a/internal/dis/component/exporter/iface.go +++ b/internal/dis/component/exporter/iface.go @@ -131,7 +131,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta // write out the log entry entry.Path = stagingDir entry.Packed = false - exporter.ExporterLogger.Add(ctx, entry) + exporter.Dependencies.ExporterLogger.Add(ctx, entry) logging.ProgressF(progress, ctx, "Wrote %s\n", stagingDir) return nil @@ -159,7 +159,7 @@ func (exporter *Exporter) MakeExport(ctx context.Context, progress io.Writer, ta logging.LogMessage(progress, ctx, "Writing Log Entry") entry.Path = archivePath entry.Packed = true - exporter.ExporterLogger.Add(ctx, entry) + exporter.Dependencies.ExporterLogger.Add(ctx, entry) // and we're done! return nil diff --git a/internal/dis/component/exporter/logger/logger.go b/internal/dis/component/exporter/logger/logger.go index 805698a..fcf8f5a 100644 --- a/internal/dis/component/exporter/logger/logger.go +++ b/internal/dis/component/exporter/logger/logger.go @@ -14,8 +14,9 @@ import ( // Logger is responsible for logging backups and snapshots type Logger struct { component.Base - - SQL *sql.SQL + Dependencies struct { + SQL *sql.SQL + } } // For retrieves (and prunes) the ExportLog. @@ -35,7 +36,7 @@ func (log *Logger) For(ctx context.Context, slug string) (exports []models.Expor // Log retrieves (and prunes) all entries in the snapshot log. func (log *Logger) Log(ctx context.Context) ([]models.Export, error) { // query the table! - table, err := log.SQL.QueryTable(ctx, false, models.ExportTable) + table, err := log.Dependencies.SQL.QueryTable(ctx, false, models.ExportTable) if err != nil { return nil, err } @@ -67,7 +68,7 @@ func (log *Logger) Log(ctx context.Context) ([]models.Export, error) { // AddToExportLog adds the provided export to the log. func (log *Logger) Add(ctx context.Context, export models.Export) error { // find the table - table, err := log.SQL.QueryTable(ctx, false, models.ExportTable) + table, err := log.Dependencies.SQL.QueryTable(ctx, false, models.ExportTable) if err != nil { return err } diff --git a/internal/dis/component/exporter/prune.go b/internal/dis/component/exporter/prune.go index 5ae75d6..cb0cf83 100644 --- a/internal/dis/component/exporter/prune.go +++ b/internal/dis/component/exporter/prune.go @@ -52,6 +52,6 @@ func (exporter *Exporter) PruneExports(ctx context.Context, progress io.Writer) } // prune the snapshot log! - _, err = exporter.ExporterLogger.Log(ctx) + _, err = exporter.Dependencies.ExporterLogger.Log(ctx) return err } diff --git a/internal/dis/component/exporter/snapshot.go b/internal/dis/component/exporter/snapshot.go index 84697a9..cdac010 100644 --- a/internal/dis/component/exporter/snapshot.go +++ b/internal/dis/component/exporter/snapshot.go @@ -107,7 +107,7 @@ func (snapshot *Snapshot) makeParts(ctx context.Context, progress io.Writer, sna defer st.Stop() // get all the components - comps := collection.FilterClone(snapshots.Snapshotable, func(sc component.Snapshotable) bool { + comps := collection.FilterClone(snapshots.Dependencies.Snapshotable, func(sc component.Snapshotable) bool { return sc.SnapshotNeedsRunning() == needsRunning }) diff --git a/internal/dis/component/instances/instances.go b/internal/dis/component/instances/instances.go index f31e0fb..110c232 100644 --- a/internal/dis/component/instances/instances.go +++ b/internal/dis/component/instances/instances.go @@ -19,9 +19,10 @@ import ( // Instances manages multiple WissKI Instances. type Instances struct { component.Base - - Malt *malt.Malt - SQL *sql.SQL + Dependencies struct { + Malt *malt.Malt + SQL *sql.SQL + } } func (instances *Instances) Path() string { @@ -38,13 +39,13 @@ var errSQL = exit.Error{ // use uses the non-nil wisski instance with this instances func (instances *Instances) use(wisski *wisski.WissKI) { - wisski.Liquid.Malt = instances.Malt + wisski.Liquid.Malt = instances.Dependencies.Malt } // WissKI returns the WissKI with the provided slug, if it exists. // It the WissKI does not exist, returns ErrWissKINotFound. func (instances *Instances) WissKI(ctx context.Context, slug string) (wissKI *wisski.WissKI, err error) { - sql := instances.SQL + sql := instances.Dependencies.SQL if err := sql.WaitQueryTable(ctx); err != nil { return nil, err } @@ -84,7 +85,7 @@ func (instances *Instances) Instance(ctx context.Context, instance models.Instan // Has checks if a WissKI with the provided slug exists inside the database. // It does not perform any checks on the WissKI itself. func (instances *Instances) Has(ctx context.Context, slug string) (ok bool, err error) { - sql := instances.SQL + sql := instances.Dependencies.SQL if err := sql.WaitQueryTable(ctx); err != nil { return false, err } @@ -128,7 +129,7 @@ func (instances *Instances) Load(ctx context.Context, slugs ...string) ([]*wissk // find finds instances based on the provided query func (instances *Instances) find(ctx context.Context, order bool, query func(table *gorm.DB) *gorm.DB) (results []*wisski.WissKI, err error) { - sql := instances.SQL + sql := instances.Dependencies.SQL if err := sql.WaitQueryTable(ctx); err != nil { return nil, err } diff --git a/internal/dis/component/instances/malt/malt.go b/internal/dis/component/instances/malt/malt.go index d8931d2..5aa5009 100644 --- a/internal/dis/component/instances/malt/malt.go +++ b/internal/dis/component/instances/malt/malt.go @@ -12,8 +12,8 @@ import ( type Malt struct { component.Base - TS *triplestore.Triplestore - SQL *sql.SQL - Meta *meta.Meta - ExporterLog *logger.Logger + TS *triplestore.Triplestore `auto:"true"` + SQL *sql.SQL `auto:"true"` + Meta *meta.Meta `auto:"true"` + ExporterLog *logger.Logger `auto:"true"` } diff --git a/internal/dis/component/meta/meta.go b/internal/dis/component/meta/meta.go index 949d677..71c8def 100644 --- a/internal/dis/component/meta/meta.go +++ b/internal/dis/component/meta/meta.go @@ -10,8 +10,9 @@ import ( // Component meta is responsible for managing metadata per WissKI Instance type Meta struct { component.Base - - SQL *sql.SQL + Dependencies struct { + SQL *sql.SQL + } sl sync.Mutex sc map[string]*Storage @@ -40,7 +41,7 @@ func (meta *Meta) Storage(slug string) *Storage { // create a new storage meta.sc[slug] = &Storage{ Slug: slug, - sql: meta.SQL, + sql: meta.Dependencies.SQL, } return meta.sc[slug] } diff --git a/internal/dis/component/resolver/prefixes.go b/internal/dis/component/resolver/prefixes.go index bdeff74..dba0070 100644 --- a/internal/dis/component/resolver/prefixes.go +++ b/internal/dis/component/resolver/prefixes.go @@ -21,7 +21,7 @@ func (resolver *Resolver) Cron(ctx context.Context) error { // AllPrefixes returns a list of all prefixes from the server. // Prefixes may be cached on the server func (resolver *Resolver) AllPrefixes(ctx context.Context) (map[string]string, error) { - instances, err := resolver.Instances.All(ctx) + instances, err := resolver.Dependencies.Instances.All(ctx) if err != nil { return nil, err } diff --git a/internal/dis/component/resolver/resolver.go b/internal/dis/component/resolver/resolver.go index ca11dac..84c3ea0 100644 --- a/internal/dis/component/resolver/resolver.go +++ b/internal/dis/component/resolver/resolver.go @@ -17,8 +17,9 @@ import ( type Resolver struct { component.Base - - Instances *instances.Instances + Dependencies struct { + Instances *instances.Instances + } prefixes lazy.Lazy[map[string]string] // cached prefixes (from the server) RefreshInterval time.Duration diff --git a/internal/dis/component/ssh2/server_auth.go b/internal/dis/component/ssh2/server_auth.go index 882139a..8c4be82 100644 --- a/internal/dis/component/ssh2/server_auth.go +++ b/internal/dis/component/ssh2/server_auth.go @@ -65,7 +65,7 @@ func (ssh2 *SSH2) handleAuth(ctx ssh.Context, key ssh.PublicKey) bool { // grab permissions for each instance { - instances, err := ssh2.Instances.All(ctx) + instances, err := ssh2.Dependencies.Instances.All(ctx) if err != nil { return false } diff --git a/internal/dis/component/ssh2/ssh2.go b/internal/dis/component/ssh2/ssh2.go index 4eefcb8..e4e28c3 100644 --- a/internal/dis/component/ssh2/ssh2.go +++ b/internal/dis/component/ssh2/ssh2.go @@ -11,7 +11,9 @@ import ( type SSH2 struct { component.Base - Instances *instances.Instances + Dependencies struct { + Instances *instances.Instances + } } var ( diff --git a/internal/wisski/ingredient/barrel/barrel.go b/internal/wisski/ingredient/barrel/barrel.go index 7afe4b3..7f9bae6 100644 --- a/internal/wisski/ingredient/barrel/barrel.go +++ b/internal/wisski/ingredient/barrel/barrel.go @@ -11,9 +11,10 @@ import ( // Barrel provides access to the underlying Barrel type Barrel struct { ingredient.Base - - Locker *locker.Locker - MStore *mstore.MStore + Dependencies struct { + Locker *locker.Locker + MStore *mstore.MStore + } } func (barrel *Barrel) DataPath() string { diff --git a/internal/wisski/ingredient/barrel/build.go b/internal/wisski/ingredient/barrel/build.go index 8533922..6c83a22 100644 --- a/internal/wisski/ingredient/barrel/build.go +++ b/internal/wisski/ingredient/barrel/build.go @@ -17,10 +17,10 @@ import ( // // It also logs the current time into the metadata belonging to this instance. func (barrel *Barrel) Build(ctx context.Context, progress io.Writer, start bool) error { - if !barrel.Locker.TryLock(ctx) { + if !barrel.Dependencies.Locker.TryLock(ctx) { return locker.Locked } - defer barrel.Locker.Unlock(ctx) + defer barrel.Dependencies.Locker.Unlock(ctx) stack := barrel.Stack() @@ -48,7 +48,7 @@ func (barrel *Barrel) Build(ctx context.Context, progress io.Writer, start bool) var lastRebuild = mstore.For[int64]("lastRebuild") func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) { - epoch, err := lastRebuild.Get(ctx, barrel.MStore) + epoch, err := lastRebuild.Get(ctx, barrel.Dependencies.MStore) if err == meta.ErrMetadatumNotSet { return t, nil } @@ -61,16 +61,17 @@ func (barrel Barrel) LastRebuild(ctx context.Context) (t time.Time, err error) { } func (barrel *Barrel) setLastRebuild(ctx context.Context) error { - return lastRebuild.Set(ctx, barrel.MStore, time.Now().Unix()) + return lastRebuild.Set(ctx, barrel.Dependencies.MStore, time.Now().Unix()) } type LastRebuildFetcher struct { ingredient.Base - - Barrel *Barrel + Dependencies struct { + Barrel *Barrel + } } func (lbr *LastRebuildFetcher) Fetch(ctx context.Context, flags ingredient.FetcherFlags, info *status.WissKI) (err error) { - info.LastRebuild, _ = lbr.Barrel.LastRebuild(ctx) + info.LastRebuild, _ = lbr.Dependencies.Barrel.LastRebuild(ctx) return } diff --git a/internal/wisski/ingredient/barrel/drush/cron.go b/internal/wisski/ingredient/barrel/drush/cron.go index 7851823..070b1c6 100644 --- a/internal/wisski/ingredient/barrel/drush/cron.go +++ b/internal/wisski/ingredient/barrel/drush/cron.go @@ -20,7 +20,7 @@ var errCronFailed = exit.Error{ } func (drush *Drush) Cron(ctx context.Context, progress io.Writer) error { - code := drush.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/cron.sh")() + code := drush.Dependencies.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/cron.sh")() if code != 0 { // keep going, because we want to run as many crons as possible logging.ProgressF(progress, ctx, "%v", errCronFailed.WithMessageF(drush.Slug, code)) @@ -31,7 +31,7 @@ func (drush *Drush) Cron(ctx context.Context, progress io.Writer) error { func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.Time, err error) { var timestamp int64 - err = drush.PHP.EvalCode(ctx, server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `) + err = drush.Dependencies.PHP.EvalCode(ctx, server, ×tamp, `$val = \Drupal::state()->get('system.cron_last'); return $val; `) if err != nil { return } @@ -40,8 +40,9 @@ func (drush *Drush) LastCron(ctx context.Context, server *phpx.Server) (t time.T type LastCronFetcher struct { ingredient.Base - - Drush *Drush + Dependencies struct { + Drush *Drush + } } var ( @@ -53,6 +54,6 @@ func (lbr *LastCronFetcher) Fetch(flags ingredient.FetcherFlags, info *status.Wi return } - info.LastRebuild, _ = lbr.Drush.LastCron(flags.Context, flags.Server) + info.LastRebuild, _ = lbr.Dependencies.Drush.LastCron(flags.Context, flags.Server) return } diff --git a/internal/wisski/ingredient/barrel/drush/drush.go b/internal/wisski/ingredient/barrel/drush/drush.go index 4b81724..b1bd302 100644 --- a/internal/wisski/ingredient/barrel/drush/drush.go +++ b/internal/wisski/ingredient/barrel/drush/drush.go @@ -10,8 +10,9 @@ import ( // Drush implements commands related to drush type Drush struct { ingredient.Base - - Barrel *barrel.Barrel - MStore *mstore.MStore - PHP *php.PHP + Dependencies struct { + Barrel *barrel.Barrel + MStore *mstore.MStore + PHP *php.PHP + } } diff --git a/internal/wisski/ingredient/barrel/drush/update.go b/internal/wisski/ingredient/barrel/drush/update.go index a150a1c..c47f75b 100644 --- a/internal/wisski/ingredient/barrel/drush/update.go +++ b/internal/wisski/ingredient/barrel/drush/update.go @@ -20,7 +20,7 @@ var errBlindUpdateFailed = exit.Error{ // Update performs a blind drush update func (drush *Drush) Update(ctx context.Context, progress io.Writer) error { - code := drush.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/blind_update.sh")() + code := drush.Dependencies.Barrel.Shell(ctx, stream.NonInteractive(progress), "/runtime/blind_update.sh")() if code != 0 { return errBlindUpdateFailed.WithMessageF(drush.Slug, code) } @@ -31,7 +31,7 @@ func (drush *Drush) Update(ctx context.Context, progress io.Writer) error { const lastUpdate = mstore.For[int64]("lastUpdate") func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) { - epoch, err := lastUpdate.Get(ctx, drush.MStore) + epoch, err := lastUpdate.Get(ctx, drush.Dependencies.MStore) if err == meta.ErrMetadatumNotSet { return t, nil } @@ -44,13 +44,14 @@ func (drush *Drush) LastUpdate(ctx context.Context) (t time.Time, err error) { } func (drush *Drush) setLastUpdate(ctx context.Context) error { - return lastUpdate.Set(ctx, drush.MStore, time.Now().Unix()) + return lastUpdate.Set(ctx, drush.Dependencies.MStore, time.Now().Unix()) } type LastUpdateFetcher struct { ingredient.Base - - Drush *Drush + Dependencies struct { + Drush *Drush + } } var ( @@ -58,6 +59,6 @@ var ( ) func (lbr *LastUpdateFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) { - info.LastUpdate, err = lbr.Drush.LastUpdate(flags.Context) + info.LastUpdate, err = lbr.Dependencies.Drush.LastUpdate(flags.Context) return } diff --git a/internal/wisski/ingredient/barrel/provisioner/provisioner.go b/internal/wisski/ingredient/barrel/provisioner/provisioner.go index f8b0a80..0561a86 100644 --- a/internal/wisski/ingredient/barrel/provisioner/provisioner.go +++ b/internal/wisski/ingredient/barrel/provisioner/provisioner.go @@ -17,14 +17,16 @@ import ( // Instead, this should code directly defined in go. type Provisioner struct { ingredient.Base - Barrel *barrel.Barrel + Dependencies struct { + Barrel *barrel.Barrel + } } // Provision provisions an instance, assuming that the required databases already exist. func (provision *Provisioner) Provision(ctx context.Context, progress io.Writer) error { // build the container - if err := provision.Barrel.Build(ctx, progress, false); err != nil { + if err := provision.Dependencies.Barrel.Build(ctx, progress, false); err != nil { return err } @@ -55,7 +57,7 @@ func (provision *Provisioner) Provision(ctx context.Context, progress io.Writer) // TODO: Move the provision script into the control plane! provisionScript := "sudo PATH=$PATH -u www-data /bin/bash /provision_container.sh " + strings.Join(provisionParams, " ") - code, err := provision.Barrel.Stack().Run(ctx, stream.NonInteractive(progress), true, "barrel", "/bin/bash", "-c", provisionScript) + code, err := provision.Dependencies.Barrel.Stack().Run(ctx, stream.NonInteractive(progress), true, "barrel", "/bin/bash", "-c", provisionScript) if err != nil { return err } diff --git a/internal/wisski/ingredient/barrel/running.go b/internal/wisski/ingredient/barrel/running.go index 4b2d570..af4b500 100644 --- a/internal/wisski/ingredient/barrel/running.go +++ b/internal/wisski/ingredient/barrel/running.go @@ -19,8 +19,9 @@ func (barrel *Barrel) Running(ctx context.Context, progress io.Writer) (bool, er type RunningFetcher struct { ingredient.Base - - Barrel *Barrel + Dependencies struct { + Barrel *Barrel + } } var ( @@ -28,6 +29,6 @@ var ( ) func (rf *RunningFetcher) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) { - info.Running, err = rf.Barrel.Running(flags.Context, io.Discard) + info.Running, err = rf.Dependencies.Barrel.Running(flags.Context, io.Discard) return } diff --git a/internal/wisski/ingredient/barrel/ssh/ssh.go b/internal/wisski/ingredient/barrel/ssh/ssh.go index ead9e0e..3be19e8 100644 --- a/internal/wisski/ingredient/barrel/ssh/ssh.go +++ b/internal/wisski/ingredient/barrel/ssh/ssh.go @@ -14,7 +14,9 @@ import ( type SSH struct { ingredient.Base - Barrel *barrel.Barrel + Dependencies struct { + Barrel *barrel.Barrel + } } var ( @@ -22,7 +24,7 @@ var ( ) func (ssh *SSH) Keys() ([]ssh.PublicKey, error) { - file, err := ssh.Environment.Open(ssh.Barrel.AuthorizedKeysPath()) + file, err := ssh.Environment.Open(ssh.Dependencies.Barrel.AuthorizedKeysPath()) if environment.IsNotExist(err) { return nil, nil } diff --git a/internal/wisski/ingredient/info/info.go b/internal/wisski/ingredient/info/info.go index e182171..9e99778 100644 --- a/internal/wisski/ingredient/info/info.go +++ b/internal/wisski/ingredient/info/info.go @@ -13,9 +13,10 @@ import ( type Info struct { ingredient.Base - - PHP *php.PHP - Fetchers []ingredient.WissKIFetcher + Dependencies struct { + PHP *php.PHP + Fetchers []ingredient.WissKIFetcher + } Analytics *lazy.PoolAnalytics } @@ -35,7 +36,7 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi // potentially setup a new server if !flags.Quick { - flags.Server = wisski.PHP.NewServer() + flags.Server = wisski.Dependencies.PHP.NewServer() if err == nil { defer flags.Server.Close() } @@ -43,7 +44,7 @@ func (wisski *Info) Information(ctx context.Context, quick bool) (info status.Wi // run all the fetchers! var group errgroup.Group - for _, fetcher := range wisski.Fetchers { + for _, fetcher := range wisski.Dependencies.Fetchers { fetcher := fetcher group.Go(func() error { return fetcher.Fetch(flags, &info) diff --git a/internal/wisski/ingredient/info/snapshots.go b/internal/wisski/ingredient/info/snapshots.go index 3e18015..4c83d31 100644 --- a/internal/wisski/ingredient/info/snapshots.go +++ b/internal/wisski/ingredient/info/snapshots.go @@ -7,8 +7,6 @@ import ( type SnapshotsFetcher struct { ingredient.Base - - Info *Info } var ( diff --git a/internal/wisski/ingredient/php/extras/pathbuilder.go b/internal/wisski/ingredient/php/extras/pathbuilder.go index 9137de8..57b19d1 100644 --- a/internal/wisski/ingredient/php/extras/pathbuilder.go +++ b/internal/wisski/ingredient/php/extras/pathbuilder.go @@ -13,8 +13,9 @@ import ( type Pathbuilder struct { ingredient.Base - - PHP *php.PHP + Dependencies struct { + PHP *php.PHP + } } var ( @@ -28,7 +29,7 @@ var pathbuilderPHP string // // server is the server to fetch the pathbuilders from, any may be nil. func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (ids []string, err error) { - err = pathbuilder.PHP.ExecScript(ctx, server, &ids, pathbuilderPHP, "all_list") + err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &ids, pathbuilderPHP, "all_list") slices.Sort(ids) return } @@ -38,7 +39,7 @@ func (pathbuilder *Pathbuilder) All(ctx context.Context, server *phpx.Server) (i // // server is the server to fetch the pathbuilders from, any may be nil. func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id string) (xml string, err error) { - err = pathbuilder.PHP.ExecScript(ctx, server, &xml, pathbuilderPHP, "one_xml", id) + err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &xml, pathbuilderPHP, "one_xml", id) return } @@ -46,7 +47,7 @@ func (pathbuilder *Pathbuilder) Get(ctx context.Context, server *phpx.Server, id // // server is the server to fetch the pathbuilders from, any may be nil. func (pathbuilder *Pathbuilder) GetAll(ctx context.Context, server *phpx.Server) (pathbuilders map[string]string, err error) { - err = pathbuilder.PHP.ExecScript(ctx, server, &pathbuilders, pathbuilderPHP, "all_xml") + err = pathbuilder.Dependencies.PHP.ExecScript(ctx, server, &pathbuilders, pathbuilderPHP, "all_xml") return } diff --git a/internal/wisski/ingredient/php/extras/prefixes.go b/internal/wisski/ingredient/php/extras/prefixes.go index afbab98..3767b30 100644 --- a/internal/wisski/ingredient/php/extras/prefixes.go +++ b/internal/wisski/ingredient/php/extras/prefixes.go @@ -20,9 +20,10 @@ import ( // Prefixes implements reading and writing prefix type Prefixes struct { ingredient.Base - - PHP *php.PHP - MStore *mstore.MStore + Dependencies struct { + PHP *php.PHP + MStore *mstore.MStore + } } var ( @@ -58,7 +59,7 @@ func (prefixes *Prefixes) All(ctx context.Context, server *phpx.Server) ([]strin func (wisski *Prefixes) database(ctx context.Context, server *phpx.Server) (prefixes []string, err error) { // get all the ugly prefixes - err = wisski.PHP.ExecScript(ctx, server, &prefixes, listURIPrefixesPHP, "list_prefixes") + err = wisski.Dependencies.PHP.ExecScript(ctx, server, &prefixes, listURIPrefixesPHP, "list_prefixes") if err != nil { return nil, err } @@ -149,7 +150,7 @@ var prefix = mstore.For[string]("prefix") // Prefixes returns the cached prefixes from the given instance func (wisski *Prefixes) AllCached(ctx context.Context) (results []string, err error) { - return prefix.GetAll(ctx, wisski.MStore) + return prefix.GetAll(ctx, wisski.Dependencies.MStore) } // Update updates the cached prefixes of this instance @@ -158,7 +159,7 @@ func (wisski *Prefixes) Update(ctx context.Context) error { if err != nil { return err } - return prefix.SetAll(ctx, wisski.MStore, prefixes...) + return prefix.SetAll(ctx, wisski.Dependencies.MStore, prefixes...) } func (prefixes *Prefixes) Fetch(flags ingredient.FetcherFlags, info *status.WissKI) (err error) { diff --git a/internal/wisski/ingredient/php/extras/settings.go b/internal/wisski/ingredient/php/extras/settings.go index 6c1267f..52b3b16 100644 --- a/internal/wisski/ingredient/php/extras/settings.go +++ b/internal/wisski/ingredient/php/extras/settings.go @@ -11,18 +11,19 @@ import ( type Settings struct { ingredient.Base - - PHP *php.PHP + Dependencies struct { + PHP *php.PHP + } } //go:embed settings.php var settingsPHP string func (settings *Settings) Get(ctx context.Context, server *phpx.Server, key string) (value any, err error) { - err = settings.PHP.ExecScript(ctx, server, &value, settingsPHP, "get_setting", key) + err = settings.Dependencies.PHP.ExecScript(ctx, server, &value, settingsPHP, "get_setting", key) return } func (settings *Settings) Set(ctx context.Context, server *phpx.Server, key string, value any) error { - return settings.PHP.ExecScript(ctx, server, nil, settingsPHP, "set_setting", key, value) + return settings.Dependencies.PHP.ExecScript(ctx, server, nil, settingsPHP, "set_setting", key, value) } diff --git a/internal/wisski/ingredient/php/extras/stats.go b/internal/wisski/ingredient/php/extras/stats.go index f23e5bf..5ec2064 100644 --- a/internal/wisski/ingredient/php/extras/stats.go +++ b/internal/wisski/ingredient/php/extras/stats.go @@ -12,8 +12,9 @@ import ( type Stats struct { ingredient.Base - - PHP *php.PHP + Dependencies struct { + PHP *php.PHP + } } var ( @@ -25,7 +26,7 @@ var statsPHP string // Get fetches all statistics from the server func (stats *Stats) Get(ctx context.Context, server *phpx.Server) (data status.Statistics, err error) { - err = stats.PHP.ExecScript(ctx, server, &data, statsPHP, "export_statistics") + err = stats.Dependencies.PHP.ExecScript(ctx, server, &data, statsPHP, "export_statistics") return } diff --git a/internal/wisski/ingredient/php/php.go b/internal/wisski/ingredient/php/php.go index edb9dcf..a9a6204 100644 --- a/internal/wisski/ingredient/php/php.go +++ b/internal/wisski/ingredient/php/php.go @@ -11,8 +11,9 @@ import ( type PHP struct { ingredient.Base - - Barrel *barrel.Barrel + Dependencies struct { + Barrel *barrel.Barrel + } } // ExecScript executes the PHP code as a script on the given server. diff --git a/internal/wisski/ingredient/php/server.go b/internal/wisski/ingredient/php/server.go index 515225d..6a54fee 100644 --- a/internal/wisski/ingredient/php/server.go +++ b/internal/wisski/ingredient/php/server.go @@ -21,6 +21,6 @@ func (php *PHP) NewServer() *phpx.Server { } func (php *PHP) spawn(ctx context.Context, str stream.IOStream, code string) error { - php.Barrel.Shell(ctx, str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))() + php.Dependencies.Barrel.Shell(ctx, str, "-c", shellescape.QuoteCommand([]string{"drush", "php:eval", code}))() return nil } diff --git a/internal/wisski/ingredient/php/users/password.go b/internal/wisski/ingredient/php/users/password.go index 49ec789..5939ecc 100644 --- a/internal/wisski/ingredient/php/users/password.go +++ b/internal/wisski/ingredient/php/users/password.go @@ -16,10 +16,10 @@ import ( var errGetValidator = errors.New("GetPasswordValidator: Unknown Error") func (u *Users) GetPasswordValidator(ctx context.Context, username string) (pv PasswordValidator, err error) { - server := u.PHP.NewServer() + server := u.Dependencies.PHP.NewServer() var hash string - err = u.PHP.ExecScript(ctx, server, &hash, usersPHP, "get_password_hash", username) + err = u.Dependencies.PHP.ExecScript(ctx, server, &hash, usersPHP, "get_password_hash", username) if err != nil { server.Close() return pv, err diff --git a/internal/wisski/ingredient/php/users/users.go b/internal/wisski/ingredient/php/users/users.go index 6ec2853..84966ae 100644 --- a/internal/wisski/ingredient/php/users/users.go +++ b/internal/wisski/ingredient/php/users/users.go @@ -14,8 +14,9 @@ import ( type Users struct { ingredient.Base - - PHP *php.PHP + Dependencies struct { + PHP *php.PHP + } } var ( @@ -27,7 +28,7 @@ var usersPHP string // All returns all known usernames func (u *Users) All(ctx context.Context, server *phpx.Server) (users []status.User, err error) { - err = u.PHP.ExecScript(ctx, server, &users, usersPHP, "list_users") + err = u.Dependencies.PHP.ExecScript(ctx, server, &users, usersPHP, "list_users") return } @@ -38,7 +39,7 @@ func (u *Users) Login(ctx context.Context, server *phpx.Server, username string) // generate a (relative) link var path string - err = u.PHP.ExecScript(ctx, server, &path, usersPHP, "get_login_link", username) + err = u.Dependencies.PHP.ExecScript(ctx, server, &path, usersPHP, "get_login_link", username) // if something went wrong, return if err != nil { @@ -64,7 +65,7 @@ var errSetPassword = errors.New("SetPassword: Unknown Error") // SetPassword sets the password for a given user func (u *Users) SetPassword(ctx context.Context, server *phpx.Server, username, password string) error { var ok bool - err := u.PHP.ExecScript(ctx, server, &ok, usersPHP, "set_user_password", username, password) + err := u.Dependencies.PHP.ExecScript(ctx, server, &ok, usersPHP, "set_user_password", username, password) if err != nil { return err } diff --git a/pkg/lazy/pool.go b/pkg/lazy/pool.go index d49aa3e..5db0a4e 100644 --- a/pkg/lazy/pool.go +++ b/pkg/lazy/pool.go @@ -105,6 +105,11 @@ func (di *delayedInit[Component]) Run(all []Component) { // - A pointer to a struct type that implements component // - A slice type of an interface type that implements component // +// Such component-like fields are only initialized if one of the following conditions are met: +// +// - The field has a tag 'auto' with the value `true` +// - The field lives inside a struct field named `Dependencies` +// // These fields are initialized in an undefined order during initialization. // The init function may not rely on these existing. // Furthermore, the init function may not cause other components to be initialized. diff --git a/pkg/lazy/pool_anal.go b/pkg/lazy/pool_anal.go index a2e4f03..5e8db03 100644 --- a/pkg/lazy/pool_anal.go +++ b/pkg/lazy/pool_anal.go @@ -19,6 +19,9 @@ type PoolAnalyticsComponent struct { CFields map[string]string // fields with type C for which C implements component IFields map[string]string // fields []I where I is an interface that implements component + DCFields map[string]string // fields of the auto field with type C for which C implements component + DIFields map[string]string // fields of the auto field []I where I is an interface that implements component + Methods map[string]string // Method signatures of type } type PoolAnalyticsGroup struct { @@ -61,11 +64,18 @@ func (context *PoolContext[Component]) anal(anal *PoolAnalytics, groups []reflec anal.Components[meta.Name].CFields = collection.MapValues(meta.CFields, func(key string, tp reflect.Type) string { return nameOf(tp.Elem()) }) + anal.Components[meta.Name].DCFields = collection.MapValues(meta.DCFields, func(key string, tp reflect.Type) string { + return nameOf(tp.Elem()) + }) anal.Components[meta.Name].IFields = collection.MapValues(meta.IFields, func(key string, iface reflect.Type) string { ifaces = append(ifaces, iface) return nameOf(iface) }) + anal.Components[meta.Name].DIFields = collection.MapValues(meta.DIFields, func(key string, iface reflect.Type) string { + ifaces = append(ifaces, iface) + return nameOf(iface) + }) } // and analyze all ifaces diff --git a/pkg/lazy/pool_meta.go b/pkg/lazy/pool_meta.go index a548c3a..5b5ca58 100644 --- a/pkg/lazy/pool_meta.go +++ b/pkg/lazy/pool_meta.go @@ -32,11 +32,14 @@ type meta[Component any] struct { CFields map[string]reflect.Type // fields with type C for which C implements component IFields map[string]reflect.Type // fields []I where I is an interface that implements component + + DCFields map[string]reflect.Type // fields with type C for which C inside auto field which implement component + DIFields map[string]reflect.Type // fields []I where I is an interface inside auto field that implements component } // init initializes this meta func (m *meta[Component]) init(tp reflect.Type) { - var componentType = reflectx.TypeOf[Component]() + var component = reflectx.TypeOf[Component]() if tp.Kind() != reflect.Pointer && tp.Elem().Kind() != reflect.Struct { panic("GetMeta: Type (" + tp.String() + ") must be backed by a pointer to slice") @@ -47,27 +50,61 @@ func (m *meta[Component]) init(tp reflect.Type) { m.CFields = make(map[string]reflect.Type) m.IFields = make(map[string]reflect.Type) + scanForFields(component, m.Name, m.Elem, false, m.CFields, m.IFields) - // fill the above variables, with a mapping of field name to struct - count := m.Elem.NumField() + // check if we have a dependencies field of struct type + dependenciesField, ok := m.Elem.FieldByName(dependencies) + if !ok { + return + } + + if dependenciesField.Type.Kind() != reflect.Struct { + panic("GetMeta: " + dependencies + " field (" + m.Name + ") is not a struct") + } + + // and initialize the type map of the given map + m.DCFields = make(map[string]reflect.Type) + m.DIFields = make(map[string]reflect.Type) + scanForFields(component, m.Name, dependenciesField.Type, true, m.DCFields, m.DIFields) +} + +// scanForFields scans the structtype for fields of component-like fields. +// they are then writen to the cFields and iFields maps. +// inDependenciesStruct indicates if we are inside a dependency struct +func scanForFields(component reflect.Type, elem string, structType reflect.Type, inDependenciesStruct bool, cFields map[string]reflect.Type, iFields map[string]reflect.Type) { + count := structType.NumField() for i := 0; i < count; i++ { - field := m.Elem.Field(i) + field := structType.Field(i) + + if !inDependenciesStruct && field.Tag.Get("auto") != "true" { + continue + } + if inDependenciesStruct && field.Tag != "" { + panic("GetMeta: " + dependencies + " field (" + elem + ") contains field (" + field.Name + ") with tag") + } - name := field.Name tp := field.Type + name := field.Name switch { - // field is a pointer to struct that implements a component - case tp.Implements(componentType) && tp.Kind() == reflect.Pointer && tp.Elem().Kind() == reflect.Struct: - m.CFields[name] = tp - - // field is []I, where I is an interface that implements component - case tp.Kind() == reflect.Slice && tp.Elem().Kind() == reflect.Interface && tp.Elem().Implements(componentType): - m.IFields[name] = tp.Elem() + case implementsComponent(component, tp): + cFields[name] = tp + case implementsSlice(component, tp): + iFields[name] = tp.Elem() + case inDependenciesStruct: + panic("GetMeta: " + dependencies + " field (" + elem + ") contains non-auto fields") } } } +func implementsComponent(component reflect.Type, tp reflect.Type) bool { + return tp.Implements(component) && tp.Kind() == reflect.Pointer && tp.Elem().Kind() == reflect.Struct +} + +func implementsSlice(component reflect.Type, tp reflect.Type) bool { + return tp.Kind() == reflect.Slice && tp.Elem().Kind() == reflect.Interface && tp.Elem().Implements(component) +} + func nameOf(tp reflect.Type) string { return tp.PkgPath() + "." + tp.Name() } @@ -79,12 +116,16 @@ func (m meta[Component]) New() Component { // NeedsInitComponent func (m meta[Component]) NeedsInitComponent() bool { - return len(m.CFields) > 0 || len(m.IFields) > 0 + return len(m.CFields) > 0 || len(m.IFields) > 0 || len(m.DCFields) > 0 || len(m.DIFields) > 0 } +// name of the dependencies field +const dependencies = "Dependencies" + // InitComponent sets up the fields of the given instance of a component. func (m meta[Component]) InitComponent(instance reflect.Value, all []Component) { elem := instance.Elem() + dependenciesElem := elem.FieldByName(dependencies) // assign the component fields for field, eType := range m.CFields { @@ -95,14 +136,28 @@ func (m meta[Component]) InitComponent(instance reflect.Value, all []Component) field := elem.FieldByName(field) field.Set(reflect.ValueOf(c)) } + for field, eType := range m.DCFields { + c := collection.First(all, func(c Component) bool { + return reflect.TypeOf(c).AssignableTo(eType) + }) - // assign the multi subtypes + field := dependenciesElem.FieldByName(field) + field.Set(reflect.ValueOf(c)) + } + + // assign the interface subtypes registryR := reflect.ValueOf(all) for field, eType := range m.IFields { cs := filterSubtype(registryR, eType) field := elem.FieldByName(field) field.Set(cs) } + for field, eType := range m.DIFields { + cs := filterSubtype(registryR, eType) + field := dependenciesElem.FieldByName(field) + field.Set(cs) + } + } // filterSubtype filters the slice of type []S into a slice of type []iface.