grafana/pkg/services/export/commit_helper.go
Jo 062d255124
Handle ioutil deprecations (#53526)
* replace ioutil.ReadFile -> os.ReadFile

* replace ioutil.ReadAll -> io.ReadAll

* replace ioutil.TempFile -> os.CreateTemp

* replace ioutil.NopCloser -> io.NopCloser

* replace ioutil.WriteFile -> os.WriteFile

* replace ioutil.TempDir -> os.MkdirTemp

* replace ioutil.Discard -> io.Discard
2022-08-10 15:37:51 +02:00

173 lines
4.0 KiB
Go

package export
import (
"context"
"fmt"
"os"
"path"
"strings"
"time"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/services/sqlstore"
jsoniter "github.com/json-iterator/go"
)
type commitHelper struct {
ctx context.Context
repo *git.Repository
work *git.Worktree
orgDir string // includes the orgID
workDir string // same as the worktree root
orgID int64
users map[int64]*userInfo
stopRequested bool
broadcast func(path string)
exporter string // key for the current exporter
counter int
}
type commitBody struct {
fpath string // absolute
body []byte
frame *data.Frame
}
type commitOptions struct {
body []commitBody
when time.Time
userID int64
comment string
}
func (ch *commitHelper) initOrg(sql *sqlstore.SQLStore, orgID int64) error {
return sql.WithDbSession(ch.ctx, func(sess *sqlstore.DBSession) error {
sess.Table("user").
Join("inner", "org_user", "user.id = org_user.user_id").
Cols("user.*", "org_user.role").
Where("org_user.org_id = ?", orgID).
Asc("user.id")
rows := make([]*userInfo, 0)
err := sess.Find(&rows)
if err != nil {
return err
}
lookup := make(map[int64]*userInfo, len(rows))
for _, row := range rows {
lookup[row.ID] = row
}
ch.users = lookup
ch.orgID = orgID
return err
})
}
func (ch *commitHelper) add(opts commitOptions) error {
if ch.stopRequested {
return fmt.Errorf("stop requested")
}
if len(opts.body) < 1 {
return nil // nothing to commit
}
user, ok := ch.users[opts.userID]
if !ok {
user = &userInfo{
Name: "admin",
Email: "admin@unknown.org",
}
}
sig := user.getAuthor()
if opts.when.Unix() > 100 {
sig.When = opts.when
}
for _, b := range opts.body {
if !strings.HasPrefix(b.fpath, ch.orgDir) {
return fmt.Errorf("invalid path, must be within the root folder")
}
// make sure the parent exists
err := os.MkdirAll(path.Dir(b.fpath), 0750)
if err != nil {
return err
}
body := b.body
if b.frame != nil {
body, err = jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(b.frame, "", " ")
if err != nil {
return err
}
}
err = os.WriteFile(b.fpath, body, 0644)
if err != nil {
return err
}
err = os.Chtimes(b.fpath, sig.When, sig.When)
if err != nil {
return err
}
sub := b.fpath[len(ch.workDir)+1:]
_, err = ch.work.Add(sub)
if err != nil {
status, e2 := ch.work.Status()
if e2 != nil {
return fmt.Errorf("error adding: %s (invalud work status: %s)", sub, e2.Error())
}
fmt.Printf("STATUS: %+v\n", status)
return fmt.Errorf("unable to add file: %s (%d)", sub, len(b.body))
}
ch.counter++
}
copts := &git.CommitOptions{
Author: &sig,
}
ch.broadcast(opts.body[0].fpath)
_, err := ch.work.Commit(opts.comment, copts)
return err
}
type userInfo struct {
ID int64 `json:"-" xorm:"id"`
Login string `json:"login"`
Email string `json:"email"`
Name string `json:"name"`
Password string `json:"password"`
Salt string `json:"salt"`
Role string `json:"org_role"` // org role
Theme string `json:"-"` // managed in preferences
Created time.Time `json:"-"` // managed in git or external source
Updated time.Time `json:"-"` // managed in git or external source
IsDisabled bool `json:"disabled" xorm:"is_disabled"`
IsServiceAccount bool `json:"serviceAccount" xorm:"is_service_account"`
LastSeenAt time.Time `json:"-" xorm:"last_seen_at"`
}
func (u *userInfo) getAuthor() object.Signature {
return object.Signature{
Name: firstRealStringX(u.Name, u.Login, u.Email, "?"),
Email: firstRealStringX(u.Email, u.Login, u.Name, "?"),
When: time.Now(),
}
}
func firstRealStringX(vals ...string) string {
for _, v := range vals {
if v != "" {
return v
}
}
return "?"
}