From 90e0c742951ff02ad2d2f7d0eef5aa0a611ddbe1 Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Fri, 27 Oct 2023 14:23:05 -0400 Subject: [PATCH] refactor: rename pkgs --- cmd/cmd.go | 71 +++ cmd/soft/{ => admin}/admin.go | 34 +- cmd/soft/{ => browse}/browse.go | 14 +- cmd/soft/{ => hook}/hook.go | 72 +-- cmd/soft/{root.go => main.go} | 82 ++-- cmd/soft/man.go | 27 -- cmd/soft/migrate_config.go | 434 ------------------ cmd/soft/{ => serve}/serve.go | 87 ++-- {server => cmd/soft/serve}/server.go | 20 +- {server => pkg}/access/access.go | 0 {server => pkg}/access/access_test.go | 0 {server => pkg}/access/context.go | 0 {server => pkg}/backend/access_token.go | 4 +- {server => pkg}/backend/auth.go | 0 {server => pkg}/backend/auth_test.go | 0 {server => pkg}/backend/backend.go | 8 +- {server => pkg}/backend/cache.go | 0 {server => pkg}/backend/collab.go | 12 +- {server => pkg}/backend/context.go | 0 {server => pkg}/backend/hooks.go | 8 +- {server => pkg}/backend/lfs.go | 12 +- {server => pkg}/backend/repo.go | 18 +- {server => pkg}/backend/settings.go | 4 +- {server => pkg}/backend/user.go | 12 +- {server => pkg}/backend/utils.go | 2 +- {server => pkg}/backend/webhooks.go | 10 +- {server => pkg}/config/config.go | 2 +- {server => pkg}/config/config_test.go | 0 {server => pkg}/config/context.go | 0 {server => pkg}/config/file.go | 0 {server => pkg}/config/ssh.go | 0 {server => pkg}/config/testdata/k1.pub | 0 {server => pkg}/cron/cron.go | 0 {server => pkg}/daemon/conn.go | 0 {server => pkg}/daemon/daemon.go | 10 +- {server => pkg}/daemon/daemon_test.go | 16 +- {server => pkg}/db/context.go | 0 {server => pkg}/db/db.go | 2 +- {server => pkg}/db/errors.go | 0 {server => pkg}/db/handler.go | 0 {server => pkg}/db/logger.go | 0 .../db/migrate/0001_create_tables.go | 8 +- .../0001_create_tables_postgres.down.sql | 0 .../0001_create_tables_postgres.up.sql | 0 .../0001_create_tables_sqlite.down.sql | 0 .../migrate/0001_create_tables_sqlite.up.sql | 0 {server => pkg}/db/migrate/0002_webhooks.go | 2 +- .../migrate/0002_webhooks_postgres.down.sql | 0 .../db/migrate/0002_webhooks_postgres.up.sql | 0 .../db/migrate/0002_webhooks_sqlite.down.sql | 0 .../db/migrate/0002_webhooks_sqlite.up.sql | 0 {server => pkg}/db/migrate/migrate.go | 2 +- {server => pkg}/db/migrate/migrations.go | 2 +- {server => pkg}/db/models/access_token.go | 0 {server => pkg}/db/models/collab.go | 2 +- {server => pkg}/db/models/lfs.go | 0 {server => pkg}/db/models/public_key.go | 0 {server => pkg}/db/models/repo.go | 0 {server => pkg}/db/models/settings.go | 0 {server => pkg}/db/models/user.go | 0 {server => pkg}/db/models/webhook.go | 0 {server => pkg}/git/errors.go | 0 {server => pkg}/git/git.go | 0 {server => pkg}/git/git_test.go | 0 {server => pkg}/git/lfs.go | 14 +- {server => pkg}/git/lfs_auth.go | 8 +- {server => pkg}/git/service.go | 0 {server => pkg}/hooks/gen.go | 4 +- {server => pkg}/hooks/hooks.go | 0 {server => pkg}/jobs/jobs.go | 0 {server => pkg}/jobs/mirror.go | 12 +- {server => pkg}/jwk/jwk.go | 2 +- {server => pkg}/lfs/basic_transfer.go | 0 {server => pkg}/lfs/client.go | 0 {server => pkg}/lfs/common.go | 0 {server => pkg}/lfs/endpoint.go | 0 {server => pkg}/lfs/http_client.go | 0 {server => pkg}/lfs/pointer.go | 0 {server => pkg}/lfs/pointer_test.go | 0 {server => pkg}/lfs/scanner.go | 0 {server => pkg}/lfs/ssh_client.go | 0 {server => pkg}/lfs/transfer.go | 0 {server => pkg}/log/log.go | 2 +- {server => pkg}/proto/access_token.go | 0 {server => pkg}/proto/context.go | 0 {server => pkg}/proto/errors.go | 0 {server => pkg}/proto/repo.go | 0 {server => pkg}/proto/user.go | 0 {server => pkg}/ssh/cmd/blob.go | 6 +- {server => pkg}/ssh/cmd/branch.go | 6 +- {server => pkg}/ssh/cmd/cmd.go | 12 +- {server => pkg}/ssh/cmd/collab.go | 4 +- {server => pkg}/ssh/cmd/commit.go | 6 +- {server => pkg}/ssh/cmd/create.go | 6 +- {server => pkg}/ssh/cmd/delete.go | 2 +- {server => pkg}/ssh/cmd/description.go | 2 +- {server => pkg}/ssh/cmd/git.go | 16 +- {server => pkg}/ssh/cmd/hidden.go | 2 +- {server => pkg}/ssh/cmd/import.go | 6 +- {server => pkg}/ssh/cmd/info.go | 4 +- {server => pkg}/ssh/cmd/jwt.go | 6 +- {server => pkg}/ssh/cmd/list.go | 6 +- {server => pkg}/ssh/cmd/mirror.go | 2 +- {server => pkg}/ssh/cmd/private.go | 2 +- {server => pkg}/ssh/cmd/project_name.go | 2 +- {server => pkg}/ssh/cmd/pubkey.go | 4 +- {server => pkg}/ssh/cmd/rename.go | 2 +- {server => pkg}/ssh/cmd/repo.go | 4 +- {server => pkg}/ssh/cmd/set_username.go | 4 +- {server => pkg}/ssh/cmd/settings.go | 4 +- {server => pkg}/ssh/cmd/tag.go | 6 +- {server => pkg}/ssh/cmd/token.go | 4 +- {server => pkg}/ssh/cmd/tree.go | 4 +- {server => pkg}/ssh/cmd/user.go | 6 +- {server => pkg}/ssh/cmd/webhooks.go | 4 +- {server => pkg}/ssh/middleware.go | 14 +- {server => pkg}/ssh/session.go | 10 +- {server => pkg}/ssh/session_test.go | 14 +- {server => pkg}/ssh/ssh.go | 10 +- {server => pkg}/ssh/ui.go | 14 +- {server => pkg}/sshutils/utils.go | 0 {server => pkg}/sshutils/utils_test.go | 0 {server => pkg}/stats/stats.go | 2 +- {server => pkg}/storage/local.go | 0 {server => pkg}/storage/storage.go | 0 {server => pkg}/store/access_token.go | 4 +- {server => pkg}/store/collab.go | 6 +- {server => pkg}/store/context.go | 0 .../store/database/access_token.go | 6 +- {server => pkg}/store/database/collab.go | 10 +- {server => pkg}/store/database/database.go | 6 +- {server => pkg}/store/database/lfs.go | 6 +- {server => pkg}/store/database/repo.go | 8 +- {server => pkg}/store/database/settings.go | 6 +- {server => pkg}/store/database/user.go | 10 +- {server => pkg}/store/database/webhooks.go | 6 +- {server => pkg}/store/lfs.go | 4 +- {server => pkg}/store/repo.go | 4 +- {server => pkg}/store/settings.go | 4 +- {server => pkg}/store/store.go | 0 {server => pkg}/store/user.go | 4 +- {server => pkg}/store/webhooks.go | 4 +- {server => pkg}/sync/workqueue.go | 0 {server => pkg}/sync/workqueue_test.go | 0 {server => pkg}/task/manager.go | 0 {server => pkg}/test/test.go | 0 {server => pkg}/ui/common/common.go | 8 +- {server => pkg}/ui/common/component.go | 0 {server => pkg}/ui/common/error.go | 0 {server => pkg}/ui/common/format.go | 2 +- {server => pkg}/ui/common/style.go | 0 {server => pkg}/ui/common/utils.go | 2 +- {server => pkg}/ui/components/code/code.go | 4 +- .../ui/components/footer/footer.go | 2 +- .../ui/components/header/header.go | 2 +- .../ui/components/selector/selector.go | 2 +- .../ui/components/statusbar/statusbar.go | 2 +- {server => pkg}/ui/components/tabs/tabs.go | 2 +- .../ui/components/viewport/viewport.go | 2 +- {server => pkg}/ui/keymap/keymap.go | 0 {server => pkg}/ui/pages/repo/empty.go | 4 +- {server => pkg}/ui/pages/repo/files.go | 8 +- {server => pkg}/ui/pages/repo/filesitem.go | 2 +- {server => pkg}/ui/pages/repo/log.go | 12 +- {server => pkg}/ui/pages/repo/logitem.go | 2 +- {server => pkg}/ui/pages/repo/readme.go | 8 +- {server => pkg}/ui/pages/repo/refs.go | 6 +- {server => pkg}/ui/pages/repo/refsitem.go | 2 +- {server => pkg}/ui/pages/repo/repo.go | 12 +- {server => pkg}/ui/pages/repo/stash.go | 8 +- {server => pkg}/ui/pages/repo/stashitem.go | 2 +- {server => pkg}/ui/pages/selection/item.go | 6 +- .../ui/pages/selection/selection.go | 12 +- {server => pkg}/ui/styles/styles.go | 0 {server => pkg}/utils/utils.go | 0 {server => pkg}/utils/utils_test.go | 0 {server => pkg}/version/version.go | 0 {server => pkg}/web/auth.go | 6 +- {server => pkg}/web/context.go | 8 +- {server => pkg}/web/git.go | 14 +- {server => pkg}/web/git_lfs.go | 18 +- {server => pkg}/web/goget.go | 6 +- {server => pkg}/web/http.go | 2 +- {server => pkg}/web/logging.go | 0 {server => pkg}/web/server.go | 0 {server => pkg}/web/util.go | 0 {server => pkg}/webhook/branch_tag.go | 8 +- {server => pkg}/webhook/collaborator.go | 8 +- {server => pkg}/webhook/common.go | 0 {server => pkg}/webhook/content_type.go | 0 {server => pkg}/webhook/event.go | 0 {server => pkg}/webhook/push.go | 8 +- {server => pkg}/webhook/repository.go | 8 +- {server => pkg}/webhook/webhook.go | 10 +- testscript/script_test.go | 20 +- 195 files changed, 556 insertions(+), 975 deletions(-) create mode 100644 cmd/cmd.go rename cmd/soft/{ => admin}/admin.go (61%) rename cmd/soft/{ => browse}/browse.go (95%) rename cmd/soft/{ => hook}/hook.go (68%) rename cmd/soft/{root.go => main.go} (62%) delete mode 100644 cmd/soft/man.go delete mode 100644 cmd/soft/migrate_config.go rename cmd/soft/{ => serve}/serve.go (55%) rename {server => cmd/soft/serve}/server.go (88%) rename {server => pkg}/access/access.go (100%) rename {server => pkg}/access/access_test.go (100%) rename {server => pkg}/access/context.go (100%) rename {server => pkg}/backend/access_token.go (94%) rename {server => pkg}/backend/auth.go (100%) rename {server => pkg}/backend/auth_test.go (100%) rename {server => pkg}/backend/backend.go (79%) rename {server => pkg}/backend/cache.go (100%) rename {server => pkg}/backend/collab.go (90%) rename {server => pkg}/backend/context.go (100%) rename {server => pkg}/backend/hooks.go (94%) rename {server => pkg}/backend/lfs.go (86%) rename {server => pkg}/backend/repo.go (97%) rename {server => pkg}/backend/settings.go (93%) rename {server => pkg}/backend/user.go (97%) rename {server => pkg}/backend/utils.go (92%) rename {server => pkg}/backend/webhooks.go (96%) rename {server => pkg}/config/config.go (99%) rename {server => pkg}/config/config_test.go (100%) rename {server => pkg}/config/context.go (100%) rename {server => pkg}/config/file.go (100%) rename {server => pkg}/config/ssh.go (100%) rename {server => pkg}/config/testdata/k1.pub (100%) rename {server => pkg}/cron/cron.go (100%) rename {server => pkg}/daemon/conn.go (100%) rename {server => pkg}/daemon/daemon.go (96%) rename {server => pkg}/daemon/daemon_test.go (85%) rename {server => pkg}/db/context.go (100%) rename {server => pkg}/db/db.go (97%) rename {server => pkg}/db/errors.go (100%) rename {server => pkg}/db/handler.go (100%) rename {server => pkg}/db/logger.go (100%) rename {server => pkg}/db/migrate/0001_create_tables.go (95%) rename {server => pkg}/db/migrate/0001_create_tables_postgres.down.sql (100%) rename {server => pkg}/db/migrate/0001_create_tables_postgres.up.sql (100%) rename {server => pkg}/db/migrate/0001_create_tables_sqlite.down.sql (100%) rename {server => pkg}/db/migrate/0001_create_tables_sqlite.up.sql (100%) rename {server => pkg}/db/migrate/0002_webhooks.go (89%) rename {server => pkg}/db/migrate/0002_webhooks_postgres.down.sql (100%) rename {server => pkg}/db/migrate/0002_webhooks_postgres.up.sql (100%) rename {server => pkg}/db/migrate/0002_webhooks_sqlite.down.sql (100%) rename {server => pkg}/db/migrate/0002_webhooks_sqlite.up.sql (100%) rename {server => pkg}/db/migrate/migrate.go (98%) rename {server => pkg}/db/migrate/migrations.go (96%) rename {server => pkg}/db/models/access_token.go (100%) rename {server => pkg}/db/models/collab.go (88%) rename {server => pkg}/db/models/lfs.go (100%) rename {server => pkg}/db/models/public_key.go (100%) rename {server => pkg}/db/models/repo.go (100%) rename {server => pkg}/db/models/settings.go (100%) rename {server => pkg}/db/models/user.go (100%) rename {server => pkg}/db/models/webhook.go (100%) rename {server => pkg}/git/errors.go (100%) rename {server => pkg}/git/git.go (100%) rename {server => pkg}/git/git_test.go (100%) rename {server => pkg}/git/lfs.go (97%) rename {server => pkg}/git/lfs_auth.go (91%) rename {server => pkg}/git/service.go (100%) rename {server => pkg}/hooks/gen.go (97%) rename {server => pkg}/hooks/hooks.go (100%) rename {server => pkg}/jobs/jobs.go (100%) rename {server => pkg}/jobs/mirror.go (90%) rename {server => pkg}/jwk/jwk.go (94%) rename {server => pkg}/lfs/basic_transfer.go (100%) rename {server => pkg}/lfs/client.go (100%) rename {server => pkg}/lfs/common.go (100%) rename {server => pkg}/lfs/endpoint.go (100%) rename {server => pkg}/lfs/http_client.go (100%) rename {server => pkg}/lfs/pointer.go (100%) rename {server => pkg}/lfs/pointer_test.go (100%) rename {server => pkg}/lfs/scanner.go (100%) rename {server => pkg}/lfs/ssh_client.go (100%) rename {server => pkg}/lfs/transfer.go (100%) rename {server => pkg}/log/log.go (94%) rename {server => pkg}/proto/access_token.go (100%) rename {server => pkg}/proto/context.go (100%) rename {server => pkg}/proto/errors.go (100%) rename {server => pkg}/proto/repo.go (100%) rename {server => pkg}/proto/user.go (100%) rename {server => pkg}/ssh/cmd/blob.go (92%) rename {server => pkg}/ssh/cmd/branch.go (96%) rename {server => pkg}/ssh/cmd/cmd.go (93%) rename {server => pkg}/ssh/cmd/collab.go (95%) rename {server => pkg}/ssh/cmd/commit.go (95%) rename {server => pkg}/ssh/cmd/create.go (89%) rename {server => pkg}/ssh/cmd/delete.go (90%) rename {server => pkg}/ssh/cmd/description.go (94%) rename {server => pkg}/ssh/cmd/git.go (95%) rename {server => pkg}/ssh/cmd/hidden.go (94%) rename {server => pkg}/ssh/cmd/import.go (91%) rename {server => pkg}/ssh/cmd/info.go (87%) rename {server => pkg}/ssh/cmd/jwt.go (88%) rename {server => pkg}/ssh/cmd/list.go (83%) rename {server => pkg}/ssh/cmd/mirror.go (91%) rename {server => pkg}/ssh/cmd/private.go (94%) rename {server => pkg}/ssh/cmd/project_name.go (94%) rename {server => pkg}/ssh/cmd/pubkey.go (94%) rename {server => pkg}/ssh/cmd/rename.go (91%) rename {server => pkg}/ssh/cmd/repo.go (95%) rename {server => pkg}/ssh/cmd/set_username.go (84%) rename {server => pkg}/ssh/cmd/settings.go (94%) rename {server => pkg}/ssh/cmd/tag.go (93%) rename {server => pkg}/ssh/cmd/token.go (96%) rename {server => pkg}/ssh/cmd/tree.go (94%) rename {server => pkg}/ssh/cmd/user.go (96%) rename {server => pkg}/ssh/cmd/webhooks.go (98%) rename {server => pkg}/ssh/middleware.go (92%) rename {server => pkg}/ssh/session.go (89%) rename {server => pkg}/ssh/session_test.go (85%) rename {server => pkg}/ssh/ssh.go (95%) rename {server => pkg}/ssh/ui.go (94%) rename {server => pkg}/sshutils/utils.go (100%) rename {server => pkg}/sshutils/utils_test.go (100%) rename {server => pkg}/stats/stats.go (95%) rename {server => pkg}/storage/local.go (100%) rename {server => pkg}/storage/storage.go (100%) rename {server => pkg}/store/access_token.go (87%) rename {server => pkg}/store/collab.go (80%) rename {server => pkg}/store/context.go (100%) rename {server => pkg}/store/database/access_token.go (94%) rename {server => pkg}/store/database/collab.go (91%) rename {server => pkg}/store/database/database.go (83%) rename {server => pkg}/store/database/lfs.go (97%) rename {server => pkg}/store/database/repo.go (96%) rename {server => pkg}/store/database/settings.go (91%) rename {server => pkg}/store/database/user.go (96%) rename {server => pkg}/store/database/webhooks.go (97%) rename {server => pkg}/store/lfs.go (94%) rename {server => pkg}/store/repo.go (93%) rename {server => pkg}/store/settings.go (80%) rename {server => pkg}/store/store.go (100%) rename {server => pkg}/store/user.go (93%) rename {server => pkg}/store/webhooks.go (96%) rename {server => pkg}/sync/workqueue.go (100%) rename {server => pkg}/sync/workqueue_test.go (100%) rename {server => pkg}/task/manager.go (100%) rename {server => pkg}/test/test.go (100%) rename {server => pkg}/ui/common/common.go (90%) rename {server => pkg}/ui/common/component.go (100%) rename {server => pkg}/ui/common/error.go (100%) rename {server => pkg}/ui/common/format.go (96%) rename {server => pkg}/ui/common/style.go (100%) rename {server => pkg}/ui/common/utils.go (94%) rename {server => pkg}/ui/components/code/code.go (97%) rename {server => pkg}/ui/components/footer/footer.go (97%) rename {server => pkg}/ui/components/header/header.go (93%) rename {server => pkg}/ui/components/selector/selector.go (99%) rename {server => pkg}/ui/components/statusbar/statusbar.go (97%) rename {server => pkg}/ui/components/tabs/tabs.go (97%) rename {server => pkg}/ui/components/viewport/viewport.go (97%) rename {server => pkg}/ui/keymap/keymap.go (100%) rename {server => pkg}/ui/pages/repo/empty.go (86%) rename {server => pkg}/ui/pages/repo/files.go (98%) rename {server => pkg}/ui/pages/repo/filesitem.go (98%) rename {server => pkg}/ui/pages/repo/log.go (97%) rename {server => pkg}/ui/pages/repo/logitem.go (98%) rename {server => pkg}/ui/pages/repo/readme.go (93%) rename {server => pkg}/ui/pages/repo/refs.go (97%) rename {server => pkg}/ui/pages/repo/refsitem.go (98%) rename {server => pkg}/ui/pages/repo/repo.go (96%) rename {server => pkg}/ui/pages/repo/stash.go (96%) rename {server => pkg}/ui/pages/repo/stashitem.go (97%) rename {server => pkg}/ui/pages/selection/item.go (97%) rename {server => pkg}/ui/pages/selection/selection.go (95%) rename {server => pkg}/ui/styles/styles.go (100%) rename {server => pkg}/utils/utils.go (100%) rename {server => pkg}/utils/utils_test.go (100%) rename {server => pkg}/version/version.go (100%) rename {server => pkg}/web/auth.go (96%) rename {server => pkg}/web/context.go (80%) rename {server => pkg}/web/git.go (97%) rename {server => pkg}/web/git_lfs.go (98%) rename {server => pkg}/web/goget.go (94%) rename {server => pkg}/web/http.go (96%) rename {server => pkg}/web/logging.go (100%) rename {server => pkg}/web/server.go (100%) rename {server => pkg}/web/util.go (100%) rename {server => pkg}/webhook/branch_tag.go (91%) rename {server => pkg}/webhook/collaborator.go (91%) rename {server => pkg}/webhook/common.go (100%) rename {server => pkg}/webhook/content_type.go (100%) rename {server => pkg}/webhook/event.go (100%) rename {server => pkg}/webhook/push.go (92%) rename {server => pkg}/webhook/repository.go (92%) rename {server => pkg}/webhook/webhook.go (92%) diff --git a/cmd/cmd.go b/cmd/cmd.go new file mode 100644 index 000000000..9aead6369 --- /dev/null +++ b/cmd/cmd.go @@ -0,0 +1,71 @@ +package cmd + +import ( + "context" + "errors" + "fmt" + "io/fs" + "os" + + "github.com/charmbracelet/soft-serve/pkg/backend" + "github.com/charmbracelet/soft-serve/pkg/config" + "github.com/charmbracelet/soft-serve/pkg/db" + "github.com/charmbracelet/soft-serve/pkg/hooks" + "github.com/charmbracelet/soft-serve/pkg/store" + "github.com/charmbracelet/soft-serve/pkg/store/database" + "github.com/spf13/cobra" +) + +// InitBackendContext initializes the backend context. +func InitBackendContext(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + cfg := config.FromContext(ctx) + if _, err := os.Stat(cfg.DataPath); errors.Is(err, fs.ErrNotExist) { + if err := os.MkdirAll(cfg.DataPath, os.ModePerm); err != nil { + return fmt.Errorf("create data directory: %w", err) + } + } + dbx, err := db.Open(ctx, cfg.DB.Driver, cfg.DB.DataSource) + if err != nil { + return fmt.Errorf("open database: %w", err) + } + + ctx = db.WithContext(ctx, dbx) + dbstore := database.New(ctx, dbx) + ctx = store.WithContext(ctx, dbstore) + be := backend.New(ctx, cfg, dbx) + ctx = backend.WithContext(ctx, be) + + cmd.SetContext(ctx) + + return nil +} + +// CloseDBContext closes the database context. +func CloseDBContext(cmd *cobra.Command, _ []string) error { + ctx := cmd.Context() + dbx := db.FromContext(ctx) + if dbx != nil { + if err := dbx.Close(); err != nil { + return fmt.Errorf("close database: %w", err) + } + } + + return nil +} + +// InitializeHooks initializes the hooks. +func InitializeHooks(ctx context.Context, cfg *config.Config, be *backend.Backend) error { + repos, err := be.Repositories(ctx) + if err != nil { + return err + } + + for _, repo := range repos { + if err := hooks.GenerateHooks(ctx, cfg, repo.Name()); err != nil { + return err + } + } + + return nil +} diff --git a/cmd/soft/admin.go b/cmd/soft/admin/admin.go similarity index 61% rename from cmd/soft/admin.go rename to cmd/soft/admin/admin.go index 16d31f278..7138f5754 100644 --- a/cmd/soft/admin.go +++ b/cmd/soft/admin/admin.go @@ -1,17 +1,19 @@ -package main +package admin import ( "fmt" - "github.com/charmbracelet/soft-serve/server/backend" - "github.com/charmbracelet/soft-serve/server/config" - "github.com/charmbracelet/soft-serve/server/db" - "github.com/charmbracelet/soft-serve/server/db/migrate" + "github.com/charmbracelet/soft-serve/cmd" + "github.com/charmbracelet/soft-serve/pkg/backend" + "github.com/charmbracelet/soft-serve/pkg/config" + "github.com/charmbracelet/soft-serve/pkg/db" + "github.com/charmbracelet/soft-serve/pkg/db/migrate" "github.com/spf13/cobra" ) var ( - adminCmd = &cobra.Command{ + // Command is the admin command. + Command = &cobra.Command{ Use: "admin", Short: "Administrate the server", } @@ -19,8 +21,8 @@ var ( migrateCmd = &cobra.Command{ Use: "migrate", Short: "Migrate the database to the latest version", - PersistentPreRunE: initBackendContext, - PersistentPostRunE: closeDBContext, + PersistentPreRunE: cmd.InitBackendContext, + PersistentPostRunE: cmd.CloseDBContext, RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() db := db.FromContext(ctx) @@ -35,8 +37,8 @@ var ( rollbackCmd = &cobra.Command{ Use: "rollback", Short: "Rollback the database to the previous version", - PersistentPreRunE: initBackendContext, - PersistentPostRunE: closeDBContext, + PersistentPreRunE: cmd.InitBackendContext, + PersistentPostRunE: cmd.CloseDBContext, RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() db := db.FromContext(ctx) @@ -51,13 +53,13 @@ var ( syncHooksCmd = &cobra.Command{ Use: "sync-hooks", Short: "Update repository hooks", - PersistentPreRunE: initBackendContext, - PersistentPostRunE: closeDBContext, - RunE: func(cmd *cobra.Command, _ []string) error { - ctx := cmd.Context() + PersistentPreRunE: cmd.InitBackendContext, + PersistentPostRunE: cmd.CloseDBContext, + RunE: func(c *cobra.Command, _ []string) error { + ctx := c.Context() cfg := config.FromContext(ctx) be := backend.FromContext(ctx) - if err := initializeHooks(ctx, cfg, be); err != nil { + if err := cmd.InitializeHooks(ctx, cfg, be); err != nil { return fmt.Errorf("initialize hooks: %w", err) } @@ -67,7 +69,7 @@ var ( ) func init() { - adminCmd.AddCommand( + Command.AddCommand( syncHooksCmd, migrateCmd, rollbackCmd, diff --git a/cmd/soft/browse.go b/cmd/soft/browse/browse.go similarity index 95% rename from cmd/soft/browse.go rename to cmd/soft/browse/browse.go index 8cb760198..43fa3e612 100644 --- a/cmd/soft/browse.go +++ b/cmd/soft/browse/browse.go @@ -1,4 +1,4 @@ -package main +package browse import ( "fmt" @@ -9,15 +9,16 @@ import ( tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" "github.com/charmbracelet/soft-serve/git" - "github.com/charmbracelet/soft-serve/server/proto" - "github.com/charmbracelet/soft-serve/server/ui/common" - "github.com/charmbracelet/soft-serve/server/ui/components/footer" - "github.com/charmbracelet/soft-serve/server/ui/pages/repo" + "github.com/charmbracelet/soft-serve/pkg/proto" + "github.com/charmbracelet/soft-serve/pkg/ui/common" + "github.com/charmbracelet/soft-serve/pkg/ui/components/footer" + "github.com/charmbracelet/soft-serve/pkg/ui/pages/repo" "github.com/muesli/termenv" "github.com/spf13/cobra" ) -var browseCmd = &cobra.Command{ +// Command is the browse command. +var Command = &cobra.Command{ Use: "browse PATH", Short: "Browse a repository", Args: cobra.MaximumNArgs(1), @@ -72,7 +73,6 @@ func init() { // HACK: This is a hack to hide the clone url // TODO: Make this configurable common.CloneCmd = func(publicURL, name string) string { return "" } - rootCmd.AddCommand(browseCmd) } type state int diff --git a/cmd/soft/hook.go b/cmd/soft/hook/hook.go similarity index 68% rename from cmd/soft/hook.go rename to cmd/soft/hook/hook.go index 1bb32b4ea..43718ed22 100644 --- a/cmd/soft/hook.go +++ b/cmd/soft/hook/hook.go @@ -1,4 +1,4 @@ -package main +package hook import ( "bufio" @@ -13,9 +13,10 @@ import ( "strings" "github.com/charmbracelet/log" - "github.com/charmbracelet/soft-serve/server/backend" - "github.com/charmbracelet/soft-serve/server/config" - "github.com/charmbracelet/soft-serve/server/hooks" + "github.com/charmbracelet/soft-serve/cmd" + "github.com/charmbracelet/soft-serve/pkg/backend" + "github.com/charmbracelet/soft-serve/pkg/config" + "github.com/charmbracelet/soft-serve/pkg/hooks" "github.com/spf13/cobra" ) @@ -26,23 +27,24 @@ var ( // Deprecated: this flag is ignored. configPath string - hookCmd = &cobra.Command{ + // Command is the hook command. + Command = &cobra.Command{ Use: "hook", Short: "Run git server hooks", Long: "Handles Soft Serve git server hooks.", Hidden: true, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - logger := log.FromContext(cmd.Context()) - if err := initBackendContext(cmd, args); err != nil { + PersistentPreRunE: func(c *cobra.Command, args []string) error { + logger := log.FromContext(c.Context()) + if err := cmd.InitBackendContext(c, args); err != nil { logger.Error("failed to initialize backend context", "err", err) return ErrInternalServerError } return nil }, - PersistentPostRunE: func(cmd *cobra.Command, args []string) error { - logger := log.FromContext(cmd.Context()) - if err := closeDBContext(cmd, args); err != nil { + PersistentPostRunE: func(c *cobra.Command, args []string) error { + logger := log.FromContext(c.Context()) + if err := cmd.CloseDBContext(c, args); err != nil { logger.Error("failed to close backend", "err", err) return ErrInternalServerError } @@ -147,8 +149,8 @@ var ( ) func init() { - hookCmd.PersistentFlags().StringVar(&configPath, "config", "", "path to config file (deprecated)") - hookCmd.AddCommand( + Command.PersistentFlags().StringVar(&configPath, "config", "", "path to config file (deprecated)") + Command.AddCommand( preReceiveCmd, updateCmd, postReceiveCmd, @@ -163,47 +165,3 @@ func runCommand(ctx context.Context, in io.Reader, out io.Writer, err io.Writer, cmd.Stderr = err return cmd.Run() } - -const updateHookExample = `#!/bin/sh -# -# An example hook script to echo information about the push -# and send it to the client. -# -# To enable this hook, rename this file to "update" and make it executable. - -refname="$1" -oldrev="$2" -newrev="$3" - -# Safety check -if [ -z "$GIT_DIR" ]; then - echo "Don't run this script from the command line." >&2 - echo " (if you want, you could supply GIT_DIR then run" >&2 - echo " $0 )" >&2 - exit 1 -fi - -if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then - echo "usage: $0 " >&2 - exit 1 -fi - -# Check types -# if $newrev is 0000...0000, it's a commit to delete a ref. -zero=$(git hash-object --stdin = 0 { - if err := sb.SetAnonAccess(ctx, anon); err != nil { - fmt.Fprintf(os.Stderr, "failed to set anon access: %s\n", err) - } - } - - // Copy repos - if reposPath != "" { - logger.Info("Copying repos...") - if err := os.MkdirAll(filepath.Join(cfg.DataPath, "repos"), os.ModePerm); err != nil { - return fmt.Errorf("failed to create repos directory: %w", err) - } - - dirs, err := os.ReadDir(reposPath) - if err != nil { - return fmt.Errorf("failed to read repos directory: %w", err) - } - - for _, dir := range dirs { - if !dir.IsDir() || dir.Name() == "config" { - continue - } - - if !isGitDir(filepath.Join(reposPath, dir.Name())) { - continue - } - - logger.Infof(" Copying repo %s", dir.Name()) - src := filepath.Join(reposPath, utils.SanitizeRepo(dir.Name())) - dst := filepath.Join(cfg.DataPath, "repos", utils.SanitizeRepo(dir.Name())) + ".git" - if err := os.MkdirAll(dst, os.ModePerm); err != nil { - return fmt.Errorf("failed to create repo directory: %w", err) - } - - if err := copyDir(src, dst); err != nil { - return fmt.Errorf("failed to copy repo: %w", err) - } - - if _, err := sb.CreateRepository(ctx, dir.Name(), nil, proto.RepositoryOptions{}); err != nil { - fmt.Fprintf(os.Stderr, "failed to create repository: %s\n", err) - } - } - - if hasReadme { - logger.Infof(" Copying readme from \"config\" to \".soft-serve\"") - - // Switch to main branch - bcmd := git.NewCommand("branch", "-M", "main") - - rp := filepath.Join(cfg.DataPath, "repos", ".soft-serve.git") - nr, err := git.Init(rp, true) - if err != nil { - return fmt.Errorf("failed to init repo: %w", err) - } - - if _, err := nr.SymbolicRef("HEAD", gitm.RefsHeads+"main"); err != nil { - return fmt.Errorf("failed to set HEAD: %w", err) - } - - tmpDir, err := os.MkdirTemp("", "soft-serve") - if err != nil { - return fmt.Errorf("failed to create temp dir: %w", err) - } - - r, err := git.Init(tmpDir, false) - if err != nil { - return fmt.Errorf("failed to clone repo: %w", err) - } - - if _, err := bcmd.RunInDir(tmpDir); err != nil { - return fmt.Errorf("failed to create main branch: %w", err) - } - - if err := os.WriteFile(filepath.Join(tmpDir, readmePath), []byte(readme), 0o644); err != nil { // nolint: gosec - return fmt.Errorf("failed to write readme: %w", err) - } - - if err := r.Add(gitm.AddOptions{ - All: true, - }); err != nil { - return fmt.Errorf("failed to add readme: %w", err) - } - - if err := r.Commit(&gitm.Signature{ - Name: "Soft Serve", - Email: "vt100@charm.sh", - When: time.Now(), - }, "Add readme"); err != nil { - return fmt.Errorf("failed to commit readme: %w", err) - } - - if err := r.RemoteAdd("origin", "file://"+rp); err != nil { - return fmt.Errorf("failed to add remote: %w", err) - } - - if err := r.Push("origin", "main"); err != nil { - return fmt.Errorf("failed to push readme: %w", err) - } - - // Create `.soft-serve` repository and add readme - if _, err := sb.CreateRepository(ctx, ".soft-serve", nil, proto.RepositoryOptions{ - ProjectName: "Home", - Description: "Soft Serve home repository", - Hidden: true, - Private: false, - }); err != nil { - fmt.Fprintf(os.Stderr, "failed to create repository: %s\n", err) - } - } - } - - // Set repos metadata & collabs - logger.Info("Setting repos metadata & collabs...") - for _, r := range ocfg.Repos { - repo, name := r.Repo, r.Name - // Special case for config repo - if repo == "config" { - repo = ".soft-serve" - r.Private = false - } - - if err := sb.SetProjectName(ctx, repo, name); err != nil { - logger.Errorf("failed to set repo name to %s: %s", repo, err) - } - - if err := sb.SetDescription(ctx, repo, r.Note); err != nil { - logger.Errorf("failed to set repo description to %s: %s", repo, err) - } - - if err := sb.SetPrivate(ctx, repo, r.Private); err != nil { - logger.Errorf("failed to set repo private to %s: %s", repo, err) - } - - for _, collab := range r.Collabs { - if err := sb.AddCollaborator(ctx, repo, collab, access.ReadWriteAccess); err != nil { - logger.Errorf("failed to add repo collab to %s: %s", repo, err) - } - } - } - - // Create users & collabs - logger.Info("Creating users & collabs...") - for _, user := range ocfg.Users { - keys := make(map[string]ssh.PublicKey) - for _, key := range user.PublicKeys { - pk, _, err := sshutils.ParseAuthorizedKey(key) - if err != nil { - continue - } - ak := sshutils.MarshalAuthorizedKey(pk) - keys[ak] = pk - } - - pubkeys := make([]ssh.PublicKey, 0) - for _, pk := range keys { - pubkeys = append(pubkeys, pk) - } - - username := strings.ToLower(user.Name) - username = strings.ReplaceAll(username, " ", "-") - logger.Infof("Creating user %q", username) - if _, err := sb.CreateUser(ctx, username, proto.UserOptions{ - Admin: user.Admin, - PublicKeys: pubkeys, - }); err != nil { - logger.Errorf("failed to create user: %s", err) - } - - for _, repo := range user.CollabRepos { - if err := sb.AddCollaborator(ctx, repo, username, access.ReadWriteAccess); err != nil { - logger.Errorf("failed to add user collab to %s: %s\n", repo, err) - } - } - } - - logger.Info("Writing config...") - defer logger.Info("Done!") - return cfg.WriteConfig() - }, -} - -// Returns true if path is a directory containing an `objects` directory and a -// `HEAD` file. -func isGitDir(path string) bool { - stat, err := os.Stat(filepath.Join(path, "objects")) - if err != nil { - return false - } - if !stat.IsDir() { - return false - } - - stat, err = os.Stat(filepath.Join(path, "HEAD")) - if err != nil { - return false - } - if stat.IsDir() { - return false - } - - return true -} - -// copyFile copies a single file from src to dst. -func copyFile(src, dst string) error { - var err error - var srcfd *os.File - var dstfd *os.File - var srcinfo os.FileInfo - - if srcfd, err = os.Open(src); err != nil { - return err - } - defer srcfd.Close() // nolint: errcheck - - if dstfd, err = os.Create(dst); err != nil { - return err - } - defer dstfd.Close() // nolint: errcheck - - if _, err = io.Copy(dstfd, srcfd); err != nil { - return err - } - if srcinfo, err = os.Stat(src); err != nil { - return err - } - return os.Chmod(dst, srcinfo.Mode()) -} - -// copyDir copies a whole directory recursively. -func copyDir(src string, dst string) error { - var err error - var fds []os.DirEntry - var srcinfo os.FileInfo - - if srcinfo, err = os.Stat(src); err != nil { - return err - } - - if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil { - return err - } - - if fds, err = os.ReadDir(src); err != nil { - return err - } - - for _, fd := range fds { - srcfp := filepath.Join(src, fd.Name()) - dstfp := filepath.Join(dst, fd.Name()) - - if fd.IsDir() { - if err = copyDir(srcfp, dstfp); err != nil { - err = errors.Join(err, err) - } - } else { - if err = copyFile(srcfp, dstfp); err != nil { - err = errors.Join(err, err) - } - } - } - - return err -} - -// Config is the configuration for the server. -type Config struct { - Name string `yaml:"name" json:"name"` - Host string `yaml:"host" json:"host"` - Port int `yaml:"port" json:"port"` - AnonAccess string `yaml:"anon-access" json:"anon-access"` - AllowKeyless bool `yaml:"allow-keyless" json:"allow-keyless"` - Users []User `yaml:"users" json:"users"` - Repos []RepoConfig `yaml:"repos" json:"repos"` -} - -// User contains user-level configuration for a repository. -type User struct { - Name string `yaml:"name" json:"name"` - Admin bool `yaml:"admin" json:"admin"` - PublicKeys []string `yaml:"public-keys" json:"public-keys"` - CollabRepos []string `yaml:"collab-repos" json:"collab-repos"` -} - -// RepoConfig is a repository configuration. -type RepoConfig struct { - Name string `yaml:"name" json:"name"` - Repo string `yaml:"repo" json:"repo"` - Note string `yaml:"note" json:"note"` - Private bool `yaml:"private" json:"private"` - Readme string `yaml:"readme" json:"readme"` - Collabs []string `yaml:"collabs" json:"collabs"` -} diff --git a/cmd/soft/serve.go b/cmd/soft/serve/serve.go similarity index 55% rename from cmd/soft/serve.go rename to cmd/soft/serve/serve.go index 0111f311a..7f81dcf0f 100644 --- a/cmd/soft/serve.go +++ b/cmd/soft/serve/serve.go @@ -1,4 +1,4 @@ -package main +package serve import ( "context" @@ -9,26 +9,26 @@ import ( "syscall" "time" - "github.com/charmbracelet/soft-serve/server" - "github.com/charmbracelet/soft-serve/server/backend" - "github.com/charmbracelet/soft-serve/server/config" - "github.com/charmbracelet/soft-serve/server/db" - "github.com/charmbracelet/soft-serve/server/db/migrate" - "github.com/charmbracelet/soft-serve/server/hooks" + "github.com/charmbracelet/soft-serve/cmd" + "github.com/charmbracelet/soft-serve/pkg/backend" + "github.com/charmbracelet/soft-serve/pkg/config" + "github.com/charmbracelet/soft-serve/pkg/db" + "github.com/charmbracelet/soft-serve/pkg/db/migrate" "github.com/spf13/cobra" ) var ( syncHooks bool - serveCmd = &cobra.Command{ + // Command is the serve command. + Command = &cobra.Command{ Use: "serve", Short: "Start the server", Args: cobra.NoArgs, - PersistentPreRunE: initBackendContext, - PersistentPostRunE: closeDBContext, - RunE: func(cmd *cobra.Command, _ []string) error { - ctx := cmd.Context() + PersistentPreRunE: cmd.InitBackendContext, + PersistentPostRunE: cmd.CloseDBContext, + RunE: func(c *cobra.Command, _ []string) error { + ctx := c.Context() cfg := config.DefaultConfig() if cfg.Exist() { if err := cfg.ParseFile(); err != nil { @@ -67,14 +67,14 @@ var ( return fmt.Errorf("migration error: %w", err) } - s, err := server.NewServer(ctx) + s, err := NewServer(ctx) if err != nil { return fmt.Errorf("start server: %w", err) } if syncHooks { be := backend.FromContext(ctx) - if err := initializeHooks(ctx, cfg, be); err != nil { + if err := cmd.InitializeHooks(ctx, cfg, be); err != nil { return fmt.Errorf("initialize hooks: %w", err) } } @@ -103,20 +103,49 @@ var ( ) func init() { - serveCmd.Flags().BoolVarP(&syncHooks, "sync-hooks", "", false, "synchronize hooks for all repositories before running the server") + Command.Flags().BoolVarP(&syncHooks, "sync-hooks", "", false, "synchronize hooks for all repositories before running the server") } -func initializeHooks(ctx context.Context, cfg *config.Config, be *backend.Backend) error { - repos, err := be.Repositories(ctx) - if err != nil { - return err - } - - for _, repo := range repos { - if err := hooks.GenerateHooks(ctx, cfg, repo.Name()); err != nil { - return err - } - } - - return nil -} +const updateHookExample = `#!/bin/sh +# +# An example hook script to echo information about the push +# and send it to the client. +# +# To enable this hook, rename this file to "update" and make it executable. + +refname="$1" +oldrev="$2" +newrev="$3" + +# Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 " >&2 + exit 1 +fi + +# Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero=$(git hash-object --stdin