From 06d9c6872655b85f1a47599add92d49d570e7b2e Mon Sep 17 00:00:00 2001 From: Michael Muré Date: Wed, 16 Jan 2019 21:23:49 +0100 Subject: identity: implement the loading from git --- identity/bare.go | 9 +++++ identity/identity.go | 109 +++++++++++++++++++++++++++++++++++++++++++++----- identity/interface.go | 6 ++- identity/version.go | 2 +- 4 files changed, 113 insertions(+), 13 deletions(-) (limited to 'identity') diff --git a/identity/bare.go b/identity/bare.go index eec00e19..24f30f9f 100644 --- a/identity/bare.go +++ b/identity/bare.go @@ -9,6 +9,11 @@ import ( "github.com/MichaelMure/git-bug/util/text" ) +// Bare is a very minimal identity, designed to be fully embedded directly along +// other data. +// +// in particular, this identity is designed to be compatible with the handling of +// identities in the early version of git-bug. type Bare struct { name string email string @@ -71,10 +76,12 @@ func (i Bare) AvatarUrl() string { return i.avatarUrl } +// Keys return the last version of the valid keys func (i Bare) Keys() []Key { return []Key{} } +// ValidKeysAtTime return the set of keys valid at a given lamport time func (i Bare) ValidKeysAtTime(time lamport.Time) []Key { return []Key{} } @@ -139,6 +146,8 @@ func (i Bare) Validate() error { return nil } +// IsProtected return true if the chain of git commits started to be signed. +// If that's the case, only signed commit with a valid key for this identity can be added. func (i Bare) IsProtected() bool { return false } diff --git a/identity/identity.go b/identity/identity.go index f65e2a86..0fe13d21 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -2,18 +2,22 @@ package identity import ( + "encoding/json" "fmt" "strings" "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" "github.com/MichaelMure/git-bug/util/lamport" + "github.com/pkg/errors" ) const identityRefPattern = "refs/identities/" const versionEntryName = "version" const identityConfigKey = "git-bug.identity" +var ErrIdentityNotExist = errors.New("identity doesn't exist") + type Identity struct { id string Versions []Version @@ -35,22 +39,106 @@ type identityJson struct { Id string `json:"id"` } -// TODO: marshal/unmarshal identity + load/write from OpBase +// MarshalJSON will only serialize the id +func (i *Identity) MarshalJSON() ([]byte, error) { + return json.Marshal(identityJson{ + Id: i.Id(), + }) +} + +// UnmarshalJSON will only read the id +// Users of this package are expected to run Load() to load +// the remaining data from the identities data in git. +func (i *Identity) UnmarshalJSON(data []byte) error { + aux := identityJson{} + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + i.id = aux.Id + return nil +} + +// TODO: load/write from OpBase + +// Read load an Identity from the identities data available in git func Read(repo repository.Repo, id string) (*Identity, error) { - // Todo - return &Identity{}, nil + i := &Identity{ + id: id, + } + + err := i.Load(repo) + if err != nil { + return nil, err + } + + return i, nil +} + +// Load will read the corresponding identity data from git and replace any +// data already loaded if any. +func (i *Identity) Load(repo repository.Repo) error { + ref := fmt.Sprintf("%s%s", identityRefPattern, i.Id()) + + hashes, err := repo.ListCommits(ref) + + var versions []Version + + // TODO: this is not perfect, it might be a command invoke error + if err != nil { + return ErrIdentityNotExist + } + + for _, hash := range hashes { + entries, err := repo.ListEntries(hash) + if err != nil { + return errors.Wrap(err, "can't list git tree entries") + } + + if len(entries) != 1 { + return fmt.Errorf("invalid identity data at hash %s", hash) + } + + entry := entries[0] + + if entry.Name != versionEntryName { + return fmt.Errorf("invalid identity data at hash %s", hash) + } + + data, err := repo.ReadData(entry.Hash) + if err != nil { + return errors.Wrap(err, "failed to read git blob data") + } + + var version Version + err = json.Unmarshal(data, &version) + + if err != nil { + return errors.Wrapf(err, "failed to decode Identity version json %s", hash) + } + + // tag the version with the commit hash + version.commitHash = hash + + versions = append(versions, version) + } + + i.Versions = versions + + return nil } // NewFromGitUser will query the repository for user detail and // build the corresponding Identity -/*func NewFromGitUser(repo repository.Repo) (*Identity, error) { +func NewFromGitUser(repo repository.Repo) (*Identity, error) { name, err := repo.GetUserName() if err != nil { return nil, err } if name == "" { - return nil, errors.New("User name is not configured in git yet. Please use `git config --global user.name \"John Doe\"`") + return nil, errors.New("user name is not configured in git yet. Please use `git config --global user.name \"John Doe\"`") } email, err := repo.GetUserEmail() @@ -58,14 +146,15 @@ func Read(repo repository.Repo, id string) (*Identity, error) { return nil, err } if email == "" { - return nil, errors.New("User name is not configured in git yet. Please use `git config --global user.email johndoe@example.com`") + return nil, errors.New("user name is not configured in git yet. Please use `git config --global user.email johndoe@example.com`") } return NewIdentity(name, email) -}*/ +} -// -func BuildFromGit(repo repository.Repo) *Identity { +// BuildFromGit will query the repository for user detail and +// build the corresponding Identity +/*func BuildFromGit(repo repository.Repo) *Identity { version := Version{} name, err := repo.GetUserName() @@ -83,7 +172,7 @@ func BuildFromGit(repo repository.Repo) *Identity { version, }, } -} +}*/ // SetIdentity store the user identity's id in the git config func SetIdentity(repo repository.RepoCommon, identity Identity) error { diff --git a/identity/interface.go b/identity/interface.go index 14287655..058e6ec6 100644 --- a/identity/interface.go +++ b/identity/interface.go @@ -1,6 +1,8 @@ package identity -import "github.com/MichaelMure/git-bug/util/lamport" +import ( + "github.com/MichaelMure/git-bug/util/lamport" +) type Interface interface { Name() string @@ -8,7 +10,7 @@ type Interface interface { Login() string AvatarUrl() string - // Login return the last version of the valid keys + // Keys return the last version of the valid keys Keys() []Key // ValidKeysAtTime return the set of keys valid at a given lamport time diff --git a/identity/version.go b/identity/version.go index f76ec4c5..3e84ece3 100644 --- a/identity/version.go +++ b/identity/version.go @@ -8,11 +8,11 @@ import ( "github.com/MichaelMure/git-bug/repository" "github.com/MichaelMure/git-bug/util/git" - "github.com/MichaelMure/git-bug/util/lamport" "github.com/MichaelMure/git-bug/util/text" ) +// Version is a complete set of informations about an Identity at a point in time. type Version struct { // Private field so not serialized commitHash git.Hash -- cgit