Skip to content

Commit

Permalink
refactor: combine migrations into one
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Aug 4, 2023
1 parent ea6b9a4 commit b3d5ce8
Show file tree
Hide file tree
Showing 23 changed files with 265 additions and 322 deletions.
82 changes: 44 additions & 38 deletions server/backend/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"fmt"
"io/fs"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
Expand Down Expand Up @@ -105,19 +104,23 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.
return nil, proto.ErrRepoExist
}

if err := os.MkdirAll(rp, fs.ModePerm); err != nil {
return nil, err
copts := git.CloneOptions{
Bare: true,
Mirror: opts.Mirror,
Quiet: true,
CommandOptions: git.CommandOptions{
Timeout: -1,
Context: ctx,
Envs: []string{
fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
filepath.Join(d.cfg.DataPath, "ssh", "known_hosts"),
d.cfg.SSH.ClientKeyPath,
),
},
},
}

cmd := exec.CommandContext(ctx, "git", "clone", "--bare", "--mirror", remote, ".")
cmd.Env = append(cmd.Env,
fmt.Sprintf(`GIT_SSH_COMMAND=ssh -o UserKnownHostsFile="%s" -o StrictHostKeyChecking=no -i "%s"`,
filepath.Join(d.cfg.DataPath, "ssh", "known_hosts"),
d.cfg.SSH.ClientKeyPath,
),
)
cmd.Dir = rp
if err := cmd.Run(); err != nil {
if err := git.Clone(remote, rp, copts); err != nil {
d.logger.Error("failed to clone repository", "err", err, "mirror", opts.Mirror, "remote", remote, "path", rp)
// Cleanup the mess!
if rerr := os.RemoveAll(rp); rerr != nil {
Expand All @@ -135,7 +138,7 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.

defer func() {
if err != nil {
if rerr := d.DeleteRepository(ctx, name, opts.LFS); rerr != nil {
if rerr := d.DeleteRepository(ctx, name); rerr != nil {
d.logger.Error("failed to delete repository", "err", rerr, "name", name)
}
}
Expand Down Expand Up @@ -187,51 +190,54 @@ func (d *Backend) ImportRepository(ctx context.Context, name string, user proto.
// DeleteRepository deletes a repository.
//
// It implements backend.Backend.
func (d *Backend) DeleteRepository(ctx context.Context, name string, deleteLFS bool) error {
func (d *Backend) DeleteRepository(ctx context.Context, name string) error {
name = utils.SanitizeRepo(name)
repo := name + ".git"
rp := filepath.Join(d.reposPath(), repo)

return d.db.TransactionContext(ctx, func(tx *db.Tx) error {
err := d.db.TransactionContext(ctx, func(tx *db.Tx) error {
// Delete repo from cache
defer d.cache.Delete(name)

if deleteLFS {
repom, err := d.store.GetRepoByName(ctx, tx, name)
if err != nil {
return err
}
repom, err := d.store.GetRepoByName(ctx, tx, name)
if err != nil {
return db.WrapError(err)
}

repoID := strconv.FormatInt(repom.ID, 10)
strg := storage.NewLocalStorage(filepath.Join(d.cfg.DataPath, "lfs", repoID))
objs, err := d.store.GetLFSObjectsByName(ctx, tx, name)
if err != nil {
return err
}
repoID := strconv.FormatInt(repom.ID, 10)
strg := storage.NewLocalStorage(filepath.Join(d.cfg.DataPath, "lfs", repoID))
objs, err := d.store.GetLFSObjectsByName(ctx, tx, name)
if err != nil {
return db.WrapError(err)
}

for _, obj := range objs {
p := lfs.Pointer{
Oid: obj.Oid,
Size: obj.Size,
}
for _, obj := range objs {
p := lfs.Pointer{
Oid: obj.Oid,
Size: obj.Size,
}

d.logger.Debug("deleting lfs object", "repo", name, "oid", obj.Oid)
if err := strg.Delete(path.Join("objects", p.RelativePath())); err != nil {
d.logger.Error("failed to delete lfs object", "repo", name, "err", err, "oid", obj.Oid)
}
d.logger.Debug("deleting lfs object", "repo", name, "oid", obj.Oid)
if err := strg.Delete(path.Join("objects", p.RelativePath())); err != nil {
d.logger.Error("failed to delete lfs object", "repo", name, "err", err, "oid", obj.Oid)
}
}

if err := d.store.DeleteRepoByName(ctx, tx, name); err != nil {
return err
return db.WrapError(err)
}

return os.RemoveAll(rp)
})
if errors.Is(err, db.ErrRecordNotFound) {
return proto.ErrRepoNotFound
}

return err
}

// DeleteUserRepositories deletes all user repositories.
func (d *Backend) DeleteUserRepositories(ctx context.Context, username string, deleteLFS bool) error {
func (d *Backend) DeleteUserRepositories(ctx context.Context, username string) error {
return d.db.TransactionContext(ctx, func(tx *db.Tx) error {
user, err := d.store.FindUserByUsername(ctx, tx, username)
if err != nil {
Expand All @@ -244,7 +250,7 @@ func (d *Backend) DeleteUserRepositories(ctx context.Context, username string, d
}

for _, repo := range repos {
if err := d.DeleteRepository(ctx, repo.Name, deleteLFS); err != nil {
if err := d.DeleteRepository(ctx, repo.Name); err != nil {
return err
}
}
Expand Down
4 changes: 4 additions & 0 deletions server/db/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ package db
import (
"context"
"database/sql"
"strings"

"github.com/charmbracelet/log"
"github.com/jmoiron/sqlx"
)

func trace(l *log.Logger, query string, args ...interface{}) {
if l != nil {
// Remove newlines and tabs
query = strings.ReplaceAll(query, "\t", "")
query = strings.TrimSpace(query)
l.Debug("trace", "query", query, "args", args)
}
}
Expand Down
91 changes: 68 additions & 23 deletions server/db/migrate/0001_create_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,65 +25,110 @@ var createTables = Migration{
insert := "INSERT "

// Alter old tables (if exist)
// This is to support prior versions of Soft Serve
// This is to support prior versions of Soft Serve v0.6
switch tx.DriverName() {
case "sqlite3", "sqlite":
insert += "OR IGNORE "

hasUserTable := hasTable(tx, "user")
if hasUserTable {
if _, err := tx.ExecContext(ctx, "ALTER TABLE user RENAME TO users"); err != nil {
if _, err := tx.ExecContext(ctx, "ALTER TABLE user RENAME TO user_old"); err != nil {
return err
}
}

if hasTable(tx, "public_key") {
if _, err := tx.ExecContext(ctx, "ALTER TABLE public_key RENAME TO public_keys"); err != nil {
if _, err := tx.ExecContext(ctx, "ALTER TABLE public_key RENAME TO public_key_old"); err != nil {
return err
}
}

if hasTable(tx, "collab") {
if _, err := tx.ExecContext(ctx, "ALTER TABLE collab RENAME TO collabs"); err != nil {
if _, err := tx.ExecContext(ctx, "ALTER TABLE collab RENAME TO collab_old"); err != nil {
return err
}
}

if hasTable(tx, "repo") {
if _, err := tx.ExecContext(ctx, "ALTER TABLE repo RENAME TO repos"); err != nil {
if _, err := tx.ExecContext(ctx, "ALTER TABLE repo RENAME TO repo_old"); err != nil {
return err
}
}
}

// Fix username being nullable
if hasUserTable {
if err := migrateUp(ctx, tx, createTablesVersion, createTablesName); err != nil {
return err
}

switch tx.DriverName() {
case "sqlite3", "sqlite":

if _, err := tx.ExecContext(ctx, "PRAGMA foreign_keys = OFF"); err != nil {
return err
}

if hasTable(tx, "user_old") {
sqlm := `
PRAGMA foreign_keys = OFF;
INSERT INTO users (id, username, admin, updated_at)
SELECT id, username, admin, updated_at FROM user_old;
`
if _, err := tx.ExecContext(ctx, sqlm); err != nil {
return err
}
}

CREATE TABLE users_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
admin BOOLEAN NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL
);
if hasTable(tx, "public_key_old") {
// Check duplicate keys
pks := []struct {
ID string `db:"id"`
PublicKey string `db:"public_key"`
}{}
if err := tx.SelectContext(ctx, &pks, "SELECT id, public_key FROM public_key_old"); err != nil {
return err
}

INSERT INTO users_new (username, admin, updated_at)
SELECT username, admin, updated_at FROM users;
pkss := map[string]struct{}{}
for _, pk := range pks {
if _, ok := pkss[pk.PublicKey]; ok {
return fmt.Errorf("duplicate public key: %q, please remove the duplicate key and try again", pk.PublicKey)
}
pkss[pk.PublicKey] = struct{}{}
}

DROP TABLE users;
ALTER TABLE users_new RENAME TO users;
sqlm := `
INSERT INTO public_keys (id, user_id, public_key, created_at, updated_at)
SELECT id, user_id, public_key, created_at, updated_at FROM public_key_old;
`
if _, err := tx.ExecContext(ctx, sqlm); err != nil {
return err
}
}

PRAGMA foreign_keys = ON;
if hasTable(tx, "repo_old") {
sqlm := `
INSERT INTO repos (id, name, project_name, description, private,mirror, hidden, created_at, updated_at, user_id)
SELECT id, name, project_name, description, private, mirror, hidden, created_at, updated_at, (
SELECT id FROM users WHERE admin = true ORDER BY id LIMIT 1
) FROM repo_old;
`
if _, err := tx.ExecContext(ctx, sqlm); err != nil {
return err
}
}
}

if err := migrateUp(ctx, tx, createTablesVersion, createTablesName); err != nil {
return err
if hasTable(tx, "collab_old") {
sqlm := `
INSERT INTO collabs (id, user_id, repo_id, created_at, updated_at)
SELECT id, user_id, repo_id, created_at, updated_at FROM collab_old;
`
if _, err := tx.ExecContext(ctx, sqlm); err != nil {
return err
}
}

if _, err := tx.ExecContext(ctx, "PRAGMA foreign_keys = ON"); err != nil {
return err
}
}

// Insert default user
Expand Down
Loading

0 comments on commit b3d5ce8

Please sign in to comment.