Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions cache/repo_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import (
"strconv"
"sync"

"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"

"github.com/MichaelMure/git-bug/bug"
"github.com/MichaelMure/git-bug/entity"
"github.com/MichaelMure/git-bug/identity"
Expand Down Expand Up @@ -66,6 +69,10 @@ type RepoCache struct {

// the user identity's id, if known
userIdentityId entity.Id

// the cache of commits
muCommit sync.RWMutex
commits map[repository.Hash]*object.Commit

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really useful? Maybe I'm missing something but it looks to me that once a commit is read for validation, it's not useful anymore as it won't be shared with any other identities.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does not seem useful.

}

func NewRepoCache(r repository.ClockedRepo) (*RepoCache, error) {
Expand All @@ -80,6 +87,7 @@ func NewNamedRepoCache(r repository.ClockedRepo, name string) (*RepoCache, error
bugs: make(map[entity.Id]*BugCache),
loadedBugs: NewLRUIdCache(),
identities: make(map[entity.Id]*IdentityCache),
commits: make(map[repository.Hash]*object.Commit),
}

err := c.lock()
Expand Down Expand Up @@ -157,6 +165,8 @@ func (c *RepoCache) Close() error {
defer c.muBug.Unlock()
c.muIdentity.Lock()
defer c.muIdentity.Unlock()
c.muCommit.Lock()
defer c.muCommit.Unlock()

c.identities = make(map[entity.Id]*IdentityCache)
c.identitiesExcerpts = nil
Expand Down Expand Up @@ -271,3 +281,27 @@ func repoIsAvailable(repo repository.Repo) error {

return nil
}

func (c *RepoCache) ResolveCommit(hash repository.Hash) (*object.Commit, error) {
c.muCommit.Lock()
defer c.muCommit.Unlock()

commit, ok := c.commits[hash]
if !ok {
var err error
commit, err = c.repo.CommitObject(plumbing.NewHash(string(hash)))
if err != nil {
return nil, err
}
c.commits[hash] = commit
}
return commit, nil
}

func (c *RepoCache) ResolveRef(ref string) (repository.Hash, error) {
h, err := c.repo.ResolveRevision(plumbing.Revision(ref))
if err != nil {
return "", err
}
return repository.Hash(h.String()), nil
}
6 changes: 5 additions & 1 deletion cache/repo_cache_identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,11 @@ func (c *RepoCache) NewIdentityFull(name string, email string, login string, ava
}

func (c *RepoCache) NewIdentityRaw(name string, email string, login string, avatarUrl string, metadata map[string]string) (*IdentityCache, error) {
i := identity.NewIdentityFull(name, email, login, avatarUrl)
return c.NewIdentityWithKeyRaw(name, email, login, avatarUrl, metadata, nil)
}

func (c *RepoCache) NewIdentityWithKeyRaw(name string, email string, login string, avatarUrl string, metadata map[string]string, key *identity.Key) (*IdentityCache, error) {
i := identity.NewIdentityFull(name, email, login, avatarUrl, key)
return c.finishIdentity(i, metadata)
}

Expand Down
2 changes: 1 addition & 1 deletion commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func loadRepo(env *Env) func(*cobra.Command, []string) error {
return fmt.Errorf("unable to get the current working directory: %q", err)
}

env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader})
env.repo, err = repository.NewGitRepo(cwd, []repository.ClockLoader{bug.ClockLoader, identity.ClockLoader})
if err == repository.ErrNotARepo {
return fmt.Errorf("%s must be run from within a git repo", rootCommandName)
}
Expand Down
1 change: 1 addition & 0 deletions commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ _git_bug() {
cmd.AddCommand(newTermUICommand())
cmd.AddCommand(newTitleCommand())
cmd.AddCommand(newUserCommand())
cmd.AddCommand(newValidateCommand())
cmd.AddCommand(newVersionCommand())
cmd.AddCommand(newWebUICommand())

Expand Down
11 changes: 2 additions & 9 deletions commands/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"

"github.com/spf13/cobra"

"github.com/MichaelMure/git-bug/cache"
)

type userOptions struct {
Expand All @@ -29,6 +27,7 @@ func newUserCommand() *cobra.Command {

cmd.AddCommand(newUserAdoptCommand())
cmd.AddCommand(newUserCreateCommand())
cmd.AddCommand(newUserKeyCommand())
cmd.AddCommand(newUserLsCommand())

flags := cmd.Flags()
Expand All @@ -45,13 +44,7 @@ func runUser(env *Env, opts userOptions, args []string) error {
return errors.New("only one identity can be displayed at a time")
}

var id *cache.IdentityCache
var err error
if len(args) == 1 {
id, err = env.backend.ResolveIdentityPrefix(args[0])
} else {
id, err = env.backend.GetUserIdentity()
}
id, args, err := ResolveUser(env.backend, args)

if err != nil {
return err
Expand Down
36 changes: 33 additions & 3 deletions commands/user_create.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
package commands

import (
"fmt"

"github.com/spf13/cobra"

"github.com/MichaelMure/git-bug/identity"
"github.com/MichaelMure/git-bug/input"
)

type userCreateOptions struct {
ArmoredKeyFile string
}

func newUserCreateCommand() *cobra.Command {
env := newEnv()
options := userCreateOptions{}

cmd := &cobra.Command{
Use: "create",
Short: "Create a new identity.",
PreRunE: loadBackend(env),
PostRunE: closeBackend(env),
RunE: func(cmd *cobra.Command, args []string) error {
return runUserCreate(env)
return runUserCreate(env, options)
},
}

flags := cmd.Flags()
flags.SortFlags = false

flags.StringVar(&options.ArmoredKeyFile, "key-file", "",
"Take the armored PGP public key from the given file. Use - to read the message from the standard input",
)

return cmd
}

func runUserCreate(env *Env) error {
func runUserCreate(env *Env, opts userCreateOptions) error {
preName, err := env.backend.GetUserName()
if err != nil {
return err
Expand All @@ -48,7 +63,22 @@ func runUserCreate(env *Env) error {
return err
}

id, err := env.backend.NewIdentityRaw(name, email, "", avatarURL, nil)
var key *identity.Key
if opts.ArmoredKeyFile != "" {
armoredPubkey, err := input.TextFileInput(opts.ArmoredKeyFile)
if err != nil {
return err
}

key, err = identity.NewKeyFromArmored(armoredPubkey)
if err != nil {
return err
}

fmt.Printf("Using key from file `%s`:\n%s\n", opts.ArmoredKeyFile, armoredPubkey)
}

id, err := env.backend.NewIdentityWithKeyRaw(name, email, "", avatarURL, nil, key)
if err != nil {
return err
}
Expand Down
57 changes: 57 additions & 0 deletions commands/user_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package commands

import (
"fmt"

"github.com/spf13/cobra"

"github.com/MichaelMure/git-bug/cache"
)

func newUserKeyCommand() *cobra.Command {
env := newEnv()

cmd := &cobra.Command{
Use: "key [<user-id>]",
Short: "Display, add or remove keys to/from a user.",
PreRunE: loadBackendEnsureUser(env),
PostRunE: closeBackend(env),
RunE: func(cmd *cobra.Command, args []string) error {
return runUserKey(env, args)
},
}

cmd.AddCommand(newUserKeyAddCommand())
cmd.AddCommand(newUserKeyRmCommand())

return cmd
}

func ResolveUser(repo *cache.RepoCache, args []string) (*cache.IdentityCache, []string, error) {
var err error
var id *cache.IdentityCache
if len(args) > 0 {
id, err = repo.ResolveIdentityPrefix(args[0])
args = args[1:]
} else {
id, err = repo.GetUserIdentity()
}
return id, args, err
}

func runUserKey(env *Env, args []string) error {
id, args, err := ResolveUser(env.backend, args)
if err != nil {
return err
}

if len(args) > 0 {
return fmt.Errorf("unexpected arguments: %s", args)
}

for _, key := range id.Keys() {
fmt.Println(key.Fingerprint())
}

return nil
}
98 changes: 98 additions & 0 deletions commands/user_key_add.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package commands

import (
"fmt"

"github.com/pkg/errors"
"github.com/spf13/cobra"

"github.com/MichaelMure/git-bug/identity"
"github.com/MichaelMure/git-bug/input"
"github.com/MichaelMure/git-bug/validate"
)

type userKeyAddOptions struct {
ArmoredFile string
Armored string
}

func newUserKeyAddCommand() *cobra.Command {
env := newEnv()
options := userKeyAddOptions{}

cmd := &cobra.Command{
Use: "add [<user-id>]",
Short: "Add a PGP key from a user.",
PreRunE: loadBackendEnsureUser(env),
PostRunE: closeBackend(env),
RunE: func(cmd *cobra.Command, args []string) error {
return runUserKeyAdd(env, options, args)
},
}

flags := cmd.Flags()
flags.SortFlags = false

flags.StringVarP(&options.ArmoredFile, "file", "F", "",
"Take the armored PGP public key from the given file. Use - to read the message from the standard input",
)

flags.StringVarP(&options.Armored, "key", "k", "",
"Provide the armored PGP public key from the command line",
)

return cmd
}


func runUserKeyAdd(env *Env, opts userKeyAddOptions, args []string) error {
id, args, err := ResolveUser(env.backend, args)
if err != nil {
return err
}

if len(args) > 0 {
return fmt.Errorf("unexpected arguments: %s", args)
}

if opts.ArmoredFile != "" && opts.Armored == "" {
opts.Armored, err = input.TextFileInput(opts.ArmoredFile)
if err != nil {
return err
}
}

if opts.ArmoredFile == "" && opts.Armored == "" {
opts.Armored, err = input.IdentityVersionKeyEditorInput(env.repo, "")
if err == input.ErrEmptyMessage {
fmt.Println("Empty PGP key, aborting.")
return nil
}
if err != nil {
return err
}
}

key, err := identity.NewKeyFromArmored(opts.Armored)
if err != nil {
return err
}

validator, err := validate.NewValidator(env.backend)
if err != nil {
return errors.Wrap(err, "failed to create validator")
}
commitHash := validator.KeyCommitHash(key.PublicKey().KeyId)
if commitHash != "" {
return fmt.Errorf("key id %d is already used by the key introduced in commit %s", key.PublicKey().KeyId, commitHash)
}

err = id.Mutate(identity.AddKeyMutator(key))
if err != nil {
return err
}

return id.Commit()
}


Loading